A picture tutorial

Handrail in five pictures

A model works a task out once. After that the task is replayed by plain code, with no model involved, and help is called only when a check fails.

Figure 1. Authoring: the task is worked out once
A chef tastes a dish and writes a recipe card
Picture 1

The chef writes the recipe once

The head chef is expensive and improvises. You do not want improvising every night. So the chef cooks the dish one time and writes a recipe card while doing it.

In Handrail the chef is the model. The recipe card is a capability: a list of steps, and beside every step a sticker saying how risky it is.

Reading the picture

  1. Chef is the model. Expensive, improvises, used one time.
  2. Recipe card is the capability. Steps written down as data.
  3. The pot is the live application the task is done in.
  4. Stack of cards is the store of capabilities, each reviewed before use.

Diagram 1. From one run to one card

One model-driven run becomes one reviewable card.

The run, as the model did it

Type the member numbermodel
Open the hold formmodel
Choose the reasonmodel
Press Post Holdmodel
Read the confirmationmodel

The capability, stored as data

enter_memberstage
open_holdnavigate
choose_reasonstage
post_holdcommit
read_resultread

read only looking. navigate changing screen. stage pencil, can be erased. commit ink, real and hard to undo. A card with one step missing its sticker is refused.

What is happening, in order

  1. The model performs a step in the live application.
  2. The compiler writes that step onto the card and gives it a risk sticker.
  3. This repeats for all five steps. The card is then reviewed by a person before it may be used.
Figure 2. Replay: the same task, every time, no model
A line cook follows a recipe card and plates identical dishes while the chef's hat hangs unused
Picture 2

The line cook follows the card

Every night after that, a line cook follows the card exactly. The chef's hat stays on the hook. Same dish, every plate.

In Handrail the line cook is the replay engine. For each step it does the same six small things in the same order, and it never asks a model.

Reading the picture

  1. Hat on the hook is the model is not in the room. llm_calls stays 0.
  2. Card on the clip is the approved capability being followed.
  3. Line cook is the replay engine. Follows the card exactly.
  4. Identical plates is the same typed result on every run.

Diagram 2. The six checkpoints every step passes

Each step passes six checkpoints. The square is a ledger entry, made only for steps that change something.

StepRight screen?Find controlLedgerActSettleExpected screen?
result SUCCESS confirmation HX-829120 llm_calls 0 classifier_calls 0

What is happening, in order

  1. Right screen? The page must match the screen the step expects.
  2. Find control. Walk the ladder of locators until exactly one control matches.
  3. Ledger. Steps that change something are written down first. Read and navigate steps skip this.
  4. Act. Type, choose or press.
  5. Settle. Wait until the page is ready for the next step.
  6. Expected screen? Confirm the application ended up where the card says it should.
Figure 3. The surface: one waiter between kitchen and dining room
A waiter stands in a doorway between a kitchen and a dining room holding a menu
Picture 3

The waiter and the menu

The kitchen never walks into the dining room. It talks to a waiter, and the waiter accepts six requests only. A browser, a green-screen terminal and a Mac app are three dining rooms, each with its own waiter.

The waiter is the surface. What it hands back is a numbered menu of things that are legal right now. A model can only say a number.

openobserveresolveactevaluateevidence

Reading the picture

  1. Kitchen staff is the engine. It never touches the application directly.
  2. Doorway is the Surface protocol. Only six requests pass through.
  3. Waiter is a surface: browser, terminal or Mac app.
  4. Menu card is the operations table, a numbered list of legal actions.
  5. Dining room is the real application, for example the mock bank.

Diagram 3. How a page becomes a numbered menu

The sign-on page of the mock bank, turned into a menu.

What is on the page

Operator ID fieldtextbox
Password fieldtextbox
Branch listcombobox
Greyed-out buttondisabled, left off
Logonot a control, left off
F5=Sign Onbutton

The menu a model sees

