feat(blocks): a block is a thing you can run, ask about, and copy - #74
Merged
Merged
Conversation
Drilling into a block changed what you could see and nothing about what you could do. Pressing play inside CPU/ALU/add ran the CPU, and if control never reached the adder on that word you learned nothing about the adder. StateMate was handed all three thousand states while eight were on screen. The clipboard was the one door left unlocked. - js/run-scope.js: a run boundary. "Run this block on its own" and "run the whole machine but stop when it enters this block" are one test on one step, enforced by the player's cursor rather than by twenty-five simulators. runStartId() is the one declaration the machine layer reads; App.startId stays the machine's start. - The trace log is its own card, and the rest of the run is reachable from it: the elided line is a button, and an expansion lasts only while the cursor is still. - scopedSource(): inside a block, the subject is that block plus its boundary. compileSpec takes a scope, so a scoped edit leaves the machine around the block standing rather than deleting it silently. - Ports describe the wiring, not the record: every crossing gets a tab, an undeclared one in orange. A note lives on one level (note.scope). - Copy/cut/paste across machines asks whether the transition shape is one this machine reads, and whether it can have blocks at all. - The profile weighs the level you are standing in, at every depth: a large machine hidden inside eight boxes is still a large machine. Tests: block-run, block-crossings, block-clipboard, blocks-statemate, statemate-scope, trace-log, note-scope. 1946 pass.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Drilling into a block changed what you could see and nothing about what you could do. Pressing play inside
CPU/ALU/addran the CPU — and if control never reached the adder on that word, you learned nothing about the adder. StateMate was handed all three thousand states while eight were on screen. The clipboard was the one door onto a canvas that never asked what machine it was landing on.Running one block
js/run-scope.js. "Run this block on its own" and "run the whole machine but stop when it reaches this block" look like two features and are one — a run boundary, answered by the same test on the same step.stepAtwas already the bounds check, sostepFwd,stepToEndand the autoplay tick needed nothing taught about it. On a streaming run the steps past the boundary are never computed.maxTmSteps, exactly the frozen tab lazy execution exists to prevent.runStartId()is the one declaration the machine layer reads.App.startIdstays the machine's start: it draws the start arrow, it is q₀ in the formal definition, it is what every exporter writes. The test asserts against the source thatApp.startIdappears nowhere underjs/machines/.decideMachine()lifts the override, so the Test Words table, the Language panel and StateMate's verification all still answer about the machine.The trace log
Its own card, and the rest of the run reachable from it. "The rest is gone" is a different claim from "the rest is not drawn" — the elided line is now a button, and an expansion lasts only while the cursor is still, which is what keeps the quadratic from coming back.
A scoped turn
Saying where the reader is standing was half an answer:
machineToSpec()still sent every state at every depth.scopedSource()cuts the machine to one block and everything under it.spec.scopestates the entry, exits and crossings as prose beside the machine —validateSpecnever reads it back.keepOutsideScope()bounds the diff.What else a block now survives
--orange— a finding, not a fault.note.scope. A note lives on one level. Absent means the top, so no serializer changed and there is no migration.transitionShapeRefusalreadstransitionFields— the app's one declaration of what a transition carries — so DFA/NFA/ε-NFA and the four tape machines still move freely, and an MTM's read tuple does not land on a TM.Testing
npm test— 1946 pass, 0 fail. Seven new files:block-run,block-crossings,block-clipboard,blocks-statemate,statemate-scope,trace-log,note-scope.The invariant everything rests on: a block run is step-for-step the whole-machine run from that point, driven through
stepFwdrather thanstepToEnd— which is what let the last one ship.🤖 Generated with Claude Code