whassan commited on
Commit
95eecc3
·
verified ·
1 Parent(s): d4d5551

Deploy Sensorflow Studio

Browse files
app_backend.py CHANGED
@@ -1488,46 +1488,51 @@ app.include_router(rca_router)
1488
  from sensorflow.hillclimb.api import router as hillclimb_router
1489
  app.include_router(hillclimb_router)
1490
 
1491
- # Agentic Retrospective Safety Analyzer (evidence-tiered failure retrospectives,
1492
- # safety-case RAG, deterministic severity + launch policy gate).
1493
- from sensorflow.retro.api import router as retro_router
1494
- app.include_router(retro_router)
 
 
 
 
1495
 
1496
  # Agentic launch readiness & misclassification triage (five-layer pipeline,
1497
  # deterministic policy engine, evidence graphs, evaluation flywheel).
1498
  from sensorflow.agentic.api import router as agentic_router
1499
  app.include_router(agentic_router)
1500
 
1501
- # Studio UX support (dashboard layout persistence + BEV frame replay for the
1502
- # interactive canvas). Read-only over other packages' data.
1503
- from sensorflow.studio_ux.api import router as studio_ux_router
1504
- app.include_router(studio_ux_router)
1505
-
1506
  # Next-gen AV perception evaluation: counterfactual simulation + validity
1507
  # gating, closed-loop behavioral evaluation, safety-informed metrics,
1508
  # compute dedup + launch-eval gauntlet scheduling.
1509
  from sensorflow.nextgen.api import router as nextgen_router
1510
  app.include_router(nextgen_router)
1511
 
1512
- # Studio 2.0 control plane: unified entity registry, deterministic release
1513
- # gate composing safety/seqeval/megaeval (+ agentic/nextgen when available),
1514
- # hardware-aware gate matrix, observability funnel, closed-loop demo.
1515
- from sensorflow.studio2.api import router as studio2_router
1516
- app.include_router(studio2_router)
 
 
 
 
1517
 
1518
  # Production hardening layer (audit browser, readiness scorecard, funnel,
1519
  # sampling/quality/HITL demos on seeded synthetic fixtures).
1520
  from sensorflow.hardening.api import router as hardening_router
1521
  app.include_router(hardening_router)
1522
 
1523
- # Multimodal rare-event mining & perception QA (costumed-pedestrian miner).
1524
- from sensorflow.raremine.api import router as raremine_router
1525
- app.include_router(raremine_router)
 
 
1526
 
1527
- # Vitis Vision acceleration layer (HIL quantization gap, accelerated ISP +
1528
- # synthetic edge cases, temporal/stereo stability). Emulated backend; no FPGA.
1529
- from sensorflow.vitis.api import router as vitis_router
1530
- app.include_router(vitis_router)
1531
 
1532
  # Mount static folder
1533
  static_dir = Path(__file__).parent / "static"
 
1488
  from sensorflow.hillclimb.api import router as hillclimb_router
1489
  app.include_router(hillclimb_router)
1490
 
1491
+ # Multimodal rare-event mining & perception QA (costumed-pedestrian miner).
1492
+ from sensorflow.raremine.api import router as raremine_router
1493
+ app.include_router(raremine_router)
1494
+
1495
+ # Vitis Vision acceleration layer (HIL quantization gap, accelerated ISP +
1496
+ # synthetic edge cases, temporal/stereo stability). Emulated backend; no FPGA.
1497
+ from sensorflow.vitis.api import router as vitis_router
1498
+ app.include_router(vitis_router)
1499
 
1500
  # Agentic launch readiness & misclassification triage (five-layer pipeline,
1501
  # deterministic policy engine, evidence graphs, evaluation flywheel).
1502
  from sensorflow.agentic.api import router as agentic_router
1503
  app.include_router(agentic_router)
1504
 
 
 
 
 
 
1505
  # Next-gen AV perception evaluation: counterfactual simulation + validity
1506
  # gating, closed-loop behavioral evaluation, safety-informed metrics,
1507
  # compute dedup + launch-eval gauntlet scheduling.
1508
  from sensorflow.nextgen.api import router as nextgen_router
1509
  app.include_router(nextgen_router)
1510
 
1511
+ # Agentic Retrospective Safety Analyzer (evidence-tiered failure retrospectives,
1512
+ # safety-case RAG, deterministic severity + launch policy gate).
1513
+ from sensorflow.retro.api import router as retro_router
1514
+ app.include_router(retro_router)
1515
+
1516
+ # Studio UX support (dashboard layout persistence + BEV frame replay for the
1517
+ # interactive canvas). Read-only over other packages' data.
1518
+ from sensorflow.studio_ux.api import router as studio_ux_router
1519
+ app.include_router(studio_ux_router)
1520
 
1521
  # Production hardening layer (audit browser, readiness scorecard, funnel,
1522
  # sampling/quality/HITL demos on seeded synthetic fixtures).
1523
  from sensorflow.hardening.api import router as hardening_router
1524
  app.include_router(hardening_router)
1525
 
