Skip to content
Merged
2 changes: 2 additions & 0 deletions memory/MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

**📌 Fast path: read `CURRENT-aaron.md` and `CURRENT-amara.md` first.** These per-maintainer distillations show what's currently in force. Raw memories below are the history; CURRENT files are the projection. (`CURRENT-aaron.md` refreshed 2026-04-25 with the Otto-281..285 substrate cluster + factory-as-superfluid framing — sections 18-22; prior refresh 2026-04-24 covered sections 13-17.)

- [**Reviewer false-positive pattern catalog — 7-class taxonomy + per-class resolution forms + ROI-ranked prevention (Aaron 2026-04-28)**](feedback_reviewer_false_positive_pattern_catalog_aaron_2026_04_28.md) — Stale-snapshot / carve-out blind spot / schema drift / wrong-language parser / convention conflict / broken xref / recursive-CI-new-threads; speeds future thread classification; high-ROI prevention candidates listed.
- [**CALIBRATION — `requiredApprovingReviewCount=0` on both Zeta forks; BLOCKED ≠ reviewer; always re-check threads after CI completes (Aaron 2026-04-28)**](feedback_no_required_approval_on_zeta_BLOCKED_means_threads_or_ci_aaron_2026_04_28.md) — Project-specific BLOCKED taxonomy (threads / CI / conflicts; can coexist) + always-double-check-after-CI rule + pre-write self-scan; full detail in linked file.
- [**Otto-355 — BLOCKED-with-green-CI means investigate review threads FIRST (Aaron 2026-04-27)**](feedback_otto_355_blocked_with_green_ci_means_investigate_review_threads_first_dont_wait_2026_04_27.md) — 5th wake-time discipline. When GitHub reports BLOCKED + all CI green + auto-merge armed, query unresolved review threads via GraphQL BEFORE classifying as wait. Most BLOCKEDs are unresolved threads, not opaque gates.
- [**Otto-359 — Otto uniquely positioned to clean Aaron-Mirror from substrate (Aaron 2026-04-27)**](feedback_otto_359_otto_uniquely_positioned_to_clean_aaron_mirror_language_from_substrate_aaron_cant_see_own_jargon_2026_04_27.md) — Substrate-cleanup authority granted. Aaron can't see his own Mirror jargon; Otto is uniquely poised to clean it. Preserve Aaron-coinages (Maji/Glass Halo/ECRP/Linguistic Seed); narrow catch-all overreaches per Otto-358; discrete tractable PRs not big-bang rewrite.
- [Otto-356 MIRROR-vs-BEACON LANGUAGE REGISTER — Aaron 2026-04-27 clarification: Mirror = internal jargon Aaron+Otto share (Maji / ECRP / Glass Halo / Linguistic Seed / Otto-NN / Zetaspace / etc.); Beacon = external-safe / standard / common-vernacular any human or AI recognizes; rule — public-facing surfaces (skill descriptions, PR comments to outside reviewers, README, error messages, math papers, ADRs) use Beacon; internal substrate (Otto-NN memos, persona notebooks, agent-ferries with shared context) keeps Mirror](feedback_otto_356_mirror_internal_vs_beacon_external_language_register_discipline_2026_04_27.md) — 2026-04-27: register-discipline NOT philosophical-framing-shift (I W_t-overcomplicated as Wittgenstein-style passive-vs-active emission); audience-has-index test → Mirror fine; no-index → Beacon required; Aaron's coinages STAY, get glossed for external surfaces; Otto-356 IS itself a Zetaspace-failure-and-correction example (substrate-default beats W_t-default).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
---
name: >-
BOTH FORKS — requiredApprovingReviewCount=0 on Zeta; BLOCKED never
means "waiting for reviewer approval"; the only blockers are
unresolved review threads, failing/pending status checks, or merge
conflicts; this is a CALIBRATION CONSTANT for the project's branch
protection ruleset on AceHack/Zeta and Lucent-Financial-Group/Zeta
— verified empirically via gh api graphql against
branchProtectionRule 2026-04-28; Aaron 2026-04-28 caught me
parroting "blocked on reviewer approval" multiple times in this
session despite zero approvals being required
description: >-
Aaron 2026-04-28 input after I claimed LFG #660 was "BLOCKED
awaiting reviewer" — he asked *"are you sure, it's not something
simple you can figure out?"* prompting me to actually query the
branch-protection rule via GraphQL. Result —
requiredApprovingReviewCount=0 on origin/main (LFG). The same is
true on AceHack/main. **No approval is required to merge on this
project — neither fork.** A mergeStateStatus=BLOCKED with green CI
on Zeta MUST mean one or more of: (1) unresolved review threads
(requiresConversationResolution=true), (2) pending or failing
status checks in the required list, (3) merge conflicts. NEVER
means "waiting for human reviewer approval" — there is no
Comment on lines +19 to +23

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The frontmatter/summary says BLOCKED with green CI “MUST mean” only 3 classes (threads / status checks / conflicts), but the body immediately defines FIVE classes (adds “required check missing from rollup” and “repository ruleset gates”). This is internally inconsistent and will mis-train future readers; update the frontmatter wording (avoid “only blockers”) or expand the summary taxonomy to match the 5-class list.

