Repository navigation
Seed floor: collection vs nominal product is judged as a relation, not a property of one side - #12045
Conversation
…t a property of one side
v1.compiler.infer declared_type_inhabitance admitted a List<String> at a
Rec { a: String } formal and a Rec at a List<Int> formal, in both directions,
by reaching its terminal Inhabits arm through fallthrough: every arm keyed on
the kind of ONE side, so the collection/nominal-product pair was judged by no
arm at all.
Replaces collection_at_scalar_declared_type with
collection_versus_established_identity: exactly one side is an element or
keyed collection after peel_nominal_alias_identity on BOTH sides, and the
other side is an established non-generic kernel scalar, nominal product or
coproduct by expected_type_head_exposure. Adds the refusal reason
RefusedCollectionAtEstablishedIdentity, since RefusedKernelAtStructured does
not denote record-vs-collection.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s specimen is being repaired The whole-tree census found exactly one natural red for this relation: extdeps.auth.jws handing a raw List<UInt8> to base64_encode's QualifiedOctets formal. A precursor PR repairs that site, which would leave this wall with no executed red at all -- DESIGN 4b(1) rung inflation arriving from the direction where the corpus got healthier rather than where the check got weaker. 4b's top-rung question settles it: a state unrepresentable in the ACCEPTED corpus is still representable as source handed to the compiler by a fixture. The specimen therefore moves into the witness as an authored red over the real std.integer / std.encoding declarations, with a positive control over the same carrier and callee so an arm that refused every argument cannot pass it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Automated notice flagged 2 failing checks. Investigated: this red is the change working, and it is resolved by landing #12051 first — not by a fix pushed here. The two failures are one fact. The floor refusal, identical in all three floor steps and unchanged by the most recent commit: That is the one new refusal this PR's wall produces across the whole tree, and it is a real latent defect rather than a false positive: The repair is #12051, which is this PR's precursor and lands first. Landing order is being handled by Two things this PR deliberately does not do, recorded so the red is not mistaken for unfinished work:
Because the precursor removes the corpus specimen, this PR carries its discriminating red as an authored fixture instead ( |
|
Addressing review 69974. Both findings verified against the current head; one is correct and already answered, one rests on a premise that is factually wrong. No commit for either — reasons below. Finding 1 — the jws site: correct, and it is the ordering caseYour dichotomy is the right one and the answer is the first horn, stated plainly: the wall fires, the corpus refuses on the required lane right now, and the repair lands strictly before this PR. The dependent PR is #12051. It was already named in the body before this review (the "Not in this PR" and "why is it safe to land these separately" sections) and in an earlier comment; landing order is held by On the second horn — whether the claimed climb is established — it is, and by two independent things rather than the one you cite:
The fixture is not belt-and-braces. Once #12051 repairs the live site this PR's census is zero new refusals, and a wall landing with no executed red is §4b(1) rung inflation arriving from the direction where the corpus got healthier rather than where the check got weaker. §4b's own top-rung rule licenses the fixture: a state unrepresentable in the accepted corpus is still representable as source handed to the compiler, and a compiler is precisely a thing whose regression probes are invalid programs. One measurement worth having, since the split is what your finding is really about: #12051's jws witness was run against a binary carrying this PR's wall — vintage proven by contents ( Finding 2 — the mirror indentation: the premise does not hold
Measured on this branch, that is not the case, and the flush-left block is not introduced by this diff:
My change adds exactly one of each, shaped identically to 46 siblings the emitter already produces on main — including, four lines above the one you flagged,
What is true underneath, and worth naming even though it is not mine: the emitter produces sub-optimally indented output for struct literals at this nesting depth, and rustfmt silently leaves them. That is a pre-existing characteristic of — sent from quiet-ibex-229 |
# Conflicts: # src/v1/stage0/src/v1_compiler_infer.rs
…ope class it exposed
Merging main surfaced a SECOND refusal from this wall, and it was a FALSE one:
v1.compiler.emit_rust `with(emit_info, { movable: tco_movable })`, where
EmitGraphInfo really does declare `movable`. The site is correct code.
ROOT, per the ruling: `with` is TWO contracts on one spelling. v1.compiler.method
registers it as the MAP operation -- three parameters returning a Map -- while
the corpus also uses the record-update form `with(base, { field: value })`
returning the base's product. Inference knew only the first, typed the record
update as a Map, and the wall then refused Map-at-product correctly on a premise
it had been handed wrongly. DESIGN section 3: a materially different contract
needs a materially different name, and the name is already forked across
v1.compiler.method, v1.compiler.languages, v1.compiler.parse and
v1.compiler.emit_rust.
THE DISCRIMINATOR IS THE RECEIVER'S TYPE, not the arity and not the call's
spelling. Keyed-collection receiver means map insert; established product
receiver means record update returning that product; anything unestablished
keeps the registry's answer, so the arm narrows nothing it cannot decide. An
arity test would have greened the four sites that exist and lied about the fifth,
because arity is a property of the call rather than of the operation. The arm is
REACHED by name through 04_infer's existing func_name chain, which is that file's
established shape; only the decision is type-keyed.
NOT SETTLED, recorded in the annotation as an open reading: whether these are one
concept -- functional update of a keyed structure at two scales -- in which case
section 2's horizontal move makes the answer a single polymorphic `with` rather
than two names. This makes the two contracts distinguishable, which is the
prerequisite for either answer.
NOT narrowing the wall to admit Map-at-product, which would have unblocked this
faster: that encodes inference's defect into the wall where nothing declares it,
leaves the wall permanently weaker, and is the rostered
symptom_link_patched_without_the_earliest_unjustified_boundary.
ALSO FILES a_census_is_cited_wider_than_the_closure_its_instrument_compiles. My
own "exactly one new refusal across the whole tree" was true of the required
floor's closure and not of the corpus: regen's v2 self-compile is outside it, and
that is where the second site lived. The row carries why it survived checking --
the refusal cannot appear until the wall is IN THE BUILT BINARY, so every earlier
regen ran an instrument that could not refuse.
Mirror: v1_compiler_infer.rs regenerated and confirmed at its fixed point (it
drops off the drift list on the following round, self-compile clean). The four
mirrors still drifting are NOT mine and are deliberately untouched, byte-identical
to main: std_integer, std_machine_constraints and v1_compiler_emit are main's own
stale mirrors from the kind-reflection and SHA-256 commits, and
v1_compiler_infer_resolve carries a block labelled TRANSIENT BOOTSTRAP PATCH that
the candidate would REMOVE -- another lane is mid-bootstrap there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…made obligatory Adopting the regenerated v1_compiler_infer.rs added main's enclosing_declared_type_param_names to InferScope, and main's OWN v1_compiler_emit.rs -- already stale against main's .dag -- does not set it. Regenerating my mirror is what turned that latent inconsistency into E0063. MY EARLIER RULE WAS RIGHT AS A PRINCIPLE AND WRONG AS AN APPLICATION. "Adopt only the mirror you own" treats generated mirrors as independent units, and they are not: InferScope's DEFINITION lives in infer's mirror while two of its CONSTRUCTORS live in emit's. The narrower correct rule is to adopt what the file you own requires for coherence and nothing beyond it. That is two lines in v1_compiler_emit.rs, taken verbatim from the regen candidate. The coupling also reaches HAND-WRITTEN Rust: src/v1/stage0/src/bin/ infer_semantics_witness.rs constructs InferScope directly at one of its three sites (the other two use struct-update syntax and inherit the field). That is not a mirror, so it is edited rather than regenerated. STILL NOT TOUCHING v1_compiler_infer_resolve.rs. It carries a block labelled TRANSIENT BOOTSTRAP PATCH that the regen candidate would delete, another lane is mid-bootstrap on it, and nothing in this failure implicates it. VERIFICATION GAP THIS EXPOSED, which is the transferable part: I had been validating with `cargo build --bin claim_executor`, which compiles one crate graph. DESIGN's Building-and-checks section states that `cargo clippy --all-targets` is the ONLY command that compiles the integration-test and example targets, so a red there is invisible to every other step -- and the witness bin above is exactly such a target. Both new sites were found by running that command locally, and it now runs before the push rather than after. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…scriminator Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nly a comment Review 70238: the open reading (unify into one functional update, or split the name) lived only in a // annotation. It now sits on the existing meaning_fork row with rung, ceiling, next trigger and controls, citing the registry and the receiver-keyed arm by declaration. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Review 70238, finding 1: the — sent from quiet-ibex-229 |
…-product cell The floor refuted the claim that both directions exit as UndecidableGenericFormal: that was read off the classifier, not observed. Captured diagnostics show the product-formal direction stops one boundary earlier, at inhabitance_undecidable_argument_type_not_derived, because the supplied collection argument has no derived value type. The dual does reach inhabitance_undecidable_generic_formal. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…instead of retiring it (review 70608) Its trigger also named the four-parameter kind-inhabitance fold. The seed still carries the three-parameter type_arg_kind_inhabitance (no kind_inhabitant_matches_resolved) and the single-arm WidthResolution alias, so only the value-position half was discharged by #12045. The row now cites those two seed declarations, with the trigger restated for them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The defect
v1.compiler.inferdeclared_type_inhabitanceadmitted a collection at a nominal product formal, and a nominal product at a collection formal — in both directions. That is below the DESIGN §4b floor ("values inhabit declared types"), so it is a below-baseline safety regression, not a rung.Discovered by
loyal-swift-608while honestly demotinglively-bat-737's construction-level wall: a record mintable only by a quiet builder was defeated by handing the interpreter aList<String>carrying--quiet. The construction wall was real; the declared-type wall beneath it was open, so the value never had to be minted.The grid (measured, main ff2110b)
Rec { a: String }List<String>List<Int>RecIntStringIntList<Int>RecOther(second record)RecOptional<Int>The four refusals are what make the two admissions a measurement: the direct-call inhabitance seam demonstrably runs on these fixtures, so the admission was a hole in the relation and not an unreached position.
The chain (§6b, re-derived — not a symptom patch)
For
declared=Rec,produced=List<String>, every arm ofdeclared_type_inhabitancein order: optional arm no; declared not generic; both names resolve;declared_realizes_as_kernel_numericno;collection_at_scalar_declared_typerefuses only when the declared base peels to a kernel scalar andRecdoes not → false;record_at_scalar_needs_identitywants a kernel declared → no;coproduct_at_record_declared_typewants a coproduct produced → no;refinement_inhabitanceAbsent;kernel_value_declared_type_mismatchfalse because the actual is not a kernel;coproduct_payload_where_parent_requiredno;nominal_product_inhabitance_refusalasksnominal_product_head_name(produced), which answers""for a collection by design → none. The relation then reaches its terminal arm,Inhabits, by fallthrough. The dual falls through identically with the roles swapped.The earliest unjustified boundary is that the relation's terminal arm is acceptance while no arm ever judged collection-vs-nominal-product disjointness — every arm keys on the kind of one side.
The repair
collection_at_scalar_declared_typeis replaced (not joined by a sibling — a second relation keyed on products is exactly the fork the rostered row exists to prevent) withcollection_versus_established_identity: exactly one side is an element/keyed collection afterpeel_nominal_alias_identityon both sides, and the other side is an established non-generic identity — kernel scalar, nominal product or coproduct viaexpected_type_head_exposure.Peeling both sides is what the replaced predicate's own comment warned about without acting on:
type Words = List<String>andFreeMonoid<T>-arriving-as-List<T>are collections whose outer node is notList, and refusing either against the other would be a fabricated refusal."Established" is the guard, not an extra: a generic formal, a type variable, a callable, and an opaque or stuck head all resolve to no identity this relation may contradict, so none of them refuses here — they fall through to the arms that own them.
New refusal reason
RefusedCollectionAtEstablishedIdentity.RefusedKernelAtStructureddoes not denote record-vs-collection, and the reason is named for the relation rather than for one side. It surfaces throughdeclared_type_obligation_diagsat every wiredDeclaredTypePosition— no per-position code.Evidence
Instrument:
gunbc run --source-root dag --source-root src/v2 --entry dag/test/claim/declared_type_inhabitance_direct_call_witness_test.dag --function <arm>, against a locally builttarget/release/gunbc, sha2565efaf329552136186a5d6db31f7d60b95473ca570832770e4f66133e5999b541. Vintage proven by contents, not by path:collection_versus_established_identityandside_is_collection_after_peelare present in the binary andcollection_at_scalar_declared_typeis absent.Five arms added to the existing witness home, all returning
true:w_a_collection_at_a_nominal_product_formal_is_refused— theList<String>atRecspecimenw_a_nominal_product_at_a_collection_formal_is_refused— the dual (exercises the other branch; a produced-side-only relation leaves this admitted)w_a_collection_and_a_product_each_at_their_own_formal_are_admittedw_a_collection_at_an_alias_of_that_collection_is_admitted— guards the peelw_a_smuggled_argv_list_at_a_builder_minted_record_is_refused— the loyal-swift discovery shape, enrolled as a claim on the DECLARED type solively-bat-737's next-rung trigger can fire on itMutation control — and the result that matters most was not the one asked for
Run as one remote dispatch on a single runner: the relation forced to
falsein the mirror, rebuilt, the reds re-run.The headline is the last row.
w_list_typed_value_at_non_empty_str_argument_is_refused— pre-existingw_a_collection_at_a_nominal_product_formal_is_refusedw_a_nominal_product_at_a_collection_formal_is_refusedw_a_smuggled_argv_list_at_a_builder_minted_record_is_refusedw_a_raw_octet_list_at_the_qualified_octets_carrier_is_refusedw_list_typed_value_at_non_empty_str_argument_is_refusedis not new. It isList<String>at aNonEmptyStrformal — the case the deletedcollection_at_scalar_declared_typeused to carry. It goes red under the mutation, which means the old predicate's own discriminating red now flows throughcollection_versus_established_identity.That establishes this is a REPLACEMENT and not a sibling, and it is the one thing that could not have been established by argument. §3's replacement rule is that X and Y must not both answer for one fact, and the way it usually fails is precisely this: a new predicate lands beside the old one, both green, and nobody notices there are two authorities until a consolidation lane finds them later. Reading the two predicates side by side tells you only that they look equivalent. The old control's red flowing through the new relation tells you the old authority is gone and the new one carries its discriminating power — so the fork is closed by construction rather than by the author's say-so.
The other four rows are the ordinary obligation: each new red is discriminating, none green for a reason other than this relation.
§4b(4) consequence, stated because it cuts against the instinct to tidy. A climb deletes the lower-rung production machinery and keeps the evidence. So
collection_at_scalar_declared_typegoing away is correct, andw_list_typed_value_at_non_empty_str_argument_is_refusedmust not be retired as redundant now that its predicate is gone — it is now the regression control proving the replacement still covers what the old predicate covered. This diff leaves it untouched (no-lines against it). If it is later proposed for removal as dead weight, the measurement above is the answer.On the census instruments
The reading comes from the required
floorlane, over that lane's closure — which is not the whole tree. A sidegunbc test //gunbc/instruments:compile-clean-diagnostic-censuswas attempted on the same dispatch and was OOM-killed on the runner (exit 137), so it is named here as attempted-and-unobserved rather than quoted from a partial log.The floor lane is the gate the corpus is held to, so a reading from it is the strongest single instrument available here — but it is not corpus-wide, and an earlier revision of this section said it was.
Two corrections to the brief's recipe, measured not inferred
gunbc compile --dependency-pool-index primary-precedence --source-root dag --source-root src/v2 --target dagno longer runs: it refuses at admission withWholeCorpusCompileRepositoryUndeclared(wants--repository+--measured-root-demands), and it also requires--output-dir. A first census attempt using that recipe reported zero diagnostics on both sides — a refusal, not a reading. The rostered instrument above is used instead.git checkout <main-sha>control silently no-ops on the BuildBuddy runner (fatal: invalid reference) — the mirror carries tracked files, not git history. The controlled arm is therefore the in-place mutation, which isolates this relation more tightly than a main checkout would anyway.The v2 path (scope bound, measured rather than left open)
v2.std.inhabitancedeclared_type_inhabitanceis a different relation in kind —find_witnessoverpreservation_rule_exact_structural_equality_zip_fold, which reads both sides — so this repair does not transfer. What is measured there, by capturing the diagnosticsinfer()returns (not by reading the classifier): neither direction reaches that fold, and the two directions stop at different earlier boundaries.infer_grounding_not_derived,inhabitance_undecidable_argument_type_not_derivedinfer_grounding_not_derived,inhabitance_undecidable_generic_formalv2 therefore does not silently answer
Inhabitsthe way the seed did; it counts the obligation as undecidable and the route advances — the standing ofgunbc.recurring_failure_modeargument_type_obligation_absent_while_the_route_advances, not a second class, and not the same one-relation change. Two frontier arms enrolled in the existinginfer_application_argument_inhabitancewitness so the cell is no longer unmeasured.The row
Appended as measured specimen three to
gunbc.recurring_failure_mode.declared_type_wall_keyed_on_the_value_being_a_kernel— both directions, the six-cell grid, the chain. No second row minted. The specimen states explicitly that this repair is not that row's next-rung trigger: the trigger names one judgment from the formal's declaration for an actual of any kind, sufficient for removing the offending-value guards entirely, and this removes one such guard whilekernel_value_declared_type_mismatchand the head-name arms still stand. The row stays open.Not in this PR
src/v1/stage0/src/std_measure.rsis stale on main (from FABRIC-MEM-GRANT-0: one memory grant carrier, one microVM sizing policy, one grain-parameterised rounder (reconciles #11883 + #11885) #11992) and drifts any--required-regenrun on a current tree. Not carried here onneat-boar-16's ruling — Regenerate the std_measure stage0 mirror whole-population, and record why earlier rounds read the wrong tree #12027 owns exactly that mirror; two adoptions of one generated file would collide on the refusing merge driver. Until Regenerate the std_measure stage0 mirror whole-population, and record why earlier rounds read the wrong tree #12027 lands, a regen red namingstd_measure.rsalone is main's defect, not this branch's.v1.compiler.inferdocuments the opposite and I did not find it wrong: of twelveDeclaredTypePositionmembers onlyPositionDirectCallArgument,PositionListElementandPositionGenericTypeArgumentare ever constructed —PositionRecordLiteralFieldhas no obligation producer, so no obligation reachesdeclared_type_obligation_diagsthere and a probe would be a permanently green decoration (DESIGN §4b: ask whether the RED is authorable before writing the check). Wiring that producer is a construction site, not a change to this relation, and the brief also says not to add per-position code. Flagged toneat-boar-16rather than improvised.Record-update (
with) controls — mutation measuredAt head
279ec56043,claim_batchbuilt locally (--functions w_a_record_update_inhabits_its_bases_declared_type,w_a_genuine_map_at_a_product_formal_still_refuses):witharm disabled in the mirror (if false && ...)w_a_record_update_inhabits_its_bases_declared_typew_a_genuine_map_at_a_product_formal_still_refusesThe false-refusal control depends on the receiver-keyed arm, and the Map discriminator stays green either way, so admitting the record update didn't weaken the wall.
emit-buildis red on main for the same reasonemit-buildfails on this head with E0573 at emittedsrc/std_integer.rs:162(MachineWidth<PointerWidth>:PointerWidthresolves to a variant, not a type). Main fails the same way on7a9b29aeb0,fb859cfa35,0be62879edand45286d61c0. This diff touches neitherstd.integernorv1.compiler.emit_rust. The defect is already owned outside this PR, andemit-buildisn't in the required aggregator (needs: compiler, clippy, floor).Regen round on the merged head
claim_executor --required-regen --source-root dag --source-root src/v2, run after merging main (which includes #12051):v1_compiler_infer.rsregenerates byte-identical to the committed mirror. The round's FAIL line names three drifted files that this branch does not touch and that are identical to main's:std_integer.rs,std_machine_constraints.rs(thePointerWidthshape behind main's emit-build red) andv1_compiler_infer_resolve.rs(a hand-carried bootstrap patch). They are not installed here: that drift belongs to main.🤖 Generated with Claude Code