Skip to content

[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

Open
6 of 6 issues completed

Description

@EHotwagner

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.

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.
The delivery --apply / Complete coupling 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:

  1. Engine-constructed generation tokens; no agent-authored wait JSON.
  2. Record references by digest, not by a URL that must satisfy an invisible invariant.
  3. Merged and Verified as distinct lifecycle states.
  4. No documented-but-unreachable transitions (.github#2883).
  5. landable returns its reason.
  6. Set-valued fields get set-valued verbs.
  7. One medium per fact, or a lint that catches the inert one.
  8. Tool resolution independent of caller cwd.
  9. 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

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.
  • Complete is a separate transition delegating to the done transaction, whose own comment
    states that Done.verify "re-reads the merged closer and refuses a stale or unrelated PR before
    any write."
  • The implementer never invoked Complete; it ran done --flip only 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

  1. The measurement is untouched. The PR and branch check sets have an empty intersection —
    that is about check sets, not about who writes Done. It remains the evidentiary core of this
    instance and is filed repository-side as EHotwagner/S.I.R.#339.
  2. 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. main came back green
    (run 32674732265 at f4004743 — protected-preflight, integrity-sweep, full-qualification,
    protected-verdict all success), so the record was unjustified when written, not wrong.
  3. The genuine fs.gg residue, which is real but small: done verifies the merged closer and
    not the branch run. So the contract permits premature completion without performing it.
    A Done that 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.

Activity

  1. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor
    No description provided.
  2. moved this to Backlog in Coordinationon Aug 24, 2026
  3. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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 --apply does not couple completion to the merge

    I reported that guardedLand performs the Complete transition in one action, writing Done and releasing the claim at merge time. That is false, and the implementation says so plainly.

    src/FS.GG.Coord.Cli.Lifecycle/LiveHandlers.fs:528 — the guardedLand apply path calls exactly one writer:

    DeliveryApplication.guardedLanding ... (fun () -> Writes.mergeAtHead ctx.Transport target pr.Value head)

    It merges. It writes no board status and releases no claim. Complete is a separate transition (Delivery.Next transition, CompletionDecision.ProjectCompletion when transition.Action = Delivery.Complete) which delegates to the done transaction, and the code comment there states the guard I wrongly said was absent:

    Delegate the coupled close / board-Done / own-claim-release sequence to the existing done transaction. Its Done.verify re-reads the merged closer and refuses a stale or unrelated PR before any write.

    So the engine does not complete at merge, and my instance does not demonstrate that it does. I never invoked Complete; I ran done --flip only after the branch run resolved.

    What actually wrote Done, established rather than assumed

    The S.I.R. board is user project 6. Its built-in GitHub Projects workflows:

    enabled=True   Item closed
    enabled=True   Pull request merged
    enabled=True   Auto-close issue
    

    Closes #335 closed the issue at merge, and the Item closed / Pull request merged project automation set Status = 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:

    1. The outcome, correctly attributed. Completion was recorded before it could be known, and happened to be right. Done was written at merge time, before full-qualification had even been created — it needs: 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.

    2. The fs.gg-side residue, which is a contract gap and not an engine fault. done's Done.verify re-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 runs done immediately 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:

    • PR run 32673232997 ran 15 jobs; main run 32674732265 skipped all 15.
    • The 5 that skipped on the PR — browser-delivery, full-qualification, integrity-sweep, protected-preflight, protected-verdict — are the ones that ran on main.
    • comm -12 on the two sets returns empty.

    main run 32674732265 at f4004743: success, with full-qualification and protected-verdict both 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.

  4. moved this from Backlog to Blocked in Coordinationon Aug 24, 2026
  5. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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:

    instances executable owner route
    1, 2, 9 — review-wait entry/generation and completion authority #2859 SDD-required, revision 3, digest f80293fe7dd81813b5e6e9e553615a05ded2f7f59dbb16f3952de5214273faf2
    3 — merge is projected as verified completion #2905 SDD-required, digest 50589191989f4f628a2434fcfccc14c415b9f3be9002c6841478459e3868b1a5
    4 — verdict-blind ceiling #2883 existing lightweight owner; #2865's unreachable-repair-phase half is merged
    5 — unexplained landable red #2906 lightweight, digest d1f5d27a1925b3a1f33815c5c61d4042d4e35c7e4c6fae52954b9e04aaca4460
    6, 7 — set-valued dependency mutation and inert body projection #2907 SDD-required, digest 4e9a8c478a9726fb21c19a9f05ad53fdb4353d223eca963eef393968264a4876
    8 — tier-4 caller-CWD engine selection #2908 lightweight, digest 43a439e45b18f40b0c0ad8261b7c514349e40fc2f45537cb1f0f3638e4bf7b27

    #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-deployment after that discharge.

    Board projection now records Class=defect, Severity=Critical, Repo Scope=.github, Status=Blocked, and Blocked 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/main 3cc364d1; #2865 merged as PR #2898 at 6126898d; #2899 merged as PR #2900 at 3cc364d1; current route receipt comment ids 5389410556/5389388207/5389388316/5389388428/5389388547; project-field writes returned green; issue bodies name exact file touch sets. Adjudicated by brant-bea2.

  6. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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-1 repair-confirmation wait entry did not exist. review record refused correctly — "a matching durable review-wait entry is required before a critic record" — and fsgg-coord review returned noVerdict — 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-review reference as saying a changed critic fails closed, and both flagged it as a conflict with their dispatch. One withdrew it after locating docs/coordination-engine-contracts.md:363-366, which states that a confirmation by a different critic is accepted after a changes-required verdict. 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.

  7. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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.

    child #2852 (dunlin-2c2f) #2854 (brant-f894) #2893 (swift-a730) startability
    #2859 disjoint disjoint LiveHandlers.fs plus both independent-review projections waits for #2893
    #2883 disjoint disjoint disjoint structurally startable when a fleet slot opens
    #2905 disjoint disjoint DeliveryApplication.fs, LiveHandlers.fs, DeliveryApplicationTests.fs waits for #2893
    #2906 disjoint disjoint LiveHandlers.fs waits for #2893
    #2907 disjoint disjoint disjoint structurally startable when a fleet slot opens
    #2908 disjoint disjoint disjoint structurally startable when a fleet slot opens

    No 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) and registry/skills.yml (#2737/#2835/#2852). #2883 was absent from the captured repo-scoped snapshot because its prior Repo Scope was 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 by brant-bea2.

  8. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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-*.py verdict. 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 excluding pull_request, returned 40 opened/16 closed; the one permitted scan→lanes pass returned 3 lanes, 0 free, 3 occupied, ceiling 0. Reading by brant-bea2.

  9. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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:

    review record: refused: the review-wait ledger is invalid:
    '*' is invalid after a single JSON value. Expected end of data.
    

    And it took out the read path, not just the write path. fsgg-coord review <ref> --pr N went from a clean dispatchSuccessor state to UNDETERMINED for the entire PR. One malformed comment blinds every reader of that PR's review state.

    Measured by critic rook-0b28, which parse-tested all four review-wait comments on the PR and isolated exactly one as malformed. Notably: review wait writes 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 lint flag trailing bytes on any fsgg:*/v1 ledger 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 #2859 rule is stated for one field and enforced on three

    .github#2859 is documented as being about the wait completion's evidenceRef: 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:

    initialReview must equal the actual current generation's initial comment URL;
    precedingReview must equal the actual immediately preceding structured comment URL
    

    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 #2859 for 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.

  10. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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:

    copy lines what it says about a changed critic
    origin/main 554 line 427: "A changed critic does NOT fail closed, and this contract said it did for four review rounds." — and lines 431-437 describe dispatchSuccessor as "what makes the fresh-successor handoff legal at all", noting observed chains have run four different critics across their rounds
    primary working checkout 427 line 318 lists "a changed critic" among the conditions that fail closed — the superseded rule

    So 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-coord resolving dotnet tool run from the caller's cwd, so a stale checkout answers 0.71.0 while origin/main pins 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

    • Version the contract and make the version observable — a header the reader can compare, or a fsgg-coord verb that prints the binding contract's revision alongside the engine's.
    • Better: serve it from the same place as the engine, so --version covers both. A contract distributed by git checkout has exactly the failure mode of any other hand-synced copy — which is, again, this packet's thesis.
    • Failing both: agents must be told to read the contract from a current worktree, never from the primary checkout. That is a workaround, not a fix, and it is the same instruction already required for the engine.

    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 → accepted mapping; git grep finds 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.

  11. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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:0 on a zero-record fresh PR while the engine required initial-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-*.py result. 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 carrying pull_request, returned 44 opened/18 closed; GitHub API reads of #2903's sub-issues and #2883 established six children/one complete. Reading by heron-695a.

  12. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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.#263 completed a full ordinary chain on PR 336 — initial plus three confirmations, four different critics, round 3 pass with 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:0 wait, reasoning that a new head begins a new review generation.

    What the engine does instead

    noVerdict — the durable review wait does not authorize dispatchSuccessor:
      expected  'b921d04b…:repair-confirmation:4'
      got       'b921d04b…:initial-review:0'
    

    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:

    route outcome
    complete the initial-review:0 wait and record the engine does not treat it as the authorized next action
    open the generation it names, repair-confirmation:4 forbidden by the ceiling; parks the item (.github#2883)
    merge without acceptance forbidden by the merge contract

    Why this is not #2883 restated

    #2883 is 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:

    1. Acceptance is bound to an exact SHA — correct, and its absence is the defect filed as EHotwagner/S.I.R.#339: accepting evidence that does not cover what is merged.
    2. A re-seal must be the final commit — correct, because its digests describe the merged tree.

    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 record may 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.#249 used 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

    • Let the ceiling consult the verdict. A chain whose latest verdict is pass is not in a repair loop, and the ceiling exists to stop repair loops. This also fixes #2883.
    • Or make a post-acceptance commit class explicit — a receipt or seal that the contract expects, reviewed as a bounded delta without consuming a repair round.
    • Or bind acceptance to a tree rather than a SHA where the delta is confined to declared receipt files.

    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.

  13. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    Instance 3, measured to the second — the repository-side confirmation

    Worker shrike-00f9 timed its own merge of PR 342 and produced the exact sequence this row has been describing indirectly:

    03:00:16Z   merged
    03:00:18Z   issue auto-closed COMPLETED · board row auto-flipped Done · claim auto-released
    03:00:19Z   main's run started
    ~03:11Z     that run: FAILURE
    

    The row called itself Done eleven minutes before the evidence existed. The worker ran no done and no release — the Closes #NNN keyword 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 main was red from 019abe6c for 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 a Done row 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:

    Completion is stamped from evidence that, by construction, cannot cover the thing being completed.

    What that means for the fix

    An acceptance criterion above asks that a green PR which would land a red main be "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 the Done transition — 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 that done verifies 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

  14. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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.

    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.

  15. EHotwagner commented on Aug 24, 2026

    @EHotwagner
    ContributorAuthor

    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 by edge 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.

    Relationship Live items Disposition
    Kernel concept (24) #2130, #2737, #2835, #2837, #2841, #2842, #2843, #2846, #2848, #2850, #2853, #2857, #2862, #2863, #2867, #2871, #2874, #2893, #2896, #2903, #2905, #2906, #2907, #2908 Defines or exercises canonical facts, evidence, identity, authority, lifecycle state, commands, events, retries, or mutations. Land the bounded repair, but make its types and tests inputs to the shared kernel rather than a new local dialect.
    Kernel prerequisite (13) #266, #2695, #2728, #2729, #2774, #2840, #2844, #2849, #2852, #2858, #2864, #2872, #2873 Required enforcement, modularity, parser strictness, provenance, identity, or execution infrastructure. Proceed independently; the kernel depends on this work being trustworthy.
    Conformance / migration (2) #2845, #2884 Exercises compatibility with Standard SDD or the consumer-facing lifecycle/default-selection surface. Preserve current sdd behavior while adding an explicit future typed-sdd lane; do not flip the default in these rows.
    Orthogonal (1) FS-GG/FS.GG.Templates#417 Product/browser baseline work; no Typed SDD scope change.

    Intake and execution rule

    1. New protocol-bearing findings are checked against this class row and the design before receiving a new number. If the kernel concept is already represented, the finding is evidence on that row.
    2. A bounded repair may land before the shared kernel, but its acceptance must pin the semantic distinction as a typed test/fixture and must not establish another authoritative prose/string representation.
    3. Default-facing work must keep none, sdd, and typed-sdd distinct. sdd remains the omitted-value default until the separately gated default-flip decision.
    4. This map is re-derived when a listed row closes or materially changes scope; it is not copied into issue bodies.

    No rows were closed, blocked, reprioritized, or re-scoped by this pass.

    Verification: scripts/fsgg-coord scan --fresh --include-backlog -n 400 at 2026-08-24T08:38Z returned 40 OPEN, non-Done items; local exhaustive classification covered each exactly once. scripts/fsgg-coord lint --json is the post-write mechanical check. Design authority: merged PR #2920, commit 44878a8bdfd522340fd62f11a77eb8d854a83e4e.

    Analyst: godwit-ea24

  16. EHotwagner commented on Aug 25, 2026

    @EHotwagner
    ContributorAuthor

    Release-verification evidence for the parent-owned coherent-set-0.75.2-release obligation (recovered while completing child #2908).

    Verification:

    • subject: coherent-set draft coherent-set/v0.75.2, GitHub Packages downloads, nuget.org flat-container downloads, and peeled kit/v0.75.2, drivers/v0.75.2, coord-engine/v0.75.2 tags.
    • authority: the draft release manifest owns the three-package census and source identity; each feed owns the externally observed archive bytes.
    • revision: manifest sourceSha=0d56bb104da22478dfef72825f8cf19425635ed0, releaseId=github:0.75.2, policyVersion=release-saga/1.
    • census: the manifest enumerates exactly FS.GG.Kit, FS.GG.Drivers, and FS.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.
    • positive control: raw nuget.org archive SHA-256 values differ from the draft/GitHub Packages values because NuGet adds its signature, while scripts/release-saga.py record-observed independently recomputed and matched the payload identities; the instrument therefore distinguished archive identity from payload identity rather than equating every download.
    • result: assert-identity passed; record-observed reported github=verified and nuget=verified; the derived phase is feeds-complete. Payload SHA-256: Coord.Cli fa1b8839f3dbf253ca740f05f3237d8e2504119e15024460c2af1df9f2057f85, Drivers 87271a2e84b3860cabb88695e8dd65c02e79bd571fd9010ebd8142237977cf30, Kit ae6183789eaa293a4b8d2a4d36e627d2a919b9935031ecd64989cdd071336ef2. Every downloaded nuspec names repository commit 0d56bb104da22478dfef72825f8cf19425635ed0.

    Recorded by minted worker shrike-51a3 while holding the converged #2908 recovery claim.

  17. moved this from Blocked to Backlog in Coordinationon Aug 25, 2026
  18. fs-gg-cross-repo-dispatch commented on Aug 25, 2026

    @fs-gg-cross-repo-dispatch
    Contributor
    No description provided.
  19. EHotwagner commented on Aug 29, 2026

    @EHotwagner
    ContributorAuthor

    Architecture-audit evidence folded into this class row:

    • The cycle ledger accepts a caller-authored source/board snapshot and proves its internal consistency, while the surrounding workflow can present that receipt as live-source truth. The engine/source already owns the fact; the caller authors a second representation.
    • The roadmap premerge critique validator permits terminal shapes that the later durable cycle validator refuses, so two validators represent one completion fact differently and the stronger answer arrives only after merge.

    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-218f

    Verification: .agents/skills/work-roadmap/scripts/validate-critique-state.py; cycle/feedback validation paths under .agents/skills/work-board and .agents/skills/work-roadmap; ADR-0078 v1 investment boundary; consolidated evidence at the parent URL above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions