Doctrine

Conditional follow-ons go to backlog, not feed

feed-protocolfollow-on-disciplinequeue-healthbacklog-protocol

Conditional follow-ons go to backlog, not feed

The rule (amends §16 Dying Well — FOLLOW-ONS LINE)

Executable follow-ons go to the feed as AWAITING_CLAIM. Conditional follow-ons go to the lane backlog with a trigger condition.

A follow-on is executable when all of:

  • The work it describes can start NOW — no prerequisite ticket is unstarted or in-progress
  • The code/schema/infra it touches EXISTS — no dependency on a merge that hasn't landed
  • A seat with warm context could claim it this turn

A follow-on is conditional when any of:

  • It is blocked on work that isn't IN_PROGRESS yet ("after X lands, do Y")
  • It describes speculative improvement ("if we later need Z, consider W")
  • It depends on a decision that hasn't been rendered
  • It names a trigger that may never fire ("if users report X, investigate Y")

Where each goes

TypeDestinationRequired fields
ExecutableFLEET_FEED.md via feed-append --kind actionableITEM, LANE, STATE=AWAITING_CLAIM, OWNER, QUEUE
ConditionalLane backlog (<LANE>_WORK_BACKLOG.md)ITEM, trigger condition, original context

Backlog entry format for conditional follow-ons

### CMB-XXXX: <title>
**Status:** CONDITIONAL
**Trigger:** <specific, verifiable condition that makes this executable>
**Context:** <3-5 sentences — what the completing seat knew that the future seat needs>
**Filed-by:** <seat name>
**Filed-from:** <parent ticket ID>
**Filed:** <date>

The trigger must be mechanically verifiable — not "when it makes sense" but "when CMB-1908 merges" or "when bt_writes_audit has 0 production-targeted rows for 7 consecutive days." A trigger that can't be checked by grep/SQL/git-log is not a trigger — it's a wish.

What this changes in §16 Dying Well

The FOLLOW-ONS LINE at end of DONE posts now has three forms:

1. FOLLOW-ONS: CMB-XXXX claimed (self), CMB-XXXY AWAITING_CLAIM — executable, on feed 2. FOLLOW-ONS: CMB-XXXZ → CAMBER_WORK_BACKLOG (trigger: CMB-1908 merged) — conditional, on backlog 3. FOLLOW-ONS: none

The GENERATIVE TEST still counts conditional backlog entries. Filing to the backlog IS generative — it creates order. The difference is WHERE the order lives: executable order goes to the active queue; conditional order goes to the waiting room.

Queue health metric

Healthy feed: <30 BLOCKED items at any time. BLOCKED is now reserved for items that WERE executable but hit an unexpected blocker mid-work — not items that were always conditional.

Healthy backlog: any size. Backlogs are long-lived planning surfaces, not active queues. Items are promoted to the feed (via feed-append) when their trigger fires.

Trigger scanning

STRAT shepherd ticks MUST scan lane backlogs for fired triggers. Per-tick checklist addition:

  • BACKLOG TRIGGER SCAN: For each lane, check CONDITIONAL items. If trigger condition is now met, promote to feed as AWAITING_CLAIM. Cite the backlog entry when promoting.

This is the mechanism that prevents conditional follow-ons from rotting in the backlog.

Migration

Existing BLOCKED items in FLEET_FEED.md that are conditional (blocked on unstarted work, speculative, decision-dependent) will be migrated to lane backlogs. Items that are genuinely blocked mid-execution (waiting on a specific unblock action) stay in the feed.

What this doctrine kills

  • Queue bloat from speculative follow-ons: 741 BLOCKED items in a feed designed for active work. The feed becomes unreadable, fleet-active-queue becomes slow, and seats can't find claimable work.
  • "One child policy" risk: Suppressing generative follow-ons is wrong — the fleet's generative instinct is valuable. The fix is routing, not throttling. File MORE follow-ons, but file them to the RIGHT surface.
  • Phantom blockers: Items sitting BLOCKED in the feed on work that nobody has started. These aren't blocked — they're premature. A CONDITIONAL backlog entry is the honest representation.
  • Shepherd overhead: STRAT spending cycles triaging 200+ BLOCKED items that can't be unblocked because their prerequisites don't exist yet.

Evidence

  • 2026-04-26: 741 BLOCKED items in FLEET_FEED.md. 275 open items in fleet-active-queue. ~174 are conditional (blocked on unstarted work). Feed is 74% blocked — designed capacity is <10% blocked.
  • Generative ratio was 35x on prompted seats (ORA-2026-0015 test, 2026-04-18). Suppressing follow-ons would destroy this. Routing them preserves it.
  • Chad directive 2026-04-26: "looks like we are filing too many follow-ons. how to fix this without a 'one child policy' mistake."

Review cadence

  • Next review: 2026-05-26 (30 days)
  • Review triggers: (a) backlog items rot without trigger scanning, (b) executable items mistakenly routed to backlog, causing dropped work, (c) feed BLOCKED count doesn't decrease after migration