Skip to content

Latest commit

 

History

History
420 lines (347 loc) · 32.6 KB

File metadata and controls

420 lines (347 loc) · 32.6 KB

RobotStudio — Roadmap

Breakdown of the approved plan (docs/PLAN.md) into Epics → Stories → Tasks. Epics map one-to-one to milestones: E0 ↔ M0 … E5 ↔ M5. IDs are stable — commits and milestone docs reference them (E1.S3.T2).

Conventions: every story lists its acceptance ("Done when"); tasks are ordered by intended sequence; estimates are working days and sum to the milestone estimates in PLAN.md §3. Acceptance tests are written at the start of the story they gate, before implementation, per the working protocol.

Definition of done applies to every story (PLAN.md §5, brief): three-OS green, no clippy warnings, no any, no skipped tests, doc comments on public core functions, budgets measured where the render loop or Live Run is touched, keyboard-accessible, prototype copy register.


Status legend: ⬜ not started · 🟡 in progress · ✅ done · ⏸️ blocked/deferred · 🟢 verified on-device

Maintenance: a task's status is updated in the same commit as the work it describes. A story is ✅ only when its "Done when" line holds and all its tasks are ✅/⏸️ (a ⏸️ requires a note in the active milestone doc). An epic is ✅ at its milestone gate. 🟢 is reserved for Arunabh confirming behavior on his machine (or the reference device) — Claude never sets 🟢 on its own.


✅ E0 — Skeleton (↔ M0, 6–8 days)

Goal: a launchable, themed, empty app with the full CI gate and the published spec skeleton. Exit gate: M0 acceptance in PLAN.md.

✅ E0.S1 — Workspace scaffold and CI matrix (1.5 d)

Done when: CI is green on macOS/Windows/Linux for fmt, clippy (deny warnings), tests, wasm check; all crates build with READMEs and lint policy inherited.

  • ✅ E0.S1.T1 Cargo workspace with all eight crates stubbed (core, rsp, rules, kin, sim, export, bom, wasm), rust-toolchain.toml, workspace lints (deny warnings, forbid unsafe outside sidecar, deny unwrap in lib paths).
  • ✅ E0.S1.T2 Frontend scaffold: Vite + React 18 + TS strict, pnpm, Vitest + RTL wired.
  • ✅ E0.S1.T3 ci.yml: fmt, clippy, cargo test, cargo check --target wasm32-unknown-unknown, three-OS Tauri build, pnpm typecheck/test.
  • ✅ E0.S1.T4 Product-name isolation: PRODUCT_NAME const, product.name in Vite config, Tauri productName, plus the CI grep test that fails if the literal name appears elsewhere (ADR 0009).
  • ✅ E0.S1.T5 Crate READMEs + repo README with build instructions.

✅ E0.S2 — .rsp/.rse spec v0.1 and validator CLI (2 d)

Done when: robotstudio-rsp validate accepts every /spec example and rejects the malformed manifest with pointered JSON diagnostics and a non-zero exit code.

  • ✅ E0.S2.T1 JSON Schemas for .rsp (manifest, kinematics, interfaces, electrical, performance, commercial) and .rse (manifest, zones) under /spec, CC-BY-4.0, versioned.
  • ✅ E0.S2.T2 Vendor-facing /spec/README.md: package layout, interface-type namespace, verification levels, license field rules, AAS/OPC UA vocabulary mapping notes.
  • ✅ E0.S2.T3 robotstudio-rsp lib: zip reading, schema validation, typed deserialization into core-consumable structs. MIT license header.
  • ✅ E0.S2.T4 CLI (robotstudio-rsp validate part.rsp) with human and --json output.
  • ✅ E0.S2.T5 Spec examples: one complete valid part, one minimal valid part (manifest+geometry+interfaces only), one valid .rse, one malformed manifest; fixture tests over all four.

✅ E0.S3 — App shell chrome (2 d)

Done when: the app launches on macOS showing the prototype's chrome — rail, empty catalog panel, view tabs (Cell/System/Live Run), right-panel tabs, status bar, prefs popover — with Graphite/Chalk/System themes and bundled fonts.

  • ✅ E0.S3.T1 tokens.css transcribed from the prototype (both themes; amber warning tokens added per ADR 0011); fonts bundled locally.
  • ✅ E0.S3.T2 Layout grid: titlebar, rail, catalog panel, center stage, right panel, status bar; responsive breakpoint from the prototype.
  • ✅ E0.S3.T3 View tabs incl. Live Run (disabled placeholder), right-panel tabs (Checker/Simulation/BOM), status bar fields with placeholders and the fidelity line.
  • ✅ E0.S3.T4 Prefs popover: theme segment control (persisted), toggles stubbed; focus-visible styles; prefers-reduced-motion plumbing.
  • ✅ E0.S3.T5 Component tests for theme switching, tab switching, popover focus behavior.

