Skip to content

classify: the browser could not tell a Markdown file from a broken spec (refs #2133) - #4541

Merged
gHashTag merged 4 commits into
masterfrom
feat/source-kind
Oct 2, 2026
Merged

gHashTag merged 4 commits into
masterfrom
feat/source-kind

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

The Spec Explorer's health chips read ✕ Broken 338. 81 of those 338 files are not modules. They are Markdown prose carrying the .t27 extension, TRI-27 assembly, the older spec Name { } dialect, and the fixtures under bootstrap/tests/fixtures/damage that this repository breaks on purpose. A parser asked to parse a document fails, correctly — and the board then reported that correct failure as a defect in the corpus.

This is #2133's theorem, at a second instrument

#2133 proved the general case at the ratchet: a count over a heterogeneous population moves under three independent operations — improving the subject, improving the instrument, and changing the mix of kinds — so its value alone cannot say which happened. Its corollary was publish the partition. Gate 28 published it for the ratchet. The browser never got it, so the public board has been carrying a composition metric labelled as a defect count.

t27c always knew; the browser had no way to ask

t27c classify answers "is this file source?" before the parser is asked. But the wasm bridge exposes analyze_source and nothing else, so every downstream caller had only parse success to go on.

So the rule moves out of run_classify into bootstrap/src/source_kind.rs, byte for byte, and both readers share it:

  • main.rs keeps printing exactly what it printed. The labels are the same padded strings, and the whole-corpus classify output is byte-identical before and after.
  • bindings/wasm-explorer picks the module up through the same #[path = "../../../bootstrap/src/..."] mechanism it already uses for the compiler itself. There is no copy to drift — that was the point of extracting it rather than writing a second rule for the browser.

analyze_source now returns sourceKind: source · alt-syntax · not-code · mixed · unclassified.

Why this is an axis and not a fourth health state

The corpus settles it. Cross-tabbing health against sourceKind over 1419 entries:

health source alt-syntax not-code mixed unclassified total
ok 986 6 – – 25 1017
warn 175 – 6 1 2 184
fail 137 2 40 – 39 218

81 non-modules fail — but 31 non-modules compile cleanly. Whether a file is a module and whether it compiles are two questions, and this corpus answers them independently. Collapsing them into one column is what produced the wrong headline.

Also: classify --verbose now says when it truncates

Refs #2607, which is the same rule at a third instrument. The listing has always capped at 40 files per class while the counts table stayed exact. That cost an afternoon here — a work-list extracted from that output looked like a whole class and was 40 of 211.

Verification

  • cargo build --release --bin t27c succeeds; t27c classify over the whole corpus is byte-identical to master's output.
  • 8 new unit tests in source_kind.rs, all passing, including the cases that separate the classes: a damaged module line is unclassified rather than source, and a heading below the 40-line window does not count.
  • cargo build --release --target wasm32-unknown-unknown from bindings/wasm-explorer/ succeeds (the crate is in the workspace exclude list, so it does not build from the root).

The consumer side — the ◇ Not a module chip and the corrected denominator — is a matching trinity PR.

🤖 Generated with Claude Code

…en spec

Refs #2133, refs #2607

The Spec Explorer read 338 specs as broken. 81 of them were never specs:
Markdown prose carrying the .t27 extension, TRI-27 assembly, the older
`spec Name { }` dialect, and the fixtures under bootstrap/tests/fixtures/damage
that this repository breaks on purpose. A parser asked to parse a document
fails, correctly, and the board then reported that failure as a defect in the
corpus.

#2133 named this exact shape at the ratchet and proved the general case: a
count over a heterogeneous population moves when the MIX moves, not only when
the subject or the instrument does, so its value alone cannot say which
happened. Its corollary was "publish the partition". Gate 28 published it for
the ratchet. The browser never got it.

t27c has always known the difference -- `t27c classify` answers "is this file
source?" before the parser is asked. The browser had no way to ask: the wasm
bridge exposes analyze_source and nothing else, so every caller downstream had
only parse success to go on.

So lift the rule out of run_classify into bootstrap/src/source_kind.rs, byte
for byte, and have both readers share it. main.rs keeps printing exactly what
it printed -- the labels are the same padded strings, verified against the old
output over the whole corpus -- and wasm-explorer picks the module up through
the same `#[path = "../../../bootstrap/src/..."]` mechanism it already uses for
the compiler itself, so there is no copy to drift.

analyze_source now returns `sourceKind`: source, alt-syntax, not-code, mixed or
unclassified. It is a separate axis from health, not a fourth state, and the
corpus is what proves it: 81 non-modules fail, but 31 others compile cleanly.
Whether a file is a module and whether it compiles are two questions, and this
corpus answers them independently.

Also make `classify --verbose` say when it is truncating, which is #2607's rule
applied to a second instrument. The listing has always capped at 40 files per
class while the counts table stayed exact, and that cost an afternoon here: a
list extracted from that output looked like a whole class and was 40 of 211.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

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

@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-09-21 13:59:45 UTC

Summary

Status Count
Total Open PRs 22
PRs with Failing Checks 19
PRs with All Checks Green 3
READY 2
FAILING 19
PENDING 0
NO CHECKS YET 0

These columns do not partition: 2 + 19 + 0 + 0 = 21, and there are 22 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=403499176a5d != 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).

