Skip to content

A census that proves its own categories - #2885

Merged
gHashTag merged 2 commits into
masterfrom
probe-backed-census
Aug 29, 2026
Merged

A census that proves its own categories#2885
gHashTag merged 2 commits into
masterfrom
probe-backed-census

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

tri unparsed names the construct that stops the compiler on each unreadable
spec. Every row is a claim, and the claims can be false in a way no amount
of reading catches. Six constructs read off real failing lines — plausible,
every one — compile in isolation:

@trim("x", "y")          builtin call            ACCEPTED
.anthropic               enum literal            ACCEPTED
if (c) { 1 } else { 2 }  if-expression           ACCEPTED
*Foo   &Foo              pointer / reference     ACCEPTED
[]const u8               const-qualified slice   ACCEPTED
for (s) |v| { }          capture in a for-loop   ACCEPTED

An earlier multi-agent fan-out named []const u8 as a cause. A queue repeating
it sends someone to implement a feature that already exists.

Probe

Every construct now carries a minimal source the compiler must reject for
the row to be named. The census is self-invalidating — when a construct gains
support its probe passes and the row leaves the queue with no list to edit. It
did that twice in this run, for module a::b (#2882) and pub module N;
(this PR).

tri unparsed probe

  constructs probed              17
  ... the compiler REJECTS       15
  ... the compiler ACCEPTS        2
  counters that still compile    10 of 10

Counter

The probe checks one direction only. is_use fired on every line starting with
use — but plain use a::b; and using a::b; both compile, and only
use a::b as C; fails. The probe was the aliased form, so it passed while
the matcher was wrong.

So each construct also carries a counter: a near-identical source the
compiler accepts, on which the matcher must stay silent.

fn every_matcher_fires_on_its_own_probe()   // can the row ever be named
fn no_matcher_fires_on_its_counter()        // is the boundary right

Counters located the real boundaries:

compiles does not so the defect is
1 as u32 1 as float the target type, not the cast
fn a(k: Result<T, E>) fn a<T>(k: T) parameters on the function
[T] [K: V] the map type, not array syntax
for (s) |v| { } if (o) |v| .. the if form of capture
use a::b; use a::b as C; the alias

tri unparsed probe fails if a counter stops compiling — that means the
boundary moved, not the compiler.

Refused on purpose — a third state

x as float is rejected, and it is not a gap: VALID_CAST_TYPES carries a
written argument that no backend lowers float arithmetic and that the C
generator would emit f32 verbatim, which is not a C type. Three specs sat in
the work queue proposing that someone undo that decision.

They now print in their own section with the citation. The error text does not
distinguish the two — I tried; the deliberate refusal still prints
parse error ... unknown cast target. The marking is manual and the docs say
so: an unmarked row is not proof it is a gap, only that nobody has looked.

The census now

  specs tracked                       745
  ... the compiler cannot read         97
  ... construct NAMED and PROBED       43
  ... cause is UPSTREAM, not named     18
  ... not decided, nothing claimed     32
  ... error names no readable line      4
  broken ON PURPOSE under fixtures/    21  (detector inputs, not debt)
  constructs the compiler now ACCEPTS   2  (probed; not named)

43 + 18 + 32 + 4 = 97. The parts sum to the total.

The compiler change, and what it did not gain

pub module N; parses now — pub is a modifier the declaration parser already
reads for fn/struct/const, and a module was the one declaration where it
was not accepted.

Specs gained: zero. The single file carrying the construct
(test_highlight.t27) advanced from line 4 to line 21 and stopped on **. Seal
drift is 537 on this branch and 537 on master — no generated output moved at
all. Saying that plainly rather than reaching for "an obstacle removed".

Controls

control expected got
pub module test; parses parses
module test; (pre-existing) still parses parses
pub const X = 1; (pre-existing) still parses parses
pub module a::b { } parses parses
every previously-parsing spec unchanged 627 of 627, 0 broken
seal drift vs master unchanged 537 = 537
bootstrap test ratchet no new failures "Baseline holds."
10 counters all compile 10 of 10

14 unit tests in unparsed.rs.

Gates, run locally

specs generate 0 · specs parse 0 · conflict markers 0 · seal coverage
--self-check 0 · seals fresh 0 · types ratchet 0 · skill check 0 ·
prose report 0 · unparsed probe 0 · cargo test -p tri 0 · bootstrap ratchet 0 ·
rustfmt --check cli/tri/src/unparsed.rs 0.

Refs #2864

`tri unparsed` names the construct that stops the compiler on each unreadable
spec. Every row is a claim, and the claims can be false in a way no amount of
reading catches: SIX constructs read off real failing lines -- plausible, every
one -- compile in isolation.

    @Trim("x", "y")          builtin call            ACCEPTED
    .anthropic               enum literal            ACCEPTED
    if (c) { 1 } else { 2 }  if-expression           ACCEPTED
    *Foo   &Foo              pointer / reference     ACCEPTED
    []const u8               const-qualified slice   ACCEPTED
    for (s) |v| { }          capture in a for-loop   ACCEPTED

An earlier fan-out had named `[]const u8` as a cause. A queue repeating it
sends someone to implement what is already there.

So every construct now carries a PROBE -- a minimal source the compiler must
reject for the row to be named -- and the census is self-invalidating: when a
construct gains support its probe passes and the row leaves with no list to
edit. It did that twice in this run, for `module a::b` and `pub module N;`.

The probe checks one direction only. `is_use` fired on every `use` line while
plain `use a::b;` compiles and only `use a::b as C;` does not -- and the probe
WAS the aliased form, so it passed while the matcher stayed wrong. Hence a
COUNTER per construct: a near-identical source the compiler ACCEPTS, on which
the matcher must stay silent. `no_matcher_fires_on_its_counter` holds it, and
`tri unparsed probe` fails if a counter stops compiling, because that means the
boundary moved rather than the compiler.

Counters found the real boundaries: `1 as u32` compiles and `1 as float` does
not, so the defect is the TARGET type; `fn a(k: Result<T, E>)` compiles and
`fn a<T>(k: T)` does not, so it is parameters on the FUNCTION; `[T]` compiles
and `[K: V]` does not.

Third state: refused ON PURPOSE. Casts to non-primitive types are a documented
position -- no backend lowers float arithmetic, argued beside VALID_CAST_TYPES
-- not a gap. Three specs moved out of the work queue into a section carrying
the citation. The error text does not distinguish the two; I tried, and the
deliberate refusal still prints "parse error". The marking is manual and says
so.

Also: `pub module N;` parses. `pub` is a modifier the declaration parser
already reads for fn/struct/const and a module was the one place it was not.
Specs gained: ZERO. The single file carrying it advanced from line 4 to line 21
and stopped on `**`. Seal drift is 537 on this branch and 537 on master, so no
generated output moved at all.

FROZEN_HASH updated in the same commit, per M5.

Refs #2864

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gHashTag
gHashTag enabled auto-merge (squash) August 29, 2026 21:02
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-08-29 21:04:47 UTC

Summary

Status Count
Total Open PRs 8
PRs with Failing Checks 7
PRs with All Checks Green 1
READY 0
FAILING 7
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=f569da0c6c14 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@github-actions

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@gHashTag
gHashTag merged commit dac4c31 into master Aug 29, 2026
27 of 29 checks passed
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.

2 participants