✅ E0.S4 — Empty stage (1 d)

Done when: R3F canvas renders grid/floor/lighting matching the prototype's feel in both themes; orbit/pan/zoom and Fit view work; render-loop budget baseline recorded.

  • ✅ E0.S4.T1 R3F scene: grid, floor, hemisphere+key lights, fog, theme-reactive colors.
  • ✅ E0.S4.T2 Camera controls (orbit/pan/zoom/Fit) matching prototype feel; keyboard access.
  • ✅ E0.S4.T3 First entry in docs/budgets.md: idle frame time on the dev machine.

✅ E0.S5 — E2E spike and harness skeleton (2.5 d, spike timeboxed 3 d wall-clock)

Done when: ADR 0013 addendum records the spike outcome; the fallback harness runs one smoke test in CI (browser + Linux tauri-driver + macOS launch smoke).

  • ✅ E0.S5.T1 Spike: drive the macOS Tauri webview natively (remote-inspection/CDP route, then AXUIElement route). Timebox 3 days; write ADR 0013 addendum with verdict.
  • ✅ E0.S5.T2 Transport abstraction in the frontend (Tauri IPC vs robotstudio-wasm calls behind one interface).
  • ✅ E0.S5.T3 robotstudio-wasm exposing the (currently tiny) command interface; Playwright browser project running against the Vite build.
  • ✅ E0.S5.T4 Linux tauri-driver CI job running the same smoke spec; macOS launch-and-screenshot smoke job.

✅ E0 exit: tag v0.0.1-m0, docs/milestones/M0.md, 5-minute demo script. Stop for sign-off.


✅ E1 — Assemble (↔ M1, 20–24 days)

Goal: the Design tab is real — 20 real parts, snap, swap, tree, posing, undo, save/load, three templates — passing the eight gesture tests and the golden path through PRD §6 step 4. Exit gate: M1 acceptance in PLAN.md.

✅ E1.S1 — Document model and command bus (3 d)

Done when: commands mutate the document through one bus with inversion-based undo/redo; DocumentView projection reaches the frontend; proptest holds invariants over random command sequences.

  • ✅ E1.S1.T1 Core types: PartRef, Instance, InterfaceRef, Connection, Zone, Scenario, document root; part registry loading .rsp via robotstudio-rsp.
  • ✅ E1.S1.T2 Command bus: AddPart, RemovePart, Connect, Disconnect, MovePart, SetJoint, SetLabel, SetScenario; each with inversion; undo/redo stacks; multi-select Duplicate/copy-paste commands.
  • ✅ E1.S1.T3 DocumentView projection + change notification over the transport abstraction (both Tauri and wasm).
  • ✅ E1.S1.T4 Proptest: random valid command sequences → undo-all restores byte-identical initial document; redo replays to identical final state.

✅ E1.S2 — Project save/load (2 d)

Done when: every template and 200 proptest-generated documents round-trip byte-identically; schema published.

  • ✅ E1.S2.T1 .robotstudio serializer: stable key order, fixed decimal formatting, asset references; kind: cell.project; format schema under /spec (ADR 0009).
  • ✅ E1.S2.T2 Loader with versioned migration hook (identity for v1).
  • ✅ E1.S2.T3 Round-trip fixture tests (templates) + proptest (generated documents); git-diff friendliness test (one-field change → one-hunk diff).

✅ E1.S3 — Snapping in the core (3.5 d)

Done when: capture radius/hysteresis behavior is unit-tested; the host/mount matrix test passes for every compatible pair in the 20-part set; free placement works.

  • ✅ E1.S3.T1 snap_candidates(part_id): free compatible hosts with world transform, orientation constraint, rank (compatibility answered by robotstudio-rules, ADR 0007).
  • ✅ E1.S3.T2 Ghost-pose resolution: {captured_host, mated_transform, orientation_index} | None; 120 mm scene / ~24 px screen capture radius with zoom scaling and hysteresis; nearest-candidate selection + Tab cycling order.
  • ✅ E1.S3.T3 Orientation stepping for 4-fold / free-spin constraints.
  • ✅ E1.S3.T4 Free placement (ASM-8): ground-mountable check, 10 mm grid snap, floor constraint, 5 mm edge/face snap between free parts; rejection reasons as core-supplied strings.
  • ✅ E1.S3.T5 Unit tests: radius/hysteresis edge cases; exhaustive host/mount matrix over the 20-part set (compatible pairs snap with correct transforms; incompatible pairs never offered).

