Add the pipeline explorer and the prediction gate - #70
Merged
Conversation
The pipeline explorer shows six panes for one box of Python: tokens, tree, symbols, the instructions code generation produced, the same instructions after the optimizer, and the finished code object. They all change together when you type, which is the only way I have found to make it obvious that each stage throws away something the one before it had. Add a comment and watch it appear in the tokens and be gone by the tree. Two panes need _testinternalcapi. On a build without it those two say so and the other four still work. The prediction gate puts a question in front of an output. Option refuses to be built without a reason, including on the right answer, and revealing shows every option's reason rather than only the right one. The choice is written to the reader's own browser and goes nowhere else, which is also why the gate is the one widget with a job of its own in the front end. Both of them get their paint, wire and caret handling from static/_common.js, which Widget.esm concatenates onto each widget module. Concatenation rather than an import, because an import is a second network request from inside a notebook output cell and that does not work everywhere a lesson is rendered. strings.text now fills in plural endings from the count, so a pane says "1 scope" and "2 scopes" without every caller doing the arithmetic. The last pane prints arg when argrepr is empty. LOAD_SMALL_INT keeps 42 in arg with an empty argrepr, and 42 is the number this widget exists to show.
This was referenced Aug 29, 2026
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.
Closes the last two rows of #14.
The pipeline explorer
Six panes for one box of Python, all updating together: the token stream, the tree, the symbol table, the instructions code generation produced, the same instructions after the optimizer, and the finished code object.
They are on screen together because the point of the pipeline is that each stage throws away something the one before it had, and that is very hard to get across one paragraph at a time. A reader who has just finished the paragraph about the parser has forgotten what the tokens looked like. With six panes you add a comment to the end of the line and watch it sit in the tokens and be gone by the tree, or leave
6 * 7alone and watch aBINARY_OPcome out of code generation and be a plainLOAD_SMALL_INT 42by the time there is a code object.Code generation and the optimizer need
_testinternalcapi. On a build without it those two panes say so and the other four still work, since a widget that shows nothing because one hook is missing teaches nobody anything about the four stages that would have run fine. There is a test that monkeypatchescompiler.stagesinto raisingUnavailableand checks the other four still draw.Output is cut at forty lines per pane and the cut is counted rather than hidden.
The prediction gate
A question, some options, and the answer behind a gate.
Optionwill not be built without awhy, including on the right answer. A wrong option is only worth offering if somebody could plausibly pick it, and if somebody could plausibly pick it then the reason it is wrong is worth teaching. Revealing shows every option's explanation, not only the one that was picked and not only the right one, so a reader who guessed correctly still finds out why the option they nearly picked was wrong.The choice is written to the reader's own browser with
localStorageand goes nowhere else. Nothing is scored and nothing is uploaded. A reader who thinks a wrong answer is being logged stops guessing and starts reading ahead, and guessing is the whole mechanism. The storage exists because notebooks get re-run and being asked six questions you have already answered is a good way to stop answering them.The static rendering gates too, with
<details>and<summary>: no JavaScript, keyboard reachable, and it works in a notebook rendered on GitHub. The options are a numbered list rather than disabled buttons, because a disabled button says the thing it does is unavailable and here the thing is just being done in the reader's head.The shared front end
Three widgets meant three copies of paint, wire and put the caret back, so that moved to
static/_common.js, whichWidget.esmconcatenates onto each widget module. Concatenation rather than an import: an import is a second network request from inside a notebook output cell, which works in Jupyter and does not reliably work everywhere else a lesson gets rendered.Focus restoration is generic.
HANDLES = ["role", "flag", "option"]is the list of data attributes that mark something a reader can put the keyboard on, so_common.jscan find the same control again in markup it has never seen. Without it a source box sends you to the end of the line a quarter of a second after you stop typing.Two smaller things
strings.textnow fills in plural endings from thecountvalue, so a template can write{count} scope{s}and get "1 scope" and "2 scopes". "1 scopes" was on screen in the first lesson, and that is the kind of thing a reader notices and then stops trusting.The code object pane prints
argwhenargrepris empty.LOAD_SMALL_INTkeeps 42 inargwith an emptyargrepr, so printing onlyargreprdropped the one number the constant folding demonstration is about.Checks
just checkis green. The widget tests are 138 now, and the live path was run under--extra live: typing into the pipeline redraws all six panes, and picking an option on the gate reveals the explanations and the verdict.