docs: permit subagents explicitly, and make claiming an issue a check rather than a label #682

Merged
timothy merged 2 commits from docs/claim-protocol-and-subagents into main 2026-07-27 18:04:14 +02:00
Owner

Docs-only. Two rules that were implied but not enforceable, both demonstrated by #649 being implemented twice in parallel to completion on 2026-07-26.

Subagents: explicitly permitted

The kickoff's HARD CONSTRAINTS already require parallelising disjoint slices, mandatory independent review from a cold brief, and a named model/effort per dispatch. None of that is satisfiable without delegation — but nothing said so outright, and a generic client preamble of the form "do not use the Agent tool unless the user requested it" reads as a prohibition.

Now stated plainly in both CLAUDE.md (always loaded) and the kickoff (pasted per session), including what to delegate (bounded recon, mechanical slices against a documented contract, disjoint worktrees, every independent review) and what to keep inline (design decisions, review arbitration, anything cheaper to do than to brief).

Claiming: a check, not a label

process.parallel-session-claim already said a claim prevents duplicate pickup, not duplicate work. But step 3 told you to apply in-progress and nothing else — so the documented risk had no corresponding action.

Step 3 now requires four checks first, each failing differently and all cheap:

Check Catches
Open PRs whose body says fixes #N The #649 case exactly
git ls-remote --heads origin '*<N>*' A branch usually exists before the PR
Comments predating the label What select-queue.sh's CLAIM? flag raises and deliberately leaves unresolved
git fetch origin main Reading current state, not your opening snapshot

Staleness: re-fetch before every push

The second half of the collision was reading origin/main once, at branch time, and not again across hours and four review rounds.

A branch on a stale base computes its diff against that base — so git diff origin/main shows other sessions' merged work as deletions, and pushing reverts them. In #649's case that would have reverted both #666 and #667. The tell is deletions you did not make.

What the record now carries

process.parallel-session-claim gains the incident, including the part worth keeping: the duplicate effort was not wasted. The merged implementation was better in one respect (it exports ETV_GITEA_URL as well as GITEA_BASE_URL, because pr-changed-files.sh reads the former at higher precedence), and the discarded branch's test coverage was salvaged onto the merged code as #673. So when you find a collision, diff the two implementations before discarding yours — the loser usually contains something the winner lacks.

Verification

decisions-validate: OK, catalog regenerated and in sync, scripts/tests 325 passed, no NUL/BOM in the changed set. No behaviour change.

Docs-only. Two rules that were implied but not enforceable, both demonstrated by **#649 being implemented twice in parallel to completion** on 2026-07-26. ## Subagents: explicitly permitted The kickoff's HARD CONSTRAINTS already require parallelising disjoint slices, mandatory independent review from a **cold** brief, and a named model/effort per dispatch. None of that is satisfiable without delegation — but nothing said so outright, and a generic client preamble of the form *"do not use the Agent tool unless the user requested it"* reads as a prohibition. Now stated plainly in **both** `CLAUDE.md` (always loaded) and the kickoff (pasted per session), including what to delegate (bounded recon, mechanical slices against a documented contract, disjoint worktrees, every independent review) and what to keep inline (design decisions, review arbitration, anything cheaper to do than to brief). ## Claiming: a check, not a label `process.parallel-session-claim` already said a claim prevents duplicate *pickup*, not duplicate *work*. But step 3 told you to apply `in-progress` and nothing else — so the documented risk had no corresponding action. Step 3 now requires four checks first, each failing differently and all cheap: | Check | Catches | |---|---| | Open PRs whose body says `fixes #N` | The #649 case exactly | | `git ls-remote --heads origin '*<N>*'` | A branch usually exists before the PR | | Comments predating the label | What `select-queue.sh`'s `CLAIM?` flag raises and deliberately leaves unresolved | | `git fetch origin main` | Reading current state, not your opening snapshot | ## Staleness: re-fetch before every push The second half of the collision was reading `origin/main` **once**, at branch time, and not again across hours and four review rounds. A branch on a stale base computes its diff against that base — so `git diff origin/main` shows other sessions' merged work as **deletions**, and pushing reverts them. In #649's case that would have reverted both #666 and #667. The tell is deletions you did not make. ## What the record now carries `process.parallel-session-claim` gains the incident, including the part worth keeping: the duplicate effort was not wasted. The merged implementation was **better** in one respect (it exports `ETV_GITEA_URL` as well as `GITEA_BASE_URL`, because `pr-changed-files.sh` reads the former at higher precedence), and the discarded branch's test coverage was salvaged onto the merged code as #673. So when you find a collision, **diff the two implementations before discarding yours** — the loser usually contains something the winner lacks. ## Verification `decisions-validate: OK`, catalog regenerated and in sync, `scripts/tests` 325 passed, no NUL/BOM in the changed set. No behaviour change.
timothy added 1 commit 2026-07-27 07:44:52 +02:00
docs: make subagent use explicit, and turn "claim an issue" into a check rather than a label
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 28s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 20s
PR Gates / Docs update reminder (pull_request) Successful in 24s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 29s
PR Gates / decisions lifecycle (pull_request) Failing after 24s
review-verdict/h10 Exempt: docs-only change (no code, no protected path)
Review verdict / Set review-verdict status (pull_request) Successful in 7s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 26s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 25s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
PR Gates / Script tests (pytest) (pull_request) Successful in 54s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 15s
b83e965994
Two rules that were implied but not enforceable, both demonstrated by ersatztv#649 being
implemented TWICE in parallel to completion on the same day.

