Skip to content

edu/ast_lol: formatter capstone track - #1453

Merged
aaylward merged 5 commits into
mainfrom
claude/ast-parsing-learning-app-qli1yg
Aug 25, 2026
Merged

edu/ast_lol: formatter capstone track#1453
aaylward merged 5 commits into
mainfrom
claude/ast-parsing-learning-app-qli1yg

Conversation

@aaylward

Copy link
Copy Markdown
Collaborator

Adds Tier 6 to ast.lol — a parallel capstone track forking after Tier 3: a layout lesson, sql-expr-print (minimal parens over SQL's precedence system), and the sql-format capstone (width-aware canonical SQL under a reparse-identity obligation), graded against a new reference formatter (src/lang/sql/format.ts). Also rewrites the Why ASTs intro around the two capstone bookends.

The four-lens review panel ran against the track head; its fixes landed as 1192f39 (split chain operands keep position-required parens, pinned by literals and a corpus×widths reparse sweep; numbers render as plain digits, LIMIT included; the printExpr solution and capstone prelude are one constant). The two commits after that — checker-diagnostic test pins and Beyoncé-rule content — were not panel-reviewed.

323 tests; tsc, vitest, build, and the Playwright E2E pass (both new challenges solvable start to finish, custom tests included, mobile clean).


Generated by Claude Code

claude added 4 commits August 25, 2026 13:53
Tier 6 forks after Tier 3: a lesson on width-aware layout, sql-expr-print
(minimal parens over SQL's precedence system, the -- comment trap
included), and the sql-format capstone — flat when the query fits,
canonical clause-per-line breaking when it doesn't, graded exact-match
with failures diagnosed by reparsing the learner's text. Reference
formatter in lang/sql/format.ts with round-trip and width-battery tests;
298 tests total. The welcome lesson drops the ambiguous 'all week'
framing and describes both capstone tracks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7snNHsXg6msYZkBUHsViv
Chain splitting kept no position context, so a split operand lost required
parens — WHERE p AND (q OR r) rejoined as a different query, and one
capstone test shipped that wrong answer as expected. Split operands now
wrap under the printer's own rule (first operand at the chain level, the
rest one tighter), pinned by literals and a corpus-times-widths round-trip
sweep. Numbers render as plain digits (String() goes exponential at the
extremes, which the tokenizer cannot read back), LIMIT included. The
printExpr solution and the capstone prelude are one constant, tier5-style.
Plus panel wording fixes across the lesson, statements, and docs; 303
tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7snNHsXg6msYZkBUHsViv
The graded challenges were contract-tested but the failure diagnoses —
the debugging layer the track leans on — had no pins: exprPrintCheck's
non-string / unparseable / wrong-style / wrong-tree layers, formatCheck's
reparse / wrong-query / line-diff / width-callout layers, the tier2
parser-message surfacing, the sql-format width default, and plainNumber.
Nineteen tests; 322 total.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7snNHsXg6msYZkBUHsViv
Custom tests persisted and re-ran but nothing told learners, and every
mention framed them as exploration. The welcome lesson now states the
habit by name — a bug-catching input becomes a custom test — with
matching nudges at the round-trip printer and both capstones. Pinned by
a content test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7snNHsXg6msYZkBUHsViv
@cursor

cursor Bot commented Aug 25, 2026

Copy link
Copy Markdown

Review: edu/ast_lol formatter capstone track

Verdict: Approve. This is a strong, well-tested addition. Tier 6 fills a real pedagogical gap (formatting as the mirror capstone to optimization), the reference implementation is cleanly separated from curriculum wiring, and the grading/diagnostic layers match the patterns established in Tier 2.

What works well

Architecture. Putting the oracle in src/lang/sql/format.ts and grading against it keeps the curriculum from drifting — same pattern as execute/optimize. Exporting printSqlExpr, formatSelectFlat, and formatSelect from the lang barrel is the right surface.

Single source for expression printing. PRINT_EXPR_SOLUTION serving as both the sql-expr-print reveal and the sql-format prelude is a good guard against the classic "capstone fails on bytes the skill-builder already solved" failure mode.

The panel fix was real. The split-operand paren bug (WHERE p AND (q OR r) rejoining as a different tree) is exactly the kind of subtle formatter bug that would have shipped without the literal + corpus×width sweep in format.test.ts. Good that the wrong expected output was caught and corrected.

