Status
as-built snapshot, with direction marked
Layers
all
Source
architecture section 3, section 3.5, section 5

These are the system views (SYS-00 to SYS-09) and the stamped-external views (EXT-01 to EXT-05), redrawn in house style. They replace the archify HTML set, which is now archived. Built and partial labels follow the archify pins (stamped-external a4c91bc; L1E 332ec0d, L1C d63ee46, L2 6c8d454, L3C 5c74aee, L4 708b1f4, L5 88fe58f, L6 82df09e). For the current as-built state read l4/30-as-built.md and l4/24-architecture-gaps.md; for the target shape read the architecture.

No integration is live at any customer plant. Verified savings to date: ₹0.

Legend for every view: yellow is governance or a contract gate, blue is a person or an agent, green is a return path or loop. A dotted arrow is a hop that is designed or deferred, not built.


SYS-00 End-to-end map#

SYS-00 · End-to-end map

Stamped cloud: repo layers L1 to L6

MQTT stamped/v1

envelope ingest

query-api reads

Finding 1.2.0

proposal (today)

card proposal (designed, not live)

closure and ledger

L0 Plant: OT meters (partial)

L1 Connect: edge and cloud (partial)

L2 Store: TimescaleDB (built)

L3 Findings: on-demand runs (partial)

L4 Decisions: runtime built, output stubbed

L5 Closure: no /cards ingest (partial)

L6 Control room: polls L5 (partial)

StubCardSink: local only, emit off

Contracts SSOT: stamped-external

How to read it.

  1. Data in: L1 wraps a plant reading in an envelope and L2 ingests it; contracts define every hop.
  2. Detect: L3 reads L2 and emits Finding 1.2.0; the hot path uses suppression then lane, not eval gates.
  3. Decide: the L4 runtime is built and runs, but its proposals land in StubCardSink; the hop to an L5 live card is missing (L5-G4), so no decision reaches an owner yet.
  4. Close: L5 workflow and M&V write the ledger; L6 polls L5 (the webhook is designed).

Build now: the L4 to L5 card hop. Later: the conceptual-layer view in architecture section 3.

View Mermaid source
flowchart TB
    %% house-style: sys-00-end-to-end
    l0["L0 Plant: OT meters (partial)"]
    subgraph cloud["Stamped cloud: repo layers L1 to L6"]
        direction LR
        l1["L1 Connect: edge and cloud (partial)"]
        l2["L2 Store: TimescaleDB (built)"]
        l3["L3 Findings: on-demand runs (partial)"]
        l4["L4 Decisions: runtime built, output stubbed"]
        l5["L5 Closure: no /cards ingest (partial)"]
        l6["L6 Control room: polls L5 (partial)"]
    end
    sink["StubCardSink: local only, emit off"]
    con{{"Contracts SSOT: stamped-external"}}
    l0 -->|"MQTT stamped/v1"| l1 -->|"envelope ingest"| l2 -->|"query-api reads"| l3 -->|"Finding 1.2.0"| l4
    l4 -->|"proposal (today)"| sink
    l4 -.->|"card proposal (designed, not live)"| l5
    l5 -->|"closure and ledger"| l6
    con -.-> l2 & l4

    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 con govc

SYS-01 Contract and boundary map#

SYS-01 · Contract and boundary map

L3 to L6

L1 to L2

L1 publish (partial)

envelope (built)

L2 /v1/ingest (built)

L3 core (partial)

Finding 1.2.0 (built)

L4 runtime (built, stub out)

card proposal (designed, no L5)

L5 workflow (partial)

L6 BFF (polls)

How to read it.

  1. Envelope plus telemetry, context and bill schemas cross into L2 ingest.
  2. Finding 1.2.0 and the l3-methods OpenAPI carry L3 output to L4; the card proposal into L5 is designed only.
  3. Transport is HTTP (OpenAPI) and MQTT (TOPICS.md); there is no cross-layer database; L5 to L6 HMAC push is designed and L6 polls /v1/events today.

