ship: v0.2 P3 API layer + integration #12

Merged
coreci-bot merged 6 commits from phase/03-api-integration into milestone/v0.2-mvp 2026-09-27 13:45:35 +00:00
Owner

REQ-25/26/33: FastAPI routes (runs, methodologies with ETA/cost cards, lifecycle, SSE events with seq-watermark replay + terminal drain, config status with cost counters), openapi.json snapshot + openapi-typescript/openapi-fetch generated client, GeneratedApiClient live binding behind NEXT_PUBLIC_RESEARCHX_API_MODE (mock default), pauseRun/resumeRun extension (G-003), live exportReport. Verify: 1 P0 (browser-invisible mode flag) + 4 P1 fixed in-phase. Gates: 115 backend + 95 frontend. Tag target v0.2.3.

REQ-25/26/33: FastAPI routes (runs, methodologies with ETA/cost cards, lifecycle, SSE events with seq-watermark replay + terminal drain, config status with cost counters), openapi.json snapshot + openapi-typescript/openapi-fetch generated client, GeneratedApiClient live binding behind NEXT_PUBLIC_RESEARCHX_API_MODE (mock default), pauseRun/resumeRun extension (G-003), live exportReport. Verify: 1 P0 (browser-invisible mode flag) + 4 P1 fixed in-phase. Gates: 115 backend + 95 frontend. Tag target v0.2.3.
coreci-bot added 6 commits 2026-09-27 13:45:31 +00:00
---ci---
phase: 3
milestone: v0.2
status: plan
message: >-
  Phase-boundary PLAN refresh: P3 plan written — FastAPI routes +
  SSE transport + openapi.json snapshot + openapi-typescript client
  generation + ApiClient live binding behind RESEARCHX_API_MODE
  (G-002 core-loop-only, G-003 pause/resume extension, G-005
  snapshot discipline, G-007 cost counters). MVP/UX sections
  authored.
requirements:
  covered: []
  partial: []
---/ci---
---ci---
phase: 3
milestone: v0.2
status: execute
persona: backend-engineer
task: T-3.2
requirements:
  covered: [REQ-25]
---/ci---

FastAPI app: POST /api/runs (201, fake adapters default, env-ready
for live), GET /api/methodologies (cards with ETA minutes, token
cost estimates labeled as estimates, why-recommended, resolved
dials), GET /api/runs/{id} + approve/pause/cancel/resume lifecycle,
GET /api/runs/{id}/events (sse-starlette; state replay on connect;
stream terminates at terminal states - finished runs never hang a
reconnecting client), GET /api/config (adapter status + G-007 cost
counters), GET report + ledger artifacts. CORS localhost:3000 only.
In-memory run registry, single uvicorn worker (single-user). Route
tests via httpx ASGITransport on the same loop: full lifecycle over
HTTP, SSE replay assertion, pause/resume/cancel, 404s, unknown-
methodology rejection. 115 backend tests green.
---ci---
phase: 3
milestone: v0.2
status: execute
persona: frontend-engineer
task: T-3.5
requirements:
  covered: [REQ-26, REQ-54]
---/ci---

G-005 snapshot discipline: openapi.json committed; openapi-
typescript@7 generates schema.d.ts from the snapshot only.
openapi-fetch@0.13 typed client inside GeneratedApiClient
(implements ApiClient via the boundary contract; fetch injectable
for tests). RESEARCHX_API_MODE=mock|live selects the binding in
client.ts — mock stays default; ZERO component rewrites (REQ-54
pinned by the untouched 90-test component suite). G-003: pauseRun/
resumeRun added as the single planned RunLifecycle extension (mock
mode maps them to no-ops). G-002 honored: non-core surfaces
delegate to MockApiClient until v0.3+. Live-mode contract tests
(5): methodology card mapping, run creation, approve/cancel/pause/
resume, ledger health+tier mapping, report fetch. Frontend 95/95.
---ci---
phase: 3
milestone: v0.2
status: execute
persona: ci-lead-developer
task: T-3.9
requirements:
  covered: [REQ-33]
---/ci---
---ci---
phase: 3
milestone: v0.2
status: verify
persona: ci-lead-developer
task: T-3.8
requirements:
  covered: [REQ-25, REQ-26]
---/ci---

P0: NEXT_PUBLIC_RESEARCHX_API_MODE - the mode flag was invisible
to the browser bundle (process.env non-NEXT_PUBLIC vars are
stripped), silently pinning every client-side action to mock while
/choose server-rendered live data (split-brain). Now the flag is
NEXT_PUBLIC_ (server value still honored); README + boundary
comments updated.

P1s: SSE replay->subscribe race fixed with a seq watermark
(EventBus now numbers events; subscribe happens before replay;
terminal streams drain run_done/run_error with a bounded 0.5s
wait instead of returning early and dropping the terminal event);
EventBus.unsubscribe added + finally-block cleanup (no more dead
subscriber/queue leaks on client disconnect); unknown/invalid dial
overrides now return 422 (was an unhandled 500); dial override keys
mapped camelCase->snake_case at the live boundary (the REQ-56
drawer will not 500); live exportReport overridden to export REAL
run report+ledger data (was silently exporting mock content);
EventSource closes on run_done/run_error (no auto-reconnect loop);
run_error messages extracted into trace lines. openapi.json
regenerated from the updated app (snapshot discipline G-005);
schema.d.ts regenerated. 115 backend + 95 frontend tests green.
---ci---
phase: 3
milestone: v0.2
status: verify
requirements:
  covered: [REQ-25, REQ-26, REQ-33]
  partial: []
lessons:
  - "P0: Next.js strips non-NEXT_PUBLIC env vars from browser bundles — the mode flag silently defaulted to mock client-side while server components saw live data. Flag renamed; contract-tested"
  - "SSE correctness needs a sequence watermark: subscribe-before-replay + bounded terminal drain, else the terminal event drops in the checkpoint-before-publish window"
  - "P2 flags for post-hoc: no auth on the loopback API (documented constraint; uvicorn defaults to 127.0.0.1 but nothing enforces it), storage path in /api/config, FAILED mapped to cancelled status, in-memory registry lost on restart, run-artifact reads not exposed via API"
---/ci---

Structural: mypy strict 37 files, ruff clean, openapi.json snapshot
verified in-sync, schema.d.ts regenerated. Behavioral: 115 backend
(route lifecycle over ASGI, SSE replay + terminal drain, 422
validation) + 95 frontend (5 live-binding contract tests, mock
suite untouched — zero component rewrites proven) green. REQ-25
(routes+SSE+config), REQ-26 (generated client + swap), REQ-33
(one-command story) covered. The phase is shippable.
coreci-bot merged commit 75479a9bc0 into milestone/v0.2-mvp 2026-09-27 13:45:35 +00:00
Sign in to join this conversation.