Subagents. The kickoff's HARD CONSTRAINTS already require parallel disjoint slices, mandatory
independent review from a cold brief, and a named model/effort per dispatch — none of which is
satisfiable without delegation. But nothing said so outright, and a generic client preamble of the
form "do not use the Agent tool unless the user requested it" reads as a prohibition. Now stated
plainly in both CLAUDE.md (always loaded) and the kickoff (pasted per session), with what to
delegate and what to keep inline.

Claiming. `in-progress` prevents duplicate PICKUP, not duplicate WORK — the record already said so,
but step 3 told you to apply the label and nothing else. It now requires four checks first: an open
PR whose body says `fixes #N`, a remote branch naming the number, a claiming comment predating the
label (exactly what select-queue.sh's CLAIM? flag raises and deliberately leaves unresolved), and a
fresh git fetch. Each fails differently; all four are cheap.

Staleness. The second half of the #649 collision was reading origin/main once, at branch time, and
not again across hours and four review rounds. A branch on a stale base computes its diff against
that base, so `git diff origin/main` shows other sessions' merged work as DELETIONS and pushing it
reverts them. Re-fetch before every push, rebase when it moved.

process.parallel-session-claim carries the incident, including what worked: the merged
implementation was better in one respect and the discarded branch's test coverage was salvageable,
so diff the two before discarding yours.
timothy added 1 commit 2026-07-27 08:03:37 +02:00
docs: record the Decisions-Edit trailer for the parallel-session-claim rationale
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 24s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 13s
PR Gates / Docs update reminder (pull_request) Successful in 15s
PR Gates / decisions lifecycle (pull_request) Successful in 16s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 18s
review-verdict/h10 Exempt: docs-only change (no code, no protected path)
Review verdict / Set review-verdict status (pull_request) Successful in 9s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 9s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 7s
PR Gates / Script tests (pytest) (pull_request) Successful in 39s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 19s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
400e30a278
The previous commit rewrote the rationale prose of process.parallel-session-claim (adding the
ersatztv#649 double-implementation incident) without this trailer, and CI's decisions-lifecycle
gate correctly rejected it.

Worth recording WHY it passed locally and failed in CI: I ran decisions_validate.py BEFORE
`git commit` in the same command chain, so it inspected the working tree. The trailer check reads
COMMITTED history, so the one rule that can only fail after committing was the one I validated
before committing. Run the decisions validator after the commit, not before it.

Decisions-Edit: yes
timothy merged commit cb7da865b6 into main 2026-07-27 18:04:14 +02:00
timothy deleted branch docs/claim-protocol-and-subagents 2026-07-27 18:04:14 +02:00
Sign in to join this conversation.