Build now: the card proposal hop. Later: the ten contracts of architecture section 5.

View Mermaid source
flowchart TB
    %% house-style: sys-01-contract-boundary
    subgraph in["L1 to L2"]
        direction LR
        l1["L1 publish (partial)"] --> env{{"envelope (built)"}} --> l2["L2 /v1/ingest (built)"]
    end
    subgraph dec["L3 to L6"]
        direction LR
        l3["L3 core (partial)"] --> fin{{"Finding 1.2.0 (built)"}} --> l4["L4 runtime (built, stub out)"]
        l4 -.-> card{{"card proposal (designed, no L5)"}} -.-> l5["L5 workflow (partial)"] --> l6["L6 BFF (polls)"]
    end
    l2 --> l3

    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 env,fin,card govc

SYS-02 Data batch to decision#

SYS-02 · Data batch to decision

Detection and decision

Edge to cloud

publish batch, MQTT QoS1

relay ingest

Finding out

relay_once to inbox (CLI)

write proposal

edge-agent: PLC poll, SQLite buffer (built)

L1 cloud (partial)

L2 ingest

L3 detect run (partial)

L3 outbox relay (built)

L4: inbox, PlantWorkQueue, worker, stages, DecisionTrace

StubCardSink (emit off)

↩ backlog drains after an outage; unsent rows not expired in code

How to read it.

  1. The edge agent buffers in SQLite until the MQTT QoS1 ack, then marks rows sent.
  2. An L5 perception call or the CLI starts a detection run; the scheduler is built but not deployed.
  3. The relay into the L4 inbox is a CLI drain; default compose does not start the relay worker.

Build now: a deployed relay worker and the L5 card hop. Later: the fast-loop path in fast-loop/.

View Mermaid source
flowchart TB
    %% house-style: sys-02-batch-runtime
    subgraph edge["Edge to cloud"]
        direction LR
        ea["edge-agent: PLC poll, SQLite buffer (built)"] -->|"publish batch, MQTT QoS1"| c1["L1 cloud (partial)"] -->|"relay ingest"| s2["L2 ingest"]
    end
    subgraph det["Detection and decision"]
        direction LR
        d3["L3 detect run (partial)"] -->|"Finding out"| ob["L3 outbox relay (built)"]
        ob -.->|"relay_once to inbox (CLI)"| r4["L4: inbox, PlantWorkQueue, worker, stages, DecisionTrace"]
        r4 -->|"write proposal"| sk["StubCardSink (emit off)"]
    end
    s2 --> d3
    back(["↩ backlog drains after an outage; unsent rows not expired in code"])
    ea --- back

    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 back loopc

SYS-03 Ask question and discovery request#

SYS-03 · Ask question and discovery request

L4

L6

ask_sweep, deduped per asset

POST /v1/chat stream

Operator

L6 web: SSE (partial)

L6 BFF: POST /analyst stream

AskHub: gate, route (SSE v2)

ReAct loop over 35 read tools, per-claim verifier

Work queue

Runtime worker: sweep flags

↩ verified claims, then token, citation, done, back to the UI

How to read it.

  1. Ask is live and read-only; it never emits a card.
  2. A discovery request is queued as ask_sweep and run by the worker; it finds nothing until Ask sends scanner_context (L4-G11).
  3. Open gaps: Ask reads cards and PSM from fixture ports (L4-G12); Ask and the runtime keep separate hard-stop lists (L4-G13); API and worker must share L4_DATABASE_URL; memory is off unless L4_MEMORY=hindsight.

Build now: scanner_context and one hard-stop list. Later: Ask over the Layer 2 store per architecture section 3.

