Skip to content

v2_compiler_parse.rs was never flat: 19 of 21 diagnostics are two roots, and three were plain .dag type defects - #8833

Merged
briansrls merged 2 commits into
mainfrom
session/neat-ferret-237
Aug 22, 2026
Merged

briansrls merged 2 commits into
mainfrom
session/neat-ferret-237

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

The file was dispatched as a FILE lane on a scale-free property — 28 diagnostics over seven rustc
codes, top-class share 21%, five classes within 1.5x of the top. Read at MECHANISM grain instead of
code grain it is not flat at all: 19 of the surviving 21 diagnostics are TWO corpus-wide roots, and
the seven-class spread is an artifact of one mechanism wearing three codes and another wearing two.

T3 (Set modeled as a function-record, realized as OrdSet)   11 diagnostics, 7 sites
    one construction yields E0560 (no field `member` on the PointwisePower it built),
    E0308 (PointwisePower where OrdSet was expected) and E0609 at every read — so a
    class lane keyed on any one code sees a third of it.

RT-builtin (bare-name interception of `contains`)            8 diagnostics, 4 sites
    02_parse.dag imports v2.std.algebra.contains explicitly and the emitter routes to
    the host builtin v1_rt::contains(String, String) anyway; the arity mismatch is
    E0061 and the `eq` closure left with nowhere to land is E0282 at the same call.
    An import is evidence of visibility; the emitter overrode it.

Neither is reachable from inside this file and neither is patched here. Both have owners — T3 is
royal-dove-436's cluster (blocked on an identity question; its renderers are not to be touched from
here), RT-builtin contains is the callee-resolution class. Dodging Set by hand or renaming
contains would be the unmarked workaround DESIGN §5 names as a line-stop signal, and would delete
the cleanest specimen either root has. Being that unpatched specimen is the deliverable those two
lanes should take from this file
— seven Set sites where one construction's three codes can be
read side by side, and four contains sites where an explicit import is demonstrably overridden.

What this PR changes

Three genuine type defects in src/v2/compiler/02_parse.dag, all inside parse_expr_terminal,
none of them emitter behaviour:

  1. stamp: StampClass declared a VARIANT as a parameter TYPE. StampClass is a variant of
    TerminalStampMode, the value is passed straight to parse_stamp_terminal(stamp: TerminalStampMode), and the sibling declaration already spells it correctly. (E0573)
  2. occurrence_id: node_occurrence_minted(id: minted.id) wrapped an OccurrenceId into a
    NodeOccurrenceId for a callee declaring OccurrenceId. The wrapper is spurious at this
    position. (E0308)
  3. ParseExprRejected { diagnostics: d } bound Outcome's NonEmptyDiagnostics to a
    List<Diagnostic> field, where the module already declares the converter and uses it
    elsewhere. (E0308)

Evidence — the delta is sound, the absolutes are NOT board figures

Two arms in ONE remote dispatch, so the ambient contamination is common-mode and cancels:

ARM=BASE  TOTAL 431  v2_compiler_parse.rs 24
ARM=HEAD  TOTAL 428  v2_compiler_parse.rs 21

Joined at SITE identity rather than by count: the removed set is exactly
{E0573@1664, E0308@1675, E0308@1684}. Nothing was added, in this file or any other, and every
other file's count is identical across the arms — so the -3 total is the -3 here, not a class moved
upstream.

