Ten versioned contracts carry data between the layers, and repos may depend on nothing else. The two you will touch first are EvidenceLayer contract for detector output (direction; as built: Finding finding.json 1.2.0), from L3 to L4, and PrescriptionWhat to do, why, who, check plan (direction; as built: prescription.json 1.0.0 / card-proposal), from L4 to L5. All of them travel inside the Envelope header.

The ten contracts and how data moves between layers

Action and value: L5 and the writer

Decision: L4

State and evidence: L2 and L3

L3 to L4

L4 to L5, becomes a card

same-condition wins

Lot and genealogy

PlantState

Evidence

Prescription

ClosureState

WriteRequest

Action

ValueRecord

AutonomyPolicy

Envelope: header on every message, with episode_id

How to read it.

  1. Read top to bottom: state and evidence, then the decision, then what happened and what it was worth.
  2. Prescription is the payload L5 receives. ClosureState is the lifecycle of the card L5 makes from it. A WriteRequest needs both a Prescription and a granted AutonomyPolicy; without the policy there is no write.
  3. The dotted return arrow is how autonomy is earned: ValueRecords showing same-condition wins feed the policy.

Build now: Evidence, Prescription and ClosureState for the slow loop. Later: PlantState, WriteRequest and AutonomyPolicy for the fast loop.

View Mermaid source
flowchart TB
    %% house-style: tour-contracts
    subgraph state["State and evidence: L2 and L3"]
        direction LR
        lot["Lot and genealogy"]
        ps["PlantState"]
        evi["Evidence"]
    end
    subgraph decide["Decision: L4"]
        direction LR
        rx["Prescription"]
    end
    subgraph act["Action and value: L5 and the writer"]
        direction LR
        cs["ClosureState"]
        wr["WriteRequest"]
        a["Action"]
        vr["ValueRecord"]
    end
    pol{{"AutonomyPolicy"}}
    env["Envelope: header on every message, with episode_id"]
    lot --> evi
    ps --> evi
    evi -- "L3 to L4" --> rx
    rx -- "L4 to L5, becomes a card" --> cs
    rx --> wr
    pol --> wr
    cs --> a
    wr --> a
    a --> vr
    vr -. "same-condition wins" .-> pol

    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 pol,env govc

The ten, briefly#

ContractCarriesProduced byConsumed by
PlantStateEstimated state of an asset, with uncertaintyL3 estimators, Plant Box twinL4, writer, safety filter
EvidenceA typed claim and its supportL3L4, agents, ledger
PrescriptionWhat to do, why, by whom, how it will be checkedL4L5 cards, safety filter
ActionWhat actually happened, by a person or the writerL5, writerLedger
ValueRecordOne ledger row per action and KPIL5 verificationCustomer, registry, autonomy
AutonomyPolicyA grant of authorityA person at the plant, through L5Safety filter, writer
Lot and genealogyWhich lots and parts passed which assets, with link confidenceL2 linkersL3, ledger
WriteRequestA request to change one set pointL4 or a personSafety filter, writer
ClosureStateThe card lifecycle, 11 statesL5 card machineL6, analytics
EnvelopeThe header around all of themEvery producerEvery consumer

What exists today#

Three of these have older ancestors in the code, and you will meet them. The L3 to L4 hop runs on FindingAs-built L3 detector output admitted to L4 (finding.json 1.2.0) 1.2.0, which forces every finding to carry a kWh and rupee estimate even when the loss is scrap. Evidence replaces it with a value vector. The L4 to L5 hop runs on the card proposal next to prescription.json 1.0.0, and L5 reads both. closure/action-intent.json is retired in favour of WriteRequestPlant Box write path request (direction; closure/action-intent.json retired) for the request and Action for the record.

Two vocabularies for how sure we are#

Evidence and ValueRecord carry a contract tier: measured, confirmed, modeled or unknown. Each quantity inside carries an evidence label: Measured, Estimated, Assumed or Unknown, plus calibrated or uncalibrated (D13, decided). A claim takes the weakest label among the quantities it rests on, and only a passed check raises it to confirmed. Confirmed is still not verified; that word is kept for counterfactual M&V that passed its checks.

Versions#

All ten are drafted in SE as 0.x, marked experimental (D2). While a contract is 0.x, a minor bump may break, so consumers pin the minor version. The first plant that uses a contract in production moves it to 1.0.0; after that, removing or renaming a field is a major change with a migration note. Consumers ignore unknown fields and reject messages missing required ones at the seam, never filling in defaults.

Go deeper: data contracts · Evidence and the tier mapping · versioning

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

Diagram

100%

Search the architecture