Skip to content

Lifecycle-bounded referents modeled, not stringly: a next-rung trigger cannot rest on a work item's ending - #10582

Merged
gunbai-bot[bot] merged 1 commit into
mainfrom
session/tidy-heron-873
Sep 5, 2026
Merged

gunbai-bot[bot] merged 1 commit into
mainfrom
session/tidy-heron-873

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

What this is

The second decidable sub-case of gunbc.recurring_failure_mode.stale_claim_survives_its_own_correct_edit (the row itself lands in #10552; this PR cites it in annotations only, so nothing here depends on that merge).

That row states the ceiling per sub-case:

  • a citation naming a declared symbol is already checked by the parse-phase v1_compiler.cli_run.declaration_index route in v1_compiler.bin.claim_executor — verified, not assumed: the call sits inside the if required_ci_mode block and its corpus_findings push to phase_failures, so a finding is a phase failure and not a printed advisory. Nothing is owed there and nothing here touches it.
  • a citation naming a lifecycle-bounded referent "is decidable the same way if such referents are modeled rather than spelled into a String". That is this PR.

The defect

gunbc.guarantee_stall carried both halves of a next-rung trigger in one String:

next_rung_trigger: "node://adhoc-a3b0e05f-374 lands: the operation-argv binding wall materializes the operation"

so the condition a later reader must re-measure and the lane that was asked to deliver it were one opaque field. gunbc.guarantee_stall.roster records the consequence against a dated dashboard reading: three cited work items reported done while their conditions were unmet, and the roster had to state in a paragraph — "each trigger's operative half is the semantic clause after the colon" — a split that no field expressed. A paragraph asserting that separation is exactly what this class survives: it does not change when a node closes.

The construction

  • gunbc.lifecycle_bounded_referent (new) — DashboardWorkItemReferent, reusing gunbc.roadmap_model RoadmapNodeId rather than minting a second identity for one concept (§3), plus the one owner of the node:// spelling and the recogniser derived from it. One referent kind deliberately, not a one-armed coproduct.
  • NextRungTrigger { capability, awaiting } — the operative half and the asked lanes as separate, typed facts. climbs_when / climbs_when_awaiting.
  • stall_trigger_admission — three arms: admitted, capability empty, capability spells a referent. every_stall_trigger_is_admitted folds it over the live roster; every_stall_names_a_trigger now reads the same admission rather than re-spelling the empty test.
  • 35 rows migrated, of which four rested on a referent — operation_argv_binding_wall, external_model_scope_live_cover, observation_heartbeat_lockstep, gitattributes_committed_emit_drift. The roster paragraph counted three; the migration falsified that count and the paragraph now records the correction rather than being silently fixed, since a paragraph counting a population it did not derive is the same shape as the sentence above it.

Evidence

In test.claim.guarantee_stall_witness_test:

  • each admission arm asserted by cause, not through a Bool — an empty capability and a capability resting on a lane's ending are different defects with different repairs;
  • a positive control differing from the red in exactly one property: whether the referent sits inside the capability or beside it in awaiting, which catches a predicate keyed on the presence of an awaiting row rather than on the capability's text;
  • the roster fold in both directions — it would have redded on main against all four unmigrated rows;
  • the rendering asserted in both directions, so the provenance half is readable after the migration and comes from the referent's own module rather than a second spelling.

Rung, honestly

Rung 2. The invalid state stays writable and safety depends on the fold staying enrolled. The residual is declared, not implied: gunbc.guarantee_stall.trigger_capability_referent_free_by_construction_stall, ceiling 3, trigger named at capability grain (a decidable does-not-contain refinement over the capability field, sufficient for a literal site to fail to compile). Rung 4 is explicitly not claimed — a capability assembled at runtime is still spellable.

Not claimed: whether responsibility for an obligation survives a lane's closure. That is the class row's own next trigger and a different subject; the free-prose form of the class remains outside the modeled guarantee.

🤖 Generated with Claude Code

https://claude.ai/code/session_011ZiUUrreNAiyLhhDBuJDaX

…on one

The second decidable sub-case of
gunbc.recurring_failure_mode.stale_claim_survives_its_own_correct_edit: a
citation naming a DECLARED SYMBOL is already decided at ingestion by
v1_compiler.cli_run.declaration_index inside the required-CI parse phase, while
a citation naming a LIFECYCLE-BOUNDED REFERENT is decidable the same way only if
such referents are modeled rather than spelled into a String.

gunbc.guarantee_stall carried both halves of a next-rung trigger in one String,
so "node://adhoc-a3b0e05f-374 lands: the wall materializes the operation" read
as a trigger whose satisfaction condition was a work item reaching DONE. The
roster's own dated reading records three such lanes reaching done with their
conditions unmet, and had to state in a paragraph the split no field expressed.

NextRungTrigger now carries the operative half as `capability` and the asked
lanes as modeled DashboardWorkItemReferent rows in `awaiting`, reusing
gunbc.roadmap_model RoadmapNodeId rather than minting a second identity.
stall_trigger_admission refuses a capability that spells the declared
dashboard-node URI scheme, and every_stall_trigger_is_admitted folds it over the
live roster. Four rows were migrated by that wall -- the roster paragraph counted
three, which the migration falsified and the paragraph now records.

Evidence: test.claim.guarantee_stall_witness_test gains a discriminating red per
admission arm asserted BY CAUSE, a positive control differing in exactly one
property (referent inside the capability vs beside it), the roster-wide fold in
both directions, and a rendering assertion in both directions so the provenance
half is not lost by the migration.

The residual is declared rather than implied:
gunbc.guarantee_stall.trigger_capability_referent_free_by_construction_stall
records rung 2 with ceiling 3 and a capability-grain trigger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ZiUUrreNAiyLhhDBuJDaX
@gunbai-bot
gunbai-bot Bot merged commit 86be37f into main Sep 5, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/tidy-heron-873 branch September 5, 2026 17:21
@briansrls
briansrls restored the session/tidy-heron-873 branch September 5, 2026 17:23
gunbai-bot Bot pushed a commit that referenced this pull request Sep 5, 2026
…t resolve

THE ROW DID NOT HAVE A TYPO. next_rung_trigger was a String when that row landed
(#10281); the field became the NextRungTrigger product with climbs_when as its
constructor in a separate change (#10582). The two never met, 31 of 33 rows in
that directory adopted the constructor, and the closure enumerating them stopped
resolving: expected Product(NextRungTrigger), got Primitive(String).

THE FINDING IS THE GATE, NOT THE ROW. Both commits are ancestors of a GREEN
required floor -- main's required-witnesses-floor at 2f8819b reported SUCCESS
with both in its history. The gate did not lose a race; it RAN AND PASSED over a
rostered row that does not typecheck.
dag/test/claim/guarantee_stall_witness_test.dag imports gunbc.guarantee_stall.roster
and declares eleven test fns, verified, so the closure looks covered and is not.
The roster is enumerated somewhere the required floor does not compile, and until
that is closed any stall row can stop typechecking with no red anywhere.

The conversion carried in the previous merge is mechanical -- the same string,
wrapped in the constructor the field now requires -- and was made only because a
branch merging main cannot resolve this closure otherwise. This commit adds the
explanation to the row so a reader of the diff cannot conclude a stall row had a
typo, which is what an unexplained one-line constructor change looks like.

Not mine to repair: the gate hole belongs to whoever owns the required floor's
discovery closure, and it is worth more than either PR it turned up in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd
gunbai-bot Bot added a commit that referenced this pull request Sep 5, 2026
…tched nothing (#10605)

gunbc.guarantee_stall.roster's migration paragraph read "Two rows were
migrated by that change", enumerated FOUR rows, and then corrected itself with
"four, not the three this paragraph's dated reading counts". Three numbers,
one paragraph, and the leading one sourced from nothing in the text.

That is the paragraph's own thesis failing on the paragraph. Its subject is that
THE COUNT WAS THE FIRST THING THE MIGRATION FALSIFIED and that the correction is
recorded rather than silently made; it says in its own next sentence that a
paragraph counting a population it did not derive is the same shape as the
sentence above it. It was then that shape itself.

REPAIRED BY DELETING THE COUNT, NOT BY CORRECTING IT TO FOUR. Review 61056
proposed Two -> Four, which is right about the defect and leaves the paragraph
stating the same number twice -- a hand-maintained leading count beside the
enumeration it summarises, which is the second authority for one fact that goes
stale exactly the way this one did. The clause "four, not the three this
paragraph's dated reading counts" is KEPT: it is load-bearing history, the
recorded correction the paragraph exists to preserve, and the row explicitly
retains the dated reading as the measurement that established why the split was
needed. So the number is now stated once, by the clause that owns it, and the
opening no longer counts a population it does not derive.

Scope: one word in a leading // annotation. Under DESIGN.md section 4c the
annotation channel is erased before every semantic pass, so no occurrence
identity, semantic graph, semantic hash or emitted byte can move; no generated
projection carries the sentence, confirmed by grep over tracked .md/.rs and
independently by the guarantee-stall rows having no doc projection.

Raised by review 61056 on #10601, whose remaining content this supersedes: 38 of
that branch's 39 files are already byte-identical to main via #10582, and this
file was the only one still differing. Main carries the defect today, which is
why a one-word PR exists.

Co-authored-by: Brian Searls <briansrls@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 5, 2026
…rier

MAIN DOES NOT RESOLVE TODAY. gunbc.guarantee_stall.roster refuses with
'type mismatch: expected Product(NextRungTrigger), got Primitive(String)' at
floor_cost_basis_boundedness_stall. Every branch that merges main pays for it.

THE ORDER, MEASURED IN BOTH DIRECTIONS BECAUSE MY FIRST READING HAD IT BACKWARDS.
The carrier landed FIRST -- 86be37f (#10582) at 17:21:02 already declared
next_rung_trigger: NextRungTrigger and supplied climbs_when. The row landed
74 minutes later, 45074b4 (#10281) at 18:35:47, spelling a bare String.
git merge-base --is-ancestor answers YES carrier-before-row and NO the other way.
So #10582 stranded nothing and this is NOT a migration that missed a caller: an
old-format declaration landed onto a carrier that had already changed.

THE INCIDENT IS DENOMINATOR LOSS, NOT A LYING GATE. The required-floor-disposition
TSV (artifact 9975676354, run 33986383584 at 2f8819b, checked against its
published SHA-256) carries all ELEVEN identities of guarantee_stall_witness_test
as declined_outside_gate_closure / not_executed. The floor reported honestly, per
identity, that they did not run; the AGGREGATE reported SUCCESS over a population
that had already excluded them. Discovering an identity so it can receive a
disposition is not the same operation as preparing and executing its dependency
closure. The narrowing is
gunbc.recurring_failure_mode.preparation_membership_derived_from_the_execution_selector.

THE CONVERSION IS MECHANICAL AND VERIFIED AS SUCH, not asserted: the capability
text is byte-identical at 321 characters, and awaiting: [] discards nothing --
the original trigger carried no referent provenance. Before/after through the
SAME compiler route and the same binary (md5 bf014f57, built 2026-09-04, which
PREDATES this tree and is not claimed to be main's current compiler): the bad
initializer refuses with the diagnostic above, the converted row resolves with
zero resolve errors. Because both readings used one binary, its revision cannot
explain the difference.

LANDING THIS CLOSES NOTHING ABOUT ADMISSION. It restores resolution. The question
it leaves open is sharper than the one I started with and no census at the
carrier's own PR could have answered it: does admission validate an incoming
declaration against the carrier current at placement? A clean merge and an active
author do not establish compatibility with an intervening authority change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd
briansrls pushed a commit that referenced this pull request Sep 5, 2026
…r, and the production path is unmeasured on all 28 (#10545)

* Step 0 calibration: what a corpus run's silence about a resolution arm is not

std.reference_binding_observation pays to preserve six typed index-build
refusals as distinct arms of StructuralBindingResolution, and its header says
they are "never collapsed". This measures whether that preservation survives to
a consumer, on controlled fixtures, BEFORE the namespace cut's corpus run cites
the instrument -- because a cell that never fires and a cell that fires and
finds nothing are indistinguishable in a corpus report, and only a calibration
run separates them.

The matrix is 4 observation kinds x 7 resolution arms, and its axes come from
the vocabulary std DECLARES, bound by the total matches arm_of_resolution and
kind_of_observation: an arm added upstream makes this module fail to compile
rather than silently shrink the denominator. A denominator derived from the
cases the instrument managed to produce would report itself complete by
construction.

Each cell carries three separately-sourced facts rather than one verdict word:
a four-valued consumer standing, the measured provenance distinguishability,
and a four-valued production standing. The last is UNSUPPORTED BY THIS ROUTE
for every cell with the missing input named -- this census hands the consumer a
constructed resolution, so it never executes the production path and obtains no
evidence about producibility. That is a statement about the route, not about
the world, and it is deliberately weaker than "unreachable".

The measured result: only the four StructuralBindingResolved cells are
provenance-distinguished. The other 24 render byte-identically to each other
AND to a resolved-but-non-matching comparator, because
binding_outcome_from_resolution maps every non-Resolved arm to Absent and each
consumer arm maps Absent to the same refused(capability, failure) as a
structural non-match. The instrument writes the full matrix and then refuses --
the stopped-line audit of DESIGN section 5.

The controls live in the witness corpus rather than beside the instrument,
because test fn rows under dag/gunbc/instruments are discovered by nothing and
an inert lens is itself a lie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* The refusal path is the oracle; 28 was a measurement compared to itself

no_cell_is_sound_and_the_instrument_refuses asserted that exactly 28 cells were
unsound, which is a count standing where a check belongs. Two things wrong with
it, and the second is worse.

It has no independent referent: 28 is this run's own measurement of the live
population compared against itself, so automating its update would collapse the
assertion to measure() == measure(). Section 5 admits a numeric literal only
when it is grounded in a fixture, an external authority, a policy budget, or a
monotone debt contract, and this was none of them.

And it points the wrong way. A repair of ONE collapsed cell would have failed
this test with "expected 28" -- reporting a genuine improvement as a regression
and telling the next author to restore the defect to get green.

What must stay true is that the instrument's refusal path is REACHED, which is
a property of the refusal rather than of how much is currently broken. The
specific collapse is already carried by the discriminating controls beside it,
where a repair makes exactly the right row go red and nothing else moves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* A defect-asserting control must say so where the reader meets it

Two of the five controls assert the COLLAPSE rather than an invariant, and that
is deliberate: a repair makes exactly the right row go red. But the only place
that was written down was a comment on a different function further down the
file, and nobody arrives at a control by reading the module top to bottom. They
arrive at a red test name in a CI log, where
"a_typed_index_refusal_is_not_distinguished_from_a_structural_non_match" reads
like a broken invariant and the obvious repair is to make the two renders
differ -- which is precisely what the real fix would already have done. The
future author would restore the defect to get green.

So each of the two now carries its own disposition on its own declaration:
going red means the defect was repaired, which is success; delete the row, do
not restore the behaviour. The six-arm control also states what a PARTIAL
repair means, because it goes red then too and that is still progress.

This is the count-oracle failure one level up. Both are true signals the reader
misclassifies, and in both cases the fix is to move the meaning to where the
signal is read rather than to weaken the signal.

Also records why the surviving == 28 in the denominator control is not the
literal that was just removed: 4 and 7 are the arities of two std types, an
authority this module does not own and cannot silently drift from, since the
exhaustive matches make an upstream change fail compilation. The removed
literal was this run's own measurement of how much is broken, compared against
itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Three gaps in what the instrument guarantees about itself

The measured matrix and the production-gap separation were right. What was
wrong was every claim this file made about its OWN evidence, and all three
holes are the class the instrument exists to detect, turned inward.

C2, the worst: consumer_standing was a CONSTANT FUNCTION. It returned
CalibrationDemonstrated unconditionally with only the conditions string
varying, so three arms of a four-armed vocabulary were unconstructible on this
route and the field carried zero information -- a fixture pinned at an
absorbing extreme, where admission cannot fail because the input cannot differ.
And cell_is_sound never read it: a cell with RefusedOrIncomplete consumer
standing was SOUND as long as its production standing was demonstrated.
Descriptive data standing where an admission obligation belonged. The matrix
stays red today only because the production axis is unsupported, so repairing
that axis would have made the consumer axis silently admit everything.

consumer_standing now DERIVES from structure that can differ -- the
demonstration's three clauses read literally, with clause two (did the case
reach the intended judging stage) checked by round-tripping the constructed
observation and resolution through the same total matches that bind the
denominator. A parameterised form exists so the RED is authorable at all, and
two of the three non-demonstrated arms are now reached by executing controls.
cell_is_sound requires both standings.

C1: the denominator control proved a COUNT, not an identity join.
calibration_cells folds one traversal list across the other, so its cardinality
is a product, and the round-trip fold checks that each visited element relabels
to itself -- which a duplicate satisfies exactly as well as a unique element.
Replacing IndexModulePathRefusedArm with a second IndexTransportRefusedArm
leaves lengths at 4/7/28 and every control green while one column is measured
twice and another never. Verified by executing that exact sabotage: the old
control stayed true, the new distinctness control went false, and green
returned on restore.

The verdict now consumes traversal integrity too, because an empty or short
traversal has no unsound cell and would otherwise exit success -- "nothing was
measured" and "nothing was wrong" arriving at the same exit.

C3: the refusal control asserted a precondition of the decision, not the
decision. Factoring calibration_verdict out was necessary and is not
sufficient, and the residual gap is stated rather than papered over: replacing
the report's post-write refusal with ExitSuccess leaves every control here
green. No witness can cover it -- the report performs a host effect and the
floor's hermetic envelope refuses those, so such a witness would be counted
executed while its assertion never ran. Declared as a boundary with a
capability-shaped trigger, and the control is renamed to the verdict it checks.

Also synchronises two scope sentences: the opening claimed to measure what the
production path can produce while the body correctly says it does not, and "no
producer anywhere" is scoped to the production route, since this instrument
itself constructs StructuralBindingProductionRefused.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* C3 closed by execution: the wet route existed, so the gap was mine not the floor's

I declared a §4b boundary and named a missing capability: a witness-executable
route that can run an effectful entry point under the floor. That capability
already exists, with thirteen precedents in the same directory. A trigger
naming an existing capability is a drop that never ends, because a drop is
retired by its trigger and by nothing else -- so the declaration would have
been permanent by construction.

My barrier was real and was not a ceiling. Hermetic discovery does refuse host
effects, and a witness swept into it would be counted executed while its
assertion never ran. What I missed is the documented second route: exclusion
from hermetic discovery plus enrolment in a wet lane, exactly as
test.claim.commit_writer_heal_admission_real_execution does.

So the gap is closed rather than declared. A new wet witness calls the real
provenance_calibration_report against a real temp path and asserts the returned
ProcessExit. To make the arm two-sided through the real path, the report is
parameterised on its cell population -- computing it inside meant the only
outcome a wet witness could observe was refusal, which a report that refused
unconditionally would satisfy. The measured matrix must refuse; a constructed
sound matrix must succeed. Two further arms: the refusing report must still
have WRITTEN the matrix, since a refusal with no file is a different and worse
outcome than the stopped-line audit claims and is invisible in the ProcessExit;
and the empty-out-path guard refuses BEFORE any write, so "did it refuse" alone
could be satisfied without reaching the decision at all.

VERIFIED BY MAKING THE SUBSTITUTION. Replacing the post-write refusal with
ExitSuccess: the hermetic control stayed true and the wet witness went false.
That is the sentence that named the gap, now flipped, and running the hermetic
control on the sabotaged tree is what proves it could not have seen it.
Restored byte-identical, green returned.

Enrolled in the identity-grain local-repo wet lane rather than the dark bin-wet
class, deliberately: the witness exists because a wall that stops executing
must refuse rather than read as covered, and enrolling it somewhere it could be
silently absent would reproduce its own subject. Its admitted effect is named
as its own row rather than folded into a neighbour -- it builds no repository,
unlike the throwaway-repo class, and it writes, unlike the read-only probe
class.

Also adds two import lists flagged in review. Both claims were that name
resolution would fail; it does not, and the file carries zero diagnostics with
or without them -- measured both ways. They land for peer consistency, not
because the stated defect was real.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Five: a helper that claimed a judgement it never ran, and two degenerate passes

N1 is the instrument's own subject one layer up, and it is the one I would not
have found. consumer_standing_for round-tripped the kind and the arm and NEVER
CALLED assess_reference_binding_observation, while its own conditions string
said the case had been "judged by" it. The matrix was not wrong today, because
the only caller supplied consistent arguments -- which is exactly how this
class survives: a derivation asserting what it did not perform is invisible
while its inputs stay well-formed.

It now takes ONE observation and reads the resolution OUT of it, so the judged
case and the checked arm cannot be two different things; the old signature took
both and could be handed a matched pair by convention alone. Demonstrated
standing is reached only after the real consumer runs, and carries that call's
attributed result. The discriminating RED is same-kind/different-embedded-arm,
which the old signature could not detect at all -- without it the change would
be a shape no input can falsify.

C1 and N2 are one shape twice: an assertion true at the absorbing extreme of
its own input.

C1: traversal_is_complete counted DISTINCT keys, which is coverage, and never
counted the list, which is uniqueness. 28 cells plus a duplicate has 28
distinct keys and passed while the population held 29. This became reachable
through the C3 repair -- parameterising the report made the population an INPUT
a caller shapes, so a duplicate now arrives through the parameter rather than
through the traversal lists the other conjuncts guard. Length == distinct ==
declared is the identity join; either count alone is a count.

N2: the write arm asserted Filesystem.Read(...).success, and a read of a
ZERO-BYTE file succeeds -- so a report that created the file and wrote nothing
satisfied the arm whose entire purpose is that the operator gets the evidence
before the line stops. It now compares the payload to calibration_body_of over
the SAME cells, using the existing renderer rather than a second authority, and
a third arm rejects a right-shape wrong-population payload.

Verified by the adjudicator's own falsifier: emptying the write content while
keeping the verdict left all three prior wet arms GREEN and reddened both
content arms. Restored byte-identical, green returned.

Two scope sentences: "no module anywhere constructs
StructuralBindingProductionRefused" was false unscoped -- this module
constructs it -- and is now scoped to the production route; and the empty-out
control no longer claims to observe the absence of a write, which its Boolean
cannot establish since no path is supplied for it to read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* The wet witness was enrolled in one roster and executed by neither

The floor refused, correctly, and named the defect exactly: four identities
"never reached their subject: the hermetic route has no arm for Dir (operation
declares no mock_response)". My wet witnesses were still being evaluated on the
HERMETIC route, where shell.Mktemp.Dir cannot run. The fifth arm did not gap
because it builds no temp directory.

That refusal is the floor doing the thing this PR is about: it did not count
four unreachable claims as covered, it stopped and said which subject was never
reached.

The cause is a deviation I made deliberately and did not verify. The route I
was pointed at enrolls a wet witness in TWO rosters -- bin_witness_wet_entries,
the per-PR executing consumer, and the local-repo wet schedule, which joins
observed terminals back at identity grain. I chose the schedule alone because
the identity-grain join is the stronger property, and treated the other as an
alternative rather than as the half that actually executes. Measured against
the working precedent: it carries 4 bin_wet rows, I carried 0.

So the enrollment asserted an executing consumer it did not have, which is
specification-without-execution -- and the seed already records another author
making the same mistake on these rosters and reverting it. Both halves now
match the precedent.

What this does not establish: that the rows take effect. That is a claim about
CI mechanics I have now been wrong about twice, and it is settled by the next
floor run rather than by this commit message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Revert the bin_wet rows: that cadence has no executor and has not since August

The rows did not take effect and the seed says why, in a note I should have
read before adding them rather than after. std_witness_admission records the
per-cadence realization gate: of ten WitnessConsumerCadence arms, exactly four
have a live scheduled route, and BinWitnessWet is NOT one of them --
"falsifier.yml, the workflow that scheduled all five, was deleted at
611fd02 (2026-08-15, #8283), and no replacement executor exists."

So enrolling there is specification-without-execution by construction, which is
what the floor_prepared_subject_exclusions comment already recorded another
author discovering and reverting. I have now reproduced that experiment and it
came out the same way. Leaving the rows would leave a roster claim with no
consumer standing as though it were coverage.

What the same note establishes is that my ORIGINAL choice was the right one and
the bin_wet addition was the wrong correction: LocalRepoWetLane returns TRUE,
is "the one arm added with its executor rather than before it", and its stated
scope is exactly this witness -- "witnesses whose real effects are confined to
a temporary directory and a local git repository, which the required lane can
run in its own checkout". Its completeness join is at identity grain in both
directions and its liveness check refuses LocalRepoWetExecutorAbsent, which is
why a member it cannot run reds the lane rather than quietly widening it.

That leaves the enrollment as it was two heads ago -- exclusion row classified
LocalRepoWetLane, five rows on the schedule -- and the four identities still
evaluating hermetically and gapping on Dir. I do not know why, I have been
wrong about this lane twice, and I said I would stop rather than try a third
model. Stopping here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* The floor's prepared subject consults a Rust literal and nothing else

Three CI cycles changed nothing because both rosters I edited were the right
rosters for the wrong consumer. There are two exclusion mechanisms with
different consumers: witness_exclusion_frontier, projected from .dag by
cli_run/witness_gates.rs, governs DISCOVERY SELECTION; the FLOOR PREPARED
SUBJECT consults floor_prepared_subject_exclusions and nothing else, as that
function's own comment has said since someone else learned it the same way. The
identities were gapping in the prepared subject.

The bin_witness_wet_entries detour was the same mistake with a worse cause:
that cadence is one of five whose executor was deleted with falsifier.yml at
611fd02, so the rows were dead on arrival. Reverted last commit. Worth
recording that the precedent I matched against is itself in that dead cadence
-- an excluded witness enrolled in a lane that does not run, which reads as
covered and is not.

This entry is the OPPOSITE of the two already in the list and its comment says
so rather than copying them. Those two are excluded BECAUSE they have no wet
consumer: the exclusion buys a green floor, the claims sit at UNEXECUTED-IN-CI,
and they say so plainly. This one is excluded so that it CAN be executed --
its five functions are on the local-repo wet schedule, whose cadence is one of
the four with a live scheduled route, and whose lane joins roster to terminal
receipts at identity grain in both directions and refuses
LocalRepoWetExecutorAbsent when a nonempty schedule meets an uninvoked
executor. A member it cannot run reds rather than reading as covered.

Admitted against the v1 freeze on the PURPOSE test: this is the executing
evidence for the calibration instrument's refusal path, and without it that
evidence cannot run at all. Mocking is not the alternative -- the witness
exists to prove the REAL report writes the REAL matrix before refusing, and a
mocked write asserts against the mock. One string and a comment; no new
declarations, no exported surface.

Seed verified by execution, with a discriminating control: cargo check
-p v1-compiler exits 0 and reports Finished; cargo check -Z
definitely-not-a-real-flag exits 101 and is refused. Whether the entry takes
effect is settled by the next floor run, not by this message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* A test with no host effect does not belong in a wet witness

The seed exclusion worked: the four Dir route-gaps are gone. The floor then
refused on a narrower and different cause, which I read from the published
measurement receipt rather than from logs:

  cause=ChangedWitnessOutsidePreparedSubject
  identity=...an_empty_out_path_refuses_by_real_execution
  the changed-witness sublane selected this exact identity, but its module
  closure was not prepared, so execution cannot be represented as a decline

That identity is the fifth function, and it is the one that makes NO host
effect at all: the argument guard returns before the report touches anything --
no temp directory, no write, no shell. I put it in the wet witness because it
was topically adjacent to the arms that do write, and that was a misplacement
independent of any CI mechanism. It made a hermetic property depend on a lane
it does not need, and the floor named it.

So it moves to the hermetic controls, where it always belonged, and its
schedule row goes with it. The wet file now holds exactly the four functions
that perform real effects, and the schedule holds exactly those four -- checked
by an identity join in the direction that can fail, with a guard that refuses
an empty subject list rather than reporting a vacuous clean.

I am not claiming this clears the floor. The cause is new, the reasoning is
about my own file rather than about the lane, and the next floor run settles it.

Also records how the cause was obtained, because it nearly was not: the run was
still in progress, so the job-log API returned "run is still in progress" into
a file I then grepped for my module and found zero hits. That empty capture
read as a clean result, and I was one step from reporting that the route-gaps
were gone on the strength of a refusal I had mistaken for evidence. The receipt
artifact was retrievable while the logs were not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Remove the prepared-subject exclusion: the wet lane's members belong IN the subject

The exclusion was the proximate cause of ChangedWitnessOutsidePreparedSubject,
not a cure for the route gaps. A LocalRepoWetLane member is PULLED INTO the
prepared subject by local_repo_wet_schedule seeding the closure; excluding it
puts the identity in the one state the site loop refuses -- selected as a
changed witness and not prepared.

Restores the configuration in which the four route gaps appeared, which is the
configuration the changed-witness projection must be read against:
HermeticRouteGapHeldAndWetPassed is the floor's designed answer here, and this
run is to capture WHICH of its conjuncts fails.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Enroll the four wet identities in floor_route_gap: the second half of a two-part enrollment

The wet schedule row supplies the EXECUTION; this supplies the record of the
HERMETIC BOUNDARY. Both are required and neither references the other, which is
why the schedule stood alone through five CI cycles.

Operation and ground are MEASURED, from required-floor run 33978797098 at
06c7740: 'the hermetic route has no arm for Dir (operation declares no
mock_response)' for each of the four. The enrollment was withheld until that run
existed rather than written from the inference that it would say Dir/NoMockResponse
-- which it did, but a roster row written from a guess is a transcribed number.

The same run establishes the pair discharges: [local-repo-wet] scheduled=22
admitted=22 refusals=0 with all four observed=passed, and the changed-witness
projection reading standing=hermetic-route-gap-held-and-wet-passed for each. The
hold is never a pass on its own.

Modelled on floor_route_gap_expectation_chunk_05, the same shape for the same
reason, in the typed form so a wrong operation or ground refuses rather than
enrolling silently.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Write the absence of the wall into the header, since prose cannot refuse

The pair sentence was already here; what it lacked was honesty about its own
weakness. Both rows are required, neither references the other, and NOTHING
refuses a witness that has one and not the other -- stated as a declared
boundary rather than as advice.

The evidence that prose cannot carry this is in this repository, twice today:
floor_prepared_subject_exclusions carries a comment saying run_required_floor
consults that list and nothing else, and it did not reach the next author;
chunk_05's header states this same pairing in this same file, and it did not
reach the author of chunk_06, who supplied the schedule row alone and learned
the rest from five red floors.

Also records that floor_route_gap_expectation_mismatch returns early on a
missing expectation, so the one wall guarding these rows cannot fire for an
UNENROLLED identity -- the state every author is in while deciding what to
write. A guard whose precondition is the state you are not yet in protects the
case that no longer needs it.

Floor verified green at 0a036af before this commit: run 33980428822,
standing=measurement_completed blockers=0, all four jobs passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* The boundary paragraph understated the boundary: three carriers, not two

Review 61028 counted the carriers and was right. The enrollment is a TRIPLE:
the expectation in floor_route_gap_expectation_chunk_06, the schedule row in
local_repo_wet_terminal local_repo_wet_schedule, and the ci_layer_roots
witness_exclusion_frontier row classifying the file LocalRepoWetLane. None
references the others and nothing refuses a witness that has some and not all.
Named by symbol rather than by line, so the next edit above them does not
silently invalidate the citation.

A wrong count in a paragraph about a coupling nothing enforces -- written by the
author who checked the OTHER count in this same change an hour earlier and did
not check this one. Same class, same day, same hand, and this one came from
inside. The paragraph now records that it was caught by a reviewer counting,
not by its author.

An understated boundary is worse than no boundary because it will be trusted: it
is stated as a declared boundary in the file the next author is already editing,
and following it exactly supplies two of three and earns a red floor.

C1, N1 and N2 are untouched; this changes comment text in one .dag header and
nothing else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* C1 reopened: the axes were counted against themselves, so an empty axis passed

THE DEFECT, reproduced as a fixture rather than described. Empty
calibration_resolution_arms, supply cells=[], and every conjunct holds:
distinct_arm_label_count == list_length is 0 == 0, the kind conjunct is 4 == 4,
length == declared is 0 == 4*0, distinct keys == declared is 0 == 0, and the
unsound list is empty. calibration_verdict returned ExitSuccess having measured
NOTHING. The two conjuncts that look like axis guards are vacuously true exactly
when the axes are most broken -- predicate_vacuously_true_on_an_empty_domain,
inside the instrument whose purpose is to refuse an empty traversal, and the
seventh specimen of a row this author appended six to this afternoon.

WHAT CHANGED. The axes are now PARAMETERS of traversal_is_complete_over and
globals only at the call site. That is the whole repair, because while the
predicate read the module lists directly NO FIXTURE COULD SUPPLY A DEGENERATE
AXIS -- the refusal arms were unauthorable, which DESIGN 4b calls a decoration
rather than a weak wall. A positive denominator on both axes now refuses the
empty case by name.

THREE CONTROLS ENROLLED, each red before this change and green after:
- an_empty_axis_refuses_rather_than_holding_vacuously (the case above)
- a_short_axis_is_internally_consistent_and_still_misses_a_kind: a shortened
  axis with its own matching matrix is INTERNALLY CONSISTENT, which is why the
  production defect is silent; the full matrix is refused against it
- a_colliding_axis_refuses_while_a_short_one_does_not: states by execution that
  the distinct-label conjuncts detect COLLISION, never OMISSION

DISCRIMINATION VERIFIED BY SABOTAGE, not by green: removing the positive
denominator turns the empty-axis control false, restoring it turns it true.

WHAT IS NOT FIXED, AND IT IS A LANGUAGE FINDING RATHER THAN A REMAINING TASK.
Axis completeness against the VARIANT TYPES is still not established anywhere.
Deriving the population from the type needs enumeration of a coproduct's
constructors from inside a fold; the substrate has no unfold, no range and no
constructor-listing primitive, so the list cannot be produced from the type by
any construction available. A third hand-maintained list would be a second
authority for the same fact and closes nothing. The capability that retires it
is named in the header.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* File the axis-completeness gap as a guarantee_stall, not a rung_drop

A rung_drop records a REGRESSION and carries a restoration trigger. Axis
completeness against the variant types was NEVER established, so there is no
height to restore and a drop would claim a loss that never happened. This is
DESIGN 4b(2)'s no-untracked-stall obligation: a class below its ceiling naming
what it waits on.

BLOCKER IS AwaitsOneGrounding, following the precedent of
roster_re_enumerates_its_own_rows_stall, which classifies a missing LANGUAGE
capability that way and argues why it is not ClimbableButUnbuilt: the climb is
not merely unstarted, it is unavailable with every construction the language
offers. That row is this one's sibling -- the same shape one layer over, an
authored list mirroring a declared population -- and the difference is the
missing primitive, VALUE BINDING for data declarations there against
CONSTRUCTOR ENUMERATION for a coproduct here. Neither implies the other.

The row carries the surface enumeration as its evidence, so one counterexample
falsifies it: no unfold, no range, no constructor-listing primitive, and std's
list surface is list_block, list_item, list_length, list_to_stack. It also
records why a third hand-maintained list is not the answer -- a second authority
for one fact that would make the stall LOOK discharged.

The trigger is stated as ENUMERATION OF THE TYPE rather than as a completeness
check over the list, because a check comparing the list to another authored
artifact is satisfied by editing that artifact while the axis stays short --
4b(3)'s trigger naming less than the capability it restores.

Guarantee stalls have no doc projection; the generated-artifact gate ran clean
with no drift.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Say why floor_cost_basis_boundedness_stall was converted: main did not resolve

THE ROW DID NOT HAVE A TYPO. next_rung_trigger was a String when that row landed
(#10281); the field became the NextRungTrigger product with climbs_when as its
constructor in a separate change (#10582). The two never met, 31 of 33 rows in
that directory adopted the constructor, and the closure enumerating them stopped
resolving: expected Product(NextRungTrigger), got Primitive(String).

THE FINDING IS THE GATE, NOT THE ROW. Both commits are ancestors of a GREEN
required floor -- main's required-witnesses-floor at 2f8819b reported SUCCESS
with both in its history. The gate did not lose a race; it RAN AND PASSED over a
rostered row that does not typecheck.
dag/test/claim/guarantee_stall_witness_test.dag imports gunbc.guarantee_stall.roster
and declares eleven test fns, verified, so the closure looks covered and is not.
The roster is enumerated somewhere the required floor does not compile, and until
that is closed any stall row can stop typechecking with no red anywhere.

The conversion carried in the previous merge is mechanical -- the same string,
wrapped in the constructor the field now requires -- and was made only because a
branch merging main cannot resolve this closure otherwise. This commit adds the
explanation to the row so a reader of the diff cannot conclude a stall row had a
typo, which is what an unexplained one-line constructor change looks like.

Not mine to repair: the gate hole belongs to whoever owns the required floor's
discovery closure, and it is worth more than either PR it turned up in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Drop the carrier repair from this PR: it belongs to #10608 alone

The same row was edited by both PRs with DIFFERENT comment text -- +26 here and
+66 on #10608 -- which is two authorities for one fact. Worse than a plain
conflict: whichever landed first, the other conflicts, and if this PR landed
first the SHORTER, UNCORRECTED wording would reach main while the corrected one
waited behind an operator adjudication.

The carrier repair was never part of this PR's subject. It rode along only
because this branch could not resolve main without it. That is exactly the
coupling a standalone PR exists to remove.

This branch may now be unresolvable for local work until #10608 lands, which is
expected and is not a reason to re-add it: a PR whose subject is correct and
whose branch needs another PR first is an ordinary dependency.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Sep 5, 2026
…nt trigger carrier (#10608)

* Convert floor_cost_basis_boundedness_stall to the current trigger carrier

MAIN DOES NOT RESOLVE TODAY. gunbc.guarantee_stall.roster refuses with
'type mismatch: expected Product(NextRungTrigger), got Primitive(String)' at
floor_cost_basis_boundedness_stall. Every branch that merges main pays for it.

THE ORDER, MEASURED IN BOTH DIRECTIONS BECAUSE MY FIRST READING HAD IT BACKWARDS.
The carrier landed FIRST -- 86be37f (#10582) at 17:21:02 already declared
next_rung_trigger: NextRungTrigger and supplied climbs_when. The row landed
74 minutes later, 45074b4 (#10281) at 18:35:47, spelling a bare String.
git merge-base --is-ancestor answers YES carrier-before-row and NO the other way.
So #10582 stranded nothing and this is NOT a migration that missed a caller: an
old-format declaration landed onto a carrier that had already changed.

THE INCIDENT IS DENOMINATOR LOSS, NOT A LYING GATE. The required-floor-disposition
TSV (artifact 9975676354, run 33986383584 at 2f8819b, checked against its
published SHA-256) carries all ELEVEN identities of guarantee_stall_witness_test
as declined_outside_gate_closure / not_executed. The floor reported honestly, per
identity, that they did not run; the AGGREGATE reported SUCCESS over a population
that had already excluded them. Discovering an identity so it can receive a
disposition is not the same operation as preparing and executing its dependency
closure. The narrowing is
gunbc.recurring_failure_mode.preparation_membership_derived_from_the_execution_selector.

THE CONVERSION IS MECHANICAL AND VERIFIED AS SUCH, not asserted: the capability
text is byte-identical at 321 characters, and awaiting: [] discards nothing --
the original trigger carried no referent provenance. Before/after through the
SAME compiler route and the same binary (md5 bf014f57, built 2026-09-04, which
PREDATES this tree and is not claimed to be main's current compiler): the bad
initializer refuses with the diagnostic above, the converted row resolves with
zero resolve errors. Because both readings used one binary, its revision cannot
explain the difference.

LANDING THIS CLOSES NOTHING ABOUT ADMISSION. It restores resolution. The question
it leaves open is sharper than the one I started with and no census at the
carrier's own PR could have answered it: does admission validate an incoming
declaration against the carrier current at placement? A clean merge and an active
author do not establish compatibility with an intervening authority change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

* Withdraw the refuted explanation, keep the measured exclusion, drop the attribution

Four wording repairs to this row's annotation. The conversion itself is unchanged
and the capability text stays byte-identical.

1. A CONTRADICTION IS RESOLVED BY SPLITTING TWO CLAIMS AN EARLIER DRAFT COLLAPSED.
   WITHDRAWN: "the roster is enumerated somewhere the floor does not compile" --
   inadequate, because the witnesses exist and consume the roster through live folds.
   NOT WITHDRAWN, because it is measured from the artifact: those eleven witnesses
   were declined before preparation and did not execute. The witnesses existing
   refutes only the claim that nothing reaches the roster; it does not refute their
   exclusion.

2. The aggregate accusation is replaced by the narrower measured statement. A run
   succeeding for its SELECTED work did not establish that this declaration
   satisfied the current carrier. DISCOVERY-ADMITTED, PREPARED and
   SELECTED-FOR-EXECUTION are three populations and must not silently become one.

3. "gunbc#10582 stranded nothing" is localised to "DID NOT STRAND THIS ROW, WHICH
   LANDED LATER" -- the ordering measurement covers this row and says nothing about
   whether every other constructor was migrated correctly.

4. The attribution heading is removed entirely. Commit order establishes neither
   fault nor its absence without branch and review context, and this repair needs
   no attribution investigation to be correct.

Also: the edit is no longer described as "no semantic change". It is a
representation and type-correctness repair preserving the row's substantive
capability requirement -- an incompatible String initializer becoming a product
construction is compiler-observable, which is the point of making it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvMEJFpYsy55NRdJ1Az4Vd

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants