A detection in L3 becomes EvidenceLayer contract for detector output (direction; as built: Finding finding.json 1.2.0), L4 turns Evidence into at most one PrescriptionWhat to do, why, who, check plan (direction; as built: prescription.json 1.0.0 / card-proposal) draft, and L5 turns that draft into a live card assigned to a person on shift. Each hop runs on a named contract, and any kWh, kilogram or rupee figure on the card must resolve to an Evidence record.

How a finding becomes a decision card

L5 closure-verification

L4 DecisionRuntime

L3 intelligence-core

Evidence (as built: Finding 1.2.0)

Prescription (as built: card proposal)

Engines on L2 telemetry

Dual lane: only status=emitted, delivery=l4 leaves

Decision case and situation model

Prescription draft: options, owner role, autonomy level, M&V plan

Withhold or abstain, with a trace

Predictive safety filter, for anything that implies action

Live card: role resolved to a person

One sender, with message budgets

Verification pack checks L2 telemetry

Person on shift: accept, edit, reject or defer

ValueRecord in the ledger, then learning

How to read it.

  1. Arrow labels are the contracts. Where the code still uses an older schema, it is named in brackets.
  2. Yellow boxes are gates. The dual lane in L3 keeps lab output from reaching L4, and the safety filter checks every proposal that implies action.
  3. Withholding is a normal result. L4 records why it did not send a card.

Build now: this whole path at AL1. Later: the same path feeding WriteRequests once a plant grants AL2.

View Mermaid source
flowchart TB
    %% house-style: tour-card-path
    subgraph l3["L3 intelligence-core"]
        direction LR
        eng["Engines on L2 telemetry"] --> lane{{"Dual lane: only status=emitted, delivery=l4 leaves"}}
    end
    subgraph l4["L4 DecisionRuntime"]
        direction LR
        case["Decision case and situation model"] --> rx["Prescription draft: options, owner role, autonomy level, M&V plan"]
        case --> wh["Withhold or abstain, with a trace"]
    end
    saf{{"Predictive safety filter, for anything that implies action"}}
    subgraph l5["L5 closure-verification"]
        direction LR
        card["Live card: role resolved to a person"] --> send["One sender, with message budgets"]
        send --> verify["Verification pack checks L2 telemetry"]
    end
    person["Person on shift: accept, edit, reject or defer"]
    led(["ValueRecord in the ledger, then learning"])
    lane -- "Evidence (as built: Finding 1.2.0)" --> case
    rx --> saf -- "Prescription (as built: card proposal)" --> card
    send --> person --> verify
    verify --> led

    classDef govc fill:#fff4d6,stroke:#c99a2e,color:#000
    classDef agentc fill:#e8f0ff,stroke:#5b7bd5,color:#000
    classDef loopc fill:#eef7ee,stroke:#4f9a4f,color:#000
    class lane,saf govc
    class person agentc
    class led loopc

In L3: detect and label#

L3 engines run on schedule over L2 telemetry and emit findings. Today the output is FindingAs-built L3 detector output admitted to L4 (finding.json 1.2.0) 1.2.0, an energy-centric schema that requires a monthly kWh and rupee estimate. The direction is the Evidence contract: a typed claim with its support, a contract tier (measured, confirmed, modeled or unknown) and a value vector that can carry scrap, throughput or quality risk as well as energy. Only findings with status=emitted and delivery=l4 leave L3. Lab results never promote themselves.

The method router decides how far up the seven-job chain the evidence allows. If the inputs are Assumed or Unknown, or a model has not passed its calibration gate, the router abstains, and that is recorded as a result rather than an error.

In L4: decide, or decline to#

DecisionRuntime takes evidence into a plant work queueDurable per-plant scheduler for Findings, sweeps, Ask, builds a decision case against the situation model, and produces at most one owned Prescription draft for the condition. The draft carries what, why, who, when, the expected impact and the M&V plan. It lists options with predicted outcomes, and hold is always one of them. It also states the autonomy level it would need and an expiry time.

L4 may also withhold, supersede an earlier proposal, or abstain. Each of those leaves a decision trace, so "why didn't we get a card?" has an answer. L4 never assigns the final person and never sends a message.

In L5: a person, a channel, a closure#

L5 resolves the owner role to a person on shift and sends the card through one sender. That sender carries budgets and suppression (D16), so a plant does not get flooded. The design target is a card within two minutes of the prescription at p95. The person accepts, edits, rejects or defers, with a reason.

The card then moves through ClosureStateEleven code states on the live card (direction; as built: stamped_l5_domain/cards/states.py), the 11 states the L5 machine already runs. A verification pack checks the change in L2 telemetry. Note the naming trap: closed_verified in code means the change was seen in telemetry, which is ops_confirmed in ledger terms, not a counterfactual verification. The outcome lands as a ValueRecord per KPI, and L6 shows the queue, the card and its history.

Go deeper: proposal and live card · L4 decision runtime · L5 closure

Page history: last 1 change
  1. 2026-10-08 docs(technical): architecture tour and page summaries 79c8ea3

Diagram

100%

Search the architecture