✅ E1.S4 — Swap command and preview (2.5 d)

Done when: SwapPart inherits correctly for every same-category pair in the 20-part set; rules.preview p99 < 16 ms (Criterion, recorded in budgets.md); swap is one undo step.

  • ✅ E1.S4.T1 SwapPart{from,to}: inheritance (host connection, transform, orientation index, label, compatible child connections), carried/detached result sets, single inversion.
  • ✅ E1.S4.T2 Swap-rejection path with core-supplied reason (SWP-3).
  • ✅ E1.S4.T3 rules.preview(SwapPart|AddPart) returning the checker delta (violations added/removed) without committing.
  • ✅ E1.S4.T4 Criterion benchmark for preview on the MVP catalog; result recorded in docs/budgets.md.
  • ✅ E1.S4.T5 Matrix test: swap inheritance for every same-category pair (arm↔arm keeps gripper when flange matches; detach case listed).

✅ E1.S5 — Seed catalog: 20 parts (4 d, parallelizable with S3–S4)

Done when: 20 .rsp packages validate in CI, load in the app, and carry interfaces sufficient for the full snap/swap matrix; UR attribution recorded.

  • ✅ E1.S5.T1 Authoring pipeline: catalog/ layout (one source dir per part), build script → .rsp, CI validation of every part; authoring guide for future curation (risk R2).
  • ✅ E1.S5.T2 UR e-Series (UR5e, UR10e, UR16e): meshes + kinematics.json derived from Universal_Robots_ROS2_Description (BSD-3), attribution in manifests + NOTICE file.
  • ✅ E1.S5.T3 Curated parametric meshes (visual + collision glTF) for the remaining 17: FANUC CRX-10iA, Robotiq 2F-85 + Hand-E, OnRobot RG6, RealSense D455, Zivid 2+ M60, Jetson AGX Orin, Mean Well HRP-600-48, Puls CP20.241, Vention pedestal, igus camera boom, Misumi t-slot member, Dorner 2200 3 m + 1.5 m, Akro-Mils tote ×2 sizes, SICK nanoScan3.
  • ✅ E1.S5.T4 interfaces.json for all 20 (flange, base-bolt, t-slot, ¼-20, DC rails, USB/GigE/tool-I/O); electrical.json, performance.json, commercial.json (indicative prices, source+date) per part; thumbnails.

✅ E1.S6 — Sidebin (catalog panel) (2 d)

Done when: search/filter/badges match the prototype; drag and + placement mode both start a placement; "In cell ×N" and swap-into-cell affordances work (FBK-3).

  • ✅ E1.S6.T1 Part list with faceted chips, search, verification badges, price/lead metadata (CAT-2/3 subset; detail panel with 3D preview may be a thin v1 — judgment call logged if trimmed).
  • ✅ E1.S6.T2 Drag source + keyboard + placement mode entering the same core-driven flow.
  • ✅ E1.S6.T3 In-cell markers and singleton drag-disable with "Swap into cell" (FBK-3).

✅ E1.S7 — Stage interactions: ghost, rings, feedback (4 d)

Done when: the three-channel feedback (ring/outline, connector line, status-bar sentence) matches the prototype's register; rejected drops bounce back with the core's reason; Esc cancels; reduced-motion respected.

  • ✅ E1.S7.T1 Ghost rendering at real scale following the cursor; candidate rings + soft glow on drag start; incompatible hosts dimmed; free-placement hatch + status-bar reason when no hosts (ASM-1/2).
  • ✅ E1.S7.T2 Capture behavior: ghost jumps to mated transform, solid ring, connector line, snap tick (mutable, reduced-motion aware); release on radius exit (ASM-3).
  • ✅ E1.S7.T3 Drop-commit, bounce-back rejection with one-line reason, Esc cancel, R/scroll orientation stepping with on-cursor indicator, Tab candidate cycling, 300 ms host tooltip (ASM-4/5/6, FBK-4).
  • ✅ E1.S7.T4 Swap targeting: same-category outline, swap chip with preview delta from rules.preview, red outline + "Won't fit…" for incompatible host (SWP-1/3).
  • ✅ E1.S7.T5 Detach and re-snap by dragging a placed part; Delete with dependent confirmation (ASM-9); post-commit pulse + checker re-eval ≤ 100 ms (FBK-2).
  • ✅ E1.S7.T6 Occlusion cues for rings/connector (FBK-5, thin version; full depth-cue polish is P1).