View Mermaid source
flowchart TB
    %% house-style: sys-03-ask-runtime
    op(["Operator"])
    subgraph l6["L6"]
        direction LR
        web["L6 web: SSE (partial)"] --> bff["L6 BFF: POST /analyst stream"]
    end
    subgraph l4["L4"]
        direction LR
        hub{{"AskHub: gate, route (SSE v2)"}} --> loop["ReAct loop over 35 read tools, per-claim verifier"]
        loop -->|"ask_sweep, deduped per asset"| q["Work queue"] --> w["Runtime worker: sweep flags"]
    end
    op --> web
    bff -->|"POST /v1/chat stream"| hub
    ret(["↩ verified claims, then token, citation, done, back to the UI"])
    loop --> ret --> web

    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 hub govc
    class op,loop agentc
    class ret loopc

SYS-04 Card closure and M&V#

SYS-04 · Card closure and M&V

Clearance

Owner acts

workflow event

read window (fixture default)

ops_confirmed

mark done

Owner

L6 UX: polls every 30 s

L5 API: ack, done

L5 worker: clearance_poll

L2 evidence (partial)

Ledger append: not bill-verified

↩ status poll back to L6

How to read it.

  1. The owner marks a card done in L6; L5 records the workflow event.
  2. The L5 worker reads L2 evidence (fixture by default) and appends a ledger row on ops_confirmed only.
  3. The ledger is not bill-verified; ADR-014 keeps the bill path deferred.

Build now: real L2 evidence reads. Later: ValueRecord and the 11 ClosureState values (architecture section 5).

View Mermaid source
flowchart TB
    %% house-style: sys-04-closure-mv
    own(["Owner"])
    subgraph act["Owner acts"]
        direction LR
        ux["L6 UX: polls every 30 s"] -->|"workflow event"| api["L5 API: ack, done"]
    end
    subgraph clr["Clearance"]
        direction LR
        wk["L5 worker: clearance_poll"] -.->|"read window (fixture default)"| ev["L2 evidence (partial)"]
        wk -->|"ops_confirmed"| led{{"Ledger append: not bill-verified"}}
    end
    own -->|"mark done"| ux
    api --> wk
    st(["↩ status poll back to L6"])
    api --> st --> ux

    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 led govc
    class own agentc
    class st loopc

SYS-05 Operating loop across layers#

SYS-05 · Operating loop across layers

Product loop

can_emit

Ingest: L1 to L2 (built)

Detect: suppression then lane (partial)

Recommend: runtime (built)

Assign: no live L4 card (partial)

Act: UX (partial)

Verify: ops_confirmed only (built)

↩ Learn: L5 to L4 (designed)

How to read it.

  1. A person gates at assign and at act.
  2. can_emit is the L4 CardSink guard between recommend and assign, not an L3 detect gate.
  3. The learn hop is designed; the evals Lab never auto-promotes to production; precision and PSI are eval-only.

Build now: assign through a live card. Later: the eight-step loop in architecture section 17.

View Mermaid source
flowchart TB
    %% house-style: sys-05-operating-loop
    subgraph loop["Product loop"]
        direction LR
        ing["Ingest: L1 to L2 (built)"] --> det["Detect: suppression then lane (partial)"] --> rec["Recommend: runtime (built)"]
        rec -.->|"can_emit"| asg{{"Assign: no live L4 card (partial)"}} --> act{{"Act: UX (partial)"}} --> ver["Verify: ops_confirmed only (built)"]
    end
    lrn(["↩ Learn: L5 to L4 (designed)"])
    ver -.-> lrn -.-> rec

    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 asg,act govc
    class lrn loopc

SYS-06 Life of one plant condition#

SYS-06 · Life of one plant condition

L4 and L5

L3 Finding rail

designed hop

Candidate (shadow)

Emitted Finding, or lab_only

Proposal: immutable

Live card

ops_confirmed: ledger append

How to read it.

  1. In L3 a candidate becomes an emitted Finding or stays lab_only; certification shadow fails closed.
  2. An L4 DecisionCase becomes an immutable proposal; the live-card hop is designed.
  3. Clearance appends to the ledger on ops_confirmed.

Build now: the live-card hop. Later: the full ClosureState machine.