1: set_value textbox 'Operator ID'
2: read textbox 'Operator ID'
3: set_value textbox 'Password'
4: read textbox 'Password'
5: select combobox 'Branch'
6: read combobox 'Branch'
7: invoke button 'F5=Sign On'

The worst a confused model can do is pick a wrong row from a list of real, legal actions. Nothing it says ever becomes a selector, a coordinate or code.

What is happening, in order

  1. The waiter lists every element it finds on the page.
  2. Disabled controls and things that are not controls are left off.
  3. Each remaining control gets one row per legal action, numbered from 1.
  4. A model answers with a number. The engine maps the number back to the control.
Figure 4. The journal: write it down before you do it
A cashier writes in a ledger before touching a stack of banknotes
Picture 4

The cashier writes before paying

A cashier writes "paying out" in the ledger before handing over cash, then "paid" after. If the lights go out in between, the ledger shows a payment in doubt. Nobody pays a second time on a guess.

That ledger is the journal. A commit step written dispatched and never observed is never pressed again. This is the rule the whole project is built around.

Reading the picture

  1. Cashier is the engine, about to run a step that changes something.
  2. Pen on paper is writes "dispatched" before the action.
  3. Ledger is the journal file on disk. Lines are never erased.
  4. Cash is the commit step, such as pressing Post Hold.

Diagram 4. A crash in the middle of a commit

Try to make the bank post the hold twice.

Journal, on disk

At the bank

0times Post Hold was pressed
0runs started

What is happening, in order

  1. The engine writes "dispatched post_hold" to disk.
  2. Only then does it press Post Hold. The click counter goes up.
  3. In a clean run it then writes "observed post_hold".
  4. If the run dies before that line, the step is in doubt. Every later run refuses to press again.
Figure 5. Escalation: three steps up, one handrail
Three steps with a brass handrail: a desk bell, a small robot with a lantern, and a person reaching out a hand
Picture 5

The stairs, and the handrail

When a check fails the line cook does not improvise. There are three steps to climb, cheapest first: ring the bell, ask the helper, call a person.

Whoever answers only proposes. The engine checks the answer itself before acting on it. That check is the handrail.

Reading the picture

  1. Handrail is the engine re-checks every answer before acting on it.
  2. Desk bell is step 1. A small classifier answers multiple choice.
  3. Robot with lantern is step 2. A bounded model looks around. No commits.
  4. Person is step 3. A human takes over the live session.

Diagram 5. Who gets asked, and in what order

Pick what went wrong on the screen.

Step 3. A personTakes over the same live session. Every action recorded.
Step 2. A bounded model excursionMay look around and navigate. Commit is denied. Must end on a screen the card already names.
Step 1. A small classifierMultiple choice among screens the card already declares. Laya on your machine, or Jev hosted.
Ground floor. Plain codeExact structural check. The ordinary path.
classifier_calls 0 llm_calls 0

What is happening, in order

  1. Plain code checks the screen. Almost every run ends here.
  2. If that fails, a small classifier picks among screens the card already names.
  3. If that fails, a model may look around, but may not commit.
  4. If that fails, a person takes over. At every step the engine verifies the proposal before acting.
Where each picture lives

Code map

PictureIdeaFileState
Recipe cardCapability with effect stickersschema/capability.py, schema/effects.pybuilt
Line cookReplay enginereplay/engine.pybuilt
WaiterSurface, six verbssurface/base.pybuilt
MenuOperations tablesurface/browser/operations.pybuilt
Directions to a houseLocator ladder, probed for uniquenesssurface/browser/locators.pybuilt
Checking the faceStructural fingerprintsurface/browser/fingerprint.pybuilt
Cashier's ledgerWrite-ahead journalreplay/journal.pybuilt
Flight recorderHash-chained evidence logkernel/evidence.pybuilt
Real dining roomPlaywright behind the six verbssurface/browser/surface.pynext
ChefAuthoring loop and compilerauthor/, compile/milestone 3
Bell on step 1Classifier port, Laya and Jevescalate/milestone 5
Helper and personBridge and human takeoverescalate/bridge.py, serve/console.pymilestone 6