OBSERVED ON:  03_ingest closure at ba63edc09b PLUS 61 uncommitted files,
              including src/v1/05_emit_rust.dag (another lane's emitter WIP)
CLAIM ABOUT:  v2_compiler_parse.rs, this file's own root partition

431 and 428 must not be differenced against the fleet board. That board on the same ref is 399,
reproduced independently twice site-for-site; the 32-diagnostic gap is the ambient dirty emitter
this lane's runner mirrored. 431/428 are internally consistent with each other and with nothing
else. The -3 is unaffected — one dispatch, one tree, site-identity join.

The instrument gap that produced it is general and is being propagated: a single-arm remote probe
cannot be trusted to be measuring your tree unless it echoes its own HEAD and its
git status --porcelain count. MARKER_REF alone proves the commit and says nothing about what is
dirty on top of it.

Also

The brief's board was one class stale: its E0597:4 column is zero live, closed by #8799 after the
6c3fbeb960 measurement. No delta is claimed on the other columns.

Written up as §22 of docs/plans/self-host-cargo-refusal-root-partition.md, ending on the thing
that generalizes: the surviving board's top-class share RISES from 21% to 24%, so fixing the
singletons makes the file flatter by the code-grain metric while making it more concentrated by the
mechanism-grain one. A code-grain histogram is not a root census, and a lane picked off one should
re-partition before it plans.

🤖 Generated with Claude Code

Brian Searls and others added 2 commits August 21, 2026 23:59
…ts, and three were plain .dag type defects

The file was dispatched as a FILE lane on a scale-free property — 28 diagnostics
over seven rustc codes, top-class share 21%, five classes within 1.5x of the top.
Read at mechanism grain instead of code grain it is not flat at all: 90% of the
surviving diagnostics are TWO corpus-wide roots, and the seven-class spread is an
artifact of one mechanism wearing three codes and another wearing two.

  T3 (Set modeled as a function-record, realized as OrdSet)  11 diagnostics, 7 sites
      one construction yields E0560 (no field `member` on the PointwisePower it
      built), E0308 (PointwisePower where OrdSet was expected) and E0609 at every
      read — so a class lane keyed on any one code sees a third of it.

  RT-builtin (bare-name interception of `contains`)           8 diagnostics, 4 sites
      02_parse.dag imports v2.std.algebra.contains explicitly and the emitter
      routes to the host builtin v1_rt::contains(String, String) anyway; the arity
      mismatch is E0061 and the `eq` closure left with nowhere to land is E0282 at
      the same call. An import is evidence of visibility; the emitter overrode it.

Neither is fixable from inside this file, and neither is patched here — dodging
`Set` by hand or renaming `contains` would be the unmarked workaround DESIGN §5
names as a line-stop signal, and would delete the cleanest specimens either root
has.

What IS fixed is three genuine type defects in src/v2/compiler/02_parse.dag, all
inside parse_expr_terminal, none of them emitter behaviour: a VARIANT (StampClass)
declared as a parameter TYPE where its coproduct TerminalStampMode belongs and
where the sibling declaration already spells it correctly; a spurious
node_occurrence_minted wrap handing a NodeOccurrenceId to a callee declaring
OccurrenceId; and Outcome's NonEmptyDiagnostics bound to a List<Diagnostic> field
when the module already declares the converter and uses it elsewhere.

Evidence, two arms in ONE remote dispatch so they share the ambient tree (the
runner mirrors a different checkout than the requesting worktree, which silently
confounded a first attempt):

  ARM=BASE  TOTAL 431  v2_compiler_parse.rs 24
  ARM=HEAD  TOTAL 428  v2_compiler_parse.rs 21

Joined at SITE identity rather than by count: the removed set is exactly
{E0573@1664, E0308@1675, E0308@1684}. Nothing was added, in this file or any
other, and every other file's count is identical across the arms — so the -3
total is the -3 here and not a class moved upstream. Independently, a clean
worktree at 531a107 produced the same 24 with a byte-identical site list.

The brief's board was also one class stale: its E0597:4 column is zero live,
closed by #8799 after that measurement. No delta is claimed on the other columns.

Reported in the coordination surface as section 22, including the observation the
lane ends on: the surviving board's top-class share RISES from 21% to 24%, so
fixing the singletons makes the file flatter by the code-grain metric while making
it more concentrated by the mechanism-grain one. A code-grain histogram is not a
root census, and a lane picked off one should re-partition before it plans.

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

smart-ram-730's fleet board on the same ref ba63edc is 399, reproduced
independently twice site-for-site. The 32-diagnostic gap is the 61 ambient dirty
files this lane's runner mirrored — a dirty src/v1/05_emit_rust.dag changes what
is emitted, which changes what rustc sees. So 431 and 428 are internally
consistent with each other and with nothing else, and differencing 428 against
399 would render this lane's -3 as a fiction. Marked as such at the point of use,
with the two strings (OBSERVED ON / CLAIM ABOUT) written on the section so the
difference is legible before a sentence quotes them rather than after.

The -3 delta is untouched by this: both arms ran in ONE dispatch against the SAME
contaminated tree, so the contamination is common-mode, and the join is at site
identity rather than by count.

Also corrects one of this section's own sentences. It described the 531a107
characterization run as a 'clean worktree', which was a claim about the REQUESTING
worktree — that run never echoed git status, so the runner's dirtiness is
unmeasured there too. Two runs agreed at 24 with a byte-identical site list; two
TREES did not. Same conflation the section exists to warn about, made one
paragraph above the warning.

And names the owning lanes for the two roots left unpatched: T3 is
royal-dove-436's cluster (blocked on an identity question, renderers not to be
touched from here), RT-builtin contains is the callee-resolution class. States
plainly that being the cleanest unpatched specimen of both is the deliverable
those lanes should take from this file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls merged commit 67437fc into main Aug 22, 2026
1 check passed
@briansrls
briansrls deleted the session/neat-ferret-237 branch August 22, 2026 00:51
This was referenced Aug 22, 2026
briansrls pushed a commit that referenced this pull request Aug 22, 2026
…ad ever obeyed until one did (#8854)

* The declaration was the lie: two OccurrenceId params that no caller had ever obeyed until one did

MAIN IS RED at 67437fc — 16 witnesses (12 fold_lowering, 4 body_lowering.statement_let_bind)
fail with `non-exhaustive pattern match on: OccurrenceId { value: 79 }`. Green PR, green base,
red union: #8833's branch did not contain #8828, and neither head ever existed in the
combination that fails.

The mechanism is one layer below the obvious one. #8833 changed one call in `02_parse`
`parse_expr_terminal` from `node_occurrence_minted(id: minted.id)` to `minted.id` — and it did
that to OBEY the signature it was calling. `v2.extdeps.languages.dag` declares

  fn dag_int_literal_node_from_lexeme(lexeme: String, occurrence_id: OccurrenceId)
  fn dag_int_literal_node_from_magnitude(magnitude: DecimalMagnitude, occurrence_id: OccurrenceId)

and stores that parameter straight into `Node.occurrence_id`, which is declared
`NodeOccurrenceId`. Both signatures have said `OccurrenceId` since #6558. Every caller in the
tree contradicted them by passing `SyntheticOccurrence`, which is why it stayed invisible.
#8833's author was the first person to take the signature at its word.

So the wrap is correct and the declaration is the defect. Fixed at the declaration, not just at
the call site — repairing only the caller leaves the lie standing for the next caller to obey:

  - dag.dag: both parameters redeclared `NodeOccurrenceId`; the now-unused
    `import std.occurrence_identity { OccurrenceId }` dropped, `NodeOccurrenceId` added to the
    existing `v2.std.node` import.
  - 02_parse.dag: `node_occurrence_minted(id: minted.id)` restored.

Caller census, read at call grain rather than by same-line grep — 17 sites across the two
functions: 15 pass `SyntheticOccurrence`, 1 passes `node.occurrence_id`, 1 is dag.dag's own
internal pass-through, and 1 passes the raw `minted.id`. Exactly one obedient caller existed and
it is the one that reddened main, so no second detonation is waiting. Changing the declared type
inverts which callers are correct, and by the finding below the typechecker cannot verify that
for us — hence reading, not building.

Green by execution, not by reasoning that the types now match: all 16 fold_lowering witnesses and
all 4 statement_let_bind witnesses PASS. The discriminating RED is main itself.

Also files one guarantee row, deliberately not fixed here. `v1.compiler.04_infer` gates
`arg_compat_diags` on `module_skips_direct_call_arg_check`, which is true for every module named
`v2.*`, keyed on the CALLER's module — so the direct-call argument-TYPE judgment is switched off
across the entire active v2 corpus. That is why nothing complained in EITHER direction for two
months. The row records the inversion that makes this class hard to see: a declaration that lies
is inert while every caller contradicts it in the same direction, and detonates on the first
caller who obeys it, so the at-risk population is callers who might get it right.

* The row is a correction to DESIGN §4b, not an observation beside it: confinement was measured and then treated as safety

DESIGN §4b names module_skips_direct_call_arg_check and reports it scoped entirely to the
direct-call argument-type judgment, not reaching sole_constructor — a positive finding, axis
retired. That finding is correct. It asked whether the exemption LEAKS; it never asked what the
exemption COSTS inside the judgment it is scoped to, and that judgment is the argument-type check
for the whole active v2 corpus. A reader who finds DESIGN's sentence and this row separately would
conclude the question was already answered, so the row now says which half it is.

Also records, against my own case: the arm is NOT unreasoned. direct_call_shape_wall_note states
the TYPE judgment's false-positive classes are representation gaps (brand aliases, optionality's
two forms, anonymous literals, expansion depth). That is a real stated reason, and it is why this
row asks for a measurement rather than a deletion. What is unmeasured is whether those classes
still fire in v2 and at what rate.