View Mermaid source
flowchart TB
    %% house-style: sys-06-condition-lifecycle
    subgraph l3["L3 Finding rail"]
        direction LR
        cand["Candidate (shadow)"] --> emit["Emitted Finding, or lab_only"]
    end
    subgraph l45["L4 and L5"]
        direction LR
        prop["Proposal: immutable"] -.->|"designed hop"| live["Live card"] --> clr{{"ops_confirmed: ledger append"}}
    end
    emit --> prop

    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 clr govc

SYS-07 Deployment and trust boundaries#

SYS-07 · Deployment and trust boundaries

Stamped managed cloud

Plant networks

MQTT egress

context HTTP

provider API keys

Plant OT net (pilot)

edge-agent: outbound only

Plant IT net: context

Stamped cloud VPC: X-Service-Key

L2 and L3 to L6 services

LLM providers: L4 seam

WhatsApp then SMS: fake clients on main

How to read it.

  1. Nothing connects inbound to the plant OT network; secrets stay in cloud vaults.
  2. L5 notify logic is WhatsApp first, SMS fallback, but the API wires FakeMeta and FakeSms, so no real messages leave L5.
  3. L6 verifies the Meta webhook HMAC; the inbound button mapping is a stub and the BFF still polls L5.

Build now: real senders behind one budget. Later: the Plant Box and its writer (architecture section 7).

View Mermaid source
flowchart TB
    %% house-style: sys-07-deployment-trust
    subgraph plant["Plant networks"]
        direction LR
        ot["Plant OT net (pilot)"] --- ea["edge-agent: outbound only"]
        it["Plant IT net: context"]
    end
    subgraph sc["Stamped managed cloud"]
        direction LR
        vpc{{"Stamped cloud VPC: X-Service-Key"}} --> svc["L2 and L3 to L6 services"]
    end
    llm["LLM providers: L4 seam"]
    wa["WhatsApp then SMS: fake clients on main"]
    ea -->|"MQTT egress"| vpc
    it -->|"context HTTP"| vpc
    svc -->|"provider API keys"| llm
    svc --> wa

    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 vpc govc

SYS-08 Built versus designed#

SYS-08 · Built versus designed

Partial, designed or deferred

Mostly built: on main with tests, not live

edge-agent

L2 store

context-agent (L1E IT)

L3 methods :8094

L4 runtime (memory partial)

PathScheduler: built, not deployed (L3C-G5)

L1C context poller: off

L5 /cards ingest: designed

Bill verified: deferred, fixtures only

Hindsight memory: opt-in

How to read it.

  1. Partial means the code exists but is not wired.
  2. Bill reconcile runs only against FixtureBillClient; no savings are verified against a real bill.
  3. The full gap list is l4/24-architecture-gaps.md.

Build now: L5 /cards. Later: the bill path, if ADR-014 reopens.

View Mermaid source
flowchart TB
    %% house-style: sys-08-built-vs-designed
    subgraph built["Mostly built: on main with tests, not live"]
        direction LR
        ea["edge-agent"] --> l2["L2 store"]
        cx["context-agent (L1E IT)"] -.-> l2
        m3["L3 methods :8094"] --> r4["L4 runtime (memory partial)"]
    end
    subgraph des["Partial, designed or deferred"]
        direction LR
        ps["PathScheduler: built, not deployed (L3C-G5)"]
        cp["L1C context poller: off"]
        cards{{"L5 /cards ingest: designed"}}
        bill{{"Bill verified: deferred, fixtures only"}}
        hs["Hindsight memory: opt-in"]
    end
    l2 --> ps
    r4 -.-> cards

    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 cards,bill govc

SYS-09 Evidence and money lineage#

SYS-09 · Evidence and money lineage

Realised ledger

Modeled estimate

Telemetry (L2)

L3 calculator_ref: only source of a rupee estimate

Tariff (L2)

Finding estimate: Modeled tier

L4 card cites the ref

Live card (partial)

L5 M&V worker

Ledger append: L5 is the only writer

↩ L6 shows the claim status sanitised

