- Status: Accepted (PR 0 foundation shipped; per-feature generators staged)
- Date: 2026-06-25
- Deciders: Maintainer + Claude Code
- Context tags: ai, resilience, offline, heuristics, fallback
When AI is unavailable (offline, quota/rate-limit, error, Eco/Heuristics-only mode, low local-inference
availability), most AI features hard-fail β a toast or an "Error: β¦" string in the result pane. The
only terminal heuristic (services/localAiFacade.ts) is a stub returning "Heuristic fallback response", and the structured generators (Outline, Character, World, Plot-Board) call
generateJson+Gemini which bypasses the provider fallback chain entirely, so they have no degrade
path at all. The app feels broken when AI fails instead of gracefully assisted.
The strategic brief proposed a large "Unified Fallback Orchestrator" service plus a Confidence Scorer
and a Context Intelligence Layer. But the codebase already contains nearly all the primitives: a
pluggable heuristic engine (services/copilot/heuristicEngine.ts, registerRule), a provider fallback
chain with a terminal local seam (services/aiProviderService.ts generateText:503), ProForge's
isFallback + SupervisionDecision { pass, qualityScore, reasons } confidence model, error
classification (classifyAiError), degraded-state UI atoms (AiModeIndicator, Badge, Toast), and
telemetry (recordInferenceTelemetry through the analytics gate).
Build the minimum that closes the real gaps, reusing those seams β no new orchestrator class.
- Heuristic-generator registry (
services/ai/heuristicFallback/) modeled on the existing rule engine:registerHeuristicGenerator(task, fn)+runHeuristicFallback(task, ctx). Each AI feature registers one generator keyed by a stable task id; if none is registered the call returnsnulland the caller keeps its existing behavior β so the layer is always safe to ship empty. - Shared envelope
HeuristicFallbackResult<T> = { data, isFallback: true, confidence (0..1), tier, reasonKey }β reuses ProForge'sisFallbackdiscriminator;confidenceis the one new field, calibrated likesupervisorAgent.confidenceScore. - Provider-layer seam β wire
runHeuristicFallbackinto the three choke points that callers already use:generateText's terminal (before the generic local stub),generateJson(the Gemini-direct path that previously had no fallback), andstreamText(deliver the heuristic throughonChunk+onDone). The seam carriesheuristicTask+heuristicContextonAIRequestOptions. We attach at the provider service rather than deep inlocalAiFacadebecause that is where the task id and feature context are available. - Degraded UX + telemetry β a small
useHeuristicFallback()hook over a module-level event observable feeds a reusableAssistedModeBadgeand records each fallback torecordInferenceTelemetry(existing schema:backend:'heuristic',taskType:'heuristic:<task>') through the analytics gate.
- A central Unified Fallback Orchestrator class (the brief's design) β rejected as over-engineering:
aiProviderService+inferenceGatewayalready are the single choke points; a new orchestrator would duplicate the routing/chain logic without earning its weight. - A new dedicated confidence type β rejected in favor of reusing ProForge's
isFallback+SupervisionDecision/confidenceconventions for cross-codebase consistency. - Re-pointing the
localAiFacadestub at the registry β deferred: the stub lacks the task id and feature context; the provider-layer seam is the better attachment point. The stub stays as the honest "no heuristic available" last resort.
- Positive: every targeted feature can degrade gracefully and offline; one consistent fallback model; minimal new surface (a tiny registry + one envelope + UI atoms); ships inert and safe, then lights up feature-by-feature.
- Negative / trade-offs: per-feature generators are real work (subsequent PRs); heuristic quality
depends on project context and templates; the generic
localAiFacadestub still exists for tasks with no registered generator. - Follow-ups (own PRs): structured generators (Outline/Character/World/Plot-Board), Writing Studio tools, analysis tools; later β Copilot rule expansion + learning/personalization.
See the plan and docs/AI-HEURISTIC-FALLBACKS.md (added with the first feature generators) for the
feature-level detail.