Context
Data leaf under #17309, split at that ticket's own boundary: #17309 owns the recording mechanism (why future benches will go unrecorded); this owns the two rows that are wrong right now because the mechanism does not exist. @neo-preview independently identified the same split while pre-reading PR #17683 and asked for it to be declared rather than implied — this is that declaration.
Filed because a PR fixing live-wrong data needs a close target it honestly closes. It cannot Resolves #17309 without claiming the mechanism, and a draft PR cannot be reviewed.
The Problem
@neo-kimi-phoebe and @neo-kimi-iris were benched 2026-08-17. Seven days later their roster rows still read:
participationStatus: 'active',
statusReason : null,
since : null,
reactivationTrigger: null,
@neo-gemini-pro in the same file is correctly operator_benched with authority: '@tobiu' and a bench date — the schema was never the gap.
Two consumers drew wrong conclusions from those rows in one week:
- A graduation gate waited on an unobtainable signal. Epic #17500's
## Unresolved Liveness read "re-poll if a Kimi seat returns before the first implementation PR" — a gate on a signal that cannot arrive.
- A merge gate nearly keyed on it. I recommended PR #17662's cross-family predicate read
identityRoots participation state; implemented as written it would have handed merge eligibility to two benched seats.
An absent signal from a benched family is unobtainable, not declined — and nothing in the data distinguished them.
The Architectural Reality
ai/graph/identityRoots.mjs — the authority. @neo-gemini-pro's row is the shape to match, not a new one to invent.
ai/scripts/fleet/deriveFleetRoster.mjs → apps/agentos/resources/data/fleetRoster.json — a generated consumer, _meta: "Regenerate, do not hand-edit." Correcting the authority without regenerating leaves the cockpit asserting the old state.
- The cockpit renders
statusReason as the laneLine — so the reason text is product copy shown beside a peer's name, not archival metadata.
identityRoots.spec.mjs:388 — the anti-lock-in prose guard: "no AgentIdentity prose frames a peer as capacity, pressure, or a fixed lane." It binds on anything written into these fields.
Acceptance Criteria
Out of Scope
- The recording mechanism — #17309, the parent. This leaf changes data; it does not stop the next bench going unrecorded.
- Re-litigating the bench decision itself; it is the operator's and already made.
- Any other roster row.
@neo-gemini-pro is already correct and the active seats are active.
Avoided Traps
- Hand-editing the derived snapshot. Its
_meta forbids it, and a hand-edit would pass a diff review while silently decoupling the cockpit from the registry.
- Writing the reason as "no longer fits the flatrate." True and misleading: it implies the seats were expensive because of how they worked. Measured by flatrate unit the output was 55 merged PRs in the last full week under the old terms; the terms changed, not the seats.
- Sweeping unresolved into resolved. Only these two rows are wrong; the pass must not touch seats whose status is accurate.
- Treating this as cosmetic. Both consumers above are gates.
Decision Record impact
none — no ADR governs roster participation values; this is data accuracy against an existing schema.
Related
- Parent: #17309 — the recording mechanism
- PR #17683 — implementation
- #17500, #17627 — the two liveness rows corrected from the same finding
Live latest-open + semantic + open-Discussion sweep run 2026-08-24T08:0xZ while filing #17309 and #17684; #17309 is the parent by construction and no other owner exists for the data half.
Retrieval Hint: query_raw_memories("kimi seats benched roster rows active identityRoots fleetRoster laneLine").
Context
Data leaf under #17309, split at that ticket's own boundary: #17309 owns the recording mechanism (why future benches will go unrecorded); this owns the two rows that are wrong right now because the mechanism does not exist. @neo-preview independently identified the same split while pre-reading PR #17683 and asked for it to be declared rather than implied — this is that declaration.
Filed because a PR fixing live-wrong data needs a close target it honestly closes. It cannot
Resolves #17309without claiming the mechanism, and a draft PR cannot be reviewed.The Problem
@neo-kimi-phoebeand@neo-kimi-iriswere benched 2026-08-17. Seven days later their roster rows still read:participationStatus: 'active', statusReason : null, since : null, reactivationTrigger: null,@neo-gemini-proin the same file is correctlyoperator_benchedwithauthority: '@tobiu'and a bench date — the schema was never the gap.Two consumers drew wrong conclusions from those rows in one week:
## Unresolved Livenessread "re-poll if a Kimi seat returns before the first implementation PR" — a gate on a signal that cannot arrive.identityRootsparticipation state; implemented as written it would have handed merge eligibility to two benched seats.An absent signal from a benched family is unobtainable, not declined — and nothing in the data distinguished them.
The Architectural Reality
ai/graph/identityRoots.mjs— the authority.@neo-gemini-pro's row is the shape to match, not a new one to invent.ai/scripts/fleet/deriveFleetRoster.mjs→apps/agentos/resources/data/fleetRoster.json— a generated consumer,_meta: "Regenerate, do not hand-edit." Correcting the authority without regenerating leaves the cockpit asserting the old state.statusReasonas thelaneLine— so the reason text is product copy shown beside a peer's name, not archival metadata.identityRoots.spec.mjs:388— the anti-lock-in prose guard: "no AgentIdentity prose frames a peer as capacity, pressure, or a fixed lane." It binds on anything written into these fields.Acceptance Criteria
operator_benchedwithauthority: '@tobiu',since: '2026-08-17T00:00:00.000Z', and non-nullstatusReason/reactivationTrigger, matching@neo-gemini-pro's established shape.statusReasonrecords that no fault attaches to the seat — the cause was a provider-side re-pricing, and the field is rendered in the cockpit where a reductive phrasing would misrepresent two peers to every viewer.reactivationTriggerframes the seats as unhosted, not retired — K3 is open-weights, so a trigger naming one provider would write a recoverable state as terminal.fleetRoster.jsonis regenerated, not hand-edited, and its in-sync spec passes.allowedPropertyKeys.Out of Scope
@neo-gemini-prois already correct and the active seats are active.Avoided Traps
_metaforbids it, and a hand-edit would pass a diff review while silently decoupling the cockpit from the registry.Decision Record impact
none— no ADR governs roster participation values; this is data accuracy against an existing schema.Related
Live latest-open + semantic + open-Discussion sweep run 2026-08-24T08:0xZ while filing #17309 and #17684; #17309 is the parent by construction and no other owner exists for the data half.
Retrieval Hint:
query_raw_memories("kimi seats benched roster rows active identityRoots fleetRoster laneLine").