How to read it.

  1. Evidence tiers are Measured, Confirmed, Modeled and Unknown.
  2. A rupee estimate comes only from an L3 calculator_ref; no layer invents rupees.
  3. A realised row is appended only by L5 after ops_confirmed; verified savings today are ₹0.

Build now: the live-card link. Later: ValueRecord with named evidence (architecture section 5).

View Mermaid source
flowchart TB
    %% house-style: sys-09-money-lineage
    subgraph est["Modeled estimate"]
        direction LR
        tel["Telemetry (L2)"] --> calc{{"L3 calculator_ref: only source of a rupee estimate"}}
        tar["Tariff (L2)"] --> calc
        calc --> fe["Finding estimate: Modeled tier"] --> c4["L4 card cites the ref"]
    end
    subgraph real["Realised ledger"]
        direction LR
        lc["Live card (partial)"] --> mv["L5 M&V worker"] --> led{{"Ledger append: L5 is the only writer"}}
    end
    c4 --> lc
    l6(["↩ L6 shows the claim status sanitised"])
    led --> l6

    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 calc,led govc
    class l6 loopc

EXT-01 The stamped-external pack#

EXT-01 · The stamped-external pack

stamped-external: docs and contracts, no runtime server

tag after green CI

Master document

decisions/: ADRs

technical/: architecture and deep docs

contracts/: schemas, fixtures, OpenAPI, tools, TOPICS.md

handoff/: cross-repo hops

CI: contract-check.sh, identity lint, check_docs

Layer repos: external/ submodule pin

How to read it.

  1. The master document and ADRs set the rules; technical/ and contracts/ encode the stack and the wire shapes.
  2. CI gates a merge before layer repos bump their external/ pin (ADR-009).
  3. This repo is docs and contracts only.

Build now: keep CI green before every tag. Later: none.

View Mermaid source
flowchart TB
    %% house-style: ext-01-ssot-pack
    subgraph pack["stamped-external: docs and contracts, no runtime server"]
        direction LR
        md{{"Master document"}} --> adr["decisions/: ADRs"] --> tech["technical/: architecture and deep docs"]
        tech --> con["contracts/: schemas, fixtures, OpenAPI, tools, TOPICS.md"]
        tech --> ho["handoff/: cross-repo hops"]
        ci{{"CI: contract-check.sh, identity lint, check_docs"}}
    end
    rep["Layer repos: external/ submodule pin"]
    ci -->|"tag after green CI"| rep

    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 md,ci govc

EXT-02 How a contract changes#

EXT-02 · How a contract changes

Validate on main

Propose and edit

links ADR when normative

merge, tag

Author PR

ADR note

Edit schema and CHANGELOG, semver bump

contract-check.sh

Tag release: VERSION and CHANGELOG

Layer repos bump external/

↩ dual-read window, then drop the old parser

How to read it.

  1. A schema mismatch starts a PR, with an ADR when the change is normative.
  2. scripts/contracts/contract-check.sh gates the merge; the tag triggers submodule bump PRs.
  3. Consumers dual-read, then drop deprecated shapes, for example prescription.json 1.0.0 beside the card proposal.

Build now: dual-read for every breaking bump. Later: a CI state machine for removal.

View Mermaid source
flowchart TB
    %% house-style: ext-02-contract-change
    subgraph edit["Propose and edit"]
        direction LR
        pr["Author PR"] -->|"links ADR when normative"| adr["ADR note"] --> sch["Edit schema and CHANGELOG, semver bump"]
    end
    subgraph main["Validate on main"]
        direction LR
        chk{{"contract-check.sh"}} -->|"merge, tag"| tag["Tag release: VERSION and CHANGELOG"] --> bump["Layer repos bump external/"]
    end
    sch --> chk
    dual(["↩ dual-read window, then drop the old parser"])
    sch -.-> dual

    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 chk govc
    class dual loopc

EXT-03 Contract catalog: producers and consumers#

EXT-03 · Contract catalog: producers and consumers

