[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-nvidia-hoisa-generate-regression-report":3,"mdc-jrh349-key":34,"related-org-nvidia-hoisa-generate-regression-report":4371,"related-repo-nvidia-hoisa-generate-regression-report":4528},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":23,"repoUrl":24,"updatedAt":25,"license":26,"forks":27,"topics":28,"repo":29,"sourceUrl":32,"mdContent":33},"hoisa-generate-regression-report","run regression testing reports on SIL stack","Run the Regression Testing Reporter (`srr`) multi-scenario test pipeline on the SIL stack. Picks one or more of 6 pre-built test cases (in-roi, psf-edge, psf-clear, balanced, fast, fixed), launches each in Isaac Sim with a clean compose restart, records 30 Hz parquet of GT + Safety Core state + BA \u002F 3D perception Kafka events, splits by forklift tripwire crossings, and runs the aggregator to produce per-clip match% + Phase 2 perception reports, per-clip MP4 videos, and optional heatmaps. Use when asked to \"run SRR multi-test\", \"regression-test Safety Core\", \"produce SRR report on these scenarios\", \"score perception detection\u002Ftracking\", or \"demo SRR pipeline\".",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},"nvidia","NVIDIA","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fnvidia.png",[12,16,19,20],{"name":13,"slug":14,"type":15},"Reporting","reporting","tag",{"name":17,"slug":18,"type":15},"QA","qa",{"name":9,"slug":8,"type":15},{"name":21,"slug":22,"type":15},"Testing","testing",52,"https:\u002F\u002Fgithub.com\u002FNVIDIA\u002Fhalos-outside-in-safety","2026-08-05T05:58:23.522352",null,12,[],{"repoUrl":24,"stars":23,"forks":27,"topics":30,"description":31},[],"NVIDIA Halos Outside-In Safety Blueprint extends robot perception beyond on-board sensors by using external infrastructure cameras and AI agents to dynamically control robot behavior and perform at maximum efficiency. ","https:\u002F\u002Fgithub.com\u002FNVIDIA\u002Fhalos-outside-in-safety\u002Ftree\u002FHEAD\u002Fskills\u002Fhoisa-generate-regression-report","---\nname: hoisa-generate-regression-report\ndescription: >-\n  Run the Regression Testing Reporter (`srr`) multi-scenario test pipeline on the\n  SIL stack. Picks one or more of 6 pre-built test cases (in-roi, psf-edge,\n  psf-clear, balanced, fast, fixed), launches each in Isaac Sim with a clean\n  compose restart, records 30 Hz parquet of GT + Safety Core state + BA \u002F 3D\n  perception Kafka events, splits by forklift tripwire crossings, and runs the\n  aggregator to produce per-clip match% + Phase 2 perception reports, per-clip\n  MP4 videos, and optional heatmaps. Use when asked to \"run SRR multi-test\",\n  \"regression-test Safety Core\", \"produce SRR report on these scenarios\", \"score\n  perception detection\u002Ftracking\", or \"demo SRR pipeline\".\nmetadata:\n  author: NVIDIA\n  version: 1.3.0\n---\n\n# SRR Skill — Multi-scenario Test Pipeline\n\nWhen this skill is active:\n1. **ALWAYS read the relevant reference doc** in [references\u002F](references\u002F) before running shell commands for that phase.\n2. **Use Explore agents to verify ready signals** instead of fixed `sleep` timers. Spawn one short-lived agent per phase boundary check (compose-up, scene-load, recording-active, analysis-done). This avoids long blocking waits and lets the agent diagnose if a check fails.\n3. **Print demo-friendly log lines** at every phase boundary (format spec below).\n4. **Stop on real errors** — never silently retry. Surface the failure with a 1-line diagnosis from the verifying agent.\n5. **Cancel `ScheduleWakeup` calls when their trigger condition is resolved.** If you set a wakeup to retry a probe (e.g. Kafka mdx-events consume in Step 3f.7) and the probe passes or you recover via another path, **explicitly cancel the wakeup** before moving on. Stale wakeups can fire during Phase 6 (post-process) and confuse the agent into re-running probes against a torn-down state. One wakeup outstanding per probe maximum.\n\nThis skill assumes the SIL + SRR stacks are already deployed and healthy on the host (see `hoisa-deploy-profile` skill for first-time setup), **and SRR fixtures (behavior trees, navmesh, Script-Editor utilities) have been synced into the Isaac SIL dir** via [`halos-integration\u002Fsync_to_halos.sh`](..\u002F..\u002Fclosed-loop-testing\u002Fregression-reporter\u002Fhalos-integration\u002Fsync_to_halos.sh). The skill's launch phase verifies this and offers to sync if missing — see [references\u002F02_launch.md](references\u002F02_launch.md) Step 3.−1.\n\n---\n\n## Phase 0 — Required reading (ONE-TIME, before any compose work)\n\nSRR runs **on top of** the SIL + VSS Warehouse stacks. Their lifecycle (clean-data-before-up, ready signals, redeploy procedure) is owned by the **`hoisa-deploy-profile`** and **`vss-deploy-profile`** skills — NOT this skill. Before any `docker compose down\u002Fup` in Phase 3a or 3b, the agent MUST have read the relevant procedure from those skills, otherwise it will skip mandatory data cleanup and miss ready-signal gates.\n\n**Read these BEFORE running any compose command:**\n\n| File | Why |\n|---|---|\n| `skills\u002Fhoisa-deploy-profile\u002FSKILL.md` § Cleanup, § Ready Signals, § Critical Rules (`SETUP_BEFORE_UP`, `VSS_BEFORE_HALOS`, `POLL_NEVER_WAIT`) | Defines `cleanup_all_datalog.sh` mandate before every `docker compose up`, the `sil`-profile ready-signal set (safety-core, comm-layer, isaac-sim), VSS-must-come-up-first ordering |\n| `skills\u002Fhoisa-deploy-profile\u002Freferences\u002Ftroubleshooting.md` | Failure recipes for \"compose up exits but services missing\", safety-core stuck, comm-layer dead. Consult before retrying a failed restart |\n| `vss-deploy-profile` skill (Deployment Flow \u002F Tear Down + `references\u002Fteardown.md`, `references\u002Fwarehouse.md`, `references\u002Fwarehouse-debug.md`) | VSS Warehouse teardown + data-volume wipe, deploy\u002Fbring-up flow, and perception ready signals (FPS check on `vss-rtvi-cv`). Needed when VSS is unhealthy and SRR's launch HARD GATE (3a.5 or 3f.7) fails |\n\n**Quickly internalize:**\n\n1. **`SETUP_BEFORE_UP`** — `cleanup_all_datalog.sh` is a one-time fresh start before the FIRST scenario only (truncates `psf-log\u002Fpss.log` + wipes `comm-layer\u002F`). **Never run it between scenarios** — it destroys the per-scn pss.log evidence. The per-scenario compose restart already truncates pss.log via Safety Core init.\n2. **`VSS_BEFORE_HALOS`** — when restarting both stacks (e.g. VSS recovery from a 3a.5 gate fail): tear down Halos first, then VSS; bring up VSS first (wait for FPS green), then Halos. Only on VSS-side incident recovery, not per-scenario.\n3. **`POLL_NEVER_WAIT`** — `compose up --detach` exits before containers serve. Always poll `docker ps` + a service-specific ready check; never assume \"returned 0 → ready\".\n\nIf a compose restart fails during Phase 3a\u002F3b, **stop and read the two troubleshooting docs above** before retrying. Do not just `docker compose up` again.\n\n---\n\n## 6 pre-built test cases\n\nAll 6 use the stock scene `indicator_warehouse_20x20_layout_overflow_test.usd` and `--agent-radius 0.8`.\n\n| Name | Length | Stress focus |\n|---|---:|---|\n| **in-roi**    |  5 min | Person stays inside work zone constantly (Safety Core \"person constantly present\" stress) |\n| **psf-edge**  |  5 min | Person sits ON ROI boundary — tests hysteresis \u002F debounce |\n| **psf-clear** |  5 min | Person clearly inside or clearly outside (clean A\u002FB partner of `psf-edge`) |\n| **balanced**  | 10 min | Mixed activity, baseline pre-redraw scenario |\n| **fast**      | 20 min | Low idle, motion-heavy — tests cumulative drift over long run |\n| **fixed**     |  5 min | Deterministic baseline — hand-authored waypoints (not randomized), person always in ROI. Reproducible regression anchor; use for unmute-direction checks, not mute% (mute untestable — always-present person). Waypoints NavMesh-validated at radius 0.8. |\n\n> **`all` and `full` run the first 5 (the randomized sweep) only.** `fixed` is\n> **opt-in** — select it explicitly (`..\u002Fscripts\u002Frun_multi.sh fixed`, or name it\n> in the prompt). It's excluded from `all`\u002F`full` because the person is always in\n> ROI (mute untestable → inflates the blended headline).\n\nScenario waypoints — IRA 1.6 behavior trees (Isaac 6.0 dropped command files):\n- Canonical trees: `..\u002Fscenarios\u002Fbehavior-trees\u002Fsrr_{name}_char{0,1,2}.bt.json`\n  (emitted directly by `..\u002Fscenarios\u002Ftools\u002Frandomize_paths.py`)\n- Synced (Isaac reads from here): `${HOISA_ROOT_PATH}\u002Fclosed-loop-testing\u002Fisaac-sim\u002Fsil\u002Fconfigs\u002Fsrr_char{0,1,2}.bt.json`\n  (the active scenario; `run_multi.sh` swaps the selected scenario onto these\n  fixed names. GitHub layout: `\u003Chalos-repo>\u002Fclosed-loop-testing\u002Fisaac-sim\u002Fsil\u002Fconfigs\u002F`)\n\nThe canonical scene + NavMesh live at `..\u002Fscenarios\u002Fscenes\u002F`. To add or\nre-generate scenarios, run `..\u002Fscenarios\u002Ftools\u002Frandomize_paths.py --name \u003Cnew-name>`\n(writes `..\u002Fscenarios\u002Fbehavior-trees\u002Fsrr_\u003Cnew-name>_char{0,1,2}.bt.json`), then\nre-run `..\u002Fhalos-integration\u002Fsync_to_halos.sh` to push into the Isaac SIL tree.\n\n**Default recording duration: 5 minutes** for any scenario unless user overrides. The \"Length\" column above shows each scenario's *natural* length, but 5 min is the default for demo \u002F regression — enough to surface most issues without burning wall clock.\n\n**User override syntax** (parse natural language):\n- `\"in-roi\"`                → 5 min (default)\n- `\"balanced for 10 min\"`   → 10 min\n- `\"fast at 3 minutes\"`     → 3 min\n- `\"all at 5 min\"`          → 5 min for each of the 5 sweep scenarios (not `fixed`)\n\nWhen invoking `..\u002Fscripts\u002Frun_multi.sh`, encode override as `name:seconds`:\n```\n..\u002Fscripts\u002Frun_multi.sh in-roi:300 balanced:600 fast:180\n```\n\nUser can request any subset, or `all` for the full multi-test (still 5 min each unless overridden).\n\n---\n\n## Architecture (one scenario)\n\n```\n[Isaac Sim] -- \u002Fgt\u002Fcharacter_*\u002Ftf, \u002Fgt\u002Fforklift\u002Ftf -----> [SRR rclpy]  (GT, the reference)\n            -- 3 RTSP cams (Isaac self-hosted) -> [VSS] --+--> Kafka mdx-events    --> [SRR consumer]  BA ROI\u002FTW events\n                                                  +--> Kafka mdx-bev       --> [SRR consumer]  3D detections (Sparse4D bbox3d)\n                                                  +--> Kafka mdx-behavior  --> [SRR consumer]  BA track positions\n                                                         [Safety Core]\n                                                          ↓ \u002Fsafety\u002F{is_muted,command,is_alarm}\n                                                          ↓\n                                                       [SRR rclpy subscribers]\n                                                          ↓ 30 Hz parquet (Phase 1 + Phase 2 columns)\n                                  \u002Fsrr\u002Frecord SetBool true|false (start\u002Fstop)\n```\n\n**Two scoring layers in one recording:**\n- **Phase 1 (Safety Core decision)** — GT-expected-mute vs actual `is_muted` → `match%`, mute\u002Funmute-correct%, reaction lag, BA ROI\u002FTW event detection.\n- **Phase 2 (perception, 3D)** — GT TF vs `mdx-bev` 3D detections + `mdx-behavior` positions → per-class **detect-fail%** \u002F **tracking-loss%**, precision\u002Frecall\u002FF1, position offset-vs-jitter, id-switches, coverage. See [references\u002F06_interpret_report.md](references\u002F06_interpret_report.md) (formula source of truth: `srr-service\u002Fsrr\u002Faggregator.py` → `compute_phase2_metrics`).\n\n> **Phase 2 depends on Sparse4D 3D detections flowing.** VSS Warehouse 3.2.1 runs\n> Sparse4D in `vss-rtvi-cv` → `mdx-bev` + `vss-behavior-analytics` → `mdx-behavior`,\n> enabling Phase 2. A 2D-only feed (only `mdx-events`) gives **Phase 1 only**:\n> `detections_json` is all-null and the Phase 2 section is omitted — expected, not\n> a failure. Availability is keyed off `mdx-bev` decoding detections (Step 3f.7 gate).\n\nThe two new Kafka consumers (`BEV_TOPIC=mdx-bev`, `BEHAVIOR_TOPIC=mdx-behavior`) add five parquet columns — `detections_json`, `tracker_state_json`, `bev_frame_id`, `bev_create_time`, `ba_positions_json` — all nullable, so a Phase-1-only deploy still works. Set either topic env to empty to disable that consumer.\n\nPer-scenario produces: 1 parquet → tw_split → N per-clip parquets → aggregator → `summary.md` (Phase 1 + Phase 2 sections) + `failures.json` + per-clip `scn_*.md` + per-clip `scn_*.mp4` auto-pulled from VST. Optional post-process: `clip_logs` evidence CSVs (incl. `detections.csv` \u002F `tracker_state.csv` \u002F `ba_positions.csv`) and spatial heatmaps.\n\n**Clip semantics**: each forklift crossing of the trailer tripwire (inside-side; warehouse wire at x = 9.574) is a scene boundary. Consecutive boundaries delimit one clip (~40 s each). 5 min recording → ~7 clips, 10 min → ~15, 20 min → ~30.\n\n---\n\n## Demo log format (user-facing output)\n\nWhen running the skill, print exactly this format. The phases \u002F sections are anchors a demo video can cut around.\n\n```\n> Generating testing plan...\n  Selected: in-roi (5 min), psf-edge (5 min), balanced (10 min)\n  Total recording: 20 min   Estimated wall clock: ~50 min\n  Output base: \u002Fapp\u002Fruns\u002Fmulti-test-YYYYMMDD-HHMMSS\u002F\n\n> Planning complete.\n\n> Launching SIL test runs...\n\n  Test 1\u002F3 starts: in-roi (5 min)\n  [00:00] Halos compose restarting...\n  [02:48] Containers up (safety-core, comm-layer, isaac-sim, srr).\n  [02:48] \u002Fsafety\u002Fis_muted publishing — Safety Core chain alive.\n  [02:48] Scene loading...\n  [05:18] Scene loaded. Replicator generating data.\n  [05:18] \u002Fsrr\u002Frecord true → recording active.\n  [05:32] Clip 1: forklift exited trailer (x=8.51, t=00:14)\n  [06:00] Clip 2: forklift entered trailer (x=10.31, t=00:42)\n  [06:43] Clip 3: forklift exited trailer (x=8.46, t=01:25)\n  ...\n  [10:18] \u002Fsrr\u002Frecord false → recording stopped.\n  [10:18] tw_split running...\n  [10:21] tw_split: 7 clips identified.\n  [10:21] aggregator running...\n  [10:50] aggregator: match% avg 84.6, failures 2\u002F7.\n  [10:50] vst_video pulling per-clip MP4...\n  [11:35] 7 clip videos saved to runs\u002Fmulti-test-...\u002Fin-roi\u002Fvideos\u002F\n  Test 1\u002F3 completes.\n\n  Test 2\u002F3 starts: psf-edge (5 min)\n  ...\n  Test 2\u002F3 completes.\n\n  Test 3\u002F3 starts: balanced (10 min)\n  ...\n  Test 3\u002F3 completes.\n\n> All test runs complete.\n\n> Analyzing results...\n  Aggregating per-scenario summary.md → cross-run summary.md\n  Computing safety-critical unmute% per scenario...\n\n> Done. Top-level summary: \u002Fapp\u002Fruns\u002Fmulti-test-YYYYMMDD-HHMMSS\u002Fsummary.md\n  Total: 3 scenarios, 29 clips, 29 review videos, ~50 min wall clock.\n  Headline: in-roi 84.6%, psf-edge 95.6%, balanced 79.6% match.\n  Mute correct: 57.8% · Unmute correct: 89.1% (safety-critical direction)\n  BA detection: ROI 95.5% · TW IN\u002FOUT 100%\n  Perception (Phase 2): 🧍 detect-fail 2.5% \u002F tracking-loss 1.9% · 🚜 detect-fail 32.0% \u002F tracking-loss 29.1% · pos-offset 0.09 m\n```\n\n> The **Perception (Phase 2)** line is present only when the 3D pipeline was\n> active (mdx-bev \u002F mdx-behavior flowing); a Phase-1-only run omits it. Pull the\n> numbers from the summary's `## Phase 2 — perception` block. See\n> [references\u002F06_interpret_report.md](references\u002F06_interpret_report.md) for what\n> `detect-fail%` vs `tracking-loss%` mean and the FAIL-clip drill-down.\n\nThe \"Clip N\" lines come from the live forklift-TF monitor (`..\u002Fscripts\u002Flive_clip_monitor.py`), printed at each TW crossing.\n\n---\n\n## Agent autonomy rules — AGENT MUST ALWAYS CHECK PROGRESS\n\n**Core rule**: never run a `sleep` longer than 60 seconds without an Explore agent actively verifying that progress is happening. If the underlying process stalled (Safety Core crashed, isaac-sim hung, parquet stopped growing), we want to know in ≤60 s, not at the end of the timer.\n\n> ⚠️ **Resolve the perception + behavior container names first (VSS 3.2.1).** On VSS\n> Warehouse 3.2.1 the perception container is **`vss-rtvi-cv`** (Sparse4D 3D warehouse,\n> `DS_MODEL_FAMILY=sparse4d-warehouse`; heavier ~12–14 FPS → floor **≥ 5**) and behavior\n> analytics is **`vss-behavior-analytics`** — the container names no longer carry a\n> `-2d`\u002F`-3d` suffix. **Don't hard-code any single name** — resolve once, then pick the FPS floor:\n> ```bash\n> PERCEPTION=$(docker ps --format '{{.Names}}' | grep -E '^(vss-rtvi-cv|perception-[23]d)$' | head -1)\n> BEHAVIOR=$(docker ps --format '{{.Names}}' | grep -E '^(vss-behavior-analytics|vss-behavior-analytics-[23]d)$' | head -1)\n> case \"$PERCEPTION\" in vss-rtvi-cv|*-3d) FPS_MIN=5;; *) FPS_MIN=25;; esac\n> ```\n> Every `vss-rtvi-cv` \u002F `FPS ≥ 5` reference below and in the reference docs means\n> \"`$PERCEPTION` \u002F `≥ $FPS_MIN`\".\n\nThis applies to every long wait in the workflow:\n\n| Long wait | What to verify each tick | Tick interval | Max patience |\n|---|---|---:|---:|\n| Halos compose up after `down` | `docker ps` shows new container IDs for the services | 30 s | 5 min |\n| Scene load + shader compile | Tail `\u002Ftmp\u002Fisaac-scenario-\u003CTS>-\u003CLBL>.log`; expect `\u002FWorld\u002FRTSPMultiGraph` built + 3 `rtsp:\u002F\u002F` stream lines, then `vss-rtvi-cv` reporting `Active sources : 3` | 30 s | 8 min (first), 3 min (subsequent) |\n| Safety Core warm-up (30 s) | Confirm `\u002Fsafety\u002Fis_muted` still publishing | 15 s | 90 s |\n| **Recording window** (5–20 min) | Verify (a) parquet file size growing, (b) parquet `ba_events_json` rows > 0 (after 90 s), (c) `$PERCEPTION` FPS ≥ `$FPS_MIN` on all 3 cams (≥25 for 2D, ≥5 for 3D) | **60 s** | RECORD_S |\n| Analysis (tw_split + aggregator + vst pull) | `ls scenes\u002Fscn_*.parquet` count, `summary.md` size > 0, mp4 count | 15 s | 5 min |\n\n**Concretely** — at every tick, spawn an Explore agent with a tight prompt like:\n\n```\nQuick health-check for SRR multi-test scenario \"\u003CLABEL>\" at T+\u003Celapsed>s of \u003CRECORD_S>s:\n\n1. `docker exec srr stat -c '%s' \u002Fapp\u002Fruns\u002Frun-*.parquet` — parquet size in bytes.\n   Should be growing tick-over-tick (rough rate: ~80 KB\u002Fmin).\n\n2. BA events flowing into the parquet:\n   docker exec srr python3 -c \"\n   import pandas as pd, glob\n   p = sorted(glob.glob('\u002Fapp\u002Fruns\u002Frun-*.parquet'))[-1]\n   df = pd.read_parquet(p)\n   print('rows:', len(df), 'ba_event_rows:', (df.ba_events_json != '[]').sum())\n   \"\n   After T+90s, ba_event_rows must be > 0. If 0, perception is dead.\n\n3. perception FPS still healthy (resolve container + threshold first):\n   PERCEPTION=$(docker ps --format '{{.Names}}' | grep -E '^(vss-rtvi-cv|perception-[23]d)$' | head -1)\n   case \"$PERCEPTION\" in vss-rtvi-cv|*-3d) FPS_MIN=5;; *) FPS_MIN=25;; esac\n   docker logs --since 60s \"$PERCEPTION\" 2>&1 | grep PERF -A1 | tail -5\n   Parse 3 FPS values from the most recent PERF block. ALL three must be ≥ $FPS_MIN\n   (≥25 on a 2D deploy, ≥5 on a 3D Sparse4D deploy).\n\nReport: parquet size, ba_event_rows, FPS triple. If parquet hasn't grown\nsince last tick OR ba_event_rows == 0 after T+90s OR any FPS \u003C $FPS_MIN, flag\nas STALLED.\n```\n\nIf the agent reports STALLED, **stop the recording phase** and surface the\nissue. Do not let a hung scenario burn 20 minutes of wall clock. (Heartbeats use\nonly `docker exec` \u002F `docker logs` — the host↔container DDS bridge is unreliable\nhere, so host `ros2 topic hz` probes can falsely read 0.)\n\n**Other rules**:\n1. **Pre-check before recording**: containers Up + `\u002Fsafety\u002Fis_muted` publishing + opcua 4840 listening. If any fails, do NOT start recording — diagnose first.\n2. **Background processes**: launch `live_clip_monitor.py` BEFORE `\u002Fsrr\u002Frecord true`, kill it after `\u002Fsrr\u002Frecord false`. Stream its stdout into the demo log.\n3. **Never declare a scenario \"done\"** until the aggregator produced N rows in `summary.md` AND N per-clip videos exist (count files in `runs\u002Fmulti-test-...\u002F\u003Clabel>\u002Fvideos\u002F`).\n4. **Cross-scenario isolation**: ALWAYS restart both Halos compose AND SRR compose between scenarios. Do not skip — Safety Core counter drift carries across runs and corrupts the next scenario's results.\n5. **Do NOT just `bash ..\u002Fscripts\u002Frun_multi.sh ...` in one shot**. The bash script is a reference\u002Ftemplate; the skill agent orchestrates step-by-step and inserts the verification agents between every phase. One-shot invocation skips the verification layer.\n\n---\n\n## Ready Signals\n\nEach phase ends when its ready signal becomes true. Poll, don't fix-time.\n\n| Phase | Ready signal (poll until true) |\n|-------|--------------------------------|\n| Compose restart | `docker ps --format '{{.Names}}'` shows all 4: safety-core, comm-layer, isaac-sim, srr |\n| Safety Core chain alive | `ros2 topic echo \u002Fsafety\u002Fis_muted --once` exits 0 |\n| Scene loaded | `\u002Ftmp\u002Fisaac-scenario.log` contains `Action Graph built at \u002FWorld\u002FRTSPMultiGraph` + 3 `rtsp:\u002F\u002F` stream lines |\n| Perception ingesting | `docker logs vss-rtvi-cv --tail 50 \\| grep -o 'Active sources : [0-9]*' \\| tail -1` = 3 (Isaac markers go green even when DeepStream pulled nothing) |\n| Recording active | `ros2 service call \u002Fsrr\u002Frecord SetBool` returned `success: True` |\n| Recording done | The above plus parquet file size > 100 KB and incrementing stops |\n| Analysis done | `summary.md` exists with header `# SRR Aggregator — N clip(s)` matching expected clip count |\n| Videos pulled | `ls runs\u002Fmulti-test-...\u002F\u003Clabel>\u002Fvideos\u002F{,scenes\u002F}scn_*.mp4 \\| wc -l` ≥ expected clip count (both layouts) |\n| pss.log snapshot (per-scn) | `\u003Crun>\u002F\u003Clabel>\u002Fpss.log` exists and is > 100 KB |\n| pss.log concat (cross-run) | `\u003Crun>\u002Fpss.log` exists and `snapshot_pss` printed `concat N per-scn snapshot(s)` |\n| Evidence bundle | `\u003Crun>.zip` exists and `[clip_logs] wrote ...\u002Fmulti-test-...zip (X.X MB)` printed |\n| Viewer running | `view.sh` printed `Serving HTTP on 0.0.0.0 port 8765` |\n\n---\n\n## Workflow checklist\n\n```\n- [ ] 0. Required reading (skip on subsequent calls in same conversation):\n        hoisa-deploy-profile SKILL.md § Cleanup + Ready Signals + Critical Rules;\n        vss-deploy-profile SKILL.md Deployment Flow \u002F Tear Down (references\u002Fteardown.md)\n        → see \"Phase 0 — Required reading\" above\n- [ ] 1. Generate test plan: parse user request → list of scenarios + durations\n        → references\u002F01_test_plan.md\n- [ ] 2. Pre-check: Halos + SRR compose state, ROS topics, opcua port\n        → references\u002F02_launch.md\n    - [ ] 2.−2 **SRR image freshness** (compare host srr-service\u002Fsrr\u002F*.py vs container \u002Fapp\u002Fsrr\u002F) — rebuild or `docker cp` if stale. **MUST happen before first scenario** — a stale image is a common root cause of clip_logs missing + vst_video wrong-path.\n              → references\u002F02_launch.md Step 3.−2\n    - [ ] 2.−1 SRR fixtures synced (one-time) → references\u002F02_launch.md Step 3.−1\n- [ ] 2.0 **Once, before the scenario loop** (run_multi does these automatically):\n        - stop **nvstreamer** so Isaac is the SOLE camera source (the VSS sample-video\n          player publishes the same camera names → churns SDR provisioning + false-positives\n          the scene-ready gate). Stays down for the whole run.\n        - clear stale `\u002Fapp\u002Fruns\u002Frun-*.parquet` stragglers (a leftover from an aborted run\n          can have a newer mtime than a fresh recording and get mis-attributed to scenario 1).\n- [ ] 3. Per scenario (loop):\n    - [ ] 3.0 **First scenario only, optional**: fresh-start `cleanup_all_datalog.sh`\n              (truncates pss.log + wipes comm-layer\u002F — never run between scenarios)\n              → references\u002F02_launch.md Step 3.0\n    - [ ] 3a. Halos compose down\u002Fup + verify (NO cleanup_all_datalog.sh here).\n              **While Isaac is down**, purge ALL VST sensors (`vst_sensor_manager.py --delete-all`)\n              so the next Isaac registration lands in a clean VST — stale dup sensors otherwise\n              pile up across restarts and the SDR never provisions perception (empty parquet from\n              scenario 2 on). run_multi's `phase_vst_purge` does this.\n    - [ ] 3a.5 **VST API gate** (record API 200 + ≤3 online Camera sensors) — HARD GATE, fail → abort\n    - [ ] 3b. SRR compose down\u002Fup + verify\n    - [ ] 3c. Select scenario behavior trees + set simulation_duration (see 02_launch Step 3c\u002F3c.1)\n    - [ ] 3d. Start scene in isaac-sim (--start --headless --enable-vst)\n    - [ ] 3e. Wait for shaders + 3 RTSP streams ready\n    - [ ] 3f. Launch live_clip_monitor.py (background — known-broken; see 03_monitor.md)\n    - [ ] 3f.5 Safety Core warm-up 30 s\n    - [ ] 3f.7 **VSS perception health gate** (FPS ≥ 5 on 3 cams + the scene-ready topic decoding real detections > 0 — `mdx-raw` for 2D \u002F `mdx-bev` for 3D, per VSS MODE; `mdx-events` flowing confirms the BA→SRR Phase-1 path) — HARD GATE, fail → abort\n    - [ ] 3g. \u002Fsrr\u002Frecord SetBool true\n    - [ ] 3h. Sleep RECORD_S (with BA event + perception FPS heartbeat)\n    - [ ] 3i. \u002Fsrr\u002Frecord SetBool false\n    - [ ] 3j. Kill live_clip_monitor.py\n    - [ ] 3k. Phase 4 analyze (per-scn, **DO BEFORE next iter's 3a**):\n              move parquet → **`sudo chmod -R a+rwX \u003Cscn-host-dir>`** (docker mkdir creates root-owned dir on bind-mount) → **snapshot_pss.sh --per-scn** → tw_split → aggregator → **vst_video.split-run** (Step 4a VST timeline probe before pull) → flatten `videos\u002Fscenes\u002F*.mp4` to `videos\u002F` if stale-image fallback\n              — 04_analyze.md. Batching these to end-of-multi-test loses pss.log (next 3a truncates) + MP4s (Isaac removes VST sensors after sim_length)\n    - [ ] 3l. Verify: summary.md row count == expected clip count + NO validity-guard banner — `PERCEPTION_LIKELY_DEAD` (pooled or per-scenario `… in \u003Crun>`), `PSF_FEED_DEAD`, `PSF feed gaps`, `GT_FROZEN`, or `N clip(s) failed analysis`. Any of these = headline metrics UNTRUSTWORTHY. **This is a SECONDARY net** — 3f.7's FPS ≥ 5 hard-gate is the primary defense against dead perception: a single stray true-positive detection anywhere in the run flips the aggregator's `phase2_alive` check and downgrades the red `PERCEPTION_LIKELY_DEAD` banner to a soft note, so \"no banner\" alone is NOT proof of live perception — 3f.7 must have passed too\n- [ ] 4. Cross-run rollup → references\u002F05_report.md\n    - [ ] 4a. Concat per-scn pss.log → `\u003Cruns-base>\u002Fpss.log` (`snapshot_pss.sh` cross-run mode)\n    - [ ] 4b. aggregator `--top-level` → top-level summary.md (idempotent — re-run is safe)\n    - [ ] 4c. Extract headline metrics + print demo log final block\n- [ ] 5. Interpret + answer user questions about the report\n        → references\u002F06_interpret_report.md\n- [ ] 6. Post-process — references\u002F05_report.md Step 6:\n    - [ ] 6a. `clip_logs --zip` → per-clip evidence + `\u003Cruns-base>.zip` self-contained bundle\n    - [ ] 6b. **ASK user**: launch debug viewer? `[y\u002Fn]`\n    - [ ] 6c. If yes: clone srr-debug-viewer if missing → symlink run into `data\u002F` → **(optional) update `data\u002Findex.json`** (prepend new run for stable ordering; the HTTP directory-listing fallback discovers runs without it — see [05_report.md](references\u002F05_report.md) Step 6) → **pre-check port 8765** (ASK reuse\u002Fkill\u002Fother-port if busy) → `view.sh` → surface URL\n    - [ ] 6d. **Optional, on request**: spatial perception heatmaps + coverage polygons\n              (requires `clip_logs` CSVs first; scripts + matplotlib are baked into the srr image):\n              `render_perception_heatmap.py` (add `--density` for occupancy, `--fov-mask` to\n              clip to calibrated FOV) → `perception_heatmaps[_fovmask]\u002F`;\n              `render_coverage_polygons.py` → `coverage_polygons\u002F`. → references\u002F05_report.md Step 6e\n    - [ ] 6e. Print final paths block (summary, reports, videos, zip, pss.log, heatmaps).\n```\n\nMark each box as it completes. Print `[ok]` or `[fail]` per check.\n\n---\n\n## Reference Documents\n\n| Document | Use When |\n|----------|----------|\n| [references\u002F01_test_plan.md](references\u002F01_test_plan.md) | Selecting scenarios, validating Halos + SRR compose are deployed |\n| [references\u002F02_launch.md](references\u002F02_launch.md) | Per-scenario launch — compose restart, scene start, `\u002Fsrr\u002Frecord true` |\n| [references\u002F03_monitor.md](references\u002F03_monitor.md) | Live recording monitor — forklift TW crossing detection, demo log lines |\n| [references\u002F04_analyze.md](references\u002F04_analyze.md) | Post-recording: tw_split + aggregator + per-clip video pull |\n| [references\u002F05_report.md](references\u002F05_report.md) | Cross-run rollup → top-level summary.md + headline metrics |\n| [references\u002F06_interpret_report.md](references\u002F06_interpret_report.md) | **Read before answering anything about the report.** What every metric means, common patterns, drill-down workflow for FAIL clips |\n\n### Related docs\n\nUser-facing + companion docs elsewhere in the repo:\n\n| Document | Use When |\n|---|---|\n| [`references\u002F06_interpret_report.md`](references\u002F06_interpret_report.md) | What every Phase 1 \u002F Phase 2 number means + the FAIL-clip drill-down workflow. Read before answering perception-metric questions. Formula source of truth: `srr-service\u002Fsrr\u002Faggregator.py` → `compute_phase2_metrics`. |\n| [`..\u002F..\u002Ftools\u002Fsrr-debug-viewer\u002FREADME.md`](..\u002F..\u002Ftools\u002Fsrr-debug-viewer\u002FREADME.md) | Browser viewer for per-clip MP4 + sync panels. Launched optionally in Phase 6c (see [05_report.md](references\u002F05_report.md) Step 6). |\n\n---\n\n## Critical constants\n\n| Constant | Source | Notes |\n|---|---|---|\n| `TW_X` (forklift trailer tripwire) | `$CALIBRATION_JSON` (`sensors[0].tripwires[0].wire.p1.x`); fallback 9.574 | clip boundary detector key; inside-side derived from `sensors[0].tripwires[0].direction` (falls back to legacy inside=+x if `direction` missing) |\n| `ROI` (work zone) | `$CALIBRATION_JSON`; fallback x ∈ [4.877, 9.574], y ∈ [-18.976, -11.239] | rectangular polygon |\n| `SAMPLE_HZ` | 30 (built-in) | SRR recording rate |\n| `PADDING_SEC` | 1.0 (built-in) | tw_split clip-boundary padding (BA TW events at x≈10.2-10.6 land in in-trailer half) |\n| `ROS_DOMAIN_ID` | `$ROS_DOMAIN_ID` (Halos `.env`, default 74) | must match between containers and host probes; multi-machine on same LAN: each machine MUST have a unique ID — see `hoisa-deploy-profile\u002Freferences\u002Ftroubleshooting.md` (ROS_DOMAIN_ID collision \u002F `Publisher count` > 1) |\n| `VST_BASE_URL` | `$VST_BASE_URL` (Halos `.env`, e.g. `http:\u002F\u002F\u003CHOST_IP>:30888\u002Fvst\u002Fapi`) | base for sensor\u002Frecord\u002Fstorage endpoints. **`\u002Fvst\u002Fapi\u002Fv1\u002F...` is the API**; `\u002Fvst\u002F...` (no `\u002Fapi`) returns the SPA HTML and is meaningless for probes |\n| `SENSORS` | `$SENSORS` (SRR `.env`, default `Camera,Camera_01,Camera_02`) | VSS sensor names; not in calib.json |\n| `BEV_TOPIC` | `$BEV_TOPIC` (default `mdx-bev`) | Kafka topic for 3D detections (Sparse4D `bbox3d`). Empty string disables the Phase 2 detection consumer |\n| `BEHAVIOR_TOPIC` | `$BEHAVIOR_TOPIC` (default `mdx-behavior`) | Kafka topic for BA track positions. Empty string disables the BA-position consumer |\n| `SAMPLE_HZ` (3D too) | 30 (built-in, `service.py`) | mdx-bev is **replace-not-append** per tick; mdx-behavior kept per `track_id` with `BA_POS_TTL_S=1.0` |\n| `gate_m` | 1.5 m (built-in, `aggregator.py`) | nearest-GT match gate for detect-fail \u002F recall. Multi-gate recall also reported @0.5\u002F1.0\u002F1.5 m |\n| `coverage_pad_m` | **0.0** (built-in) | coverage = convex hull of detections, pad=0 (a nonzero pad over-reports detect-fail by counting out-of-FOV GT as misses) |\n| `boundary_m` | 2.0 m (built-in) | forklift trailer-boundary slice (within 2 m perpendicular distance of the tripwire line) |\n| `split_dist_m` | 1.0 m (built-in) | same-class split\u002Ffragmentation threshold |\n| forklift GT origin offset | estimated per-run (~0.39 m → ~0.08 m residual) | GT `body` TF is behind the 3D-box centre; aggregator infers + removes the bias before matching |\n| Repo root | `$HOISA_ROOT_PATH` (REQUIRED) | halos-outside-in-safety repo root — everything below derives from it |\n| ⤷ deployment dir | `$HOISA_ROOT_PATH\u002Fdeployments` | compose.yaml + profiles\u002F |\n| ⤷ profile env | `$HOISA_ROOT_PATH\u002Fdeployments\u002Fprofiles\u002Fsil.env` | source of all shared values |\n| ⤷ Isaac SIL dir | `$HOISA_ROOT_PATH\u002Fclosed-loop-testing\u002Fisaac-sim\u002Fsil` | scenes\u002Fconfigs\u002Fbehavior-trees\u002Fscripts |\n| SRR service dir | `${SRR_PIPELINE_DIR}\u002Fsrr-service\u002F` | where to `docker compose up` |\n| Output base | `${RUNS_HOST_DIR:-${SRR_PIPELINE_DIR}\u002Fsrr-service\u002Fruns}\u002Fmulti-test-YYYYMMDD-HHMMSS\u002F` | per-scenario subdirs containing `scenes\u002F`, `videos\u002F`, `reports\u002F` |\n| Top-level summary | `\u003Coutput-base>\u002Fsummary.md` | cross-run rollup, written by aggregator `--top-level` |\n\n> All host paths above resolve from the repo's `.env` (which sets `HOISA_ROOT_PATH`; scripts source the derived profile env for shared values). Skill scripts self-locate via `$(dirname \"$0\")` — no absolute path is baked into them.\n\n---\n\n## Cleanup\n\n```bash\n# After multi-test, leave containers running for inspection.\n# Only tear down when explicitly asked.\n\n# To free disk space (drop old runs — videos now live inside the run dir):\nrm -rf ${RUNS_HOST_DIR}\u002Fmulti-test-OLDDATE\n```\n\n---\n\n### When VSS is corrupted (sensor\u002Fadd 400, record API 503)\n\nThe VST postgres DB persists across `docker compose down` (mounted volume\nat `${MDX_DATA_DIR}\u002Fdata_log\u002Fvst`, ~30 GB). `down` + `up` alone will NOT\nclear stale `online` Camera sensors — Isaac will get 400 on `sensor\u002Fadd`\nand the next run will produce ghost results (see\n[`06_interpret_report.md`](references\u002F06_interpret_report.md) — ghost-result\nsection).\n\n**Symptoms** (any of):\n- `\u002Fvst\u002Fapi\u002Fv1\u002Frecord\u002Fstreams` returns 503 (envoy upstream connection failure)\n- Isaac log: `[Error] [vst_sensor_manager] ✗ Failed to add sensor Camera: 400 Client Error`\n- `$PERCEPTION` (`vss-rtvi-cv`; legacy `perception-2d`\u002F`-3d`) PERF lines all show FPS 0.00000\n- Aggregator emits `🚫 PERCEPTION_LIKELY_DEAD` banner\n\n**Reset recipe** (idempotent — safe to rerun):\n\n```bash\n# 1. Stop VSS Warehouse\ncd ${WAREHOUSE_DIR:-\u002Fpath\u002Fto\u002Fvss-warehouse}\ndocker compose --env-file warehouse\u002F.env down\n\n# 2. Wipe accumulated data (postgres, kafka, elastic, redis, vst recordings)\nbash .\u002Fcleanup_all_datalog.sh -b warehouse\n\n# 3. Start VSS Warehouse fresh\ndocker compose --env-file warehouse\u002F.env up -d\n\n# 4. After VSS is healthy, delete any auto-registered Camera\u002FCamera_01\u002FCamera_02\n#    that nvstreamer creates from default config (otherwise Isaac sensor\u002Fadd 400)\nfor SID in $(curl -sf \"${VST_BASE_URL}\u002Fv1\u002Fsensor\u002Flist\" \\\n              | jq -r '.[] | select(.state==\"online\") | select(.name | test(\"^Camera(_0[12])?$\")) | .sensorId'); do\n  curl -sf -X DELETE \"${VST_BASE_URL}\u002Fv1\u002Fsensor\u002F${SID}\"\ndone\n\n# 5. Restart Halos compose so Isaac re-registers fresh sensors\ncd ${HOISA_ROOT_PATH}\u002Fdeployments\ndocker compose --env-file ${HOISA_ROOT_PATH}\u002Fdeployments\u002Fprofiles\u002Fsil.env down && docker compose --env-file ${HOISA_ROOT_PATH}\u002Fdeployments\u002Fprofiles\u002Fsil.env up -d\n```\n\nFor full warehouse lifecycle (NGC artifact download, env config, etc.) see the\n`vss-deploy-profile` skill — Deployment Flow + `references\u002Fteardown.md`.\n\nFor full Halos lifecycle (safety-core, comm-layer, Isaac scene config) see the\n`hoisa-deploy-profile` skill (`skills\u002Fhoisa-deploy-profile\u002FSKILL.md`).\n\n",{"data":35,"body":38},{"name":4,"description":6,"metadata":36},{"author":9,"version":37},"1.3.0",{"type":39,"children":40},"root",[41,50,56,144,183,187,194,235,243,401,409,496,515,518,524,544,701,764,769,821,858,876,886,939,960,972,984,987,993,1002,1010,1101,1171,1226,1292,1302,1305,1311,1316,1325,1368,1381,1384,1390,1407,1791,1796,2039,2049,2058,2093,2102,2208,2211,2217,2222,2520,2523,2529,2538,2559,2562,2568,2694,2701,2706,2784,2787,2793,3562,3593,3596,3602,3678,3681,3687,3749,3759,3827,3837,4329,4347,4365],{"type":42,"tag":43,"props":44,"children":46},"element","h1",{"id":45},"srr-skill-multi-scenario-test-pipeline",[47],{"type":48,"value":49},"text","SRR Skill — Multi-scenario Test Pipeline",{"type":42,"tag":51,"props":52,"children":53},"p",{},[54],{"type":48,"value":55},"When this skill is active:",{"type":42,"tag":57,"props":58,"children":59},"ol",{},[60,80,99,109,119],{"type":42,"tag":61,"props":62,"children":63},"li",{},[64,70,72,78],{"type":42,"tag":65,"props":66,"children":67},"strong",{},[68],{"type":48,"value":69},"ALWAYS read the relevant reference doc",{"type":48,"value":71}," in ",{"type":42,"tag":73,"props":74,"children":76},"a",{"href":75},"references\u002F",[77],{"type":48,"value":75},{"type":48,"value":79}," before running shell commands for that phase.",{"type":42,"tag":61,"props":81,"children":82},{},[83,88,90,97],{"type":42,"tag":65,"props":84,"children":85},{},[86],{"type":48,"value":87},"Use Explore agents to verify ready signals",{"type":48,"value":89}," instead of fixed ",{"type":42,"tag":91,"props":92,"children":94},"code",{"className":93},[],[95],{"type":48,"value":96},"sleep",{"type":48,"value":98}," timers. Spawn one short-lived agent per phase boundary check (compose-up, scene-load, recording-active, analysis-done). This avoids long blocking waits and lets the agent diagnose if a check fails.",{"type":42,"tag":61,"props":100,"children":101},{},[102,107],{"type":42,"tag":65,"props":103,"children":104},{},[105],{"type":48,"value":106},"Print demo-friendly log lines",{"type":48,"value":108}," at every phase boundary (format spec below).",{"type":42,"tag":61,"props":110,"children":111},{},[112,117],{"type":42,"tag":65,"props":113,"children":114},{},[115],{"type":48,"value":116},"Stop on real errors",{"type":48,"value":118}," — never silently retry. Surface the failure with a 1-line diagnosis from the verifying agent.",{"type":42,"tag":61,"props":120,"children":121},{},[122,135,137,142],{"type":42,"tag":65,"props":123,"children":124},{},[125,127,133],{"type":48,"value":126},"Cancel ",{"type":42,"tag":91,"props":128,"children":130},{"className":129},[],[131],{"type":48,"value":132},"ScheduleWakeup",{"type":48,"value":134}," calls when their trigger condition is resolved.",{"type":48,"value":136}," If you set a wakeup to retry a probe (e.g. Kafka mdx-events consume in Step 3f.7) and the probe passes or you recover via another path, ",{"type":42,"tag":65,"props":138,"children":139},{},[140],{"type":48,"value":141},"explicitly cancel the wakeup",{"type":48,"value":143}," before moving on. Stale wakeups can fire during Phase 6 (post-process) and confuse the agent into re-running probes against a torn-down state. One wakeup outstanding per probe maximum.",{"type":42,"tag":51,"props":145,"children":146},{},[147,149,155,157,162,164,174,176,181],{"type":48,"value":148},"This skill assumes the SIL + SRR stacks are already deployed and healthy on the host (see ",{"type":42,"tag":91,"props":150,"children":152},{"className":151},[],[153],{"type":48,"value":154},"hoisa-deploy-profile",{"type":48,"value":156}," skill for first-time setup), ",{"type":42,"tag":65,"props":158,"children":159},{},[160],{"type":48,"value":161},"and SRR fixtures (behavior trees, navmesh, Script-Editor utilities) have been synced into the Isaac SIL dir",{"type":48,"value":163}," via ",{"type":42,"tag":73,"props":165,"children":167},{"href":166},"..\u002F..\u002Fclosed-loop-testing\u002Fregression-reporter\u002Fhalos-integration\u002Fsync_to_halos.sh",[168],{"type":42,"tag":91,"props":169,"children":171},{"className":170},[],[172],{"type":48,"value":173},"halos-integration\u002Fsync_to_halos.sh",{"type":48,"value":175},". The skill's launch phase verifies this and offers to sync if missing — see ",{"type":42,"tag":73,"props":177,"children":179},{"href":178},"references\u002F02_launch.md",[180],{"type":48,"value":178},{"type":48,"value":182}," Step 3.−1.",{"type":42,"tag":184,"props":185,"children":186},"hr",{},[],{"type":42,"tag":188,"props":189,"children":191},"h2",{"id":190},"phase-0-required-reading-one-time-before-any-compose-work",[192],{"type":48,"value":193},"Phase 0 — Required reading (ONE-TIME, before any compose work)",{"type":42,"tag":51,"props":195,"children":196},{},[197,199,204,206,214,216,225,227,233],{"type":48,"value":198},"SRR runs ",{"type":42,"tag":65,"props":200,"children":201},{},[202],{"type":48,"value":203},"on top of",{"type":48,"value":205}," the SIL + VSS Warehouse stacks. Their lifecycle (clean-data-before-up, ready signals, redeploy procedure) is owned by the ",{"type":42,"tag":65,"props":207,"children":208},{},[209],{"type":42,"tag":91,"props":210,"children":212},{"className":211},[],[213],{"type":48,"value":154},{"type":48,"value":215}," and ",{"type":42,"tag":65,"props":217,"children":218},{},[219],{"type":42,"tag":91,"props":220,"children":222},{"className":221},[],[223],{"type":48,"value":224},"vss-deploy-profile",{"type":48,"value":226}," skills — NOT this skill. Before any ",{"type":42,"tag":91,"props":228,"children":230},{"className":229},[],[231],{"type":48,"value":232},"docker compose down\u002Fup",{"type":48,"value":234}," in Phase 3a or 3b, the agent MUST have read the relevant procedure from those skills, otherwise it will skip mandatory data cleanup and miss ready-signal gates.",{"type":42,"tag":51,"props":236,"children":237},{},[238],{"type":42,"tag":65,"props":239,"children":240},{},[241],{"type":48,"value":242},"Read these BEFORE running any compose command:",{"type":42,"tag":244,"props":245,"children":246},"table",{},[247,266],{"type":42,"tag":248,"props":249,"children":250},"thead",{},[251],{"type":42,"tag":252,"props":253,"children":254},"tr",{},[255,261],{"type":42,"tag":256,"props":257,"children":258},"th",{},[259],{"type":48,"value":260},"File",{"type":42,"tag":256,"props":262,"children":263},{},[264],{"type":48,"value":265},"Why",{"type":42,"tag":267,"props":268,"children":269},"tbody",{},[270,337,354],{"type":42,"tag":252,"props":271,"children":272},{},[273,308],{"type":42,"tag":274,"props":275,"children":276},"td",{},[277,283,285,291,293,299,300,306],{"type":42,"tag":91,"props":278,"children":280},{"className":279},[],[281],{"type":48,"value":282},"skills\u002Fhoisa-deploy-profile\u002FSKILL.md",{"type":48,"value":284}," § Cleanup, § Ready Signals, § Critical Rules (",{"type":42,"tag":91,"props":286,"children":288},{"className":287},[],[289],{"type":48,"value":290},"SETUP_BEFORE_UP",{"type":48,"value":292},", ",{"type":42,"tag":91,"props":294,"children":296},{"className":295},[],[297],{"type":48,"value":298},"VSS_BEFORE_HALOS",{"type":48,"value":292},{"type":42,"tag":91,"props":301,"children":303},{"className":302},[],[304],{"type":48,"value":305},"POLL_NEVER_WAIT",{"type":48,"value":307},")",{"type":42,"tag":274,"props":309,"children":310},{},[311,313,319,321,327,329,335],{"type":48,"value":312},"Defines ",{"type":42,"tag":91,"props":314,"children":316},{"className":315},[],[317],{"type":48,"value":318},"cleanup_all_datalog.sh",{"type":48,"value":320}," mandate before every ",{"type":42,"tag":91,"props":322,"children":324},{"className":323},[],[325],{"type":48,"value":326},"docker compose up",{"type":48,"value":328},", the ",{"type":42,"tag":91,"props":330,"children":332},{"className":331},[],[333],{"type":48,"value":334},"sil",{"type":48,"value":336},"-profile ready-signal set (safety-core, comm-layer, isaac-sim), VSS-must-come-up-first ordering",{"type":42,"tag":252,"props":338,"children":339},{},[340,349],{"type":42,"tag":274,"props":341,"children":342},{},[343],{"type":42,"tag":91,"props":344,"children":346},{"className":345},[],[347],{"type":48,"value":348},"skills\u002Fhoisa-deploy-profile\u002Freferences\u002Ftroubleshooting.md",{"type":42,"tag":274,"props":350,"children":351},{},[352],{"type":48,"value":353},"Failure recipes for \"compose up exits but services missing\", safety-core stuck, comm-layer dead. Consult before retrying a failed restart",{"type":42,"tag":252,"props":355,"children":356},{},[357,388],{"type":42,"tag":274,"props":358,"children":359},{},[360,365,367,373,374,380,381,387],{"type":42,"tag":91,"props":361,"children":363},{"className":362},[],[364],{"type":48,"value":224},{"type":48,"value":366}," skill (Deployment Flow \u002F Tear Down + ",{"type":42,"tag":91,"props":368,"children":370},{"className":369},[],[371],{"type":48,"value":372},"references\u002Fteardown.md",{"type":48,"value":292},{"type":42,"tag":91,"props":375,"children":377},{"className":376},[],[378],{"type":48,"value":379},"references\u002Fwarehouse.md",{"type":48,"value":292},{"type":42,"tag":91,"props":382,"children":384},{"className":383},[],[385],{"type":48,"value":386},"references\u002Fwarehouse-debug.md",{"type":48,"value":307},{"type":42,"tag":274,"props":389,"children":390},{},[391,393,399],{"type":48,"value":392},"VSS Warehouse teardown + data-volume wipe, deploy\u002Fbring-up flow, and perception ready signals (FPS check on ",{"type":42,"tag":91,"props":394,"children":396},{"className":395},[],[397],{"type":48,"value":398},"vss-rtvi-cv",{"type":48,"value":400},"). Needed when VSS is unhealthy and SRR's launch HARD GATE (3a.5 or 3f.7) fails",{"type":42,"tag":51,"props":402,"children":403},{},[404],{"type":42,"tag":65,"props":405,"children":406},{},[407],{"type":48,"value":408},"Quickly internalize:",{"type":42,"tag":57,"props":410,"children":411},{},[412,455,468],{"type":42,"tag":61,"props":413,"children":414},{},[415,423,425,430,432,438,440,446,448,453],{"type":42,"tag":65,"props":416,"children":417},{},[418],{"type":42,"tag":91,"props":419,"children":421},{"className":420},[],[422],{"type":48,"value":290},{"type":48,"value":424}," — ",{"type":42,"tag":91,"props":426,"children":428},{"className":427},[],[429],{"type":48,"value":318},{"type":48,"value":431}," is a one-time fresh start before the FIRST scenario only (truncates ",{"type":42,"tag":91,"props":433,"children":435},{"className":434},[],[436],{"type":48,"value":437},"psf-log\u002Fpss.log",{"type":48,"value":439}," + wipes ",{"type":42,"tag":91,"props":441,"children":443},{"className":442},[],[444],{"type":48,"value":445},"comm-layer\u002F",{"type":48,"value":447},"). ",{"type":42,"tag":65,"props":449,"children":450},{},[451],{"type":48,"value":452},"Never run it between scenarios",{"type":48,"value":454}," — it destroys the per-scn pss.log evidence. The per-scenario compose restart already truncates pss.log via Safety Core init.",{"type":42,"tag":61,"props":456,"children":457},{},[458,466],{"type":42,"tag":65,"props":459,"children":460},{},[461],{"type":42,"tag":91,"props":462,"children":464},{"className":463},[],[465],{"type":48,"value":298},{"type":48,"value":467}," — when restarting both stacks (e.g. VSS recovery from a 3a.5 gate fail): tear down Halos first, then VSS; bring up VSS first (wait for FPS green), then Halos. Only on VSS-side incident recovery, not per-scenario.",{"type":42,"tag":61,"props":469,"children":470},{},[471,479,480,486,488,494],{"type":42,"tag":65,"props":472,"children":473},{},[474],{"type":42,"tag":91,"props":475,"children":477},{"className":476},[],[478],{"type":48,"value":305},{"type":48,"value":424},{"type":42,"tag":91,"props":481,"children":483},{"className":482},[],[484],{"type":48,"value":485},"compose up --detach",{"type":48,"value":487}," exits before containers serve. Always poll ",{"type":42,"tag":91,"props":489,"children":491},{"className":490},[],[492],{"type":48,"value":493},"docker ps",{"type":48,"value":495}," + a service-specific ready check; never assume \"returned 0 → ready\".",{"type":42,"tag":51,"props":497,"children":498},{},[499,501,506,508,513],{"type":48,"value":500},"If a compose restart fails during Phase 3a\u002F3b, ",{"type":42,"tag":65,"props":502,"children":503},{},[504],{"type":48,"value":505},"stop and read the two troubleshooting docs above",{"type":48,"value":507}," before retrying. Do not just ",{"type":42,"tag":91,"props":509,"children":511},{"className":510},[],[512],{"type":48,"value":326},{"type":48,"value":514}," again.",{"type":42,"tag":184,"props":516,"children":517},{},[],{"type":42,"tag":188,"props":519,"children":521},{"id":520},"_6-pre-built-test-cases",[522],{"type":48,"value":523},"6 pre-built test cases",{"type":42,"tag":51,"props":525,"children":526},{},[527,529,535,536,542],{"type":48,"value":528},"All 6 use the stock scene ",{"type":42,"tag":91,"props":530,"children":532},{"className":531},[],[533],{"type":48,"value":534},"indicator_warehouse_20x20_layout_overflow_test.usd",{"type":48,"value":215},{"type":42,"tag":91,"props":537,"children":539},{"className":538},[],[540],{"type":48,"value":541},"--agent-radius 0.8",{"type":48,"value":543},".",{"type":42,"tag":244,"props":545,"children":546},{},[547,569],{"type":42,"tag":248,"props":548,"children":549},{},[550],{"type":42,"tag":252,"props":551,"children":552},{},[553,558,564],{"type":42,"tag":256,"props":554,"children":555},{},[556],{"type":48,"value":557},"Name",{"type":42,"tag":256,"props":559,"children":561},{"align":560},"right",[562],{"type":48,"value":563},"Length",{"type":42,"tag":256,"props":565,"children":566},{},[567],{"type":48,"value":568},"Stress focus",{"type":42,"tag":267,"props":570,"children":571},{},[572,593,613,639,660,681],{"type":42,"tag":252,"props":573,"children":574},{},[575,583,588],{"type":42,"tag":274,"props":576,"children":577},{},[578],{"type":42,"tag":65,"props":579,"children":580},{},[581],{"type":48,"value":582},"in-roi",{"type":42,"tag":274,"props":584,"children":585},{"align":560},[586],{"type":48,"value":587},"5 min",{"type":42,"tag":274,"props":589,"children":590},{},[591],{"type":48,"value":592},"Person stays inside work zone constantly (Safety Core \"person constantly present\" stress)",{"type":42,"tag":252,"props":594,"children":595},{},[596,604,608],{"type":42,"tag":274,"props":597,"children":598},{},[599],{"type":42,"tag":65,"props":600,"children":601},{},[602],{"type":48,"value":603},"psf-edge",{"type":42,"tag":274,"props":605,"children":606},{"align":560},[607],{"type":48,"value":587},{"type":42,"tag":274,"props":609,"children":610},{},[611],{"type":48,"value":612},"Person sits ON ROI boundary — tests hysteresis \u002F debounce",{"type":42,"tag":252,"props":614,"children":615},{},[616,624,628],{"type":42,"tag":274,"props":617,"children":618},{},[619],{"type":42,"tag":65,"props":620,"children":621},{},[622],{"type":48,"value":623},"psf-clear",{"type":42,"tag":274,"props":625,"children":626},{"align":560},[627],{"type":48,"value":587},{"type":42,"tag":274,"props":629,"children":630},{},[631,633,638],{"type":48,"value":632},"Person clearly inside or clearly outside (clean A\u002FB partner of ",{"type":42,"tag":91,"props":634,"children":636},{"className":635},[],[637],{"type":48,"value":603},{"type":48,"value":307},{"type":42,"tag":252,"props":640,"children":641},{},[642,650,655],{"type":42,"tag":274,"props":643,"children":644},{},[645],{"type":42,"tag":65,"props":646,"children":647},{},[648],{"type":48,"value":649},"balanced",{"type":42,"tag":274,"props":651,"children":652},{"align":560},[653],{"type":48,"value":654},"10 min",{"type":42,"tag":274,"props":656,"children":657},{},[658],{"type":48,"value":659},"Mixed activity, baseline pre-redraw scenario",{"type":42,"tag":252,"props":661,"children":662},{},[663,671,676],{"type":42,"tag":274,"props":664,"children":665},{},[666],{"type":42,"tag":65,"props":667,"children":668},{},[669],{"type":48,"value":670},"fast",{"type":42,"tag":274,"props":672,"children":673},{"align":560},[674],{"type":48,"value":675},"20 min",{"type":42,"tag":274,"props":677,"children":678},{},[679],{"type":48,"value":680},"Low idle, motion-heavy — tests cumulative drift over long run",{"type":42,"tag":252,"props":682,"children":683},{},[684,692,696],{"type":42,"tag":274,"props":685,"children":686},{},[687],{"type":42,"tag":65,"props":688,"children":689},{},[690],{"type":48,"value":691},"fixed",{"type":42,"tag":274,"props":693,"children":694},{"align":560},[695],{"type":48,"value":587},{"type":42,"tag":274,"props":697,"children":698},{},[699],{"type":48,"value":700},"Deterministic baseline — hand-authored waypoints (not randomized), person always in ROI. Reproducible regression anchor; use for unmute-direction checks, not mute% (mute untestable — always-present person). Waypoints NavMesh-validated at radius 0.8.",{"type":42,"tag":702,"props":703,"children":704},"blockquote",{},[705],{"type":42,"tag":51,"props":706,"children":707},{},[708,726,728,733,735,740,742,748,750,755,757,762],{"type":42,"tag":65,"props":709,"children":710},{},[711,717,718,724],{"type":42,"tag":91,"props":712,"children":714},{"className":713},[],[715],{"type":48,"value":716},"all",{"type":48,"value":215},{"type":42,"tag":91,"props":719,"children":721},{"className":720},[],[722],{"type":48,"value":723},"full",{"type":48,"value":725}," run the first 5 (the randomized sweep) only.",{"type":48,"value":727}," ",{"type":42,"tag":91,"props":729,"children":731},{"className":730},[],[732],{"type":48,"value":691},{"type":48,"value":734}," is\n",{"type":42,"tag":65,"props":736,"children":737},{},[738],{"type":48,"value":739},"opt-in",{"type":48,"value":741}," — select it explicitly (",{"type":42,"tag":91,"props":743,"children":745},{"className":744},[],[746],{"type":48,"value":747},"..\u002Fscripts\u002Frun_multi.sh fixed",{"type":48,"value":749},", or name it\nin the prompt). It's excluded from ",{"type":42,"tag":91,"props":751,"children":753},{"className":752},[],[754],{"type":48,"value":716},{"type":48,"value":756},"\u002F",{"type":42,"tag":91,"props":758,"children":760},{"className":759},[],[761],{"type":48,"value":723},{"type":48,"value":763}," because the person is always in\nROI (mute untestable → inflates the blended headline).",{"type":42,"tag":51,"props":765,"children":766},{},[767],{"type":48,"value":768},"Scenario waypoints — IRA 1.6 behavior trees (Isaac 6.0 dropped command files):",{"type":42,"tag":770,"props":771,"children":772},"ul",{},[773,793],{"type":42,"tag":61,"props":774,"children":775},{},[776,778,784,786,792],{"type":48,"value":777},"Canonical trees: ",{"type":42,"tag":91,"props":779,"children":781},{"className":780},[],[782],{"type":48,"value":783},"..\u002Fscenarios\u002Fbehavior-trees\u002Fsrr_{name}_char{0,1,2}.bt.json",{"type":48,"value":785},"\n(emitted directly by ",{"type":42,"tag":91,"props":787,"children":789},{"className":788},[],[790],{"type":48,"value":791},"..\u002Fscenarios\u002Ftools\u002Frandomize_paths.py",{"type":48,"value":307},{"type":42,"tag":61,"props":794,"children":795},{},[796,798,804,806,812,814,820],{"type":48,"value":797},"Synced (Isaac reads from here): ",{"type":42,"tag":91,"props":799,"children":801},{"className":800},[],[802],{"type":48,"value":803},"${HOISA_ROOT_PATH}\u002Fclosed-loop-testing\u002Fisaac-sim\u002Fsil\u002Fconfigs\u002Fsrr_char{0,1,2}.bt.json",{"type":48,"value":805},"\n(the active scenario; ",{"type":42,"tag":91,"props":807,"children":809},{"className":808},[],[810],{"type":48,"value":811},"run_multi.sh",{"type":48,"value":813}," swaps the selected scenario onto these\nfixed names. GitHub layout: ",{"type":42,"tag":91,"props":815,"children":817},{"className":816},[],[818],{"type":48,"value":819},"\u003Chalos-repo>\u002Fclosed-loop-testing\u002Fisaac-sim\u002Fsil\u002Fconfigs\u002F",{"type":48,"value":307},{"type":42,"tag":51,"props":822,"children":823},{},[824,826,832,834,840,842,848,850,856],{"type":48,"value":825},"The canonical scene + NavMesh live at ",{"type":42,"tag":91,"props":827,"children":829},{"className":828},[],[830],{"type":48,"value":831},"..\u002Fscenarios\u002Fscenes\u002F",{"type":48,"value":833},". To add or\nre-generate scenarios, run ",{"type":42,"tag":91,"props":835,"children":837},{"className":836},[],[838],{"type":48,"value":839},"..\u002Fscenarios\u002Ftools\u002Frandomize_paths.py --name \u003Cnew-name>",{"type":48,"value":841},"\n(writes ",{"type":42,"tag":91,"props":843,"children":845},{"className":844},[],[846],{"type":48,"value":847},"..\u002Fscenarios\u002Fbehavior-trees\u002Fsrr_\u003Cnew-name>_char{0,1,2}.bt.json",{"type":48,"value":849},"), then\nre-run ",{"type":42,"tag":91,"props":851,"children":853},{"className":852},[],[854],{"type":48,"value":855},"..\u002Fhalos-integration\u002Fsync_to_halos.sh",{"type":48,"value":857}," to push into the Isaac SIL tree.",{"type":42,"tag":51,"props":859,"children":860},{},[861,866,868,874],{"type":42,"tag":65,"props":862,"children":863},{},[864],{"type":48,"value":865},"Default recording duration: 5 minutes",{"type":48,"value":867}," for any scenario unless user overrides. The \"Length\" column above shows each scenario's ",{"type":42,"tag":869,"props":870,"children":871},"em",{},[872],{"type":48,"value":873},"natural",{"type":48,"value":875}," length, but 5 min is the default for demo \u002F regression — enough to surface most issues without burning wall clock.",{"type":42,"tag":51,"props":877,"children":878},{},[879,884],{"type":42,"tag":65,"props":880,"children":881},{},[882],{"type":48,"value":883},"User override syntax",{"type":48,"value":885}," (parse natural language):",{"type":42,"tag":770,"props":887,"children":888},{},[889,900,911,922],{"type":42,"tag":61,"props":890,"children":891},{},[892,898],{"type":42,"tag":91,"props":893,"children":895},{"className":894},[],[896],{"type":48,"value":897},"\"in-roi\"",{"type":48,"value":899},"                → 5 min (default)",{"type":42,"tag":61,"props":901,"children":902},{},[903,909],{"type":42,"tag":91,"props":904,"children":906},{"className":905},[],[907],{"type":48,"value":908},"\"balanced for 10 min\"",{"type":48,"value":910},"   → 10 min",{"type":42,"tag":61,"props":912,"children":913},{},[914,920],{"type":42,"tag":91,"props":915,"children":917},{"className":916},[],[918],{"type":48,"value":919},"\"fast at 3 minutes\"",{"type":48,"value":921},"     → 3 min",{"type":42,"tag":61,"props":923,"children":924},{},[925,931,933,938],{"type":42,"tag":91,"props":926,"children":928},{"className":927},[],[929],{"type":48,"value":930},"\"all at 5 min\"",{"type":48,"value":932},"          → 5 min for each of the 5 sweep scenarios (not ",{"type":42,"tag":91,"props":934,"children":936},{"className":935},[],[937],{"type":48,"value":691},{"type":48,"value":307},{"type":42,"tag":51,"props":940,"children":941},{},[942,944,950,952,958],{"type":48,"value":943},"When invoking ",{"type":42,"tag":91,"props":945,"children":947},{"className":946},[],[948],{"type":48,"value":949},"..\u002Fscripts\u002Frun_multi.sh",{"type":48,"value":951},", encode override as ",{"type":42,"tag":91,"props":953,"children":955},{"className":954},[],[956],{"type":48,"value":957},"name:seconds",{"type":48,"value":959},":",{"type":42,"tag":961,"props":962,"children":966},"pre",{"className":963,"code":965,"language":48},[964],"language-text","..\u002Fscripts\u002Frun_multi.sh in-roi:300 balanced:600 fast:180\n",[967],{"type":42,"tag":91,"props":968,"children":970},{"__ignoreMap":969},"",[971],{"type":48,"value":965},{"type":42,"tag":51,"props":973,"children":974},{},[975,977,982],{"type":48,"value":976},"User can request any subset, or ",{"type":42,"tag":91,"props":978,"children":980},{"className":979},[],[981],{"type":48,"value":716},{"type":48,"value":983}," for the full multi-test (still 5 min each unless overridden).",{"type":42,"tag":184,"props":985,"children":986},{},[],{"type":42,"tag":188,"props":988,"children":990},{"id":989},"architecture-one-scenario",[991],{"type":48,"value":992},"Architecture (one scenario)",{"type":42,"tag":961,"props":994,"children":997},{"className":995,"code":996,"language":48},[964],"[Isaac Sim] -- \u002Fgt\u002Fcharacter_*\u002Ftf, \u002Fgt\u002Fforklift\u002Ftf -----> [SRR rclpy]  (GT, the reference)\n            -- 3 RTSP cams (Isaac self-hosted) -> [VSS] --+--> Kafka mdx-events    --> [SRR consumer]  BA ROI\u002FTW events\n                                                  +--> Kafka mdx-bev       --> [SRR consumer]  3D detections (Sparse4D bbox3d)\n                                                  +--> Kafka mdx-behavior  --> [SRR consumer]  BA track positions\n                                                         [Safety Core]\n                                                          ↓ \u002Fsafety\u002F{is_muted,command,is_alarm}\n                                                          ↓\n                                                       [SRR rclpy subscribers]\n                                                          ↓ 30 Hz parquet (Phase 1 + Phase 2 columns)\n                                  \u002Fsrr\u002Frecord SetBool true|false (start\u002Fstop)\n",[998],{"type":42,"tag":91,"props":999,"children":1000},{"__ignoreMap":969},[1001],{"type":48,"value":996},{"type":42,"tag":51,"props":1003,"children":1004},{},[1005],{"type":42,"tag":65,"props":1006,"children":1007},{},[1008],{"type":48,"value":1009},"Two scoring layers in one recording:",{"type":42,"tag":770,"props":1011,"children":1012},{},[1013,1039],{"type":42,"tag":61,"props":1014,"children":1015},{},[1016,1021,1023,1029,1031,1037],{"type":42,"tag":65,"props":1017,"children":1018},{},[1019],{"type":48,"value":1020},"Phase 1 (Safety Core decision)",{"type":48,"value":1022}," — GT-expected-mute vs actual ",{"type":42,"tag":91,"props":1024,"children":1026},{"className":1025},[],[1027],{"type":48,"value":1028},"is_muted",{"type":48,"value":1030}," → ",{"type":42,"tag":91,"props":1032,"children":1034},{"className":1033},[],[1035],{"type":48,"value":1036},"match%",{"type":48,"value":1038},", mute\u002Funmute-correct%, reaction lag, BA ROI\u002FTW event detection.",{"type":42,"tag":61,"props":1040,"children":1041},{},[1042,1047,1049,1055,1057,1063,1065,1070,1072,1077,1079,1084,1086,1092,1093,1099],{"type":42,"tag":65,"props":1043,"children":1044},{},[1045],{"type":48,"value":1046},"Phase 2 (perception, 3D)",{"type":48,"value":1048}," — GT TF vs ",{"type":42,"tag":91,"props":1050,"children":1052},{"className":1051},[],[1053],{"type":48,"value":1054},"mdx-bev",{"type":48,"value":1056}," 3D detections + ",{"type":42,"tag":91,"props":1058,"children":1060},{"className":1059},[],[1061],{"type":48,"value":1062},"mdx-behavior",{"type":48,"value":1064}," positions → per-class ",{"type":42,"tag":65,"props":1066,"children":1067},{},[1068],{"type":48,"value":1069},"detect-fail%",{"type":48,"value":1071}," \u002F ",{"type":42,"tag":65,"props":1073,"children":1074},{},[1075],{"type":48,"value":1076},"tracking-loss%",{"type":48,"value":1078},", precision\u002Frecall\u002FF1, position offset-vs-jitter, id-switches, coverage. See ",{"type":42,"tag":73,"props":1080,"children":1082},{"href":1081},"references\u002F06_interpret_report.md",[1083],{"type":48,"value":1081},{"type":48,"value":1085}," (formula source of truth: ",{"type":42,"tag":91,"props":1087,"children":1089},{"className":1088},[],[1090],{"type":48,"value":1091},"srr-service\u002Fsrr\u002Faggregator.py",{"type":48,"value":1030},{"type":42,"tag":91,"props":1094,"children":1096},{"className":1095},[],[1097],{"type":48,"value":1098},"compute_phase2_metrics",{"type":48,"value":1100},").",{"type":42,"tag":702,"props":1102,"children":1103},{},[1104],{"type":42,"tag":51,"props":1105,"children":1106},{},[1107,1112,1114,1119,1120,1125,1127,1133,1134,1139,1141,1147,1149,1154,1156,1162,1164,1169],{"type":42,"tag":65,"props":1108,"children":1109},{},[1110],{"type":48,"value":1111},"Phase 2 depends on Sparse4D 3D detections flowing.",{"type":48,"value":1113}," VSS Warehouse 3.2.1 runs\nSparse4D in ",{"type":42,"tag":91,"props":1115,"children":1117},{"className":1116},[],[1118],{"type":48,"value":398},{"type":48,"value":1030},{"type":42,"tag":91,"props":1121,"children":1123},{"className":1122},[],[1124],{"type":48,"value":1054},{"type":48,"value":1126}," + ",{"type":42,"tag":91,"props":1128,"children":1130},{"className":1129},[],[1131],{"type":48,"value":1132},"vss-behavior-analytics",{"type":48,"value":1030},{"type":42,"tag":91,"props":1135,"children":1137},{"className":1136},[],[1138],{"type":48,"value":1062},{"type":48,"value":1140},",\nenabling Phase 2. A 2D-only feed (only ",{"type":42,"tag":91,"props":1142,"children":1144},{"className":1143},[],[1145],{"type":48,"value":1146},"mdx-events",{"type":48,"value":1148},") gives ",{"type":42,"tag":65,"props":1150,"children":1151},{},[1152],{"type":48,"value":1153},"Phase 1 only",{"type":48,"value":1155},":\n",{"type":42,"tag":91,"props":1157,"children":1159},{"className":1158},[],[1160],{"type":48,"value":1161},"detections_json",{"type":48,"value":1163}," is all-null and the Phase 2 section is omitted — expected, not\na failure. Availability is keyed off ",{"type":42,"tag":91,"props":1165,"children":1167},{"className":1166},[],[1168],{"type":48,"value":1054},{"type":48,"value":1170}," decoding detections (Step 3f.7 gate).",{"type":42,"tag":51,"props":1172,"children":1173},{},[1174,1176,1182,1183,1189,1191,1196,1197,1203,1204,1210,1211,1217,1218,1224],{"type":48,"value":1175},"The two new Kafka consumers (",{"type":42,"tag":91,"props":1177,"children":1179},{"className":1178},[],[1180],{"type":48,"value":1181},"BEV_TOPIC=mdx-bev",{"type":48,"value":292},{"type":42,"tag":91,"props":1184,"children":1186},{"className":1185},[],[1187],{"type":48,"value":1188},"BEHAVIOR_TOPIC=mdx-behavior",{"type":48,"value":1190},") add five parquet columns — ",{"type":42,"tag":91,"props":1192,"children":1194},{"className":1193},[],[1195],{"type":48,"value":1161},{"type":48,"value":292},{"type":42,"tag":91,"props":1198,"children":1200},{"className":1199},[],[1201],{"type":48,"value":1202},"tracker_state_json",{"type":48,"value":292},{"type":42,"tag":91,"props":1205,"children":1207},{"className":1206},[],[1208],{"type":48,"value":1209},"bev_frame_id",{"type":48,"value":292},{"type":42,"tag":91,"props":1212,"children":1214},{"className":1213},[],[1215],{"type":48,"value":1216},"bev_create_time",{"type":48,"value":292},{"type":42,"tag":91,"props":1219,"children":1221},{"className":1220},[],[1222],{"type":48,"value":1223},"ba_positions_json",{"type":48,"value":1225}," — all nullable, so a Phase-1-only deploy still works. Set either topic env to empty to disable that consumer.",{"type":42,"tag":51,"props":1227,"children":1228},{},[1229,1231,1237,1239,1245,1247,1253,1254,1260,1262,1268,1270,1276,1277,1283,1284,1290],{"type":48,"value":1230},"Per-scenario produces: 1 parquet → tw_split → N per-clip parquets → aggregator → ",{"type":42,"tag":91,"props":1232,"children":1234},{"className":1233},[],[1235],{"type":48,"value":1236},"summary.md",{"type":48,"value":1238}," (Phase 1 + Phase 2 sections) + ",{"type":42,"tag":91,"props":1240,"children":1242},{"className":1241},[],[1243],{"type":48,"value":1244},"failures.json",{"type":48,"value":1246}," + per-clip ",{"type":42,"tag":91,"props":1248,"children":1250},{"className":1249},[],[1251],{"type":48,"value":1252},"scn_*.md",{"type":48,"value":1246},{"type":42,"tag":91,"props":1255,"children":1257},{"className":1256},[],[1258],{"type":48,"value":1259},"scn_*.mp4",{"type":48,"value":1261}," auto-pulled from VST. Optional post-process: ",{"type":42,"tag":91,"props":1263,"children":1265},{"className":1264},[],[1266],{"type":48,"value":1267},"clip_logs",{"type":48,"value":1269}," evidence CSVs (incl. ",{"type":42,"tag":91,"props":1271,"children":1273},{"className":1272},[],[1274],{"type":48,"value":1275},"detections.csv",{"type":48,"value":1071},{"type":42,"tag":91,"props":1278,"children":1280},{"className":1279},[],[1281],{"type":48,"value":1282},"tracker_state.csv",{"type":48,"value":1071},{"type":42,"tag":91,"props":1285,"children":1287},{"className":1286},[],[1288],{"type":48,"value":1289},"ba_positions.csv",{"type":48,"value":1291},") and spatial heatmaps.",{"type":42,"tag":51,"props":1293,"children":1294},{},[1295,1300],{"type":42,"tag":65,"props":1296,"children":1297},{},[1298],{"type":48,"value":1299},"Clip semantics",{"type":48,"value":1301},": each forklift crossing of the trailer tripwire (inside-side; warehouse wire at x = 9.574) is a scene boundary. Consecutive boundaries delimit one clip (~40 s each). 5 min recording → ~7 clips, 10 min → ~15, 20 min → ~30.",{"type":42,"tag":184,"props":1303,"children":1304},{},[],{"type":42,"tag":188,"props":1306,"children":1308},{"id":1307},"demo-log-format-user-facing-output",[1309],{"type":48,"value":1310},"Demo log format (user-facing output)",{"type":42,"tag":51,"props":1312,"children":1313},{},[1314],{"type":48,"value":1315},"When running the skill, print exactly this format. The phases \u002F sections are anchors a demo video can cut around.",{"type":42,"tag":961,"props":1317,"children":1320},{"className":1318,"code":1319,"language":48},[964],"> Generating testing plan...\n  Selected: in-roi (5 min), psf-edge (5 min), balanced (10 min)\n  Total recording: 20 min   Estimated wall clock: ~50 min\n  Output base: \u002Fapp\u002Fruns\u002Fmulti-test-YYYYMMDD-HHMMSS\u002F\n\n> Planning complete.\n\n> Launching SIL test runs...\n\n  Test 1\u002F3 starts: in-roi (5 min)\n  [00:00] Halos compose restarting...\n  [02:48] Containers up (safety-core, comm-layer, isaac-sim, srr).\n  [02:48] \u002Fsafety\u002Fis_muted publishing — Safety Core chain alive.\n  [02:48] Scene loading...\n  [05:18] Scene loaded. Replicator generating data.\n  [05:18] \u002Fsrr\u002Frecord true → recording active.\n  [05:32] Clip 1: forklift exited trailer (x=8.51, t=00:14)\n  [06:00] Clip 2: forklift entered trailer (x=10.31, t=00:42)\n  [06:43] Clip 3: forklift exited trailer (x=8.46, t=01:25)\n  ...\n  [10:18] \u002Fsrr\u002Frecord false → recording stopped.\n  [10:18] tw_split running...\n  [10:21] tw_split: 7 clips identified.\n  [10:21] aggregator running...\n  [10:50] aggregator: match% avg 84.6, failures 2\u002F7.\n  [10:50] vst_video pulling per-clip MP4...\n  [11:35] 7 clip videos saved to runs\u002Fmulti-test-...\u002Fin-roi\u002Fvideos\u002F\n  Test 1\u002F3 completes.\n\n  Test 2\u002F3 starts: psf-edge (5 min)\n  ...\n  Test 2\u002F3 completes.\n\n  Test 3\u002F3 starts: balanced (10 min)\n  ...\n  Test 3\u002F3 completes.\n\n> All test runs complete.\n\n> Analyzing results...\n  Aggregating per-scenario summary.md → cross-run summary.md\n  Computing safety-critical unmute% per scenario...\n\n> Done. Top-level summary: \u002Fapp\u002Fruns\u002Fmulti-test-YYYYMMDD-HHMMSS\u002Fsummary.md\n  Total: 3 scenarios, 29 clips, 29 review videos, ~50 min wall clock.\n  Headline: in-roi 84.6%, psf-edge 95.6%, balanced 79.6% match.\n  Mute correct: 57.8% · Unmute correct: 89.1% (safety-critical direction)\n  BA detection: ROI 95.5% · TW IN\u002FOUT 100%\n  Perception (Phase 2): 🧍 detect-fail 2.5% \u002F tracking-loss 1.9% · 🚜 detect-fail 32.0% \u002F tracking-loss 29.1% · pos-offset 0.09 m\n",[1321],{"type":42,"tag":91,"props":1322,"children":1323},{"__ignoreMap":969},[1324],{"type":48,"value":1319},{"type":42,"tag":702,"props":1326,"children":1327},{},[1328],{"type":42,"tag":51,"props":1329,"children":1330},{},[1331,1333,1338,1340,1346,1348,1352,1354,1359,1361,1366],{"type":48,"value":1332},"The ",{"type":42,"tag":65,"props":1334,"children":1335},{},[1336],{"type":48,"value":1337},"Perception (Phase 2)",{"type":48,"value":1339}," line is present only when the 3D pipeline was\nactive (mdx-bev \u002F mdx-behavior flowing); a Phase-1-only run omits it. Pull the\nnumbers from the summary's ",{"type":42,"tag":91,"props":1341,"children":1343},{"className":1342},[],[1344],{"type":48,"value":1345},"## Phase 2 — perception",{"type":48,"value":1347}," block. See\n",{"type":42,"tag":73,"props":1349,"children":1350},{"href":1081},[1351],{"type":48,"value":1081},{"type":48,"value":1353}," for what\n",{"type":42,"tag":91,"props":1355,"children":1357},{"className":1356},[],[1358],{"type":48,"value":1069},{"type":48,"value":1360}," vs ",{"type":42,"tag":91,"props":1362,"children":1364},{"className":1363},[],[1365],{"type":48,"value":1076},{"type":48,"value":1367}," mean and the FAIL-clip drill-down.",{"type":42,"tag":51,"props":1369,"children":1370},{},[1371,1373,1379],{"type":48,"value":1372},"The \"Clip N\" lines come from the live forklift-TF monitor (",{"type":42,"tag":91,"props":1374,"children":1376},{"className":1375},[],[1377],{"type":48,"value":1378},"..\u002Fscripts\u002Flive_clip_monitor.py",{"type":48,"value":1380},"), printed at each TW crossing.",{"type":42,"tag":184,"props":1382,"children":1383},{},[],{"type":42,"tag":188,"props":1385,"children":1387},{"id":1386},"agent-autonomy-rules-agent-must-always-check-progress",[1388],{"type":48,"value":1389},"Agent autonomy rules — AGENT MUST ALWAYS CHECK PROGRESS",{"type":42,"tag":51,"props":1391,"children":1392},{},[1393,1398,1400,1405],{"type":42,"tag":65,"props":1394,"children":1395},{},[1396],{"type":48,"value":1397},"Core rule",{"type":48,"value":1399},": never run a ",{"type":42,"tag":91,"props":1401,"children":1403},{"className":1402},[],[1404],{"type":48,"value":96},{"type":48,"value":1406}," longer than 60 seconds without an Explore agent actively verifying that progress is happening. If the underlying process stalled (Safety Core crashed, isaac-sim hung, parquet stopped growing), we want to know in ≤60 s, not at the end of the timer.",{"type":42,"tag":702,"props":1408,"children":1409},{},[1410,1479,1758],{"type":42,"tag":51,"props":1411,"children":1412},{},[1413,1415,1420,1422,1430,1432,1438,1440,1445,1447,1455,1457,1463,1464,1470,1472,1477],{"type":48,"value":1414},"⚠️ ",{"type":42,"tag":65,"props":1416,"children":1417},{},[1418],{"type":48,"value":1419},"Resolve the perception + behavior container names first (VSS 3.2.1).",{"type":48,"value":1421}," On VSS\nWarehouse 3.2.1 the perception container is ",{"type":42,"tag":65,"props":1423,"children":1424},{},[1425],{"type":42,"tag":91,"props":1426,"children":1428},{"className":1427},[],[1429],{"type":48,"value":398},{"type":48,"value":1431}," (Sparse4D 3D warehouse,\n",{"type":42,"tag":91,"props":1433,"children":1435},{"className":1434},[],[1436],{"type":48,"value":1437},"DS_MODEL_FAMILY=sparse4d-warehouse",{"type":48,"value":1439},"; heavier ~12–14 FPS → floor ",{"type":42,"tag":65,"props":1441,"children":1442},{},[1443],{"type":48,"value":1444},"≥ 5",{"type":48,"value":1446},") and behavior\nanalytics is ",{"type":42,"tag":65,"props":1448,"children":1449},{},[1450],{"type":42,"tag":91,"props":1451,"children":1453},{"className":1452},[],[1454],{"type":48,"value":1132},{"type":48,"value":1456}," — the container names no longer carry a\n",{"type":42,"tag":91,"props":1458,"children":1460},{"className":1459},[],[1461],{"type":48,"value":1462},"-2d",{"type":48,"value":756},{"type":42,"tag":91,"props":1465,"children":1467},{"className":1466},[],[1468],{"type":48,"value":1469},"-3d",{"type":48,"value":1471}," suffix. ",{"type":42,"tag":65,"props":1473,"children":1474},{},[1475],{"type":48,"value":1476},"Don't hard-code any single name",{"type":48,"value":1478}," — resolve once, then pick the FPS floor:",{"type":42,"tag":961,"props":1480,"children":1484},{"className":1481,"code":1482,"language":1483,"meta":969,"style":969},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","PERCEPTION=$(docker ps --format '{{.Names}}' | grep -E '^(vss-rtvi-cv|perception-[23]d)$' | head -1)\nBEHAVIOR=$(docker ps --format '{{.Names}}' | grep -E '^(vss-behavior-analytics|vss-behavior-analytics-[23]d)$' | head -1)\ncase \"$PERCEPTION\" in vss-rtvi-cv|*-3d) FPS_MIN=5;; *) FPS_MIN=25;; esac\n","bash",[1485],{"type":42,"tag":91,"props":1486,"children":1487},{"__ignoreMap":969},[1488,1585,1663],{"type":42,"tag":1489,"props":1490,"children":1493},"span",{"class":1491,"line":1492},"line",1,[1494,1500,1506,1512,1518,1523,1528,1533,1538,1543,1548,1553,1557,1562,1566,1570,1575,1580],{"type":42,"tag":1489,"props":1495,"children":1497},{"style":1496},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[1498],{"type":48,"value":1499},"PERCEPTION",{"type":42,"tag":1489,"props":1501,"children":1503},{"style":1502},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[1504],{"type":48,"value":1505},"=$(",{"type":42,"tag":1489,"props":1507,"children":1509},{"style":1508},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[1510],{"type":48,"value":1511},"docker",{"type":42,"tag":1489,"props":1513,"children":1515},{"style":1514},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[1516],{"type":48,"value":1517}," ps",{"type":42,"tag":1489,"props":1519,"children":1520},{"style":1514},[1521],{"type":48,"value":1522}," --format",{"type":42,"tag":1489,"props":1524,"children":1525},{"style":1502},[1526],{"type":48,"value":1527}," '",{"type":42,"tag":1489,"props":1529,"children":1530},{"style":1514},[1531],{"type":48,"value":1532},"{{.Names}}",{"type":42,"tag":1489,"props":1534,"children":1535},{"style":1502},[1536],{"type":48,"value":1537},"'",{"type":42,"tag":1489,"props":1539,"children":1540},{"style":1502},[1541],{"type":48,"value":1542}," |",{"type":42,"tag":1489,"props":1544,"children":1545},{"style":1508},[1546],{"type":48,"value":1547}," grep",{"type":42,"tag":1489,"props":1549,"children":1550},{"style":1514},[1551],{"type":48,"value":1552}," -E",{"type":42,"tag":1489,"props":1554,"children":1555},{"style":1502},[1556],{"type":48,"value":1527},{"type":42,"tag":1489,"props":1558,"children":1559},{"style":1514},[1560],{"type":48,"value":1561},"^(vss-rtvi-cv|perception-[23]d)$",{"type":42,"tag":1489,"props":1563,"children":1564},{"style":1502},[1565],{"type":48,"value":1537},{"type":42,"tag":1489,"props":1567,"children":1568},{"style":1502},[1569],{"type":48,"value":1542},{"type":42,"tag":1489,"props":1571,"children":1572},{"style":1508},[1573],{"type":48,"value":1574}," head",{"type":42,"tag":1489,"props":1576,"children":1577},{"style":1514},[1578],{"type":48,"value":1579}," -1",{"type":42,"tag":1489,"props":1581,"children":1582},{"style":1502},[1583],{"type":48,"value":1584},")\n",{"type":42,"tag":1489,"props":1586,"children":1588},{"class":1491,"line":1587},2,[1589,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1643,1647,1651,1655,1659],{"type":42,"tag":1489,"props":1590,"children":1591},{"style":1496},[1592],{"type":48,"value":1593},"BEHAVIOR",{"type":42,"tag":1489,"props":1595,"children":1596},{"style":1502},[1597],{"type":48,"value":1505},{"type":42,"tag":1489,"props":1599,"children":1600},{"style":1508},[1601],{"type":48,"value":1511},{"type":42,"tag":1489,"props":1603,"children":1604},{"style":1514},[1605],{"type":48,"value":1517},{"type":42,"tag":1489,"props":1607,"children":1608},{"style":1514},[1609],{"type":48,"value":1522},{"type":42,"tag":1489,"props":1611,"children":1612},{"style":1502},[1613],{"type":48,"value":1527},{"type":42,"tag":1489,"props":1615,"children":1616},{"style":1514},[1617],{"type":48,"value":1532},{"type":42,"tag":1489,"props":1619,"children":1620},{"style":1502},[1621],{"type":48,"value":1537},{"type":42,"tag":1489,"props":1623,"children":1624},{"style":1502},[1625],{"type":48,"value":1542},{"type":42,"tag":1489,"props":1627,"children":1628},{"style":1508},[1629],{"type":48,"value":1547},{"type":42,"tag":1489,"props":1631,"children":1632},{"style":1514},[1633],{"type":48,"value":1552},{"type":42,"tag":1489,"props":1635,"children":1636},{"style":1502},[1637],{"type":48,"value":1527},{"type":42,"tag":1489,"props":1639,"children":1640},{"style":1514},[1641],{"type":48,"value":1642},"^(vss-behavior-analytics|vss-behavior-analytics-[23]d)$",{"type":42,"tag":1489,"props":1644,"children":1645},{"style":1502},[1646],{"type":48,"value":1537},{"type":42,"tag":1489,"props":1648,"children":1649},{"style":1502},[1650],{"type":48,"value":1542},{"type":42,"tag":1489,"props":1652,"children":1653},{"style":1508},[1654],{"type":48,"value":1574},{"type":42,"tag":1489,"props":1656,"children":1657},{"style":1514},[1658],{"type":48,"value":1579},{"type":42,"tag":1489,"props":1660,"children":1661},{"style":1502},[1662],{"type":48,"value":1584},{"type":42,"tag":1489,"props":1664,"children":1666},{"class":1491,"line":1665},3,[1667,1673,1678,1683,1688,1693,1698,1703,1707,1711,1716,1721,1726,1731,1736,1740,1744,1749,1753],{"type":42,"tag":1489,"props":1668,"children":1670},{"style":1669},"--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic",[1671],{"type":48,"value":1672},"case",{"type":42,"tag":1489,"props":1674,"children":1675},{"style":1502},[1676],{"type":48,"value":1677}," \"",{"type":42,"tag":1489,"props":1679,"children":1680},{"style":1496},[1681],{"type":48,"value":1682},"$PERCEPTION",{"type":42,"tag":1489,"props":1684,"children":1685},{"style":1502},[1686],{"type":48,"value":1687},"\"",{"type":42,"tag":1489,"props":1689,"children":1690},{"style":1669},[1691],{"type":48,"value":1692}," in",{"type":42,"tag":1489,"props":1694,"children":1695},{"style":1514},[1696],{"type":48,"value":1697}," vss-rtvi-cv",{"type":42,"tag":1489,"props":1699,"children":1700},{"style":1502},[1701],{"type":48,"value":1702},"|*",{"type":42,"tag":1489,"props":1704,"children":1705},{"style":1514},[1706],{"type":48,"value":1469},{"type":42,"tag":1489,"props":1708,"children":1709},{"style":1502},[1710],{"type":48,"value":307},{"type":42,"tag":1489,"props":1712,"children":1713},{"style":1496},[1714],{"type":48,"value":1715}," FPS_MIN",{"type":42,"tag":1489,"props":1717,"children":1718},{"style":1502},[1719],{"type":48,"value":1720},"=",{"type":42,"tag":1489,"props":1722,"children":1723},{"style":1514},[1724],{"type":48,"value":1725},"5",{"type":42,"tag":1489,"props":1727,"children":1728},{"style":1502},[1729],{"type":48,"value":1730},";;",{"type":42,"tag":1489,"props":1732,"children":1733},{"style":1502},[1734],{"type":48,"value":1735}," *)",{"type":42,"tag":1489,"props":1737,"children":1738},{"style":1496},[1739],{"type":48,"value":1715},{"type":42,"tag":1489,"props":1741,"children":1742},{"style":1502},[1743],{"type":48,"value":1720},{"type":42,"tag":1489,"props":1745,"children":1746},{"style":1514},[1747],{"type":48,"value":1748},"25",{"type":42,"tag":1489,"props":1750,"children":1751},{"style":1502},[1752],{"type":48,"value":1730},{"type":42,"tag":1489,"props":1754,"children":1755},{"style":1669},[1756],{"type":48,"value":1757}," esac\n",{"type":42,"tag":51,"props":1759,"children":1760},{},[1761,1763,1768,1769,1775,1777,1782,1783,1789],{"type":48,"value":1762},"Every ",{"type":42,"tag":91,"props":1764,"children":1766},{"className":1765},[],[1767],{"type":48,"value":398},{"type":48,"value":1071},{"type":42,"tag":91,"props":1770,"children":1772},{"className":1771},[],[1773],{"type":48,"value":1774},"FPS ≥ 5",{"type":48,"value":1776}," reference below and in the reference docs means\n\"",{"type":42,"tag":91,"props":1778,"children":1780},{"className":1779},[],[1781],{"type":48,"value":1682},{"type":48,"value":1071},{"type":42,"tag":91,"props":1784,"children":1786},{"className":1785},[],[1787],{"type":48,"value":1788},"≥ $FPS_MIN",{"type":48,"value":1790},"\".",{"type":42,"tag":51,"props":1792,"children":1793},{},[1794],{"type":48,"value":1795},"This applies to every long wait in the workflow:",{"type":42,"tag":244,"props":1797,"children":1798},{},[1799,1825],{"type":42,"tag":248,"props":1800,"children":1801},{},[1802],{"type":42,"tag":252,"props":1803,"children":1804},{},[1805,1810,1815,1820],{"type":42,"tag":256,"props":1806,"children":1807},{},[1808],{"type":48,"value":1809},"Long wait",{"type":42,"tag":256,"props":1811,"children":1812},{},[1813],{"type":48,"value":1814},"What to verify each tick",{"type":42,"tag":256,"props":1816,"children":1817},{"align":560},[1818],{"type":48,"value":1819},"Tick interval",{"type":42,"tag":256,"props":1821,"children":1822},{"align":560},[1823],{"type":48,"value":1824},"Max patience",{"type":42,"tag":267,"props":1826,"children":1827},{},[1828,1861,1920,1951,2005],{"type":42,"tag":252,"props":1829,"children":1830},{},[1831,1842,1852,1857],{"type":42,"tag":274,"props":1832,"children":1833},{},[1834,1836],{"type":48,"value":1835},"Halos compose up after ",{"type":42,"tag":91,"props":1837,"children":1839},{"className":1838},[],[1840],{"type":48,"value":1841},"down",{"type":42,"tag":274,"props":1843,"children":1844},{},[1845,1850],{"type":42,"tag":91,"props":1846,"children":1848},{"className":1847},[],[1849],{"type":48,"value":493},{"type":48,"value":1851}," shows new container IDs for the services",{"type":42,"tag":274,"props":1853,"children":1854},{"align":560},[1855],{"type":48,"value":1856},"30 s",{"type":42,"tag":274,"props":1858,"children":1859},{"align":560},[1860],{"type":48,"value":587},{"type":42,"tag":252,"props":1862,"children":1863},{},[1864,1869,1911,1915],{"type":42,"tag":274,"props":1865,"children":1866},{},[1867],{"type":48,"value":1868},"Scene load + shader compile",{"type":42,"tag":274,"props":1870,"children":1871},{},[1872,1874,1880,1882,1888,1890,1896,1898,1903,1905],{"type":48,"value":1873},"Tail ",{"type":42,"tag":91,"props":1875,"children":1877},{"className":1876},[],[1878],{"type":48,"value":1879},"\u002Ftmp\u002Fisaac-scenario-\u003CTS>-\u003CLBL>.log",{"type":48,"value":1881},"; expect ",{"type":42,"tag":91,"props":1883,"children":1885},{"className":1884},[],[1886],{"type":48,"value":1887},"\u002FWorld\u002FRTSPMultiGraph",{"type":48,"value":1889}," built + 3 ",{"type":42,"tag":91,"props":1891,"children":1893},{"className":1892},[],[1894],{"type":48,"value":1895},"rtsp:\u002F\u002F",{"type":48,"value":1897}," stream lines, then ",{"type":42,"tag":91,"props":1899,"children":1901},{"className":1900},[],[1902],{"type":48,"value":398},{"type":48,"value":1904}," reporting ",{"type":42,"tag":91,"props":1906,"children":1908},{"className":1907},[],[1909],{"type":48,"value":1910},"Active sources : 3",{"type":42,"tag":274,"props":1912,"children":1913},{"align":560},[1914],{"type":48,"value":1856},{"type":42,"tag":274,"props":1916,"children":1917},{"align":560},[1918],{"type":48,"value":1919},"8 min (first), 3 min (subsequent)",{"type":42,"tag":252,"props":1921,"children":1922},{},[1923,1928,1941,1946],{"type":42,"tag":274,"props":1924,"children":1925},{},[1926],{"type":48,"value":1927},"Safety Core warm-up (30 s)",{"type":42,"tag":274,"props":1929,"children":1930},{},[1931,1933,1939],{"type":48,"value":1932},"Confirm ",{"type":42,"tag":91,"props":1934,"children":1936},{"className":1935},[],[1937],{"type":48,"value":1938},"\u002Fsafety\u002Fis_muted",{"type":48,"value":1940}," still publishing",{"type":42,"tag":274,"props":1942,"children":1943},{"align":560},[1944],{"type":48,"value":1945},"15 s",{"type":42,"tag":274,"props":1947,"children":1948},{"align":560},[1949],{"type":48,"value":1950},"90 s",{"type":42,"tag":252,"props":1952,"children":1953},{},[1954,1964,1992,2000],{"type":42,"tag":274,"props":1955,"children":1956},{},[1957,1962],{"type":42,"tag":65,"props":1958,"children":1959},{},[1960],{"type":48,"value":1961},"Recording window",{"type":48,"value":1963}," (5–20 min)",{"type":42,"tag":274,"props":1965,"children":1966},{},[1967,1969,1975,1977,1982,1984,1990],{"type":48,"value":1968},"Verify (a) parquet file size growing, (b) parquet ",{"type":42,"tag":91,"props":1970,"children":1972},{"className":1971},[],[1973],{"type":48,"value":1974},"ba_events_json",{"type":48,"value":1976}," rows > 0 (after 90 s), (c) ",{"type":42,"tag":91,"props":1978,"children":1980},{"className":1979},[],[1981],{"type":48,"value":1682},{"type":48,"value":1983}," FPS ≥ ",{"type":42,"tag":91,"props":1985,"children":1987},{"className":1986},[],[1988],{"type":48,"value":1989},"$FPS_MIN",{"type":48,"value":1991}," on all 3 cams (≥25 for 2D, ≥5 for 3D)",{"type":42,"tag":274,"props":1993,"children":1994},{"align":560},[1995],{"type":42,"tag":65,"props":1996,"children":1997},{},[1998],{"type":48,"value":1999},"60 s",{"type":42,"tag":274,"props":2001,"children":2002},{"align":560},[2003],{"type":48,"value":2004},"RECORD_S",{"type":42,"tag":252,"props":2006,"children":2007},{},[2008,2013,2031,2035],{"type":42,"tag":274,"props":2009,"children":2010},{},[2011],{"type":48,"value":2012},"Analysis (tw_split + aggregator + vst pull)",{"type":42,"tag":274,"props":2014,"children":2015},{},[2016,2022,2024,2029],{"type":42,"tag":91,"props":2017,"children":2019},{"className":2018},[],[2020],{"type":48,"value":2021},"ls scenes\u002Fscn_*.parquet",{"type":48,"value":2023}," count, ",{"type":42,"tag":91,"props":2025,"children":2027},{"className":2026},[],[2028],{"type":48,"value":1236},{"type":48,"value":2030}," size > 0, mp4 count",{"type":42,"tag":274,"props":2032,"children":2033},{"align":560},[2034],{"type":48,"value":1945},{"type":42,"tag":274,"props":2036,"children":2037},{"align":560},[2038],{"type":48,"value":587},{"type":42,"tag":51,"props":2040,"children":2041},{},[2042,2047],{"type":42,"tag":65,"props":2043,"children":2044},{},[2045],{"type":48,"value":2046},"Concretely",{"type":48,"value":2048}," — at every tick, spawn an Explore agent with a tight prompt like:",{"type":42,"tag":961,"props":2050,"children":2053},{"className":2051,"code":2052,"language":48},[964],"Quick health-check for SRR multi-test scenario \"\u003CLABEL>\" at T+\u003Celapsed>s of \u003CRECORD_S>s:\n\n1. `docker exec srr stat -c '%s' \u002Fapp\u002Fruns\u002Frun-*.parquet` — parquet size in bytes.\n   Should be growing tick-over-tick (rough rate: ~80 KB\u002Fmin).\n\n2. BA events flowing into the parquet:\n   docker exec srr python3 -c \"\n   import pandas as pd, glob\n   p = sorted(glob.glob('\u002Fapp\u002Fruns\u002Frun-*.parquet'))[-1]\n   df = pd.read_parquet(p)\n   print('rows:', len(df), 'ba_event_rows:', (df.ba_events_json != '[]').sum())\n   \"\n   After T+90s, ba_event_rows must be > 0. If 0, perception is dead.\n\n3. perception FPS still healthy (resolve container + threshold first):\n   PERCEPTION=$(docker ps --format '{{.Names}}' | grep -E '^(vss-rtvi-cv|perception-[23]d)$' | head -1)\n   case \"$PERCEPTION\" in vss-rtvi-cv|*-3d) FPS_MIN=5;; *) FPS_MIN=25;; esac\n   docker logs --since 60s \"$PERCEPTION\" 2>&1 | grep PERF -A1 | tail -5\n   Parse 3 FPS values from the most recent PERF block. ALL three must be ≥ $FPS_MIN\n   (≥25 on a 2D deploy, ≥5 on a 3D Sparse4D deploy).\n\nReport: parquet size, ba_event_rows, FPS triple. If parquet hasn't grown\nsince last tick OR ba_event_rows == 0 after T+90s OR any FPS \u003C $FPS_MIN, flag\nas STALLED.\n",[2054],{"type":42,"tag":91,"props":2055,"children":2056},{"__ignoreMap":969},[2057],{"type":48,"value":2052},{"type":42,"tag":51,"props":2059,"children":2060},{},[2061,2063,2068,2070,2076,2077,2083,2085,2091],{"type":48,"value":2062},"If the agent reports STALLED, ",{"type":42,"tag":65,"props":2064,"children":2065},{},[2066],{"type":48,"value":2067},"stop the recording phase",{"type":48,"value":2069}," and surface the\nissue. Do not let a hung scenario burn 20 minutes of wall clock. (Heartbeats use\nonly ",{"type":42,"tag":91,"props":2071,"children":2073},{"className":2072},[],[2074],{"type":48,"value":2075},"docker exec",{"type":48,"value":1071},{"type":42,"tag":91,"props":2078,"children":2080},{"className":2079},[],[2081],{"type":48,"value":2082},"docker logs",{"type":48,"value":2084}," — the host↔container DDS bridge is unreliable\nhere, so host ",{"type":42,"tag":91,"props":2086,"children":2088},{"className":2087},[],[2089],{"type":48,"value":2090},"ros2 topic hz",{"type":48,"value":2092}," probes can falsely read 0.)",{"type":42,"tag":51,"props":2094,"children":2095},{},[2096,2101],{"type":42,"tag":65,"props":2097,"children":2098},{},[2099],{"type":48,"value":2100},"Other rules",{"type":48,"value":959},{"type":42,"tag":57,"props":2103,"children":2104},{},[2105,2122,2156,2180,2190],{"type":42,"tag":61,"props":2106,"children":2107},{},[2108,2113,2115,2120],{"type":42,"tag":65,"props":2109,"children":2110},{},[2111],{"type":48,"value":2112},"Pre-check before recording",{"type":48,"value":2114},": containers Up + ",{"type":42,"tag":91,"props":2116,"children":2118},{"className":2117},[],[2119],{"type":48,"value":1938},{"type":48,"value":2121}," publishing + opcua 4840 listening. If any fails, do NOT start recording — diagnose first.",{"type":42,"tag":61,"props":2123,"children":2124},{},[2125,2130,2132,2138,2140,2146,2148,2154],{"type":42,"tag":65,"props":2126,"children":2127},{},[2128],{"type":48,"value":2129},"Background processes",{"type":48,"value":2131},": launch ",{"type":42,"tag":91,"props":2133,"children":2135},{"className":2134},[],[2136],{"type":48,"value":2137},"live_clip_monitor.py",{"type":48,"value":2139}," BEFORE ",{"type":42,"tag":91,"props":2141,"children":2143},{"className":2142},[],[2144],{"type":48,"value":2145},"\u002Fsrr\u002Frecord true",{"type":48,"value":2147},", kill it after ",{"type":42,"tag":91,"props":2149,"children":2151},{"className":2150},[],[2152],{"type":48,"value":2153},"\u002Fsrr\u002Frecord false",{"type":48,"value":2155},". Stream its stdout into the demo log.",{"type":42,"tag":61,"props":2157,"children":2158},{},[2159,2164,2166,2171,2173,2179],{"type":42,"tag":65,"props":2160,"children":2161},{},[2162],{"type":48,"value":2163},"Never declare a scenario \"done\"",{"type":48,"value":2165}," until the aggregator produced N rows in ",{"type":42,"tag":91,"props":2167,"children":2169},{"className":2168},[],[2170],{"type":48,"value":1236},{"type":48,"value":2172}," AND N per-clip videos exist (count files in ",{"type":42,"tag":91,"props":2174,"children":2176},{"className":2175},[],[2177],{"type":48,"value":2178},"runs\u002Fmulti-test-...\u002F\u003Clabel>\u002Fvideos\u002F",{"type":48,"value":1100},{"type":42,"tag":61,"props":2181,"children":2182},{},[2183,2188],{"type":42,"tag":65,"props":2184,"children":2185},{},[2186],{"type":48,"value":2187},"Cross-scenario isolation",{"type":48,"value":2189},": ALWAYS restart both Halos compose AND SRR compose between scenarios. Do not skip — Safety Core counter drift carries across runs and corrupts the next scenario's results.",{"type":42,"tag":61,"props":2191,"children":2192},{},[2193,2206],{"type":42,"tag":65,"props":2194,"children":2195},{},[2196,2198,2204],{"type":48,"value":2197},"Do NOT just ",{"type":42,"tag":91,"props":2199,"children":2201},{"className":2200},[],[2202],{"type":48,"value":2203},"bash ..\u002Fscripts\u002Frun_multi.sh ...",{"type":48,"value":2205}," in one shot",{"type":48,"value":2207},". The bash script is a reference\u002Ftemplate; the skill agent orchestrates step-by-step and inserts the verification agents between every phase. One-shot invocation skips the verification layer.",{"type":42,"tag":184,"props":2209,"children":2210},{},[],{"type":42,"tag":188,"props":2212,"children":2214},{"id":2213},"ready-signals",[2215],{"type":48,"value":2216},"Ready Signals",{"type":42,"tag":51,"props":2218,"children":2219},{},[2220],{"type":48,"value":2221},"Each phase ends when its ready signal becomes true. Poll, don't fix-time.",{"type":42,"tag":244,"props":2223,"children":2224},{},[2225,2241],{"type":42,"tag":248,"props":2226,"children":2227},{},[2228],{"type":42,"tag":252,"props":2229,"children":2230},{},[2231,2236],{"type":42,"tag":256,"props":2232,"children":2233},{},[2234],{"type":48,"value":2235},"Phase",{"type":42,"tag":256,"props":2237,"children":2238},{},[2239],{"type":48,"value":2240},"Ready signal (poll until true)",{"type":42,"tag":267,"props":2242,"children":2243},{},[2244,2263,2282,2316,2335,2360,2373,2399,2418,2437,2470,2496],{"type":42,"tag":252,"props":2245,"children":2246},{},[2247,2252],{"type":42,"tag":274,"props":2248,"children":2249},{},[2250],{"type":48,"value":2251},"Compose restart",{"type":42,"tag":274,"props":2253,"children":2254},{},[2255,2261],{"type":42,"tag":91,"props":2256,"children":2258},{"className":2257},[],[2259],{"type":48,"value":2260},"docker ps --format '{{.Names}}'",{"type":48,"value":2262}," shows all 4: safety-core, comm-layer, isaac-sim, srr",{"type":42,"tag":252,"props":2264,"children":2265},{},[2266,2271],{"type":42,"tag":274,"props":2267,"children":2268},{},[2269],{"type":48,"value":2270},"Safety Core chain alive",{"type":42,"tag":274,"props":2272,"children":2273},{},[2274,2280],{"type":42,"tag":91,"props":2275,"children":2277},{"className":2276},[],[2278],{"type":48,"value":2279},"ros2 topic echo \u002Fsafety\u002Fis_muted --once",{"type":48,"value":2281}," exits 0",{"type":42,"tag":252,"props":2283,"children":2284},{},[2285,2290],{"type":42,"tag":274,"props":2286,"children":2287},{},[2288],{"type":48,"value":2289},"Scene loaded",{"type":42,"tag":274,"props":2291,"children":2292},{},[2293,2299,2301,2307,2309,2314],{"type":42,"tag":91,"props":2294,"children":2296},{"className":2295},[],[2297],{"type":48,"value":2298},"\u002Ftmp\u002Fisaac-scenario.log",{"type":48,"value":2300}," contains ",{"type":42,"tag":91,"props":2302,"children":2304},{"className":2303},[],[2305],{"type":48,"value":2306},"Action Graph built at \u002FWorld\u002FRTSPMultiGraph",{"type":48,"value":2308}," + 3 ",{"type":42,"tag":91,"props":2310,"children":2312},{"className":2311},[],[2313],{"type":48,"value":1895},{"type":48,"value":2315}," stream lines",{"type":42,"tag":252,"props":2317,"children":2318},{},[2319,2324],{"type":42,"tag":274,"props":2320,"children":2321},{},[2322],{"type":48,"value":2323},"Perception ingesting",{"type":42,"tag":274,"props":2325,"children":2326},{},[2327,2333],{"type":42,"tag":91,"props":2328,"children":2330},{"className":2329},[],[2331],{"type":48,"value":2332},"docker logs vss-rtvi-cv --tail 50 | grep -o 'Active sources : [0-9]*' | tail -1",{"type":48,"value":2334}," = 3 (Isaac markers go green even when DeepStream pulled nothing)",{"type":42,"tag":252,"props":2336,"children":2337},{},[2338,2343],{"type":42,"tag":274,"props":2339,"children":2340},{},[2341],{"type":48,"value":2342},"Recording active",{"type":42,"tag":274,"props":2344,"children":2345},{},[2346,2352,2354],{"type":42,"tag":91,"props":2347,"children":2349},{"className":2348},[],[2350],{"type":48,"value":2351},"ros2 service call \u002Fsrr\u002Frecord SetBool",{"type":48,"value":2353}," returned ",{"type":42,"tag":91,"props":2355,"children":2357},{"className":2356},[],[2358],{"type":48,"value":2359},"success: True",{"type":42,"tag":252,"props":2361,"children":2362},{},[2363,2368],{"type":42,"tag":274,"props":2364,"children":2365},{},[2366],{"type":48,"value":2367},"Recording done",{"type":42,"tag":274,"props":2369,"children":2370},{},[2371],{"type":48,"value":2372},"The above plus parquet file size > 100 KB and incrementing stops",{"type":42,"tag":252,"props":2374,"children":2375},{},[2376,2381],{"type":42,"tag":274,"props":2377,"children":2378},{},[2379],{"type":48,"value":2380},"Analysis done",{"type":42,"tag":274,"props":2382,"children":2383},{},[2384,2389,2391,2397],{"type":42,"tag":91,"props":2385,"children":2387},{"className":2386},[],[2388],{"type":48,"value":1236},{"type":48,"value":2390}," exists with header ",{"type":42,"tag":91,"props":2392,"children":2394},{"className":2393},[],[2395],{"type":48,"value":2396},"# SRR Aggregator — N clip(s)",{"type":48,"value":2398}," matching expected clip count",{"type":42,"tag":252,"props":2400,"children":2401},{},[2402,2407],{"type":42,"tag":274,"props":2403,"children":2404},{},[2405],{"type":48,"value":2406},"Videos pulled",{"type":42,"tag":274,"props":2408,"children":2409},{},[2410,2416],{"type":42,"tag":91,"props":2411,"children":2413},{"className":2412},[],[2414],{"type":48,"value":2415},"ls runs\u002Fmulti-test-...\u002F\u003Clabel>\u002Fvideos\u002F{,scenes\u002F}scn_*.mp4 | wc -l",{"type":48,"value":2417}," ≥ expected clip count (both layouts)",{"type":42,"tag":252,"props":2419,"children":2420},{},[2421,2426],{"type":42,"tag":274,"props":2422,"children":2423},{},[2424],{"type":48,"value":2425},"pss.log snapshot (per-scn)",{"type":42,"tag":274,"props":2427,"children":2428},{},[2429,2435],{"type":42,"tag":91,"props":2430,"children":2432},{"className":2431},[],[2433],{"type":48,"value":2434},"\u003Crun>\u002F\u003Clabel>\u002Fpss.log",{"type":48,"value":2436}," exists and is > 100 KB",{"type":42,"tag":252,"props":2438,"children":2439},{},[2440,2445],{"type":42,"tag":274,"props":2441,"children":2442},{},[2443],{"type":48,"value":2444},"pss.log concat (cross-run)",{"type":42,"tag":274,"props":2446,"children":2447},{},[2448,2454,2456,2462,2464],{"type":42,"tag":91,"props":2449,"children":2451},{"className":2450},[],[2452],{"type":48,"value":2453},"\u003Crun>\u002Fpss.log",{"type":48,"value":2455}," exists and ",{"type":42,"tag":91,"props":2457,"children":2459},{"className":2458},[],[2460],{"type":48,"value":2461},"snapshot_pss",{"type":48,"value":2463}," printed ",{"type":42,"tag":91,"props":2465,"children":2467},{"className":2466},[],[2468],{"type":48,"value":2469},"concat N per-scn snapshot(s)",{"type":42,"tag":252,"props":2471,"children":2472},{},[2473,2478],{"type":42,"tag":274,"props":2474,"children":2475},{},[2476],{"type":48,"value":2477},"Evidence bundle",{"type":42,"tag":274,"props":2479,"children":2480},{},[2481,2487,2488,2494],{"type":42,"tag":91,"props":2482,"children":2484},{"className":2483},[],[2485],{"type":48,"value":2486},"\u003Crun>.zip",{"type":48,"value":2455},{"type":42,"tag":91,"props":2489,"children":2491},{"className":2490},[],[2492],{"type":48,"value":2493},"[clip_logs] wrote ...\u002Fmulti-test-...zip (X.X MB)",{"type":48,"value":2495}," printed",{"type":42,"tag":252,"props":2497,"children":2498},{},[2499,2504],{"type":42,"tag":274,"props":2500,"children":2501},{},[2502],{"type":48,"value":2503},"Viewer running",{"type":42,"tag":274,"props":2505,"children":2506},{},[2507,2513,2514],{"type":42,"tag":91,"props":2508,"children":2510},{"className":2509},[],[2511],{"type":48,"value":2512},"view.sh",{"type":48,"value":2463},{"type":42,"tag":91,"props":2515,"children":2517},{"className":2516},[],[2518],{"type":48,"value":2519},"Serving HTTP on 0.0.0.0 port 8765",{"type":42,"tag":184,"props":2521,"children":2522},{},[],{"type":42,"tag":188,"props":2524,"children":2526},{"id":2525},"workflow-checklist",[2527],{"type":48,"value":2528},"Workflow checklist",{"type":42,"tag":961,"props":2530,"children":2533},{"className":2531,"code":2532,"language":48},[964],"- [ ] 0. Required reading (skip on subsequent calls in same conversation):\n        hoisa-deploy-profile SKILL.md § Cleanup + Ready Signals + Critical Rules;\n        vss-deploy-profile SKILL.md Deployment Flow \u002F Tear Down (references\u002Fteardown.md)\n        → see \"Phase 0 — Required reading\" above\n- [ ] 1. Generate test plan: parse user request → list of scenarios + durations\n        → references\u002F01_test_plan.md\n- [ ] 2. Pre-check: Halos + SRR compose state, ROS topics, opcua port\n        → references\u002F02_launch.md\n    - [ ] 2.−2 **SRR image freshness** (compare host srr-service\u002Fsrr\u002F*.py vs container \u002Fapp\u002Fsrr\u002F) — rebuild or `docker cp` if stale. **MUST happen before first scenario** — a stale image is a common root cause of clip_logs missing + vst_video wrong-path.\n              → references\u002F02_launch.md Step 3.−2\n    - [ ] 2.−1 SRR fixtures synced (one-time) → references\u002F02_launch.md Step 3.−1\n- [ ] 2.0 **Once, before the scenario loop** (run_multi does these automatically):\n        - stop **nvstreamer** so Isaac is the SOLE camera source (the VSS sample-video\n          player publishes the same camera names → churns SDR provisioning + false-positives\n          the scene-ready gate). Stays down for the whole run.\n        - clear stale `\u002Fapp\u002Fruns\u002Frun-*.parquet` stragglers (a leftover from an aborted run\n          can have a newer mtime than a fresh recording and get mis-attributed to scenario 1).\n- [ ] 3. Per scenario (loop):\n    - [ ] 3.0 **First scenario only, optional**: fresh-start `cleanup_all_datalog.sh`\n              (truncates pss.log + wipes comm-layer\u002F — never run between scenarios)\n              → references\u002F02_launch.md Step 3.0\n    - [ ] 3a. Halos compose down\u002Fup + verify (NO cleanup_all_datalog.sh here).\n              **While Isaac is down**, purge ALL VST sensors (`vst_sensor_manager.py --delete-all`)\n              so the next Isaac registration lands in a clean VST — stale dup sensors otherwise\n              pile up across restarts and the SDR never provisions perception (empty parquet from\n              scenario 2 on). run_multi's `phase_vst_purge` does this.\n    - [ ] 3a.5 **VST API gate** (record API 200 + ≤3 online Camera sensors) — HARD GATE, fail → abort\n    - [ ] 3b. SRR compose down\u002Fup + verify\n    - [ ] 3c. Select scenario behavior trees + set simulation_duration (see 02_launch Step 3c\u002F3c.1)\n    - [ ] 3d. Start scene in isaac-sim (--start --headless --enable-vst)\n    - [ ] 3e. Wait for shaders + 3 RTSP streams ready\n    - [ ] 3f. Launch live_clip_monitor.py (background — known-broken; see 03_monitor.md)\n    - [ ] 3f.5 Safety Core warm-up 30 s\n    - [ ] 3f.7 **VSS perception health gate** (FPS ≥ 5 on 3 cams + the scene-ready topic decoding real detections > 0 — `mdx-raw` for 2D \u002F `mdx-bev` for 3D, per VSS MODE; `mdx-events` flowing confirms the BA→SRR Phase-1 path) — HARD GATE, fail → abort\n    - [ ] 3g. \u002Fsrr\u002Frecord SetBool true\n    - [ ] 3h. Sleep RECORD_S (with BA event + perception FPS heartbeat)\n    - [ ] 3i. \u002Fsrr\u002Frecord SetBool false\n    - [ ] 3j. Kill live_clip_monitor.py\n    - [ ] 3k. Phase 4 analyze (per-scn, **DO BEFORE next iter's 3a**):\n              move parquet → **`sudo chmod -R a+rwX \u003Cscn-host-dir>`** (docker mkdir creates root-owned dir on bind-mount) → **snapshot_pss.sh --per-scn** → tw_split → aggregator → **vst_video.split-run** (Step 4a VST timeline probe before pull) → flatten `videos\u002Fscenes\u002F*.mp4` to `videos\u002F` if stale-image fallback\n              — 04_analyze.md. Batching these to end-of-multi-test loses pss.log (next 3a truncates) + MP4s (Isaac removes VST sensors after sim_length)\n    - [ ] 3l. Verify: summary.md row count == expected clip count + NO validity-guard banner — `PERCEPTION_LIKELY_DEAD` (pooled or per-scenario `… in \u003Crun>`), `PSF_FEED_DEAD`, `PSF feed gaps`, `GT_FROZEN`, or `N clip(s) failed analysis`. Any of these = headline metrics UNTRUSTWORTHY. **This is a SECONDARY net** — 3f.7's FPS ≥ 5 hard-gate is the primary defense against dead perception: a single stray true-positive detection anywhere in the run flips the aggregator's `phase2_alive` check and downgrades the red `PERCEPTION_LIKELY_DEAD` banner to a soft note, so \"no banner\" alone is NOT proof of live perception — 3f.7 must have passed too\n- [ ] 4. Cross-run rollup → references\u002F05_report.md\n    - [ ] 4a. Concat per-scn pss.log → `\u003Cruns-base>\u002Fpss.log` (`snapshot_pss.sh` cross-run mode)\n    - [ ] 4b. aggregator `--top-level` → top-level summary.md (idempotent — re-run is safe)\n    - [ ] 4c. Extract headline metrics + print demo log final block\n- [ ] 5. Interpret + answer user questions about the report\n        → references\u002F06_interpret_report.md\n- [ ] 6. Post-process — references\u002F05_report.md Step 6:\n    - [ ] 6a. `clip_logs --zip` → per-clip evidence + `\u003Cruns-base>.zip` self-contained bundle\n    - [ ] 6b. **ASK user**: launch debug viewer? `[y\u002Fn]`\n    - [ ] 6c. If yes: clone srr-debug-viewer if missing → symlink run into `data\u002F` → **(optional) update `data\u002Findex.json`** (prepend new run for stable ordering; the HTTP directory-listing fallback discovers runs without it — see [05_report.md](references\u002F05_report.md) Step 6) → **pre-check port 8765** (ASK reuse\u002Fkill\u002Fother-port if busy) → `view.sh` → surface URL\n    - [ ] 6d. **Optional, on request**: spatial perception heatmaps + coverage polygons\n              (requires `clip_logs` CSVs first; scripts + matplotlib are baked into the srr image):\n              `render_perception_heatmap.py` (add `--density` for occupancy, `--fov-mask` to\n              clip to calibrated FOV) → `perception_heatmaps[_fovmask]\u002F`;\n              `render_coverage_polygons.py` → `coverage_polygons\u002F`. → references\u002F05_report.md Step 6e\n    - [ ] 6e. Print final paths block (summary, reports, videos, zip, pss.log, heatmaps).\n",[2534],{"type":42,"tag":91,"props":2535,"children":2536},{"__ignoreMap":969},[2537],{"type":48,"value":2532},{"type":42,"tag":51,"props":2539,"children":2540},{},[2541,2543,2549,2551,2557],{"type":48,"value":2542},"Mark each box as it completes. Print ",{"type":42,"tag":91,"props":2544,"children":2546},{"className":2545},[],[2547],{"type":48,"value":2548},"[ok]",{"type":48,"value":2550}," or ",{"type":42,"tag":91,"props":2552,"children":2554},{"className":2553},[],[2555],{"type":48,"value":2556},"[fail]",{"type":48,"value":2558}," per check.",{"type":42,"tag":184,"props":2560,"children":2561},{},[],{"type":42,"tag":188,"props":2563,"children":2565},{"id":2564},"reference-documents",[2566],{"type":48,"value":2567},"Reference Documents",{"type":42,"tag":244,"props":2569,"children":2570},{},[2571,2587],{"type":42,"tag":248,"props":2572,"children":2573},{},[2574],{"type":42,"tag":252,"props":2575,"children":2576},{},[2577,2582],{"type":42,"tag":256,"props":2578,"children":2579},{},[2580],{"type":48,"value":2581},"Document",{"type":42,"tag":256,"props":2583,"children":2584},{},[2585],{"type":48,"value":2586},"Use When",{"type":42,"tag":267,"props":2588,"children":2589},{},[2590,2606,2626,2642,2658,2674],{"type":42,"tag":252,"props":2591,"children":2592},{},[2593,2601],{"type":42,"tag":274,"props":2594,"children":2595},{},[2596],{"type":42,"tag":73,"props":2597,"children":2599},{"href":2598},"references\u002F01_test_plan.md",[2600],{"type":48,"value":2598},{"type":42,"tag":274,"props":2602,"children":2603},{},[2604],{"type":48,"value":2605},"Selecting scenarios, validating Halos + SRR compose are deployed",{"type":42,"tag":252,"props":2607,"children":2608},{},[2609,2616],{"type":42,"tag":274,"props":2610,"children":2611},{},[2612],{"type":42,"tag":73,"props":2613,"children":2614},{"href":178},[2615],{"type":48,"value":178},{"type":42,"tag":274,"props":2617,"children":2618},{},[2619,2621],{"type":48,"value":2620},"Per-scenario launch — compose restart, scene start, ",{"type":42,"tag":91,"props":2622,"children":2624},{"className":2623},[],[2625],{"type":48,"value":2145},{"type":42,"tag":252,"props":2627,"children":2628},{},[2629,2637],{"type":42,"tag":274,"props":2630,"children":2631},{},[2632],{"type":42,"tag":73,"props":2633,"children":2635},{"href":2634},"references\u002F03_monitor.md",[2636],{"type":48,"value":2634},{"type":42,"tag":274,"props":2638,"children":2639},{},[2640],{"type":48,"value":2641},"Live recording monitor — forklift TW crossing detection, demo log lines",{"type":42,"tag":252,"props":2643,"children":2644},{},[2645,2653],{"type":42,"tag":274,"props":2646,"children":2647},{},[2648],{"type":42,"tag":73,"props":2649,"children":2651},{"href":2650},"references\u002F04_analyze.md",[2652],{"type":48,"value":2650},{"type":42,"tag":274,"props":2654,"children":2655},{},[2656],{"type":48,"value":2657},"Post-recording: tw_split + aggregator + per-clip video pull",{"type":42,"tag":252,"props":2659,"children":2660},{},[2661,2669],{"type":42,"tag":274,"props":2662,"children":2663},{},[2664],{"type":42,"tag":73,"props":2665,"children":2667},{"href":2666},"references\u002F05_report.md",[2668],{"type":48,"value":2666},{"type":42,"tag":274,"props":2670,"children":2671},{},[2672],{"type":48,"value":2673},"Cross-run rollup → top-level summary.md + headline metrics",{"type":42,"tag":252,"props":2675,"children":2676},{},[2677,2684],{"type":42,"tag":274,"props":2678,"children":2679},{},[2680],{"type":42,"tag":73,"props":2681,"children":2682},{"href":1081},[2683],{"type":48,"value":1081},{"type":42,"tag":274,"props":2685,"children":2686},{},[2687,2692],{"type":42,"tag":65,"props":2688,"children":2689},{},[2690],{"type":48,"value":2691},"Read before answering anything about the report.",{"type":48,"value":2693}," What every metric means, common patterns, drill-down workflow for FAIL clips",{"type":42,"tag":2695,"props":2696,"children":2698},"h3",{"id":2697},"related-docs",[2699],{"type":48,"value":2700},"Related docs",{"type":42,"tag":51,"props":2702,"children":2703},{},[2704],{"type":48,"value":2705},"User-facing + companion docs elsewhere in the repo:",{"type":42,"tag":244,"props":2707,"children":2708},{},[2709,2723],{"type":42,"tag":248,"props":2710,"children":2711},{},[2712],{"type":42,"tag":252,"props":2713,"children":2714},{},[2715,2719],{"type":42,"tag":256,"props":2716,"children":2717},{},[2718],{"type":48,"value":2581},{"type":42,"tag":256,"props":2720,"children":2721},{},[2722],{"type":48,"value":2586},{"type":42,"tag":267,"props":2724,"children":2725},{},[2726,2757],{"type":42,"tag":252,"props":2727,"children":2728},{},[2729,2740],{"type":42,"tag":274,"props":2730,"children":2731},{},[2732],{"type":42,"tag":73,"props":2733,"children":2734},{"href":1081},[2735],{"type":42,"tag":91,"props":2736,"children":2738},{"className":2737},[],[2739],{"type":48,"value":1081},{"type":42,"tag":274,"props":2741,"children":2742},{},[2743,2745,2750,2751,2756],{"type":48,"value":2744},"What every Phase 1 \u002F Phase 2 number means + the FAIL-clip drill-down workflow. Read before answering perception-metric questions. Formula source of truth: ",{"type":42,"tag":91,"props":2746,"children":2748},{"className":2747},[],[2749],{"type":48,"value":1091},{"type":48,"value":1030},{"type":42,"tag":91,"props":2752,"children":2754},{"className":2753},[],[2755],{"type":48,"value":1098},{"type":48,"value":543},{"type":42,"tag":252,"props":2758,"children":2759},{},[2760,2772],{"type":42,"tag":274,"props":2761,"children":2762},{},[2763],{"type":42,"tag":73,"props":2764,"children":2766},{"href":2765},"..\u002F..\u002Ftools\u002Fsrr-debug-viewer\u002FREADME.md",[2767],{"type":42,"tag":91,"props":2768,"children":2770},{"className":2769},[],[2771],{"type":48,"value":2765},{"type":42,"tag":274,"props":2773,"children":2774},{},[2775,2777,2782],{"type":48,"value":2776},"Browser viewer for per-clip MP4 + sync panels. Launched optionally in Phase 6c (see ",{"type":42,"tag":73,"props":2778,"children":2779},{"href":2666},[2780],{"type":48,"value":2781},"05_report.md",{"type":48,"value":2783}," Step 6).",{"type":42,"tag":184,"props":2785,"children":2786},{},[],{"type":42,"tag":188,"props":2788,"children":2790},{"id":2789},"critical-constants",[2791],{"type":48,"value":2792},"Critical constants",{"type":42,"tag":244,"props":2794,"children":2795},{},[2796,2817],{"type":42,"tag":248,"props":2797,"children":2798},{},[2799],{"type":42,"tag":252,"props":2800,"children":2801},{},[2802,2807,2812],{"type":42,"tag":256,"props":2803,"children":2804},{},[2805],{"type":48,"value":2806},"Constant",{"type":42,"tag":256,"props":2808,"children":2809},{},[2810],{"type":48,"value":2811},"Source",{"type":42,"tag":256,"props":2813,"children":2814},{},[2815],{"type":48,"value":2816},"Notes",{"type":42,"tag":267,"props":2818,"children":2819},{},[2820,2874,2915,2937,2959,3011,3081,3123,3165,3198,3249,3278,3305,3327,3349,3375,3399,3421,3443,3465,3492,3534],{"type":42,"tag":252,"props":2821,"children":2822},{},[2823,2834,2853],{"type":42,"tag":274,"props":2824,"children":2825},{},[2826,2832],{"type":42,"tag":91,"props":2827,"children":2829},{"className":2828},[],[2830],{"type":48,"value":2831},"TW_X",{"type":48,"value":2833}," (forklift trailer tripwire)",{"type":42,"tag":274,"props":2835,"children":2836},{},[2837,2843,2845,2851],{"type":42,"tag":91,"props":2838,"children":2840},{"className":2839},[],[2841],{"type":48,"value":2842},"$CALIBRATION_JSON",{"type":48,"value":2844}," (",{"type":42,"tag":91,"props":2846,"children":2848},{"className":2847},[],[2849],{"type":48,"value":2850},"sensors[0].tripwires[0].wire.p1.x",{"type":48,"value":2852},"); fallback 9.574",{"type":42,"tag":274,"props":2854,"children":2855},{},[2856,2858,2864,2866,2872],{"type":48,"value":2857},"clip boundary detector key; inside-side derived from ",{"type":42,"tag":91,"props":2859,"children":2861},{"className":2860},[],[2862],{"type":48,"value":2863},"sensors[0].tripwires[0].direction",{"type":48,"value":2865}," (falls back to legacy inside=+x if ",{"type":42,"tag":91,"props":2867,"children":2869},{"className":2868},[],[2870],{"type":48,"value":2871},"direction",{"type":48,"value":2873}," missing)",{"type":42,"tag":252,"props":2875,"children":2876},{},[2877,2888,2910],{"type":42,"tag":274,"props":2878,"children":2879},{},[2880,2886],{"type":42,"tag":91,"props":2881,"children":2883},{"className":2882},[],[2884],{"type":48,"value":2885},"ROI",{"type":48,"value":2887}," (work zone)",{"type":42,"tag":274,"props":2889,"children":2890},{},[2891,2896,2898,2903,2905],{"type":42,"tag":91,"props":2892,"children":2894},{"className":2893},[],[2895],{"type":48,"value":2842},{"type":48,"value":2897},"; fallback x ∈ ",{"type":42,"tag":1489,"props":2899,"children":2900},{},[2901],{"type":48,"value":2902},"4.877, 9.574",{"type":48,"value":2904},", y ∈ ",{"type":42,"tag":1489,"props":2906,"children":2907},{},[2908],{"type":48,"value":2909},"-18.976, -11.239",{"type":42,"tag":274,"props":2911,"children":2912},{},[2913],{"type":48,"value":2914},"rectangular polygon",{"type":42,"tag":252,"props":2916,"children":2917},{},[2918,2927,2932],{"type":42,"tag":274,"props":2919,"children":2920},{},[2921],{"type":42,"tag":91,"props":2922,"children":2924},{"className":2923},[],[2925],{"type":48,"value":2926},"SAMPLE_HZ",{"type":42,"tag":274,"props":2928,"children":2929},{},[2930],{"type":48,"value":2931},"30 (built-in)",{"type":42,"tag":274,"props":2933,"children":2934},{},[2935],{"type":48,"value":2936},"SRR recording rate",{"type":42,"tag":252,"props":2938,"children":2939},{},[2940,2949,2954],{"type":42,"tag":274,"props":2941,"children":2942},{},[2943],{"type":42,"tag":91,"props":2944,"children":2946},{"className":2945},[],[2947],{"type":48,"value":2948},"PADDING_SEC",{"type":42,"tag":274,"props":2950,"children":2951},{},[2952],{"type":48,"value":2953},"1.0 (built-in)",{"type":42,"tag":274,"props":2955,"children":2956},{},[2957],{"type":48,"value":2958},"tw_split clip-boundary padding (BA TW events at x≈10.2-10.6 land in in-trailer half)",{"type":42,"tag":252,"props":2960,"children":2961},{},[2962,2971,2990],{"type":42,"tag":274,"props":2963,"children":2964},{},[2965],{"type":42,"tag":91,"props":2966,"children":2968},{"className":2967},[],[2969],{"type":48,"value":2970},"ROS_DOMAIN_ID",{"type":42,"tag":274,"props":2972,"children":2973},{},[2974,2980,2982,2988],{"type":42,"tag":91,"props":2975,"children":2977},{"className":2976},[],[2978],{"type":48,"value":2979},"$ROS_DOMAIN_ID",{"type":48,"value":2981}," (Halos ",{"type":42,"tag":91,"props":2983,"children":2985},{"className":2984},[],[2986],{"type":48,"value":2987},".env",{"type":48,"value":2989},", default 74)",{"type":42,"tag":274,"props":2991,"children":2992},{},[2993,2995,3001,3003,3009],{"type":48,"value":2994},"must match between containers and host probes; multi-machine on same LAN: each machine MUST have a unique ID — see ",{"type":42,"tag":91,"props":2996,"children":2998},{"className":2997},[],[2999],{"type":48,"value":3000},"hoisa-deploy-profile\u002Freferences\u002Ftroubleshooting.md",{"type":48,"value":3002}," (ROS_DOMAIN_ID collision \u002F ",{"type":42,"tag":91,"props":3004,"children":3006},{"className":3005},[],[3007],{"type":48,"value":3008},"Publisher count",{"type":48,"value":3010}," > 1)",{"type":42,"tag":252,"props":3012,"children":3013},{},[3014,3023,3047],{"type":42,"tag":274,"props":3015,"children":3016},{},[3017],{"type":42,"tag":91,"props":3018,"children":3020},{"className":3019},[],[3021],{"type":48,"value":3022},"VST_BASE_URL",{"type":42,"tag":274,"props":3024,"children":3025},{},[3026,3032,3033,3038,3040,3046],{"type":42,"tag":91,"props":3027,"children":3029},{"className":3028},[],[3030],{"type":48,"value":3031},"$VST_BASE_URL",{"type":48,"value":2981},{"type":42,"tag":91,"props":3034,"children":3036},{"className":3035},[],[3037],{"type":48,"value":2987},{"type":48,"value":3039},", e.g. ",{"type":42,"tag":91,"props":3041,"children":3043},{"className":3042},[],[3044],{"type":48,"value":3045},"http:\u002F\u002F\u003CHOST_IP>:30888\u002Fvst\u002Fapi",{"type":48,"value":307},{"type":42,"tag":274,"props":3048,"children":3049},{},[3050,3052,3063,3065,3071,3073,3079],{"type":48,"value":3051},"base for sensor\u002Frecord\u002Fstorage endpoints. ",{"type":42,"tag":65,"props":3053,"children":3054},{},[3055,3061],{"type":42,"tag":91,"props":3056,"children":3058},{"className":3057},[],[3059],{"type":48,"value":3060},"\u002Fvst\u002Fapi\u002Fv1\u002F...",{"type":48,"value":3062}," is the API",{"type":48,"value":3064},"; ",{"type":42,"tag":91,"props":3066,"children":3068},{"className":3067},[],[3069],{"type":48,"value":3070},"\u002Fvst\u002F...",{"type":48,"value":3072}," (no ",{"type":42,"tag":91,"props":3074,"children":3076},{"className":3075},[],[3077],{"type":48,"value":3078},"\u002Fapi",{"type":48,"value":3080},") returns the SPA HTML and is meaningless for probes",{"type":42,"tag":252,"props":3082,"children":3083},{},[3084,3093,3118],{"type":42,"tag":274,"props":3085,"children":3086},{},[3087],{"type":42,"tag":91,"props":3088,"children":3090},{"className":3089},[],[3091],{"type":48,"value":3092},"SENSORS",{"type":42,"tag":274,"props":3094,"children":3095},{},[3096,3102,3104,3109,3111,3117],{"type":42,"tag":91,"props":3097,"children":3099},{"className":3098},[],[3100],{"type":48,"value":3101},"$SENSORS",{"type":48,"value":3103}," (SRR ",{"type":42,"tag":91,"props":3105,"children":3107},{"className":3106},[],[3108],{"type":48,"value":2987},{"type":48,"value":3110},", default ",{"type":42,"tag":91,"props":3112,"children":3114},{"className":3113},[],[3115],{"type":48,"value":3116},"Camera,Camera_01,Camera_02",{"type":48,"value":307},{"type":42,"tag":274,"props":3119,"children":3120},{},[3121],{"type":48,"value":3122},"VSS sensor names; not in calib.json",{"type":42,"tag":252,"props":3124,"children":3125},{},[3126,3135,3152],{"type":42,"tag":274,"props":3127,"children":3128},{},[3129],{"type":42,"tag":91,"props":3130,"children":3132},{"className":3131},[],[3133],{"type":48,"value":3134},"BEV_TOPIC",{"type":42,"tag":274,"props":3136,"children":3137},{},[3138,3144,3146,3151],{"type":42,"tag":91,"props":3139,"children":3141},{"className":3140},[],[3142],{"type":48,"value":3143},"$BEV_TOPIC",{"type":48,"value":3145}," (default ",{"type":42,"tag":91,"props":3147,"children":3149},{"className":3148},[],[3150],{"type":48,"value":1054},{"type":48,"value":307},{"type":42,"tag":274,"props":3153,"children":3154},{},[3155,3157,3163],{"type":48,"value":3156},"Kafka topic for 3D detections (Sparse4D ",{"type":42,"tag":91,"props":3158,"children":3160},{"className":3159},[],[3161],{"type":48,"value":3162},"bbox3d",{"type":48,"value":3164},"). Empty string disables the Phase 2 detection consumer",{"type":42,"tag":252,"props":3166,"children":3167},{},[3168,3177,3193],{"type":42,"tag":274,"props":3169,"children":3170},{},[3171],{"type":42,"tag":91,"props":3172,"children":3174},{"className":3173},[],[3175],{"type":48,"value":3176},"BEHAVIOR_TOPIC",{"type":42,"tag":274,"props":3178,"children":3179},{},[3180,3186,3187,3192],{"type":42,"tag":91,"props":3181,"children":3183},{"className":3182},[],[3184],{"type":48,"value":3185},"$BEHAVIOR_TOPIC",{"type":48,"value":3145},{"type":42,"tag":91,"props":3188,"children":3190},{"className":3189},[],[3191],{"type":48,"value":1062},{"type":48,"value":307},{"type":42,"tag":274,"props":3194,"children":3195},{},[3196],{"type":48,"value":3197},"Kafka topic for BA track positions. Empty string disables the BA-position consumer",{"type":42,"tag":252,"props":3199,"children":3200},{},[3201,3211,3223],{"type":42,"tag":274,"props":3202,"children":3203},{},[3204,3209],{"type":42,"tag":91,"props":3205,"children":3207},{"className":3206},[],[3208],{"type":48,"value":2926},{"type":48,"value":3210}," (3D too)",{"type":42,"tag":274,"props":3212,"children":3213},{},[3214,3216,3222],{"type":48,"value":3215},"30 (built-in, ",{"type":42,"tag":91,"props":3217,"children":3219},{"className":3218},[],[3220],{"type":48,"value":3221},"service.py",{"type":48,"value":307},{"type":42,"tag":274,"props":3224,"children":3225},{},[3226,3228,3233,3235,3241,3243],{"type":48,"value":3227},"mdx-bev is ",{"type":42,"tag":65,"props":3229,"children":3230},{},[3231],{"type":48,"value":3232},"replace-not-append",{"type":48,"value":3234}," per tick; mdx-behavior kept per ",{"type":42,"tag":91,"props":3236,"children":3238},{"className":3237},[],[3239],{"type":48,"value":3240},"track_id",{"type":48,"value":3242}," with ",{"type":42,"tag":91,"props":3244,"children":3246},{"className":3245},[],[3247],{"type":48,"value":3248},"BA_POS_TTL_S=1.0",{"type":42,"tag":252,"props":3250,"children":3251},{},[3252,3261,3273],{"type":42,"tag":274,"props":3253,"children":3254},{},[3255],{"type":42,"tag":91,"props":3256,"children":3258},{"className":3257},[],[3259],{"type":48,"value":3260},"gate_m",{"type":42,"tag":274,"props":3262,"children":3263},{},[3264,3266,3272],{"type":48,"value":3265},"1.5 m (built-in, ",{"type":42,"tag":91,"props":3267,"children":3269},{"className":3268},[],[3270],{"type":48,"value":3271},"aggregator.py",{"type":48,"value":307},{"type":42,"tag":274,"props":3274,"children":3275},{},[3276],{"type":48,"value":3277},"nearest-GT match gate for detect-fail \u002F recall. Multi-gate recall also reported @0.5\u002F1.0\u002F1.5 m",{"type":42,"tag":252,"props":3279,"children":3280},{},[3281,3290,3300],{"type":42,"tag":274,"props":3282,"children":3283},{},[3284],{"type":42,"tag":91,"props":3285,"children":3287},{"className":3286},[],[3288],{"type":48,"value":3289},"coverage_pad_m",{"type":42,"tag":274,"props":3291,"children":3292},{},[3293,3298],{"type":42,"tag":65,"props":3294,"children":3295},{},[3296],{"type":48,"value":3297},"0.0",{"type":48,"value":3299}," (built-in)",{"type":42,"tag":274,"props":3301,"children":3302},{},[3303],{"type":48,"value":3304},"coverage = convex hull of detections, pad=0 (a nonzero pad over-reports detect-fail by counting out-of-FOV GT as misses)",{"type":42,"tag":252,"props":3306,"children":3307},{},[3308,3317,3322],{"type":42,"tag":274,"props":3309,"children":3310},{},[3311],{"type":42,"tag":91,"props":3312,"children":3314},{"className":3313},[],[3315],{"type":48,"value":3316},"boundary_m",{"type":42,"tag":274,"props":3318,"children":3319},{},[3320],{"type":48,"value":3321},"2.0 m (built-in)",{"type":42,"tag":274,"props":3323,"children":3324},{},[3325],{"type":48,"value":3326},"forklift trailer-boundary slice (within 2 m perpendicular distance of the tripwire line)",{"type":42,"tag":252,"props":3328,"children":3329},{},[3330,3339,3344],{"type":42,"tag":274,"props":3331,"children":3332},{},[3333],{"type":42,"tag":91,"props":3334,"children":3336},{"className":3335},[],[3337],{"type":48,"value":3338},"split_dist_m",{"type":42,"tag":274,"props":3340,"children":3341},{},[3342],{"type":48,"value":3343},"1.0 m (built-in)",{"type":42,"tag":274,"props":3345,"children":3346},{},[3347],{"type":48,"value":3348},"same-class split\u002Ffragmentation threshold",{"type":42,"tag":252,"props":3350,"children":3351},{},[3352,3357,3362],{"type":42,"tag":274,"props":3353,"children":3354},{},[3355],{"type":48,"value":3356},"forklift GT origin offset",{"type":42,"tag":274,"props":3358,"children":3359},{},[3360],{"type":48,"value":3361},"estimated per-run (~0.39 m → ~0.08 m residual)",{"type":42,"tag":274,"props":3363,"children":3364},{},[3365,3367,3373],{"type":48,"value":3366},"GT ",{"type":42,"tag":91,"props":3368,"children":3370},{"className":3369},[],[3371],{"type":48,"value":3372},"body",{"type":48,"value":3374}," TF is behind the 3D-box centre; aggregator infers + removes the bias before matching",{"type":42,"tag":252,"props":3376,"children":3377},{},[3378,3383,3394],{"type":42,"tag":274,"props":3379,"children":3380},{},[3381],{"type":48,"value":3382},"Repo root",{"type":42,"tag":274,"props":3384,"children":3385},{},[3386,3392],{"type":42,"tag":91,"props":3387,"children":3389},{"className":3388},[],[3390],{"type":48,"value":3391},"$HOISA_ROOT_PATH",{"type":48,"value":3393}," (REQUIRED)",{"type":42,"tag":274,"props":3395,"children":3396},{},[3397],{"type":48,"value":3398},"halos-outside-in-safety repo root — everything below derives from it",{"type":42,"tag":252,"props":3400,"children":3401},{},[3402,3407,3416],{"type":42,"tag":274,"props":3403,"children":3404},{},[3405],{"type":48,"value":3406},"⤷ deployment dir",{"type":42,"tag":274,"props":3408,"children":3409},{},[3410],{"type":42,"tag":91,"props":3411,"children":3413},{"className":3412},[],[3414],{"type":48,"value":3415},"$HOISA_ROOT_PATH\u002Fdeployments",{"type":42,"tag":274,"props":3417,"children":3418},{},[3419],{"type":48,"value":3420},"compose.yaml + profiles\u002F",{"type":42,"tag":252,"props":3422,"children":3423},{},[3424,3429,3438],{"type":42,"tag":274,"props":3425,"children":3426},{},[3427],{"type":48,"value":3428},"⤷ profile env",{"type":42,"tag":274,"props":3430,"children":3431},{},[3432],{"type":42,"tag":91,"props":3433,"children":3435},{"className":3434},[],[3436],{"type":48,"value":3437},"$HOISA_ROOT_PATH\u002Fdeployments\u002Fprofiles\u002Fsil.env",{"type":42,"tag":274,"props":3439,"children":3440},{},[3441],{"type":48,"value":3442},"source of all shared values",{"type":42,"tag":252,"props":3444,"children":3445},{},[3446,3451,3460],{"type":42,"tag":274,"props":3447,"children":3448},{},[3449],{"type":48,"value":3450},"⤷ Isaac SIL dir",{"type":42,"tag":274,"props":3452,"children":3453},{},[3454],{"type":42,"tag":91,"props":3455,"children":3457},{"className":3456},[],[3458],{"type":48,"value":3459},"$HOISA_ROOT_PATH\u002Fclosed-loop-testing\u002Fisaac-sim\u002Fsil",{"type":42,"tag":274,"props":3461,"children":3462},{},[3463],{"type":48,"value":3464},"scenes\u002Fconfigs\u002Fbehavior-trees\u002Fscripts",{"type":42,"tag":252,"props":3466,"children":3467},{},[3468,3473,3482],{"type":42,"tag":274,"props":3469,"children":3470},{},[3471],{"type":48,"value":3472},"SRR service dir",{"type":42,"tag":274,"props":3474,"children":3475},{},[3476],{"type":42,"tag":91,"props":3477,"children":3479},{"className":3478},[],[3480],{"type":48,"value":3481},"${SRR_PIPELINE_DIR}\u002Fsrr-service\u002F",{"type":42,"tag":274,"props":3483,"children":3484},{},[3485,3487],{"type":48,"value":3486},"where to ",{"type":42,"tag":91,"props":3488,"children":3490},{"className":3489},[],[3491],{"type":48,"value":326},{"type":42,"tag":252,"props":3493,"children":3494},{},[3495,3500,3509],{"type":42,"tag":274,"props":3496,"children":3497},{},[3498],{"type":48,"value":3499},"Output base",{"type":42,"tag":274,"props":3501,"children":3502},{},[3503],{"type":42,"tag":91,"props":3504,"children":3506},{"className":3505},[],[3507],{"type":48,"value":3508},"${RUNS_HOST_DIR:-${SRR_PIPELINE_DIR}\u002Fsrr-service\u002Fruns}\u002Fmulti-test-YYYYMMDD-HHMMSS\u002F",{"type":42,"tag":274,"props":3510,"children":3511},{},[3512,3514,3520,3521,3527,3528],{"type":48,"value":3513},"per-scenario subdirs containing ",{"type":42,"tag":91,"props":3515,"children":3517},{"className":3516},[],[3518],{"type":48,"value":3519},"scenes\u002F",{"type":48,"value":292},{"type":42,"tag":91,"props":3522,"children":3524},{"className":3523},[],[3525],{"type":48,"value":3526},"videos\u002F",{"type":48,"value":292},{"type":42,"tag":91,"props":3529,"children":3531},{"className":3530},[],[3532],{"type":48,"value":3533},"reports\u002F",{"type":42,"tag":252,"props":3535,"children":3536},{},[3537,3542,3551],{"type":42,"tag":274,"props":3538,"children":3539},{},[3540],{"type":48,"value":3541},"Top-level summary",{"type":42,"tag":274,"props":3543,"children":3544},{},[3545],{"type":42,"tag":91,"props":3546,"children":3548},{"className":3547},[],[3549],{"type":48,"value":3550},"\u003Coutput-base>\u002Fsummary.md",{"type":42,"tag":274,"props":3552,"children":3553},{},[3554,3556],{"type":48,"value":3555},"cross-run rollup, written by aggregator ",{"type":42,"tag":91,"props":3557,"children":3559},{"className":3558},[],[3560],{"type":48,"value":3561},"--top-level",{"type":42,"tag":702,"props":3563,"children":3564},{},[3565],{"type":42,"tag":51,"props":3566,"children":3567},{},[3568,3570,3575,3577,3583,3585,3591],{"type":48,"value":3569},"All host paths above resolve from the repo's ",{"type":42,"tag":91,"props":3571,"children":3573},{"className":3572},[],[3574],{"type":48,"value":2987},{"type":48,"value":3576}," (which sets ",{"type":42,"tag":91,"props":3578,"children":3580},{"className":3579},[],[3581],{"type":48,"value":3582},"HOISA_ROOT_PATH",{"type":48,"value":3584},"; scripts source the derived profile env for shared values). Skill scripts self-locate via ",{"type":42,"tag":91,"props":3586,"children":3588},{"className":3587},[],[3589],{"type":48,"value":3590},"$(dirname \"$0\")",{"type":48,"value":3592}," — no absolute path is baked into them.",{"type":42,"tag":184,"props":3594,"children":3595},{},[],{"type":42,"tag":188,"props":3597,"children":3599},{"id":3598},"cleanup",[3600],{"type":48,"value":3601},"Cleanup",{"type":42,"tag":961,"props":3603,"children":3605},{"className":1481,"code":3604,"language":1483,"meta":969,"style":969},"# After multi-test, leave containers running for inspection.\n# Only tear down when explicitly asked.\n\n# To free disk space (drop old runs — videos now live inside the run dir):\nrm -rf ${RUNS_HOST_DIR}\u002Fmulti-test-OLDDATE\n",[3606],{"type":42,"tag":91,"props":3607,"children":3608},{"__ignoreMap":969},[3609,3618,3626,3635,3644],{"type":42,"tag":1489,"props":3610,"children":3611},{"class":1491,"line":1492},[3612],{"type":42,"tag":1489,"props":3613,"children":3615},{"style":3614},"--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic",[3616],{"type":48,"value":3617},"# After multi-test, leave containers running for inspection.\n",{"type":42,"tag":1489,"props":3619,"children":3620},{"class":1491,"line":1587},[3621],{"type":42,"tag":1489,"props":3622,"children":3623},{"style":3614},[3624],{"type":48,"value":3625},"# Only tear down when explicitly asked.\n",{"type":42,"tag":1489,"props":3627,"children":3628},{"class":1491,"line":1665},[3629],{"type":42,"tag":1489,"props":3630,"children":3632},{"emptyLinePlaceholder":3631},true,[3633],{"type":48,"value":3634},"\n",{"type":42,"tag":1489,"props":3636,"children":3638},{"class":1491,"line":3637},4,[3639],{"type":42,"tag":1489,"props":3640,"children":3641},{"style":3614},[3642],{"type":48,"value":3643},"# To free disk space (drop old runs — videos now live inside the run dir):\n",{"type":42,"tag":1489,"props":3645,"children":3647},{"class":1491,"line":3646},5,[3648,3653,3658,3663,3668,3673],{"type":42,"tag":1489,"props":3649,"children":3650},{"style":1508},[3651],{"type":48,"value":3652},"rm",{"type":42,"tag":1489,"props":3654,"children":3655},{"style":1514},[3656],{"type":48,"value":3657}," -rf",{"type":42,"tag":1489,"props":3659,"children":3660},{"style":1502},[3661],{"type":48,"value":3662}," ${",{"type":42,"tag":1489,"props":3664,"children":3665},{"style":1496},[3666],{"type":48,"value":3667},"RUNS_HOST_DIR",{"type":42,"tag":1489,"props":3669,"children":3670},{"style":1502},[3671],{"type":48,"value":3672},"}",{"type":42,"tag":1489,"props":3674,"children":3675},{"style":1514},[3676],{"type":48,"value":3677},"\u002Fmulti-test-OLDDATE\n",{"type":42,"tag":184,"props":3679,"children":3680},{},[],{"type":42,"tag":2695,"props":3682,"children":3684},{"id":3683},"when-vss-is-corrupted-sensoradd-400-record-api-503",[3685],{"type":48,"value":3686},"When VSS is corrupted (sensor\u002Fadd 400, record API 503)",{"type":42,"tag":51,"props":3688,"children":3689},{},[3690,3692,3698,3700,3706,3708,3713,3714,3720,3722,3728,3730,3736,3738,3747],{"type":48,"value":3691},"The VST postgres DB persists across ",{"type":42,"tag":91,"props":3693,"children":3695},{"className":3694},[],[3696],{"type":48,"value":3697},"docker compose down",{"type":48,"value":3699}," (mounted volume\nat ",{"type":42,"tag":91,"props":3701,"children":3703},{"className":3702},[],[3704],{"type":48,"value":3705},"${MDX_DATA_DIR}\u002Fdata_log\u002Fvst",{"type":48,"value":3707},", ~30 GB). ",{"type":42,"tag":91,"props":3709,"children":3711},{"className":3710},[],[3712],{"type":48,"value":1841},{"type":48,"value":1126},{"type":42,"tag":91,"props":3715,"children":3717},{"className":3716},[],[3718],{"type":48,"value":3719},"up",{"type":48,"value":3721}," alone will NOT\nclear stale ",{"type":42,"tag":91,"props":3723,"children":3725},{"className":3724},[],[3726],{"type":48,"value":3727},"online",{"type":48,"value":3729}," Camera sensors — Isaac will get 400 on ",{"type":42,"tag":91,"props":3731,"children":3733},{"className":3732},[],[3734],{"type":48,"value":3735},"sensor\u002Fadd",{"type":48,"value":3737},"\nand the next run will produce ghost results (see\n",{"type":42,"tag":73,"props":3739,"children":3740},{"href":1081},[3741],{"type":42,"tag":91,"props":3742,"children":3744},{"className":3743},[],[3745],{"type":48,"value":3746},"06_interpret_report.md",{"type":48,"value":3748}," — ghost-result\nsection).",{"type":42,"tag":51,"props":3750,"children":3751},{},[3752,3757],{"type":42,"tag":65,"props":3753,"children":3754},{},[3755],{"type":48,"value":3756},"Symptoms",{"type":48,"value":3758}," (any of):",{"type":42,"tag":770,"props":3760,"children":3761},{},[3762,3773,3784,3814],{"type":42,"tag":61,"props":3763,"children":3764},{},[3765,3771],{"type":42,"tag":91,"props":3766,"children":3768},{"className":3767},[],[3769],{"type":48,"value":3770},"\u002Fvst\u002Fapi\u002Fv1\u002Frecord\u002Fstreams",{"type":48,"value":3772}," returns 503 (envoy upstream connection failure)",{"type":42,"tag":61,"props":3774,"children":3775},{},[3776,3778],{"type":48,"value":3777},"Isaac log: ",{"type":42,"tag":91,"props":3779,"children":3781},{"className":3780},[],[3782],{"type":48,"value":3783},"[Error] [vst_sensor_manager] ✗ Failed to add sensor Camera: 400 Client Error",{"type":42,"tag":61,"props":3785,"children":3786},{},[3787,3792,3793,3798,3800,3806,3807,3812],{"type":42,"tag":91,"props":3788,"children":3790},{"className":3789},[],[3791],{"type":48,"value":1682},{"type":48,"value":2844},{"type":42,"tag":91,"props":3794,"children":3796},{"className":3795},[],[3797],{"type":48,"value":398},{"type":48,"value":3799},"; legacy ",{"type":42,"tag":91,"props":3801,"children":3803},{"className":3802},[],[3804],{"type":48,"value":3805},"perception-2d",{"type":48,"value":756},{"type":42,"tag":91,"props":3808,"children":3810},{"className":3809},[],[3811],{"type":48,"value":1469},{"type":48,"value":3813},") PERF lines all show FPS 0.00000",{"type":42,"tag":61,"props":3815,"children":3816},{},[3817,3819,3825],{"type":48,"value":3818},"Aggregator emits ",{"type":42,"tag":91,"props":3820,"children":3822},{"className":3821},[],[3823],{"type":48,"value":3824},"🚫 PERCEPTION_LIKELY_DEAD",{"type":48,"value":3826}," banner",{"type":42,"tag":51,"props":3828,"children":3829},{},[3830,3835],{"type":42,"tag":65,"props":3831,"children":3832},{},[3833],{"type":48,"value":3834},"Reset recipe",{"type":48,"value":3836}," (idempotent — safe to rerun):",{"type":42,"tag":961,"props":3838,"children":3840},{"className":1481,"code":3839,"language":1483,"meta":969,"style":969},"# 1. Stop VSS Warehouse\ncd ${WAREHOUSE_DIR:-\u002Fpath\u002Fto\u002Fvss-warehouse}\ndocker compose --env-file warehouse\u002F.env down\n\n# 2. Wipe accumulated data (postgres, kafka, elastic, redis, vst recordings)\nbash .\u002Fcleanup_all_datalog.sh -b warehouse\n\n# 3. Start VSS Warehouse fresh\ndocker compose --env-file warehouse\u002F.env up -d\n\n# 4. After VSS is healthy, delete any auto-registered Camera\u002FCamera_01\u002FCamera_02\n#    that nvstreamer creates from default config (otherwise Isaac sensor\u002Fadd 400)\nfor SID in $(curl -sf \"${VST_BASE_URL}\u002Fv1\u002Fsensor\u002Flist\" \\\n              | jq -r '.[] | select(.state==\"online\") | select(.name | test(\"^Camera(_0[12])?$\")) | .sensorId'); do\n  curl -sf -X DELETE \"${VST_BASE_URL}\u002Fv1\u002Fsensor\u002F${SID}\"\ndone\n\n# 5. Restart Halos compose so Isaac re-registers fresh sensors\ncd ${HOISA_ROOT_PATH}\u002Fdeployments\ndocker compose --env-file ${HOISA_ROOT_PATH}\u002Fdeployments\u002Fprofiles\u002Fsil.env down && docker compose --env-file ${HOISA_ROOT_PATH}\u002Fdeployments\u002Fprofiles\u002Fsil.env up -d\n",[3841],{"type":42,"tag":91,"props":3842,"children":3843},{"__ignoreMap":969},[3844,3852,3903,3930,3937,3945,3968,3976,3985,4015,4023,4032,4040,4101,4143,4198,4207,4215,4224,4249],{"type":42,"tag":1489,"props":3845,"children":3846},{"class":1491,"line":1492},[3847],{"type":42,"tag":1489,"props":3848,"children":3849},{"style":3614},[3850],{"type":48,"value":3851},"# 1. Stop VSS Warehouse\n",{"type":42,"tag":1489,"props":3853,"children":3854},{"class":1491,"line":1587},[3855,3861,3865,3870,3875,3880,3884,3889,3893,3898],{"type":42,"tag":1489,"props":3856,"children":3858},{"style":3857},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[3859],{"type":48,"value":3860},"cd",{"type":42,"tag":1489,"props":3862,"children":3863},{"style":1502},[3864],{"type":48,"value":3662},{"type":42,"tag":1489,"props":3866,"children":3867},{"style":1496},[3868],{"type":48,"value":3869},"WAREHOUSE_DIR",{"type":42,"tag":1489,"props":3871,"children":3872},{"style":1502},[3873],{"type":48,"value":3874},":-\u002F",{"type":42,"tag":1489,"props":3876,"children":3877},{"style":1496},[3878],{"type":48,"value":3879},"path",{"type":42,"tag":1489,"props":3881,"children":3882},{"style":1502},[3883],{"type":48,"value":756},{"type":42,"tag":1489,"props":3885,"children":3886},{"style":1496},[3887],{"type":48,"value":3888},"to",{"type":42,"tag":1489,"props":3890,"children":3891},{"style":1502},[3892],{"type":48,"value":756},{"type":42,"tag":1489,"props":3894,"children":3895},{"style":1496},[3896],{"type":48,"value":3897},"vss-warehouse",{"type":42,"tag":1489,"props":3899,"children":3900},{"style":1502},[3901],{"type":48,"value":3902},"}\n",{"type":42,"tag":1489,"props":3904,"children":3905},{"class":1491,"line":1665},[3906,3910,3915,3920,3925],{"type":42,"tag":1489,"props":3907,"children":3908},{"style":1508},[3909],{"type":48,"value":1511},{"type":42,"tag":1489,"props":3911,"children":3912},{"style":1514},[3913],{"type":48,"value":3914}," compose",{"type":42,"tag":1489,"props":3916,"children":3917},{"style":1514},[3918],{"type":48,"value":3919}," --env-file",{"type":42,"tag":1489,"props":3921,"children":3922},{"style":1514},[3923],{"type":48,"value":3924}," warehouse\u002F.env",{"type":42,"tag":1489,"props":3926,"children":3927},{"style":1514},[3928],{"type":48,"value":3929}," down\n",{"type":42,"tag":1489,"props":3931,"children":3932},{"class":1491,"line":3637},[3933],{"type":42,"tag":1489,"props":3934,"children":3935},{"emptyLinePlaceholder":3631},[3936],{"type":48,"value":3634},{"type":42,"tag":1489,"props":3938,"children":3939},{"class":1491,"line":3646},[3940],{"type":42,"tag":1489,"props":3941,"children":3942},{"style":3614},[3943],{"type":48,"value":3944},"# 2. Wipe accumulated data (postgres, kafka, elastic, redis, vst recordings)\n",{"type":42,"tag":1489,"props":3946,"children":3948},{"class":1491,"line":3947},6,[3949,3953,3958,3963],{"type":42,"tag":1489,"props":3950,"children":3951},{"style":1508},[3952],{"type":48,"value":1483},{"type":42,"tag":1489,"props":3954,"children":3955},{"style":1514},[3956],{"type":48,"value":3957}," .\u002Fcleanup_all_datalog.sh",{"type":42,"tag":1489,"props":3959,"children":3960},{"style":1514},[3961],{"type":48,"value":3962}," -b",{"type":42,"tag":1489,"props":3964,"children":3965},{"style":1514},[3966],{"type":48,"value":3967}," warehouse\n",{"type":42,"tag":1489,"props":3969,"children":3971},{"class":1491,"line":3970},7,[3972],{"type":42,"tag":1489,"props":3973,"children":3974},{"emptyLinePlaceholder":3631},[3975],{"type":48,"value":3634},{"type":42,"tag":1489,"props":3977,"children":3979},{"class":1491,"line":3978},8,[3980],{"type":42,"tag":1489,"props":3981,"children":3982},{"style":3614},[3983],{"type":48,"value":3984},"# 3. Start VSS Warehouse fresh\n",{"type":42,"tag":1489,"props":3986,"children":3988},{"class":1491,"line":3987},9,[3989,3993,3997,4001,4005,4010],{"type":42,"tag":1489,"props":3990,"children":3991},{"style":1508},[3992],{"type":48,"value":1511},{"type":42,"tag":1489,"props":3994,"children":3995},{"style":1514},[3996],{"type":48,"value":3914},{"type":42,"tag":1489,"props":3998,"children":3999},{"style":1514},[4000],{"type":48,"value":3919},{"type":42,"tag":1489,"props":4002,"children":4003},{"style":1514},[4004],{"type":48,"value":3924},{"type":42,"tag":1489,"props":4006,"children":4007},{"style":1514},[4008],{"type":48,"value":4009}," up",{"type":42,"tag":1489,"props":4011,"children":4012},{"style":1514},[4013],{"type":48,"value":4014}," -d\n",{"type":42,"tag":1489,"props":4016,"children":4018},{"class":1491,"line":4017},10,[4019],{"type":42,"tag":1489,"props":4020,"children":4021},{"emptyLinePlaceholder":3631},[4022],{"type":48,"value":3634},{"type":42,"tag":1489,"props":4024,"children":4026},{"class":1491,"line":4025},11,[4027],{"type":42,"tag":1489,"props":4028,"children":4029},{"style":3614},[4030],{"type":48,"value":4031},"# 4. After VSS is healthy, delete any auto-registered Camera\u002FCamera_01\u002FCamera_02\n",{"type":42,"tag":1489,"props":4033,"children":4034},{"class":1491,"line":27},[4035],{"type":42,"tag":1489,"props":4036,"children":4037},{"style":3614},[4038],{"type":48,"value":4039},"#    that nvstreamer creates from default config (otherwise Isaac sensor\u002Fadd 400)\n",{"type":42,"tag":1489,"props":4041,"children":4043},{"class":1491,"line":4042},13,[4044,4049,4054,4059,4064,4069,4074,4079,4083,4087,4092,4096],{"type":42,"tag":1489,"props":4045,"children":4046},{"style":1669},[4047],{"type":48,"value":4048},"for",{"type":42,"tag":1489,"props":4050,"children":4051},{"style":1496},[4052],{"type":48,"value":4053}," SID ",{"type":42,"tag":1489,"props":4055,"children":4056},{"style":1669},[4057],{"type":48,"value":4058},"in",{"type":42,"tag":1489,"props":4060,"children":4061},{"style":1502},[4062],{"type":48,"value":4063}," $(",{"type":42,"tag":1489,"props":4065,"children":4066},{"style":1508},[4067],{"type":48,"value":4068},"curl",{"type":42,"tag":1489,"props":4070,"children":4071},{"style":1514},[4072],{"type":48,"value":4073}," -sf",{"type":42,"tag":1489,"props":4075,"children":4076},{"style":1502},[4077],{"type":48,"value":4078}," \"${",{"type":42,"tag":1489,"props":4080,"children":4081},{"style":1496},[4082],{"type":48,"value":3022},{"type":42,"tag":1489,"props":4084,"children":4085},{"style":1502},[4086],{"type":48,"value":3672},{"type":42,"tag":1489,"props":4088,"children":4089},{"style":1514},[4090],{"type":48,"value":4091},"\u002Fv1\u002Fsensor\u002Flist",{"type":42,"tag":1489,"props":4093,"children":4094},{"style":1502},[4095],{"type":48,"value":1687},{"type":42,"tag":1489,"props":4097,"children":4098},{"style":1496},[4099],{"type":48,"value":4100}," \\\n",{"type":42,"tag":1489,"props":4102,"children":4104},{"class":1491,"line":4103},14,[4105,4110,4115,4120,4124,4129,4133,4138],{"type":42,"tag":1489,"props":4106,"children":4107},{"style":1502},[4108],{"type":48,"value":4109},"              |",{"type":42,"tag":1489,"props":4111,"children":4112},{"style":1508},[4113],{"type":48,"value":4114}," jq",{"type":42,"tag":1489,"props":4116,"children":4117},{"style":1514},[4118],{"type":48,"value":4119}," -r",{"type":42,"tag":1489,"props":4121,"children":4122},{"style":1502},[4123],{"type":48,"value":1527},{"type":42,"tag":1489,"props":4125,"children":4126},{"style":1514},[4127],{"type":48,"value":4128},".[] | select(.state==\"online\") | select(.name | test(\"^Camera(_0[12])?$\")) | .sensorId",{"type":42,"tag":1489,"props":4130,"children":4131},{"style":1502},[4132],{"type":48,"value":1537},{"type":42,"tag":1489,"props":4134,"children":4135},{"style":1502},[4136],{"type":48,"value":4137},");",{"type":42,"tag":1489,"props":4139,"children":4140},{"style":1669},[4141],{"type":48,"value":4142}," do\n",{"type":42,"tag":1489,"props":4144,"children":4146},{"class":1491,"line":4145},15,[4147,4152,4156,4161,4166,4170,4174,4178,4183,4188,4193],{"type":42,"tag":1489,"props":4148,"children":4149},{"style":1508},[4150],{"type":48,"value":4151},"  curl",{"type":42,"tag":1489,"props":4153,"children":4154},{"style":1514},[4155],{"type":48,"value":4073},{"type":42,"tag":1489,"props":4157,"children":4158},{"style":1514},[4159],{"type":48,"value":4160}," -X",{"type":42,"tag":1489,"props":4162,"children":4163},{"style":1514},[4164],{"type":48,"value":4165}," DELETE",{"type":42,"tag":1489,"props":4167,"children":4168},{"style":1502},[4169],{"type":48,"value":4078},{"type":42,"tag":1489,"props":4171,"children":4172},{"style":1496},[4173],{"type":48,"value":3022},{"type":42,"tag":1489,"props":4175,"children":4176},{"style":1502},[4177],{"type":48,"value":3672},{"type":42,"tag":1489,"props":4179,"children":4180},{"style":1514},[4181],{"type":48,"value":4182},"\u002Fv1\u002Fsensor\u002F",{"type":42,"tag":1489,"props":4184,"children":4185},{"style":1502},[4186],{"type":48,"value":4187},"${",{"type":42,"tag":1489,"props":4189,"children":4190},{"style":1496},[4191],{"type":48,"value":4192},"SID",{"type":42,"tag":1489,"props":4194,"children":4195},{"style":1502},[4196],{"type":48,"value":4197},"}\"\n",{"type":42,"tag":1489,"props":4199,"children":4201},{"class":1491,"line":4200},16,[4202],{"type":42,"tag":1489,"props":4203,"children":4204},{"style":1669},[4205],{"type":48,"value":4206},"done\n",{"type":42,"tag":1489,"props":4208,"children":4210},{"class":1491,"line":4209},17,[4211],{"type":42,"tag":1489,"props":4212,"children":4213},{"emptyLinePlaceholder":3631},[4214],{"type":48,"value":3634},{"type":42,"tag":1489,"props":4216,"children":4218},{"class":1491,"line":4217},18,[4219],{"type":42,"tag":1489,"props":4220,"children":4221},{"style":3614},[4222],{"type":48,"value":4223},"# 5. Restart Halos compose so Isaac re-registers fresh sensors\n",{"type":42,"tag":1489,"props":4225,"children":4227},{"class":1491,"line":4226},19,[4228,4232,4236,4240,4244],{"type":42,"tag":1489,"props":4229,"children":4230},{"style":3857},[4231],{"type":48,"value":3860},{"type":42,"tag":1489,"props":4233,"children":4234},{"style":1502},[4235],{"type":48,"value":3662},{"type":42,"tag":1489,"props":4237,"children":4238},{"style":1496},[4239],{"type":48,"value":3582},{"type":42,"tag":1489,"props":4241,"children":4242},{"style":1502},[4243],{"type":48,"value":3672},{"type":42,"tag":1489,"props":4245,"children":4246},{"style":1514},[4247],{"type":48,"value":4248},"\u002Fdeployments\n",{"type":42,"tag":1489,"props":4250,"children":4252},{"class":1491,"line":4251},20,[4253,4257,4261,4265,4269,4273,4277,4282,4287,4292,4297,4301,4305,4309,4313,4317,4321,4325],{"type":42,"tag":1489,"props":4254,"children":4255},{"style":1508},[4256],{"type":48,"value":1511},{"type":42,"tag":1489,"props":4258,"children":4259},{"style":1514},[4260],{"type":48,"value":3914},{"type":42,"tag":1489,"props":4262,"children":4263},{"style":1514},[4264],{"type":48,"value":3919},{"type":42,"tag":1489,"props":4266,"children":4267},{"style":1502},[4268],{"type":48,"value":3662},{"type":42,"tag":1489,"props":4270,"children":4271},{"style":1496},[4272],{"type":48,"value":3582},{"type":42,"tag":1489,"props":4274,"children":4275},{"style":1502},[4276],{"type":48,"value":3672},{"type":42,"tag":1489,"props":4278,"children":4279},{"style":1514},[4280],{"type":48,"value":4281},"\u002Fdeployments\u002Fprofiles\u002Fsil.env",{"type":42,"tag":1489,"props":4283,"children":4284},{"style":1514},[4285],{"type":48,"value":4286}," down",{"type":42,"tag":1489,"props":4288,"children":4289},{"style":1502},[4290],{"type":48,"value":4291}," &&",{"type":42,"tag":1489,"props":4293,"children":4294},{"style":1508},[4295],{"type":48,"value":4296}," docker",{"type":42,"tag":1489,"props":4298,"children":4299},{"style":1514},[4300],{"type":48,"value":3914},{"type":42,"tag":1489,"props":4302,"children":4303},{"style":1514},[4304],{"type":48,"value":3919},{"type":42,"tag":1489,"props":4306,"children":4307},{"style":1502},[4308],{"type":48,"value":3662},{"type":42,"tag":1489,"props":4310,"children":4311},{"style":1496},[4312],{"type":48,"value":3582},{"type":42,"tag":1489,"props":4314,"children":4315},{"style":1502},[4316],{"type":48,"value":3672},{"type":42,"tag":1489,"props":4318,"children":4319},{"style":1514},[4320],{"type":48,"value":4281},{"type":42,"tag":1489,"props":4322,"children":4323},{"style":1514},[4324],{"type":48,"value":4009},{"type":42,"tag":1489,"props":4326,"children":4327},{"style":1514},[4328],{"type":48,"value":4014},{"type":42,"tag":51,"props":4330,"children":4331},{},[4332,4334,4339,4341,4346],{"type":48,"value":4333},"For full warehouse lifecycle (NGC artifact download, env config, etc.) see the\n",{"type":42,"tag":91,"props":4335,"children":4337},{"className":4336},[],[4338],{"type":48,"value":224},{"type":48,"value":4340}," skill — Deployment Flow + ",{"type":42,"tag":91,"props":4342,"children":4344},{"className":4343},[],[4345],{"type":48,"value":372},{"type":48,"value":543},{"type":42,"tag":51,"props":4348,"children":4349},{},[4350,4352,4357,4359,4364],{"type":48,"value":4351},"For full Halos lifecycle (safety-core, comm-layer, Isaac scene config) see the\n",{"type":42,"tag":91,"props":4353,"children":4355},{"className":4354},[],[4356],{"type":48,"value":154},{"type":48,"value":4358}," skill (",{"type":42,"tag":91,"props":4360,"children":4362},{"className":4361},[],[4363],{"type":48,"value":282},{"type":48,"value":1100},{"type":42,"tag":4366,"props":4367,"children":4368},"style",{},[4369],{"type":48,"value":4370},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":4372,"total":4527},[4373,4391,4409,4420,4432,4446,4459,4473,4482,4493,4507,4516],{"slug":4374,"name":4374,"fn":4375,"description":4376,"org":4377,"tags":4378,"stars":4388,"repoUrl":4389,"updatedAt":4390},"nemoclaw-user-guide","retrieve NemoClaw documentation and configuration","Guides human users' AI agents to the NemoClaw docs MCP server and canonical Fern documentation in Markdown form. Use when users ask how to install, configure, operate, troubleshoot, secure, or learn NemoClaw with an AI coding assistant. Trigger keywords - nemoclaw docs, use nemoclaw with ai agent, nemoclaw mcp docs, nemoclaw install help, nemoclaw quickstart, nemoclaw markdown docs, llms.txt, agent skills.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4379,4382,4385],{"name":4380,"slug":4381,"type":15},"Documentation","documentation",{"name":4383,"slug":4384,"type":15},"MCP","mcp",{"name":4386,"slug":4387,"type":15},"Search","search",21777,"https:\u002F\u002Fgithub.com\u002FNVIDIA\u002FNemoClaw","2026-07-20T06:00:01.461044",{"slug":4392,"name":4392,"fn":4393,"description":4394,"org":4395,"tags":4396,"stars":4406,"repoUrl":4407,"updatedAt":4408},"mcore-build-and-dependency","manage Megatron-LM development environments","Container-based dev environment setup and dependency management for Megatron-LM. Covers acquiring and launching the CI container, uv package management, and updating uv.lock.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4397,4400,4403],{"name":4398,"slug":4399,"type":15},"Containers","containers",{"name":4401,"slug":4402,"type":15},"Deployment","deployment",{"name":4404,"slug":4405,"type":15},"Python","python",17049,"https:\u002F\u002Fgithub.com\u002FNVIDIA\u002FMegatron-LM","2026-07-27T06:06:11.249662",{"slug":4410,"name":4410,"fn":4411,"description":4412,"org":4413,"tags":4414,"stars":4406,"repoUrl":4407,"updatedAt":4419},"mcore-bump-base-image","update NVIDIA PyTorch base images","Bump the NVIDIA PyTorch base image (`nvcr.io\u002Fnvidia\u002Fpytorch:YY.MM-py3`) used by Megatron-LM CI. Covers the two pin sites (GitHub CI in `docker\u002F.ngc_version.dev` and GitLab CI in `.gitlab\u002Fstages\u002F01.build.yml`), the post-bump CI loop (re-run functional tests, refresh golden values, mark broken tests), and the gotchas that bit PRs",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4415,4418],{"name":4416,"slug":4417,"type":15},"CI\u002FCD","ci-cd",{"name":4401,"slug":4402,"type":15},"2026-07-14T05:25:59.97109",{"slug":4421,"name":4421,"fn":4422,"description":4423,"org":4424,"tags":4425,"stars":4406,"repoUrl":4407,"updatedAt":4431},"mcore-cicd","manage CI\u002FCD pipelines for Megatron-LM","CI\u002FCD reference for Megatron-LM. Covers CI pipeline structure, PR scope labels, triggering internal GitLab CI (which force-pushes the current branch to a pull-request\u002FBRANCH ref — always dry-run and verify the destination first; never run against shared or protected branches), and CI failure investigation.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4426,4427,4428],{"name":4416,"slug":4417,"type":15},{"name":4401,"slug":4402,"type":15},{"name":4429,"slug":4430,"type":15},"GitHub","github","2026-07-27T06:06:12.278222",{"slug":4433,"name":4433,"fn":4434,"description":4435,"org":4436,"tags":4437,"stars":4406,"repoUrl":4407,"updatedAt":4445},"mcore-create-issue","investigate CI failures and create issues","Investigate a failing GitHub Actions run or job and create a GitHub issue for the failure.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4438,4441,4442],{"name":4439,"slug":4440,"type":15},"Debugging","debugging",{"name":4429,"slug":4430,"type":15},{"name":4443,"slug":4444,"type":15},"Triage","triage","2026-07-14T05:25:57.442089",{"slug":4447,"name":4447,"fn":4448,"description":4449,"org":4450,"tags":4451,"stars":4406,"repoUrl":4407,"updatedAt":4458},"mcore-linting-and-formatting","lint and format Megatron-LM code","Linting and formatting for Megatron-LM. Covers running autoformat.sh, tools (ruff, black, isort, pylint, mypy), and code style rules.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4452,4455],{"name":4453,"slug":4454,"type":15},"Best Practices","best-practices",{"name":4456,"slug":4457,"type":15},"Code Analysis","code-analysis","2026-07-14T05:25:56.18433",{"slug":4460,"name":4460,"fn":4461,"description":4462,"org":4463,"tags":4464,"stars":4406,"repoUrl":4407,"updatedAt":4472},"mcore-migrate-gpt-to-hybrid","migrate Megatron-LM models to HybridModel","Migration guide for moving Megatron Core GPTModel checkpoints, model providers, training commands, and layer mappings to HybridModel.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4465,4468,4471],{"name":4466,"slug":4467,"type":15},"Machine Learning","machine-learning",{"name":4469,"slug":4470,"type":15},"Migration","migration",{"name":9,"slug":8,"type":15},"2026-07-17T06:07:11.777011",{"slug":4474,"name":4474,"fn":4475,"description":4476,"org":4477,"tags":4478,"stars":4406,"repoUrl":4407,"updatedAt":4481},"mcore-onboard-gb200-1node-tests","onboard functional tests for GB200","Onboard 1-node GitHub MR functional tests for GB200 from existing mr-scoped 2-node tests.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4479,4480],{"name":17,"slug":18,"type":15},{"name":21,"slug":22,"type":15},"2026-07-14T05:25:53.673039",{"slug":4483,"name":4483,"fn":4484,"description":4485,"org":4486,"tags":4487,"stars":4406,"repoUrl":4407,"updatedAt":4492},"mcore-run-on-slurm","launch distributed training jobs on SLURM","How to launch distributed Megatron-LM training jobs on a SLURM cluster. Covers a minimal sbatch skeleton, environment-variable setup for torch.distributed.run, CUDA_DEVICE_MAX_CONNECTIONS rules across hardware and parallelism modes, container conventions, monitoring, and per-rank failure diagnosis.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4488,4489],{"name":4401,"slug":4402,"type":15},{"name":4490,"slug":4491,"type":15},"Infrastructure","infrastructure","2026-07-14T05:25:49.362534",{"slug":4494,"name":4494,"fn":4495,"description":4496,"org":4497,"tags":4498,"stars":4406,"repoUrl":4407,"updatedAt":4506},"mcore-split-pr","split pull requests to reduce review load","Split a PR into multiple PRs to reduce the number of required CODEOWNERS reviewer groups.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4499,4502,4503],{"name":4500,"slug":4501,"type":15},"Code Review","code-review",{"name":4429,"slug":4430,"type":15},{"name":4504,"slug":4505,"type":15},"Pull Requests","pull-requests","2026-07-14T05:26:01.226578",{"slug":4508,"name":4508,"fn":4509,"description":4510,"org":4511,"tags":4512,"stars":4406,"repoUrl":4407,"updatedAt":4515},"mcore-testing","run and manage Megatron-LM tests","Test system for Megatron-LM. Covers test layout, recipe YAML structure, adding and running unit and functional tests, golden values, marker filters, and CI parity.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4513,4514],{"name":17,"slug":18,"type":15},{"name":21,"slug":22,"type":15},"2026-07-14T05:25:54.928983",{"slug":4517,"name":4517,"fn":4518,"description":4519,"org":4520,"tags":4521,"stars":4406,"repoUrl":4407,"updatedAt":4526},"nightly-sync","manage nightly main-to-dev sync workflows","Domain knowledge for the nightly main-to-dev sync workflow. Covers merge strategy, CI architecture, failure investigation, and known issues.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4522,4525],{"name":4523,"slug":4524,"type":15},"Automation","automation",{"name":4416,"slug":4417,"type":15},"2026-07-30T05:29:03.275638",525,{"items":4529,"total":1587},[4530,4544],{"slug":154,"name":154,"fn":4531,"description":4532,"org":4533,"tags":4534,"stars":23,"repoUrl":24,"updatedAt":4543},"deploy HOISA safety testing profiles","Deploy Halos Outside-In Safety (HOISA) closed-loop testing by PROFILE (base \u002F sil \u002F hil) on top of the VSS Warehouse 3.2.1 perception backend. Clone the OSS repo, pick a profile, deploy. Covers prerequisites, NGC artifacts (sil-data + PSF + VSS images), VSS SIL overrides, the Halos stack (PSF, comm-layer, Isaac Sim, forklift-controller), test scenario, and monitoring. Use when asked to deploy Halos, deploy HOISA, deploy SIL, set up warehouse safety simulation, or run outside-in safety testing.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4535,4536,4539,4540],{"name":4401,"slug":4402,"type":15},{"name":4537,"slug":4538,"type":15},"Engineering","engineering",{"name":9,"slug":8,"type":15},{"name":4541,"slug":4542,"type":15},"Security","security","2026-08-05T05:37:26.80915",{"slug":4,"name":4,"fn":5,"description":6,"org":4545,"tags":4546,"stars":23,"repoUrl":24,"updatedAt":25},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[4547,4548,4549,4550],{"name":9,"slug":8,"type":15},{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},{"name":21,"slug":22,"type":15}]