Skip to content

The cost-debt roster's outside-gate arm was a name test, so an enrolled identity that does not exist refused nothing - #9695

Merged
gunbai-bot[bot] merged 3 commits into
mainfrom
session/clever-fox-24-cost-debt-standing
Aug 29, 2026
Merged

gunbai-bot[bot] merged 3 commits into
mainfrom
session/clever-fox-24-cost-debt-standing

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

The defect

The cost-debt roster's reverse (staleness) join already had an outside-the-gate arm — added with the 2026-08-29 gate cut, already counted rather than silent. What it could not do is tell two populations apart.

Its filter, identity_inside_required_gate, takes an identity's module path and prefix-matches it against required_gate_prefixes. It is a name test consulting nothing else. So for any enrolled row that did not execute, it asked only whether the string starts with a gate prefix.

A module name cannot distinguish "declared, but this run's gate never loaded it" from "no such declaration anywhere." So an enrolled identity that does not exist — a typo, a renamed or deleted witness, a fabricated line — prefix-missed the gate, was counted as outside-the-gate, and refused nothing.

That is precisely the hole the reverse join exists to close, in its own words:

that also closes the cheapest way to fake a green run: enrolling an identity that does not exist would otherwise cost nothing.

The gate cut reopened it across the whole non-gate namespace, which is now the majority of the corpus. 122 enrolled rows sat in that arm on the first gate-bounded fold, and nothing could tell a real one from a fabricated one.

This is a fail-open in the roster's anti-fabrication wall, not only in its debt accounting.

Why it is fixable now

gunbc#9684 makes every declared identity carry exactly one disposition, so preparation's own account of what it loaded is available here as a population rather than as a name test.

The change

partition_cost_debt_roster puts every enrolled identity in exactly one arm:

arm meaning refuses?
Withheld discovered and withheld — the operative debt no
OutsideThisRunsUniverse declared, but preparation never offered it (gate closure / discovery exclusion) — kept as record, not counted as debt no
Undeclared the tree declares no such identity yes ← the new arm
DeclaredButNotWithheld declared and offered, but not withheld — renamed, or declined for a home reason outranking cost debt yes (pre-existing arm, unchanged)

The discriminator is the disposition, and only the disposition — derived from what preparation actually loaded, never the spelling of a name and never a second structure's opinion.

Reworked after review. The first draft consulted the fold's withheld set first and fell back to the disposition. That made two structures answer one question — the §3 defect this PR exists to close, rebuilt inside the repair — and its test asserted that a withheld identity with no disposition row is Withheld, blessing exactly that divergence. The disposition is now the sole classifier. The declared-set parameter is gone too: since #9684 every declared identity carries exactly one disposition, so "no disposition" is "not declared", and a separate declared set would have been a third representation.

The withheld set is still computed for execution accounting, and it is now reconciled against the classification rather than consulted by it: reconcile_withheld_against_dispositions reports both directions of the difference, and any disagreement refuses the run with CostDebtWithholdDispositionDisagreement. Two observations of one act may disagree loudly; they may not be silently resolved in favour of either.

It is a free function beside reconcile_identity_population, for that function's own stated reason: "the test that proves it must call THE PRODUCTION CODE" — an earlier draft of that test carried its own copy of the loop and would have passed while production drifted.

The discriminating RED

A pair that differs only in declaration: two enrolled identities in the same non-gate module, neither withheld, one declared and one not. The undeclared one must refuse; its declared sibling must not.

That pairing is the point. A fix that refused both would close the hole by breaking the 122 legitimate rows, and nothing but the declared join separates them.

Verified by mutation, not by assertion, twice:

  • absorbing the undeclared arm back into outside-universe (the old semantics) reds 3 of the 6 tests;
  • dropping one direction of the reconciliation reds the disagreement test while the agreement test stays green.

One test is deliberately the reverse of one the first draft carried: a_missing_disposition_refuses_and_is_never_overridden_by_another_structure.

Reporting

Identity grain, replacing a bare count of an arm that silently mixed legitimate rows with unrefusable fabrications:

[floor-cost-debt] roster standing: enrolled=N withheld=N outside_this_runs_universe=N undeclared=N declared_not_withheld=N
[floor-cost-debt] outside this run's universe, kept as record and NOT counted as debt (...): <identities>

Preserved deliberately

Both refusing arms stay guarded by reverse_joins_answerable, exactly as before. A halted run's population is truncated, and answering "delete the row" over it is the empty-observation narrow this file already refuses to commit for the sibling rosters. The partition's inputs are planning-time facts and survive an execution halt — but a halt during preparation truncates them too, and this arm must not be the one place that assumes otherwise.

No roster edits. No row released, no row added.

Seed-growth receipt

gunbc.floor_cost_debt_standing_seed_growth enrols all three new hand declarations (partition_cost_debt_roster, CostDebtRosterStanding, reconcile_withheld_against_dispositions), with one entry in seed_growth_justification_roster().

