Safely reconcile fallback and registered project partitions during dashboard startup. - Merge duplicate partition rows with fallback data taking precedence. - Validate unique indexes and foreign-key dependencies before rekeying. - Bind safely after failed promotion and stop non-retryable dashboard failures. - Add PostgreSQL reconciliation and supervisor coverage. Files changed: .changeset/fn-8419-rekey-partition-merge.md | 7 + packages/cli/src/bin.ts | 5 +- .../commands/__tests__/dashboard-supervise.test.ts | 16 +- packages/cli/src/commands/dashboard.ts | 41 ++- .../src/__tests__/postgres/schema-applier.test.ts | 178 +++++++++++- packages/core/src/async-secrets-store.ts | 9 +- packages/core/src/index.ts | 8 +- packages/core/src/postgres-errors.ts | 9 + packages/core/src/postgres/index.ts | 5 + packages/core/src/postgres/migration-stamping.ts | 318 ++++++++++++++++----- packages/core/src/postgres/startup-factory.ts | 49 +++- packages/core/src/process-supervisor.ts | 3 + packages/core/src/task-store/async-persistence.ts | 7 +- 13 files changed, 546 insertions(+), 109 deletions(-) Fusion-Task-Id: FN-8419 Fusion-Task-Lineage: bfc54e40-a31e-4b61-b6ae-01eb147efde1 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
252 lines
8.6 KiB
TypeScript
252 lines
8.6 KiB
TypeScript
/**
|
|
* PostgreSQL connection layer.
|
|
*
|
|
* FNXC:PostgresConnection 2026-06-24-02:05:
|
|
* Barrel export for the postgres connection subsystem. This module provides
|
|
* backend resolution (embedded vs external), connection pool management with
|
|
* the DATABASE_MIGRATION_URL split, and credential redaction.
|
|
*
|
|
* Consumers:
|
|
* - The embedded lifecycle feature (U2) calls createConnectionSetFromUrl()
|
|
* after starting the bundled Postgres.
|
|
* - The external startup path calls createConnectionSet() with DATABASE_URL set.
|
|
* - Tests use resolveBackend() and the credential-redact helpers directly.
|
|
*/
|
|
|
|
export {
|
|
resolveBackend,
|
|
resolveBackendWithOptions,
|
|
looksLikePoolerUrl,
|
|
poolerWarning,
|
|
describeBackendForLog,
|
|
DATABASE_URL_ENV,
|
|
DATABASE_MIGRATION_URL_ENV,
|
|
POOLER_PREPARED_STATEMENT_WARNING,
|
|
type BackendMode,
|
|
type ResolvedBackend,
|
|
type ResolveBackendOptions,
|
|
} from "./backend-resolver.js";
|
|
|
|
export {
|
|
createConnectionSet,
|
|
createConnectionSetFromUrl,
|
|
verifyConnection,
|
|
DatabaseConnectionError,
|
|
redactConnectionString,
|
|
type PostgresConnections,
|
|
type CreateConnectionOptions,
|
|
} from "./connection.js";
|
|
|
|
export {
|
|
registerEmbeddedRuntimeUrl,
|
|
releaseEmbeddedRuntimeLease,
|
|
invalidateEmbeddedRuntimeUrl,
|
|
getActiveEmbeddedRuntimeUrl,
|
|
clearActiveEmbeddedRuntimeUrl,
|
|
type EmbeddedRuntimeLease,
|
|
} from "./active-backend-registry.js";
|
|
|
|
export {
|
|
redactUrlPassword,
|
|
redactUrlQueryPassword,
|
|
redactKeywordPassword,
|
|
redactConnectionString as redactCredentials,
|
|
redactCredentialsFromMessage,
|
|
REDACTED_PASSWORD_PLACEHOLDER,
|
|
} from "./credential-redact.js";
|
|
|
|
// FNXC:RuntimeStartupWiring 2026-06-24-11:05:
|
|
// The embedded PostgreSQL lifecycle module (embedded-lifecycle.ts) imports the
|
|
// `embedded-postgres` package, which uses dynamic import() for platform-
|
|
// specific optional binaries (@embedded-postgres/linux-x64, etc.). Re-exporting
|
|
// it from this barrel would pull those unresolved imports into every consumer
|
|
// of @fusion/core — including the CLI bundle (tsup/esbuild bundles @fusion/*
|
|
// with noExternal), which breaks the build and the boot smoke on platforms
|
|
// whose optional binary is absent.
|
|
//
|
|
// The embedded lifecycle is therefore NOT re-exported here. The runtime
|
|
// startup factory (startup-factory.ts) loads it lazily via await import()
|
|
// only when FUSION_EMBEDDED_PG=1, and the integration tests import it
|
|
// directly from "./embedded-lifecycle.js". This keeps the embedded-postgres
|
|
// dependency out of the static import graph of every other consumer.
|
|
|
|
/**
|
|
* FNXC:PostgresSchema 2026-06-24-03:50:
|
|
* Drizzle schema-as-code for the three application databases (project/central/
|
|
* archive) and plugin-owned tables. The fresh migration baseline
|
|
* (migrations/0000_initial.sql) materializes these definitions; the schema
|
|
* applier applies the baseline + plugin hooks to a connection.
|
|
*/
|
|
export * as schema from "./schema/index.js";
|
|
export {
|
|
applySchemaBaseline,
|
|
getAppliedMigrations,
|
|
readBaselineMigrationSql,
|
|
SCHEMA_BASELINE_VERSION,
|
|
// FNXC:StaleBinaryGuard 2026-07-19-03:10 (U9b / R10): old-binary write refusal.
|
|
StaleBinarySchemaError,
|
|
assertBinaryNotOlderThanDatabase,
|
|
WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_VERSION,
|
|
PROJECT_OWNERSHIP_SCHEMA_VERSION,
|
|
SESSION_ADVISOR_ENABLED_SCHEMA_VERSION,
|
|
MIGRATION_BOOKKEEPING_TABLE,
|
|
} from "./schema-applier.js";
|
|
export {
|
|
roadmapPluginSchemaInit,
|
|
cePluginSchemaInit,
|
|
whatsappPluginSchemaInit,
|
|
evenRealitiesPluginSchemaInit,
|
|
reportsPluginSchemaInit,
|
|
cliPressPluginSchemaInit,
|
|
DEFAULT_PLUGIN_SCHEMA_INIT_HOOKS,
|
|
runPluginSchemaInitHooks,
|
|
runLoadedPluginSchemaInitHooks,
|
|
assertLoadedPluginSchemaInitHooksSupported,
|
|
type PluginSchemaInitHook,
|
|
type LoadedPluginSchemaContract,
|
|
} from "./plugin-schema-hook.js";
|
|
|
|
/**
|
|
* FNXC:AsyncDataLayer 2026-06-24-10:30:
|
|
* Async data-layer foundation (U4). The stable `AsyncDataLayer` interface that
|
|
* replaces the synchronous `DatabaseSync` adapter. Plugin stores and the
|
|
* decomposed task-store modules program against this interface so the
|
|
* SQLite→PostgreSQL backend swap is invisible to them (VAL-DATA-016).
|
|
*
|
|
* The `getDatabase()` accessor on `TaskStore` will return an async-capable
|
|
* connection backed by this interface; the direct-`prepare()` consumers that
|
|
* relied on the synchronous `Database` shape are converted in U15.
|
|
*
|
|
* Consumers:
|
|
* - U12-U14 (task-store module migrations) call `layer.transactionImmediate()`
|
|
* and `recordRunAuditEventWithinTransaction(tx, ...)` to preserve the
|
|
* run-audit-event-within-transaction atomicity.
|
|
* - U6 (satellite stores) construct an `AsyncDataLayer` per database.
|
|
* - Plugin stores (`fusion-plugin-roadmap`) consume the stable interface.
|
|
*/
|
|
export {
|
|
createAsyncDataLayer,
|
|
recordRunAuditEvent,
|
|
recordRunAuditEventWithinTransaction,
|
|
projectTable,
|
|
type AsyncDataLayer,
|
|
type DrizzleDb,
|
|
type DbTransaction,
|
|
type TransactionOptions,
|
|
type RunAuditEventInput,
|
|
type RunAuditEvent,
|
|
} from "./data-layer.js";
|
|
|
|
/**
|
|
* FNXC:PostgresHealth 2026-06-24-16:00:
|
|
* PostgreSQL health and maintenance surface (U8). Replaces SQLite-specific
|
|
* surfaces (PRAGMA integrity_check, VACUUM-on-SQLite, WAL checkpointing,
|
|
* PRAGMA table_info schema self-heal) with PostgreSQL equivalents:
|
|
* - Health check via connectivity probe + pg_stat_database (VAL-HEALTH-001/002)
|
|
* - Schema drift detection via information_schema with self-heal (VAL-HEALTH-004)
|
|
* - Explicit VACUUM/ANALYZE compaction with stats (VAL-HEALTH-005)
|
|
* - Async task-ID integrity detector (VAL-HEALTH-003)
|
|
*/
|
|
export {
|
|
checkPostgresHealth,
|
|
detectSchemaDrift,
|
|
healSchemaDrift,
|
|
validateAndHealSchema,
|
|
vacuumAnalyze,
|
|
EXPECTED_PROJECT_COLUMNS,
|
|
type PostgresHealthSnapshot,
|
|
type SchemaDriftFinding,
|
|
type SchemaValidationReport,
|
|
type VacuumAnalyzeStats,
|
|
type VacuumAnalyzeResult,
|
|
} from "./postgres-health.js";
|
|
export {
|
|
detectTaskIdIntegrityAnomaliesAsync,
|
|
} from "./async-task-id-integrity.js";
|
|
|
|
/**
|
|
* FNXC:PostgresMigration 2026-06-24-10:00:
|
|
* SQLite-to-PostgreSQL data migration tool (U9 / VAL-MIGRATE-001..006).
|
|
* Snapshots the current final SQLite schema into PostgreSQL and bulk-copies
|
|
* all data across the three Fusion databases, idempotently and with
|
|
* verification. Used at cutover to migrate a populated SQLite deployment into
|
|
* PostgreSQL. The cutover harness (dual-read-cutover) and SQLite removal
|
|
* (sqlite-removal) features consume this tool.
|
|
*/
|
|
export {
|
|
migrateSqliteToPostgres,
|
|
isSqliteMigrationComplete,
|
|
getSqliteMigrationState,
|
|
completeSqliteMigration,
|
|
defaultMigrationSources,
|
|
formatMigrationProgress,
|
|
toSnakeCase,
|
|
type SqliteMigrationSource,
|
|
type SchemaName,
|
|
type MigrationOptions,
|
|
type SqliteMigrationState,
|
|
type MigrationReport,
|
|
type MigrationProgressEvent,
|
|
type MigrationProgressPhase,
|
|
type TableMigrationResult,
|
|
} from "./sqlite-migrator.js";
|
|
|
|
/**
|
|
* FNXC:CentralProjectIdentity 2026-07-13-23:10:
|
|
* Post-migration project-partition stamping, shared by the startup-factory
|
|
* first-boot auto-migration and the manual `fn db migrate` cutover command so
|
|
* migrated rows (tasks/archived_tasks/config/workflow settings) are re-keyed to
|
|
* the central-registry project id on BOTH paths.
|
|
*/
|
|
export {
|
|
stampMigratedProjectRows,
|
|
lookupRegisteredProjectIdByPath,
|
|
rekeyFallbackProjectPartition,
|
|
ProjectPartitionRekeyError,
|
|
selectDegradedBindTarget,
|
|
type StampMigratedProjectRowsInput,
|
|
type StampMigratedProjectRowsResult,
|
|
type ProjectPartitionOwnership,
|
|
type ProjectPartitionRekeyReason,
|
|
} from "./migration-stamping.js";
|
|
|
|
/**
|
|
* FNXC:BackendFlip 2026-06-26-14:30:
|
|
* Runtime startup factory (cutover milestone). `createTaskStoreForBackend()`
|
|
* is the single entry point production construction sites consult to decide
|
|
* how to boot PostgreSQL. Embedded PostgreSQL is the zero-config default and
|
|
* DATABASE_URL selects an external service; the removed SQLite opt-out is
|
|
* rejected so callers always receive a live backend result.
|
|
*/
|
|
export {
|
|
createTaskStoreForBackend,
|
|
createCentralBackendLayer,
|
|
shouldUsePostgresBackend,
|
|
isEmbeddedPgRequested,
|
|
isEmbeddedPgOptedOut,
|
|
EMBEDDED_PG_ENV,
|
|
NO_EMBEDDED_PG_ENV,
|
|
TEST_MODE_ENV,
|
|
TEST_DATABASE_URL_ENV,
|
|
TEST_DATABASE_MIGRATION_URL_ENV,
|
|
type BackendBootResult,
|
|
type CentralBackendLayerResult,
|
|
type CreateTaskStoreForBackendOptions,
|
|
} from "./startup-factory.js";
|
|
|
|
/**
|
|
* FNXC:PostgresBackup 2026-06-24-21:00:
|
|
* PostgreSQL backup and restore via pg_dump/pg_restore (U11 / VAL-REMOVAL-003).
|
|
* After the SQLite cutover, backups are PostgreSQL logical dumps instead of
|
|
* SQLite file copies. This module preserves the project + central pairing.
|
|
*/
|
|
export {
|
|
PgBackupManager,
|
|
PROJECT_BACKUP_SCHEMAS,
|
|
CENTRAL_BACKUP_SCHEMAS,
|
|
parsePgUrl,
|
|
type PgBackupOptions,
|
|
type PgBackupPair,
|
|
type PgDumpResult,
|
|
} from "./pg-backup.js";
|