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
10 KiB
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.
- Research tables:
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/researchviarouter.use("/research", createResearchRouter(store)).
- Mounts router at
packages/dashboard/app/hooks/useResearch.ts- Dashboard hook consuming
/api/research/*and run lifecycle updates.
- Dashboard hook consuming
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.
- Phase execution (
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.tscreate,list,show,export,cancel,retrycommands.
packages/cli/src/extension.ts- Research tools:
fn_research_run,fn_research_list,fn_research_get,fn_research_cancel,fn_research_retry.
- Research tools:
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.tsis 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
- route file:
3) Lifecycle/status contract as shipped
Canonical ResearchRunStatus values in research-types.ts:
queuedrunningcancellingretry_waitingcompletedfailedcancelledtimed_outretry_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) with409 INVALID_TRANSITION. - Otherwise calls
ResearchStore.requestCancellation()→ run moves tocancelling.
- Rejects terminal statuses (
POST /runs/:id/retry- Delegates to
ResearchStore.createRetryRun(). - Maps retry exhaustion to
409 RETRY_EXHAUSTED, non-retryable failures to409 NON_RETRYABLE_PROVIDER_ERROR, invalid state to409 INVALID_TRANSITION.
- Delegates to
Store behavior (research-store.ts)
requestCancellation()- Non-terminal runs transition to
cancelling, appendcancel_requestedlifecycle event.
- Non-terminal runs transition to
createRetryRun()- Only from
failed/timed_out. - Enforces retryable + max-attempt budget; can set source run to
retry_exhaustedand thrownot_retryable. - Creates new run and sets new run status to
retry_waitingwithretry_scheduledevent.
- Only from
Orchestrator behavior (research-orchestrator.ts)
cancelRun(runId)always callsstore.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.
- Primary run row including JSON columns:
research_run_events- Append-only lifecycle/event stream (
seq,type,message, optional status/classification/metadata).
- Append-only lifecycle/event stream (
research_exports- Export artifacts linked by
runId.
- Export artifacts linked by
Read/write shape (research-store.ts)
- Run row stores denormalized snapshots (
sources,events,results) inresearch_runsJSON fields. - Lifecycle events are also persisted separately in
research_run_events(durable ordered log). - Results/citations/findings are stored in
research_runs.resultsJSON.
6) Provider execution path and abort semantics
research-step-runner.ts:
runSourceQuery→ providersearch(query, options, signal)runContentFetch→ providerfetchContent(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/:idPOST /runs/:id/cancel,POST /runs/:id/retry,PATCH /runs/:id/statusPOST /runs/:id/events,POST /runs/:id/sources,PATCH /runs/:id/sources/:sourceId,PUT /runs/:id/resultsGET /runs/:id/export,POST /runs/:id/exports,GET /runs/:id/exports,GET /exports/:exportIdGET /stats,GET /searchPOST /runs/:runId/findings/:findingId/taskPOST /runs/:runId/findings/:findingId/tasks/:taskId/enrich
8) Hardening pressure points recorded (no fixes in this task)
-
Status drift risk
- Some surfaces (notably tool parameter enums in extension) still expose legacy compact status sets while core status domain is broader.
-
Orchestrator cancel scope nuance
- Full graceful cancel path is only available when run is in
activeRuns; non-active cancellation takes direct status path.
- Full graceful cancel path is only available when run is in
-
Dual event storage model complexity
research_runs.eventsJSON snapshot andresearch_run_eventsappend-only log coexist; hardening should preserve consistency guarantees.
-
Export surface asymmetry
- Route export endpoint advertises markdown/json/html behavior while core export type includes
pdf; CLI command acceptspdfformat but markdown renderer fallback behavior should remain explicitly documented/validated.
- Route export endpoint advertises markdown/json/html behavior while core export type includes
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
ResearchStorepersistence verification at orchestrator level (sources/events/results/lifecycle events persisted end-to-end).
- Boundary guidance for future work:
- keep retryability/lifecycle ownership in
ResearchStoretransitions, - keep error classification in
ResearchStepRunner, - keep sequencing and policy decisions in
ResearchOrchestrator.
- keep retryability/lifecycle ownership in
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,Appresearch 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/researchroutes 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) acrossfn_research_get/fn_research_cancel/fn_research_retrybehavior. - Server-level
/api/researchintegration assertions are locked throughcreateServercoverage for cancel/retry success paths, structured400/404/409envelopes, 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.tspackages/core/src/__tests__/research-store.test.tspackages/engine/src/__tests__/research-orchestrator.test.tspackages/cli/src/commands/__tests__/research.test.ts
These tests were used as behavioral evidence while preparing this baseline.