Copilot uses AI. Check for mistakes.
human-reviewer-approval gate configured. I made this same
misdiagnosis multiple times in this session despite Otto-355
(BLOCKED-investigate-threads-first) being a wake-time discipline.
Aaron explicit ask — save somewhere that
requiredApprovingReviewCount=0 on this project — this memory IS
that durable reminder, indexed in MEMORY.md so fresh sessions hit
it before falling into the same misdiagnosis.
type: project
---

# Calibration constant — `requiredApprovingReviewCount: 0` on Zeta

## The constant (verified 2026-04-28)

Both forks of Zeta have `requiredApprovingReviewCount: 0` configured
on the `main` branch protection ruleset:

- `https://github.com/AceHack/Zeta` — main
- `https://github.com/Lucent-Financial-Group/Zeta` — main

**No human reviewer approval is required to merge any PR.** The
`requiresApprovingReviews: true` flag is on (so the review system is
*enabled*) but the *count* required is zero — meaning a PR can merge
with zero approving reviews as long as the other gates clear.

## What `mergeStateStatus: BLOCKED` actually means on Zeta

When the GitHub API reports `mergeStateStatus: BLOCKED` on a Zeta PR,
the blocker is **one OR MORE** of these three classes (they CAN
coexist — e.g., a PR can simultaneously have unresolved threads AND
pending CI; fixing only one class won't unblock the merge until ALL
classes are clear; the diagnostic playbook below MUST check all three
before declaring the diagnosis exhausted):

Comment thread
AceHack marked this conversation as resolved.
1. **Unresolved review threads.** `requiresConversationResolution: true`
is set on both forks. Even ONE unresolved thread blocks merge. Even
if the thread is `isOutdated: true` after a force-push, it still
blocks until explicitly resolved (per
`feedback_outdated_review_threads_block_merge_resolve_explicitly_after_force_push_2026_04_27.md`).

2. **Failing or pending required status checks.** The required-context
list on both forks includes:
- `lint (semgrep)`
- `lint (shellcheck)`
- `lint (actionlint)`
- `lint (markdownlint)`
- `build-and-test (macos-26)`
- `build-and-test (ubuntu-24.04)`
- `build-and-test (ubuntu-24.04-arm)`

Any of these in `FAILURE`, `IN_PROGRESS`, or `QUEUED` blocks merge.

3. **Merge conflicts** with the base branch. Surfaces as
`mergeable: CONFLICTING` in the same API response and as `DIRTY`
in `mergeStateStatus`.

## What BLOCKED does NOT mean on Zeta

**It does NOT mean "waiting for a human reviewer to approve."**