It is a sibling of floor_cost_debt_seed_growth rather than an edit to it: that row justifies the forward direction (declining a rostered site at build) and retires when the self-emitted claim executor consumes required_floor_site_disposition directly. This one justifies the reverse direction, which reads different inputs and retires on a different condition. Folding them would give one trigger two capabilities, so whichever was satisfied first would retire an obligation it does not cover — the grain mismatch §4b(3) names. One row per capability is already the pattern here.

No LOC or item deltas are typed: the policy note rules them derivable from the diff and drops them from the enumeration.

Also: the held live_deploy population's trigger

Recorded on the carrier, and it is a capability, not a PR: restoration of the §4b(3) rung drop "Required gate reduced to the compiler floor" by a change-derived required population.

Those 45 identities cannot take the roster's ordinary exit ("delete the line, let the floor run it"), because the floor does not run them — they are outside the gate closure, and no full-corpus floor remains in CI (witnesses.yml invokes claim_executor --required-ci twice, once per lane, and nothing else runs a floor). Their marginal cost is unobservable by any instrument this repository currently runs, so releasing them would be bookkeeping rather than a measured shrink.

floor_cost_debt's roster is a bare List<String> with no per-row field, so the trigger is a paragraph beside it rather than on the rows — a real limitation of the carrier, stated rather than worked around.

