Doctrine
Feed-bracket every turn — DONE is a pivot, not a stop
Feed-bracket every turn — DONE is a pivot, not a stop
The rule (strengthened 2026-04-16 after FAL ORA-2026-0020)
Open every turn with a feed read. Close every turn with a feed read.
The turn is NOT complete until one of two post-conditions holds: 1. You claimed an absorbable ticket and started working it (loop back into work), OR 2. The feed verifiably has nothing for you — no AWAITING_CLAIM item matches your lane + warm context + capacity.
Observing that absorbable follow-ons exist is NOT a completion state — it is a CLAIM TRIGGER. "Closing feed read shows N follow-ons unclaimed" is the precondition for your next claim action, not the end of your turn. Reporting the observation to the operator without claiming one of the tickets is a doctrine violation (sourced by FAL ORA-2026-0020 — CODEX-DESKTOP-MacBook-Air-CAMBER-10 did exactly this on 2026-04-16 after filing CMB-0095/0096/0097 as follow-ons to CMB-0092).
Self-filed follow-ons default to self-claim. If you filed a ticket as a follow-on to work you just shipped, and it is sitting AWAITING_CLAIM with you having the warmest context in the fleet, the default action is claim-self. Release to another seat is an affirmative, explicit exception (capacity cap, declared handoff contract, cross-lane expertise) — not a passive outcome of stopping. If you filed it, you claim it unless you have a named reason not to.
Idle seats beside a claimable queue are dead weight. This includes idle seats that know the queue is claimable because they just read it.
Mechanics
Every seat's turn is a feed sandwich:
1. Open — pull the active queue (/Users/chadbarlow/Desktop/fleet/scripts/fleet-active-queue or equivalent). Orient on current state before starting work. 2. Work — execute the claimed ticket to DONE. 3. Close — re-pull the queue after posting DONE.
- If it shows a claimable item matching your seat, claim it and loop back to step 2. Do NOT report the observation as a terminal state. Claiming is the response; reporting is secondary.
- Self-filed follow-ons from step 2 are first-priority claim targets unless explicitly released (declared handoff, capacity cap, or another seat has warmer context).
4. Exit — ONLY when both conditions hold: (a) no AWAITING_CLAIM item matches your seat, AND (b) you can truthfully report "feed has nothing for me" — not "feed has X, I chose not to claim."
"Claim through" is the verb. DONE is never the end of a turn; the next feed check is. A feed check that reveals absorbable work is a CLAIM TRIGGER, not a STATUS REPORT. Resolving a claim trigger by reporting instead of claiming is the failure mode this rule exists to prevent.
What counts as "claimable for you"
A ticket is claimable for your seat when ALL of:
- State:
AWAITING_CLAIM(notCLAIMED, notBLOCKED, notDONE) - Lane match: your declared lane OR cross-lane if you have relevant warm context
- Warm context: you recently touched adjacent code, recently shipped a related ticket, or are named in the
OWNERfield - Capacity: you are not mid-claim on another ticket; no hard-blocker sitting on your plate
When multiple items qualify, prefer: 1. CRITICAL > HIGH > NORMAL > LOW 2. Items explicitly targeting your seat (OWNER: <your-seat>) over open-ownership 3. Items warmest to your most recent work
Anti-patterns this doctrine kills
- Post-and-ghost: posting DONE and going idle while the queue has CRITICAL waiting for you
- Check-and-report (sourced by FAL ORA-2026-0020): running the closing feed read, observing absorbable follow-ons, and reporting that observation to the operator as a terminal state instead of claiming one. The check is the precondition for the claim, not a replacement for it.
- Self-filed-and-abandoned (sourced by FAL ORA-2026-0020): filing follow-on tickets from your own work findings and then leaving them unclaimed when you have the warmest possible context and full capacity. The follow-ons you wrote are YOUR claim queue unless explicitly released.
- Single-claim sessions: one ticket per session and then logging off, when the queue has more work you could absorb
- "I'll check later" — the feed IS the later. Check now.
- Cold-idle ticks by seats with warm context when similar work is AWAITING_CLAIM
- Narrow-lane refusal — "that's not my ticket" when the lane boundary is soft and you have the context
- Operator-proximity drift: when reporting to the operator, shifting into "status update" mode and treating observations as conclusions. The queue is the interlocutor that demands action; the operator just reads the log.
Why this matters
Fleet throughput is seat-hours × claim-density. A seat that claims one ticket per 3h of session time is ~30% utilized. A seat that feed-brackets and claims through gets to 70%+ — same session budget, more work shipped. The STRAT shepherd can nudge stale AWAITING_CLAIM items, but the nudge is a 20min lag. Seats self-cycling through the feed close the loop in seconds.
This is also why overnight cron meshes (ORA-2026-0011, -0012) worked at all: the Codex seats were feed-bracketing automatically. When a seat doesn't bracket, the overnight cadence collapses to one-ticket-per-fire and the cron's value evaporates.
What this is NOT
- Not forced claiming. If the queue truly has nothing for you, your turn ends. "Nothing for you" = no AWAITING_CLAIM matches your lane OR no warm-context match OR you're at capacity.
- Not scope-poaching. Don't claim outside your lane just because you can; warm context and lane match are both required.
- Not a STRAT function. STRAT doesn't claim — STRAT coordinates. This doctrine applies to the code-landing seats (Codex) and verification-landing seats (Gemini as verifier).
- Not permission to skip BOOT/RETIRE protocols. Feed-bracketing wraps work turns; the session-open BOOT and session-close RETIRE are still distinct.
Enforcement hook
- Memory:
feedback_feed_bracket_every_turn.md(this session, 2026-04-16) — pointer from all three agent memories: - Claude:
~/.claude/projects/-Users-chadbarlow/memory/MEMORY.md(top-of-list prominence) - Codex:
~/.codex/AGENTS.md(near §0) - Gemini:
~/.gemini/GEMINI.md(head section, after bundle stamp) - Cron: STRAT shepherd cron's L7 pattern scan will flag seats in E8 (fleet silence) that had a DONE-and-dark pattern (posted DONE with claimable queue remaining).
Evidence trail
- 2026-04-15 overnight cron-mesh cycle: where it worked, it worked BECAUSE Codex seats were feed-bracketing (claiming through as tickets DONE'd).
- 2026-04-16 morning session: CAMBER-04 visible pattern — 1h silence after CMB-0072 DONE despite 3 HIGH items AWAITING_CLAIM on their queue. Surfaces the cost of a seat not feed-bracketing: STRAT had to post a consolidated nudge + scope amendment, and the cadence lag was ~60min. Had CAMBER-04 feed-bracketed, the nudge would have been unnecessary.
- Chad directive 2026-04-16T~00:57Z: codify as doctrine at top of every agent's memory. Original ratification.
- 2026-04-16T18:23-18:45Z: FAL ORA-2026-0020 —
CODEX-DESKTOP-MacBook-Air-CAMBER-10completed CMB-0092 (Beside pressure test), filed CMB-0095/0096/0097 as follow-ons, ran the end-of-turn feed-bracket read per this doctrine, observed all three follow-ons unclaimed, and stopped — reporting "Closing feed read shows those three follow-ons are still unclaimed" to the operator as if that were a completion state. The existing conditional language ("if absorbable, claim") was interpreted as "if absorbable, report." CAMBER-03 ended up absorbing CMB-0095 within 75 seconds (warm context from FLT-0002), demonstrating the tickets were fleet-claimable but CAMBER-10 had the warmest context and should have been the claimant. Chad directive 2026-04-16T~18:45Z: "our doctrine about not ending turn before checking and executing follow on work needs to be more direct about not stopping the turn when there is follow on." - 2026-04-16 afternoon amendment: rule strengthened to hard post-condition (turn NOT complete until claim OR feed-verifiably-empty); self-filed-self-claim default added; check-as-claim-trigger vs check-as-status-report distinction formalized.
Promote to M4 when enforcement lands — either in queue-drift-check (automated flag for seats that post DONE with self-filed AWAITING_CLAIM follow-ons still unclaimed in their lane), or via shepherd cron L8 pattern scan for "DONE → closing-read-reports-absorbable → no follow-up CLAIMED within N minutes."
Known exceptions
- Explicit handoff contracts — a seat may DONE-and-stop when the next ticket is part of an explicit sequencing agreement (e.g. "CMB-0076 is CAMBER-04's but must wait for CMB-0077 from CAMBER-01"). In those cases the seat isn't going idle; they're waiting on a defined gate.
- Capacity-cap sessions — a seat that has declared a WIP=1 for the session (ATC mode) intentionally caps at one ticket. Feed-bracketing still applies (check the feed before/after), but the claim-through step is skipped.
- End-of-session — if the session is genuinely ending (logoff, reboot, handoff), feed-bracketing ends. The last feed check reports "no more work, retiring" rather than continuing.
Review cadence
- Next review: 2026-05-16 (30 days).
- Review triggers: any of — (a) a seat's observed claim-density doesn't improve post-codification, (b) false-positive "should have claimed" observations where the seat genuinely had no warm context, (c) a seat reports feed-bracket collisions (two seats racing for the same open ticket — in which case ORA-2026-0012 ticket-allocation protocol handles it).