{"type":"meta","slug":"overdeck-observability-b3","topic":"Consume landed harness B3 observability and guarded task controls in Overdeck","created":"2026-07-22","exec_mode":"ship","scheduler":"dag-parallel","base_branch":"main","gate0_mode":"strict","preset":"codex","land_mode":"merge-to-main"}
{"type":"goal","desc":"Expose authoritative harness events, resumable task streams, capability-driven run detail, and attempt-guarded controls through Overdeck. Preserve legacy runs. Ship and deploy through the frozen project delivery controller."}
{"type":"methodology","desc":"Read /home/user/Projects/mega-plan-harness/docs/specs/2026-07-18-observability-control-api-design.md first. Reuse existing @overdeck/deck-ui components per AGENTS.md and .claude/skills/od-ui-dev/SKILL.md. NEVER add a generic harness proxy, browser-visible harness token, inferred attempt identity, fabricated telemetry, or new UI primitive. Detect support from API capabilities and field presence. Keep A8 cost, A9 account, and A10 watchdog progress as honest gaps."}
{"type":"anchor","path":"/home/user/Projects/mega-plan-harness","desc":"Harness origin/main 3da2f2dc9560bc6636ab98798fe159671d938927 or newer is the producer contract. Verify actual route/status/body behavior in src/control-api.js, src/event-feed.js, src/task-control.js, src/control-config.js, and src/observability.js before implementing consumers."}
{"type":"task","id":"c1","wave":1,"seat":"coder","tier":"medium","deps":[],"files":["collector/src/adapters/harness.ts","collector/src/adapters/harness.test.ts","collector/test/fixtures/harness"],"desc":"Build the typed harness observability boundary. Add exact wire types and adapter methods for GET run events, task SSE, run config, effective plan, enriched decisions, ratelimits, and POST task/run/config controls. Preserve opaque event IDs, cursors, source, taskId, attemptId, payload, capabilities, legacy string/object decision options, and upstream status/body via a typed HarnessApiError. Do not apply the ordinary request timeout to SSE. Keep existing plans-panel output byte-compatible for legacy fixtures; forward optional fields only when present. Tests MUST cover every-new-field-absent legacy fixtures, enriched fixtures, malformed payloads, opaque cursors, redaction, and upstream errors without inferred data.","acceptance":[{"id":"c1-legacy","criterion":"Legacy harness fixtures remain readable and unchanged at existing panel boundaries.","kind":"auto"},{"id":"c1-enriched","criterion":"Enriched fields and capabilities survive typed projection without fabricated defaults.","kind":"auto"}],"requires_decision":null,"verify":["cd collector && bun test src/adapters/harness.test.ts"]}
{"type":"task","id":"c2","wave":2,"seat":"coder","tier":"medium","deps":["c1"],"files":["collector/src/server.ts","collector/src/server.test.ts","collector/src/index.ts","collector/src/actions.ts","collector/src/actions.test.ts"],"desc":"Expose exact collector read routes and default-deny mutations. Add authenticated GET routes only for /harness/runs/:runId/events, /harness/runs/:runId/tasks/:taskId/stream, /harness/runs/:runId/config, and /harness/runs/:runId/plan. Preserve query strings, Last-Event-ID, content type, streaming body, cancellation, and upstream statuses; NEVER buffer SSE. Add explicit action verbs harness.task.pause|resume|kill, harness.run.pause|resume|kill, and harness.config.patch. Strictly validate exact args. Task mutations MUST require non-empty runId, taskId, attemptId, requestId; config patch MUST parse validated JSON and carry revision/If-Match. Journal request and result. Preserve upstream conflict/validation statuses. Tests MUST prove unknown verbs and extra/missing args call nothing, stale attempts conflict, duplicate request IDs are safe, config edits are atomic, auth remains mandatory, and SSE cancellation closes upstream.","acceptance":[{"id":"c2-deny","criterion":"Unknown or malformed mutations fail closed before any harness call.","kind":"auto"},{"id":"c2-stream","criterion":"Collector streams task SSE without buffering and propagates cancellation/cursors.","kind":"auto"}],"requires_decision":null,"verify":["cd collector && bun test src/actions.test.ts"]}
{"type":"task","id":"w1","wave":3,"seat":"coder","tier":"medium","deps":["c2"],"files":["apps/web/src/pages/api/collector/[...path].ts","apps/web/src/pages/api/collector/[...path].test.ts","apps/web/src/lib/collector-client.ts","apps/web/src/lib/collector-client.test.ts","apps/web/src/lib/harness-types.ts"],"desc":"Add browser-safe typed transport. Extend Astro GET allowlisting with exact harness read-route regexes only and forward Last-Event-ID; keep all mutation traffic under the existing /actions/:verb gateway. NEVER add an arbitrary harness path proxy. Add typed clients for events, plan, and config. Make postCollectorAction return validated JSON results while preserving current callers. Keep data-only structural types in harness-types.ts. Tests MUST prove disallowed paths cannot proxy, tokens never enter responses, headers/cursors survive, non-2xx details remain actionable, and existing action clients regress green.","acceptance":[{"id":"w1-proxy","criterion":"Only explicit observability read paths and existing action gateway mutations are browser reachable.","kind":"auto"}],"requires_decision":null,"verify":["pnpm --filter web test -- src/lib/collector-client.test.ts"]}
{"type":"task","id":"u1","wave":3,"seat":"coder","tier":"medium","deps":["c2"],"files":["packages/deck-ui/src/useSseStream.ts","packages/deck-ui/src/useSseStream.test.ts"],"desc":"Upgrade existing useSseStream without changing its current onMessage contract. Parse complete SSE frames across arbitrary chunk boundaries: id, event, data, multiline data, heartbeat comments. Add optional structured onEvent callback. Track only the last successfully delivered opaque ID and send Last-Event-ID on reconnect. Prevent duplicates and reconnect storms. Explicit consumer terminal closure MUST not reconnect. Tests MUST cover split frames, comments, malformed frames, cursor resume, duplicate prevention, abort, and current call sites.","acceptance":[{"id":"u1-resume","criterion":"Reconnect resumes from the last delivered opaque event ID without duplicate delivery.","kind":"auto"}],"requires_decision":null,"verify":["pnpm --filter @overdeck/deck-ui test -- src/useSseStream.test.ts"]}
{"type":"task","id":"u2","wave":4,"seat":"coder","tier":"medium","deps":["u1"],"files":["packages/deck-ui/src/AgentStatusBar.tsx","packages/deck-ui/src/AgentStatusBar.test.tsx","packages/deck-ui/src/AgentFeed.tsx","packages/deck-ui/src/AgentFeed.test.tsx","packages/deck-ui/src/DistanceToDone.tsx","packages/deck-ui/src/DistanceToDone.test.tsx","packages/deck-ui/src/RunCommandBar.tsx","packages/deck-ui/src/RunCommandBar.test.tsx"],"desc":"Extend existing shared components only. AgentStatusBar: replace literal B3 gap with explicit capability/control state, pause/resume, attempt-guard disabled reasons, and confirmed kill; retain restart undo. AgentFeed: accept authoritative raw event records, render escaped text, retain friendly TurnCard and historical modes. DistanceToDone: render structured acceptance only when present. RunCommandBar: capability-driven pause/resume and confirmed run kill; remove universal B3 tooltip. Do not add exports or primitives. Tests MUST cover active enriched, active legacy, paused, killed, unsupported, missing attempt guard, confirmation/keyboard, escaped hostile payload, and absent acceptance preserving current UI.","acceptance":[{"id":"u2-honesty","criterion":"Controls and observability render only from explicit capability/state; legacy gaps remain labeled.","kind":"auto"},{"id":"u2-shared","criterion":"No new UI primitive or duplicate component is introduced.","kind":"auto"}],"requires_decision":null,"verify":["pnpm --filter @overdeck/deck-ui test"]}
{"type":"task","id":"w2","wave":5,"seat":"coder","tier":"medium","deps":["w1","u2"],"files":["apps/web/src/components/plans/AgentApp.tsx","apps/web/src/components/plans/AgentApp.test.tsx"],"desc":"Wire the agent page end to end. Load authoritative task events; keep forensics segments only as legacy fallback/history. Select latest explicit active attempt; NEVER infer attempt identity. Map gate class/detail, review verdict/findings, exact duration, diff counts/files, acceptance results, and transcript/activity into existing AgentFeed/TurnCard. For live tasks, open resumable task SSE and merge by opaque event ID; close when independently refreshed plans state becomes terminal. Enable pause/resume/kill only with active task, observed attemptId, and capability. Send runId+taskId+attemptId+requestId through action gateway. On 409 refresh state; NEVER retry a stale mutation. Keep restart/composer on steer. Tests MUST cover legacy read-only, enriched control, no SSE duplication, stale-attempt refresh, terminal close, historical no-stream, and hostile payload escaping.","acceptance":[{"id":"w2-events","criterion":"Agent history and live updates come from authoritative events with cursor-safe deduplication.","kind":"auto"},{"id":"w2-control","criterion":"Task controls target only the observed attempt and stale conflicts refresh without retry.","kind":"auto"}],"requires_decision":null,"verify":["pnpm --filter web test -- src/components/plans/AgentApp.test.tsx"]}
{"type":"task","id":"w3","wave":5,"seat":"coder","tier":"medium","deps":["w1","u2"],"files":["apps/web/src/lib/panel-data.ts","apps/web/src/components/plans/PlanRunApp.tsx","apps/web/src/components/plans/PlanRunApp.test.tsx","apps/web/src/components/plans/PlansContent.test.tsx"],"desc":"Expand the run control room using existing components. Fetch authoritative events, effective plan, and config. Populate SettingsTable from value/source/immutable/mutationClass; edit only mutable mid-run fields and refresh on stale revision. Project structured acceptance plus acceptance.result, explicit task.duration fix-loop share, gate failures, blocker/major review findings, diff evidence, enriched decisions including needs/why/blast radius/option meaning, and real ratelimits into existing panels. Wire run pause/resume/kill through explicit gateway verbs. Retain only genuine A8/A9/A10 and absent partial-detail gaps. Partial/legacy data MUST remain partial and labeled; never derive observability from run date or slug. Tests MUST cover legacy unavailable surfaces, enriched projections, optimistic config concurrency, locked-field denial, decision option preservation, ratelimit partials, and zero fabricated values.","acceptance":[{"id":"w3-capabilities","criterion":"Run detail fills observability surfaces from explicit capabilities while preserving honest legacy gaps.","kind":"auto"},{"id":"w3-config","criterion":"Only mutable mid-run config fields can be changed and stale revisions refresh safely.","kind":"auto"}],"requires_decision":null,"verify":["pnpm --filter web test -- src/components/plans/PlanRunApp.test.tsx src/components/plans/PlansContent.test.tsx"]}
{"type":"task","id":"v1","wave":6,"seat":"coder","tier":"medium","deps":["w2","w3"],"files":["scratchpad/verify-overdeck-observability-b3.mjs","scratchpad/shots/overdeck-observability-b3"],"desc":"Verify the integrated result and leave an executable receipt. Run collector full tests, @overdeck/deck-ui full tests+typecheck, web full build+typecheck, slopgate, and warning gate with zero ignored signals. Add a Playwright verifier using domcontentloaded, never networkidle. Against fixtures and live deployed-compatible routes verify: legacy run readable with guarded controls; enriched run config/events/acceptance/findings/diff/decisions/ratelimits; task SSE reconnect resumes without duplicates; stale attempt conflict refreshes; pause/resume/kill confirmation is keyboard accessible; both themes; zero console errors; no harness/collector token in browser response or bundle. Do not mutate or kill a non-disposable live run. Save screenshots and machine-readable assertions under scratchpad. Fix every failure before commit.","acceptance":[{"id":"v1-gates","criterion":"All scoped full gates pass cleanly with no warnings or ignored signals.","kind":"auto"},{"id":"v1-live","criterion":"Executable browser receipt proves legacy honesty, enriched observability, guarded controls, resumable stream, both themes, and no leaked token.","kind":"auto"}],"requires_decision":null,"verify":["node scratchpad/verify-overdeck-observability-b3.mjs"]}
