Skip to content

Commit c1230af

Browse files
committed
Collapse README bench block to a per-language bar chart
The auto-generated block was a TS-only expanded breakdown (per-issue table, 21-fix list, token table) — that doesn't scale as Monogram adds languages. Replace it with one compact ASCII bar chart, one row per language (Monogram vs official, % of that language's documented official-grammar bugs handled), so new languages slot in as single rows. - buildBenchMarkdown takes a per-language list and renders bars; TypeScript is populated, JavaScript is a pending placeholder until it gets the oracle bench. - The per-issue / token detail is dropped from the README (still printed when you run the bench directly).
1 parent f2179fe commit c1230af

2 files changed

Lines changed: 53 additions & 58 deletions

File tree

README.md

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,32 +56,24 @@ The valid-code/bidirectional numbers are the grammar's correctness proof; the hi
5656

5757
### Head-to-head: highlighter correctness vs the official grammar
5858

59-
The numbers below are **auto-generated** by [`test/highlight-bench.ts`](test/highlight-bench.ts)it grades *both* the official TextMate grammar and Monogram's against a neutral `tsc` oracle, so the comparison is absolute (each has a real distance from 100%), not relative.
59+
**Auto-generated** by [`test/highlight-bench.ts`](test/highlight-bench.ts)one row per language, more as Monogram gains them:
6060

6161
<!-- bench:start -->
62-
<!-- generated by `node test/highlight-bench.ts --write-readme` — do not edit by hand -->
62+
<!-- generated by `npm run bench:readme` — do not edit by hand -->
6363