Finding to card proposal

L1 to L2 families

L1 connectors

envelope/*

L2 ingest (ADR-019)

L3 intelligence

intelligence/*: Finding 1.2.0

L4 runtime: tools

↩ L5 closure and L6 BFF consume DTOs from the catalog; never redefine them

How to read it.

  1. L2 ingest validates the envelope and telemetry and plant schemas (ADR-019).
  2. L4 consumes Finding and emits the card proposal; prescription.json 1.0.0 is dual-read.
  3. Seven families plus OpenAPI, tools and TOPICS.md make up the catalog: contracts/README.md.

Build now: L5 ingest of the card proposal. Later: the direction contracts of architecture section 5.

View Mermaid source
flowchart TB
    %% house-style: ext-03-contract-catalog
    subgraph fam1["L1 to L2 families"]
        direction LR
        l1["L1 connectors"] --> env{{"envelope/*"}} --> l2["L2 ingest (ADR-019)"]
    end
    subgraph fam2["Finding to card proposal"]
        direction LR
        l3["L3 intelligence"] --> fin{{"intelligence/*: Finding 1.2.0"}} --> l4["L4 runtime: tools"]
    end
    cons(["↩ L5 closure and L6 BFF consume DTOs from the catalog; never redefine them"])
    l4 --> cons

    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 env,fin govc
    class cons loopc

EXT-04 Authority order when docs disagree#

EXT-04 · Authority order when docs disagree

Build

Architecture

Identity

Master document

technical/STAMPED_ARCHITECTURE.md

technical/DECISIONS.md

technical/ deep docs

handoff/

contracts/: wire truth

identity lint: PR gate

How to read it.

  1. On a meaning conflict the earlier node wins; the master document wins on identity.
  2. The architecture holds the technical shape; open choices live only in the decision board.
  3. Contracts are wire truth; scripts/vision-identity-lint.ps1 blocks withdrawn identity on PRs.

Build now: follow this order. Later: none.

View Mermaid source
flowchart TB
    %% house-style: ext-04-authority-order
    subgraph id["Identity"]
        direction LR
        md{{"Master document"}}
    end
    subgraph tech["Architecture"]
        direction LR
        arch["technical/STAMPED_ARCHITECTURE.md"] --> dec["technical/DECISIONS.md"] --> deep["technical/ deep docs"]
    end
    subgraph wire["Build"]
        direction LR
        ho["handoff/"] --> con["contracts/: wire truth"] --> lint{{"identity lint: PR gate"}}
    end
    md --> arch
    deep --> ho

    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 md,lint govc

EXT-05 Contract version lifecycle#

EXT-05 · Contract version lifecycle

Lifecycle

merge

dual-read

Draft: PR

CI review: contract-check.sh

Active: default

Deprecated

↩ removed after consumers drop parsers (policy in CHANGELOG, designed)

How to read it.

  1. Draft plus fixtures must pass contract-check.sh; the CHANGELOG records semver and the dual-read policy.
  2. A new emit uses the new schema while the old file stays dual-read.
  3. Removal is policy only; no CI state machine enforces it yet.

Build now: record every deprecation in contracts/CHANGELOG.md. Later: automated removal.

View Mermaid source
flowchart TB
    %% house-style: ext-05-contract-lifecycle
    subgraph life["Lifecycle"]
        direction LR
        dr["Draft: PR"] --> rv{{"CI review: contract-check.sh"}} -->|"merge"| ac["Active: default"]
        ac -.->|"dual-read"| dp["Deprecated"]
    end
    rm(["↩ removed after consumers drop parsers (policy in CHANGELOG, designed)"])
    dp -.-> rm

    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 rv govc
    class rm loopc
Page history: last 2 changes
  1. 2026-10-07 docs: keep agents out of archive; changelog; final check suite fd7f122
  2. 2026-10-07 docs(technical): archive archify; add SYSTEM_VIEWS.md house diagrams; check_docs --min 1e190b6

Diagram

100%

Search the architecture