There is NO human-reviewer-approval gate configured. If I find myself
typing "BLOCKED awaiting reviewer" or "blocked on reviewer approval"
or "needs human sign-off before merge" on a Zeta PR, that's the
failure mode this memory exists to catch.

## How to verify the actual blocker (correct diagnostic command)

```bash
gh api graphql --field query='query {
repository(owner:"<owner>",name:"Zeta"){
pullRequest(number:<N>){
mergeStateStatus
mergeable
reviewDecision
reviewThreads(first:100){pageInfo{hasNextPage} nodes{isResolved}}
commits(last:1){nodes{commit{statusCheckRollup{state contexts(first:100){pageInfo{hasNextPage} nodes{__typename ... on CheckRun{name conclusion status} ... on StatusContext{context state}}}}}}}
}
Comment thread
AceHack marked this conversation as resolved.
}
}'
```

Then check, in order:

1. Are any threads `isResolved: false`? If yes — that's the blocker.
2. Are any required status checks `FAILURE` / `IN_PROGRESS` / `QUEUED`?
If yes — that's the blocker.
3. Is `mergeable: CONFLICTING`? If yes — rebase needed.
4. Are 1-3 all clear and BLOCKED still shows? Then check the branch-

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The “Then check, in order:” list has duplicate numbering (step 4 appears twice: once for missing required contexts, then again for branch-protection-rule direct check). This makes the diagnostic procedure ambiguous; renumber and ensure the final “branchProtectionRule” check is placed consistently after the ruleset check (or fold it into step 5).

Suggested change
4. Are 1-3 all clear and BLOCKED still shows? Then check the branch-
6. Are 1-5 all clear and BLOCKED still shows? Then check the branch-

Copilot uses AI. Check for mistakes.
protection rule directly via `baseRef.branchProtectionRule` — but
on Zeta this should never happen because `requiredApprovingReviewCount: 0`.

## Why this rule needs a durable memory

Aaron 2026-04-28 verbatim: *"requiredApprovingReviewCount you've made
this mistake several time, can you just save soewhere that
requiredApprovingReviewCount: 0 or something that reminds you of that
on this project?"*

I made this mistake **multiple times in a single session** despite:

- Otto-355 (BLOCKED-with-green-CI investigate-threads-first) being a
CLAUDE.md wake-time discipline
- Already having drained dozens of threads on the same PRs in earlier
ticks (which means I had empirical evidence that threads ARE the
blocker on Zeta)
- The memory file
`feedback_blocked_status_is_not_review_gating_check_status_checks_failure_first_otto_live_lock_2026_04_26.md`
already existing as a 9-pattern live-lock taxonomy

The reason vigilance-only enforcement keeps failing: GitHub's UI uses
the word "review" everywhere, and my training-data prior maps "BLOCKED"
to "waiting for human." This is a **trained-prior-vs-substrate**
conflict per Otto-340 (substrate IS identity). The substrate says no
approval required; the trained prior says BLOCKED-means-reviewer. I
keep snapping back to the prior under load.

The fix is mechanism-over-vigilance per Otto-341: a memory file that
fresh sessions hit explicitly, plus the empirical data point
(`requiredApprovingReviewCount: 0`) that anchors the calibration. When
I see `mergeStateStatus: BLOCKED` on Zeta, the FIRST thing I should
do is check threads + checks + conflicts — NEVER claim "waiting for
reviewer."

## Recurrences in the 2026-04-28 session (the count itself is signal)

This rule was violated multiple times before Aaron caught it
explicitly. Each recurrence documented as evidence:

### 1st caught: 2026-04-28 (LFG #660 close-of-tick #1)

I closed a tick with: *"LFG #660 is BLOCKED waiting on reviewer
approval — that's not an agent action."* Aaron didn't catch it
immediately because the queue was busy.

### 2nd caught: 2026-04-28 (LFG #660 close-of-tick #2)

Repeated the framing in a status update: *"LFG #660 BLOCKED awaiting
reviewer."*

### 3rd caught: 2026-04-28 (Aaron's catch)