64-
Both grammars are graded against a neutral **`tsc`** oracle (the parser only — never
65-
Monogram's own output, never the official grammar). Ceiling is 100%.
64+
Each bar = **% of that language's documented official-grammar bugs** the highlighter renders
65+
correctly, graded against a neutral `tsc` oracle (100% = all of them). Monogram derives its
66+
highlighter from its conformance-proven parser; the official one is hand-written regex.
6667

67-
**On the documented official-grammar bug ledger** — the 49 [`microsoft/TypeScript-TmLanguage`](https://github.com/microsoft/TypeScript-TmLanguage/issues) issues in [`test/issue-cases.ts`](test/issue-cases.ts) (49 adjudicable by a syntactic oracle), graded per issue:
68-
69-
| grammar | handles the bug correctly |
70-
|---|---|
71-
| Official TextMate | 38.8% (19/49) |
72-
| **Monogram** | **77.6% (38/49)** |
73-
74-
Independently-verified **Monogram fixes** — official structurally wrong, Monogram right: **21** issues (#815, #853, #859, #873, #883, #891, #973, #978, #981, #983, #1014, #1020, #1025, #1040, #1041, #1043, #1050, #1051, #1053, #1056, #1059). Monogram regressions vs official: 2 (#819, #876).
75-
76-
**Token-level role accuracy** (every parser-classifiable token):
77-
78-
| corpus | Official | Monogram |
79-
|---|---|---|
80-
| documented bug ledger (534 tokens) | 83.5% | 94.2% |
81-
82-
<sub>Parser-conformance row omitted — run with the TS corpus cloned to `/tmp/ts-repo` to include it.</sub>
68+
```
69+
TypeScript
70+
Monogram █████████████████░░░░░ 78% (38/49)
71+
official █████████░░░░░░░░░░░░░ 39% (19/49)
72+
JavaScript
73+
pending — JS not yet on the neutral-oracle bench (see ROADMAP)
74+
```
8375

84-
<sub>Regenerate: `node test/highlight-bench.ts --write-readme`. Neutral oracle + frozen scope→role table: [`test/scope-roles.ts`](test/scope-roles.ts).</sub>
76+
<sub>TypeScript = 49 oracle-adjudicable open [`microsoft/TypeScript-TmLanguage`](https://github.com/microsoft/TypeScript-TmLanguage/issues) issues ([`test/issue-cases.ts`](test/issue-cases.ts)) — 21 of Monogram's wins are fixes the official grammar gets *structurally* wrong. Per-issue breakdown: `node test/highlight-bench.ts`. Regenerate: `npm run bench:readme`.</sub>
8577
<!-- bench:end -->
8678

8779
> **The other side of the ledger (honesty check).** On the *broad* TS parser-conformance corpus — not just the documented bugs — raw token-role accuracy flips: the official grammar's decade of hardening leads (~99% vs ~96%). Monogram's gap there is specific backlog (Unicode identifiers, qualified type names), **not** the ambiguity class above. Clone the TS corpus to `/tmp/ts-repo` and run `node test/highlight-bench.ts` to see both corpora.

test/highlight-bench.ts

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -572,42 +572,43 @@ function reportByIssue(perInput: InputResult[]): IssueStats {
572572
return { total: all.length, adj: D, offPass, monoPass, fixes, regress, bothFail };
573573
}
574574

575-
// ── README auto-generation: build the marker block from the computed summaries ─
576-
function buildBenchMarkdown(parser: BenchSummary | null, adv: BenchSummary | null, iss: IssueStats | null): string {
577-
const p = (n: number, d: number) => (d === 0 ? 'n/a' : ((n / d) * 100).toFixed(1) + '%');
575+
// ── README auto-generation: one compact bar chart, one row per language ────────
576+
// Deliberately NOT expanded (no per-issue tables): this scales to many languages.
577+
interface LangResult { name: string; issue: IssueStats | null; note?: string }
578+
579+
const BAR_W = 22;
580+
function bar(frac: number): string {
581+
const f = Math.max(0, Math.min(BAR_W, Math.round(frac * BAR_W)));
582+
return '█'.repeat(f) + '░'.repeat(BAR_W - f);
583+
}
584+
585+
function buildBenchMarkdown(langs: LangResult[]): string {
578586
const out: string[] = [];
579-
out.push('<!-- generated by `node test/highlight-bench.ts --write-readme` — do not edit by hand -->');
587+
out.push('<!-- generated by `npm run bench:readme` — do not edit by hand -->');
580588
out.push('');
581-
out.push('Both grammars are graded against a neutral **`tsc`** oracle (the parser only — never');
582-
out.push("Monogram's own output, never the official grammar). Ceiling is 100%.");
583-
if (iss) {
584-
out.push('');
585-
out.push(`**On the documented official-grammar bug ledger** — the ${iss.total} [\`microsoft/TypeScript-TmLanguage\`](https://github.com/microsoft/TypeScript-TmLanguage/issues) issues in [\`test/issue-cases.ts\`](test/issue-cases.ts) (${iss.adj} adjudicable by a syntactic oracle), graded per issue:`);
586-
out.push('');
587-
out.push('| grammar | handles the bug correctly |');
588-
out.push('|---|---|');
589-
out.push(`| Official TextMate | ${p(iss.offPass, iss.adj)} (${iss.offPass}/${iss.adj}) |`);
590-
out.push(`| **Monogram** | **${p(iss.monoPass, iss.adj)} (${iss.monoPass}/${iss.adj})** |`);
591-
out.push('');
592-
out.push(`Independently-verified **Monogram fixes** — official structurally wrong, Monogram right: **${iss.fixes.length}** issues (${iss.fixes.map((n) => '#' + n).join(', ')}).` + (iss.regress.length ? ` Monogram regressions vs official: ${iss.regress.length} (${iss.regress.map((n) => '#' + n).join(', ')}).` : ''));
593-
}
594-
const tokRows: string[] = [];
595-
if (adv) tokRows.push(`| documented bug ledger (${adv.token.n} tokens) | ${p(adv.token.oRole, adv.token.n)} | ${p(adv.token.mRole, adv.token.n)} |`);
596-
if (parser) tokRows.push(`| TS parser conformance (${parser.token.n} tokens) | ${p(parser.token.oRole, parser.token.n)} | ${p(parser.token.mRole, parser.token.n)} |`);
597-
if (tokRows.length) {
598-
out.push('');
599-
out.push('**Token-level role accuracy** (every parser-classifiable token):');
600-
out.push('');
601-
out.push('| corpus | Official | Monogram |');
602-
out.push('|---|---|---|');
603-
out.push(...tokRows);
604-
}
605-
if (!parser) {
606-
out.push('');
607-
out.push('<sub>Parser-conformance row omitted — run with the TS corpus cloned to `/tmp/ts-repo` to include it.</sub>');
589+
out.push("Each bar = **% of that language's documented official-grammar bugs** the highlighter renders");
590+
out.push('correctly, graded against a neutral `tsc` oracle (100% = all of them). Monogram derives its');
591+
out.push('highlighter from its conformance-proven parser; the official one is hand-written regex.');
592+
out.push('');
593+
out.push('```');
594+
for (const L of langs) {
595+
out.push(L.name);
596+
if (L.issue && L.issue.adj > 0) {
597+
const m = L.issue.monoPass / L.issue.adj;
598+
const o = L.issue.offPass / L.issue.adj;
599+
out.push(` Monogram ${bar(m)} ${Math.round(m * 100)}% (${L.issue.monoPass}/${L.issue.adj})`);
600+
out.push(` official ${bar(o)} ${Math.round(o * 100)}% (${L.issue.offPass}/${L.issue.adj})`);
601+
} else {
602+
out.push(` ${L.note ?? 'pending — not yet on the neutral-oracle bench'}`);
603+
}
608604
}
605+
out.push('```');
609606
out.push('');
610-
out.push('<sub>Regenerate: `node test/highlight-bench.ts --write-readme`. Neutral oracle + frozen scope→role table: [`test/scope-roles.ts`](test/scope-roles.ts).</sub>');
607+
const ts = langs.find((l) => l.issue && l.issue.adj > 0);
608+
const ctx = ts
609+
? `TypeScript = ${ts.issue!.adj} oracle-adjudicable open [\`microsoft/TypeScript-TmLanguage\`](https://github.com/microsoft/TypeScript-TmLanguage/issues) issues ([\`test/issue-cases.ts\`](test/issue-cases.ts)) — ${ts.issue!.fixes.length} of Monogram's wins are fixes the official grammar gets *structurally* wrong. `
610+
: '';
611+
out.push(`<sub>${ctx}Per-issue breakdown: \`node test/highlight-bench.ts\`. Regenerate: \`npm run bench:readme\`.</sub>`);
611612
return out.join('\n');
612613
}
613614

@@ -649,8 +650,6 @@ async function allTs(dir: string): Promise<string[]> {
649650
const WRITE_README = argv.includes('--write-readme');
650651
const WHICH = getFlag('--corpus') ?? 'both'; // --write-readme respects --corpus (CI uses adversarial = deterministic, no TS clone)
651652

652-
let parserSummary: BenchSummary | null = null;
653-
let advSummary: BenchSummary | null = null;
654653
let issueStats: IssueStats | null = null;
655654

656655
if (WHICH === 'parser' || WHICH === 'both') {
@@ -665,7 +664,7 @@ if (WHICH === 'parser' || WHICH === 'both') {
665664
for (const f of files) {
666665
try { inputs.push({ name: f, text: readFileSync(f, 'utf-8') }); } catch { /* skip unreadable */ }
667666
}
668-
parserSummary = runBench('parser conformance corpus', 'tests/cases/conformance/parser (TS parser test suite)', inputs).summary;
667+
runBench('parser conformance corpus', 'tests/cases/conformance/parser (TS parser test suite)', inputs);
669668
}
670669
}
671670

@@ -683,10 +682,14 @@ if (WHICH === 'adversarial' || WHICH === 'both') {
683682
`${distinct} issues / ${advInputs.length} cases from test/issue-cases.ts`,
684683
advInputs,
685684
);
686-
advSummary = res.summary;
687685
issueStats = reportByIssue(res.perInput);
688686
}
689687

690688
if (WRITE_README) {
691-
writeReadmeBlock(buildBenchMarkdown(parserSummary, advSummary, issueStats));
689+
// One row per language. TypeScript has the full oracle bench today; add more
690+
// languages here as each gets its grammar + documented-bug ledger.
691+
writeReadmeBlock(buildBenchMarkdown([
692+
{ name: 'TypeScript', issue: issueStats },
693+
{ name: 'JavaScript', issue: null, note: 'pending — JS not yet on the neutral-oracle bench (see ROADMAP)' },
694+
]));
692695
}

0 commit comments

Comments
 (0)