Repository navigation
classify: the browser could not tell a Markdown file from a broken spec (refs #2133) - #4541
Conversation
…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>
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
…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.
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-10-02 20:17:58 UTC
Summary
Seal Status
|
|
bee review (not merged) -- head Content is sound:
Blocker: 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>
PR DashboardGenerated at: 2026-10-02 20:52:35 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
|
Bee review evidence -- #4541 at
|
* 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>
The Spec Explorer's health chips read
✕ Broken 338. 81 of those 338 files are not modules. They are Markdown prose carrying the.t27extension, TRI-27 assembly, the olderspec Name { }dialect, and the fixtures underbootstrap/tests/fixtures/damagethat 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.
t27calways knew; the browser had no way to askt27c classifyanswers "is this file source?" before the parser is asked. But the wasm bridge exposesanalyze_sourceand nothing else, so every downstream caller had only parse success to go on.So the rule moves out of
run_classifyintobootstrap/src/source_kind.rs, byte for byte, and both readers share it:main.rskeeps printing exactly what it printed. The labels are the same padded strings, and the whole-corpusclassifyoutput is byte-identical before and after.bindings/wasm-explorerpicks 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_sourcenow returnssourceKind: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:
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 --verbosenow says when it truncatesRefs #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 t27csucceeds;t27c classifyover the whole corpus is byte-identical to master's output.source_kind.rs, all passing, including the cases that separate the classes: a damagedmoduleline isunclassifiedrather thansource, and a heading below the 40-line window does not count.cargo build --release --target wasm32-unknown-unknownfrombindings/wasm-explorer/succeeds (the crate is in the workspaceexcludelist, so it does not build from the root).The consumer side — the
◇ Not a modulechip and the corrected denominator — is a matching trinity PR.🤖 Generated with Claude Code