fix(FN-7952): require PostgreSQL in CLI and desktop#2110
Conversation
|
Warning Review limit reached
Next review available in: 24 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (20)
📝 WalkthroughWalkthroughThe CLI now treats PostgreSQL as the authoritative runtime store, uses ChangesPostgreSQL CLI lifecycle
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant CLICommand
participant ProjectContext
participant BackendFactory
participant TaskStore
participant CentralCore
CLICommand->>ProjectContext: resolve project and store owner
ProjectContext->>BackendFactory: createTaskStoreForBackend
BackendFactory-->>ProjectContext: taskStore and shutdown
CLICommand->>TaskStore: execute command operations
CLICommand->>ProjectContext: close project store
ProjectContext->>BackendFactory: shutdown backend
ProjectContext->>CentralCore: close retained core
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR makes PostgreSQL the required runtime store across CLI, desktop, and maintenance workflows. The main changes are:
Confidence Score: 4/5The research queue race should be fixed before merging.
packages/cli/src/commands/research.ts Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant CLI as Research CLI
participant DB as PostgreSQL
participant Dispatcher as Research Dispatcher
CLI->>DB: Create queued run with empty query
Dispatcher->>DB: Poll queued runs
DB-->>Dispatcher: Return incomplete run
Dispatcher->>Dispatcher: Start run with empty query
CLI->>DB: Store supplied query
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant CLI as Research CLI
participant DB as PostgreSQL
participant Dispatcher as Research Dispatcher
CLI->>DB: Create queued run with empty query
Dispatcher->>DB: Poll queued runs
DB-->>Dispatcher: Return incomplete run
Dispatcher->>Dispatcher: Start run with empty query
CLI->>DB: Store supplied query
Reviews (4): Last reviewed commit: "fix(FN-7952): resolve CLI lifecycle feed..." | Re-trigger Greptile |
8b9125d to
73ed302
Compare
Move CLI commands, desktop startup, and operational maintenance scripts onto the authoritative PostgreSQL lifecycle without runtime SQLite fallback. Fusion-Task-Id: FN-7952
Fusion-Task-Id: FN-7952
4cf7da9 to
bff151c
Compare
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/cli/src/commands/project.ts (2)
152-180: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winUse the backend shutdown owner as the sole cleanup path.
boot.shutdown()already closesboot.taskStore; closing the store first performs teardown twice and obscures ownership.Proposed fix
- try { - await store?.close(); - } catch { - // Best-effort: an already-closed/never-initialized store must not throw. - } if (backendShutdown) { await backendShutdown().catch(() => undefined); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/commands/project.ts` around lines 152 - 180, Update the cleanup logic in the surrounding task-counting function to use backendShutdown as the sole teardown path: remove the direct store.close() call from finally and invoke boot.shutdown() when available, preserving best-effort error handling for shutdown failures.
361-373: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winTreat
BackendBootResult.shutdown()as the sole cleanup owner.The current production paths manually close the store, while one test mock omits that behavior from shutdown. This causes double closure and leaks the backend when initialization rejects.
packages/cli/src/commands/project.ts#L361-L373: wrap initialization intry/finallyand invoke onlyboot.shutdown().packages/cli/src/commands/project.ts#L152-L180: remove the directstore.close()and invoke the retained shutdown owner.packages/cli/src/commands/__tests__/project-lock-retry.test.ts#L49-L51: make mocked shutdown call the corresponding task store’sclose().🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/commands/project.ts` around lines 361 - 373, Make BackendBootResult.shutdown() the sole cleanup owner: in packages/cli/src/commands/project.ts lines 361-373, wrap store initialization in try/finally and invoke only boot.shutdown(), ensuring cleanup runs when initialization rejects; in packages/cli/src/commands/project.ts lines 152-180, remove direct store.close() calls and retain shutdown cleanup; in packages/cli/src/commands/__tests__/project-lock-retry.test.ts lines 49-51, update the mocked shutdown to close its corresponding task store.
🧹 Nitpick comments (2)
packages/cli/src/commands/agent.ts (1)
167-173: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove redundant
catchblocks.The
catchblock is completely redundant because it only executescloseAgentStoreSafely(agentStore)before rethrowing, and thefinallyblock immediately executes the exact same cleanup.
packages/cli/src/commands/agent.ts#L167-L173: Remove thecatchblock and leave only thefinallyblock forrunAgentStop.packages/cli/src/commands/agent.ts#L222-L228: Remove thecatchblock and leave only thefinallyblock forrunAgentStart.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/commands/agent.ts` around lines 167 - 173, Remove the redundant catch blocks from runAgentStop at packages/cli/src/commands/agent.ts lines 167-173 and runAgentStart at lines 222-228; retain each finally block’s closeAgentStoreSafely(agentStore) and owned.cleanup() calls so cleanup still runs while errors propagate naturally.packages/cli/src/project-resolver.ts (1)
973-1018: 🚀 Performance & Scalability | 🔵 TrivialCap status fan-out in
getProjectsWithStatus.createTaskStoreForBackendstill opens a fresh connection set per call, so a large registry can create N concurrent pools on this hot path. Reuse one backend boot for the listing or bound the concurrency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/project-resolver.ts` around lines 973 - 1018, Update getProjectsWithStatus so task listing does not create one concurrent createTaskStoreForBackend boot per project. Prefer initializing a single shared backend boot for the operation and reusing its task store across project listings, ensuring its shutdown runs once after all work completes; otherwise introduce an explicit concurrency limit while preserving per-project taskCount fallback behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/__tests__/project-resolver.test.ts`:
- Around line 177-207: Add rejection cases for listTasks in both
getProjectsWithStatus and getProjectTaskCounts, and assert the operation rejects
while the owned store’s shutdown function is still called once. Preserve the
existing successful-path assertions and use the same createTaskStoreForBackend
mocks to cover both aggregate status and one-shot column-count flows.
In `@packages/cli/src/commands/__tests__/agent-import.test.ts`:
- Around line 9-12: Update the resolveAgentStoreBase mock used by the
agent-import tests so asyncLayer is a non-null fake PostgreSQL backend, matching
the updated agent export and command test fixtures; keep the mock’s existing
rootDir and cleanup behavior unchanged.
In `@packages/cli/src/commands/__tests__/project-lock-retry.test.ts`:
- Line 48: Update the FNXC comment in the project-lock retry test to describe
the current mock and decision now that it no longer returns null, and replace
the date-only timestamp with the required yyyy-MM-dd-hh:mm format. Keep the
existing FNXC:Area-of-product structure and do not add an FNXC_LOG token.
- Around line 49-51: Update the createTaskStoreForBackend mock so its shutdown
implementation explicitly invokes taskStore.close() before resolving. Preserve
the existing shutdown mock behavior while ensuring the mock owns TaskStore
lifecycle cleanup like production BackendBootResult.shutdown().
In `@packages/cli/src/commands/__tests__/settings-export.test.ts`:
- Around line 166-171: Update the test case around runSettingsExport to verify
cleanup ordering, not just invocation count: capture or inspect the call order
of closeProjectStore and createTaskStoreForBackend, and assert closeProjectStore
is invoked before backend startup is attempted. Keep the existing startup
failure assertion and cleanup-count check.
In `@packages/cli/src/commands/agent-import.ts`:
- Around line 236-239: Update the exitWithCleanup helper so base.cleanup()
always runs even when agentStore.close() throws by placing cleanup in a finally
block. Preserve the helper’s Promise<never> exit behavior, ensuring
process.exit(code) occurs after all teardown attempts.
In `@packages/cli/src/commands/chat.ts`:
- Around line 33-37: Ensure cleanup always runs when store closure fails: in
packages/cli/src/commands/chat.ts lines 33-37, wrap store.close() in a
synchronous try/catch before awaiting base.cleanup(); in lines 229-233, apply
the same pattern to agentStore.close() so ownedAgentStore.cleanup() executes,
and safely suppress rejection from messageOwner?.db.close() with catch handling.
In `@packages/cli/src/commands/desktop.ts`:
- Around line 35-36: Update the FNXC comment in the desktop startup section to
replace the date-only timestamp with the actual change date and time in
yyyy-MM-dd-hh:mm format, while preserving the existing FNXC:PostgresCutover
prefix and comment content.
In `@packages/cli/src/commands/experiment-finalize.ts`:
- Around line 53-55: Prevent shutdown rejection from bypassing CLI termination:
in packages/cli/src/commands/experiment-finalize.ts lines 53-55, update
exitWithError to contain or handle shutdown failure, then preserve the original
mapped error and established exit code; in
packages/cli/src/commands/settings-export.ts lines 38-42, apply the same
teardown-failure guard so error handling always reaches the intended failure
process.exit.
In `@packages/cli/src/commands/mission.ts`:
- Around line 227-230: Update the FNXC comment near the PostgreSQL
mission-interview draft query to include the required hour-and-minute component
in its date, using the yyyy-MM-dd-hh:mm format while preserving the existing
area and explanation.
In `@packages/cli/src/project-context.ts`:
- Around line 48-55: Update the store shutdown flow around
owner.backendShutdown(), owner.central?.close(), and owner.closePromise so
teardown errors are not swallowed as successful completion. Ensure both
resources are attempted, but only delete the owner and add the store to
closedProjectStores after both close operations succeed; preserve or reset
closePromise on failure so callers can observe the error or retry cleanup.
---
Outside diff comments:
In `@packages/cli/src/commands/project.ts`:
- Around line 152-180: Update the cleanup logic in the surrounding task-counting
function to use backendShutdown as the sole teardown path: remove the direct
store.close() call from finally and invoke boot.shutdown() when available,
preserving best-effort error handling for shutdown failures.
- Around line 361-373: Make BackendBootResult.shutdown() the sole cleanup owner:
in packages/cli/src/commands/project.ts lines 361-373, wrap store initialization
in try/finally and invoke only boot.shutdown(), ensuring cleanup runs when
initialization rejects; in packages/cli/src/commands/project.ts lines 152-180,
remove direct store.close() calls and retain shutdown cleanup; in
packages/cli/src/commands/__tests__/project-lock-retry.test.ts lines 49-51,
update the mocked shutdown to close its corresponding task store.
---
Nitpick comments:
In `@packages/cli/src/commands/agent.ts`:
- Around line 167-173: Remove the redundant catch blocks from runAgentStop at
packages/cli/src/commands/agent.ts lines 167-173 and runAgentStart at lines
222-228; retain each finally block’s closeAgentStoreSafely(agentStore) and
owned.cleanup() calls so cleanup still runs while errors propagate naturally.
In `@packages/cli/src/project-resolver.ts`:
- Around line 973-1018: Update getProjectsWithStatus so task listing does not
create one concurrent createTaskStoreForBackend boot per project. Prefer
initializing a single shared backend boot for the operation and reusing its task
store across project listings, ensuring its shutdown runs once after all work
completes; otherwise introduce an explicit concurrency limit while preserving
per-project taskCount fallback behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ff61df52-4251-43df-b597-bed77e175d41
📒 Files selected for processing (58)
.changeset/postgres-cli-lifecycle.mdpackages/cli/STANDALONE.mdpackages/cli/skill/fusion/references/fusion-capabilities.mdpackages/cli/skill/fusion/references/task-structure.mdpackages/cli/src/__tests__/experiment-finalize.test.tspackages/cli/src/__tests__/extension.test.tspackages/cli/src/__tests__/project-context-lifecycle.test.tspackages/cli/src/__tests__/project-context.test.tspackages/cli/src/__tests__/project-resolver.test.tspackages/cli/src/commands/__tests__/agent-export.test.tspackages/cli/src/commands/__tests__/agent-import.test.tspackages/cli/src/commands/__tests__/agent.test.tspackages/cli/src/commands/__tests__/desktop.test.tspackages/cli/src/commands/__tests__/ensure-project-registered.test.tspackages/cli/src/commands/__tests__/init.test.tspackages/cli/src/commands/__tests__/message.test.tspackages/cli/src/commands/__tests__/project-lock-retry.test.tspackages/cli/src/commands/__tests__/research-lock-retry.test.tspackages/cli/src/commands/__tests__/research.test.tspackages/cli/src/commands/__tests__/serve.test.tspackages/cli/src/commands/__tests__/settings-export.test.tspackages/cli/src/commands/__tests__/settings-import-lock-retry.test.tspackages/cli/src/commands/__tests__/settings-import.test.tspackages/cli/src/commands/__tests__/task-lock-retry.test.tspackages/cli/src/commands/agent-export.tspackages/cli/src/commands/agent-import.tspackages/cli/src/commands/agent.tspackages/cli/src/commands/chat.tspackages/cli/src/commands/db.tspackages/cli/src/commands/desktop.tspackages/cli/src/commands/ensure-project-registered.tspackages/cli/src/commands/experiment-finalize.tspackages/cli/src/commands/init.tspackages/cli/src/commands/message.tspackages/cli/src/commands/mission.tspackages/cli/src/commands/onboard-autolaunch.tspackages/cli/src/commands/project.tspackages/cli/src/commands/research.tspackages/cli/src/commands/settings-export.tspackages/cli/src/commands/settings-import.tspackages/cli/src/commands/workflow.tspackages/cli/src/extension.tspackages/cli/src/lock-retry.tspackages/cli/src/project-context.tspackages/cli/src/project-resolver.tspackages/desktop/src/__tests__/local-runtime.test.tspackages/desktop/src/__tests__/local-server.test.tspackages/desktop/vitest.config.tsscripts/__tests__/backfill-fn-4441-transition-evidence.test.mjsscripts/__tests__/start-local-project.test.mjsscripts/backfill-fn-4441-transition-evidence.mjsscripts/cache-stats.mjsscripts/lib/backend-db.mjsscripts/lib/start-local-project.mjsscripts/reconcile-fn-3909-identity.mjsscripts/reconcile-task-state-consistency.mjsscripts/restore-merge-sha-fn-3878.mjsscripts/start-local.mjs
|
Verification evidence for the deletion-ratchet ledger: a combined file-scoped CLI run on 2026-07-14 observed |
Fusion-Task-Id: FN-7952
Addressed in
Verification: focused changed suites passed; CLI typecheck and production lint passed; merge gate passed 479/479 (294 engine + 122 PostgreSQL + 63 CI-shape). The loaded-lane |
| }); | ||
|
|
||
| const runPromise = orchestrator.startRun(runId, options.query); | ||
| await store.getResearchStore().updateRun(runId, { query: options.query }); |
There was a problem hiding this comment.
Queue Complete Runs Atomically
createRun() first publishes a queued row with an empty query, and this separate updateRun() stores the supplied query afterward. When a server, daemon, or desktop engine is already polling the same database, its dispatcher can claim the row between these operations and call startRun() with an empty query. The run can then fail or produce results for the wrong input. Store the query when creating the queued row, or keep the row out of the dispatchable state until this update finishes.
## Summary Operators and contributors now have one current contract for the completed PostgreSQL cutover: PostgreSQL is mandatory runtime authority, legacy SQLite files are read-only migration evidence, and rollback is restore-based rather than a fallback toggle. The major changeset communicates the same boundary to published CLI users. ## Operational guidance - Documents the authoritative storage inventory and the five intentional legacy SQLite readers. - Defines maintenance-window migration, backup, restore-test, ownership, and isolation checks. - Clarifies lifecycle ownership for CLI, desktop, dashboard, engine, and bundled plugins. - Supersedes the earlier readiness review without deleting its historical record. ## Validation - Changeset format check passes. - `pnpm test:gate` passes all 478 gate tests on the completed stack. - Every file from the original oversized PR is represented in the replacement stack; this PR changes 22 files. ## Stack - Depends on #2111 → #2110 → #2109 → #2108. - Merge bottom-up in that order. Related: #2105
## Summary Operators and contributors now have one current contract for the completed PostgreSQL cutover: PostgreSQL is mandatory runtime authority, legacy SQLite files are read-only migration evidence, and rollback is restore-based rather than a fallback toggle. The major changeset communicates the same boundary to published CLI users. ## Operational guidance - Documents the authoritative storage inventory and the five intentional legacy SQLite readers. - Defines maintenance-window migration, backup, restore-test, ownership, and isolation checks. - Clarifies lifecycle ownership for CLI, desktop, dashboard, engine, and bundled plugins. - Supersedes the earlier readiness review without deleting its historical record. ## Validation - Changeset format check passes. - `pnpm test:gate` passes all 478 gate tests on the completed stack. - Every file from the original oversized PR is represented in the replacement stack; this PR changes 22 files. ## Stack - Depends on #2111 → #2110 → #2109 → #2108. - Merge bottom-up in that order. Related: #2105
## Summary Operators and contributors now have one current contract for the completed PostgreSQL cutover: PostgreSQL is mandatory runtime authority, legacy SQLite files are read-only migration evidence, and rollback is restore-based rather than a fallback toggle. The major changeset communicates the same boundary to published CLI users. ## Operational guidance - Documents the authoritative storage inventory and the five intentional legacy SQLite readers. - Defines maintenance-window migration, backup, restore-test, ownership, and isolation checks. - Clarifies lifecycle ownership for CLI, desktop, dashboard, engine, and bundled plugins. - Supersedes the earlier readiness review without deleting its historical record. ## Validation - Changeset format check passes. - `pnpm test:gate` passes all 478 gate tests on the completed stack. - Every file from the original oversized PR is represented in the replacement stack; this PR changes 22 files. ## Stack - Depends on #2111 → #2110 → #2109 → #2108. - Merge bottom-up in that order. Related: #2105
## Summary Bundled plugins now persist shared runtime state in project-scoped PostgreSQL tables instead of maintaining independent SQLite authority. Reports, CLI Printing Press, Compound Engineering, Roadmap, Even Realities, and WhatsApp all follow the same ownership and startup contract as Fusion core. ## Design decisions - Plugin schema hooks run through the host’s PostgreSQL owner and enforce project isolation. - The SDK exposes the host contract needed by bundled plugins without importing engine internals. - Legacy Roadmap ownership fixtures use the supported empty-owner sentinel, preserving current composite primary/foreign keys while exercising backfill behavior. - The lockfile travels with the Even Realities PostgreSQL dependency so packaged installs remain reproducible. ## Validation - All six affected plugin builds pass. - Affected plugin suites pass: 773 tests across Printing Press, Compound Engineering, Even Realities, Reports, Roadmap, and WhatsApp. - `pnpm test:gate` passes all 478 gate tests. - This PR changes 40 files. ## Stack - Depends on #2110 → #2109 → #2108. - The documentation/release PR completes the stack. Related: #2105 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Breaking Changes** * PostgreSQL is now required for runtime storage; SQLite files are used only as one-time migration inputs. * The legacy `FUSION_NO_EMBEDDED_PG` fallback has been removed. * **New Features** * Added project-isolated PostgreSQL storage for plugins, reports, tasks, notifications, and other plugin data. * Added agent tools for reports and CLI service drafts. * Added PostgreSQL schema initialization support for plugin authors. * **Bug Fixes** * Improved migration and recovery of legacy plugin state. * Prevented cross-project data access and strengthened transactional schema updates. * **Documentation** * Updated storage, migration, deployment, plugin authoring, CLI, and dashboard guidance for PostgreSQL. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary CLI commands, daemon/dashboard startup, packaged desktop startup, and live-data maintenance scripts now share the mandatory PostgreSQL lifecycle. Operators no longer risk a command silently reading or writing a disconnected SQLite shadow when PostgreSQL setup fails. ## Design decisions - Every startup owner retains and awaits its PostgreSQL shutdown callback, including partial-startup failure paths. - CLI project context and lock-retry flows resolve through asynchronous project stores. - Maintenance scripts use the shared backend helper; explicit database migration/inspection remains the only CLI surface allowed to read legacy SQLite sources. ## Validation - CLI and Desktop typechecks pass on the stacked branch. - `pnpm test:gate` passes all 478 gate tests. - This PR changes 54 files. ## Stack - Depends on #2109, which depends on #2108. - Bundled plugins and docs/release follow in later PRs. Related: #2105 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * PostgreSQL is now the authoritative store for structured project and task metadata. * Projects can be recognized and initialized using `.fusion/project.json`, without creating a legacy SQLite database. * CLI commands now retry transient PostgreSQL contention errors. * **Bug Fixes** * Improved cleanup when commands complete, fail, or run in the background, preventing lingering resources. * Improved desktop, server, and session shutdown reliability. * **Documentation** * Updated storage and standalone binary guidance to reflect PostgreSQL and legacy SQLite compatibility. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Bundled plugins now persist shared runtime state in project-scoped PostgreSQL tables instead of maintaining independent SQLite authority. Reports, CLI Printing Press, Compound Engineering, Roadmap, Even Realities, and WhatsApp all follow the same ownership and startup contract as Fusion core. ## Design decisions - Plugin schema hooks run through the host’s PostgreSQL owner and enforce project isolation. - The SDK exposes the host contract needed by bundled plugins without importing engine internals. - Legacy Roadmap ownership fixtures use the supported empty-owner sentinel, preserving current composite primary/foreign keys while exercising backfill behavior. - The lockfile travels with the Even Realities PostgreSQL dependency so packaged installs remain reproducible. ## Validation - All six affected plugin builds pass. - Affected plugin suites pass: 773 tests across Printing Press, Compound Engineering, Even Realities, Reports, Roadmap, and WhatsApp. - `pnpm test:gate` passes all 478 gate tests. - This PR changes 40 files. ## Stack - Depends on #2110 → #2109 → #2108. - The documentation/release PR completes the stack. Related: #2105 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Breaking Changes** * PostgreSQL is now required for runtime storage; SQLite files are used only as one-time migration inputs. * The legacy `FUSION_NO_EMBEDDED_PG` fallback has been removed. * **New Features** * Added project-isolated PostgreSQL storage for plugins, reports, tasks, notifications, and other plugin data. * Added agent tools for reports and CLI service drafts. * Added PostgreSQL schema initialization support for plugin authors. * **Bug Fixes** * Improved migration and recovery of legacy plugin state. * Prevented cross-project data access and strengthened transactional schema updates. * **Documentation** * Updated storage, migration, deployment, plugin authoring, CLI, and dashboard guidance for PostgreSQL. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
CLI commands, daemon/dashboard startup, packaged desktop startup, and live-data maintenance scripts now share the mandatory PostgreSQL lifecycle. Operators no longer risk a command silently reading or writing a disconnected SQLite shadow when PostgreSQL setup fails.
Design decisions
Validation
pnpm test:gatepasses all 478 gate tests.Stack
Related: #2105
Summary by CodeRabbit
New Features
.fusion/project.json, without creating a legacy SQLite database.Bug Fixes
Documentation