[speckl#37.5] B1: Stop silently inventing let/forall stubs in TS generator #43
Labels
No labels
blocked
bug
design
docs
engineering
feature
infra
priority:high
priority:low
priority:medium
question
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: sscoble/speckl#43
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The TypeScript generator in
compiler/src/generators/typescript-state-machine.ts:482silently invents stubs whenever a referenced identifier is not in the parser's AST. Specifically, it emitsconst xxx: any = {} as any; // FIXME: parser dropped let/foralland tags the source line. The root cause is thatparser.ts'sparseActionBlockMultilinedoes not emitletorforallAST nodes, so the generator fakes them.This affects 16/16 examples. The output is semantically wrong: state mutations are dropped.
Scope
Two acceptable resolutions (pick one and document which):
parser.tsparseActionBlockMultilineto emitletandforallAST nodes. Update the generator'semitAction()to consume them. This benefits rust/z3/wasm generators automatically.If you choose option 1, also update the AST type definitions in
parser.ts(or wherever the node types live). If you choose option 2, no parser change is needed.Out of scope
nix buildornixos-rebuild. Build only the compiler.Acceptance Criteria
// FIXME: parser dropped let/forallmarkers in the emitted TSgrep -r 'FIXME: parser dropped' compiler/dist/ 2>/dev/null | wc -lreturns 0 (or the count of such markers is documented in the comment with reasoning)tsc --noEmit --target es2020Why this exists
Triage on #39 found 6 bugs. B1 touches the most examples (16/16) and is the root cause of the most FIXME markers in the output. Needs parser + generator coordination; flagged as the high-risk child of this decomposition.
Depends on
None
Blocks
None
sscoble referenced this issue2026-06-03 01:41:02 +00:00
Closing — re-diagnosed from real code, premise was wrong
Scott directive 2026-06-02 ~19:00 PT: if the ticket framing is wrong, re-diagnose. I read
parser.tsandtypescript-state-machine.tsto verify, and the premise was wrong on three counts:letAST nodes.parser.ts:136declares{ type: 'let'; name: string; expr: string }in the AST types, andparser.ts:1024actually emits them viaparseActionBlockMultiline. The TS generator already hascase 'let':attypescript-state-machine.ts:374that produces a realconst/letdeclaration.forallis not an action-block AST node at all. It only appears inconstraintexpression parsing (parser.ts:274, 1103). The framing ofparser drops let/forallis a category error.typescript-state-machine.ts:456-482runs a preamble heuristic AFTER the structured emit. It scans the rendered body with a regex, finds any identifier not in the known set (state vars, locals, reserved words,let/const/vardeclared in body), and silently inventsconst x: any = {}for each one. The misleading comment// FIXME: parser dropped let/forallwas wrong from day one.Real symptom (Raft.ts
StartElection)xxxis the residual of the heuristic matching itself in a regex;termis a realletbinding the structured emit handled correctly (line 391:const newTerm = ...) but the heuristic is re-declaring it as a bogus any stub BEFORE the real code, which would shadow orredeclarationerror iftscwere run withnoEmitOnError: true. 16/16 examples have this noise.Plus a separate init-block bug (out of scope for the new ticket)
The Raft.ts constructor contains the raw forall text rendered as a string literal:
this.servers = {"s1", "s2", ...} forall s in servers: serverState[s] == ...;This is a different bug — the init-block emit is not iterating the state-value enum correctly, or the parser is producing a stringly-typed init body. This is in the same file region but is a different root cause. NOT in scope for the new ticket. Filed separately as a follow-up if needed.What I'm doing
Closing this ticket. Opening a new ticket that:
// FIXME: parser droppedmarkers, verifytsc --noEmitstill passes on every example that was previously clean)forallas out of scope (it's a constraint-only keyword, never was an action-block AST node)Tracking the init-block raw-string bug as a follow-up note in the new ticket's
## Follow-upsection.