* The corrected declaration is TRUE but INERT: the judgment that would enforce it is the one switched off

Two changes, neither to the repair.

RUNG HONESTY, and it is the point. Correcting the parameter to NodeOccurrenceId reads like the §5
construction move -- fix the type and the wrong call stops compiling -- but the judgment that would
refuse the wrong call is `module_skips_direct_call_arg_check`, which exempts every `v2.*` caller
from the direct-call argument-TYPE check. So this PR lands a wall that CANNOT FIRE. The declaration
is now true, which is worth having on its own terms, but as enforcement it is inert, and shipping
it while believing the class is closed is exactly the rung inflation §4b calls worse than sitting
low. The class stays at its old rung; the next-rung trigger is the exemption's deletion, which the
guarantee row already names. (Product-direction ruling, swift-badger-524.)

ANNOTATIONS, grafted from gunbc#8856 (author's wording kept) with two additions of my own. With the
type wall inert, a §4c annotation is the only thing standing at these two sites -- it is not
evidence, and nothing mechanical reads it, which is precisely why it has to say why the shape is
what it is. Added to the callee: a bare OccurrenceId is the PAYLOAD INSIDE one of NodeOccurrenceId's
arms, never a member of the coproduct -- the modeling error in one line (smart-ram-730's phrasing,
the clearest statement of it anyone produced). Added to the caller: that the exemption is why no
mechanism stands there.

