Repository navigation
PrimitiveCostFact carries the structured cost, and the duplicate carrier goes - #11125
Merged
Merged
Conversation
…ier goes `PrimitiveCostFact.cost` moves from the coarse `CostShape` to the structured `CostBound` that `std.realization_cost_fidelity` compares, closing the fork that module's own frontier note named. Follow-up to review 63996 finding 2 on gunbc#11026. TWO CORRECTIONS THE MIGRATION FOUND BEFORE CHANGING ANYTHING. There are FIVE rows, not the six that note claimed -- the sixth was the `type` declaration, counted by a grep -- and the count is fixed in the note this change retires. And no row's parameter is recoverable from its signature: three are `SignatureUngrounded` and each says authoring one would fabricate it, while the two grounded rows use a profile that supplies type params and a `FiniteSupport` classification but NO cardinality variable. So the axis is DERIVED from the carrier's declared support, not read off a signature. ONE PRODUCER FOR THE AXIS. `finite_support_cardinality_param` is the only place that string is produced and `linear_support_scan_cost` the only constructor the rows go through, so two rows about one carrier cannot spell one axis differently -- which nothing in the type system would otherwise prevent, `AtomicCost.param` being a bare `String`. The coarse shape SURVIVES on the refusal arm: dropping it would delete `ShapeSortBody` and `ShapeIterateBody`, facts that were never in question, when only the structured form is unavailable. THE DUPLICATE CARRIER IS DELETED AND THE CUT IS AT THE ROOT. `ModeledCostBoundFact` held the same (primitive, cost) pair with no production rows at all -- fixtures only -- so it is removed and `realization_cost_fidelity_rows` re-signatured onto `PrimitiveCostFact`. That collapses its two input lists into one, and the consequence is a ladder climb rather than a tidy-up: a primitive in BOTH lists used to be a contradiction only a check could catch, and with one list of coproduct- bearing rows it cannot be written at all. Section 4b's mechanically preventable to structurally impossible, and section 5's construction over validation. NO COVERAGE WAS LOST TO THAT DELETION, which is the part worth checking rather than asserting. The old both-lists specimen becomes an ordinary duplicate -- one primitive on two rows, once structured and once coarse -- still refused by the surviving arm and still exercised. The refusal type drops to the one arm that stays writable and is RENAMED: `StructuredPrimitiveDuplicated` said "structured" when there were two lists, and the single list holds both kinds, so the old spelling would have left one name over two populations. EVIDENCE. 101 witnesses pass across five suites: the new `primitive_modeled_cost_witness` 14, `realization_cost_fidelity_witness` 39, `primitive_identity_join_witness` 16, `primitive_signature_grounding_witness` 11, `primitive_projection_authority_witness` 21. All nine modules that import `std.primitive_identity` compile with 0 blocking errors. Four planted defects, each with its failures predicted BEFORE the run: an invented axis for an open-support carrier failed exactly the 2 refusal arms; a quadratic bound failed 4 (two more than predicted, which exposed that the axis-identity witness was comparing coarse SHAPES -- it now compares parameter names via `cost_bound_params`); a per-row literal axis failed exactly that 1; and disabling the duplicate check failed exactly the 3 partition specimens. FRONTIERS, BOTH DECLARED ON THE CARRIER. Section 3c consumption: the join is the consumer and takes this carrier DIRECTLY, with the realized side and a production caller still missing; trigger is the first `RealizationCostFact` constructed outside `dag/test/`, with a kill condition if that lands and these rows stay unread. Section 2 next rung: `AtomicCost.param` is an anemic `String` and the single-producer discipline is a CONTAINMENT, not a fix; trigger is a parameter identity in `std.induction`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
The frontier note still said the cut was "named here and sequenced separately rather than performed inside a change that cannot establish its inputs". This PR performs it, so that sentence described a plan that no longer exists -- the stale-present-tense class, in the authority a reader consults first, which is the thing this note is most likely to be read for. Replaced with what performing it ESTABLISHED, which is more than the deferral assumed: there are FIVE populated rows, not the six this note claimed (the sixth was the `type` declaration, counted by a grep), and NO row's parameter is recoverable from its signature -- three are `SignatureUngrounded` and say so themselves, and the two grounded rows use a profile carrying type params and `FiniteSupport` but no cardinality variable, so their axis is DERIVED from the carrier rather than read off a signature. The load-bearing half survives in substance because it is still true and is why the migration could not be a substitution: an invented parameter produces a spurious axis and a fabricated verdict, which is this authority's own subject authored into its inputs. Found by re-reading the change against the REQUEST rather than the review tally. The tally was already met -- one distinct approval, no request-changes, CI green, GitHub clean -- and the request had named retiring this note as part of the work. Evidence: gunbc compile of std.realization_cost_fidelity, 0 blocking errors; claim_batch over realization_cost_fidelity_witness, rc=0, 39 PASS. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
gunbai-bot Bot
pushed a commit
that referenced
this pull request
Sep 12, 2026
…h authorities survive The only conflict was src/v2/compiler/00_compile.dag, and it was two sides adding imports to the same block rather than a rename or a contested declaration. Resolved as a per-module union: std.algebra keeps this branch's `trim` beside main's Cons/Empty/FreeMonoid; v2.std.algebra keeps contains/is_empty/length and the promoted list_find_first beside main's folds; v2.std.collection takes main's Map/empty_map/map_insert/map_lookup beside List; and main's new std.decl_ref, std.content_hash, std.types, v2.std.integer and v2.std.logic imports all land. One import line per module, no duplicate module imports. Verified rather than assumed, since a clean auto-merge is weak evidence when both sides touch the same closure: this branch's native_lane_universe, native_lane_closure_modules, native_lane_module_for_path and list_find_first are all present; main's #11004 lens-registration join is present (85 references to CompileLens / declaration_ref_display_key / content_hash_of_value); the file is brace-balanced; the seventh row is intact in dag/std/compiler_entry.dag and the emitter; and the driver template is still the adjudicate one (2 x 'adjudicate <host-facts', 0 x universe.tsv). ONE DELIBERATE DIVERGENCE FROM THE STANDING MIRROR RULE, flagged rather than silent. The rule has been to take main's side on the stage0 mirrors, which was right while main carried the newer ones. Here the opposite holds: 86761d1's regen put THIS branch's route contract into them, and main has no such commit. So the merge keeps the regenerated mirrors -- universe.tsv 0, adjudicate 1, INGEST-CLOSURE 1, row_serialization 1. They are now stale against #11004's additions and will drift for the next regen either way; keeping them means anything that runs before that regen still gets the right driver rather than the pre-route one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013aZDLk2CxsCDznqn49Xhe8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PrimitiveCostFact.costmoves from the coarseCostShapeto the structuredCostBoundthatstd.realization_cost_fidelityactually compares, closing the two-carrier fork that module's own frontier note named and scheduled. Follow-up to review 63996 finding 2 on #11026.What the migration found before it changed anything
The note that scheduled this work said "the six populated rows record a shape and NO PARAMETER". Two corrections, both load-bearing:
type PrimitiveCostFact {declaration, counted by a grep. The count is corrected in that note by this PR, which also retires it.sorted_map_keys,fold_list,index_by) areSignatureUngrounded, and each states in its own reason that authoring a signature would fabricate it. The other two ground onFinitelySupportedFunctionProfile, which supplies type paramsK,Vand aFiniteSupportclassification but no cardinality variable. So the axis for the two grounded rows is derived from the carrier's declared support, not read off a signature.The shape of the change
PrimitiveModeledCosthas two arms:StructuredCost { bound }for a row whose axis is derivable, andCoarseCostOnly { shape, cause }for one whose is not.The coarse shape survives on the refusal arm. Dropping it would have deleted
ShapeSortBodyandShapeIterateBody— facts that were true and never in question. Only the structured form is unavailable for those rows, so the two-grain state survives exactly where it is declared with a typed cause, instead of silently across the population.The axis has exactly one producer.
finite_support_cardinality_paramreads the carrier's own support axis;linear_support_scan_costis the single constructor every structured row goes through. No row authors a parameter literal, so two rows about one carrier cannot spell the same axis differently — which nothing in the type system would otherwise prevent, sinceAtomicCost.paramis a bareString.Evidence
claim_batchover the new suite: 14 witnesses, 14 PASS, rc=0. The existing suites that touch this module are unaffected and re-run green:realization_cost_fidelity_witness39,primitive_identity_join_witness16,primitive_signature_grounding_witness11. All eight modules importingstd.primitive_identitycompile with 0 blocking errors.Green witnesses prove nothing on their own, so each discriminating arm was planted against, with the failures predicted in advance:
map_valuesauthors its own literal axisThe second plant failed two arms I had not predicted, and that exposed a defect in my own witness:
both_grounded_rows_scale_in_the_same_derived_axiswas comparing coarse shapes, so two rows with different parameter names would both have passed it. It now compares the actual parameter names viacost_bound_params, and the third plant confirms it fails on exactly that divergence.The duplicate carrier goes with it, and the cut is at the root
ModeledCostBoundFactcarried the same(PrimitiveIdentity, CostBound)pair as this carrier and had no production rows at all — its only constructions in the tree were fixtures. Leaving two carriers of one fact standing is the §3 fork that gets consolidated later at interest, so it is deleted here rather than after, and §3's replacement-migration rule says the cut goes at the root: the join's signature.realization_cost_fidelity_rowsnow takesList<PrimitiveCostFact>directly. That collapses its two input lists into one, and the consequence is worth stating precisely because it is a ladder climb rather than a tidy-up:modeledandunstructuredseparately, so a primitive appearing in both was a contradiction about one key that only a check could catch —PrimitiveIsBothStructuredAndUnstructured.No coverage was lost to that deletion. The old both-lists specimen becomes an ordinary duplicate — the same primitive on two rows, once structured and once coarse — which the surviving arm still refuses, and the witness still exercises it. The refusal type drops from three arms to the one that remains writable, and it is renamed:
StructuredPrimitiveDuplicatedsaid "structured" when there were two lists, and the single list holds both kinds, so keeping that spelling would have left one name covering two populations — the same §3 meaning fork this PR closes one layer up.Declared frontiers
§3c consumption. The five rows had no roster and no consumers — dangling, while their sibling
PrimitiveTraversalOrderFacthas both. This PR addsprimitive_d0_cost_facts, and the row says plainly that the roster is the identity join's subject universe, not the consumer.std.realization_cost_fidelityrealization_cost_fidelity_row, reached throughrealization_cost_fidelity_report.ModeledCostBoundFact, whose only constructions in the tree are fixtures intest.claim.realization_cost_fidelity_witness— a shape with no production supplier, which is what these rows are shaped for.RealizationCostFactoutsidedag/test/— stated as that symbol rather than "when measurements exist", because the capability it stands for (the emitted compiler being measurable per primitive, so a realized cost is an observation rather than an assertion) is exactly what the first non-fixture producer demonstrates.§2 next rung.
AtomicCost.paramis a bareString— an anemic leaf carrying a modeled quantity as free text. The single-producer discipline above is a containment, not a fix: it makes this module's rows agree with each other and can do nothing about another module naming the same axis differently. Trigger:std.inductionAtomicCostcarrying a parameter identity rather thanString, which dissolves the discipline into the type. Not attempted here — it rewrites every cost-bearing row in the tree.What is still open
The realized side. No
RealizationCostFactexists outsidedag/test/, so no production caller passes the roster to the join yet — that is the §3c frontier above, and no amount of work on this carrier can supply it. The modeled side is now one carrier, read directly by the join, and executes in the witness suite.🤖 Generated with Claude Code
https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f