Skip to content

Close the dissolution carrier fork and eliminate raw lifecycle prose - #8059

Merged
briansrls merged 44 commits into
mainfrom
session/valiant-bear-355
Aug 10, 2026
Merged

briansrls merged 44 commits into
mainfrom
session/valiant-bear-355

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

Close the dissolution carrier fork, and derive the population from the corpus

What this closes

A lifecycle condition — "the code change that retires this carve-out" — was
carried two ways: a typed frontier row on some carriers, and bare prose on
others. The string form had a forgeable firing path: TriggerProse plus
prose_fired let a caller report an unbound condition as fired, which is
rung inflation at the carrier (DESIGN §4b(1)).

std.dissolution is now the single authority:

DissolutionTrigger   = DeclarationAppears { ref: DeclarationRef }
DissolutionCondition = BoundDissolution { trigger } | UnboundDissolution { description: NonEmptyStr }
DissolutionStatus    = DissolutionUnbound | DissolutionPending | DissolutionFired

TriggerProse and prose_fired are deleted, not deprecated. An unbound
condition is structurally unable to report fired: DissolutionFired is
reachable only through dissolution_status, which requires a DeclarationRef
resolved against present_decls. dissolution_is_bound is derived from
dissolution_status rather than re-matching the arms, so there is one decision
procedure, not two. unbound_dissolution takes NonEmptyStr as its
parameter — the earlier internal cast was demonstrably not a wall, since
unbound_dissolution(description: "") constructed.

The population is now derived, not remembered

The reviewer's blocking verdict was that the residue census could not ground its
own completeness: it answered "here are the survivors someone wrote down", a
measurement copied from the same tree, which DESIGN §5 rejects as an oracle.

Deriving it refuted the census in both directions at once. All 35 of its rows
are outside the lifecycle name class — they are *_note prose — and 19 real
in-class survivors existed that it had never seen
: active lifecycle conditions
still typed String, skipped by the original sweep because their values feed
concat sites. The two populations were disjoint.

Those 19 are migrated, not classified. An active condition still typed
String is a migration miss, not residue.

population state
lifecycle-named fields and params typed String/NonEmptyStr 0 — held by a compile gate
lifecycle-named top-level declarations typed String/NonEmptyStr 0 — derived from the corpus, gated
top-level conditions carrying DissolutionCondition 199 — derived by the same producer, not counted by grep

The producer

data_decl_type_facts(pool_roots) -> List<DataDeclTypeFact>
    { module_path, decl_name, type_name, rel_path }

Host-derived because no substrate-reachable producer answers the question:
decl_facts marshals a DataItem's node through the initializer projection and
drops type_annotation entirely, export_signature_facts refuses
corpus-wide, and data_init_decl_facts_live is import-closure scoped — a
different and smaller population than the corpus.

It is a missing projection, not a new mechanism. It walks the same parse-only
corpus walk concept_decl_facts already uses — generalized with a kind filter
rather than forked — so a file that fails to parse refuses instead of
silently shrinking the denominator. Unlike decl_facts_corpus_walk it does not
skip test .dag files; a survivor authored in a witness would otherwise be
invisible. module_path is the authored module line verbatim, so it composes
with DeclarationRef directly.

Measured: 16,975 data declarations across 3,475 modules, 6,903 bare-string
typed, zero with an unread type annotation, zero surviving lifecycle carriers.

The name class reuses lifecycle_field_name_rows — the same roster the field
wall consults — differing only in match shape (a field is named exactly
dissolve_on; a declaration carries the spelling as a suffix). A second roster
spelled for declarations is the nickname the field predicate exists to prevent.

Evidence

Split per the witness-cost ruling: a live population whose breadth is the
subject decomposes into cheap mechanism fixtures per PR plus the irreducible
census on a cadence.

Per-PR (~0ms) — lifecycle_survivor_scan_witness_test, running the same
predicate production filters with:

control asserts
planted_raw_survivor_is_selected RED — the exact migrated shape is still selected
planted_nonempty_str_survivor_is_selected RED — NonEmptyStr is not a hole
planted_migrated_control_is_not_selected the migrated form passes
planted_ordinary_string_note_is_not_selected discriminating: a predicate rejecting every String would satisfy the control above and still be wrong

Cadence (18,482ms measured) — lifecycle_survivor_corpus_census_test, on
FalsifierSubstrateLongLane with an exclusion row and five execution rows.
Enrolled, not relocated: a witness moved out of discovery without an executing
consumer is deletion of the evidence with the file retained. Four of its five
tests exist because zero is also what a producer that read nothing returns —
they rule out an empty walk, a walk seeing no bare strings, an unread
annotation, and a skipped test subtree.

The gate was proven to red: planting a real data x_dissolve_on: String in
an isolated worktree gave 16,981 declarations, one survivor, FAIL.

What the census is now

gunbc.dissolution_migration_census keeps its value and loses its completeness
claim. Its header said it held every in-class survivor; that sentence was false
in both directions and is corrected in place, naming the scan as the authority.
Its real subject is *_note prose whose text discusses a dissolution — receipts,
rationales, refusal reasons — which is worth classifying so a later reader does
not mistake a receipt for an unmigrated condition.

What the earlier revision got wrong

An earlier pass deleted 63 top-level lifecycle declarations as "prose". Three
had visibly live subjects — std.measure still has no Day, TrackedChannel
still stores no resolution date. On inspection the rest were the same: removed
for their type, not because the condition was met. Deleting a live condition
is not a disposition.
All 63 are restored and typed; the pin trio came back as
consumed pin_frontier_rows.

17 note-clauses that were the sole authority for a live condition were extracted
into sibling *_dissolve_on: DissolutionCondition rows.

The field/param wall

v2.lens.lifecycle_carrier refuses a record field whose name is in the
lifecycle class and whose type is bare String/NonEmptyStr. Node-local,
reading only direct children — the same grain as unit_modeling_gate, so it
does not stack with run_required_lens_gates_on_subtree's fold_node into
O(n²). Labelled WallAfterGrounding { dissolves_to: SubstrateMandatoryTag }:
membership is decidable, so not RatchetForever, but the field stays writable
today and the gate is what refuses it.

A defect the type system did not catch

Three data ..._runner_scaffold_comment: String = concat("# ", <condition>)
rows passed a DissolutionCondition into a String concat. The .dag
typechecker accepted it; the interpreter stringified the coproduct, so the
emitted workflow comment read # UnboundDissolution { description: … }. It
surfaced only because a wet regenerator writes bytes a drift gate compares.

Also in scope

  • PlanRetirement.PlanRetiresWhen carries a DissolutionCondition. Its nonempty
    guard is retained deliberately: refinement at non-literal positions is
    still deferred, so an empty description can still reach the carrier.
  • Three permanent g1-cited-symbol-control-* rows were misclassified as
    never-retiring conditions; they now carry PlanHasNoRetirement.
  • The empty-condition REDs could no longer cast String to NonEmptyStr, so
    they reach the deferred non-literal gap through a returned concat — the
    evidence stays enrolled when the wall lands (DESIGN §4b(4)).
  • A 3-way declaration_ref_eq fork consolidated onto std.decl_ref.

Known limitation

type_name is the annotation head name (String, Disposition, List) —
never the initializer variant. So the producer enumerates Disposition-typed
rows exactly but cannot distinguish Scaffold from another variant; the ~97
Disposition.Scaffold rows remain outside both counts above and are not this
PR's subject. Carrying a variant discriminator is the honest extension and is
left to the consumer that needs it.

Verification

  • Two-pass fixed point: regen_stage0 → rebuild → regen_stage0 --verify.
  • Witnesses: 4/4 per-PR, 5/5 cadence census, counted PASS against roster.
  • Whole-tree compile: the pre-existing diagnostic set only (32 undefined Empty
    in complexity_accumulator_copy/analyze.dag, plus body-position annotations
    in files byte-identical to main).

gunbc-ci-auto-heal and others added 10 commits August 8, 2026 19:46
… expiry

Adds std.dissolution as the single authority for when a counted debt row must
disappear, and migrates std.roster_frontier onto it.

The split that makes it worth existing: a trigger is always checkable, and a
condition that is not checkable is explicitly not a trigger. The deleted
DissolveTrigger.TriggerProse arm, together with the caller-supplied prose_fired
list, let an uncheckable sentence report as fired whenever a caller passed the
same string back -- the roster's expiry check answering from its caller rather
than from the tree. UnboundDissolution has no path to DissolutionFired at all.

- std.dissolution: DissolutionTrigger = DeclarationAppears; DissolutionCondition
  = BoundDissolution | UnboundDissolution; status Unbound | Pending | Fired.
- FrontierRow.trigger: DissolveTrigger -> dissolution: DissolutionCondition;
  reason: String -> NonEmptyStr.
- Deleted DissolveTrigger, TriggerProse, prose_fired, dissolve_trigger_fired,
  and the frontier_row prose convenience constructor.
- FrontierExpiryReport gains unbound_count beside pending_count, because the old
  two-counter shape could not distinguish "checkable, not yet fired" from "not
  checkable at all" -- both landed in unfired_count.
- 198 call sites converted. 2 pre-existing bound rows verified genuinely pending
  (extdeps.network.mac parse_mac_address and extdeps.network.ipv6
  parse_ipv6_address do not exist), so neither was stale. No declaration name
  was invented to bind a prose condition.
- decl_field_eq/declaration_ref_eq/declaration_ref_in_list were minted THREE
  times (std.roster_frontier, gunbc.commit_workflow, v2.lens.disposition_redundancy)
  -- the exact ambiguity class std.decl_ref's own note says already redded a
  witness closure on main. Consolidated onto std.decl_ref beside their type.

Green by execution: 7 witnesses in annotation_carrier_witness_test. The no-forge
control is proven discriminating by mutation -- making UnboundDissolution return
DissolutionFired reds it and the unbound-status test, and restoring greens both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ducts already encode

Three subtractions, none of which wrap prose in a constructor:

gunbc.plan.DissolutionTrigger -> PlanRetirement (PlanRetiresWhen | PlanHasNoRetirement).
Two unrelated public types must not share one name: std.dissolution's is an
executable expiry condition decided against the tree, this one is document
metadata rendered into a plan's markdown. condition is NonEmptyStr, so the
emptiness check plan_has_dissolution_trigger performed is now a constraint the
carrier holds -- the predicate is a total projection with no length test. The
plan_with_empty_trigger fixture and its two assertions are deleted rather than
ported: they asserted a predicate over a state that no longer compiles, the same
disposition doc_graph_roots recorded for its empty-works control. 76 registry and
plan files migrated; the rendered heading is deliberately unchanged so no
generated docs/plans/*.md byte moves for a rename.

SelectedWitnessMember.InterpreterFrontier.dissolve_on deleted. It was bound to _
at both match sites and never read, while the coproduct already distinguishes
InterpreterFrontier from NativeSelected and cause is a typed
NativeUnavailableCause -- the arm change IS the transition.

StateDefinitionLinkage/StateDefinitionCallerAssertion.dissolve_on deleted across
8 sites. Every site carried the same sentence as the module-level
state_definition_linkage_frontier_note, so it was one module fact copied per
instance -- including a witness asserting the sentence verbatim, which made the
prose the contract rather than the behaviour. That assertion is re-anchored on
the typed reason.

7 zero-consumer past-tense receipt rows deleted ("X -- deleted <fork>; sole
authority is Y"): the fork is absent and the authority present, so the structure
is the evidence.

Green by execution: plan lens (4), bmc linkage (3), state durability compile.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e partition

CI red at 5903b0a was mine: adding dag/std/dissolution.dag without its emitted
counterpart broke the self-host fixed point (regen_verify_gate_passes: "read
committed src/v1/stage0/src/std_dissolution.rs: No such file or directory"), and
the heal job could not repair it because the ci.yml half needs an author commit.

- std_dissolution enrolled in v2.workflow.rust_crate_partition's std-core module
  list with its module-DAG edges (roster_frontier -> dissolution -> decl_ref,
  types). std_roster_frontier lives in v1-stage0-std-core and now imports
  dissolution, so without the membership row the crate root never declared the
  module and std-core failed to resolve it.
- Regenerated: ci.yml, the crate partition, and 139 stage0 files.
- dissolution_trigger_ref flattens the nested destructure of the one-arm
  DissolutionTrigger. Emitting BoundDissolution { trigger: DeclarationAppears {..} }
  lowers to an irrefutable `let ... else` that -D warnings rejects; a single-arm
  match in its own function does not. Fixed at the source rather than suppressed
  with an allow, and the coproduct keeps its shape for a second arm.
- Two notes in roster_frontier had gone stale against this same change ("typed
  migration trigger", "the prose_fired list below") -- the §3 class, corrected in
  the module that introduced it.

Note the regen cycle is two passes: regen_stage0's partition is baked into the
binary, so main_wet -> regen -> REBUILD -> regen is required before the new crate
root appears.

Verified: workspace builds, cargo fmt --all --check clean, regen_stage0 --verify
at regen_divergence_count=0, and the four discriminating witnesses green against
the rebuilt seed. Pre-existing and untouched: p1_cohort_probe.rs fails only under
a stricter-than-CI RUSTFLAGS=-D warnings (function-casts-as-integer).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CI batch 3 red: "name 'frontier_row' not found in module 'std.roster_frontier'
(imported by 'v2.lens.registry.completeness')".

The miss was in my verification, not the design. I converted the 195
trigger: TriggerProse{...} sites and swept residual references, but the sweep
covered call expressions and not IMPORT LISTS, and frontier_row -- the 3-arg
prose convenience constructor, a separate deletion from TriggerProse -- had 9
call sites I never converted. Four v2.lens modules imported and called it:
inert_carrier, meta_exec_confinement, complexity_linearity_audit, and
registry/completeness.

Each now calls frontier_row_path(path:, reason:, dissolution:
unbound_dissolution(description: ...)). The conditions are unchanged text and
stay unbound: they are "the module becomes an enforcing lens or leaves
src/v2/lens", which is a module moving rather than a declaration appearing.

Verification changed so this class cannot recur silently. A single --entry run
builds a narrower pool than CI's discovery corpus, so it is not a whole-tree
oracle -- it also surfaces a PRE-EXISTING unrelated failure (lens_module_gate.dag
references AdvisoryLens with no import, resolving only by pool-membership
coincidence, DESIGN's Class B). The oracle is now `gunbc compile --target dag`
over both source roots: 2259 sources resolve with zero diagnostics naming any
symbol this PR deleted. The 12 remaining hard diagnostics are annotation
placement in cross_file_binding_assembly and guarantee_probe_corpus, neither in
this diff, and batch 2 passed on the prior run.

Re-verified: generated artifacts clean, regen_divergence_count=0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…sumed rows

Applies the operator's classification to the module-level dissolve_on population.

DELETED (46 rows, zero consumers): 36 with no reference anywhere, and 10 whose
only mention was inside another prose string -- a citation is not a consumer.
Git history is their archive. The 6 notes that cited a deleted name now describe
the condition inline instead of pointing at a symbol that no longer exists.

DELETED (5 rows + 6 assertions): rows whose only "consumer" was a test asserting
the prose contains a substring -- string_contains(s: X, pattern: "dissolve-on"),
(X |> count) > 0. Those are change detectors, exactly what DESIGN section 5's
oracle ruling rejects: automating the literal collapses them to measure() ==
measure(). The row and its detector go together.

MIGRATED to DissolutionCondition (real consumers that decide something):
- HandScaffold in stage0_rust_source_lifecycle_scaffold (8 residue rows).
- DeclaredFrontier in roster_registry, read by v2.lens.roster_registry.
- CountedFrontierSite in observation_emit_census, read by emit_site_dissolve_on.
All conditions are disjunctive ("X or Y"), so they stay unbound. Nothing invented.

FIELD DELETED where the coproduct already encodes the transition:
InterpreterRetained, InterpretedRetained, DeclaredHere -- each sits beside a done
arm (SelfEmittedNative / NativeRouted / AuthoredInRoster) that IS the dissolution.

Two climbs dissolved their own controls (DESIGN section 4b(4)): the empty-trigger
RED in roster_registry_test and the empty-dissolve_on RED in the scaffold witness
asserted states that NonEmptyStr now makes unconstructible. The nickname control
keeps its still-writable reason axis and still discriminates.

Supporting: declaration_ref_display_key moved to std.decl_ref beside its type,
and std.dissolution gained dissolution_description -- a total projection that
renders the bound arm from its ref, so no authored sentence sits beside a
DeclarationRef to drift from it. dissolution_status never reads it.

Corrections made during the sweep, all caught by the whole-tree compile: I first
deleted the dissolve_on field from DeclaredFrontier and CountedFrontierSite too,
which broke two real consumers -- over-application of the coproduct rule to arms
whose trigger is actually read. Restored and migrated properly. A regex also
rewrote two match patterns into constructor calls, and an import insertion landed
INSIDE a multi-line import block, silently dropping a module's exports from scope.

Oracle: gunbc compile --target dag over both roots -- 2259 sources, back to
exactly the 12 pre-existing annotation-placement diagnostics in two files not in
this diff. Remaining raw population: 12 fields/params, down from 89.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The final field/parameter population. Each of these is a counted debt row whose
expiry is a genuine generic live condition, so the field becomes
DissolutionCondition rather than being deleted: ProviderContractTarget,
WitnessExclusionRow, RehomedBinWetRow, SubstrateLongLaneRow,
ExplicitWitnessAdmission, OccurrenceIdentityConsumerRedDebt,
OccurrenceIdentityReceiptEnrollmentDebt, RealizationVocabGrandfatheredEdgeRow.

Three emptiness checks deleted because NonEmptyStr made them unsatisfiable to
violate (witness_admission's row well-formedness, two in the enforcement
inventory witness); pattern and reason stay bare Strings so their checks remain
real validation. One change detector deleted (a witness asserting the row's prose
contained the literal "DISSOLVE-ON:").

ExplicitWitnessAdmission did NOT get the derived staleness predicate the brief
asked for, and the reason is worth stating rather than quietly substituting: the
rows carry `expected`, but no observed-verdict feed reaches this module -- verdicts
are produced by claim_executor at runtime, outside the carrier. Deriving staleness
here would mean inventing the observation it compares against, which is the
fabricated-evidence failure. The condition is unbound with the derivation named as
its next rung.

Also stated honestly rather than overclaimed: ci_layer_roots still decides
wet-lane membership by SCANNING the condition's rendered text for spellings. The
carrier climbed off a raw String; that classification did not. Same strings, now
through dissolution_description. Its next rung -- a typed wet-lane axis on the row
-- is a modeling decision about a load-bearing CI carrier, deliberately not made
inside a representation migration, and the existing unclassified-residue counter
still surfaces a fourth spelling.

Two more collateral regex errors caught by the whole-tree compile: the field
rewrite also renamed function PARAMETERS in explicit_witness_admission (bodies
then referenced a name that no longer existed), and it rewrote a pattern over
std.occurrence_binding_candidates' `dissolve_on: DeclarationRef?` -- a field that
was ALREADY typed and never in the forbidden population. Reverted.

Population: 89 raw declarations at the start of this PR, 0 now.
Oracle: 2259 sources compile to exactly the 12 pre-existing annotation-placement
diagnostics in two files not in this diff.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	dag/gunbc/ci_layer_roots.dag
#	src/v1/stage0/src/lib.rs
@gunbai-bot gunbai-bot Bot changed the title dissolve on migration Close the dissolution carrier fork and eliminate raw lifecycle prose Aug 9, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 9, 2026 00:47
The field migration on CountedFrontierSite changed dissolve_on: NonEmptyStr
to dissolution: DissolutionCondition, but left the old cast suffix on all
eleven construction sites. Review 50655 found them.

The reviewer read these as a compile blocker; they are not, and that is the
more useful fact. The whole tree compiles at 2276 sources with the casts
present, because validate_cast judges a cast only when source and target
both appear in std.coercion dag_cast_rules -- a cast from a coproduct to an
unrelated refinement type is unjudged rather than refused. So the typechecker
accepted a meaningless cast silently, which is why the compile oracle used
throughout this migration never saw them.

Class swept rather than the named sites: these two files are the only ones
carrying the pattern, and the 48 remaining casts in observation_emit_census
are the legitimate marker/source_file/via string fields.

Witness observation_emit_census_witness_test 16/16 PASS, counted against
its roster. regen_divergence_count=0.
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in ee3815f — all eleven sites, both files. Thanks, that was regex residue from the field migration and I missed it.

One correction, because it changes what the finding means: these casts do not block compilation. The whole tree compiles at 2276 sources with them present, which is exactly how they survived — my oracle throughout this migration was a whole-tree gunbc compile, and it was green.

The reason is that validate_cast judges a cast only when source and target both appear in std.coercion dag_cast_rules. A cast from a coproduct to an unrelated refinement type sits outside that table, so it is unjudged rather than refused. The typechecker accepted a meaningless cast in silence. That is the more interesting defect of the two, it is compiler-layer rather than anything this PR introduced, and it is not fixed here.

Swept the class rather than the ten named sites: those two files are the only ones carrying the pattern anywhere in dag/ or src/, and the 48 remaining as NonEmptyStr in observation_emit_census.dag are the legitimate marker / source_file / via string fields.

Verification on the new head: 2276 sources with exactly the 12 pre-existing annotation-placement diagnostics in two files not in this diff; observation_emit_census_witness_test 16/16 PASS counted against its roster; regen_divergence_count=0; fmt clean.

— sent from valiant-bear-355

Review 50670, both findings verified against the tree.

The positive control in witness_exclusion_reconciliation_test passed
dissolution: to a function whose parameter is description: String, so the
constructor was wrapped twice. Corrected to match its sibling call; the
witness runs 14/14.

dissolution_is_bound now derives from dissolution_status under an empty
present_decls instead of re-matching the arms. The reviewer offered a
disposition tag as the alternative; deriving is the stronger option because
it removes the second classification of the same axis rather than annotating
it. Concretely: a third arm would leave a re-matching predicate compiling
and silently answering false, so the two surfaces could disagree about one
condition. Bound-under-empty-list is DissolutionPending by construction, so
the narrower question routes through the one authority.

As with the previous round, the first finding was NOT a compile-time error.
The whole tree including src/v2 compiles at 2276 sources with the bad call
present. This is the second authoring defect in this PR that the typechecker
admitted silently and the compile oracle then reported green.

Census 6/6, carrier 9/9, exclusion 14/14, regen_divergence_count=0 verified
with a locally rebuilt binary.
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Both fixed in ddb7164 (review 50670).

Finding 1 — real, and the double-wrap is exactly what happened: synthetic_wet_lane_row takes description: String and wraps it internally, so passing dissolution: wrapped it twice. Corrected to match the sibling call at line 200; the witness runs 14/14 PASS against its roster.

Finding 2 — took the stronger of the two options you offered. dissolution_is_bound now derives from dissolution_status under an empty present_decls rather than carrying a disposition tag, because deriving removes the second classification of the axis instead of annotating it. The concrete failure that prevents: a third DissolutionCondition arm would leave a re-matching predicate compiling and silently answering false, so the two surfaces could disagree about one condition. Bound-under-an-empty-list is DissolutionPending by construction — DissolutionFired requires a matching declaration and the empty list has none — so boundness is that question asked of the one authority. Census 6/6 and carrier 9/9 stay green, so it is behaviour-preserving.

One correction, same as last round: the bad named argument is not a compile-time error. The whole tree, src/v2 included, compiles at 2276 sources with that call present.

That makes two authoring defects in this PR that the typechecker admitted in silence — a cast from a coproduct to an unrelated refinement type, and now a mismatched named argument — both of which my whole-tree compile oracle duly reported green. Worth naming as one class rather than two slips: the oracle I have been leaning on does not discriminate these, which is why review caught them and I did not. Compiler-layer, and not something I am fixing inside a representation migration.

regen_divergence_count=0, verified with a locally rebuilt binary (the earlier remote build uploads no local artifacts, so its verify could have run on a stale seed).

— sent from valiant-bear-355

gunbc-ci-auto-heal added 3 commits August 9, 2026 02:25
…v2/std

Correcting my own census. The 89 -> 0 population figure reported earlier was
a count of dag/ only, so three declarations in src/v2/std survived a sweep
that claimed to have closed the class:

  decl_facts_skeleton.dag  outer_record_constructor_lexeme_dissolve_on
  decl_facts_skeleton.dag  skeleton_marshal_atom_lexeme_dissolve_on
  orchestration.dag        orchestration_to_effect_plan_dissolve_on

All three predate this PR. Deleted under the zero-consumer rule.

The orchestration row appeared consumed -- two references -- but both were
one string_contains witness asserting that its own prose exists. A test whose
subject is the declaration it asserts the existence of is a change detector,
not a consumer, so it is deleted with the row. host_effect_plan_witness_test
runs 2/2 after.

Census now spans both source roots: zero declaration, field, or parameter
forms of dissolve_on: String|NonEmptyStr. What remains is the word inside
prose and one already-typed dissolve_on: DeclarationRef?, neither a
forbidden form.

regen_divergence_count=0, verified with a locally rebuilt binary.
Two defects, both mine.

DEAD PROSE. This PR deleted 49 zero-consumer prose rows and introduced 27 of
its own -- data ..._note: String rows explaining the migration, which is the
class the PR exists to close (DESIGN 4c: an ordinary String declaration whose
sole purpose is commentary is misplaced or dead data). All 27 deleted rather
than converted to comments: migration history, operator rulings and accounts
of deleted representations belong in the PR body and git history, not in the
source. Two survivors are genuinely referenced -- one bound as a
DeclarationRef in doc_graph_roots, one cited by a sibling module.

MISSING IMPORTS. Five files called unbound_dissolution with no import,
resolving only because an unrelated file dragged std.dissolution into the
pool -- the Class B pool-membership coincidence DESIGN records. CI's
affected-set scoping gave one a narrower closure and it died at evaluation
with 'no such function'. A whole-tree compile cannot catch this: whole-tree
is exactly the closure where the coincidence holds. Explicit imports added.

Verified by execution rather than by the summary line: the first repair
inserted the import inside a multi-line import block and broke the parse,
which claim_batch reported as pass=0 fail=0 -- green-looking. Now 10/10,
18/18, 14/14 on the three affected entries; regen_divergence_count=0.
Review 50736, verified against the tree. All three findings stand.

registration_membership_is_standard, witness_exclusion_row_well_formed and
rust_maintenance_disposition_well_formed each enforced a nonempty dissolve_on
on main. The field migration dropped that half and kept only the reason half,
so a row carrying an empty condition passed all three gates. Restored through
dissolution_description.

WHY THEY WERE DELETED, since the reasoning was wrong and not merely careless:
this PR claimed the empty-condition state had become unconstructible once the
carrier held NonEmptyStr, and removed the checks and their RED controls as a
DESIGN 4b(4) dissolution-on-climb. That premise is false.
unbound_dissolution(description: "") constructs today -- an existing witness
in witness_exclusion_reconciliation_test does exactly that and runs -- because
the cast to NonEmptyStr on a parameter is not enforced at the call. There was
no climb, so the guards were live checks and the claim in the PR body was a
safety assertion with nothing behind it. The body is corrected with this
commit.

roster_registry_test 4/4, witness_exclusion_reconciliation_test 14/14,
stage0_rust_source_lifecycle_scaffold_witness_test 40/40, all counted against
their rosters. regen_divergence_count=0 verified on a locally rebuilt binary.
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

All three findings verified and fixed in 596e894 (review 50736). You were right on each one, and the reason they were deleted is worth stating because it was a wrong argument rather than an oversight.

I removed those guards deliberately, claiming a §4b(4) dissolution-on-climb: that once the carrier held NonEmptyStr, an empty condition was unconstructible, so the checks and their RED controls were redundant lower-rung machinery. That premise is false. unbound_dissolution(description: "") constructs today — witness_exclusion_reconciliation_test does exactly that and runs green — because the cast to NonEmptyStr on a parameter is not enforced at the call site. There was no climb. The guards were live, the deletion left three gates accepting an empty condition, and the PR body carried a safety claim with nothing behind it. The body is now corrected rather than quietly amended.

Restored through dissolution_description in all three, matching frontier_row_well_formed. Counted against rosters: roster_registry_test 4/4, witness_exclusion_reconciliation_test 14/14, stage0_rust_source_lifecycle_scaffold_witness_test 40/40. regen_divergence_count=0 on a locally rebuilt binary.

One related correction in the same push: I previously reported the structural zero wall as blocked on a producer that does not exist. It exists — v2.std.decl_index decl_facts is hermetic and carries each declaration's rel_path and node. Three versions were built and none was landable: a text scan cannot separate an authored field from the same characters inside a string literal, and needs Filesystem.List, which is unpublished hermetically, so it runs only on a dark wet cadence — a wall with no executing consumer; an exact-atom subtree check never sees data foo_dissolve_on, which was 66 of the 91 removed forms; and adding a name-suffix test refuses std.occurrence_binding_candidates's legitimately typed dissolve_on: DeclarationRef?. The wall must key on the field's type rather than its name. Nothing half-working is in the PR.

— sent from valiant-bear-355

gunbc-ci-auto-heal added 2 commits August 9, 2026 04:53
# Conflicts:
#	src/v1/stage0/src/std_algebra.rs
…olution explicitly

Reviews 50750 and 50756, both verified against the tree.

DeclaredHere lost its condition entirely. I deleted the field under the rule
'the coproduct already encodes the transition', but that rule did not apply
here: AuthoredInRoster | DeclaredHere records PROVENANCE, while dissolve_on
named the specific code change that retires each carve-out -- the method-call
short-circuit becoming an algebra arm, the eval_service_call carve-out going
away. Different facts. Both conditions restored verbatim as
DissolutionCondition, with arm_declares_dissolution_trigger and the roster
acceptance assertion that consumes it. The predecessor scanned the sentence
for the phrase 'dissolves when'; the restored check asserts the typed
condition is nonempty, which is the part that is actually decidable.

Two RED controls restored. The previous commit fixed the production guards but
not their evidence, which is the same 4b(4) violation one rung up: a guard
that moved back to validation needs its executing control back with it.

ci_layer_roots (166 call sites) and explicit_witness_admission (21) had NO
import of std.dissolution and resolved purely by pool coincidence. My earlier
sweep FLAGGED both files; a follow-up check I wrote counted lines matching
'dissolution' and 'import' together, which matched their imports of other
modules, so I read the count as proof and dismissed a correct finding. The
re-sweep strips string literals and enforces identifier boundaries: zero
files remain.

Also merges origin/main (968a7c1). The generated std_algebra.rs conflict
was resolved by regeneration, not by hand.

roster_registry_test 5/5, stage0_rust_source_lifecycle_scaffold_witness 41/41,
v1_interpreter_primitive_roster_acceptance 1/1, witness_exclusion 14/14,
exact_witness_admission 18/18, dissolution_census 6/6.
regen_divergence_count=0 on a locally rebuilt binary.
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Both reviews addressed in cfb9d4e (reviews 50750 and 50756). Every finding verified against the tree; all six stand.

DeclaredHere lost its condition. I deleted the field under my rule "the coproduct already encodes the transition" — but that rule did not apply. AuthoredInRoster | DeclaredHere records provenance; dissolve_on named the specific code change that retires each carve-out (the method-call short-circuit becoming an algebra arm; the eval_service_call carve-out going away). Different facts, and the second is not recoverable from the first. Both conditions restored verbatim as DissolutionCondition.

The acceptance check. arm_declares_dissolution_trigger and the assertion consuming it are back, so the contract note is enforced rather than merely stated. One deliberate change: the predecessor scanned the sentence for the literal phrase "dissolves when", which is prose-scanning; the restored check asserts the typed condition is nonempty, which is the decidable part.

The two RED controls. You are right that this is the sharper version of the same mistake: my previous commit restored the production guards but not their evidence, which is the §4b(4) violation one rung up — a check that moved back to validation needs its executing control back with it. Both restored against the migrated signatures.

The missing imports — and this one is worse than a miss. My own corpus sweep flagged both files. A follow-up check I then wrote counted lines matching dissolution and import together, which matched their imports of other modules, so I read "3" and "4" as "already imported" and talked myself out of a correct finding. 166 call sites in ci_layer_roots and 21 in explicit_witness_admission were resolving purely by pool coincidence. The re-sweep strips string literals and enforces identifier boundaries; zero files remain.

Counted against rosters: roster_registry_test 5/5, stage0_rust_source_lifecycle_scaffold_witness 41/41, v1_interpreter_primitive_roster_acceptance 1/1, witness_exclusion_reconciliation 14/14, exact_witness_admission 18/18, dissolution_census 6/6. regen_divergence_count=0 on a locally rebuilt binary.

Unrelated, for the record: the heal job's trim failure on earlier heads was not from this PR — it passes at the post-merge head, it names files this PR never touched, and main independently carries a class_b_trim pool-coincidence investigation. The regen/ci failures at 6b3df64 were autocommit pushing the merge commit before I had regenerated the resolved generated file.

— sent from valiant-bear-355

The build failed with unconditional_panic at std_algebra.rs:1691 --
v1_rt::from_code_point((1 / 0)), a guaranteed runtime divide-by-zero in
generated code.

Cause: main landed a fix for the Class B trim pool-coincidence, adding
fn trim to std.algebra whose declared body is a pure-dag seam (1 / 0) that
the emitter is supposed to special-case into v1_rt::trim(s). When I merged
main I regenerated with a binary built BEFORE the merge, so it lacked that
emitter rule and rendered the seam literally, overwriting main's correct
output. The result then self-verified at divergence 0, because the same stale
binary produced both sides of the comparison.

Fix: restore main's std_algebra.rs, rebuild the binary from it so the emitter
rule is present, then regenerate. trim now emits v1_rt::trim(s).

regen_divergence_count=0 and fmt clean, both on the freshly built binary.
@gunbai-bot
gunbai-bot Bot marked this pull request as draft August 9, 2026 06:15
gunbc-ci-auto-heal and others added 5 commits August 9, 2026 07:48
Bounded restoration pass. Each carrier restored individually and verified by
executing its focused witnesses before moving to the next:

  1 WitnessExecutionDisposition.InterpretedRetained      6/6
  2 NativeRoutingDisposition.InterpretedRetained         6/6
  3 EmitCoverageDisposition.InterpreterRetained
  4 InterpreterWetSurfaceMembership.DeclaredFrontier      9 sites
  5 SelectedWitnessMember.InterpreterFrontier
  6 StateDefinitionLinkage / StateDefinitionCallerAssertion  15/15, 42/42
  7 PlanRetirement nonempty guard + RED fixture           4/4

Each row keeps its original condition; bound_dissolution is used only where an
exact live declaration is known. For StateDefinitionLinkage the SymbolIndex
condition is authored once as symbol_index_subtree_digest_dissolution and
projected through every row rather than copied per row.

A semantic census -- the class, not the spelling dissolve_on -- found eight
further raw-String lifecycle fields under other names (dissolves_on,
dissolve_trigger, dissolves_when, dissolution_trigger), including
InterpreterSurvivingRole.dissolution_trigger in emit_on_demand. That site is why
the previous zero was a spelling census. Three name-matched but already-typed
fields (Symbol / Disposition) were reverted as out of scope.

Adds v2.lens.lifecycle_carrier: a node-local compile gate refusing a record
field whose name is in the lifecycle class and whose type is bare String or
NonEmptyStr. Same grain as unit_modeling_gate (direct children only, so it does
not stack with run_required_lens_gates_on_subtree's fold_node into O(n^2)),
enrolled in always_required_lenses and registered in v2.lens.registry.
Four executing controls: two RED (String and NonEmptyStr spellings), one
positive on the migrated form, and one discriminating positive proving an
ordinary String field passes -- without which a gate rejecting every String
field would satisfy both REDs and still be wrong.

Whole-tree compile: zero lifecycle_carrier diagnostics, no new errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… return

regen_stage0 --verify: regen_divergence_count=0 against a binary rebuilt on the
merged-main tree, so the fixed point is proven rather than assumed. main_wet
produces no further drift; cargo fmt --all --check clean.

The first regen pass exposed a defect the .dag typechecker had admitted:
unresolved_method_frontier_trigger still declared `-> String?` while its body
returned the migrated DissolutionCondition field. The generic Optional return
collapses, so nothing refused at .dag typecheck -- it only surfaced as E0308 in
the emitted Rust. The return type is now DissolutionCondition?, and the caller
projects dissolution_description into the MethodExistenceFrontierAdmitted
diagnostic, which is a rendered message rather than a lifecycle carrier and
therefore stays String. The two Rust test callers use only is_some/is_none and
are unaffected.

Worth recording: ctrl-build reported exit 0 on the build that carried this
error. The failure was visible only in the log body.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The regen job's pre-plan hygiene walk refused v2.lens.lifecycle_carrier for
carrying no construction_justification. Legitimate refusal: DESIGN 5/6 require a
lens to justify why its bad-state class cannot instead be made unwritable.

Classified WallAfterGrounding { dissolves_to: SubstrateMandatoryTag }, not
RatchetForever. Membership is decidable -- a field's name and declared type are
both readable off the Node tree -- so the undecidable arm would be false. It is
not a wall today only because the substrate cannot mandate that a field with a
given name carry a given carrier type, which is the capability the row names as
its trigger; when that lands the raw form loses its constructor and this gate
deletes.

Verified by executing the gate that failed, not by inspection: the naming-hygiene
walk completes clean and regen_verify_gate_passes is green locally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 15 commits August 9, 2026 17:18
The cost-fix commit put its explanatory // block inside the match in
field_lifecycle_violation. DESIGN 4c admits only standalone leading blocks at
module-item grain; body position refuses, so the whole discovery corpus failed
to parse on that one comment.

Moved above the fn. Also swept every .dag file this branch touches for the same
shape -- none remain.

Worth naming: I had been reading this exact diagnostic in other files for
several rounds and classifying it as pre-existing debt, which it was, and then
authored a fresh instance of it myself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Step 1 -- the authority boundary:
  - unbound_dissolution takes NonEmptyStr, no internal cast. The cast form was
    demonstrably not a wall (unbound_dissolution(description: "") constructed,
    which is why the downstream guards had to be restored). Empty literals are
    now refused at compile, with unbound_dissolution_empty_literal_refuses and a
    nonempty positive control as the executing evidence.
  - 37 shared condition constants retyped String -> DissolutionCondition. That
    also removes all 246 non-literal constructor call sites, because the literal
    now lives once in the typed declaration instead of being wrapped per use.
  - synthetic_wet_lane_row accepts DissolutionCondition rather than wrapping a
    String internally.
  - direct-import audit, run against each file's DECLARED imports and exact
    identifiers rather than the ambient pool: 0 across dag/, src/v1/, src/v2/.
    Three files the review named were real; my conversion introduced four more
    and the audit caught them.

Step 2 -- PlanRetirement:
  - PlanRetiresWhen.condition is DissolutionCondition; 141 construction sites
    migrated across 66 files. Unbound throughout: these conditions describe
    future states, and inventing declaration names to raise the bound count is
    exactly what the direction forbids.
  - rendering goes through dissolution_description; the nonempty guard stays,
    now stated against the gap it actually defends.

The three empty-condition RED controls could no longer construct a literal, so
each reaches the empty value through the NON-LITERAL path instead -- which is
precisely the deferred-refinement gap the guards defend. Deleting them would
have recreated specification-without-execution one rung up (DESIGN 4b(4)).

Adding an explicit import to plan_lens_witness_test, which previously had NONE,
narrowed its pool and broke resolution of all_plans and friends -- the Class B
coincidence, caused by my own fix. It now imports from each definer.

Whole-tree compile: 42 diagnostics, all pre-existing in two files with zero diff
from main; zero from this change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…dition

The three g1-cited-symbol-control-* document bindings are permanent
discriminating evidence for feature:cited-symbol-resolution. My Plan migration
wrapped their descriptions in PlanRetiresWhen, producing a model contradiction:
the coproduct said retires-when while the payload said "never retires when the
production population is zero". PlanHasNoRetirement is the arm that already
exists for exactly this.

The module note claimed every HandAuthoredDocBind carries "the trigger that
deletes the row". It does not -- the carrier admits permanent rows and the
module already separates them via hand_authored_bind_is_cited_symbol_resolution_control.
Note rewritten to state both classes and why a permanent row must not be an
unbound future condition.

Two witnesses, both structural rather than textual:
  - cited_symbol_discriminating_controls_have_no_retirement asserts the ARM on
    the filtered control rows. Scanning descriptions for "permanent" would have
    passed on the broken shape.
  - production_doc_binds_all_carry_a_retirement is the positive control on the
    complementary filter, so the first cannot pass by the filter being empty or
    by no row having a retirement at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rows

These were deleted as top-level prose declarations, but their subjects are
live, so deletion was not an honest disposition:

- std.measure still has no Day (grep -cE '\bDay\b' -> 0), and a calendar day
  is not an SI scale of seconds, so refresh_window_days cannot be satisfied by
  picking an existing magnitude row.
- TrackedChannel still carries no resolution date, so pin_currency_gap has no
  derivable positive arm.
- pin_refresh_window_positivity_note still embedded its own dissolve-on clause
  in prose -- the note was the sole authority for an active condition.

pin_frontier_rows is imported and concatenated by census_closure_frontier, so
these are consumed rows, not zero-consumer typed constants. The note keeps its
rationale and loses the clause: it explains, it does not legislate.

The three empty-condition controls could not keep casting String to NonEmptyStr
(v2 refuses the cast); they now reach the deferred non-literal refinement gap
through a returned concat, which is the gap the downstream guard defends.

The hand-count witness moves 21 -> 24 and is renamed, since a test named
_is_twenty_one asserting 24 is a lie. The count remains the tree-copied oracle
its own frontier row already dispositions.
An earlier pass in this PR deleted 63 top-level lifecycle declarations as
"prose". Three of them (the pin trio) turned out to have live subjects; on
inspection so do the rest -- they were removed for their TYPE, not because
their condition was met or their subject vanished. Deleting a live condition
is not a disposition, so they come back, now carrying the authority type:

  data X_dissolve_on: DissolutionCondition = unbound_dissolution(description: ...)

Whole-tree compile: 42 hard diagnostics, byte-identical to the pre-existing set
(10 body-position annotations in host_phase_status_witness_test, 32 undefined
'Empty' in complexity_accumulator_copy/analyze.dag). The two type mismatches the
previous run carried are gone. The 60 restorations added none.

Text is preserved verbatim from the deleted rows, with `{` escaped -- an
unescaped brace in a .dag string is interpolated, not literal.
… their reads

Every top-level declaration whose NAME says the row is the condition itself
(*_dissolution_trigger, *_dissolve_trigger, *_dissolution) now carries
DissolutionCondition, and each of the ~30 consuming files reads it through
dissolution_description(condition: ...) rather than the bare string.

These are consumed carriers, not zero-consumer typed constants: the conditions
are emitted into generated shell comments and asserted by existing witnesses
(ci_spec_witness_test and friends), which is why the retype had to carry the
projection rather than just change a declared type. The projected text is
byte-identical, so no emitted artifact moves.

Deliberately NOT swept: the 39 *_note / *_reason / *_value rows. Those are the
narrative class -- historical receipts, refusal poisons, and rationale prose --
and the reviewer's own table says a narrative-only string stays a String. The
mixed ones (narrative carrying a live clause) are classified next, not
bulk-wrapped.

Whole-tree compile: 42 hard diagnostics, the identical pre-existing set
(host_phase_status_witness_test body annotations, complexity_accumulator_copy
'Empty'). This sweep added none.
…on identity

Two halves of the same finding: a note that is the SOLE authority for a live
condition is a lifecycle carrier wearing narrative clothes.

Extraction (17 declarations). Where a note carried a marked clause (DISSOLVES
WHEN / dissolve-on: / DISSOLUTION TRIGGER), the clause moves into a sibling
`*_dissolve_on: DissolutionCondition` and the note keeps only its rationale.
Where the condition was stated without a marker -- RestAuthScheme and
RestTargetForm having no matching realization, reference_deps and
module_graph waiting on the namespace terminal step, frontier_probe_survey's
knowledge_attributed rows, the octet-to-bool codec bridge, the v1 walker's
owed-not-due retirement, the conformance import envelope -- the condition is
authored explicitly from what the note says, rather than left implicit.

Classification (17 declarations). gunbc.dissolution_migration_census records
every survivor at declaration identity in one of four classes: historical
receipt, dissolves-by-greening, refusal-or-reason carrier, not-a-lifecycle-
carrier. The coproduct HAS NO ACTIVE-CONDITION VARIANT -- that is where the
zero lives, structurally, rather than as a predicate asserting no row is
active, which would be vacuously true over a type that cannot express one.

The witness checks what is actually checkable: the four class lists partition
the population, keys are distinct at declaration identity, and the dedup that
decides distinctness is itself discriminated by a planted duplicate. A dedup
returning its input unchanged would pass the uniqueness assertion and still be
wrong; duplicate_keys_are_detected is what rules that out.

Whole-tree compile after extraction: 42 hard diagnostics, the unchanged
pre-existing set.
Found by running the generated-artifact regenerator, not by the compiler: three
`data ..._runner_scaffold_comment: String = concat("# ", <condition>)` rows in
ci_floor_peak_emit passed `DissolutionCondition` straight into a String concat.
The .dag typechecker accepted it and the interpreter stringified the coproduct,
so the emitted workflow comment read

  # UnboundDissolution { description: 🟡 dissolve-on: ... }

instead of the description. The earlier sweep missed them because it skipped
every line starting with `data ` -- correct for not rewriting a declaration in
place, wrong for a DIFFERENT declaration that reads one. The rule is now the
declaration's own name, not the line's prefix.

Worth stating plainly: nothing in the type system caught this. It surfaced only
because a wet regenerator wrote bytes a drift gate compares -- the same
"declarations are not execution-checked" class this repo has hit before, and the
reason the emitted-artifact regeneration is part of the verification and not a
formality.

Two-pass fixed point: regen_stage0, rebuild, regen_stage0 --verify ->
regen_divergence_count=0. ci.yml and falsifier.yml regenerate byte-identical.
The census carried 17 rows while 35 lifecycle-named String declarations
survived in tree -- so 18 were unaccounted, and a classification record with a
hole is worth less than no record, because it reads as complete.

The 18 are the notes whose condition this PR extracted. They are a real class,
not an oversight to sweep: the condition left, the rationale stayed, and the
reviewer's own table says a narrative-only string keeps its String. Each row
names the sibling its condition became, so the extraction is checkable rather
than asserted -- a NarrativeOnly row pointing at nothing would be the same hole
one level down.

Census population now equals the survivor population exactly (35 = 35, zero
uncensused, verified by an identity join over declaration names, not a count).
…d controls

CI at ca4623c red on a type mismatch in src/v2/test/claim/roster_registry_test:
a fourth `unbound_dissolution(description: "")` control I had not found. There
were two, not one -- witness_exclusion_reconciliation_test carried the same
shape. Both now reach the empty condition through the deferred non-literal
refinement gap, the same way the three earlier controls do, so the evidence
stays enrolled rather than being deleted with the wall it tests.

Neither appeared in the whole-tree compile: src/v2/test/claim/** resolves in the
discovery corpus, not that closure. A green compile is not a green corpus.

The second defect is worse and was NOT in the CI output -- the floor stopped at
batch 3 before reaching it. Running the file locally exposed
falsifier_self_host_wet_dark_lane_unclassified_rows_empty_holds red, because
witness_exclusion_row_waits_on_wet_lane_undarken compared

  dissolution_description(condition: row.dissolution) == excl_wet_integration_dissolve

-- a String against a DissolutionCondition. The typechecker admitted it and the
comparison silently answered false, so the positive predicate stopped claiming
rows the wider candidate net still caught, and they surfaced as unclassified
residue. That is exactly the cross-representation `==` straddle DESIGN records:
it fails OPEN to false, and here the guard designed to catch a silently
deflating predicate is what caught it. Both arms now compare description to
description.

Swept the class rather than the two sites: zero remaining uses of a
DissolutionCondition in a String context (concat, string_contains, ==, !=,
length) across dag/ and src/.

roster_registry 5/5, witness_exclusion_reconciliation 14/14, by execution.
…ss_test

Unnecessary duplicate binding surface in a PR whose subject is consolidating
authority. 13/13 witnesses still pass.
# Conflicts:
#	.github/workflows/ci.yml
#	dag/gunbc/doc_graph_roots.dag
…n a subject

CI at 7b22689 carried 12 REAL witness failures, not the budget refusal I had
been reporting. I misread the earlier runs: the floor did hit its 55-minute
ceiling, but these twelve reds were above it in the log and I did not look past
the terminal refusal. The reds are mine.

CAUSE, and it is a trap this repo documents. shell_bash_runner_witness_test and
cli_run_workspace_root_hand_rust_witness_test had ZERO imports on main and
resolved every symbol by ambient pool membership. My retype sweep added one
`import std.dissolution { dissolution_description }` to each, which flips the
resolver out of ambient-pool mode into declared-imports mode -- so every OTHER
symbol they used vanished. The failures read `no such function:
shell_exec_via_bash`, which is resolution, not semantics. That is Class B
(DESIGN: pool-membership coincidence) caused by my own import edit.

FIX: name the definers explicitly, import-from-definer.

WHAT I TRIED AND REVERTED, because it made things worse. I first swept the whole
class -- eight more files that had zero imports on main -- and added derived
imports to all of them. Whole-tree compile went 42 -> 90 diagnostics, and the
new failures were in files I never touched (complexity_accumulator_copy,
json_emit_witness_test): adding explicit imports REMOVED modules from the ambient
pool that unrelated files were silently relying on. The cascade runs in both
directions, which is why DESIGN blocks further dag/** import-stripping. Only the
two files with actual failing witnesses keep their imports.

The third change is a real DESIGN 4c violation in githooks_pre_push_emit_test,
byte-identical to main: nine trailing `//` lines after the last declaration, an
annotation with no subject. Closure shift pulled the file into scope and exposed
it. Moved above pre_push_line_budget_note, the declaration it discusses.

Verified: 8/8 and 4/4 on the two repaired files. Whole-tree compile 48, of which
32 are the pre-existing `Empty` set and 16 are body-position annotations in
host_phase_status_witness_test -- also byte-identical to main, and a file whose
diagnostics my local 3-root compile surfaces more of than CI's scoped
compile-clean does.
# Conflicts:
#	.github/workflows/ci.yml
#	dag/gunbc/ci_layer_roots.dag
#	src/v1/stage0/src/extdeps_languages_rust_emit.rs
…the 19 survivors it found

The residue census could not ground its own completeness. It answered "here are
the survivors someone wrote down" -- a measurement copied from the same tree,
which DESIGN section 5 rejects as an oracle. Reviewer verdict: derive the
population independently and join at declaration identity.

Doing that refuted the census in both directions at once. Every one of its 35
rows is OUTSIDE the lifecycle name class (they are `*_note` prose), and 19 real
in-class survivors existed that it had never seen -- active lifecycle conditions
still typed String, skipped by the original sweep because their values feed
concat sites. They are migrated here rather than classified, because an active
condition still typed String is a migration miss, not residue.

The population is now derived and gated at zero:

  data_decl_type_facts(pool_roots)   host producer, the missing projection
  gunbc.lifecycle_survivor_scan      derives + gates the in-class population

`decl_facts` marshals a DataItem's node through the initializer projection and
drops `type_annotation`, so no substrate-reachable producer can decide whether a
declaration is still a bare string. The new builtin walks the SAME parse-only,
fail-closed corpus walk `concept_decl_facts` already uses -- it generalizes that
walk with a kind filter rather than forking a second one -- so a file that fails
to parse refuses instead of silently shrinking the denominator. It also does not
skip test files, which `decl_facts_corpus_walk` does; a survivor authored in a
witness would otherwise be invisible.

Measured: 16975 data declarations across 3475 modules, 6903 of them bare-string
typed, zero with an unread type annotation, zero surviving lifecycle carriers.

The name class reuses `lifecycle_field_name_rows` -- the same roster the field
wall consults -- differing only in match shape (fields are named exactly
`dissolve_on`; declarations carry the spelling as a suffix). A second roster
spelled for declarations is the nickname the field predicate exists to prevent.

Evidence, split per the witness-cost ruling. The mechanism half is fixture-shaped
and runs per-PR at ~0ms: a planted raw survivor and a planted NonEmptyStr
survivor must be SELECTED, the migrated form must not be, and an ordinary String
declaration outside the name class must be rejected on the name axis -- without
that last one a predicate rejecting every String would pass. The census half
measures 18482ms against the 5s fast-lane budget, so it is enrolled on
FalsifierSubstrateLongLane with an exclusion row AND five execution rows, never
relocated: a witness moved out of discovery without an executing consumer is
deletion of the evidence with the file retained.

The gate was proven to red by planting a real `data x_dissolve_on: String` in an
isolated worktree: 16981 declarations, one survivor, FAIL.

The census keeps its value and loses its completeness claim; its header said it
held every in-class survivor, and that sentence was false in both directions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/ci.yml
#	dag/gunbc/ci_workflow.dag
#	src/v1/stage0/src/extdeps_languages_rust_emit.rs
#	src/v1/stage0/src/v1_interpreter_dispatch_generated.rs
#	src/v2/workflow/ci_v1_compiler_tests_compile_gate_emit.dag
@briansrls
briansrls marked this pull request as ready for review August 10, 2026 20:40
@briansrls
briansrls merged commit 45e7024 into main Aug 10, 2026
3 of 4 checks passed
@briansrls
briansrls deleted the session/valiant-bear-355 branch August 10, 2026 20:40
gunbai-bot Bot pushed a commit that referenced this pull request Aug 10, 2026
…map onto the 2026-08-10 stop

Two things, the first a live main repair found while validating the second.

MAIN IS RED AND NOTHING WAS GOING TO CATCH IT. #8114 (24ff2da) added 18
SubstrateLongLaneRow literals carrying `dissolve_on:`; #8059 (45e7024)
merged after it and renamed that field to `dissolution: DissolutionCondition`.
Each PR was green alone and the pair is red — the merge race a merge queue
exists to prevent, landing during the runner outage, so no run has reported it.
All 18 now carry `unbound_dissolution(description: ...)` and name their sibling
row explicitly rather than saying "same as sibling row", which is the vague
prose #8059 was eliminating. Verified: compiling ci_layer_roots' closure emits
zero SubstrateLongLaneRow diagnostics (the residual exit=1 is the pre-existing
25-row §4c population in host_phase_status_witness_test.dag, untouched here).

ROADMAP RECONCILIATION. ROADMAP.md is a generated artifact; the authority is
dag/gunbc/roadmap_authority.dag. Baseline control first: the unedited authority
reproduces the committed ROADMAP.md exactly, modulo one trailing newline the
CLI adds — so the instrument was validated before it was trusted.

The structural fix: edge(five-minute-ci-gate -> native-selected-witness-bundle)
is DELETED. The entire CI-cost chain — discovery snapshot, scoped substrate,
early selection, streaming — hung beneath a node that is now stopped and can
never be accepted, so every floor row was unschedulable. It was also backwards
on the merits: a 3,290s floor carries 97s of witness evaluation, so an
infinitely fast evaluator leaves ~97% of the floor standing and native
execution was never the CI-cost lever.

Four rows follow from that:

- native-selected-witness-bundle re-cut from "complete cutover in one PR" to
  the self-host frontier it always was (operator root 3). The frontier is
  stated as measured: of 11 rejecting members in one real 15-file std closure,
  5 are normalize contract violations, 2 the graft guard working, 3 genuine
  LEX/PARSE gaps, 1 uncaptured. A broken contract is a bounded repair; a
  missing capability is a program — they do not schedule together. The sugar
  chain is deferred WITH its SHAs (6888b97 -> f62e838 -> c84842c):
  cherry-picked clean onto main it is 5/5 FAIL, because separability was
  asserted from a description and refuted by execution.
- five-minute-ci-gate carries the measured decomposition rather than a
  narrative: 1,422s discovery/setup, 690s scoped worker, 97s evaluation;
  duplicate discovery 295.7s + 284.3s; selection paid after preparation;
  one missing typed key costing 82-96% of a cold symbol-index build.
- five_minute_ci_gate_program_note updated, because DESIGN cites it as the
  single authority for sub-lane scope and dispatch order and must not carry
  a second copy.
- v2-lens-suite-execution's trigger ("after CI2-0 terminal acceptance") is
  unreachable and now says so. It KEEPS its dependency deliberately: its own
  handback demands zero v1 lens-body executions, so relaxing the trigger would
  only move the frontier into the handback.

Regenerated ROADMAP.md from the edited authority; the lead-budget lens returns
[] (no violations).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff
gunbai-bot Bot pushed a commit that referenced this pull request Aug 10, 2026
…onstructor

wise-boar-328 hit a symptom my first commit did not cover, reproducing it
independently while merging main into #8109. Checked rather than assumed, and
it is real: dag/gunbc/doc_graph_roots.dag calls `HasTrigger { text: ... }` in
81 places and HasTrigger is DEFINED NOWHERE IN THE TREE.

All 81 were introduced by #8059 (45e7024) itself — the same PR that renamed
SubstrateLongLaneRow.dissolve_on. So that PR shipped a nonexistent constructor
81 times and merged during the runner outage, where nothing executed it.

The intended form is not a guess. The field is typed:

  HandAuthoredDocBind.dissolution: PlanRetirement
  PlanRetirement = PlanRetiresWhen { condition: DissolutionCondition }
                 | PlanHasNoRetirement

and the file ALREADY IMPORTS both `PlanRetiresWhen` and `unbound_dissolution`
while using neither — the imports were written for the correct form and the
constructor call was wrong. Each payload is free text describing when the plan
retires, which is UnboundDissolution by construction (BoundDissolution carries
a DeclarationRef, not prose), so every row becomes:

  dissolution: PlanRetiresWhen { condition: unbound_dissolution(description: ...) }

Verified by execution: compiling doc_graph_roots' closure emits zero errors and
zero HasTrigger/PlanRetirement/dissolution diagnostics. The residual 25 hard
diagnostics are the pre-existing §4c annotation population in
host_phase_status_witness_test.dag, untouched and unrelated.

Main needed both halves; the first commit alone would have left it red.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff
gunbai-bot Bot pushed a commit that referenced this pull request Aug 10, 2026
#8116 carries both halves of main's #8059 skew break and is proven green --
main_wet EXIT=0 with zero drift -- so this branch's copy of the same 81 rows is
redundant. Pushing an identical repair from two directions into a merge is the
duplication itself, not a safety margin, and the manager owning #8116 asked
explicitly that it not happen.

CONSEQUENCE, stated rather than hidden: this branch cannot derive an emit plan
again until #8116 lands, so its three new emitted stage0 modules stay unregistered
and the regen chain stays red. That red is inherited from main, not produced here,
and it clears by merging main once #8116 is in. #8115 stays draft until then.

Also correcting arithmetic I put in the closed PR and in the merge commit before
it: 77 is the POPULATION of SubstrateLongLaneRow literals, not the count of broken
fields. The broken field count is 18, out of 21 dissolve_on spellings, three of
which are prose inside strings. The number I quoted answered a neighbouring
question and read as though it answered this one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 10, 2026
gunbc.ci_process_end_to_end already legislated this class — "no check present
means not yet observed and never counts as satisfied; cancelled, timed out,
refused by the infrastructure, and genuinely failed stay four different things"
— but its displaced_cost was written as a PREDICTION ("an absent check
currently reads the same as one that passed elsewhere"), so nothing made it
rank. It now carries measurement, supplied by calm-ram-435 who had recorded the
class before tonight:

  #7932 @ 493de34 (2026-08-07)  a CANCELLED required ci folded into PASS; the
                                tally reported MERGE CRITERIA MET while GitHub
                                held mergeStateStatus=BLOCKED
  #8051 @ b4a8d5d               two runs on one head; the concurrency-cancelled
                                one pinned checks_state at PENDING beside a
                                SUCCESS row
  #8059 (2026-08-10)            merged on a cancelled run → 99 sites, two files

THE SKEW RUNS BOTH WAYS. One cancelled row reads as pass in one direction and
as pending in the other, so no single sign-correction closes it — which is why
red_control now demands an executed control for EACH direction, and says the
verdict derives from the authoritative merge state rather than from aggregating
rollup rows. It also names the adjacent trap: mergeable: MERGEABLE is GitHub's
conflict-freedom field, not a checks verdict, so it is never a second
confirmation of anything.

What #8059 cost is stated as the receipt rather than as a story: main could not
derive its own generated artifacts, every PR adding an emitted module was
blocked, three sessions each found it believing their own branch was broken,
and two independently wrote the same 81-row repair within a minute. None of the
99 is a review gap and none is a review fix — each is a type error the compiler
decides in milliseconds. The only thing that had to happen was for the checks
to run.

Verified: main_wet EXIT=0 with drift confined to this authority edit and its
regenerated ROADMAP.md projection; lead-budget lens returns [].

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff
briansrls pushed a commit that referenced this pull request Aug 10, 2026
…arrier

#8059 closed the dissolution carrier fork but half-migrated two files. Both
declare the new field and import the new API, then populate it with the old one:

  doc_graph_roots.dag   81x  HasTrigger { text: X }  (variant no longer exists)
  ci_layer_roots.dag    21x  dissolve_on: X          (field renamed to dissolution)

Migrated to the pattern #8059 itself uses elsewhere in ci_layer_roots.dag:
  HasTrigger { text: X }   -> unbound_dissolution(description: X)
  dissolve_on: X           -> dissolution: unbound_dissolution(description: X)

Three surviving dissolve_on matches are checked and benign: two are the literal
word inside prose descriptions, one is a declaration named
v1_claim_scoped_witness_dissolve_on. None is a row field.

This is a MAIN breakage, not this branch's: pure origin/main fails the exact CI
command (gunbc run --entry dag/tools/generated_artifact_gate.dag --function
main_wet) with identical errors, and both files here were byte-identical to
main's before this commit. The branch inherited it by merging main, which is why
#8073 went from 1 failing check to 3.

Verified: regen now ExitSuccess, 0 problems, no generated-artifact drift.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 10, 2026
…map onto the 2026-08-10 stop (#8116)

* Roadmap: declare the infrastructure lanes, and make main the fleet's desired state

The roadmap carried no node for most of what is now the priority. Verified
against the authority before writing anything: zero hits for TasksMax, sccache,
compile pool, build cache, Spark, ctrl-build, or the generated-file merge
driver; one incidental hit for GitHub Actions ownership. The three "watchdog"
hits are observation-collapse-watchdog-restatement, a display concept that
happens to share the word with the runner recovery timer.

The fleet lane's six rows all say the same shape - given a stated setting,
apply it and read it back. None binds MAIN as where that stated setting comes
from, which is exactly the gap: the mechanism half was modelled and the
authority half never was.

Meanwhile the work exists in design documents nothing on the roadmap points at.
generated-file-conflict-policy.md is operator-ruled with four chartered lanes
and no nodes. fleet-self-converge-enforcement-design.md names the self-converge
timer as missing on every host and calls it the highest-risk gap. It also cited
roadmap node 2-periodic-actuation, deleted in the 2026-07-27 refresh - repointed
here to its successor fleet-anti-entropy-hygiene rather than left dangling.

Sixteen nodes across five lanes, three of them new:

  fleet +5              main-revision-authority, atomic-convergence-verdict,
                        runner-host-convergence, runner-broker-recovery,
                        spark-inference-serving
  ci-placement +1       compile-pool-envelope
  ci-control (new) 4    owned-execution, executed-coverage-receipt,
                        check-projection, actions-runner-retirement,
                        remote-build-containment
  generated-artifact 2  projection-registry-containment, commit-policy-census
  ci-cost +2            arc-reconciliation, build-once-per-subject
  judgment (new) 1      mechanical-review-service

Focus moves from the v1 exit and guarantee-ladder lanes to the infrastructure
lanes. Nothing is deleted or parked: 98 hidden rows are counted on the page and
one row restores the full view.

The judgment lane is deliberately off the page while its prerequisite is on it.

One witness repair, and it is not cosmetic. witness_projection_is_active_only
rendered through roadmap_authority(), which applies the focus, while both its
negative controls name ACCEPTED nodes. Any focus that stops selecting the
namespace and P-derive lanes therefore makes them absent because HIDDEN, and the
claim greens while proving nothing about acceptance. It now reads the
focus-independent view, where absence can only mean accepted - the same reason
witness_rendered_nodes_are_declared_or_derived already reads both documents.
Proven discriminating by planting an active node's headline as a negative
control (FAIL) and restoring it (PASS).

Executed: generated-artifact drift gate green after regeneration; 44/44
roadmap_authority witnesses; 39/39 roadmap_page; 13/13 roadmap_frontier;
7/7 roadmap_emit.

No acceptance receipts recorded. 123 nodes are active and only 9 carry a bound
closing check; merged is not accepted, and manufacturing receipts for 51 merges
would be the rung inflation this authority spends paragraphs forbidding.
roadmap-receipt-continuity is the one mechanically decidable candidate and is
left for the operator.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff

* Compute fabric above CI, and the two nodes the wind-down inventory named

Two corrections to the previous commit.

ONE: the compute fabric was missing, and owning CI was standing where it
should have been. Building, checking, regenerating, changing machines,
serving models and eventually judging changes are four consumers of one
fabric, not four execution systems, and the previous cut put the build
story underneath ci-control - which makes owned CI the definition of a
build rather than one caller of it.

  compute-exact-work-contract
      exact subject in, one of five typed endings out. A branch name or
      a working directory is not a subject. A provider that cannot serve
      the requested operation class refuses BEFORE running rather than
      answering a smaller question.

  compute-artifact-return-and-materialization
      a write-producing computation cannot report success while its
      declared outputs are unreachable. That is the exact live defect:
      a remote run finished successfully, produced nothing locally, and
      the stale binary left behind was compared against itself.

It grounds on docs/plans/execution-spine-design.md rather than minting a
parallel concept. That document is operator-SIGNED (FLAGS A-E, 2026-07-09)
and its thesis is already that realization and materialization are the only
downstream readers of the dependency view - which is the fabric being asked
for. Minting a second scheduler beside it would have been the nicknaming
DESIGN section 3 forbids, in the place it costs most.

ci-owned-execution, ci-remote-build-containment, fleet-runner-host-convergence
and fleet-spark-inference-serving now depend on it. ci-remote-build-containment
is restated as what it actually is: a MIGRATION, whose only permitted additions
are refusals, and which is deleted once its useful behaviour is a provider
behind the contract. Remote execution does not live there.

TWO: two nodes the inventory named that genuinely had no home.

  ci-floor-discovery-snapshot
      the ordinary and scoped workers each walk the corpus in separate
      processes; the second walk measures around 284 seconds. It carries
      the complete typed result, never a pass-or-fail flag, and a consumer
      that finds it absent, damaged or wrong-subject refuses instead of
      recomputing. Distinct from phased-single-process-ci, which removes
      the cross-PHASE duplicate; this removes the cross-WORKER one.

  compiler-declaration-floor
      a value was observed flowing through a field declared as the wrong
      type while all fifty-two behaviour witnesses over it stayed green.
      Five planted defects refused separately, plus an unchanged-behaviour
      control so the wall cannot be satisfied by refusing more of the
      language. No rung asserted - the claims carrier says where it stands.

Focus adds compute. 100 hidden rows counted on the page.

The focus note now states plainly what a focus is NOT. Off the page sits
real retained work with real remaining boundaries, and nothing currently
records why a hidden lane is paused or what restarts it - a lane frozen
behind infrastructure, one draining to merge, and one parked because its
hypothesis was falsified are three states that all read identically as
absent. That is a missing dimension on the node, and it is named as landing
next rather than papered over here.

Executed: drift gate green after regeneration; roadmap_authority 44/44.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff

* Deduplication before consumers, and the mechanism chain that removes preparation

The compute contract as landed said exact subject in, typed ending out. It did
not say identical computations collapse to one producer, and it did not say the
fabric owns admission. Without both, handing agents a compute interface is a
tidier way for ten callers to launch ten cold builds of one tree - the exact
failure the lane exists to prevent.

  compute-deduplication-and-admission
      two requests naming the same computation are one piece of work: one
      producer, everyone else a consumer of its result. The fabric decides
      how many cold builds a machine carries, what the pool's total demand
      may be, which host serves a request, and what order competing work is
      served in - and tells a caller which of those it waits on. Requests
      differing anywhere in the identity must NOT collapse, and a capacity
      refusal is counted rather than becoming an invisible queue.

It stands IN FRONT OF ci-owned-execution in the graph rather than beside it.
Owning CI adds a consumer, and a consumer added before the duplication is
removed multiplies the load instead of sharing it.

The mechanism staircase, each removing a DIFFERENT duplicate:

  ci-scoped-worker-shared-substrate   the second initialised world. Isolation
                                      keeps meaning separate mutable scratch
                                      and lifetime, never recomputing facts
                                      already fixed and immutable.
  ci-selection-before-preparation     preparation that precedes selection.
                                      Selection is sharp about meaning and
                                      blunt about cost: it concludes the
                                      corpus is irrelevant after discovering,
                                      naming, rostering and indexing it.
  ci-streaming-realization            the barrier between preparing and
                                      executing. Its acceptance property is
                                      that the first witness executes before
                                      the last selected entry is prepared.

Chained by dependency edges rather than declared as a set, so at most the next
one is startable and the limit on concurrent performance mechanisms falls out
of the graph instead of being prose nothing enforces. phased-single-process-ci
now sits behind the scoped-substrate row for the same reason. Width two is
deliberately absent from the chain and stays parked: the tested implementation
shared typed bytes while each worker still built its own world.

compute_consumer_admission_sequencing_note records the ruling and, separately,
that native realization and shared preparation are ONE programme. Emitting a
native bundle is the right destination and the miniature is decisive at its
scale, but the cited production enrolment delivered zero of three native and
three of three fallback, so the required path took no benefit - and native
bodies surrounded by duplicated preparation would still be bad CI.

Executed: drift gate green after regeneration; roadmap_authority 44/44.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff

* Review response: native cutover unblocked, thresholds out of RED controls, dedup bound to a real build

Four review findings acted on. The lifecycle finding is answered by sequencing
rather than by content and is stated at the end.

NATIVE CUTOVER WAS STALE AND ORDERED BACKWARDS. native-selected-witness-bundle
read "merge #7599 once controls clear" and "fallback counts trending to zero".
#7599 is MERGED, and the cited production enrolment ran none of its three
selected members natively and fell back on all three. So the mechanism exists,
the required path takes no benefit, and the node was still describing the
mechanism as the work.

It is now a REPLACEMENT: emit the bundle, execute the selected population by
direct call, and DELETE that population's interpreter scheduling in the same
change. Interpretation survives only as a named differential control on a
cadence, never as a success arm the production path falls through to. Fallback,
interpreted and unavailable all at zero is the bar, not a residue to trend.

Its two parent edges are removed and one is REVERSED: five-minute-ci-gate now
depends on the cutover. The gate is an aggregate outcome, so making the cutover
wait for it meant the one step that removes the interpreter from the required
path could not start until the programme it contributes to had succeeded. The
warm-merge edge went with it - no input dependency was ever shown; the bundle
needs a selected population, an emitter and a toolchain, none of which merge
admission supplies. The node now has no parents and is startable.

witness_five_minute_ci_gate_program_chain_is_explicit CAUGHT THIS, which is
what it is for. It pinned the old edge shape, so the reordering had to be
deliberate rather than incidental. Updated to require the reversed edge and to
assert BOTH old edges absent, so the previous direction cannot return silently.

TIME THRESHOLD REMOVED FROM A SEMANTIC RED CONTROL. ci-scoped-worker-shared-
substrate required "the scoped segment falls by at least three minutes". That
is a tree-measured number standing in for a structural claim - the same shape
DESIGN section 5 rejects for census pins. Replaced with what the row actually
means: no second source loading, no second index construction, no second
initialised world, same population, same outcomes, bounded scratch, no path
back to cold construction. Wall, CPU and memory sit beside it as observations.
A timer moving cannot claim a duplicate was removed, and a duplicate genuinely
removed is not disqualified by a noisy host.

DEDUPLICATION IS BOUND TO A REAL ARTEFACT BUILD. Its first slice was open to
being demonstrated on two read-only checks collapsing into one verdict - the
one case where duplicate work costs nothing, while the case that swamps the
fleet is two cold builds. It now names two agent sessions requesting the same
artefact-producing build, one producer, one compilation, one returned output,
two attached consumers - and it depends on artifact return rather than
standing beside it.

LIFECYCLE: not in this PR, by agreement with the review. ProgramDisposition and
the work-item agreement land first as their own change and this stacks behind
them; RoadmapNode is constructed in 19 files and that shape change deserves an
isolated review rather than riding a 24-node expansion.

Executed: drift gate green after regeneration; roadmap_authority 44/44 with the
chain witness green on the new direction.

CI failure on b47d383 was infrastructure, established two ways: the regen job
died at "Setup Rust" with rustup ETXTBSY (exit 126, 10s in, before any content
ran) because runner slots share one home directory; and gunbc.roadmap_authority
is absent from the 112-module regen input closure, so this change cannot alter
regen output. regen_stage0 --verify run locally reports divergence count 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff

* Lane 1 gets its node: commit-writer admission is scheduled first, not implied

Review response (PR #8034 review, finding 1): the conflict-policy charter's
four lanes were covered two-of-four, and the uncovered pair included lane 1 —
the one the charter titles "FIRST: the live safety hole" and the one
gunbc.repo_local_git_config's authority note names as the boundary a writer
cannot pass. A generated-artifact lane whose first row is the population and
whose absent row is the writer reads, on the page, as if the safety hole is
scheduled. Now it is scheduled, as the parent of the lane-2/3 chain, matching
the charter's own transaction ("prove no unmerged index entries — lane 1
predicate").

The node transcribes the charter's two refusal arms (unmerged-stage refusal;
staged-blob conflict-marker-grammar refusal) and the operator's second-pass
acceptance wall (complete staged-index observation, observed-not-declared
classification, provenance-receipt fixture exemption, writer bindings as
countable carriers). ROADMAP.md regenerated via generated_artifact_gate
main_wet; all 44 roadmap witnesses green by execution with the node in place.

Deferred per the same review's recommendation, recorded here: lane 4 (keyed
rosters get set/map construction semantics) and the execution-spine-design.md
doc-graph binding (needs a typed HandAuthoredDocBind anchor or a plan
registration) stack behind the sequenced work-item PR.

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

* Consolidation: quarry #8033, add the deterministic confidence lane, reframe owned CI

Operator consolidation ruling (2026-08-08): #8034 is the sole roadmap authority
branch; #8033's parallel edits port here rather than merging beside it.

Ported from #8033, at their exact homes rather than as new identities:
- placement-compile-pool-envelope absorbs the task-vs-outer-budget distinction
  as typed acceptance classes (ProcessAdmissionExhausted, OuterResourceEnvelopeKilled,
  EffectiveLimitMismatch, CompilePoolPlacementRefused) plus the 8.8%-of-visible-limit
  receipt. No second placement identity.
- The five false-verification incident classes map to their existing exact homes
  in false_verification_incident_mapping_note; the proposed umbrella node does
  not port (a coarse identity over mechanisms this graph already decomposes is
  the §3 second authority).
- ci-gate-contention-independent-verdict lands as the one genuine gap, recut
  qualitatively: host load cannot decide a semantic merge verdict; timeout is a
  typed execution outcome, never assertion failure; the cutoff is never widened.

New lane: confidence-semantic-impact-query (owner confidence, on the focused
page) — the deterministic repository-inspection product, explicitly independent
of LLM/Spark; judgment-mechanical-review-service now depends on it as its
grounding packet. First consumer is one real corpus query usable by a person,
not a fixture suite.

Reframed: ci-owned-execution's old floor is quarry + shadow oracle, not the
template — obligations port only on a proven disagreement; first slice is the
exact-subject → bounded population → emitted bundle → owned execution → typed
receipt chain with the old path shadowing.

Updated: the focus note's namespace standing now carries the 2026-08-08
exact-subject re-observation (A–D established, E/F unavailable under P2a
triggers, frontier 2), superseding the stale none-of-six wording.

Structure: 151 unique ids, acyclic, no dangling edges, all cited paths resolve.

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

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Spark enrollment as fleet membership, and abstraction formation on the confidence chain

Two operator directions (2026-08-08), landed as four graph changes.

fleet-spark-host-enrollment: srv5/srv6 stop being hand-managed boxes. The
endpoint rows are DERIVED as a downstream projection joining procurement
identity and network allocation — re-typing the reserved address literal
refuses (§3 fork), a reverse import into the network intent refuses (the
measured cycle: procurement already imports it), and a second host-identity
authority refuses. Enrollment carries a GB10 inference envelope, never
runner-style thread capacity. Identity converge + reach ride the installed
fleet key. fleet-spark-inference-serving now depends on it; runtime, model
revision, auth and the collector bundle stay in the serving row, sequenced
separately per the operator's "1 and 2 now".

abstraction-candidate-discovery (owner confidence): descriptive grouping of
subjects observationally equivalent under a NAMED lens, carrying the
distinctions the quotient would erase, nearest existing authorities, and
over-collapse/demand standing. Descriptive evidence only — the normative
"these should share a layer" is an explicit bridge in the judgment row, per
the abstraction-calculus mode-crossing rule. Deterministic: no Spark, no LLM.
First slice hard-stops on an APPLIED acceptance (consumer migrated, duplicate
deleted, receipts equal) so discovery cannot become an inert analysis
service. REDs plant the three negative classes: keep-distinct on a
load-bearing distinction, projection-missing on a downstream-join pair (the
Spark endpoint session is the live receipt), demand-absent on a
consumer-less candidate.

judgment-mechanical-review-service broadens to the abstraction/modeling
ruling vocabulary (existing-authority, likely-duplicate,
candidate-new-abstraction, projection-missing, reprime-candidate,
keep-distinct, over-collapse-risk, missing-consumer/actuator/readback,
unknown) and gains the discovery dependency. Chain: confidence → discovery
→ judgment ← spark-serving; the Spark ranks and explains over exact packets,
it never becomes the repository index.

Structure: 153 unique ids, acyclic, no dangling edges; ROADMAP.md
regenerated via main_wet; 44/44 roadmap witnesses green by execution.

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

* Regenerate ROADMAP.md from the merged authorities

Post-merge projection: the conflict on the generated file was taken
provisionally and the bytes here are main_wet's output over the merged
authority state, per the generated-file policy (regenerate, never
hand-resolve).

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

* Bind the Spark standup accounting doc: main's floor has been red since #7972 landed it orphaned

docs/plans/spark-standup-program-accounting.md landed in the #7972 omega with
no HandAuthoredDocBind and no inbound link, so doc_graph_has_no_orphan_docs
(and doc_graph_is_clean) have correctly refused every main push since the
last green at 4cdcd57 — the doc-reachability wall working as designed,
fleet-wide. Attribution receipt: replaying the doc-graph reachability rule
(ROADMAP.md/DESIGN.md/runbook roots + registered plans + hand binds, markdown
links as edges) over last-green main, current main, and a candidate branch
shows exactly one orphan appearing in the window, this doc.

The bind anchors on the physical facts the doc records —
gunbc.dgx_spark_procurement spark_a3ee_reservation / spark_3bd5_reservation —
and its dissolution names the follow-up the doc itself declares: the Spark
standup program landing as roadmap rows, findings migrating to typed
carriers, then the doc registers as a plan or deletes and the bind deletes
with it.

Verified by execution: doc_graph_has_no_orphan_docs and doc_graph_is_clean
both PASS on this tree; both FAIL on its parent.

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

* Floor fixes: four boundaries back inside the brief budget; ROADMAP reprojected

The floor's brief-budget witness (100 words of authored boundary per ticket,
gunbc.roadmap_page ticket_brief_word_budget) redded on four nodes this branch
authored or lengthened: ci-owned-execution (104), commit-writer-admission
(106), abstraction-candidate-discovery (114), judgment-mechanical-review-
service (114). Each boundary is trimmed to <=100 tokens with no clause of the
bar dropped — overflow either compressed or already carried by the node's
other fields (abstraction discovery's no-model-server fact lives in its
out_of_scope). Max boundary is now 99.

The sibling doc-graph reds are main's breakage (the #7972 omega landed
docs/plans/spark-standup-program-accounting.md orphaned; every push since
last-green 4cdcd57 refused): fixed for the fleet in PR #8053 and carried
here by cherry-pick so this branch's floor does not wait on that merge.

Verified by execution on this tree: witness_ticket_brief_budget_holds_and_reds
PASS, doc_graph_has_no_orphan_docs PASS, doc_graph_is_clean PASS, roadmap
suite 44/44, regen ExitSuccess.

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

* Final Spark/convergence recut per executive verdict

Narrow Spark enrollment to membership/profile/endpoint with honestly
Unobserved cells; join lifecycle cells into the fleet convergence
verdict and name the one-producer defect; spell the inference-serving
internal path; make the fleet participation migration the first
abstraction-candidate-discovery specimen.

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

* Add ci2-complete-native-cost-receipt: whole-corpus native shadow experiment as the bounded cutover's immediate successor

Operator direction 2026-08-08: keep CI2-0's bounded acceptance attainable;
measure emission/compilation/execution walls separately over the complete
roster, then decide from the measured warm wall whether per-PR selection
remains load-bearing or is deleted.

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

* CI-0 recut: one row, one PR — fallback deleted, whole corpus classified, emitted, executed, authoritative (operator 2026-08-08)

Collapses diagnosis-precursor / bounded-cutover / whole-corpus-receipt
into a single state transition on native-selected-witness-bundle;
deletes the ci2-complete-native-cost-receipt row added earlier today.

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

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Add roadmap-serve-emitted-realization: dissolve the interpreted serve scaffold via emit-on-demand (srv1 outage 2026-08-08)

Interpreted concat clones its accumulator (quadratic); emitted concat
moves (linear). Order: emit wiring first, content-hashed bodies second,
concurrency last; request deadline regardless; belt GcpProjectId fix
folded in.

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

* Reconcile #8034 per operator review: record #8054 failed acceptance on confidence-semantic-impact-query; collapse five-minute-gate parent onto the CI-0 one-PR child (cursor review 50559 §3 finding)

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

* Wire compiler-declaration-floor into guarantee_ladder_edges (cursor review 50566)

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

* Catch #8034 up to the day's rulings: CI-0 staged (3-member merge, producer successor, v2-only terminal), general-witness-body-producer row with construct census, CONFIDENCE post-rework standing, structural fork detector as abstraction-discovery first slice

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

* Operator amendment: two judgment modes over one evidence substrate, semantic judgment receipt, model-selection successor, serving infra acceptance, participation-criterion detector, forward-intent refusals

Incorporates worker corrections: participation over shape as the
mechanical criterion; consumer-verb stringly-enum class moved into the
deterministic detector; runner-vs-inference capacity control marked
not-yet-built.

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

* Wire fleet-runner-broker-recovery into the fleet graph (cursor review 50583)

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

* Wire ci-executed-coverage-receipt and ci-gate-contention-independent-verdict as prerequisites of ci-check-projection (cursor review 50587)

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

* De-number the gate program prose: dispatch order follows graph edges (cursor review 50595 non-blocking finding)

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

* CI2-0 mandate recut: one node, complete v2 witness-execution cutover in #8043 — producer successor row deleted (operator mandate 2026-08-08)

The census's 3-of-9,353 was circular (restated enrollment, never
attempted realization); the fixture route's limits were mistaken for
compiler limits. No successor PRs; canonical-pipeline wiring, per-identity
semantic-kind x realization-standing from actual attempts, predecessor
deletion, and the whole-population receipt all land in #8043.

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

* Dirty-worktree verification as compute's first daily consumer (operator verdict 2026-08-08)

Amends compute-exact-work-contract first_slice: exact dirty-tree snapshot
runs all affected (or explicitly conservatively complete) v2 tests, exact
receipt at most 5s warm, BaseUnstable a distinct answer; confidence
optional for narrowing, never correctness. No new node.

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

* V2-LENS-0 node and the two-command product interface (operator convergence mandate 2026-08-09)

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

* Heal main: link the #8062 probe receipt, admit its specimen module to the debt ceiling, read trim's input in its seam

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

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Move the probe-receipt link to the emitting plan authority (review 50763)

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

* Regenerate model-realization-fork.md from the amended authority

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

* Hoist in-body annotations to module grain in two witness files (12 §4c refusals)

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

* V2-LENS-0: dispatch trigger, checkpoint structure, permanence laws (operator ruling 2026-08-09)

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

* Record the four-lane closeout and the root it identified

Four lanes (CONVERGE, CI RESET, CI2-0, DEVBOOT-0) closed 2026-08-10 with zero
displacement between them. Each was asked for the root with evidence and
explicitly invited to reject the manager's hypothesis; all four declined to
confirm it.

The re-cut that matters: of 11 rejecting members in one real std closure, 5 are
normalize contradicting its OWN declared contract (retaining wrapper
declarations, then rejecting the tree those retentions live in via its own
module-grain well_formed gate) and only 3 are genuine frontend gaps. A broken
contract is a bounded repair; a missing capability is a program.

Synthesis across the four: nothing could be verified incrementally — the
acceptance contract demanded the whole corpus and moved between measurements,
the mechanism demanded 60-75 minutes and gated deploys as well as merges, and
the instruments built to escape both were themselves unverified.

Written to git rather than left in message threads because five sessions were
archived today holding measurements, one leaving a PR whose premise had been
reverted underneath it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff

* Heal main's SubstrateLongLaneRow schema break, and reconcile the roadmap onto the 2026-08-10 stop

Two things, the first a live main repair found while validating the second.

MAIN IS RED AND NOTHING WAS GOING TO CATCH IT. #8114 (24ff2da) added 18
SubstrateLongLaneRow literals carrying `dissolve_on:`; #8059 (45e7024)
merged after it and renamed that field to `dissolution: DissolutionCondition`.
Each PR was green alone and the pair is red — the merge race a merge queue
exists to prevent, landing during the runner outage, so no run has reported it.
All 18 now carry `unbound_dissolution(description: ...)` and name their sibling
row explicitly rather than saying "same as sibling row", which is the vague
prose #8059 was eliminating. Verified: compiling ci_layer_roots' closure emits
zero SubstrateLongLaneRow diagnostics (the residual exit=1 is the pre-existing
25-row §4c population in host_phase_status_witness_test.dag, untouched here).

ROADMAP RECONCILIATION. ROADMAP.md is a generated artifact; the authority is
dag/gunbc/roadmap_authority.dag. Baseline control first: the unedited authority
reproduces the committed ROADMAP.md exactly, modulo one trailing newline the
CLI adds — so the instrument was validated before it was trusted.

The structural fix: edge(five-minute-ci-gate -> native-selected-witness-bundle)
is DELETED. The entire CI-cost chain — discovery snapshot, scoped substrate,
early selection, streaming — hung beneath a node that is now stopped and can
never be accepted, so every floor row was unschedulable. It was also backwards
on the merits: a 3,290s floor carries 97s of witness evaluation, so an
infinitely fast evaluator leaves ~97% of the floor standing and native
execution was never the CI-cost lever.

Four rows follow from that:

- native-selected-witness-bundle re-cut from "complete cutover in one PR" to
  the self-host frontier it always was (operator root 3). The frontier is
  stated as measured: of 11 rejecting members in one real 15-file std closure,
  5 are normalize contract violations, 2 the graft guard working, 3 genuine
  LEX/PARSE gaps, 1 uncaptured. A broken contract is a bounded repair; a
  missing capability is a program — they do not schedule together. The sugar
  chain is deferred WITH its SHAs (6888b97 -> f62e838 -> c84842c):
  cherry-picked clean onto main it is 5/5 FAIL, because separability was
  asserted from a description and refuted by execution.
- five-minute-ci-gate carries the measured decomposition rather than a
  narrative: 1,422s discovery/setup, 690s scoped worker, 97s evaluation;
  duplicate discovery 295.7s + 284.3s; selection paid after preparation;
  one missing typed key costing 82-96% of a cold symbol-index build.
- five_minute_ci_gate_program_note updated, because DESIGN cites it as the
  single authority for sub-lane scope and dispatch order and must not carry
  a second copy.
- v2-lens-suite-execution's trigger ("after CI2-0 terminal acceptance") is
  unreachable and now says so. It KEEPS its dependency deliberately: its own
  handback demands zero v1 lens-body executions, so relaxing the trigger would
  only move the frontier into the handback.

Regenerated ROADMAP.md from the edited authority; the lead-budget lens returns
[] (no violations).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff

* Heal the second half of the #8059 schema break: HasTrigger is not a constructor

wise-boar-328 hit a symptom my first commit did not cover, reproducing it
independently while merging main into #8109. Checked rather than assumed, and
it is real: dag/gunbc/doc_graph_roots.dag calls `HasTrigger { text: ... }` in
81 places and HasTrigger is DEFINED NOWHERE IN THE TREE.

All 81 were introduced by #8059 (45e7024) itself — the same PR that renamed
SubstrateLongLaneRow.dissolve_on. So that PR shipped a nonexistent constructor
81 times and merged during the runner outage, where nothing executed it.

The intended form is not a guess. The field is typed:

  HandAuthoredDocBind.dissolution: PlanRetirement
  PlanRetirement = PlanRetiresWhen { condition: DissolutionCondition }
                 | PlanHasNoRetirement

and the file ALREADY IMPORTS both `PlanRetiresWhen` and `unbound_dissolution`
while using neither — the imports were written for the correct form and the
constructor call was wrong. Each payload is free text describing when the plan
retires, which is UnboundDissolution by construction (BoundDissolution carries
a DeclarationRef, not prose), so every row becomes:

  dissolution: PlanRetiresWhen { condition: unbound_dissolution(description: ...) }

Verified by execution: compiling doc_graph_roots' closure emits zero errors and
zero HasTrigger/PlanRetirement/dissolution diagnostics. The residual 25 hard
diagnostics are the pre-existing §4c annotation population in
host_phase_status_witness_test.dag, untouched and unrelated.

Main needed both halves; the first commit alone would have left it red.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff

* The cancelled-check row stops predicting and carries its three receipts

gunbc.ci_process_end_to_end already legislated this class — "no check present
means not yet observed and never counts as satisfied; cancelled, timed out,
refused by the infrastructure, and genuinely failed stay four different things"
— but its displaced_cost was written as a PREDICTION ("an absent check
currently reads the same as one that passed elsewhere"), so nothing made it
rank. It now carries measurement, supplied by calm-ram-435 who had recorded the
class before tonight:

  #7932 @ 493de34 (2026-08-07)  a CANCELLED required ci folded into PASS; the
                                tally reported MERGE CRITERIA MET while GitHub
                                held mergeStateStatus=BLOCKED
  #8051 @ b4a8d5d               two runs on one head; the concurrency-cancelled
                                one pinned checks_state at PENDING beside a
                                SUCCESS row
  #8059 (2026-08-10)            merged on a cancelled run → 99 sites, two files

THE SKEW RUNS BOTH WAYS. One cancelled row reads as pass in one direction and
as pending in the other, so no single sign-correction closes it — which is why
red_control now demands an executed control for EACH direction, and says the
verdict derives from the authoritative merge state rather than from aggregating
rollup rows. It also names the adjacent trap: mergeable: MERGEABLE is GitHub's
conflict-freedom field, not a checks verdict, so it is never a second
confirmation of anything.

What #8059 cost is stated as the receipt rather than as a story: main could not
derive its own generated artifacts, every PR adding an emitted module was
blocked, three sessions each found it believing their own branch was broken,
and two independently wrote the same 81-row repair within a minute. None of the
99 is a review gap and none is a review fix — each is a type error the compiler
decides in milliseconds. The only thing that had to happen was for the checks
to run.

Verified: main_wet EXIT=0 with drift confined to this authority edit and its
regenerated ROADMAP.md projection; lead-budget lens returns [].

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018gTJKsR5YdkaEc2SUGN9ff

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 11, 2026
#8116 landed both halves of the #8059 dissolution-carrier skew and #8110 was
reverted, so main derives its own artifacts again and this branch's inherited red
clears. Merged with no conflicts -- the previous commit had already reverted the
duplicated heal, which is what left nothing to collide.

The three new emitted stage0 modules are now registered by the derived plan rather
than by hand: the bridge witness, the declaration matrix, and its support module.
`main_wet` reaches a fixed point proven by BYTES rather than by a third quiet pass
-- md5 of .gitattributes, ci.yml and the emit plan is unchanged across a further
run -- and the two-round seed regen verifies at regen_divergence_count=0 with
build exit checked before the verify.

Evidence re-run on the merged tree, not carried over: all seven scoped-roster
witness files green -- the declaration matrix 18/18, the import-deletion bridge
3/3, and the four siblings 13/4/4/7/3. Zero failures.

Co-Authored-By: Claude Opus 5 (1M context) <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.

1 participant