Owner: planning agent. Autonomous (P6). Upstream:specs/spec.md,architecture/architecture.md.
Downstream: P7 gate → IMPLEMENT (one task at a time, TDD). Each task: deps + measurable AC +
borrowed pattern (ref §A of architecture.md). Implementation runs against fixtures until
D-1 (First Light) merges; live cutover is gated on D-1 (see end).
AC → the spec.md §5 criterion the task must satisfy. pat → borrowed pattern (arch §A).
Status: ☐ todo.
Create implementation/ tree (arch §5), config.py (pydantic Settings, env-driven),
non-root Dockerfile skeleton, requirements. AC: app boots, /health 200, deps match
arch §6 (no ORM / no Orion DB driver). pat: A.1 Dockerfile shape.
css/tokens.css = brand.md tokens verbatim; self-host IBM Plex Sans/Mono .woff2;
css/cockpit.css = .rail/.sidebar/.main/.workspace-panel 3-panel + responsive collapse.
AC: AA contrast on all tokens (aa-on-brand-color); layout matches brand.md §3; mobile
single-column (FR-7.3). pat: A.1 shell.
observe_client.py (httpx) and FixtureObserveClient (same interface) over
fixtures/observe/ matching spec.md §4.1. AC: contract test — both clients return the
§4.1 shape; no field invented (AC-Trust foundation). pat: A.3 consumes this shape.
routes/observe.py (/api/runs, /api/runs/{id}, /api/runs/stream) + sse.py (bounded
queue, heartbeat, no Connection: close). AC: routes serve fixture data; SSE streams
updates; 503 {source,reachable:false} on upstream down (NFR-7). pat: A.1 SSE.
session.py (HMAC-signed cookie, 0600 store, lazy-prune) + routes/auth.py (py_webauthn
register/verify) + middleware requiring auth on every route incl. /terminal. AC-Sec-2:
unauthenticated → 401/redirect on 100% of routes. pat: A.1 session (library-backed).
index.html (rail/sidebar/main/workspace, dataset panel toggle, ?v= cache-bust), boot.js
(orchestrator, loaded last), router.js, panels.js (% split + localStorage width),
sse.js (EventSource {withCredentials:true} + poll fallback). AC: panels resize +
persist; ES modules load with no bundler. pat: A.1 shell, A.4 resize.
runs.js — FR-1: all fields, live runs first w/ amber breathe, 3s refresh (SSE/poll),
calm empty + unreachable states. AC-Observe-1, AC-Resilience(observe), AC-Latency (≤5s).
pat: A.1 SSE client.
trace.js — FR-2: A.3 three-pass tree-build + two timing formulas (plain JS), tool-call
cards, cost/token rings (tick), --ember + failure taxonomy on failed steps. AC-Observe-2
(byte-match on cost/tokens/status). pat: A.3 (reimplemented, no Langfuse import).
routes/prism.py + repo_reader.py (memory/, products/*) + directus_client.py (read-only)
+ prism.js — FR-3: product instances + pipeline stage, read-only pending-gate indicator,
memory browser. AC-PRISM-1. pat: repo + Directus read-through.
terminal.js (same-origin iframe /terminal) + deploy/Caddyfile + ttyd invocation +
deploy/tailscale.md. AC-Terminal-1 (connects over Tailscale, runs a command, both modes).
pat: A.2 (embed, check-origin OFF, -W, -c).
motion.js — breathe (single live element) + tick (rings/numerals) + hairline focus; all gated
on prefers-reduced-motion. AC-A11y (reduced-motion). pat: aa-proof-kinetics.
docker-compose.yml (Studio + Caddy; ttyd documented), non-root image, security headers +
credential-redaction. AC-Sec-1: port scan = 0 open public ports (Tailscale-only). pat: A.1.
Automate: JS-budget (≤60KB gz), a11y (AA + keyboard + reduced-motion), zero-drift diff
(AC-Trust), port scan (AC-Sec-1), auth-on-all-routes (AC-Sec-2), ≤1-accent/viewport (AC-Calm),
resilience 3-case (AC-Resilience). AC: all gates green on fixtures. pat: js-budget-gate.
Localhost + remote/Tailscale modes, env vars, D-1 cutover steps. AC: a fresh operator can
run it from the doc.
T01 → T03 → T04 → T07/T08 → T13. (T05 auth and T02→T06 shell run in parallel; T10 terminal and
T09 PRISM are independent leaves.)
All of T01–T14 complete against FixtureObserveClient. When **First Light merges + the Observe
API is live**, flip OBSERVE_BACKEND=live (config) → observe_client hits the real API. Re-run
AC-Trust (zero-drift) and AC-Observe-1/2 against live data. No code change beyond config
(same interface) — that is the payoff of the §2 seam.
b182dc5) — yes45cdb11) — yesc08885a) — yes→ Gate result recorded at end of file once IMPLEMENT is authorized.