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

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.

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.