Files
fusion/docs/research/research-hardening-preflight.md
Fusion 7fc7b7653f feat(FN-3599): align documentation with delivery process
Documentation delivery alignment completing Step 5 of FN-3369, updating the CLI reference, research docs, and research hardening preflight guide with consistent documentation delivery guidance across all three files.

Fusion-Task-Id: FN-3599
2026-05-06 18:40:52 -07:00

187 lines
10 KiB
Markdown

# Research Hardening Preflight Baseline (FN-2999)
Date: 2026-05-04
Task: FN-3266
## Scope and intent
This document is the verified baseline for FN-2999 hardening work. It reflects **shipped behavior in-repo** and explicitly calls out drift from older assumptions.
## 1) Verified module map (Research vs Insights)
### Core (`@fusion/core`)
- `packages/core/src/research-types.ts`
- Canonical research statuses/types/lifecycle contracts.
- `packages/core/src/research-store.ts`
- Persistence-backed run lifecycle, transitions, cancellation request, retry creation, events/sources/results/exports operations.
- `packages/core/src/research-settings.ts`
- Feature enablement and resolved runtime limits/provider settings.
- `packages/core/src/db.ts`
- Research tables: `research_runs`, `research_run_events`, `research_exports`.
### Dashboard API/UI (`@fusion/dashboard`)
- `packages/dashboard/src/research-routes.ts`
- Research API endpoints (run CRUD + cancel/retry + results/sources/events + exports + finding-to-task actions).
- `packages/dashboard/src/routes/register-integrated-routers.ts`
- Mounts router at `/api/research` via `router.use("/research", createResearchRouter(store))`.
- `packages/dashboard/app/hooks/useResearch.ts`
- Dashboard hook consuming `/api/research/*` and run lifecycle updates.
- `packages/dashboard/app/components/ResearchView.tsx`
- Standalone Research view, run controls, result display, finding task actions.
### Engine (`@fusion/engine`)
- `packages/engine/src/research-orchestrator.ts`
- Phase execution (`planning/searching/fetching/synthesizing/finalizing`), cancellation, retry handoff, status/event writes.
- `packages/engine/src/research-step-runner.ts`
- Provider adapters with timeout + abort handling and error classification.
### CLI + extension (`@runfusion/fusion`)
- `packages/cli/src/commands/research.ts`
- `create`, `list`, `show`, `export`, `cancel`, `retry` commands.
- `packages/cli/src/extension.ts`
- Research tools: `fn_research_run`, `fn_research_list`, `fn_research_get`, `fn_research_cancel`, `fn_research_retry`.
### Boundary with Insights (separate subsystem)
- Insights files/routes/stores remain separate (`insight-store`, `insights-routes`, `project_insights*` tables).
- Research is **not** a wrapper around Insights and does not share run tables.
## 2) Renamed-path drift and stale assumptions
- Older wording referencing `packages/dashboard/src/routes/register-research-routes.ts` is stale.
- Actual implementation is:
- route file: `packages/dashboard/src/research-routes.ts`
- mount file: `packages/dashboard/src/routes/register-integrated-routers.ts`
- mount path: `/api/research`
## 3) Lifecycle/status contract as shipped
Canonical `ResearchRunStatus` values in `research-types.ts`:
- `queued`
- `running`
- `cancelling`
- `retry_waiting`
- `completed`
- `failed`
- `cancelled`
- `timed_out`
- `retry_exhausted`
### Important mismatch to older baseline text
Older baseline language (`pending | running | completed | failed | cancelled`) is obsolete. `pending` is normalized to `queued` for compatibility in store code, but not a primary status in current contracts.
## 4) Cancel/retry behavior (API + store + orchestrator)
### Dashboard route behavior (`research-routes.ts`)
- `POST /runs/:id/cancel`
- Rejects terminal statuses (`completed`, `failed`, `cancelled`, `timed_out`, `retry_exhausted`) with `409 INVALID_TRANSITION`.
- Otherwise calls `ResearchStore.requestCancellation()` → run moves to `cancelling`.
- `POST /runs/:id/retry`
- Delegates to `ResearchStore.createRetryRun()`.
- Maps retry exhaustion to `409 RETRY_EXHAUSTED`, non-retryable failures to `409 NON_RETRYABLE_PROVIDER_ERROR`, invalid state to `409 INVALID_TRANSITION`.
### Store behavior (`research-store.ts`)
- `requestCancellation()`
- Non-terminal runs transition to `cancelling`, append `cancel_requested` lifecycle event.
- `createRetryRun()`
- Only from `failed`/`timed_out`.
- Enforces retryable + max-attempt budget; can set source run to `retry_exhausted` and throw `not_retryable`.
- Creates new run and sets new run status to `retry_waiting` with `retry_scheduled` event.
### Orchestrator behavior (`research-orchestrator.ts`)
- `cancelRun(runId)` always calls `store.requestCancellation(runId)` first.
- If run is active in orchestrator `activeRuns`, abort controller is triggered and final state transitions through cancellation handling.
- If run is **not** active, orchestrator directly sets status `cancelled`.
- Practical limitation: orchestrator-side graceful cancellation logic only applies to runs currently tracked in `activeRuns`.
## 5) Persistence/storage model (verified)
### Tables (`db.ts`)
- `research_runs`
- Primary run row including JSON columns: `providerConfig`, `sources`, `events`, `results`, `tokenUsage`, `tags`, `metadata`, `lifecycle`.
- `research_run_events`
- Append-only lifecycle/event stream (`seq`, `type`, `message`, optional status/classification/metadata).
- `research_exports`
- Export artifacts linked by `runId`.
### Read/write shape (`research-store.ts`)
- Run row stores denormalized snapshots (`sources`, `events`, `results`) in `research_runs` JSON fields.
- Lifecycle events are also persisted separately in `research_run_events` (durable ordered log).
- Results/citations/findings are stored in `research_runs.results` JSON.
## 6) Provider execution path and abort semantics
`research-step-runner.ts`:
- `runSourceQuery` → provider `search(query, options, signal)`
- `runContentFetch` → provider `fetchContent(url, options, signal)`
- `runSynthesis` → configured synthesis runner with model settings + signal
All step calls are wrapped by `withTimeout(...)`:
- timeout classification: `ResearchStepTimeoutError` (`retryable: true`)
- abort classification: `ResearchStepAbortError` (`retryable: false`)
- provider failures: `provider_error` (`retryable: true`)
Abort propagation uses `AbortSignal` listeners and races promise vs timeout vs abort.
## 7) API shape summary (`/api/research`)
Key endpoints:
- `GET /runs`, `POST /runs`, `GET /runs/:id`, `PATCH /runs/:id`, `DELETE /runs/:id`
- `POST /runs/:id/cancel`, `POST /runs/:id/retry`, `PATCH /runs/:id/status`
- `POST /runs/:id/events`, `POST /runs/:id/sources`, `PATCH /runs/:id/sources/:sourceId`, `PUT /runs/:id/results`
- `GET /runs/:id/export`, `POST /runs/:id/exports`, `GET /runs/:id/exports`, `GET /exports/:exportId`
- `GET /stats`, `GET /search`
- `POST /runs/:runId/findings/:findingId/task`
- `POST /runs/:runId/findings/:findingId/tasks/:taskId/enrich`
## 8) Hardening pressure points recorded (no fixes in this task)
1. **Status drift risk**
- Some surfaces (notably tool parameter enums in extension) still expose legacy compact status sets while core status domain is broader.
2. **Orchestrator cancel scope nuance**
- Full graceful cancel path is only available when run is in `activeRuns`; non-active cancellation takes direct status path.
3. **Dual event storage model complexity**
- `research_runs.events` JSON snapshot and `research_run_events` append-only log coexist; hardening should preserve consistency guarantees.
4. **Export surface asymmetry**
- Route export endpoint advertises markdown/json/html behavior while core export type includes `pdf`; CLI command accepts `pdf` format but markdown renderer fallback behavior should remain explicitly documented/validated.
## 9) FN-3292 boundary stress-test confirmations
- Provider ordering assumptions were tightened: content fetch selection can now use source-level provider metadata (`providerType`) and falls back only when that provider is unavailable.
- Orchestrator/provider seam was validated with behavior-first tests:
- fallback from failed primary provider to a later provider,
- partial fetch failure with successful completion when at least one source is fetched,
- real `ResearchStore` persistence verification at orchestrator level (sources/events/results/lifecycle events persisted end-to-end).
- Boundary guidance for future work:
- keep retryability/lifecycle ownership in `ResearchStore` transitions,
- keep error classification in `ResearchStepRunner`,
- keep sequencing and policy decisions in `ResearchOrchestrator`.
## 10) FN-3370 refinement scope correction
- FN-3370 replaces FN-3015's stale insights-backed child scope with the landed research subsystem surfaces in this document (core `ResearchStore` + dashboard `/api/research` + engine orchestrator lifecycle persistence).
- Regression coverage work should stay bounded to shipped lifecycle/status/export/task-integration contracts and use follow-up tasks for any unshipped behavior instead of feature expansion.
## 11) Dashboard regression coverage status (FN-3368 refinement)
- Dashboard interaction tests are anchored to landed standalone research surfaces (`ResearchView`, `ResearchTaskActionModal`, `useResearch`, `App` research route wiring).
- Route regression tests explicitly cover finding-to-task create/enrich provenance metadata, task-document writes, duplicate-attachment skip behavior, archived/missing target guards, and payload validation.
- There is no placeholder/optional assumption that research dashboard files or `/api/research` routes are absent.
## 12) FN-3369/FN-3599 verification lock note
- Extension research tool contracts are now explicitly locked for missing-run errors and completed-run structured details (`summary`, `findings`, `citations`) across `fn_research_get` / `fn_research_cancel` / `fn_research_retry` behavior.
- Server-level `/api/research` integration assertions are locked through `createServer` coverage for cancel/retry success paths, structured `400`/`404`/`409` envelopes, and export response contract checks.
- CLI routing + docs alignment are locked to shipped behavior, including intentional CLI/core vs server export-format asymmetry documentation (no forced unification).
## 13) Validation references used for this baseline
- `packages/dashboard/src/__tests__/research-routes.test.ts`
- `packages/core/src/__tests__/research-store.test.ts`
- `packages/engine/src/__tests__/research-orchestrator.test.ts`
- `packages/cli/src/commands/__tests__/research.test.ts`
These tests were used as behavioral evidence while preparing this baseline.