✅ E1.S8 — Cell tree and joint posing (2 d)

Done when: tree matches the prototype (hierarchy, rename, hide/show, lock, selection sync, accent selection bar); joint HUD poses the arm within limits from kinematics.json.

  • ✅ E1.S8.T1 Tree view: host→mounted hierarchy from DocumentView, rename, group, hide/show, lock, selection synced both directions (ASM-10).
  • ✅ E1.S8.T2 Joint-pose HUD: sliders bound to SetJoint within limits; FK-driven arm pose on stage (ASM-11 — interactive FK only until E3 brings reach analysis).
  • ⏸️ E1.S8.T3 Drop-onto-tree-row snapping (ASM-7, P1 — attempt; cut first inside E1 if the schedule needs it, logged in the milestone doc).

✅ E1.S9 — Templates (1 d)

Done when: sortation-a, pick-place-minimal, sortation-safe open clean (expected checker state documented), round-trip, and are covered by fixtures.

  • ✅ E1.S9.T1 Author the three templates as .robotstudio fixtures using the 20-part catalog.
  • ✅ E1.S9.T2 Template picker on launch (prototype-register copy); fixture tests.

✅ E1.S10 — E2E gesture and golden-path suites (3 d)

Done when: all eight gesture tests plus the golden path through PRD §6 step 4 are green in CI on the harness of record (ADR 0013).

  • ✅ E1.S10.T1 Gesture specs: drag-snap to flange; no-compatible-host; Tab cycling; R orientation stepping; swap with child inheritance; swap rejection with reason; Esc cancel; detach-and-resnap.
  • ✅ E1.S10.T2 Golden-path spec: template → scenario params → build the cell per §6 step 3 → intentional payload swap per step 4.
  • ✅ E1.S10.T3 Keyboard-only golden-path variant (accessibility gate).

✅ E1 exit: tag v0.1.0-m1, docs/milestones/M1.md, demo script. Stop for sign-off.


✅ E2 — Check + cost (↔ M2, 10–12 days)

Goal: the checker and BOM are live and data-driven; the design summary exists. Exit gate: M2 acceptance in PLAN.md.

✅ E2.S1 — Rule engine (3 d)

Done when: rules load from versioned data, evaluate over typed interfaces with scoped incremental re-evaluation, and emit violations with severity/message/fix-command; proptest shows no false-positive errors on 500 random valid assemblies.

  • ✅ E2.S1.T1 Rule format design: selector, predicate language (deliberately minimal — comparisons, arithmetic, interface/spec field access, aggregation over connected parts), severity, message template, fix-as-command; documented in /spec alongside the catalog bundle format.
  • ⏸️ E2.S1.T2 Evaluator with incremental scoping (only rules whose selector graph touches the changed instances re-run) — feeds both checker and the 16 ms preview budget.
  • ✅ E2.S1.T3 Rule-set versioning with the catalog bundle; loader + validation.
  • ✅ E2.S1.T4 Proptest generator for random valid assemblies; false-positive gate.

✅ E2.S2 — The eight rule families as data (2.5 d)

Done when: every violation from the prototype's hard-coded checker reproduces from data rules on the transcribed prototype cell state.

  • ✅ E2.S2.T1 CHK-1 mechanical interface + CHK-2 payload/moment (incl. reach derating as data).
  • ✅ E2.S2.T2 CHK-4 electrical (voltage, PSU headroom, missing PSU) + CHK-5 data/bus (protocol, ports, USB bandwidth).
  • ✅ E2.S2.T3 CHK-3 reach/workspace (zone distance vs. usable reach — analytical pre-E3 version, upgraded by E3.S2) + CHK-6 static collision (Parry intersection at current pose).
  • ✅ E2.S2.T4 CHK-7 safety-envelope advisory + CHK-8 sourcing (EOL, lead vs. project date) — P1 families, thin data versions.
  • ✅ E2.S2.T5 Prototype-scenario fixture: transcribe the prototype cell + scenario, assert the same violation set (rules, severities, fix labels).

✅ E2.S3 — Checker panel (1.5 d)

Done when: violations render per the prototype (severity order, amber warnings, fix buttons), re-evaluate ≤ 100 ms after commits, and fix buttons dispatch the same commands as sidebin swaps (command-log asserted).

  • ✅ E2.S3.T1 Panel UI: severity sections, one-sentence explanations, fix buttons, all-clear state; status-bar checker field.
  • ✅ E2.S3.T2 Fix dispatch through the command bus; identity-with-sidebin-swap test (SWP-4).
  • ✅ E2.S3.T3 FBK-2 timing test (re-eval ≤ 100 ms after snap/swap).

