docs(handoff): fix queue-drift root cause — live Gitea state is the sole source of truth
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m17s
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Has been cancelled

Recent session pickups re-did finished work (thought closed issues were
still open). Root cause: DONE/OPEN status lived in append-only prose (arc
inline markers + each comment's 'Recommended next'), which lags real issue
state — worst across parallel sessions narrating each other's merges.

Kickoff prompt fixes:
- SOURCE OF TRUTH = live Gitea state, never prose; verify OPEN (issue AND
  milestone) before claiming.
- Gate/frontier defined structurally (lowest-numbered open arc item), not
  hardcoded to an issue number (an earlier pass re-planted the bug by
  hardcoding '#197 cluster'/'#91b milestone CLOSED').
- Label-based ranking: arc order -> gate(review label/milestone) -> priority.
- Pick order across arc-frontier / priority-pickup / audit pools.
- Bound the comment read (~6 newest); MCP-down REST fallback; #237 canonical.
- New lore bullet capturing the drift root cause + structural cure.

Companion edits to tracker #237 body (prune arc status -> 'Done (history)'
section) made live; noted in a session comment there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 16:22:57 +02:00
co-authored by Claude Opus 4.8
parent 4112413ca5
commit aed4b5c056
+43 -6
View File
@@ -32,12 +32,32 @@ Everything else (claiming, worktrees, dispatching implementers, CI monitoring, p
bookkeeping, routine merges of green reviewed PRs with user consent) stays at your level.
Then work the queue:
1. Read the pinned tracker **ersatztv#237** — body = goal + ordered arc + session protocol —
and its most recent session comments; list open issues in the `Blazor removal (#91 phase b)`
milestone and with the `review` label; ALSO list open `ersatztv`-labeled issues in
**timothy/adversarial-reviewer** — unclaimed audits there are pickup candidates too
(read-only, parallel-safe; see the tracker's "Pending adversarial reviews" section).
2. Pick the top arc item that is open and NOT labeled `in-progress` (or the item the user names).
1. Read the pinned tracker **ersatztv#237** — body = goal + ordered arc + session protocol — and
its **last ~6 session comments** (newest-first; the full comment payload is large, so stop at ~6).
**SOURCE OF TRUTH = live Gitea issue state, NEVER the prose.** The arc body carries ORDER + goal
only; a session comment's "Recommended next" is a forward *guess* written before the next session
acted. Both go stale the instant an item closes (especially under parallel sessions narrating each
other's work as "the gate that unblocks X"). So derive the candidate set from LIVE state, not from
any inline marker or a prior comment's "next": the **current gate = the lowest-numbered OPEN arc
item in #237's arc list**; its open children are the gate cluster (query them by the `review`
label). Cross-check every arc / "recommended" item's real open/closed state (issue **and**
milestone) before trusting it — do NOT hardcode which issue is the frontier; read it. ALSO list
open `ersatztv`-labeled issues in **timothy/adversarial-reviewer** — unclaimed audits there are
pickup candidates too (read-only, parallel-safe; see the tracker's "Pending adversarial reviews"
section). If the Gitea MCP is down, hit the REST API directly (creds in your global CLAUDE.md):
`curl -u <user>:<pass> http://192.168.1.95:3000/api/v1/repos/timothy/ersatztv/issues/237`.
**The authoritative pickup + ranking protocol lives in #237's "Session protocol" section — this is a summary; if the two ever disagree, #237 wins.**
2. Pick the highest-ranked OPEN, un-`in-progress` candidate (or the item the user names). **Rank by
labels, not just arc position** (labels are live state; prose is not): (1) arc order in #237, then
(2) **gate vs backlog** — an item marked gate by the `review` label OR membership in an open gate
milestone outranks anything unmilestoned; then (3) **`priority:`** label — `high` > `medium` >
`low` within a tier. Pick order across the three pools: the **arc frontier** (lowest-numbered open
arc item) first; an unclaimed Blocker/High **priority-pickup** (`review` + `priority: high`, e.g.
#253) beats a *non-frontier* arc item; reviewer-repo **audits** are read-only and run in parallel.
**Confirm the pick is genuinely OPEN in Gitea first.** If the prose says "recommended next / now
unblocked" but the issue (or its milestone) is already CLOSED, it is done — skip it and fix the
stale line in your session comment. Prose lags live state; live state wins; milestone + `priority:`
labels decide gate-vs-backlog, not the prose. (This mirrors #237's Session-protocol ranking — #237 is canonical.)
3. **Claim it**: add the `in-progress` label + a "claiming" comment on the issue(s);
reviewer-repo audits are claimed by comment only.
4. Read the issue bodies (they carry the task context/evidence) and work the item under the
@@ -282,3 +302,20 @@ HARD CONSTRAINTS:
transport/timeout exceptions must be caught and turned into a response (a `-32603`), else the failure escapes
the handler and the client hangs awaiting a reply that never comes. Proved live with a black-hole socket
(accept, never respond) → 1s timeout → error in ~1s, no hang.
- **Queue-drift root cause + standing rule (2026-07-12, user-surfaced)**: pickups repeatedly re-picked
already-done work — #91b was framed "recommended next / now unblocked" for two sessions *after* it had
merged (2026-07-11), and the #251/#252 priority-pickups sat listed "open" after closing — requiring a
reactive body correction (tracker comment 16:00). ROOT CAUSE: DONE/OPEN status was read from **prose** (the
arc body's inline "DONE" markers + each session comment's "Recommended next"), which is append-only and
hand-edited, so it lags real issue state — worst under parallel sessions that narrate each other's merges as
"the gate that unblocks X" (#271 got cast as the last gate for an already-merged #91b). It is a *structural*
bug, not a stale-writer bug: any status embedded in prose will drift. STANDING FIX (don't just re-patch the
body next time): **live Gitea state is the ONLY source of truth for status.** The arc body carries order+goal;
a comment's "Recommended next" is a *candidate* that MUST be re-verified OPEN (issue **and** milestone) at
pickup. When prose disagrees with live state, live state wins — correct the prose in your session comment,
never propagate it. STRUCTURAL CURE (2026-07-12 review, Fable): #237's arc no longer carries inline `DONE`
markers — closed items move to a "Done (history)" section, so status lives ONLY in live Gitea state and can't
drift; and the gate/frontier is defined **structurally** (lowest-numbered open arc item), never hardcoded to
an issue number. Beware: the *first* pass at this fix re-planted the very bug by hardcoding "#197 cluster" /
"#91b milestone CLOSED" into the kickoff — if you name today's frontier issue in this standing file, you are
writing the next drift. Gate cluster = open `review`-labeled issues serving the current open arc item.