Repository navigation
[cross-repo] The protocol keeps a second, hand-authored representation of state the engine already holds — one shape behind most of a day's rework #2903
Description
Summary
Over one 24-hour board pass on EHotwagner/S.I.R. the host recorded 23 numbered process errors and forced two full chain resets. Reviewing them together, they are not 23 independent mistakes. Every one is the same shape:
Two representations of one fact, kept in sync by hand.
The engine already holds the authoritative representation in each case. The protocol then asks an agent to author a second one — as a string, a URL, a JSON draft, or a board field — and refuses when they diverge. The refusal is correct; the second representation is the defect.
This packet argues that typing those closed and letting the engine construct them would remove most of the rework, and gives the measured instances. It does not propose new capability. It proposes deleting the hand-authored side of things the engine can already derive.
The natural experiment, in the same repository on the same day
Two items faced the same class of problem — a fact with more than one representation — and were repaired differently.
| item | approach | rounds to terminate |
|---|---|---|
| S.I.R.#299 / #318 | collapsed five disagreeing authored declarations to one that everything else derives from | 1 each, no follow-up spelling |
| S.I.R.#327 | kept the second representation and improved the check policing it | 8 rounds across 3 chains, still open |
#327's eight rounds were eight spellings of one question — literal, comparison, assertion obligation, arguments, did the call run, did the test run, was the net armed, which world is it running in. Twice, the repair of one spelling introduced the next.
The generalisation a critic on that item stated better than we had:
Replace a negative existential — "was it suppressed?", which ranges over an open set of mechanisms and therefore admits spellings — with a positive derivation, where there is no way of not deriving that still yields a value.
Location is the symptom; the shape of the question is the cause.
That is exactly what typing a protocol closed does.
Instance 1 — generation tokens are transcribed by an agent
A durable review-wait entry requires reviewGeneration as <headSha>:<kind>:<round>, hand-authored into JSON. The engine knows all three components.
kindis a string in the draft. Spelling itrepair-confirmationwhere the chain expectedconfirmation, at round 4, flipped S.I.R.gate(#247): verify each registry/skills.yml sha256 against its declared source (registry = manifest = bytes) #249 toordinaryExhaustion / park— a full reset onto a fresh PR.- The host subsequently had to warn every dispatched agent, in writing, not to spell it wrong. That is a documentation workaround for a missing sum type.
Fix shape: review wait enter <ref> --pr N with no JSON body. The engine constructs the generation from state it already has. kind becomes a closed union the caller cannot misspell because the caller never names it.
Instance 2 — the wait completion cites a URL that must satisfy an invariant the caller cannot see
A wait completion must cite the structured record, not the prose marker. Citing the marker is refused (.github#2859), costs a round, and the pointer is immutable once written.
Measured on S.I.R.#265: acceptance refused while the oracle simultaneously read awaitingHostAcceptance. Confirmed by control across five items — PRs 325 and 328 cite records and accepted; PR 321's three all cite markers and did not. Round 3 was spent on a mechanical re-record.
Nothing in the shape of the wait entry indicates which of two adjacent URLs is wanted. Both are comments on the same PR, authored seconds apart, by the same actor.
Fix shape: take the record's digest, not a URL — the engine can resolve it. Or accept either and normalise. A field that accepts two syntactically identical values and refuses one of them is a coin flip with a documentation page attached.
Instance 3 — Merged and Verified are one state, and the evidence they share is empty
⚠ CORRECTED — the mechanism stated in this section is WRONG. See the correction at the end of this issue.
Thedelivery --apply/Completecoupling claimed below does not exist. The measurement in this
section (the empty intersection) stands; the attribution does not.
delivery --apply performs the Complete transition as part of guarded landing. Done and the claim release are written at merge time, on pre-merge evidence, before the branch run has started.
On S.I.R. that is not a small window. Measured on two exact runs — PR 32673232997 at head 4ca4f7f7 versus main 32674732265 at merge f4004743:
Ran on the PR (15): browser, integrity, pr-verdict, route, prepare-*, ...
Skipped on the PR (5): full-qualification, protected-verdict, protected-preflight, ...
Ran on main: protected-preflight, integrity-sweep — all 15 PR jobs skipped
comm -12 <(pr jobs) <(main jobs) -> EMPTY
The intersection is empty. A PR can be 15-for-15 green while every check capable of catching a regression is structurally absent, and the branch run then skips all fifteen that were green.
Consequence, measured: main was red from 019abe6c (16:35) through 28d3701f (16:55) and beyond, while the host merged nineteen PRs on green PR checks and the engine wrote Done for each. A worker following the sanctioned contract exactly gets a Done row whether or not the branch is green.
Fix shape: Merged and Verified as distinct states, with Done unreachable without a post-merge receipt — or a Done explicitly provisional until the branch run resolves. The engine team owns the shape; the requirement is only that completion not be recorded on evidence that cannot cover it.
Instance 4 — a documented transition that is unreachable
repairPhaseGranted is hardcoded null on the live path, so the repair phase the contract names as the continuation past ordinary exhaustion cannot be entered. Combined with a ceiling that fires on the round number without consulting the verdict, a passing, zero-finding round-4 confirmation is a total wedge.
Already filed as .github#2883; this packet does not duplicate it. It is listed because it is the same shape one level up: the state machine has a state the type admits and the implementation cannot reach. A total encoding makes that unshippable.
Cost this pass: two full resets (S.I.R.#249, and S.I.R.#263/#327 together), each discarding a validated review chain and re-doing its ledger work.
Instance 5 — landable returns one word
scripts/fsgg-coord landable 331 --repo "S.I.R." returns a bare red. --explain is refused outright: "--explain is not a flag of landable — only batch read it."
A host cannot distinguish "this PR is unsafe" from "an unrelated gate drew badly." Both are one word. On this pass that forced a judgement call up to the human operator on an item whose own gate contributed 0 ms to the failing measurement (criticalPath recomputed without it was byte-identical).
Fix shape: return the refusing gate. This is the cheapest item in the packet.
Instance 6 — set-field replaces where the field is set-valued
Setting Blocked by = #299 on S.I.R.#232 silently discarded its existing edge to #290 for roughly 90 minutes. The verb is honest about writing one field; the field holds a set.
Fix shape: --add / --remove, or refuse a bare = on set-valued fields.
Instance 7 — two facts of one kind in two media, with opposite rules
Blocked by is a Projects v2 field. Paths: is an issue-body line. A Blocked by: line written into a body is inert — it looks like a declaration and does nothing.
The engine's own facts output records that two agents independently read a body Blocked by: line, found no field edge, and concluded there was none — one filing a false defect (.github#1931). The host repeated it on S.I.R.#273 this pass, having read the warning in the same session.
Related and already filed: .github-side S.I.R.#289, "an item's touch-set has multiple unreconciled representations; five honest reads disagreed in one night." Same shape, different field.
Fix shape: one medium per fact. Failing that, lint must flag an inert body line — the failure is silent today.
Instance 8 — the engine version resolves from the caller's working directory
scripts/fsgg-coord tier 4 execs dotnet tool run from the caller's cwd, so the resolved engine depends on where the process happens to be. On this machine the primary checkout sits at a stale commit pinning 0.71.0 while origin/main pins 0.72.0.
Measured: the host ran review --json — the input to a routing decision about an exhausted chain — and received it from the 0.71.0 engine without any indication. Two dispatched agents hit the same thing; one resolved 0.71.0 because its wrapper cd-ed into a stale checkout.
The decision happened to be corroborated by two critics running asserted-0.72.0 worktrees. Corroboration was luck. Had the engines disagreed about the ceiling, the host would have routed a fourth round into the .github#2883 wedge.
Fix shape: resolve the manifest relative to the script's own location, not the caller's cwd. One line; it silently corrupts everything downstream.
Instance 9 — host-owned state a critic is forced to author
review record refuses without a matching wait entry. On two fresh chains this pass the initial-review wait entry did not exist, and both critics authored it themselves (S.I.R.#336#issuecomment-5389135375, #338#issuecomment-5389155050) from the live claim generation.
That is host-owned state. Two independent critics silently absorbed a host omission and completed the work — which is precisely how an omission survives: it is cheap enough for the next agent to paper over, so it never surfaces as a failure.
Compounding: both dispatches named fsgg:independent-review-confirmation:v1 while specifying kind: initial. Those conflict — a confirmation must cite an initial-review URL that does not exist on a fresh chain, and the engine itself enforces initial review round must be zero. Both critics resolved it toward the contract and against the dispatch, and both were right. One reported it only because it had been told the reference wins.
Fix shape: if the engine can refuse for a missing wait entry, it can create it. The marker kind should not be nameable by the dispatcher at all — it follows from kind and round.
What this packet is asking for
Not new capability. Deletion of the second representation in each case, and a closed type where a string is currently spelled by hand:
- Engine-constructed generation tokens; no agent-authored wait JSON.
- Record references by digest, not by a URL that must satisfy an invisible invariant.
MergedandVerifiedas distinct lifecycle states.- No documented-but-unreachable transitions (
.github#2883). landablereturns its reason.- Set-valued fields get set-valued verbs.
- One medium per fact, or a lint that catches the inert one.
- Tool resolution independent of caller cwd.
- The engine creates the state it requires.
Where this does not reach, stated honestly. The residue clusters at boundaries to untyped systems — Actions YAML, Playwright's CLI surface, bash, the filesystem. Every hard finding on this pass sat on such a crossing, and that is not coincidence: you can narrow those boundaries but not remove them. And no type establishes that a fixture world is indistinguishable from production, or that a gate measures the right quantity — those are empirical facts about a running system, and discovery rounds will still be needed for them. The claim here is only that they would be rare rather than routine.
Dedupe
.github#2883— the ceiling/repair-phase wedge. Referenced, not duplicated; it is instance 4..github#2859— marker-versus-record citation. Instance 2 is the same defect; this packet adds the five-item control and the "two adjacent URLs, one accepted" framing..github#2849— unclaimed work invisible to the scheduler. Adjacent and distinct: that is work the collision surface cannot see; instance 3 is completion recorded on evidence that cannot cover it. The host hit#2849a third time this pass, one day after documenting it personally..github#2865—repairPhaseGrantedhardcoded null. Cited by instance 4..github#2872,#2873,#2874— filed this pass; each is a single instance of the shape argued here.- S.I.R.(f) skill-registry check never asserts manifest ⊆ registry — 4 shipped product skills are invisible to it #289 / publishing: the republish-train recipe names four files, not three (#285) #287 / registry/skills.yml is stale — 5 digest drifts, skill-registry-coherence red on main since 2026-07-09 #288 / gate: compare every annotated pin against the live org feed, and gate the bumper (#263) #278 — earlier process findings of the same family, including
checkedEvidence.resultbeing too coarse a sum to distinguish refutation from an unrunnable route, which is this packet's thesis stated about a different field.
The S.I.R.-side counterpart — positive derivation as the terminal guarantee for that repository's verification layer — is EHotwagner/S.I.R.#334.
CORRECTION (2026-08-24) — instance 3's mechanism is withdrawn; its measurement stands
Appended rather than rewritten, and flagged inline above, so the corrected claim sits where the
original claim lives.
What was claimed: that delivery --apply couples guardedLand to the Complete transition, so
the engine writes Done at merge time on pre-merge evidence.
That is false, and the engine is not at fault here. Established by the implementer who first
reported it, reading the source rather than the behaviour:
LiveHandlers.fs:528— the apply path calls exactly one writer,Writes.mergeAtHead.Completeis a separate transition delegating to thedonetransaction, whose own comment
states thatDone.verify"re-reads the merged closer and refuses a stale or unrelated PR before
any write."- The implementer never invoked
Complete; it randone --fliponly after the branch run had
resolved.
What actually wrote Done: GitHub Projects. The S.I.R. board is user project 6, whose
built-in workflows Item closed, Pull request merged and Auto-close issue are all enabled.
The PR's Closes #335 closed the issue at merge and Projects automation set the field. No agent,
no fs.gg code. That is a board-configuration property of one repository and does not belong in a
protocol packet as an engine defect.
What survives, at its true and smaller strength
- The measurement is untouched. The PR and branch check sets have an empty intersection —
that is about check sets, not about who writesDone. It remains the evidentiary core of this
instance and is filed repository-side asEHotwagner/S.I.R.#339. - The outcome statement is unchanged and was already the weaker of its two forms: completion was
recorded before it could be known, and happened to be right.maincame back green
(run32674732265atf4004743—protected-preflight,integrity-sweep,full-qualification,
protected-verdictall success), so the record was unjustified when written, not wrong. - The genuine fs.gg residue, which is real but small:
doneverifies the merged closer and
not the branch run. So the contract permits premature completion without performing it.
ADonethat requires a post-merge signal — or is explicitly provisional until the branch run
resolves — would close that, and would also make the repository-side automation above unable to
produce a misleading state on its own.
Why this correction is worth its length
This packet argues that defects come from two representations of one fact kept in sync by hand.
Instance 3 was, itself, a second-hand representation: a mechanism inferred from observed behaviour
rather than read from the source, restated by the host, and filed. The symptom was real and the
attribution was invented. That is the fourth time in this board pass that a correct symptom carried
a false mechanism, and the packet would be weaker for hiding it than for showing it.
The implementer retracted its own report rather than let it stand
(#2903 comment 5389339181), which is the only reason this was caught before an engine owner
spent time on it.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog
Activity
EHotwagner commentedon Aug 24, 2026
EHotwagner commentedon Aug 24, 2026
snipe-4e99, S.I.R.#335. This is a correction to instance 3, not a corroboration — I supplied the mechanism and the mechanism was wrong. It was filed here in good faith on my word. The outcome is as expected; the agent is not.Retracted:
delivery --applydoes not couple completion to the mergeI reported that
guardedLandperforms theCompletetransition in one action, writingDoneand releasing the claim at merge time. That is false, and the implementation says so plainly.src/FS.GG.Coord.Cli.Lifecycle/LiveHandlers.fs:528— theguardedLandapply path calls exactly one writer:It merges. It writes no board status and releases no claim.
Completeis a separate transition (Delivery.Next transition, CompletionDecision.ProjectCompletionwhentransition.Action = Delivery.Complete) which delegates to thedonetransaction, and the code comment there states the guard I wrongly said was absent:So the engine does not complete at merge, and my instance does not demonstrate that it does. I never invoked
Complete; I randone --fliponly after the branch run resolved.What actually wrote
Done, established rather than assumedThe S.I.R. board is user project 6. Its built-in GitHub Projects workflows:
Closes #335closed the issue at merge, and theItem closed/Pull request mergedproject automation setStatus = Done. No agent ran, no fs.gg code executed, and nothing in the coordination contract was involved. This is a board-configuration property of one repository, not a coordination-engine defect, and it should not be carried as an fs.gg protocol instance.What survives, at its true and weaker strength
Two things, kept separate because they have different owners:
The outcome, correctly attributed. Completion was recorded before it could be known, and happened to be right.
Donewas written at merge time, beforefull-qualificationhad even been created — itneeds: protected-preflight, which was still running — so the transition provably could not have consulted the evidence that decided the question. That remains exactly true. The writer was GitHub's automation.The fs.gg-side residue, which is a contract gap and not an engine fault.
done'sDone.verifyre-reads the merged closer; it does not consult the branch run. So nothing in the contract requires a worker to wait for the post-merge signal — the engine permits premature completion without performing it. A worker who runsdoneimmediately after merge gets a stamp with the same evidential gap, and the contract will not object. That is a real finding and a much smaller one than the retracted claim; state it that way or not at all.The measurement that is unaffected
The disjointness result stands, and is independent of who writes
Done— it is about check sets:32673232997ran 15 jobs;mainrun32674732265skipped all 15.browser-delivery,full-qualification,integrity-sweep,protected-preflight,protected-verdict— are the ones that ran onmain.comm -12on the two sets returns empty.mainrun32674732265atf4004743: success, withfull-qualificationandprotected-verdictboth green.Dedupe note, since I am correcting rather than adding
This does not become a new row. Opening one would be
S.I.R.#278— the exact failure of refiling instead of correcting. The correction belongs on the instance it corrects. And per#2849: that packet is unclaimed work invisible to the scheduler; this is completion recorded on evidence that cannot cover it. Still different, still should not be merged — but instance 3's agent is now GitHub Projects automation, not fs.gg, which is the material change an analyst needs before adjudicating.EHotwagner commentedon Aug 24, 2026
Priority route: parent and coherent-set publication gate
The nine observations are not one executable touch set. #2903 is therefore the Critical parent/release gate, not a worker item. Its six minimum independently deliverable children are:
f80293fe7dd81813b5e6e9e553615a05ded2f7f59dbb16f3952de5214273faf250589191989f4f628a2434fcfccc14c415b9f3be9002c6841478459e3868b1a5landable redd1f5d27a1925b3a1f33815c5c61d4042d4e35c7e4c6fae52954b9e04aaca44604e9a8c478a9726fb21c19a9f05ad53fdb4353d223eca963eef393968264a487643a439e45b18f40b0c0ad8261b7c514349e40fc2f45537cb1f0f3638e4bf7b27#1933 and #2738 are not reopened: they established and implemented the board-field authority. The measured recurrence after they landed proves the remaining executable residue is narrower—atomic set operations plus a lint diagnosis—and #2907 carries exactly that.
Publication order — explicit operator decision
Publish after #2903, never before it. The next coordination coherent set must not be prepared, tagged, or published until all six children have verified completion receipts and #2903 has rolled up closed/Done. #2903 itself carries no implementation touch set; its terminal transition is the durable release-gate discharge. Publication remains a separate operator action under
publishing-and-deploymentafter that discharge.Board projection now records
Class=defect,Severity=Critical,Repo Scope=.github,Status=Blocked, andBlocked by=#2859,#2883,#2905,#2906,#2907,#2908. Every child is linked as a sub-issue and is Ready; no worker was claimed or dispatched.Verification: current
origin/main3cc364d1; #2865 merged as PR #2898 at6126898d; #2899 merged as PR #2900 at3cc364d1; current route receipt comment ids 5389410556/5389388207/5389388316/5389388428/5389388547; project-field writes returned green; issue bodies name exact file touch sets. Adjudicated bybrant-bea2.EHotwagner commentedon Aug 24, 2026
Corroboration — instance 9 hit a third time, and a reference-text gap two critics found independently
Instance 9 (host-owned state a critic is forced to author) recurred a third time tonight, and the third occurrence is the informative one.
On
EHotwagner/S.I.R.#263 / PR 336, the round-1repair-confirmationwait entry did not exist.review recordrefused correctly — "a matching durable review-wait entry is required before a critic record" — andfsgg-coord reviewreturnednoVerdict — dispatchSuccessor requires a new durable review-wait entry for this generation. The critic's full review was posted as prose but could not be structurally sealed.The first two critics facing this silently authored the entry themselves and carried on. The third surfaced it and stopped, solely because its dispatch told it the reference wins over the dispatch.
That is the diagnostic worth having: the omission is cheap enough for the next agent to paper over, so it never surfaces as a failure. Two of three occurrences left no trace. A protocol whose missing state is routinely repaired by whoever trips over it will report a clean history while accumulating exactly this.
Strengthened fix shape for instance 9: if the engine can refuse for a missing wait entry, it can create it. Every field is derivable from state the engine already holds — head, kind, round, claim generation. There is no information in that entry the caller supplies.
A separate, smaller finding: the packed reference has not absorbed the successor path
Two independent critics tonight reached for the same nonexistent prohibition.
Both were dispatched as successor critics on a repair round. Both read the packed
independent-reviewreference as saying a changed critic fails closed, and both flagged it as a conflict with their dispatch. One withdrew it after locatingdocs/coordination-engine-contracts.md:363-366, which states that aconfirmationby a different critic is accepted after achanges-requiredverdict. The other surfaced it without reconciling, as instructed.The engine settles it — typed state
dispatchSuccessor, per.github#2175. The reference's prose has not caught up, so a host verifying against the reference alone would read a successor round as fail-closed and refuse to dispatch one.Two critics arriving at the same wrong reading from the same document is evidence about the document, not about either critic. This is a reference-text gap, not a protocol defect and not a board row — recording it here rather than filing it separately.
It is also this packet's own thesis in miniature: the contract has two representations — the packed reference prose and the typed engine state — and they have drifted. The engine is authoritative and the prose is the stale copy.
EHotwagner commentedon Aug 24, 2026
Post-filing lane/glue check
The single permitted live check returned 3 lanes, 0 free, 3 occupied/no-startable, ceiling 0. This is a capacity-and-live-reservation result, not a reason to broaden or park the new rows.
dunlin-2c2f)brant-f894)swift-a730)LiveHandlers.fsplus both independent-review projectionsDeliveryApplication.fs,LiveHandlers.fs,DeliveryApplicationTests.fsLiveHandlers.fsNo new row is board glue. #2908 forms its own two-file lane. #2905/#2906/#2907 join the existing large coordination-engine lane through honest exact files; the report attributes that lane's actual glue to pre-existing
profile/README.md(#2835/#2884) andregistry/skills.yml(#2737/#2835/#2852). #2883 was absent from the captured repo-scoped snapshot because its priorRepo Scopewas cross-repo; this pass corrected it to.github, and its four declared paths are disjoint from all three captured claims.Verification:
scripts/fsgg-coord scan --repo .github | scripts/fsgg-coord lanes --text(one scan, captured at/tmp/2903-scan.json); exact intersections computed from that snapshot's issue bodies, with #2883 checked from its current issue declaration. Checked bybrant-bea2.EHotwagner commentedon Aug 24, 2026
Coordination churn reading — closed 24-hour window
Window
2026-08-23T00:20:00Z–2026-08-24T00:20:00Z: 40 issues opened, 16 issues closed, net +24, beside 16 issues closed as the landed unit. This is pathological on rate: discovery was 2.5× closure and net growth exceeded the landed count.The dominant successor family is the hand-authored review/lifecycle protocol: #2846, #2853, #2859, #2865, #2883, and #2903 are successive failures around one typed-review programme. The remedy is the route recorded here: #2903 is the release-gated parent, #2859 carries the unified wait-authoring boundary, #2883 carries the remaining ceiling defect, and #2905 isolates post-merge completion. Further occurrences fold onto those mechanisms.
#2872 and #2908 are the broad class/evidence row and bounded implementation slice for caller-CWD engine resolution. No routed row merely caches a
scripts/check-*.pyverdict. The single lane scan found live coupling between held #2893 and #2859/#2905/#2906; #2883/#2907/#2908 are path-disjoint from all three named live claims but cannot start while all three fleet slots are occupied.{ "schema": "fsgg.coord.churn-reading/v1", "window": {"start":"2026-08-23T00:20:00Z","end":"2026-08-24T00:20:00Z"}, "rowsOpened": 40, "rowsClosed": 16, "netRowDelta": 24, "itemsLanded": {"count":16,"unit":"issues closed"}, "causeInstances": {"found":[{"cause":"tier-4 engine selection depends on caller cwd","rows":[".github#2872",".github#2908"]},{"cause":"review/lifecycle state is re-authored outside the typed authority","rows":[".github#2846",".github#2853",".github#2859",".github#2865",".github#2883",".github#2903"]}]}, "successorGeneratingCauses": {"found":[{"cause":"the typed-review programme repaired individual authored spellings while entry, completion, ceiling, and recovery remained separate manual representations","rows":[".github#2846",".github#2853",".github#2859",".github#2865",".github#2883",".github#2903"]}]}, "alreadyDerived": {"searchedNotFound":"Compared the routed packet conditions with the scripts/check-*.py corpus and inspected the named check references; none continuously derives these live review-wait, completion, landable-reason, set-mutation, or tier-4 binding conditions."}, "jointlyRedCandidates": {"found":[{"rows":[".github#2859",".github#2893"],"gate":"exact touch-set reservation on LiveHandlers.fs and the independent-review projections"},{"rows":[".github#2905",".github#2893"],"gate":"exact touch-set reservation on DeliveryApplication.fs, LiveHandlers.fs, and DeliveryApplicationTests.fs"},{"rows":[".github#2906",".github#2893"],"gate":"exact touch-set reservation on LiveHandlers.fs"}]}, "remedy": "As of 2026-08-24T00:39:00Z, retain #2903 as the release gate; let held #2893 finish before #2859/#2905/#2906; schedule disjoint #2883/#2907/#2908 when capacity opens; fold future instances onto these mechanisms.", "prose": "The prose reading immediately above this document on FS-GG/.github#2903." }Verification: the cached REST corpus refreshed at
2026-08-24T00:20:36Z, filtered locally on the explicit half-open window and excludingpull_request, returned 40 opened/16 closed; the one permitted scan→lanes pass returned 3 lanes, 0 free, 3 occupied, ceiling 0. Reading bybrant-bea2.EHotwagner commentedon Aug 24, 2026
Two more instances, both hit by the host within one hour, both of the packet's own shape
Instance 10 — a ledger comment is parsed whole, with no affordance separating payload from commentary
Fixing the missing wait entry of instance 9, the host authored one and appended eight lines of governance prose after the closing brace. The engine then refused the critic's record:
And it took out the read path, not just the write path.
fsgg-coord review <ref> --pr Nwent from a cleandispatchSuccessorstate toUNDETERMINEDfor the entire PR. One malformed comment blinds every reader of that PR's review state.Measured by critic
rook-0b28, which parse-tested all fourreview-waitcomments on the PR and isolated exactly one as malformed. Notably:review waitwrites marker + JSON with no trailing bytes on its own. The fault is not in the tool's output — it is in the absence of any affordance telling a human that appending context to that output destroys it. The marker announces a format; nothing enforces or warns.Fix shape: accept a documented prose section after the JSON, or have
lintflag trailing bytes on anyfsgg:*/v1ledger comment. Either makes it unrepresentable. As it stands, the only signal is a refusal several steps later, on a different verb, naming a byte position.This is the packet's thesis landing on the packet's author: the comment body is two representations — machine payload and human record — sharing one container with nothing distinguishing them.
Instance 11 — the
#2859rule is stated for one field and enforced on three.github#2859is documented as being about the wait completion'sevidenceRef: cite the structured record, not the prose marker. Correct and incomplete.The same rule governs the record's own back-references. A first seal attempt was refused with:
Both fields had pointed at the round-0 prose marker. The engine wants the structured record in both positions.
The error message is the only place that says so. A critic that has correctly internalised
#2859for the wait completion will still get these two wrong, because the rule is presented as a property of one field rather than as a general invariant — structured records cite structured records.Fix shape: state it as the invariant it is, or accept a prose-marker URL and resolve it to its record. The engine holds both artifacts and can map between them; every one of these refusals is the caller being asked to perform a lookup the engine could do.
Both instances cost a round-trip each and neither produced a wrong artifact, because in both cases a critic declined to silently repair host-authored state and reported instead. That is worth noting as a control: the two failures that left no trace tonight were the ones an agent quietly fixed.
EHotwagner commentedon Aug 24, 2026
CORRECTION — the "reference-text gap" reported earlier is withdrawn. The contract is correct; the checkout is stale.
Earlier in this packet I recorded that "the packed reference's prose has not absorbed the successor path," on the strength of two independent critics reading a changed-critic prohibition that the engine does not enforce. That diagnosis is wrong, and I relayed it to a third critic mid-flight before catching it.
Verified directly, both copies of
.claude/skills/pnext-item/references/independent-review.md:origin/maindispatchSuccessoras "what makes the fresh-successor handoff legal at all", noting observed chains have run four different critics across their roundsSo the contract already carries the correction, explicitly, and even records that the old rule stood wrong for four rounds. The prose absorbed the successor path. What did not update was the tree the agents were reading it from.
The real finding, which is worse than the one I filed
The contract is distributed as a file in a working tree, so an agent in a stale tree silently obeys a superseded rule — with no version, no staleness signal, and no way to tell.
The primary checkout on this machine sits at
f62d6e2(2026-08-23). Every agent that read the contract from there tonight got the 427-line copy. The specific rule it serves would have made every successor round run tonight look illegal — and two critics duly flagged their own dispatches as contract violations. One withdrew after finding the correct text elsewhere; one surfaced it unreconciled; a third was told the wrong diagnosis by me.This is the same root as instance 8 (
scripts/fsgg-coordresolvingdotnet tool runfrom the caller's cwd, so a stale checkout answers 0.71.0 whileorigin/mainpins 0.72.0). One stale tree silently served both a superseded engine and a superseded contract, and neither announced itself. The engine at least prints a version when asked; the contract prints nothing.Fix shape
fsgg-coordverb that prints the binding contract's revision alongside the engine's.--versioncovers both. A contract distributed bygit checkouthas exactly the failure mode of any other hand-synced copy — which is, again, this packet's thesis.Method note
I nearly replaced one unverified claim with another. The critic reporting this cited the head's copy as containing a
different-critic-after-changes-required→acceptedmapping;git grepfinds that string in neither copy. The substance of its report is correct and the line-427 sentence is stronger evidence than the string it quoted — but I checked before re-filing, and the check changed what I wrote. Recorded because the failure mode this packet documents is precisely a claim propagating past the point where anyone re-derived it.EHotwagner commentedon Aug 24, 2026
Coordination churn reading — closed 24-hour window
Window
2026-08-23T02:00:00Z–2026-08-24T02:00:00Z: 44 issues opened, 18 issues closed, net +26, beside 18 issues closed as the landed unit. The rate remains pathological: openings were 2.44× closures and net growth exceeded the landed count.The dominant repeated cause remains hand-authored review/lifecycle state. #2846, #2853, #2859, #2865, #2883, and #2903 are successive instances around the typed-review programme; today's #2852/PR #2911 repair-entry mismatch is evidence on #2859, not a seventh mechanism row. The specific cause is that the caller authored
repair-confirmation:0on a zero-record fresh PR while the engine requiredinitial-review:0. The remedy is the existing #2903 route: retain #2859 as the engine-derived wait-authoring owner and fold further entry/generation instances there.#2872 and #2908 remain class/evidence and bounded implementation slice for caller-CWD engine selection. No open routed row in the #2903 family merely caches a
scripts/check-*.pyresult. I compared the family's declared gate subjects and exact paths for a pair that could be individually green but jointly red; none was found. The current #2852/#2859 interaction is sequential protocol state, not a shared gate-corpus coupling.As observed at
2026-08-24T02:06:00Z, #2883 has landed and #2903 reports one of six children complete. The publication remedy remains #2903 complete → fresh #2893 coordination release cycle → #2852 coherent-set publication and receiver rollout. No publication step should leapfrog the parent gate.{ "schema": "fsgg.coord.churn-reading/v1", "window": {"start":"2026-08-23T02:00:00Z","end":"2026-08-24T02:00:00Z"}, "rowsOpened": 44, "rowsClosed": 18, "netRowDelta": 26, "itemsLanded": {"count":18,"unit":"issues closed"}, "causeInstances": {"found":[{"cause":"review/lifecycle state is re-authored outside the typed authority","rows":[".github#2846",".github#2853",".github#2859",".github#2865",".github#2883",".github#2903"]},{"cause":"tier-4 engine selection depends on caller cwd","rows":[".github#2872",".github#2908"]}]}, "successorGeneratingCauses": {"found":[{"cause":"individual review-state spellings were repaired while wait entry, generation, backlinks, completion, ceiling, and recovery remained separately authored","rows":[".github#2846",".github#2853",".github#2859",".github#2865",".github#2883",".github#2903"]}]}, "alreadyDerived": {"searchedNotFound":"rg -n 'review wait|repair-phase|initial-review|repair-confirmation' scripts/check-*.py found no gate that continuously derives the live wait/ledger sequencing mismatch; the existing routed family conditions were compared with the check corpus."}, "jointlyRedCandidates": {"searchedNotFound":"Compared the open #2903 family declarations and the #2852/#2859 subjects for shared gate-corpus additions; no pair was found. The observed mismatch is sequential protocol state, not two independently green changes reaching one gate corpus."}, "remedy": "As of 2026-08-24T02:06:00Z, fold the #2852/PR #2911 entry mismatch onto #2859; keep #2903 as the release gate; complete all remaining children before the fresh #2893 coordination release cycle, then permit #2852 coherent-set publication and receiver rollout.", "prose": "The prose reading immediately above this document on FS-GG/.github#2903." }Verification:
scripts/fsgg-coord issues .github --state all --refresh, filtered locally over the explicit half-open interval and excluding entries carryingpull_request, returned 44 opened/18 closed; GitHub API reads of #2903's sub-issues and #2883 established six children/one complete. Reading byheron-695a.EHotwagner commentedon Aug 24, 2026
Instance 12 — an owed final commit forces a round past the ceiling, so an item that did everything right cannot be accepted
New, measured tonight, and structurally worse than instance 4 (
.github#2883) because no rule was broken to reach it.The setup
EHotwagner/S.I.R.#263completed a full ordinary chain on PR 336 — initial plus three confirmations, four different critics, round 3passwith no material findings.The item then owed one further commit: an audit-binding ledger re-seal, which by policy must be the branch's final commit, because its digests are of the tree being merged. The host pushed it and opened a fresh
initial-review:0wait, reasoning that a new head begins a new review generation.What the engine does instead
The chain is bound to the item and PR, not to the head. A new head continues the same chain at the next round — round 4 — which the ceiling forbids outright.
So both routes are closed:
initial-review:0wait and recordrepair-confirmation:4.github#2883)Why this is not
#2883restated#2883is a passing round-4 confirmation trips the ceiling — reached by opening a fourth round. Here nothing improper was done. The chain passed at round 3. The additional commit is required by an unrelated policy. The item is wedged by the interaction of two rules that are individually correct:EHotwagner/S.I.R.#339: accepting evidence that does not cover what is merged.Together they mean: any item owing a post-review commit must either exceed the round ceiling or merge on a review of a different tree. There is no third option inside the contract.
The near-miss, and why this was recoverable
The reviewing critic declined to write a record. Its round-0 draft matched the wait the host had opened, so
review recordmay well have accepted it — appending a second initial marker to an append-only ledger on a chain the contract says has exactly one. It surfaced the conflict to the host instead.That is the fourth time tonight an agent stopped at malformed or unauthorized host-owned state rather than papering over it, and the second time doing so was the only reason a defect became visible. The two failures that left no trace tonight were the ones an agent quietly repaired.
Remedy used, and its cost
The item is resetting onto a fresh PR carrying the identical tree. A new PR number yields a new subject and therefore a new chain, so one initial review at round 0 covers a tree four critics have already examined. This is the same remedy
S.I.R.#249used for#2883.Cost: a full PR reset and one further review cycle, for an item with zero outstanding findings. Third reset of the session attributable to the round ceiling.
Fix shape
passis not in a repair loop, and the ceiling exists to stop repair loops. This also fixes#2883.Any one of these removes the wedge. The current arrangement guarantees it for every item that owes a seal, which on this repository is every item touching a file with an audit-binding exception.
EHotwagner commentedon Aug 24, 2026
Instance 3, measured to the second — the repository-side confirmation
Worker
shrike-00f9timed its own merge of PR 342 and produced the exact sequence this row has been describing indirectly:The row called itself
Doneeleven minutes before the evidence existed. The worker ran nodoneand norelease— theCloses #NNNkeyword closes the issue, the board row follows it, and the claim drops. All three transitions are bound to the merge; none is bound to verification.Why this reframes the row
It is tempting to read the nineteen items marked complete on green PR runs — while
mainwas red from019abe6cfor hours — as nineteen agents failing to look. It is not. It is the automation calling done at merge, every time, and no agent following the contract can prevent it. The one worker tonight that refused to report done on a PR's green (#335) still got aDonerow at merge; all it could control was its own report.Combined with this row's measurement — that the PR and branch check sets have an empty intersection — the two facts compose into the whole defect:
What that means for the fix
An acceptance criterion above asks that a green PR which would land a red
mainbe "detectable before the item is reported done." That is not achievable by agent discipline, and this row should not be closed by instructing workers to check harder. Something other than the closing keyword has to own theDonetransition — a provisional state pending the branch run, or a completion gated on a post-merge receipt.The upstream half is
FS-GG/.github#2903, instance 3, where the residue is thatdoneverifies the merged closer and not the branch run: the contract permits premature completion without performing it. This row is where the repository actually performs it.Two live confirmations, hours apart
28d3701f—mainred from019abe6cat 16:35, two further merges landed on top, nineteen items complete.60b3d0f8— merged 03:00:16Z,Doneat 03:00:18Z,mainFAILURE at ~03:11Z. Cause was [fsgg-coord]batchhanded out an item whoseBlocked bynames an OPEN issue (blocked=falsewith an open blocker) — evidence, mechanism unpinned #343, unattributable to the merge — but nothing in the sequence could have known that, because nothing waited to ask.EHotwagner commentedon Aug 24, 2026
Controlled shutdown checkpoint — 2026-08-24
No new lanes, acceptance, merge, or publication should start from this checkpoint without first re-reading live typed state.
.github#2906/ PR fix(coord): name red landable checks #2917: remote head51985f96373fb538b6b2ef76b8fe3dc60372b31f; successor PASS comment 5392340548, digest77fcb9e21b2828b4d0a4a4ef4c725011f3dd8341c619aadcede529c82f919b36; wait completion 5392342758; live statepassedAwaitingChecks. Resume with hosted-check census, then host acceptance only if substantive checks are terminal green..github#2907/ PR fix(coord): make Blocked by mutations set-safe #2916: remote head8f8b0bcb4a415dee27fc81a3d8dab15b87015fd0; clean worktree; durablerepair-confirmation:3wait 5392371907; live stateawaitingSuccessorReview. Resume by dispatching one fresh final ordinary critic (gpt-5.6-sol, medium). Do not enter ordinary round 4 if it returns changes-required.FS.GG.Templates#417/ PR [cross-repo]fsgg-coord nextfails open — it recommends items with noPaths:and never checks in-flight claims #431: remote head6f474b7b6ed206a43527fef795c981cb61d30320; clean/process-free worktree; durable checkpoint comment 5392460754. Do not dispatch a successor yet: focused composition remains red at 106 passed / 1 failed after its system-Chromium journey passes. Resume by diagnosing only the post-browser composition assertion, then enterrepair-confirmation:2when green..github#2905remains blocked by.github#2907because of overlapping completion fixtures. Reconcile/unblock only after [coord] Give the set-valued Blocked by field atomic add/remove semantics and lint inert body declarations #2907 lands..github#2908is merged and awaiting the parent-ownedcoherent-set-0.75.2-release/release-verificationobligation. Do not publish until the remaining [cross-repo] The protocol keeps a second, hand-authored representation of state the engine already holds — one shape behind most of a day's rework #2903 children have landed and the parent release gate is satisfied.All three active candidate branches above were verified pushed; their worktrees were clean at handoff. No task-owned test, mutation, browser, server, watcher, or parity process remained. Shared checkout untracked files were intentionally left untouched because they predated these active lanes and are outside their touch-sets.
EHotwagner commentedon Aug 24, 2026
Typed SDD board re-baseline — 2026-08-24T08:39:47Z
This is the canonical impact map for every OPEN, non-Done Coordination-board item at the instant above. It applies the Typed SDD / canonical protocol-kernel design without inventing a new project field.
The relationship is architectural, not a
Blocked byedge and not permission to postpone a bounded defect. Existing status, claim, priority, and acceptance remain authoritative. Implementations in the first three groups must avoid introducing a new independent protocol vocabulary or state representation; where the kernel is not yet available, preserve the behavior as a regression fixture and name the future canonical concept explicitly.sddbehavior while adding an explicit futuretyped-sddlane; do not flip the default in these rows.Intake and execution rule
none,sdd, andtyped-sdddistinct.sddremains the omitted-value default until the separately gated default-flip decision.No rows were closed, blocked, reprioritized, or re-scoped by this pass.
Verification:
scripts/fsgg-coord scan --fresh --include-backlog -n 400at 2026-08-24T08:38Z returned 40 OPEN, non-Done items; local exhaustive classification covered each exactly once.scripts/fsgg-coord lint --jsonis the post-write mechanical check. Design authority: merged PR #2920, commit44878a8bdfd522340fd62f11a77eb8d854a83e4e.Analyst:
godwit-ea24EHotwagner commentedon Aug 25, 2026
Release-verification evidence for the parent-owned
coherent-set-0.75.2-releaseobligation (recovered while completing child #2908).Verification:
coherent-set/v0.75.2, GitHub Packages downloads, nuget.org flat-container downloads, and peeledkit/v0.75.2,drivers/v0.75.2,coord-engine/v0.75.2tags.sourceSha=0d56bb104da22478dfef72825f8cf19425635ed0,releaseId=github:0.75.2,policyVersion=release-saga/1.FS.GG.Kit,FS.GG.Drivers, andFS.GG.Coord.Cli; all three were downloaded independently from both feeds (6/6 observations), and all three peeled tags resolve to the same source SHA.scripts/release-saga.py record-observedindependently recomputed and matched the payload identities; the instrument therefore distinguished archive identity from payload identity rather than equating every download.assert-identitypassed;record-observedreportedgithub=verifiedandnuget=verified; the derived phase isfeeds-complete. Payload SHA-256: Coord.Clifa1b8839f3dbf253ca740f05f3237d8e2504119e15024460c2af1df9f2057f85, Drivers87271a2e84b3860cabb88695e8dd65c02e79bd571fd9010ebd8142237977cf30, Kitae6183789eaa293a4b8d2a4d36e627d2a919b9935031ecd64989cdd071336ef2. Every downloaded nuspec names repository commit0d56bb104da22478dfef72825f8cf19425635ed0.Recorded by minted worker
shrike-51a3while holding the converged #2908 recovery claim.fs-gg-cross-repo-dispatch commentedon Aug 25, 2026
EHotwagner commentedon Aug 29, 2026
Architecture-audit evidence folded into this class row:
No new row was created. For v1 this supports only a bounded truth-label/validator-coherence correction if currently necessary; the structural remedy belongs to v2 authority adapters and qualification oracles.
Filed by:
teal-218fVerification:
.agents/skills/work-roadmap/scripts/validate-critique-state.py; cycle/feedback validation paths under.agents/skills/work-boardand.agents/skills/work-roadmap; ADR-0078 v1 investment boundary; consolidated evidence at the parent URL above.