✅ E2.S4 — BOM engine and panel (2 d)

Done when: BOM matches the hand-computed fixture (lines, extended prices, longest lead); CSV exports; status bar shows total + longest lead.

  • ✅ E2.S4.T1 robotstudio-bom: line derivation from instances, price provenance + date, lead parsing, totals, longest-lead flagging.
  • ✅ E2.S4.T2 Panel UI per prototype (table, lead highlight, provenance footnote); status-bar totals (BOM-1/2, "show the money").
  • ✅ E2.S4.T3 CSV export (BOM-3) as a pure function with fixture test.
  • ✅ E2.S4.T4 Hand-computed fixture for sortation-a.

✅ E2.S5 — Design summary modal and scenario panel (2 d)

Done when: the paper-styled summary modal renders task params, checker results, BOM, and assumptions per the prototype; scenario panel edits drive SetScenario and mark sim results stale.

  • ✅ E2.S5.T1 Scenario panel (uniform defaults per decision #4) bound to SetScenario; staleness propagation to status bar.
  • ✅ E2.S5.T2 Summary modal: paper layout, KV stats, checker table, BOM table, assumptions block, watermark placeholder (licensing hook only).
  • ⏸️ E2.S5.T3 PDF path decision: try webview print-to-PDF; if it fights back, defer rendering-to-file to E3/E5 and log the judgment call (per PLAN).

✅ E2.S6 — System view (2 d) — added at M0 (see docs/milestones/M0.md)

Done when: the System tab shows the auto-generated power/data node graph derived from interfaces (SYS-1) with React Flow; user can connect/disconnect ports and unconnected required ports are flagged (SYS-2); graph re-derives on assembly changes; component tests cover derivation and flags.

  • ✅ E2.S6.T1 Graph derivation in core: power edges (supply→rails) and data edges (connectors) from the document, exposed in DocumentView.
  • 🟡 E2.S6.T2 React Flow rendering per the prototype's system view styling; connect/disconnect dispatch commands; missing-connection flags feed CHK-4/5.
  • ✅ E2.S6.T3 Tests: derivation fixtures for the sortation template; flag rendering.

✅ E2 exit: tag v0.2.0-m2, docs/milestones/M2.md, demo script. Stop for sign-off.


✅ E3 — Cycle check + export (↔ M3, 18–22 days)

Goal: kinematics, the analytical simulation, and all non-STEP exporters with CI validation; catalog at 60. Exit gate: M3 acceptance in PLAN.md.

✅ E3.S1 — Kinematics crate (4 d)

Done when: FK matches published UR e-Series poses within tolerance; IK verified by FK round-trip under proptest; profiles are monotonic in distance/mass; determinism holds.

  • ✅ E3.S1.T1 FK from kinematics.json (joint frames, limits); pose evaluation API.
  • ✅ E3.S1.T2 DLS IK with joint limits, deterministic seeding/damping/iteration caps; convergence failure as reportable reach.fail.
  • ✅ E3.S1.T3 Trapezoidal joint-space profiles; timing API with velocity-fraction + dwell calibration inputs (data-driven, ADR 0012).
  • ✅ E3.S1.T4 Property tests: UR reference poses, IK↔FK round-trip, profile monotonicity.

✅ E3.S2 — Reach envelope and cycle check (3.5 d)

Done when: SIM-1..6 results render in the Simulation panel per the prototype; reach envelope visualizes on stage; CHK-3 upgraded to true reach analysis.

  • ✅ E3.S2.T1 Reach envelope via sampled FK; stage visualization (prefs toggle, per prototype).
  • ✅ E3.S2.T2 Analytical cycle time: approach/grasp/transport/release phases over IK endpoints + profiles; throughput/utilization projection (SIM-3/4).
  • ✅ E3.S2.T3 Power budget: peak/average/kWh-per-shift from electrical.json (SIM-6).
  • ✅ E3.S2.T4 Simulation panel results UI (stats grid, run button, progress, staleness) + status-bar cycle field; fidelity note.
  • 🟡 E3.S2.T5 CHK-3 rule upgraded to kinematic reach; zone editing on stage (pick/place zone placement).

✅ E3.S3 — Swept-volume collision (2 d)

Done when: the pick→place path sweep detects seeded collisions against environment and static parts; results feed SIM-5 and later LR-9.

  • ✅ E3.S3.T1 Path sweep via Parry (sampled poses along the profile) against static geometry.
  • ✅ E3.S3.T2 Injection tests: colliding layout detected; clear layout clean; result surfaced in Simulation panel.

✅ E3.S4 — Exporters (5 d)

Done when: every exporter is a fixture-tested pure function; all template exports load in Gazebo Harmonic + MuJoCo 3.x in CI; USD passes structural validation; manual Isaac checklist documented and executed once.

  • ✅ E3.S4.T1 URDF + SRDF (collision groups) + mesh emission (glTF/STL) (IO-2).
  • ✅ E3.S4.T2 MJCF (IO-3).
  • ✅ E3.S4.T3 USD .usda writer: Xform hierarchy, mesh prims, articulation APIs, mass/inertia (IO-4, ADR 0006).
  • ✅ E3.S4.T4 glTF scene export (IO-6).
  • ✅ E3.S4.T5 Export modal per prototype ("Export N files", format cards, validation captions).
  • ⏸️ E3.S4.T6 STEP sidecar client stub behind feature flag; sidecar itself remains P1 stretch (first in cut order).
  • ✅ E3.S4.T7 exports.yml CI: Gazebo Harmonic + MuJoCo 3.x headless containers load every template export; USD structural/schema validation; manual Isaac Sim load checklist in docs/ (decision #8).

✅ E3.S5 — Catalog to 60 parts (3 d, parallelizable)

Done when: ≥ 60 parts across the PRD §7.1 vendor set validate in CI; ≥ 60% carry kinematics/performance data; licenses recorded, no forbidden bundling.

  • ✅ E3.S5.T1 Curation batch against the E1.S5 pipeline (vendors: add Doosan/Kinova arms, Schunk grippers, Basler camera, Advantech compute, 80/20 + McMaster structure, Interroll conveyor, more totes/racks).
  • ✅ E3.S5.T2 License audit pass: every manifest's license field verified; link-out entries for non-redistributable parts.

🟡 E3.S6 — RoboDK comparison study (1.5 d)

Done when: cycle-time comparison on the three templates is documented with a results table; calibration data adjusted if needed; gate ±15% met or the deviation flagged as a plan change.

  • 🟡 E3.S6.T1 Reproduce the three templates' pick cycles in RoboDK; record timings.
  • 🟡 E3.S6.T2 Calibrate velocity-fraction/dwell data; document method + results in docs/milestones/M3.md.

✅ E3 exit: tag v0.3.0-m3, docs/milestones/M3.md, demo script. Stop for sign-off.


✅ E4 — Live Run (↔ M4, 18–22 days)

Goal: deterministic Live Run with environments, behavior, metrics, recording, and the golden-run gate. Exit gate: M4 acceptance in PLAN.md.

✅ E4.S1 — Fixed-step simulation engine (4 d)

Done when: step/snapshot/events_since work at 240/60 Hz with seeded determinism; the golden-run hash test runs in CI (macOS + Linux) from this story onward.

  • ✅ E4.S1.T1 Engine skeleton: tick loop, sim clock, seeded PCG64, event queue, deterministic containers audit of the sim path (ADR 0010).
  • ⏸️ E4.S1.T2 Rapier deferred: a custom deterministic item integrator (belt advection, gravity, kinematic grasp attach) ships instead — bit-identical across runs by construction; ≤ 40-body budget enforced. ADR 0004 deviation logged in docs/milestones/M4.md.
  • ✅ E4.S1.T3 Binary snapshot format (versioned): instance transforms + joint angles; events_since(tick).
  • ✅ E4.S1.T4 Golden-run CI test (seeded scenario → event-log + metrics hash, 20 runs, macOS + Linux) — lands green on a trivial scenario now, guards everything after (risk R1).

✅ E4.S2 — Environments (.rse) and placement (2.5 d)

Done when: bay-sortation-a and bay-empty load from .rse; the cell snaps to environment anchors with §7.2 feedback as one undoable command.

  • ✅ E4.S2.T1 Author bay-sortation-a (floor/walkways, conveyor source+sink, 2–6 sort lanes, semantic zones) and bay-empty; validate via robotstudio-rsp.
  • 🟡 E4.S2.T2 Environment loading + anchors done; cell placement auto-anchors at the environment origin — the ghost-snap placement gesture (LR-3) is deferred (docs/milestones/M4.md).
  • ✅ E4.S2.T3 Live Run tab entry/exit: assembly freeze (tree read-only, gestures disabled), return-to-Design flow (LR-1/11).

✅ E4.S3 — Behavior state machine and item stream (4 d)

Done when: the data-described sortation FSM runs the eight-state cycle with performance.json timings and bounded trajectories; items stream per scenario; grasp model logs misses per LR-6.

  • ✅ E4.S3.T1 FSM interpreter over behaviors/sortation.json (states, transitions, timing sources) — data-described so pick-and-place/palletizing can be added later without code.
  • ✅ E4.S3.T2 Item stream: uniform mass/size (decision #4), fixed-interval arrivals, deterministic conveyor advection, tote fill.
  • ✅ E4.S3.T3 Camera frustum visibility ("perceive"), mass-band sort rule, lane assignment.
  • ✅ E4.S3.T4 Trajectory generation per cycle via robotstudio-kin (bounded by limits); grasp = kinematic attach with force check; miss logging with reasons.
  • ✅ E4.S3.T5 Unit tests per state + a scripted one-item end-to-end cycle test.

✅ E4.S4 — Transport bar, snapshot channel, stage rendering (3 d)

Done when: Play/Pause/Step/Reset/speed/scrubber/clock work; frames flow over the binary channel at render rate; reduced-motion falls back to snapshot updates; perf measured against budget.

  • ✅ E4.S4.T1 Transport bar UI + shell-side run loop mapping wall→sim time (0.25×–8×).
  • ✅ E4.S4.T2 Binary snapshots flow over a pull-based per-frame IPC call (ADR 0010 deviation: no push channel; docs/milestones/M4.md); frontend applies them imperatively to three.js objects (ADR 0011).
  • ✅ E4.S4.T3 Environment + items rendering on stage; collision-pair highlight.
  • ✅ E4.S4.T4 Perf pass against docs/budgets.md: ≥ 2× real time on dev machine proxy (decision #10); profile before optimizing; document.

✅ E4.S5 — Metrics, event log, collision pause (2.5 d)

Done when: LR-7 metrics update at 250 ms; LR-8 event log filters and scrubs-to-event; LR-9 collision pauses the run, raises a checker error, highlights the pair (injection test).

  • ✅ E4.S5.T1 Metrics accumulation in-core (picks/hr rolling+cumulative, cycle histogram, utilization, misses by reason, backlog, power, kWh); metrics panel UI.
  • ✅ E4.S5.T2 Event log: typed events (grasp.miss, reach.fail, collision, backlog.overflow), filterable UI, click-to-scrub + part highlight.
  • ✅ E4.S5.T3 Swept-volume check per control tick against environment/static parts; pause + checker error + pair highlight; injection test.
  • ✅ E4.S5.T4 Assumptions panel + fidelity labels on every Live Run number (LR-12).

✅ E4.S6 — Recording and scrubbing (2 d)

Done when: runs record state-per-control-tick + events into a bounded ring buffer persisted in the project; scrubbing works after pause; last-run summary appears in the Simulation panel and design summary.

  • 🟡 E4.S6.T1 Ring buffer (10 sim-minutes) done; recording stays in-session — persistence into the project file deferred (docs/milestones/M4.md). Size budget recorded in docs/budgets.md.
  • ✅ E4.S6.T2 Scrubber replay from recorded snapshots; post-pause scrub; reset semantics.
  • ✅ E4.S6.T3 Run summary into Simulation panel + design summary modal (LR-11, M4 gate item).

✅ E4.S7 — Live Run E2E (1.5 d)

Done when: Playwright covers transport controls, scrub-after-pause, event-click-to- scrub, metrics updates, reduced-motion mode; suites green on the harness of record.

  • ✅ E4.S7.T1 Transport/scrub/event-log specs.
  • ✅ E4.S7.T2 Reduced-motion spec (snapshots-only rendering keeps working).

✅ E4 exit: tag v0.4.0-m4, docs/milestones/M4.md, demo script. Stop for sign-off.


✅ E5 — Ship (↔ M5, 14–18 days)

Goal: launchable product — licensing, telemetry, 200-part catalog, signed builds, onboarding, docs. Exit gate: M5 acceptance in PLAN.md. Revisit-at-M5 decisions due here: catalog service scope (#1), telemetry default (#9).

✅ E5.S1 — Licensing (2.5 d)

Done when: Ed25519 keys gate Pro features offline with 30-day grace; watermark toggles on the PDF; free tier needs no key.

  • ✅ E5.S1.T1 Key format + core verification + tier gating (ADR 0015); offline issuance tool (license_tool). The embedded dev issuer key must be replaced with Arunabh's real key before launch (M5 checklist).
  • ✅ E5.S1.T2 Watermark gated on Pro in the design summary; tier pill in the title bar; key entry in Prefs. Private library/alternates were never built, so watermark removal is the shipped Pro gate.
  • ✅ E5.S1.T3 Grace-period and tamper tests.

✅ E5.S2 — Telemetry (2 d)

Done when: every event type is listed in docs/telemetry.md; buffered/batched pipeline uploads to the service; consent flow ships with the default Arunabh chooses now (decision #9 closes).

  • ✅ E5.S2.T1 Typed events in core (search count, place, swap, new violation, export, live-run summary); BOM category totals reserved but not yet emitted. Structural privacy guarantee holds (ADR 0016).
  • 🟡 E5.S2.T2 Local bounded buffer + off-in-dev enforcement shipped; the batch uploader does not exist because there is no ingestion backend (static distribution, decision #1) — docs/milestones/M5.md.
  • 🟡 E5.S2.T3 Consent toggle + privacy copy in Prefs; docs/telemetry.md complete; default is a build flag (VITE_TELEMETRY_DEFAULT) currently opt-in — the launch value is Arunabh's open decision #9 (M5 checklist).

✅ E5.S3 — Catalog to 200 + bundle sync + service (4 d)

Done when: ≥ 200 parts / ≥ 8 vendors validate in CI; the app fetches and verifies signed bundles over HTTPS and works fully offline; service scope decision recorded.

  • ✅ E5.S3.T1 200 parts / 58 vendors via the curation pipeline; every part matrix-tested placeable, all validating against the spec.
  • 🟡 E5.S3.T2 Manifest fetch + Ed25519 verification + silent offline fallback shipped (scripts/build-bundle.py + sign-bundle produce the hosted side); per-file download/install lands when a bundle URL actually exists (M5 checklist).
  • ✅ E5.S3.T3 Decision #1 closed: static hosting; no backend service. License validation is offline (ADR 0015) and telemetry has no ingestion endpoint yet by design (docs/milestones/M5.md).

✅ E5.S4 — Release engineering (3 d)

Done when: signed + notarized macOS build, Windows and Linux release builds, crash reporting wired; install-to-first-export < 10 min on a clean machine.

  • 🟡 E5.S4.T1 release.yml carries the full signing/notarization path, activating when the Apple secrets exist — provisioning them is Arunabh's task (M5 checklist, risk R8). Unsigned builds work for design partners.
  • ✅ E5.S4.T2 dmg/app/msi/nsis/deb/appimage bundling on v* tags via tauri-action; bundled resources resolved by the shell. Unverified remotely until the repo is pushed.
  • ✅ E5.S4.T3 Panic hook appends to a local crash.log in the app config dir; nothing uploads (consistent with telemetry policy — users attach it to bug reports).
  • ⏸️ E5.S4.T4 On-device task: docs/install-test.md is the timed procedure; needs a real release artifact and Arunabh's machine.

✅ E5.S5 — Onboarding and docs site (2.5 d)

Done when: first-run flow lands a new user in a template with guidance; the .rsp spec docs site is published; design partners can run the golden path unassisted.

  • ✅ E5.S5.T1 First-run template picker + three one-time hint cards along the golden path; dismissible (button/Escape), keyboard accessible, covered by onboarding.spec.ts.
  • ✅ E5.S5.T2 scripts/build-spec-site.mjs generates docs-site/index.html from /spec (README + schema reference + facts + changelog). Publishing (GitHub Pages) is a repo-settings task.
  • ⏸️ E5.S5.T3 Design-partner runs are scheduled with Arunabh; results land in docs/milestones/M5.md when they happen.

✅ E5 exit: tagged v1.0.0, docs/milestones/M5.md with the launch checklist. Stopped for launch sign-off.


Post-1.0

  • ✅ PRJ.1 Save/Open project UI: native save/open dialogs on desktop (tauri-plugin-dialog, Rust-side), download/upload in the browser, dirty-state tracking with discard confirms (native dialog on desktop window close, beforeunload in the browser), New-project action, real title-bar crumb with unsaved marker, ⌘S/⌘⇧S/⌘O. Covered by project-file.spec.ts + App.test.tsx.

Cross-epic tracking

  • Cut order (PLAN.md §4) applies within and across epics; any cut is logged in the active milestone doc, never silent.
  • Budgets (docs/budgets.md) accrue entries at: E0.S4 (idle frame), E1.S4 (preview p99), E4.S1/S4 (sim step + channel + frame), E4.S6 (recording size).
  • Determinism CI (E4.S1.T4) and export CI (E3.S4.T7) stay required checks from the story that introduces them.
  • Open decisions parked at M5: catalog service scope (#1), telemetry default (#9), final product name (external, risk R10).