← חזרה לכל השלבים

Orion Studio — Task Graph (P5, stage: TASKS)

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).

Legend

AC → the spec.md §5 criterion the task must satisfy. pat → borrowed pattern (arch §A).

Status: ☐ todo.

Build order (DAG)

Foundation

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.

Data seam (P10-clean)

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.

Auth & shell

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.

Instruments (the cockpit)

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.

Harden, deploy, verify

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.

Critical path

T01 → T03 → T04 → T07/T08 → T13. (T05 auth and T02→T06 shell run in parallel; T10 terminal and

T09 PRISM are independent leaves.)

D-1 cutover (gated on First Light)

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.

P7 — Pre-implementation gate (checklist; verify before IMPLEMENT)

→ Gate result recorded at end of file once IMPLEMENT is authorized.