gHashTag added a commit that referenced this pull request Sep 21, 2026
…mitted both (#4558)

Fixes #4557

`state_after` and `retry_allowed` were each declared twice in
specs/automation/crm-duet.t27, byte-identical down to the comment.

`t27c check` had been saying so all along -- "every backend rejects a
redeclaration" -- and it was right. What it did not do was stop
anything: the warning is not an error, `gen-c` exits 0, and the emitted
header carries both definitions.

  cc -std=c11 -fsyntax-only  before  ->  error: redefinition of 'state_after'
  cc -std=c11 -fsyntax-only  after   ->  that error is gone
  t27c check                 before  ->  0 errors, 2 warnings
  t27c check                 after   ->  0 errors, 0 warnings
  tools/dupe_scan.py         after   ->  no new duplicate, no known group grew

The deletion keeps the pair that sits with the module's other function
declarations. The spec's 12 tests are unchanged and still resolve.

This is master's red, not either open PR's: #4541 and #4551 both fail
`duplicate-bodies` on this file, which neither of them touches.
This was referenced Sep 21, 2026
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

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

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-02 20:17:58 UTC

Summary

Status Count
Total Open PRs 34
PRs with Failing Checks 33
PRs with All Checks Green 1
READY 1
FAILING 33
PENDING 0
NO CHECKS YET 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=b45a356c2eb6 != 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).

@gHashTag

gHashTag commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

bee review (not merged) -- head 9c3a1e5c43c20a985f2d17610ffc02e6b246fd9a, master 7079823ca7c5

Content is sound:

Blocker: check-now-freshness is red and the PR causes it -- docs/now/2026-09-21-...md is outside the window 2026-10-01..2026-10-03. Master is green on it.

To clear: re-date the NOW entry (or add one dated today) on the branch.

The NOW sync gate reads the entry date from the filename and accepts only
yesterday..tomorrow UTC. The entry was dated 2026-09-21; it is moved to
2026-10-03 with its heading, and a line says it was re-dated for re-review.

Refs #2133

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-02 20:52:35 UTC

Summary

Status Count
Total Open PRs 34
PRs with Failing Checks 27
PRs with All Checks Green 7
READY 1
FAILING 27
PENDING 0
NO CHECKS YET 0

These columns do not partition: 1 + 27 + 0 + 0 = 28, and there are 34 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=b45a356c2eb6 != 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

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

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

@gHashTag

gHashTag commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