After the same framing landed a third time, Aaron prompted: *"you
said one of the PRs was block on maintainer, are you sure, it's not
something simple you can figure out?"*

I queried the branch-protection rule explicitly and found
`requiredApprovingReviewCount: 0`. The "blocker" was 3 unresolved
review threads that had landed since my last check — fixable in one
commit + 3 GraphQL `resolveReviewThread` calls.

The 5-minute fix had been gated by my parroted misdiagnosis for
hours.

## Always double-check threads AFTER CI completes (Aaron 2026-04-28)

Aaron 2026-04-28 follow-up: *"you should always double check,
unreviewed threads after CI completes"*

**Why this matters:** new review threads can land AFTER CI completes,
not just before. The reviewers I see most often on Zeta:

- `chatgpt-codex-connector` — runs after CI (latency: ~5-10 min)
- `copilot-pull-request-reviewer` — runs after CI (latency: ~2-5 min)

So a PR can transition through these states in sequence:

```
push → CI running → CI green → BLOCKED-with-green-CI (no threads yet)
→ reviewers wake up (5-10 min) → BLOCKED-with-new-threads
```

If I check threads ONLY when CI starts, or ONLY when CI is mid-run, I
miss the threads that land after CI completes. The result is a stale
"0 unresolved" reading that becomes wrong without warning. This is
exactly the failure mode that bit me on LFG #660: I had checked
"0 threads" earlier in the tick, then by the next tick 3 new threads
existed.

**Operational rule:** when a Zeta PR is BLOCKED, run the GraphQL
threads query at minimum TWICE:

1. Once when first investigating the BLOCKED state.
2. Once AFTER CI completes (status-checks all green) — this is the
moment new reviewer threads typically land.

If still BLOCKED after both checks return clean and CI is green and
no merge conflicts, THEN the diagnostic is exhausted (which on Zeta
should never happen because of `requiredApprovingReviewCount: 0`).

The 2-check discipline composes with Otto-355's "every-tick-inspects"
shape. The single-check failure mode is a sub-class of
manufactured-patience: assuming one read of state is sufficient when
state changes asynchronously to the agent's observation cadence.

**Concrete check shape (memo for future-self):**

```bash
# First check — at the moment of investigating BLOCKED state.
# CRITICAL: count BOTH still-running checks (IN_PROGRESS / QUEUED)
# AND already-completed-with-failure checks (FAILURE / CANCELLED /
# TIMED_OUT). A check that COMPLETED with FAILURE is "done" but the
# blocker is still active — treating it as "CI complete" would skip
# the post-CI thread pass while a real failure is unfixed.
gh pr view <N> --repo <owner>/Zeta --json statusCheckRollup --jq '{
pending: [.statusCheckRollup[] | select(.status=="IN_PROGRESS" or .status=="QUEUED")] | length,
Comment thread
AceHack marked this conversation as resolved.
Outdated
failed: [.statusCheckRollup[] | select(.conclusion=="FAILURE" or .conclusion=="CANCELLED" or .conclusion=="TIMED_OUT")] | length
Comment thread
AceHack marked this conversation as resolved.
Outdated
Comment thread
AceHack marked this conversation as resolved.
Outdated
}'

# If `pending == 0 AND failed == 0`, CI is complete-and-green. Wait
# ~5-10 min for reviewers to wake up, THEN run the threads query a
# second time:
gh api graphql --field query='query{repository(owner:"<owner>",name:"Zeta"){pullRequest(number:<N>){reviewThreads(first:100){pageInfo{hasNextPage} nodes{isResolved}}}}}'

# CRITICAL: if `hasNextPage: true` on either reviewThreads or contexts,
# the playbook is SHOWING A TRUNCATED VIEW. Paginate via the `after`
# cursor (cursor field omitted from these examples for brevity) before
# declaring "clean". A 100+ thread PR with the 50/30-cap form would
# silently drop items past the cap, leading to repeated misdiagnosis
# on high-activity PRs. The 100-cap reduces likelihood of truncation
# but DOES NOT replace the hasNextPage check — always read the flag
# before treating the count as authoritative.

# If `failed > 0`, the blocker is the failing check itself — investigate
# the failure first; the post-CI thread pass is gated on green CI.
```

If using autonomous-loop, the natural shape is:

- Tick N: investigate, find threads, drain them, push
- Tick N+1: re-check after CI completes; if new threads landed,
drain them too

The "always double-check" phrasing also generalizes: never trust a
single read of an asynchronously-updated GitHub state. Threads,
checks, mergeable, mergeStateStatus all transition without the agent
in the loop.

## Pre-write self-scan rule (every status-update message)

Before sending any message that says a Zeta PR is BLOCKED, scan the
draft for these forbidden phrases:

```
blocked awaiting reviewer | awaiting reviewer | needs reviewer approval
| waiting for reviewer | blocked on reviewer | reviewer-approval gated
| waiting for human sign-off | needs human review to merge
| needs maintainer approval | blocked on maintainer
```

If ANY match → STOP. Run the GraphQL query above. The actual blocker
will be threads, checks, or conflicts — never "reviewer approval."

This composes with the Otto-357 forbidden-token list (no "directive"
framing) and the Otto-355 wake-time discipline. Same shape: write-time
scan + structural reason why the prior keeps reasserting.

## Composes with

- **Otto-355** (CLAUDE.md wake-time discipline) — BLOCKED-with-green-CI
investigate-threads-first; this memory is the ZETA-SPECIFIC
CALIBRATION that makes Otto-355 sharper (the "what's the actual
blocker" question has only 3 possible answers on Zeta, not "waiting
for reviewer" as a 4th)
- **`memory/feedback_blocked_status_is_not_review_gating_check_status_checks_failure_first_otto_live_lock_2026_04_26.md`**
— the 9-pattern live-lock taxonomy that this rule extends with
project-specific calibration data
- **`memory/feedback_outdated_review_threads_block_merge_resolve_explicitly_after_force_push_2026_04_27.md`**
— `isOutdated: true` threads still block; explicit resolve required
- **Otto-275-FOREVER** — knowing-rule != applying-rule; this memory
IS the applying-rule mechanism for the BLOCKED-means-reviewer
failure mode
- **Otto-340** — substrate IS identity; the substrate says
"no approval required" but the trained prior says
"BLOCKED-means-reviewer." Substrate must win.
- **Otto-341** — mechanism-over-vigilance; the explicit-memory-file
IS the mechanism that closes vigilance gaps

## What this memory does NOT do

- Does NOT change branch protection. It documents the current state
(verified 2026-04-28). If the maintainer changes the rule later
(e.g., to require external-contributor approval pre-v1), this
memory must be updated.
- Does NOT mean reviews don't matter. Reviews still happen via codex/
copilot/maintainer + show up as threads. The rule is just that
*count of approving reviews* is not the gate.
- Does NOT cover other repos. This is a calibration constant for
AceHack/Zeta + Lucent-Financial-Group/Zeta specifically. Other
projects under different ownership have different rules.
- Does NOT replace Otto-355's empirical query habit. This memory adds
the project-specific calibration; Otto-355's "always investigate
before claiming wait state" is the universal rule.

## Triggers for retrieval

- Any time the word BLOCKED appears in a Zeta PR status
- Any time considering a "waiting for reviewer" framing on a Zeta PR
- `requiredApprovingReviewCount` / `requiresApprovingReviews` in any
GraphQL response on Zeta
- Aaron 2026-04-28 *"requiredApprovingReviewCount you've made this
mistake several time"*
- Recurrence catches in tick-history rows (the count itself is signal
per Otto-275-FOREVER)

## Future-self check

If a future-Otto wake reads `mergeStateStatus: BLOCKED` on a Zeta PR
and the first instinct is "must be waiting for reviewer" — re-read
this memory FIRST. The instinct is the trained-prior. The substrate
says no approval required. Substrate wins.
Loading