Green by execution after the annotations: 16/16 fold_lowering witnesses PASS, 0 FAIL.

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
briansrls added a commit that referenced this pull request Aug 25, 2026
…uted flag names an RcStr carrier that does not exist (#9212)

* char_at's ascii-aware split has no producer on main: delete it and bound the ASCII test by pos

`v1_rt::char_at_ascii_aware` / `string_length_ascii_aware` /
`substring_ascii_aware` take a precomputed `is_ascii` flag, and their doc
comment names the producer of that flag as "the `RcStr` carrier fact". No
`RcStr` exists in this tree: `Value::Str` is `Rc<str>`, and every caller --
`char_at`, `string_length`, `substring`, and the one interpreter call site --
supplies `s.is_ascii()`, an O(n) whole-string rescan computed fresh per call.
The split is therefore unroutable: it is three public functions whose
parameter has no producer, plus a comment asserting a carrier that does not
exist.

Provenance, because the obvious reading (someone deleted RcStr) is wrong:
b1775d8 (#8360) landed BOTH halves and is NOT an ancestor of main. main's
history is rooted at 67437fc (#8833), a wholesale seed re-import whose tree
already carries the runtime split (`src/v1/runtime_rust.dag` +826) beside an
interpreter with no `RcStr` (+16717, zero occurrences). The flag has never had
a producer anywhere in main's reachable history, and #8360's O(1) claim has
never been true of this tree.

The repair, at the single authority `src/v1/runtime_rust.dag` (mirrors
`v1_rt.rs` / `v1_compiler_runtime_rust.rs` follow by regen):

- Delete the `_ascii_aware` triplet. Nothing supplies a flag other than
  `s.is_ascii()`, so the parameter is a second representation of a fact the
  function can read itself (DESIGN §2/§3), and the comment on it is the §4b
  inflation case -- a carrier named for a rung the tree does not occupy.
- Bound the ASCII test by the requested position instead of by the whole
  string. A leading run of ASCII bytes makes the byte offset equal the
  code-point offset, so `char_at` examines `bytes[..=pos]` and `substring`
  examines `bytes[..end]`, never the tail. Cost drops from
  O(n) + O(pos) to O(min(pos, n)) -- the fallback's own cost. Semantics are
  unchanged: where the old form fell back to `chars()` because the STRING
  contained a multibyte char, the new form takes the byte path only when the
  PREFIX up to the requested index is ASCII, which is exactly the condition
  under which byte index equals code-point index.
- Route the interpreter's `native_len` `Value::Str` arm through
  `v1_rt::string_length` and fix its doc comment, which named the deleted
  helper.
- Delete `gunbc.char_at_scaling_probe_support`. Its `DissolutionCondition`
  names `src/v1/stage0/src/bin/char_at_scaling_probe.rs`, deleted by #9160,
  and its trigger is "when char_at's O(1) property is floor-enrolled" -- a
  property this tree does not have. It is unconsumed (census row in
  docs/plans/unconsumed-module-residue-disposition.md) and its subject is gone.

RESIDUAL, DECLARED RATHER THAN CLAIMED CLOSED: a left-to-right walk of a
string is still O(n^2), now with a smaller constant rather than a different
shape. A single call cannot be O(1) without the whole-string ASCII fact, which
needs a carrier on the string value; that carrier -- or a cursor surface that
does not re-index from zero -- is this class's next-rung trigger, and it is
recorded in the `char_at` doc comment rather than left to be rediscovered.
This change lowers no rung: the deleted split was inert, so nothing it
guaranteed is lost.

Evidence: dag/test/claim/char_at_unicode_witness_test.dag (SubstrateInputsOnly,
floor-routed) gains the discriminating control for the prefix-bounded path --
"ab" + U+00E9 + "c" is 5 bytes and 4 code points, so a byte-offset
implementation returns U+00A9 at index 3 and "c" at index 4 where code-point
indexing returns "c" at 3 and "" at 4, with the same split applied to
`substring`.

* Regen: converge v1_compiler_runtime_rust.rs with the edited runtime_rust.dag authority (pass 1)

Pass 1 of the stage0 two-pass convergence. `--required-regen` regenerated
`v1_compiler_runtime_rust.rs` -- the stage0 transliteration of
`src/v1/runtime_rust.dag` -- from the edited authority; this installs that
candidate byte-for-byte. `v1_rt.rs` is emitted BY this mirror, so its pass-1
candidate was still the old `_ascii_aware` text and converges only on pass 2,
after a rebuild against the mirror installed here.

* Drop the substring assertion: its RED was never observed, so it is not coverage

The witness gained three assertions for the prefix-bounded fast path. Two of
them are demonstrated discriminating: with `char_at`'s prefix check removed and
the binary rebuilt from scratch (perturbation confirmed present in source),
`char_at_agrees_across_the_ascii_prefix_boundary`,
`char_at_past_the_multibyte_char_is_not_a_byte_offset` and the pre-existing
`char_at_indexes_code_points_on_multibyte_text` all go RED.

The third, `substring_agrees_across_the_ascii_prefix_boundary`, does not. Its
own perturbation -- `if bytes[..out_end].is_ascii()` replaced by `if true`, so
the byte-slice path is taken unconditionally -- left it GREEN, twice, the
second time with the binary deleted first, the build failure-checked rather
than piped through `tail`, and the edit grep-proven in source. A follow-up
probe that would have printed the returned values panicked in `cli_run.rs` on
BOTH arms, so it measured nothing: identical output across arms is the
signature of an instrument that did not run, not of agreement.

So the mechanism is unexplained. What is NOT in doubt is the assertion's
status: a check whose RED has never been observed is not evidence, and
shipping it would put it in the worst class DESIGN §4b names -- permanently
green as far as anyone can show, and cited as coverage precisely because it is
named after the thing it does not test. It is removed rather than kept with a
caveat, because a caveat in a PR body does not travel with the test.

The `substring` code change stands: it is the same prefix-bounding as
`char_at`, semantics-preserving by the same argument (the byte path is taken
only when the prefix up to the requested index is ASCII, which is exactly when
byte index equals code-point index), and substring is exercised heavily by the
existing corpus. What it does not have is a discriminating control of its own,
and the witness note now says so in the module rather than leaving a reader to
infer coverage from the file's name.

OPEN QUESTION, recorded rather than routed around: `substring(s, 0, 3)` on
"ab" + U+00E9 + "c" under the unconditional byte path slices `s[0..3]`, which
lands inside the two-byte U+00E9 and should panic on a non-char-boundary. It
did not. Either that path is not reached by a named-argument `.dag` call, or
the panic is absorbed somewhere between the interpreter arm and the claim
runner's exit status. The second would be the more serious finding -- a witness
that cannot go red because failures are swallowed would affect every witness,
not this one -- and it is worth its own lane.

---------

Co-authored-by: Brian Searls <briansearls1@gmail.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