Diagnostic pinning. checkers.test.ts is the right layer — these messages are the learner debugging UX for prescriptive grading. Surfacing parser errors in tier2.ts printCheck (matching the SQL track) is a nice consistency win.

Test depth. 323 tests locally (npm test, tsc --noEmit both green). The corpus round-trips at multiple widths, extreme-number rendering, and harness integration give confidence beyond happy-path literals.

Content/docs. Welcome rewrite around two capstone bookends reads cleanly. The Beyoncé rule nudge is on-brand for a course that grades against contracts. ROADMAP deferring comment-preserving formatting is honest about scope.

Nits (non-blocking)

  1. Tier ordering vs. "parallel fork" narrative. Docs say Tier 6 needs only Tier 3 and can be taken before Tiers 4–5, but registry.ts still lists it after the optimizer track. That's fine given the "soft ordering, no locks" policy in CURRICULUM.md, but a learner following "continue" linearly won't encounter the formatter until after the optimizer. Consider inserting tier6 between tier3 and tier4 in the registry if the fork UX matters — purely presentational, not a correctness issue.

  2. Learner chainPart vs. reference wrap. The capstone solution uses a simplified three-way level heuristic for split operands while format.ts reuses full prec()/wrap(). Covered cases align, but the starter could nudge learners toward reusing their prec/wrap helpers from sql-expr-print rather than a separate chain-specific rule — less duplication, fewer edge-case divergences.

  3. formatCheck newline collapse. Reparse for layout failures uses actual.replaceAll('\n', ' '), which is documented as desyncing when string literals contain raw newlines. There's a flat round-trip test for that case; a checker-diagnostic pin for multiline literals would close the loop if learners hit it in the wild.

  4. PR transparency. Good call noting the last two commits (checker pins + Beyoncé content) weren't panel-reviewed — those look low-risk from this pass, but the disclosure is appreciated.

Verification

  • Checked out claude/ast-parsing-learning-app-qli1yg
  • npm test: 323 passed
  • npm run typecheck: clean
  • CI: test-ast-lol, Workers build, format-check, and JS/TS analysis all green at review time (build-and-test / sanitizer jobs still pending)

Nice work — ship it.

The tokenizer reads newlines as whitespace and keeps them inside string
literals, so formatCheck's newline collapse was corrupting
newline-bearing literals — a layout mistake on such a query was
misdiagnosed as a different query. Reparse the output as-is; pinned.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7snNHsXg6msYZkBUHsViv

Copy link
Copy Markdown
Collaborator Author

Addressed the nits:

3 — newline collapse: fixed and pushed (b7b540b). The tokenizer already reads newlines as whitespace and preserves them inside string literals, so the replaceAll('\n', ' ') was unnecessary — and it was the bug: it corrupted newline-bearing literals, so a pure layout mistake on such a query was misdiagnosed as "reparses to a different query". formatCheck now reparses the output as-is; pinned by a new checker test that reproduced the misdiagnosis before the fix.

1 — tier ordering: keeping as is. Inserting tier 6 between tiers 3 and 4 would either display tiers as 0-1-2-3-6-4-5 or force renumbering the optimizer tiers. The fork is instead signposted at the decision point — the sql-select-parse statement and the welcome lesson both say the formatter track opens after Tier 3 — and a linear "continue" walk ending with the formatter is intentional: doing both is the full course.

2 — chainPart vs prec/wrap: keeping as is. The premise doesn't quite hold: prec and wrap are nested inside the provided printExpr prelude, so they aren't in scope for the learner's format — reusing them would mean re-implementing the precedence table the prelude already carries. chainPart's three-way check exists because only AND/OR tops can bind looser than a chain position, and the starter states that rule directly.

4 — thanks; noted.


Generated by Claude Code

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
iili b7b540b Commit Preview URL

Branch Preview URL
Aug 25 2026, 09:41 PM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ast-lol b7b540b Commit Preview URL

Branch Preview URL
Aug 25 2026, 09:42 PM

@aaylward
aaylward merged commit ec8198e into main Aug 25, 2026
22 checks passed
@aaylward
aaylward deleted the claude/ast-parsing-learning-app-qli1yg branch August 25, 2026 21:46
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