1526
+ # Studio 2.0 control plane: unified entity registry, deterministic release
1527
+ # gate composing safety/seqeval/megaeval (+ agentic/nextgen when available),
1528
+ # hardware-aware gate matrix, observability funnel, closed-loop demo.
1529
+ from sensorflow.studio2.api import router as studio2_router
1530
+ app.include_router(studio2_router)
1531
 
1532
+ # ROTR: right-of-the-road violation detection, causal-layer attribution,
1533
+ # counterfactual consequence, taxonomy mining, governed flywheel + stop-ship.
1534
+ from sensorflow.rotr.api import router as rotr_router
1535
+ app.include_router(rotr_router)
1536
 
1537
  # Mount static folder
1538
  static_dir = Path(__file__).parent / "static"
docs/architecture/rotr-architecture.md ADDED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ROTR — Right-of-the-Road Violation Detection, Triage, Evaluation & Training
2
+
3
+ Status: accepted (implementation in `sensorflow/rotr/`, API `/api/rotr`,
4
+ UI "ROTR Control Center"). Companion docs: `nextgen-adr.md` (reuse
5
+ precedents), `nextgen-architecture-comparison.md` (three-path format this
6
+ doc extends).
7
+
8
+ Evidence discipline used throughout: every claim is tagged
9
+ **[Observed]** (verified in this repo by import/read/execution),
10
+ **[Documented]** (stated in repo docs but not independently executed here),
11
+ **[Proposed]** (what `sensorflow/rotr` adds), or **[Inference]**
12
+ (engineering judgment about systems outside this repo — phrased as "a
13
+ production system could…", never as a claim about any specific vendor's
14
+ implementation).
15
+
16
+ ---
17
+
18
+ ## 1. Executive architecture — three paths, one problem
19
+
20
+ The problem: detect events where an AV (or a labeled agent in a log)
21
+ violated right-of-the-road rules — failure to yield, restricted-path entry,
22
+ wrong lane association, intersection conflicts, unsafe merges — then triage
23
+ them by causal layer, measure whether they *matter behaviorally*, and feed
24
+ the confirmed ones back into evaluation and training **without ever
25
+ auto-attributing a violation to perception**. Causal-layer separation is
26
+ the load-bearing design constraint: a ROTR violation is a statement about
27
+ *behavior versus expectation*, and behavior is downstream of at least eight
28
+ candidate causes (perception, prediction, planning, localization, map,
29
+ control, the policy rule itself, and the data/label that recorded it). Any
30
+ architecture that hard-wires "violation ⇒ perception bug" produces false
31
+ blame at scale, poisons the training flywheel with mislabeled failure
32
+ cohorts, and — worst — hides genuine planning regressions behind perception
33
+ noise.
34
+
35
+ ### Path A — 2-day rapid PoC
36
+
37
+ One notebook/script: hand-rolled rule checks over a handful of logs or
38
+ synthetic scenes, printed violation counts, maybe a CSV. **[Inference]**
39
+ Its fundamental property is that *detection and judgment are fused*: the
40
+ same code that finds "ego didn't stop" also decides it was a perception
41
+ miss, because there is no evidence model that could distinguish causes. No
42
+ provenance, no versioned rules, no negative controls (scenes that *look*
43
+ like violations but aren't), no statistics — a count of 12 violations
44
+ cannot be compared to last week's 9 because neither number has a
45
+ denominator, a seed, or a rule version attached. Path A answers "can we see
46
+ these events at all?" and nothing else. It is the correct first spend of
47
+ two days and the wrong foundation for a third day.
48
+
49
+ ### Architecture B — Sensorflow Studio gated evaluation (THIS codebase)
50
+
51
+ What this repo already is, grounded in what I verified:
52
+
53
+ * **Deterministic synthetic substrate** — `sensorflow.bevfusion.scenes.generate_sequences`
54
+ produces seeded scene sequences with GT boxes, occlusion, day/night/rain
55
+ cycling **[Observed]**; `sensorflow.raremine` generates seeded scene banks
56
+ for mining **[Observed]**.
57
+ * **Surrogate-safety math** — `sensorflow.safety.ssam_ext` implements
58
+ `projected_ttc`, `zone_grid_pet`, `drac`, `rect_gap`, `rects_overlap`,
59
+ `collision_probability` **[Observed]**; `sensorflow.retro.metrics.stopping_distance`
60
+ gives friction/latency-parameterized stopping distance **[Observed]**.
61
+ * **Closed-loop behavioral evaluation** — `sensorflow.nextgen.closedloop.run_closed_loop`
62
+ is a deterministic IDM-longitudinal planner + first-order actuation over
63
+ `ActorTrack`s with a seeded perception failure model and a `corrected=True`
64
+ ground-truth-injection mode; `nextgen.causal.causal_replay` diffs
65
+ actual-vs-corrected and issues `BEHAVIORALLY_CONSEQUENTIAL` / `METRIC_ONLY`
66
+ verdicts **[Observed]**.
67
+ * **Sequential statistics** — `sensorflow.seqeval.evaluate_regression`
68
+ (paired sequential testing over megaeval populations, early stopping,
69
+ stratum attribution, INSUFFICIENT as a first-class outcome) **[Observed]**.
70
+ * **Distribution-shift forensics** — `megaeval.analysis.distribution_shift`
71
+ and the `rca` package's planted-cause forensics stages **[Observed]**.
72
+ * **Governed data lineage** — `raremine.lineage` refuses
73
+ `TRAINING_CANDIDATE` for members of protected evaluation sets without a
74
+ recorded governance override (`LeakageError`) **[Observed]**;
75
+ `agentic.flywheel` mirrors these semantics for its regression suites
76
+ **[Observed]**.
77
+ * **Deterministic release policy** — `agentic.policy.evaluate` is a
78
+ versioned, hash-addressed policy engine with pre-authorized
79
+ `AUTOMATIC_STOP_SHIP` conditions and a fail-safe INDETERMINATE outcome
80
+ **[Observed]**.
81
+
82
+ The fundamental difference from Path A is **separation of concerns
83
+ enforced by contracts**: detection (rules over evidence), attribution
84
+ (per-layer evidence tests), consequence (counterfactual behavioral replay),
85
+ statistics (delegated sequential testing), and governance (lineage +
86
+ policy gates) are separate modules with typed interfaces, each
87
+ independently testable, each with provenance. A violation here is a
88
+ *record with evidence*, not a print statement. What Architecture B does
89
+ NOT claim: its scenes are synthetic and its planner is simplified — it
90
+ measures the *machinery* of ROTR evaluation, and every threshold derived
91
+ from synthetic data is labeled ILLUSTRATIVE **[Proposed — carried through
92
+ the implementation]**.
93
+
94
+ ### Conceptual Production-L4 architecture
95
+
96
+ **[Inference throughout this subsection.]** A production system could keep
97
+ Architecture B's *shape* — the module boundaries are the durable asset —
98
+ while swapping every substrate behind a vendor-replaceable interface:
99
+
100
+ * Scenario substrate → fleet logs + a log-ingestion contract (the
101
+ `ROTRScenario` contract in §7 is deliberately log-shaped: frames of ego
102
+ pose + actor states + map context, all versioned).
103
+ * Rule engine → a formalized traffic-rule library (jurisdiction-aware,
104
+ legally reviewed), still deterministic and versioned; the rule-id +
105
+ evidence-fields output contract is unchanged.
106
+ * Perception diff → real GT from labeling pipelines or auto-label
107
+ consensus, behind the same "GT-vs-detected" evidence interface.
108
+ * Counterfactual replay → the actual planner stack in resimulation, or a
109
+ learned world model behind an adapter boundary
110
+ (`nextgen.worldmodel.ExternalWorldModelAdapter` already documents that
111
+ contract shape: determinism, provenance labels, no gate exemption
112
+ **[Observed]**).
113
+ * Statistics → the same sequential-testing discipline, but the population
114
+ is fleet miles and the strata are ODD cells; exposure weights calibrated
115
+ from actual fleet exposure rather than a synthetic bank (§6).
116
+ * Governance → the same lineage/contamination guards, backed by a real
117
+ dataset registry and an incident-review workflow with human sign-off.
118
+
119
+ What changes is *evidence strength and scale*, not architecture: each
120
+ Architecture B module names the production component that replaces it, and
121
+ the interfaces are the deliverable that survives the swap.
122
+
123
+ ---
124
+
125
+ ## 2. Unified data/control-flow diagram
126
+
127
+ ```mermaid
128
+ flowchart TB
129
+ subgraph SUBSTRATE["Scenario substrate (rotr/scenes.py)"]
130
+ GEN["Deterministic generator\n(seeded; extends bevfusion scene conventions)"]
131
+ BANK["Scenario bank\nplanted violations + planted non-violations\n+ env attributes (visibility/weather/lighting)"]
132
+ GEN --> BANK
133
+ end
134
+
135
+ subgraph DETECT["Detection (rules.py)"]
136
+ RULES["Versioned ROTR rule set\nobserved trajectory vs expected-behavior envelope"]
137
+ VIOL["ROTRViolation records\nrule id + evidence + confidence"]
138
+ RULES --> VIOL
139
+ end
140
+
141
+ subgraph TRIAGE["Triage"]
142
+ ATTR["attribution.py\nper-layer evidence tests\nSUPPORTED / RULED_OUT / UNKNOWN"]
143
+ CONS["consequence.py\ncounterfactual replay: corrected vs observed\nNO_MATERIAL_CONSEQUENCE ... SAFETY_CRITICAL"]
144
+ STOP["stopship.py\ndeterministic catastrophic trigger\n(NOT LLM-driven; policy-versioned)"]
145
+ end
146
+
147
+ subgraph MEASURE["Measurement (metrics.py)"]
148
+ MET["ROTR recall / SC-ROTR recall\nBCR / CFR / cohorts"]
149
+ SEQ["seqeval delegation\nbaseline-vs-candidate sequential test\nsix-outcome distinction"]
150
+ end
151
+
152
+ subgraph MINE["Mining (taxonomy.py)"]
153
+ TAX["Six-axis taxonomy\nActor/Vulnerability/Legality/Environment/\nInteraction/Behavior (+3 extensions)"]
154
+ QRY["Structured query\n+ violation clustering"]
155
+ end
156
+
157
+ subgraph LOOP["Flywheel + governance (flywheel.py)"]
158
+ HITL["HITL validation queue"]
159
+ SIG["Failure signatures -> clusters"]
160
+ REG["Regression-test artifacts\nimmutable dataset roles + contamination guard"]
161
+ end
162
+
163
+ BANK -->|"scenario frames + GT + detected"| RULES
164
+ VIOL --> ATTR
165
+ VIOL --> CONS
166
+ ATTR --> STOP
167
+ CONS --> STOP
168
+ VIOL --> MET
169
+ CONS --> MET
170
+ MET --> SEQ
171
+ VIOL --> TAX
172
+ TAX --> QRY
173
+ QRY --> SIG
174
+ ATTR -->|"never auto-implies perception"| SIG
175
+ SIG --> HITL
176
+ HITL -->|"validated"| REG
177
+ REG -->|"regression suite re-runs each candidate"| SEQ
178
+ STOP -->|"NO_GO events"| GATE["Release gate state\n(agentic policy engine if importable,\nelse local gate record)"]
179
+ SEQ --> GATE
180
+
181
+ API["api.py /api/rotr"] -.-> SUBSTRATE & DETECT & TRIAGE & MEASURE & MINE & LOOP
182
+ UI["ROTR Control Center\nExecutive / Engineering / Data / Infrastructure"] -.-> API
183
+ RUNS[("runs/rotr/ persistence\nprovenance on every record")] -.-> API
184
+ ```
185
+
186
+ Control flow: everything is request-scoped FastAPI over file persistence
187
+ (the platform convention **[Observed]** across all 12 landed packages); no
188
+ daemons, no queues. Determinism: same seed + rule version + policy version
189
+ ⇒ byte-identical violation set.
190
+
191
+ ---
192
+
193
+ ## 3. ROTR event model
194
+
195
+ A ROTR violation is **a function of five structured evidence inputs**, and
196
+ is undefined if any is missing (missing ⇒ `UNKNOWN`, never a default):
197
+
198
+ | Evidence input | Contents | Why it is load-bearing |
199
+ |---|---|---|
200
+ | `EgoState` (sequence) | pose (x, y, yaw), speed, acceleration, lane association, localization confidence | "Ego entered the intersection at 9.8 m/s" is meaningless without knowing *which lane the ego believed it was in* — wrong-lane-association violations live entirely in the gap between true and believed lane. |
201
+ | `RoadContext` | lane geometry, intersection topology (controlled/uncontrolled), traffic-control devices (signal state, stop/yield signs), crosswalks, permitted maneuvers per lane, speed limits | The *same trajectory* is legal at a green light and a violation at a red one. Expected behavior is derived from context, so context errors (map layer) are a first-class attribution target. |
202
+ | `ActorStates` (sequences) | per-actor pose/velocity/class, right-of-way state (HAS_ROW / MUST_YIELD / NONE), intent (CROSSING / MERGING / YIELDING / PROCEEDING), occlusion, GT-vs-detected pairing | Right-of-way is *relational*: ego's obligation exists only relative to a specific actor's state and intent. The GT-vs-detected pairing is what lets attribution test the perception layer instead of assuming it. |
203
+ | `ObservedBehavior` | the trajectory the ego actually drove (+ the plan it computed, when available) | The plan/trajectory split is what separates planning failures (bad plan, faithful execution) from control failures (good plan, unfaithful execution). |
204
+ | `ExpectedBehavior` | the envelope of acceptable behavior: legal path corridor, permissible maneuver set, yield/stop obligations with trigger conditions, speed envelope | An *envelope*, not a single reference trajectory — many trajectories are acceptable; a violation is exit from the envelope, which is why superficially-aggressive-but-legal maneuvers (assertive merge with sufficient gap) are planted as NON-violations in the scenario bank. |
205
+
206
+ `violation = f(EgoState, RoadContext, ActorStates, ObservedBehavior,
207
+ ExpectedBehavior)` — the rule engine consumes all five and records *which
208
+ fields of which inputs* drove the decision (the `evidence` block of every
209
+ `ROTRViolation`), so attribution and HITL review can re-derive the verdict
210
+ from the record alone.
211
+
212
+ ---
213
+
214
+ ## 4. Three-level maturity model
215
+
216
+ **Level 1 — PoC (detect).** Rules over one data source; violations as
217
+ console output; no attribution, no statistics, no governance. Exit
218
+ criterion: the rule set finds planted violations and *rejects planted
219
+ non-violations* on a fixed bank. Risk accepted: numbers are not
220
+ comparable across runs.
221
+
222
+ **Level 2 — Gated evaluation (this implementation).** Everything in §2:
223
+ versioned rules, per-layer attribution with UNKNOWN as a legal state,
224
+ counterfactual consequence classification, sequential baseline-vs-candidate
225
+ statistics with the six-outcome distinction, taxonomy mining, HITL-governed
226
+ flywheel with contamination guards, deterministic stop-ship. Exit
227
+ criterion: a model candidate can be *blocked* by a ROTR regression with an
228
+ auditable evidence trail, and no training set can silently absorb a
229
+ regression-suite member. Risk accepted: synthetic substrate — verdicts
230
+ demonstrate machinery, not road reality; all thresholds ILLUSTRATIVE.
231
+
232
+ **Level 3 — Closed-loop production.** **[Inference]** Fleet logs in,
233
+ jurisdiction-aware rule library, resimulation with the real planner,
234
+ exposure weights calibrated from fleet miles, incident-review integration,
235
+ and the flywheel driving actual retraining with measured
236
+ regression-suite pass-rate improvement per cycle. Exit criterion: a
237
+ confirmed on-road ROTR event class shows measurable recurrence reduction
238
+ across two consecutive releases without any regression-suite contamination
239
+ event. The architecture is unchanged from Level 2; each module's substrate
240
+ is swapped behind its existing interface (§1, Production-L4).
241
+
242
+ ---
243
+
244
+ ## 5. Failure attribution model
245
+
246
+ Principle: **downstream failure never auto-implies an upstream cause.**
247
+ Each causal layer gets an independent evidence *test*; each test returns
248
+ `SUPPORTED`, `RULED_OUT`, or `UNKNOWN` (evidence unavailable). A layer is
249
+ implicated only by its own positive evidence — never by another layer's
250
+ absence of evidence. The canonical trap this prevents: a planted
251
+ planning-error case with *perfect perception* must attribute to planning,
252
+ with perception `RULED_OUT` (GT-vs-detected diff is empty), and the test
253
+ suite enforces exactly that.
254
+
255
+ | Layer | Evidence test (what SUPPORTED requires) | Evidence source in this repo |
256
+ |---|---|---|
257
+ | Perception | GT-vs-detected diff shows a missed/misplaced/misclassified actor *material to the rule that fired* (the actor the ego failed to yield to, not any actor) | GT/detected pairing planted in `scenes.py`; diff logic in `attribution.py` **[Proposed]**; pattern precedent: `nextgen.closedloop.PerceptionModel` corrected mode **[Observed]** |
258
+ | Prediction | Actor's ground-truth intent (e.g. CROSSING) diverges from the intent the stack predicted, while detection itself was adequate | planted `predicted_intent` vs `intent` per actor **[Proposed]** |
259
+ | Planning | Perception + prediction adequate at decision time, yet the computed plan exits the expected-behavior envelope | plan-vs-envelope check; planted planning-fault cases **[Proposed]** |
260
+ | Localization | Ego believed pose/lane differs from true pose/lane beyond threshold | planted ego pose-error cases; `localization_error_m` field **[Proposed]** |
261
+ | Map | `RoadContext` as mapped differs from as-built (signal present but unmapped, wrong permitted-maneuver set) | planted map-mismatch cases (`map_context` vs `actual_context`) **[Proposed]** |
262
+ | Control | Planned trajectory acceptable; executed trajectory deviates beyond actuation tolerance | planned-vs-executed diff **[Proposed]**; actuation-lag precedent in `nextgen.closedloop` **[Observed]** |
263
+ | Policy/rule | The rule itself misfires: evidence fields are internally consistent and behavior was within a *reasonable* envelope — flagged for HITL rule review, not silently suppressed | planted non-violation cases that superficially match rule patterns **[Proposed]** |
264
+ | Data/label | Provenance checks fail: frame gaps, timestamp disorder, GT self-inconsistency | record-integrity checks; precedent: `rca` OFFLINE_CONTAMINATION / LABEL_LATENCY planted causes **[Observed]** |
265
+
266
+ The **attribution matrix** is one row per violation × eight layer columns,
267
+ each cell carrying `{status, evidence, confidence}`. Multiple layers can
268
+ be SUPPORTED simultaneously (a missed detection *and* a late plan);
269
+ `primary_layer` is the highest-confidence SUPPORTED layer, and is `None`
270
+ (triage to HITL) when nothing is SUPPORTED — that is the honest outcome,
271
+ not a bug.
272
+
273
+ ---
274
+
275
+ ## 6. Metric hierarchy
276
+
277
+ Detection-layer metrics (precision/recall of boxes) are necessary but
278
+ categorically insufficient for ROTR: they average over exposure, weight a
279
+ parked-car miss equal to a crossing-pedestrian miss, and say nothing about
280
+ behavior. The ROTR hierarchy, bottom-up:
281
+
282
+ 1. **ROTR recall** = detected planted violations / all planted violations
283
+ (per rule, per cohort). Suits ROTR because the scenario bank gives a
284
+ true denominator — on fleet data this becomes recall against
285
+ HITL-adjudicated events. The companion **ROTR precision** is measured
286
+ by the planted non-violations (false-accusation rate), which generic
287
+ detection metrics have no analogue for.
288
+ 2. **Safety-critical ROTR recall (SC-ROTR)** = exposure-weighted recall
289
+ restricted to violations whose consequence class is SAFETY_CRITICAL or
290
+ whose scenario involves a vulnerable actor. **Weight calibration**: the
291
+ weight of stratum *s* is `w_s = p_harm(s) / p_harm(reference)` where
292
+ `p_harm` is estimated from the *consequence replay outcomes on the bank
293
+ itself* (fraction of stratum members whose counterfactual divergence
294
+ crosses the safety envelope) — i.e. weights are *derived from measured
295
+ exposure-to-harm in the same evaluation substrate*, not hand-picked
296
+ class multipliers. On synthetic data these weights are ILLUSTRATIVE by
297
+ construction and labeled as such; the calibration *procedure* (weights
298
+ from measured harm exposure, monotone in severity, renormalized per
299
+ release) is the deliverable, and a production system could feed it
300
+ fleet-measured harm rates without changing the code path.
301
+ 3. **Behavioral Consequence Rate (BCR)** = fraction of detected violations
302
+ whose consequence class ≥ DEGRADED_COMFORT. Separates "the rule fired"
303
+ from "the vehicle's behavior actually changed the outcome" — this is
304
+ the ROTR analogue of `nextgen.causal`'s METRIC_ONLY vs
305
+ BEHAVIORALLY_CONSEQUENTIAL verdict **[Observed precedent]**.
306
+ 4. **Critical Failure Rate (CFR)** = SAFETY_CRITICAL consequences per
307
+ scenario evaluated (a rate with a denominator, reportable with a
308
+ Wilson interval — precedent `rca.stats.wilson_ci` **[Observed]**).
309
+ 5. **Regression verdicts** — baseline vs candidate deltas on 1–4 are
310
+ *claims*, and claims go through `seqeval.evaluate_regression`
311
+ **[Observed]** with rare-event handling (cluster-aware effective n).
312
+ Every comparison is forced into the **six-outcome distinction**:
313
+ observed difference / statistically significant / practically
314
+ significant / safety-critical / insufficient evidence /
315
+ distribution-driven (the last diagnosed with `megaeval` shift analysis
316
+ + `rca` comparison-validity concepts **[Observed]**). A raw delta is
317
+ never reported as a conclusion.
318
+
319
+ **Surrogate-safety caveat** (carried into code comments and the UI):
320
+ TTC, PET, DRAC and friends are *conflict proxies*. Low TTC does not alone
321
+ establish collision risk (it ignores controllability, evasive options,
322
+ and actor reaction), and high TTC does not establish safety (occlusion,
323
+ surface, kinematic limits). They gate *triage priority* here, never a
324
+ GO/NO-GO by themselves; the stop-ship trigger requires a conjunction of
325
+ independent evidence (§ stopship), not a surrogate threshold.
326
+
327
+ ---
328
+
329
+ ## 7. Data contracts design
330
+
331
+ All contracts are pydantic models in `rotr/models.py`; all persist as JSON
332
+ under `runs/rotr/` (platform convention **[Observed]**). Every record
333
+ carries a `Provenance` block: `scenario_id`, `dataset_version`,
334
+ `model_version`, `software_version` (rotr component versions),
335
+ `calibration_version` (weight/threshold set), `timestamp`, `source`
336
+ (SYNTHETIC / LOG / COUNTERFACTUAL), `confidence`. Contracts:
337
+
338
+ `ROTRScenario` (frames of `EgoState` + `ActorState` + `RoadContext`,
339
+ planted-truth block for evaluation) · `ROTRViolation` (rule id/version,
340
+ evidence fields, actor refs, confidence) · `FailureAttribution` (matrix
341
+ row: eight `LayerEvidence` cells + primary layer) · `CounterfactualScenario`
342
+ (corrected-input replay spec + divergence measurements) ·
343
+ `PlannerEvaluation` (observed vs corrected trajectory + per-metric deltas) ·
344
+ `SafetyAssessment` (TTC/PET/clearance/stopping/braking/lateral + the
345
+ surrogate caveat inline) · `RegressionResult` (six-outcome verdict +
346
+ seqeval delegation payload) · `HITLReview` (queue item, action, actor,
347
+ timestamp) · `TrainingCandidate` (dataset role, guard state, lineage) ·
348
+ `ReleaseGateResult` (stop-ship policy version, conjunction evidence,
349
+ GO/NO_GO). Design rules: IDs are content-addressed where possible
350
+ (policy hashes mirror `agentic.policy.policy_hash` **[Observed]**);
351
+ enums over booleans for tri-state evidence; no field defaults that could
352
+ fabricate evidence (`UNKNOWN` is explicit).
353
+
354
+ ---
355
+
356
+ ## 8. Build / Reuse / Integrate / Do-Not-Build
357
+
358
+ Format per row: decision — business value / complexity / ops burden /
359
+ failure modes / 3am cost / replacement strategy.
360
+
361
+ | Capability | Decision | Rationale |
362
+ |---|---|---|
363
+ | Statistical regression testing | **REUSE** `seqeval.evaluate_regression` + megaeval populations | Value: gate-grade sequential stats with zero new statistical code (the highest-risk code class to hand-roll). Complexity: adapter only (map ROTR cohort deltas → stratum effects). Ops: none beyond seqeval's own. Failure mode: population meta missing → create-on-demand, seeded. 3am cost: near zero — deterministic, file-backed. Replacement: swap the adapter to feed fleet strata; seqeval interface unchanged. |
364
+ | Surrogate-safety math | **REUSE** `safety.ssam_ext` (`projected_ttc`, `zone_grid_pet`, `rect_gap`, `rects_overlap`) + `retro.metrics.stopping_distance` | Value: reviewed geometry code shared with 3 packages; consistent numbers across the platform. Complexity: direct calls. Failure modes: shape mismatches (states dicts) — caught by tests. 3am: zero. Replacement: production replaces the *inputs* (real trajectories), not the math. |
365
+ | Scene conventions | **REUSE** `bevfusion.scenes` conventions (DT, seeding discipline, GTBox shape) — **BUILD** the road-context generator | bevfusion scenes are straight-road, no intersections/signals/right-of-way **[Observed]**, so ROTR *must* build topology + ROW states; but it keeps DT=0.1, seeded `default_rng`, ego-frame conventions so downstream consumers (studio_ux BEV replay) stay compatible. Failure mode of building: geometry bugs → planted-truth tests. 3am: generator is pure/deterministic. Replacement: log-ingestion adapter emits the same `ROTRScenario`. |
366
+ | Counterfactual replay | **REUSE** `nextgen.closedloop` planner (importable today) with a self-contained IDM fallback reusing `ssam_ext` math (nextgen is an in-progress workstream — guarded import, graceful fallback, re-checked at integration end) | Value: consequence classification is the highest-value triage signal. Complexity: medium (trajectory diffing). Failure modes: nextgen API drift → fallback planner keeps the feature alive; verdicts labeled with which engine produced them. 3am: deterministic, no services. Replacement: production resim behind the same `replay(scenario, corrected) → trajectory` seam. |
367
+ | Mining / dedup / diversity | **REUSE raremine patterns conceptually** (signature → dedup → diversity → destination), own implementation | raremine's store/models are bound to its own `TrackCandidate` bank **[Observed]**; forcing ROTR violations into that store couples two lifecycles. We mirror the *semantics* (incl. `LeakageError` guard behavior) over ROTR-native records. Failure mode: semantic drift from raremine — contract tests pin the guard behavior. Replacement: a production system could back both with one dataset registry. |
368
+ | Contamination guard | **BUILD** local, mirroring `raremine.lineage` semantics; **INTEGRATE** `studio2` registry when it lands (not importable today **[Observed]**) | Guard is 60 lines; correctness is testable; blocking on an unlanded package is worse. Re-check at end of build: if `sensorflow.studio2` becomes importable, wire through its registry. |
369
+ | Release gate | **INTEGRATE** `agentic.policy` (importable today, guarded) — stop-ship conjunction evaluated locally, forwarded as advisory `PolicyInput` | Value: one deterministic policy authority platform-wide. Failure mode: agentic in-flight changes → local gate record is always written; agentic outcome attached when available. 3am: both paths file-backed. |
370
+ | World models | **INTEGRATE behind nextgen's boundary** (`ExternalWorldModelAdapter` contract **[Observed]**) | ROTR never talks to a world model directly; if/when one lands behind nextgen's adapter, counterfactual generation upgrades transparently. |
371
+ | Vector DB / embedding search for clusters | **DO-NOT-BUILD** | Violation clustering here is over *structured* taxonomy signatures (exact + Jaccard similarity) — an index over ~10³ records needs a dict, not a service. A vector DB adds an ops dependency, an embedding-versioning problem, and a 3am pager (index corruption, service down) for zero verdict change at this scale. Replacement trigger: when signatures become unstructured (free-text descriptions, image embeddings) AND the corpus exceeds what exact structured search handles — then buy, don't build. |
372
+ | Custom stats / dashboards / metric store | **DO-NOT-BUILD** | seqeval/megaeval/rca cover the statistics; JSON under `runs/rotr/` matches every landed package; the UI reads the API like every other Studio page. |
373
+ | LLM triage of stop-ship | **DO-NOT-BUILD** (explicitly) | The catastrophic trigger must be a deterministic, versioned conjunction — auditable, reproducible, and immune to prompt drift. LLM assistance belongs in HITL *summarization*, never in the gate. |
374
+
375
+ ---
376
+
377
+ ## 9. Roadmap — Phases 0–7
378
+
379
+ Phases marked ✅ are ALREADY effectively complete in this codebase (landed
380
+ packages provide them); ROTR work is phases 2–6.
381
+
382
+ | Phase | Scope | Depends on | Components / interfaces | Tests / acceptance | Failure modes | Measurable outcome |
383
+ |---|---|---|---|---|---|---|
384
+ | **0 — Substrate** ✅ | Deterministic scenes, sensors, GT, persistence conventions | — | `bevfusion.scenes/sensors`, `runs/` convention | landed suites green | — | seeded scene banks reproducible byte-for-byte |
385
+ | **1 — Safety math + stats foundations** ✅ | Surrogate measures, sequential testing, shift forensics | 0 | `safety.ssam_ext`, `seqeval`, `megaeval`, `rca` | landed suites green | — | reusable, tested math with zero ROTR-specific code |
386
+ | **2 — ROTR detection PoC** | Road-context scenarios + versioned rule engine | 0,1 | `rotr/scenes.py`, `rotr/rules.py`; `generate_bank(seed) → ROTRScenario[]`, `evaluate(scenario) → ROTRViolation[]` | planted violations found AND planted non-violations rejected; determinism test | over/under-fit rules → negative-control cases in the bank | 100% planted-truth agreement on the seeded bank |
387
+ | **3 — Attribution** | Per-layer evidence tests + matrix | 2 | `rotr/attribution.py`; `attribute(violation, scenario) → FailureAttribution` | planning-error-with-perfect-perception → planning (perception RULED_OUT); map/localization planted cases correct | evidence gaps mislabeled → UNKNOWN is enforced default | 0 auto-perception attributions across the bank |
388
+ | **4 — Consequence** | Counterfactual replay + classification | 2,3 | `rotr/consequence.py`; `replay(scenario, violation) → PlannerEvaluation + SafetyAssessment` | cosmetic → NO_MATERIAL_CONSEQUENCE; missed crossing ped → SAFETY_CRITICAL | fallback-vs-nextgen divergence → engine recorded on every verdict | BCR/CFR computable on the full bank |
389
+ | **5 — Metrics + regression gate** | Metric hierarchy, seqeval delegation, six outcomes, stop-ship | 2–4 | `rotr/metrics.py`, `rotr/stopship.py` | weight monotonicity; six-outcome mapping; stop-ship fires ONLY on the defined conjunction | weight miscalibration → calibration doc + monotonicity test | candidate blockable by ROTR regression with audit trail |
390
+ | **6 — Mining + flywheel** | Taxonomy, structured query, clusters, HITL, roles + guard | 2–5 | `rotr/taxonomy.py`, `rotr/flywheel.py` | spec query returns exactly matching violations; guard raises without override | signature drift splits clusters → signature version pinned | confirmed violation → regression artifact in one governed path |
391
+ | **7 — Production hardening** | Fleet logs, jurisdictional rules, real resim, calibrated weights | 2–6 + external | log adapter emitting `ROTRScenario`; rule library; registry integration | shadow-mode parity vs HITL adjudication | **[Inference]** log quality, rule jurisdiction gaps, resim fidelity | recurrence reduction of confirmed classes across releases |
392
+
393
+ ---
394
+
395
+ ## 10. Capability comparison — what changes architecturally
396
+
397
+ | Capability | Path A (2-day PoC) | Architecture B (this codebase) | Production-L4 [Inference] |
398
+ |---|---|---|---|
399
+ | Scenario source | a few hand-built cases | seeded generator, planted truth incl. negative controls | fleet logs + targeted resim; *change:* ingestion contract replaces generator behind the same `ROTRScenario` |
400
+ | Rule evaluation | inline ifs, unversioned | versioned deterministic rule set, evidence-field output | jurisdiction-aware legal rule library; *change:* rule content, not the engine contract |
401
+ | Attribution | none (violation ⇒ "model bug") | 8-layer evidence matrix, UNKNOWN legal, no auto-perception | same matrix over real stack telemetry; *change:* evidence sources, not the matrix |
402
+ | Consequence | none | counterfactual IDM replay, 4-class verdicts | full-stack resim / world model behind adapter; *change:* replay engine behind the same seam |
403
+ | Statistics | raw counts | sequential testing, six-outcome, rare-event aware | same discipline, fleet-mile denominators; *change:* population + exposure calibration |
404
+ | Safety weighting | none | exposure-derived, ILLUSTRATIVE-labeled, monotone | calibrated from fleet harm rates; *change:* calibration inputs only |
405
+ | Data governance | none | immutable roles + contamination guard + override audit | registry-backed with org-level enforcement; *change:* backing store |
406
+ | Release decision | vibes | deterministic stop-ship conjunction + policy engine, NO_GO auditable | same, plus human safety board integration; *change:* authority chain, not the trigger |
407
+ | Mining | grep | six-axis taxonomy + structured query + clustering | same axes over embeddings + structured; *change:* retrieval substrate when scale demands |
408
+ | UI | notebook plots | four-audience control center on live API | same views on fleet-scale aggregates; *change:* aggregation layer |
409
+
410
+ The through-line: Path A → B adds *contracts, evidence discipline, and
411
+ governance*; B → L4 swaps *substrates behind those contracts*. Nothing in
412
+ B's module graph is thrown away on the way to L4 — which is the definition
413
+ of "no unnecessary infrastructure debt" this design optimizes for.