L2 — Universal repository
L2 is universal-repositary, the store of record for plant truth in TimescaleDB. It is the only layer that opens the database. L1 posts envelopes to its ingest service, and L3 to L6 read through the query API with service keys, never a database URL. L2 holds readings, assets, topology and context records today, with lots, genealogy, twin state and the write log as direction. L4 may keep derived data of its own, but never a second plant record.
- Status
- as-built (
universal-repositaryon main) · contract (envelope ingest, query API, ADR-019 context) · direction (fast-loop tables, Plant Box config pull) - Conceptual layer
- ② Context
- Repo layer
- L2
universal-repositary - Source
- architecture section 3.6.2, section 4, section 5.7 · ADRs 007, 019
- configure & prove
- L1-L2-DATA-PLANE.md
L2 is the only layer that opens Timescale for plant truth. L1 posts envelopes; L3–L6 read through HTTP with service keys. L4 may hold derived operational data (PSMPlant Situation Model, traces) in its own store — never a second plant system of record.
| Label | Meaning |
|---|---|
| as-built | universal-repositary on main |
| contract | Envelope ingest + query API + ADR-019 context records |
| direction | Plant-wide industrial graph product (explicit non-goal) |
Repo#
| Repo | Job | Must not |
|---|---|---|
universal-repositary | Timescale seven schemas; HTTP ingest; query-api; ops console | L1 protocol adapters; customer Forge UI; hand L2_DATABASE_URL to L3–L6 |
Typical ports (local compose): ingest :8090 · query :8091 · console :8092 · admin :8093 · Timescale :5433.
Seven schemas (as-built)#
| Schema | Holds | Writers |
|---|---|---|
ingest | Dedup inbox + audit | ingest only |
telemetry | measurement / event hypertables, aggregates, evidence archives, asset_state | ingest |
graph | Asset topology | seed / admin |
commercial | tariffs, bills, bill lines, operating rates | ingest + seed |
features | production, orders, department graph, context tables | ingest + seed |
baselines | baseline models | seed / admin |
ledger | M&V ledger intents | L5 flows via ops/SQL paths — not L1 stream |
Detail and retention: consumer docs/EXTENSIVE.md. Configure meters and context into these stores via L1-L2-DATA-PLANE.md.
How facts land#
How to read it.
- L1 relay
POST /v1/ingest/recordswithStampedRecordEnvelope. - Validate against contracts → insert
ingest.l1_processed_inboxondedupe_key. - New → demux to schema tables (201); conflict → 200
{inserted: false}. bill_linerequiresextraction.validated=trueor 422.- Historian backfill:
POST /v1/ingest/measurements/backfillforceslate=trueand stamps lineage — same measurement store.
Build now: one Timescale store (D1, D20). Later: graph path queries if needed (architecture section 4).
View Mermaid source
flowchart TB
%% house-style: l2-ingest-seven-schemas
l1["L1 POST /v1/ingest/records<br/>StampedRecordEnvelope"]
gate{{"contracts plus bill_line validated"}}
subgraph ingestPath["Ingest path"]
direction LR
inbox["ingest.l1_processed_inbox<br/>dedupe_key"] --> demux["route_record to schema tables"]
end
subgraph seven["Seven schemas"]
direction LR
s1["ingest"]
s2["telemetry"]
s3["graph"]
s4["commercial"]
s5["features"]
s6["baselines"]
s7["ledger"]
end
dup(["↩ 200 duplicate inserted false"])
l1 --> gate --> inbox --> demux --> seven
gate -.-> dup
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 gate govc
class dup loopc
Fast-loop tables and the Plant Box bundle (direction)#
Nothing here is as-built. Sixteen new tables land in the existing schemas; rows arrive as upserts through records/{type} and the normal L1 cloud path, each stamped with episode_id where one applies and the Plant BoxPlant-side computer for the fast loop (direction; D4) lockfile id. Producer, consumers and proposed contracts per table: ../fast-loop/07-interfaces-and-ownership.md section 3. Keys: ../fast-loop/05-records-deployment-operations.md.
| Schema | Tables | Producer | Retention |
|---|---|---|---|
telemetry | fast_reading (compressed batches) | L1 edge-agent batch upload | At least 13 months (full-year replay) |
telemetry | billet_push, forged_part | L3 twin | As telemetry |
features | part_link, part_flag, time_bin, ht_basket, twin_state | L3 twin | As features |
features | ht_test, rejection_row | L1 (lab export, register intake); match fields from the twin | As features |
ledger | write_log (hash-chained; the record of every write and refusal) | L1 stamped-writer | Ledger retention; never pruned |
ledger | follow_through, missed_savings | L3 twin | Ledger retention |
baselines | param_row, param_promotion | L3 tuning job via L2 HTTP; approver on the L5 staff console | Versioned; never deleted |
graph | part_alias | L5 staff console via L2 admin API | Current plus history |
Plant Box config read. GET /v1/plants/{plant_id}/plant-box-config?since= (plant-box credential) returns the signed plant_box_config bundle that L2 assembles from parts written by L5 (procedures, switches, roster, budgets) and the L3 tuning job (parameter rows, aliases). The Plant Box pulls; the cloud never connects in. The bundle never carries the writer allow-list or limits; those live in the site packVersioned, owner-reviewed plant configuration including topology. See 07 section 4.
What L3–L6 may ask#
| Allowed | Forbidden |
|---|---|
Query HTTP (X-Service-Key + X-Org-Id): measurements, assets, tariffs, context | L2_DATABASE_URL in L3–L6 |
| Constraint / roster / condition context reads | Treating L2 as a plant-wide graph product |
L3 engines KeyError or empty when required tags are missing — that is fail-closed, not invent.
Hard rules#
| Rule | Why |
|---|---|
| Only L2 opens Timescale for plant truth | Spine invariant |
Dedupe on dedupe_key | At-least-once L1 relays |
No invent asset_id / timestamps | Data plane honesty |
| Ops console ≠ customer UI | Customer surface is L6 |
Related#
- Data plane (configure + prove): L1-L2-DATA-PLANE.md
- Handoffs:
../../handoff/l2/— prefer this page for architecture
Deep docs in L2
Page history: last 5 changes
- docs(technical): rewrite layers/ and L1-L2-DATA-PLANE.md to the architecture
322bf46 - docs(layers): L1 fast read, writer and sync; L2 tables; L5 relay and budgets; L6 surfaces; data-plane topics
5127af9 - docs(decisions): renumber live ADRs 001-032 in order, mark withdrawn refs ADR-W###, repoint withdrawn links to archive, note partial supersessions
36c944e - docs(architecture): add L2 store architecture
7d1b648 - docs(repo): reorganize for agent navigation and architecture SSOT
4f1a12c