fix(FN-7952): establish PostgreSQL core authority (#2108)

## Summary

Fusion’s core runtime now treats PostgreSQL as the authoritative
metadata store without leaving current CLI, dashboard, desktop, or
engine composition roots uncompilable between stack layers. This is the
99-file foundation for the larger cutover: subsequent PRs migrate the
remaining consumers, plugins, and operator surfaces.

## Design decisions

- Runtime store construction fails closed when an asynchronous
PostgreSQL layer is unavailable; SQLite remains readable only at
explicit migration and identity-recovery boundaries.
- Project ownership is enforced across active, archived, workflow,
mission, analytics, and plugin-schema data.
- The small set of cross-package files in this layer are
compatibility-critical call sites required for a green intermediate
commit, not the complete consumer migration.
- Schema migration 0008 remains assigned to session-advisor state from
current `main`; mission lineage idempotency advances to 0009 so neither
invariant can be skipped.

## Validation

- All affected package typechecks pass: Core, Engine, Dashboard, CLI,
and Desktop.
- `pnpm test:gate` passes: 478 tests across the engine gate, PostgreSQL
core gate, and CLI workflow shape.
- The PR changes exactly 99 files.

## Stack

This is the base PR. Engine/dashboard, CLI/desktop/ops, plugins, and
docs/release follow as stacked PRs, each below 100 changed files.

Related: #2105


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* PostgreSQL is now the standard runtime backend, with embedded
PostgreSQL enabled by default.
* Added project-scoped storage for tasks, archives, chat sessions,
missions, knowledge pages, and operational data.
* Improved archived-task search, filtering, pagination, and restoration.
* Added safer plugin schema initialization with validation and project
isolation.
* Added PostgreSQL-backed workflow, mission, validator, and dashboard
capabilities.

* **Bug Fixes**
  * Improved startup timeout cancellation and resource cleanup.
* Prevented cross-project data access and phantom reservation cleanup
errors.
* Ensured archived tasks remain read-only and asynchronous writes
complete reliably.
  * Retired SQLite opt-out settings with clear startup errors.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
gsxdsm
2026-07-14 22:13:30 -07:00
committed by GitHub
parent e97081fb77
commit 2e4fcfcaea
99 changed files with 7026 additions and 5166 deletions

View File

@@ -239,30 +239,10 @@ export class PluginRunner {
const result = await this.options.pluginLoader.loadAllPlugins();
executorLog.log(`PluginRunner loaded ${result.loaded} plugins (${result.errors} errors)`);
// Execute onSchemaInit hooks from loaded plugins.
const schemaInitHooks = this.options.pluginLoader.getPluginSchemaInitHooks();
if (schemaInitHooks.length > 0) {
executorLog.log(`Executing onSchemaInit hooks from ${schemaInitHooks.length} plugins`);
try {
/*
* FNXC:PostgresCutover 2026-07-04:
* Skip the SQLite-specific runPluginSchemaInits path in backend mode.
* PostgreSQL uses Drizzle migrations for schema management. Matches the
* daemon.ts / dashboard.ts / serve.ts convention. Previously
* getDatabase() threw in backend mode and the catch swallowed it, so
* plugin onSchemaInit hooks silently never ran.
*/
if (this.options.taskStore.isBackendMode()) {
executorLog.log("onSchemaInit skipped — backend mode (PostgreSQL Drizzle migrations)");
} else {
const db = this.options.taskStore.getDatabase();
await db.runPluginSchemaInits(schemaInitHooks);
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
executorLog.log(`onSchemaInit execution failed: ${message}`);
}
}
/*
FNXC:PluginPostgresSchema 2026-07-14-21:48:
PluginLoader completes each plugin's backend-specific schema initialization before loadAllPlugins counts it as loaded. PluginRunner must not replay the accumulated contracts after loading.
*/
// Subscribe to store events for task lifecycle hooks
this.subscribeToStoreEvents();