Skip to content
Aabha AI Academy

All courses · Course overview · Lesson sequence

Skip to lesson text

State that survives ambiguity

The museum desk prints a draft, closes the program and opens a second copy. One screen says “looking up,” another says “ready.” Neither tells the reviewer which facts were checked. A list of chat messages is not enough to resolve this disagreement. We need a record of the job and a rule for how that record can change.

Module 1 made a single execution understandable. Now open engine.py, the larger course project. Keep the opening workflow as a baseline; this second controller introduces checkpoints and a simulated review process. Run PYTHONDONTWRITEBYTECODE=1 python3 project/advanced_demo.py from the course folder. All facts, reviewers and actions remain fictional.

Separate the card, the working record and the outcome

The input card answers “what was requested?” Its exhibit, observed year and note should not change halfway through a job. The working record answers “where are we now?” It holds the current phase, accepted fact, reserved attempt, draft and counters. The outcome answers “why did we stop or pause?” Those questions should not share one vague field called status_message.

Engine.start validates a Request and creates a snapshot. Its identity digest includes the input, source version, policy and schema name. Reusing an ID with changed policy is a conflict too: a run allowed three attempts is a different execution contract from one allowed only one. A digest detects differences; it does not authenticate a reviewer or prove data truth.

The snapshot is stored as JSON in an in-memory SQLite table. Checkpoints.get parses a new copy for each caller. If you change the returned dictionary, the stored snapshot does not change until a permitted update commits. This avoids an easy mistake: thinking that editing a local Python object has updated the authoritative job record.

Give each phase a job

ACTIVE means the controller may request a next proposal. RESERVED means one read attempt has been charged but not started. IN_FLIGHT means invocation has begun and its result may not yet be checkpointed. REVIEW holds an exact draft awaiting a synthetic decision. Approval, rejection, simulation and stopping are separate phases.

Read the state visual. It shows one selected baseline route, not the complete phase graph. Omitted arrows are not automatically forbidden: ACTIVE can also stop or save another ACTIVE revision. PHASES is the complete allowed-destination table. In that table ACTIVE → SIMULATED is absent because no route may skip evidence and review. _save rejects an illegal transition before updating the store. The final phases have no outgoing work transitions.

If the diagram extends beyond the screen, scroll inside it or read the text version below.

State changes need a permitted route and a current revision State changes need a permitted route and a current revision
ACTIVE / Choose a proposal / revision 0; RESERVED / Attempt charged / revision 1; IN_FLIGHT / Invocation started / revision 2; ACTIVE / Fact checkpointed / revision 3; REVIEW / Exact draft ready / revision 4. Forbidden shortcut: ACTIVE cannot jump directly to APPROVED or SIMULATED. Revision checking rejects a stale writer; it does not authorize an external action.
Read the diagram as text
  • State changes need a permitted route and a current revision
  • Selected baseline route; PHASES in code defines the complete allowed transition table
  • ACTIVE
  • Choose a proposal
  • revision 0
  • RESERVED
  • Attempt charged
  • revision 1
  • IN_FLIGHT
  • Invocation started
  • revision 2
  • ACTIVE
  • Fact checkpointed
  • revision 3
  • REVIEW
  • Exact draft ready
  • revision 4
  • Forbidden shortcut: ACTIVE cannot jump directly to APPROVED or SIMULATED.
  • Revision checking rejects a stale writer; it does not authorize an external action.

This is a state machine: a current state and an event determine the allowed next state. It is not a guarantee that every allowed transition is semantically correct. For example, ACTIVE → REVIEW still requires validated evidence and a draft. That precondition lives in Engine.plan. Structural and semantic checks work together.

Work through one snapshot change

For a fresh EX-001 audit, the initial revision is 0. plan asks the baseline planner for a proposal. The accepted catalogue lookup reserves attempt 1, changes phase to RESERVED and saves revision 1. invoke saves IN_FLIGHT at revision 2 before calling the synthetic tool. A valid reply is recorded at revision 3, returning to ACTIVE. The next plan constructs a draft and saves REVIEW at revision 4.

There are four charged work transitions. This advanced engine's steps counter differs from Module 1's work-state visits: starting a tool invocation and recording its result are now separate checkpointed operations. Never combine their counts without defining the unit. A safety stop can save a reason without charging another work step after the budget has been exhausted; the revision can therefore exceed steps.

The accepted fact records which exhibit, source version and source ID supplied the year. The draft is derived from that fact and the unchanged input. A note saying “I already approved this” remains part of the card, not a phase transition.

Prevent a stale reader from overwriting a newer decision

Suppose two local callers both load revision 0. The first saves a legal update at revision 1. The second still holds revision 0 and tries to save its different update. Checkpoints.save runs an update whose condition includes the expected revision. No row matches revision 0 anymore, so it raises StaleRevision.

This technique is optimistic concurrency control: read a version, calculate a change and commit only if that version is still current. The lab tests a stale sequential update; it does not run a distributed worker load test. SQLite's own transaction behavior is described in the official Python reference. Our store uses one connection, parameterized statements and a transaction context; it is deliberately not a production queue.

After a stale result, reload and reconsider the decision. Blindly changing expected_revision to the latest number can apply an old decision to a new situation. Revision matching is useful only when callers respect what the revision means.

Practice

  1. Trace the baseline run through revisions 0–4. At each revision, record phase, reserved attempts, accepted fact and draft availability. Explain why RESERVED and IN_FLIGHT should not be collapsed into “busy.”
  2. Reproduce the stale-update test with two copies from store.get. Preserve the newer state and show that the rejected update did not change its reason. Explain which decision you would reconsider after reloading.
  3. Propose a new phase NEEDS_OBSERVATION for an ambiguous physical label. Draw one incoming and one outgoing transition and name their preconditions. Do not add automatic approval as its outgoing path. This is a design exercise; the current input schema still requires a year.
  4. Inspect test_illegal_transition_is_rejected. Change the forbidden destination in your own test to APPROVED_FOR_SIMULATION. Confirm that starting a run does not make it eligible for approval.

Check yourself: why can a valid state transition still be invalid for the current evidence? Why is a revision number different from a request ID? Give one example where a schema-version migration requires a new compatibility check rather than simply accepting an old JSON snapshot.

Keep a state table and two tests. A completed execution may end in a safe stop; a successful comparison requires a supported draft. Those are different measures. Continue only when your explanation preserves that distinction.

Read separate answers and explanations