Verification

  • cargo test --release -p v1-compiler --lib (what CI's rust-unit-tests runs): 541 passed, 0 failed; all four new tests confirmed present in that release profile, not just locally in debug.
  • Mutation: old semantics → 3 of 4 red, then green again on restore.
  • cargo clippy -p v1-compiler --lib -- -D warnings: clean. (--all-targets fails on main already, in tests//examples//bins/ I did not touch.)
  • cargo fmt --all --check: clean.
  • gunbc compile on the changed .dag: 0 blocking errors.

…ty that does not exist refused nothing

The roster's reverse join already had an outside-the-gate arm, added with the
2026-08-29 gate cut, and it was already counted rather than silent. What it
could not do is tell the two populations apart. Its filter,
`identity_inside_required_gate`, takes an identity's module path and
prefix-matches it against `required_gate_prefixes` -- a NAME test consulting
nothing else -- so for any enrolled row that did not execute it asked only
whether the string starts with a gate prefix.

A module name cannot distinguish "declared, but this run's gate never loaded
it" from "no such declaration anywhere". So an enrolled identity that DOES NOT
EXIST -- a typo, a renamed or deleted witness, a fabricated line -- prefix-missed
the gate, was counted as outside-the-gate, and refused nothing. That is exactly
the hole the reverse join exists to close, in its own words: "the cheapest way
to fake a green run: enrolling an identity that does not exist would otherwise
cost nothing." The gate cut reopened it across the whole non-gate namespace,
which is now the majority of the corpus -- 122 enrolled rows sat in that arm on
the first gate-bounded fold, and nothing could tell a real one from a fabricated
one.

gunbc#9684 makes the repair possible: every DECLARED identity now carries
exactly one disposition, so preparation's own account of what it loaded is
available as a population instead of a name test.

`partition_cost_debt_roster` puts every enrolled identity in exactly one arm --
Withheld (the operative debt), OutsideThisRunsUniverse (declared, never offered:
record, NOT debt), Undeclared (REFUSES), DeclaredButNotWithheld (the
pre-existing stale arm, REFUSES). It is a free function beside
`reconcile_identity_population` for that function's own stated reason: the test
that proves it must call the production code, not a paraphrase.

The discriminating RED is a PAIR that differs only in declaration: two enrolled
identities in the same non-gate module, neither withheld, one declared and one
not. The undeclared one must refuse; its declared sibling must not. A fix that
refused both would close the hole by breaking the 122 legitimate rows, and
nothing but the declared join separates them. Verified by mutation: restoring
the old semantics reds three of the four new tests and leaves the untouched
withheld-precedence arm green.

Reporting is now identity grain. The old line was a bare count of an arm that
silently mixed legitimate rows with unrefusable fabrications; the roster-standing
line names all four arms and the outside-universe identities are listed.

Both refusing arms stay guarded by `reverse_joins_answerable` exactly as before:
a halted run's population is truncated, and answering "delete the row" over it
is the empty-observation narrow this file refuses to commit for the sibling
rosters.

Roster edits: NONE. No row released, no row added.

Also records the held live_deploy population's trigger on the carrier. It is a
capability, not a PR -- the restoration of the 4b(3) rung drop "Required gate
reduced to the compiler floor" by a change-derived required population -- because
those identities are outside the gate closure AND no full-corpus floor remains
in CI (witnesses.yml is --required-ci twice), so their cost is unobservable by
any instrument this repository runs. The roster is a bare List<String> with no
per-row field, which is why the trigger is a paragraph beside it; that
limitation is stated rather than worked around.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotWMhkrZSo3Hcy1K68Mt9
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 29, 2026 20:50
… gate)

gunbc.seed_growth_admission seed_growth_forward_freeze_policy_note makes an
unenumerated hand-src/v1-Rust addition a stop-line, and this change adds two
hand declarations without one. Adds the row and its roster entry.

A SECOND ROW BESIDE gunbc.floor_cost_debt_seed_growth RATHER THAN AN EDIT TO IT.
That row justifies the FORWARD direction — the build-loop branch declining a
rostered site at build rather than skipping it at execution — and retires when
the self-emitted claim executor consumes required_floor_site_disposition
directly. This one justifies the REVERSE direction, which asks a different
question of different inputs (the declared identity population and preparation's
disposition rows, neither of which the forward branch reads) and retires on a
different condition. Folding them would give one trigger two capabilities, so
whichever was satisfied first would retire an obligation it does not cover —
the grain mismatch DESIGN §4b(3) names as the review tell for a trigger naming
less than it restores. One row per capability is already the pattern at this
boundary (floor_non_verdict, floor_route_gap, floor_cost_debt,
floor_population_projection), not a fork.

The two items are enumerated exactly: partition_cost_debt_roster and
CostDebtRosterStanding, both in v1_compiler.cli_run. The row records why Rust
is still needed (the declared population and disposition rows are produced
inside run_required_floor and never leave it), what is NOT grown (no roster, no
policy, no status vocabulary, no roster line), why the repair was impossible
before gunbc#9684 (it needs a declared population to join against), and why the
RED is a pair rather than a single probe.

NO LOC OR ITEM DELTAS ARE TYPED. The policy note rules them derivable from the
diff and drops them from the enumeration — an authored copy is a second
representation of a fact the diff already owns, and it measured one wrong
(gunbc#9095 claimed +195/+65 against +203/-0, +60/-5, +102/-0). Two existing
rows still carry them from before that ruling; this one does not.

Trigger is the roster's reverse join folding in .dag with the v1 floor bridge
hollowed — explicitly NOT retired by the roster reaching zero, and NOT by the
undeclared arm being empty on any number of runs: an empty arm still needs the
wall that keeps it empty.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotWMhkrZSo3Hcy1K68Mt9
@gunbai-bot gunbai-bot Bot changed the title FLOOR-EMIT-RECOMPUTATION: live_deploy.emit fixture cut, then release exact identities from the shrink-only cost roster The cost-debt roster's outside-gate arm was a name test, so an enrolled identity that does not exist refused nothing Aug 29, 2026
…3 defect it was repairing

Blocker from neat-swift-219, and it is correct. `partition_cost_debt_roster`
consulted the fold's withheld set BEFORE the disposition and fell back to it, so
two structures answered one question — the same §3 defect this change exists to
close, rebuilt inside the repair. It was not hypothetical: the test
`a_withheld_identity_is_debt_regardless_of_its_disposition_row` asserted that a
withheld identity with NO disposition row is `Withheld`, blessing exactly the
divergence the join should refuse.

The four arms are now driven SOLELY by the disposition index: no disposition ->
Undeclared; DeclinedCostDebt -> Withheld; DeclinedOutsideGateClosure |
DeclinedDiscoveryExcluded -> OutsideThisRunsUniverse; every other declared
disposition -> DeclaredButNotWithheld.

The declared-set parameter is REMOVED as well, which the blocker did not ask for
and which follows from it: since gunbc#9684 every declared identity carries
exactly one disposition, so "no disposition" IS "not declared", and passing a
separate declared set would have been a third representation of one fact.

The withheld set is still computed for execution accounting and is RECONCILED
against the classification rather than consulted by it.
`reconcile_withheld_against_dispositions` reports both directions of the
difference — a withhold with no DeclinedCostDebt disposition, and a
DeclinedCostDebt disposition with no withhold — and the runner REFUSES on either
with CostDebtWithholdDispositionDisagreement. Two observations of one act may
disagree loudly; they may not be silently resolved in favour of one.

The offending test is REVERSED rather than deleted:
a_missing_disposition_refuses_and_is_never_overridden_by_another_structure
asserts that a missing disposition refuses whatever any other structure believes.

Mutation-verified twice: absorbing the undeclared arm back into outside-universe
reds 3 of 6; dropping one direction of the reconciliation reds the disagreement
test while the agreement test stays green.

The seed-growth receipt gains the third declaration and records why the draft
was wrong, so the next reader sees the failure mode rather than only the repair.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotWMhkrZSo3Hcy1K68Mt9
@gunbai-bot
gunbai-bot Bot merged commit 493bc90 into main Aug 29, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/clever-fox-24-cost-debt-standing branch August 29, 2026 21:29
briansrls pushed a commit that referenced this pull request Aug 29, 2026
…ion/deep-heron-231

# Conflicts:
#	dag/gunbc/seed_growth_admission.dag
@briansrls
briansrls restored the session/clever-fox-24-cost-debt-standing branch August 29, 2026 22:00
@gunbai-bot
gunbai-bot Bot deleted the session/clever-fox-24-cost-debt-standing branch August 29, 2026 22:01
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