Repository navigation
Derive serialized generated projections inside a pre-merge admission transaction - #10183
gunbai-bot[bot] wants to merge 7 commits into
Conversation
…transaction
A serialized generated projection must be derived from the composed authority
INSIDE the transaction that advances main. Post-merge regeneration is rejected
because it opens an interval in which main holds authority and projection from
different states; and a remediator on a mutable branch cannot establish
admission order no matter how correct its bytes are.
gunbc.projection_admission_transaction models that transaction and executes its
consequences rather than asserting them:
* the candidate is composed from the trunk tip and the lane's AUTHORITY only,
with a typed refusal arm where the composition is not total (a whole-row
.dag conflict was measured 2026-09-03, so step 3 refuses rather than
resolving on the lane's behalf);
* P is derived from the composed authority -- the lane's inherited projection
bytes are read nowhere in apply_derive, and that omission is the ruling;
* sealing refuses any machine-authored change outside the derived set;
* verification is the retained read-only equality, RELOCATED rather than
deleted: the merge driver and the generated-artifact phase stop being late
detectors of predictable invalidation and become the verifier of
admission-produced bytes;
* the advance is atomic against base and roster, and discards the candidate
when either moved.
Three separately falsifiable claims, all executed by
test.claim.projection_admission_transaction_witness (21 witnesses, all green):
* ORDER. One discriminating pair differing only in derivation order. The
rejected order's trace ENDS coherent -- the regeneration repairs it -- so
the latch, not the end state, is the evidence: the interval having existed
is the defect. Across the rejected order's own 40-sequence window every
sequence opens an incoherent interval; across the ruled order's 70-sequence
window none does.
* SLOT. Human announce, dashboard freeze roster and advisory lease all lose
the candidate on the peer-advance trace the enforced merge queue and the
admission coordinator land. The roster axis is separated out and shown to
discard IDENTICALLY under both slot kinds, so an enforced slot is not
credited with refusals it does not cause.
* SHARD. The rule is written over the derived resource (generator plus
authority closure), never over an observed file list. Two ledgers with
disjoint OUTPUTS share one generator and refuse; two resources with
disjoint CLOSURES admit. The starting policy is globally serialized and is
relaxed only by a closure proof.
First-implementation scope is enforced by construction, not by prose: a member
whose generator is built from its own output (the stage0 bootstrap mirror)
classifies as RequiresBootstrapFixedPointArm and a lane carrying one refuses at
derive, so the whole-document ledgers cannot be silently generalized over the
mirrors.
Rung: mitigatable, ceiling mechanically preventable -- an admission slot is a
fact about a coordinator's behaviour over time and no constructor here makes it
unwritable. The next-rung trigger is the CAPABILITY (an enforced slot excluding
another main advance for the critical window, plus a production producer that
mints the candidate), not an artifact. This lands the model and its executed
evidence; it is not the enforcement, and the hand queue remains the honest
interim mitigation until the trigger lands.
Files one gunbc.recurring_failure_mode row,
remediator_read_as_admission_order, carrying the recognition rule and both
directions of the file-list shard misread.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YRSSLXXVjavzktziwdpEpH
… classifier Ruling A (operator, 2026-09-03), from a self-audit of the previous commit: two of this module's three parts were not what they claimed to be, and the classifier that WAS production-shaped was keyed on the wrong type. ELIGIBILITY IS NOW AN EXHAUSTIVE MATCH OVER gunbc.generated_artifact GeneratedArtifact. It took a ProjectionMember record carrying a hand-declared generator_built_from_own_output boolean; a caller can build any record, so a NEWLY ADDED ARTIFACT WAS SILENTLY ELIGIBLE and the classifier could be satisfied by editing the declaration while the realization lied -- DESIGN section 5's own tell for validation standing where construction was available, plus a section 3 second carrier for an identity the registry already owns. GeneratedArtifact is a closed coproduct whose emit dispatch is already an exhaustive match, so keying on it means a new variant cannot compile until it is classified. THE RUNG CHANGE IS MEASURED, NOT ASSERTED. Deleting one arm and compiling the module refuses with `non-exhaustive match: missing variant(s) DesignRungDropsArtifact`, one blocking error -- the same refusal a newly registered artifact meets. The discriminating RED is authorable in the module itself, so the probe needs no fixture. THE SHARD CLASSIFIER IS DELETED RATHER THAN STAGED. Its authority_closure was a hand-supplied list: the same defect one level down, and precisely the presumption the ruling forbade when it said path-disjointness must not be presumed. The starting policy is global serialization, which needs no classifier; a rule keyed on v2.lens.module_graph would come back as construction. Its four witnesses go with it -- keeping evidence for a rule the module no longer implements would be the inert-lens tier. The population is now DERIVED from committed_generated_artifacts() rather than declared beside it, and the two arms are asserted to partition it exactly, so a member falling out of both is not writable either. Exactly two members are deferred: the emitted Rust under src/v1/stage0/src that `gunbc` is compiled from. A new witness pins that the discriminant is the BOOTSTRAP LOOP and not the neighbourhood -- a stage0 `.dag` projection sits beside the two mirrors and is derivable, because nothing is built from it. 19 witnesses, all green. The state machine stays as declared evidence with the role named honestly: a theorem carrier plus a regression control that reds if post-merge regeneration is proposed again (DESIGN section 4b(4) keeps a class's discriminating evidence enrolled). "Checked against" is deliberately absent -- nothing checks a coordinator against this mechanically, and writing that it does would be the rung inflation section 4b(1) names. Also records, in the module note and deliberately NOT in the projected roster row, that the remediator's push can SUSPEND the required aggregate in action_required (gunbc#10157, two hours, reads identically to "no checks reported") -- editing a projected ledger to record a fact about projection churn would cost the exact regeneration this lane exists to remove. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YRSSLXXVjavzktziwdpEpH
…ger by union The conflict is this lane's own subject arriving as a specimen: #10145 landed `non_execution_undifferentiated_by_what_it_silenced` while this branch carried `remediator_read_as_admission_order`, so both the authority and its projection collided. RESOLVED BY UNION, AFTER CHECKING THAT UNION IS SOUND. A union resolve on a roster is only safe if nothing was deliberately DELETED on the other side -- otherwise it silently re-adds a row someone removed on purpose, and git reports a clean append/append resolve either way. Measured against the merge base before resolving: main added exactly one row and removed none. Verified after, by identity join rather than by count: 68 roster entries and 68 declarations, with both comm directions empty. docs/design-failure-modes.md WAS NOT HAND-MERGED. The generated-artifact merge driver refused it exactly as designed -- ours side in the worktree, path left unmerged, regeneration recipe printed -- so it was regenerated from the merged authorities and checked to carry both lanes' rows. CONTROLS RE-RUN AGAINST THE SHIPPED TREE, not the pre-merge one. Main brought ~1,600 lines of seed Rust, so the binaries that certified the previous head no longer described this one: gunbc and claim_batch were rebuilt from the merged tree, the 19 witnesses re-run green against it (19 PASS / 0 FAIL / 19 roster), and a second regeneration under the rebuilt binary left the projection byte identical -- a fixed point, so the bytes are not an artifact of a stale emitter. The module note gains the cost this lane is denominated in, now measured rather than argued: five lanes contended the failure-mode ledger and four the rung-drop ledger, every pair conflicting, order decided by hand. It also gains the stronger argument, which is a correctness one: the union-soundness check has to be made against the merge base, an admission transaction over the composed candidate holds the merge base and both sides at the moment it decides, and a human resolving on a mutable branch has to remember to look. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YRSSLXXVjavzktziwdpEpH
…trigger The search for an operational consumer of projection_member_eligibility returned nothing, and that negative result was reachable only from a message thread. It belongs where a held PR's next owner looks. Four sites partition the generated-artifact population, on four different axes, and none asks "may this member be derived here": heal_push_plan sorts on CREDENTIAL, required_regen regen_scope_select on AFFECTED SET, stage0_rust_source_lifecycle_scaffold on GENERATED VS HAND-MAINTAINED (an identity join committed_generated_artifacts already answers), and generated_artifact_emit main_wet applies no filter at all -- it folds the whole committed population in one pass, both stage0 .rs mirrors included, verified against a real regeneration run rather than read off the source. Consulting this module from any of them is a category error, not a wiring change: same population, different question. The near miss is recorded too, because it is the strongest candidate and still fails. The merge driver's repair steps and spine_regen_recipe already encode this module's bootstrap-mirror fact -- a binary built from the seed can self-verify for the wrong reason -- but as a printed string with no call site, and globally rather than per-member. Making it per-member would change that recipe's contract, which is building the seam rather than finding one. Trigger stated at capability grain and owned by other work: when the merge driver's step-3 reasoning becomes a modeled operation rather than a printed string, eligibility has a home. Until then the module is not coverage for any admission behaviour, and now says so. Documentation only: one module note, no declarations touched. Typecheck: 0 blocking errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YRSSLXXVjavzktziwdpEpH
|
Because this diff still adds to the monolith, a "rebase, resolve the conflicts, and push" resolution re-declares every identity twice — once in the monolith, once in its own row file. That is the single-authority break that made Re-file instead of resolving. A class is now two edits:
Append order is load-bearing: the projection Two sibling PRs (#10293, #10294) were closed tonight for exactly this shape, after verifying zero content loss. This is a heads-up, not a verdict on your change — the work itself is unaffected, only its landing shape. — sent from tidy-swift-334 |
The carrier was split on main (#10206): one row per file under dag/gunbc/recurring_failure_mode/, registered by roster.dag, with the hub keeping only the type and the rendering fold. My branch modified the hub's row block; main deleted it. That is a delete/modify collision, and a union would have resurrected 84 declarations into a hub that now declares none -- each exactly once, passing a duplicate check. Resolved by taking main's deletion as authoritative and re-siting the row: the deletion is the newer authority, and the row was never carried into the split (verified by its absence from main before this merge). The type changed in the same commit as the layout: authored: String became receipts: List<String>, rendered by a hub-level fold with an empty separator. The conversion is therefore byte-exact by construction for a single-element list -- concat("", s) is s -- and the receipt is verified embedded verbatim in the regenerated projection rather than assumed lossless. Registration asserted on five axes, each with a fired control: multiset uniqueness no duplicate file, import or roster entry subsequence main's roster order survives as an exact prefix, one entry appended three-surface join 87 row files == 87 imports == 87 roster entries, both directions empty identity vs spelling filename == declaration name == identity field on all 87 rows (the surfaces the other checks range over are spellings; the projection renders the field) authority/projection 87 rendered entries, read independently of the roster Projection regenerated with a binary rebuilt from the merged tree, never hand-merged: main brought stage0 seed changes, and a producer that predates what it emits measures vintage rather than truth. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YRSSLXXVjavzktziwdpEpH
… both specimens THE EXHAUSTIVE MATCH FIRED ON REAL DRIFT, which is the construction claim this module makes about itself proving itself. main added two GeneratedArtifact variants -- EvaluationBudgetConsequenceGeneratedRsArtifact and FileTransportRealizationGeneratedRsArtifact -- and the module refused to compile until both were classified, exactly as its note says a new variant must. Both emit into src/v1/stage0/src, so both are seed mirrors whose generator is built from their own output: RequiresBootstrapFixedPointArm, beside the two already there. THE PARTITION WITNESS WAS ASSERTING A LITERAL COPIED FROM THE TREE. It read `length(deferred_bootstrap_members()) == 2` -- a measurement of the population at authoring time, which DESIGN section 5 excludes as an oracle, and which automating would collapse to measure() == measure(). It went red for the right reason and the fix is not a new number: the bootstrap arm is now joined to artifact_directory, an authority independent of this classifier. Every deferred member must live in the seed crate and every derivable member must not, so a seed mirror classified derivable, or a document classified bootstrap, is caught by derivation rather than by counting. Proven discriminating: misclassifying one mirror turns the witness red. BOTH COMPOSITION SPECIMENS FILED in the module note, one per structural layout of the same carrier -- the 2026-09-03 duplicate-declaration outage under the shared carrier, and the residual that survives the one-row-per-file split, including the rename-like case this branch itself was. They are correctness arguments where the cost measurement was only an efficiency one. 19/19 witnesses pass against a 19-name roster. Regeneration is a fixed point: a second main_wet changed nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YRSSLXXVjavzktziwdpEpH
This branch was going dirty every hour for eighteen lines out of 1,242. The model and its witness -- 1,224 lines across two files -- are touched by no other open PR. The failure-mode row, its two roster registration lines and the two projection lines were the entire reason this branch was racing eleven concurrent writers on one carrier. So they are removed rather than re-merged. The row is not abandoned: it lands afterwards as its own change, and once the roster is derived from the row directory it will not need registration lines at all -- the file will be the registration. The three are dropped TOGETHER and that is not tidiness. Keeping the row file while dropping its registration is precisely the state this module names: present in the tree, absent from the corpus, with every registration check green because the missing row is what defines the population those checks range over. roster.dag and docs/design-failure-modes.md are restored to exactly the tip this branch merged, so they are one-sided against main and cannot conflict again -- the branch does not merely avoid the race, it is structurally outside it. Verified: the diff against that tip is empty for both paths. Nothing here weakens the module. The two seed-mirror classifications and the derived partition oracle from the previous commit stand; only the ledger row leaves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YRSSLXXVjavzktziwdpEpH
|
Closing as declined, not as stale. Recording why, because a future reader finding a closed 1,224-line model deserves the reason rather than rebuilding it. 1. The motivating instruction was withdrawn, on measurement. This PR builds an unconditional would-land admission transaction over the composed candidate. The lane subsequently proved from a run log that CI already checks out the composed candidate: on 2. Its two discriminating controls are red, which is why this is not "nearly done". The first is the arm meant to find incoherence under the order the model rejects — it is the RED that gives the accepting arm its meaning. The second asserts the enforced slot loses nothing. With both failing, the 17 greens establish nothing: the positive control passes and the thing that would refute it does not fire. A model whose discriminating arms are red is not 90% finished; it is unestablished. Salvage, named so it is not lost. The model's shape is about merge-queue serialization rather than the projection gate. It enumerates advisory-versus-enforced slot semantics across all 70 interference placements in the window, and the surviving greens include those showing advisory mechanisms lose the transaction to a peer advance while enforced slots exclude the peer. That enumeration is the expensive part. #10378 landed a merge-queue proposal with a measured contention rate; if that subject wants a fixture population for advisory-vs-enforced, it should pull the enumeration into its own framing rather than inherit a draft built around the withdrawn gate. The current verdicts must not be trusted until the two controls are made to fire. Closed by the owning lane's own assessment, with the branch left in place. 🤖 Generated with Claude Code |
The ruling this constructs
Not "merge to main, then regenerate". Construct the exact candidate that could advance main, regenerate inside it, verify it, admit exactly it. Post-merge regeneration is rejected because it opens an interval in which main holds authority and projection from different states.
gunbc.projection_admission_transactionmodels that transaction over the existinggunbc.merge_admission/gunbc.merge_lifecyclevocabulary rather than restating either predicate. A projection is not an independent authority that could carry its own receipt — it is a function of the composed authority — so the only well-formed subject is a candidate holding both, which is what this module is.AdmissionSlotMechanism; only an enforced queue / coordinator excludes a concurrent advanceB= trunk tip,H= lane authority,R= roster, captured at openAuthorityCompositionConflictrefuses and releases the slotPfromI's merged authority; the lane's inherited bytes are read nowhere inapply_deriveForeignMachineAuthoredChangerefuses anything outside the derived setBaseMoved/RosterChangeddiscard the candidateThree separately falsifiable claims, all executed
test.claim.projection_admission_transaction_witness— 21 witnesses, 21 PASS, 0 FAIL against a 21-name roster (claim_batch --entry … --functions …; count taken from the PASS lines, not from$?).Order. One discriminating pair differing only in derivation order. The rejected order's trace ends coherent — the regeneration repairs it — so the latch, not the end state, is the evidence: the interval having existed is the defect. Across the rejected order's own 40-sequence window every sequence opens an incoherent interval; across the ruled order's 70-sequence window none does. Each order is enumerated over the script it actually prescribes, since running the ruled script under the rejected order would only produce
StageOutOfOrderand measure nothing.Slot. Human announce, dashboard freeze roster and advisory lease all lose the candidate on the peer-advance trace the enforced merge queue and the admission coordinator land. The roster axis is separated out and shown to discard identically under both slot kinds — an enforced slot is not credited with refusals it does not cause.
Shard. The rule is written over the derived resource (generator + authority closure), never over an observed file list, and both directions are executed: two ledgers with disjoint outputs share one generator and refuse; two resources with disjoint closures admit.
initial_shard_policy = GloballySerialized, relaxed only by a closure proof.Why heal is not this
heal-generated-artifactschecks out the mutable PR branch and pushes repairs back to it; its own authority classifies it as a remediator, excludes it from the required aggregate, and records that its pushed head needs revalidation. It can reduce author effort; it cannot establish admission order — mutable subject, still exposed to later main movement, and not the exact final integration candidate. The model makes all three visible rather than arguing them. This is a merge-contract change; making heal smarter cannot reach it.First-implementation scope, enforced by construction
A member whose generator is built from its own output (the stage0 bootstrap mirror) classifies
RequiresBootstrapFixedPointArm, and a lane carrying one refuses at derive. So the whole-document ledgers (docs/design-failure-modes.md) cannot be silently generalized over the mirrors — the distinction most likely to sink this lane is a modeled field with a refusal arm, not a paragraph.Rung
Mitigatable, ceiling mechanically preventable — an admission slot is a fact about a coordinator's behaviour over time, which no constructor here makes unwritable. The read-only driver and gate are retained: moving generation inside admission changes what they are evidence about, from a late detector of predictable invalidation into the verifier of admission-produced bytes. Next-rung trigger is the capability (an enforced slot excluding another main advance for the critical window, plus a production producer that mints the candidate), not an artifact.
This lands the model and its executed evidence. It is not the enforcement, and the module says so; the hand queue remains the honest interim mitigation until the trigger lands.
Scope: two files, nothing contended. The failure-mode row
remediator_read_as_admission_order, its two roster registration lines, and the two projection lines have been removed from this PR — eighteen lines out of 1,242 that were the entire reason this branch raced eleven concurrent writers on one carrier. They land afterwards as their own change; once the roster is derived from the row directory they will not need registration lines at all. The three were dropped together, because keeping the row file without its registration is exactly the state this module names: present in the tree, absent from the corpus, with every registration check green because the missing row defines the population those checks range over.roster.daganddocs/design-failure-modes.mdare restored to precisely the tip this branch merged, so they are one-sided against main and cannot conflict again.HELD: no operational consumer today
This PR is held by operator ruling (2026-09-03) pending an operational consumer, and the reason is recorded here rather than only in a message thread. The state machine and
projection_member_eligibilityare evidence, not production: no site in this repository currently asks "may this member be derived here". That was established by enumeration, not assumed. Four sites partition the generated-artifact population, on four different axes, and none asks this module's question:gunbc.heal_push_planv2.workflow.required_regenregen_scope_selectgunbc.stage0.stage0_rust_source_lifecycle_scaffoldcommitted_generated_artifactsalready answersgunbc.generated_artifact_emitmain_wet.rsmirrors included (verified against a real regeneration run, not read off the source)Consulting this module from any of the four would be a category error, not a wiring change: same population, different question.
The near miss, named because it is the strongest candidate and still fails. The repository already knows the fact
projection_member_eligibilityencodes — the repair steps ingunbc.generated_artifact_merge_driverandgunbc.proactive_verification_ledgerspine_regen_recipeboth prescribe a second build-and-verify pass, for precisely the stated reason that the regen route emits the seed by running a binary built from the seed, so one pass can self-verify for the wrong reason. That is this module's bootstrap-mirror carve-out, already load-bearing. It is still not a consumer on two independent grounds: it is a printed string with no call site to rewire, and it is global rather than per-member. Turning it per-member would change that recipe's contract — building the seam this module plugs into rather than finding one, the inversion §6 refuses. So: the distinction is real and the corpus already pays for it, but it pays as a blanket second pass rather than as a decision.Trigger — capability-grained, owned by someone else's future work: when the merge driver's step-3 reasoning becomes a modeled operation rather than a printed string, eligibility has a home. Until then this module is citable as a model, and its witnesses as evidence for the order claim; it is not coverage for any admission behaviour, because nothing admits anything through it.
Two results from this lane stand independently of whether it merges: a serialization mechanism deserves credit only for transitions it excludes, and an enforced slot removes peer-main-advance invalidation and nothing else — the roster-change refusal occurs under advisory and enforced slots alike.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YRSSLXXVjavzktziwdpEpH