Bee review evidence -- #4541 at 372cf43193d59b9f24c1702daf12d86e3c3fd8e1

  • Diff re-read: the classify rule moves verbatim from run_classify in bootstrap/src/main.rs into bootstrap/src/source_kind.rs (same has_module, has_spec, 40-line Markdown window, has_fn and branch order; label() reproduces the old column strings exactly). bindings/wasm-explorer includes the same file by #[path] and adds sourceKind to analyze_source. classify --verbose now reports a truncated listing. Unit tests cover each variant. This is a faithful refactor.
  • Re-date commit 372cf4319: a rename docs/now/2026-09-21-the-browser-could-not-tell-a-markdown-file-from-a-broken-spe.md -> 2026-10-03-..., the heading date 2026-09-21 -> 2026-10-03, and an appended ## Re-dated section stating the original date (2026-09-21, matching the old filename). Nothing else changed.
  • Mergeable: MERGEABLE on master 3fddac432 (after specs/functions: crm-proactive-sweep -- one step per seller after the 502 runs #4113 and specs/functions: payment-ai-server-process -- claim-invoice before crediting #4116). Required checks (validate, parse-ratchet, check-linked-issue) pass; check-now-freshness, Check L1 TRACEABILITY, the L1 summary and the corpus ratchet pass.
  • Red non-required, each compared against master:
    • test-ratchet: "the failing set grew by 25". The 25 test names are identical (a set diff with zero differences) to the master push run 37044782881 at 551579b23 (C-backend list/tuple/enum tests, corpus_unresolved, corpus_classifier_matches_lean_completeness). This is master-wide, not caused by this PR.
    • fpga-conformance: the elab ratchet reports "178 (baseline 176): NEW adapter, WORSE ternary_isa 6->7, WORSE uart 0->1, iverilog 12.0 vs baseline 13.0". The master push run 37044782965 at 551579b23 prints identical output. This is master-wide.
    • untrusted-input, spec-guards and emit-bitexact are on the known master-wide list. fpga-bitstream is still pending (non-required).

@t27-bees t27-bees Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bee review: see evidence comment

@gHashTag
gHashTag merged commit 1cf5252 into master Oct 2, 2026
38 of 43 checks passed
gHashTag added a commit to gHashTag/trinity that referenced this pull request Oct 4, 2026
* fix(explorer): 81 of the 338 "broken" specs were never specs

The board said `✕ Broken 338`. It was counting Markdown prose that happens to
carry the .t27 extension, TRI-27 assembly, the older `spec Name { }` dialect,
and the fixtures t27 damages on purpose. A parser asked to parse a document
fails, correctly, and the chip then reported that correct failure as a defect
in the corpus.

The compiler has always known the difference -- `t27c classify` answers "is
this file source?" before the parser is asked -- but the wasm bridge exposed
only analyze_source, so nothing downstream could ask. gHashTag/t27#4541 lifts
that rule into bootstrap/src/source_kind.rs and publishes it as `sourceKind`.
This is the consumer side.

What changed here:

  corpusEntry carries sourceKind through, defaulting to `source`. A file
  leaves the module count only when the classifier positively says it is not
  one; an absent field never silently shrinks the denominator.

  corpusAggregates counts health over modules and reports the rest as
  `notSource` -- total, byKind and byHealth. The last of those is the evidence
  that this is a separate axis rather than a fourth health state: 81 of these
  files fail, and 31 of them compile cleanly.

  SpecExplorer gains a `◇ Not a module` chip. Nothing is hidden: the four
  health chips plus this one still add up to All. `inGroup()` replaces the
  filter predicate that both `filtered` and `tagCounts` had been spelling out
  separately, which is how the two could have disagreed.

  The onboarding gate now checks a four-term sum. Adding the term rather than
  dropping it matters -- OK+WARN+FAIL alone would hold over 1333 files while
  SPEC_COUNT said 1454, green and wrong. HEALTH_FAIL_UNPARSED, _JS_ONLY and
  HEALTH_PARTIAL are module-only for the same reason: over every entry the
  first counts 228 against a HEALTH_FAIL of 156, and a subset larger than its
  set is a denominator mismatch wearing the clothes of a new fact. The gate
  now says so directly instead of leaving it to be noticed.

  isSourceEntry is imported, not retyped. Two copies of that predicate is
  exactly how the two denominators drift apart again.

Measured after regeneration against the new compiler:

  1001 ok · 176 warn · 156 fail   (of 1333 modules)
  121 not a module: unclassified 66 · not-code 46 · alt-syntax 8 · mixed 1
  1001 + 176 + 156 + 121 = 1454 ✓

Broken falls 218 -> 156 while the corpus itself grew by 35 files. The 156 that
remain are real: genuine module-level parse failures, a long tail rather than
a few shared gaps, and they are the next piece of work.

public/t27/ is regenerated by sync-t27-specs.mjs against the t27 branch,
including the vendored t27_compiler.wasm that carries the classifier.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(website): drop PR-vendored turbobaby files main's manifest does not list

Main's sync owns public/t27/files; these five came from the PR's older sync.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bee-reviewed A reviewer bee reviewed and verified this PR at its current head; the only merge signal (#5525)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant