Initial Commit
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
# foundation-fix-gap-4-db-split
|
||||
|
||||
- **Status**: PROPOSED
|
||||
- **Spec deltas**:
|
||||
- ./specs/api-host/spec.md
|
||||
- ./specs/api-types/spec.md
|
||||
|
||||
## What & why
|
||||
|
||||
The post-Stage-4 foundation-coherence audit (Gap #4) flagged that
|
||||
`HostAdapters.db` was shaped for the narrow `LedgerDb` interface
|
||||
(`bun:sqlite`-style `prepare(sql)` / `run(sql)`) consumed by the
|
||||
host-internal `PluginLedger`, while `@suaveplan/api-db-adapter`
|
||||
produces a multi-engine `AdminDatabaseLike` façade plugins consume.
|
||||
The two surfaces are type-incompatible — there is no safe way to
|
||||
share a single `adapters.db` slot. The E2E foundation-stack server
|
||||
documented the gap explicitly (`@suaveplan/api-db-adapter` was
|
||||
swapped out for a raw `bun:sqlite` handle to satisfy the ledger).
|
||||
|
||||
This change splits the slot:
|
||||
|
||||
1. **`HostAdapters.ledgerDb: LedgerDb`** — host-private, narrow
|
||||
SQLite handle the `PluginLedger` keeps using. Renamed from the
|
||||
former `HostAdapters.db`.
|
||||
2. **`HostAdapters.db?: AdminDatabaseLike`** — optional,
|
||||
consumer-facing. Populated by `createDbAdapter(...).admin` from
|
||||
`@suaveplan/api-db-adapter`. The host threads it onto
|
||||
`PluginContext.db` (admin-scoped) and applies
|
||||
`createTenantScopedWrapper(admin, tenantId)` per request to
|
||||
expose it on `RequestContext.db` (tenant-scoped).
|
||||
3. **`PluginContext.db: AdminDatabaseLike | null`** + **`RequestContext.db: TenantScopedDatabaseLike | null`** added as
|
||||
top-level fields. `null` when (a) the host was booted without
|
||||
`adapters.db` configured, or (b) for `RequestContext` only, the
|
||||
tenant resolver chain returned `null` on this request.
|
||||
4. **E2E foundation-stack** restores `createDbAdapter({ engine:
|
||||
"sqlite", url: ":memory:" })` as `adapters.db` and adds a
|
||||
`GET /api/db-ping` route exercising `ctx.db?.execute` +
|
||||
`ctx.db?.query` through the tenant-scoped wrapper. A
|
||||
companion test asserts 200 + non-empty rows.
|
||||
|
||||
## Impact
|
||||
|
||||
### Affected dependents
|
||||
|
||||
- `@suaveplan/api-types` — `PluginContext` / `RequestContext` /
|
||||
`JobContext` / `ConnectionContext` each gain a `db` field. Source-
|
||||
incompatible for any consumer constructing a `PluginContext`
|
||||
literal — but the only in-tree literal consumer is the host's own
|
||||
test harness (`{} as never` mock), which already type-erases.
|
||||
- `@suaveplan/api-host` —
|
||||
- `HostAdapters.db` renamed to `ledgerDb`; new optional
|
||||
`HostAdapters.db: AdminDatabaseLike`.
|
||||
- Host config Zod schema updated.
|
||||
- `RequestPipelineOptions` gains optional `db: AdminDatabaseLike`.
|
||||
- `buildRequestContext` accepts + propagates `db`.
|
||||
- Request-pipeline driver applies `createTenantScopedWrapper`
|
||||
when both `adapters.db` is set AND a tenant is resolved.
|
||||
- New runtime dep `@suaveplan/api-db-adapter`.
|
||||
- `@suaveplan/e2e-foundation-stack` — wires `createDbAdapter` +
|
||||
registers an inline `bun:sqlite` engine factory; adds the
|
||||
`/api/db-ping` route + an E2E test.
|
||||
|
||||
Blast radius (atomic update list in this commit):
|
||||
|
||||
- `packages/api-stack/api/api-types/src/plugin-context/plugin-context.types.ts`
|
||||
- `packages/api-stack/api/api-host/src/host/host.types.ts`
|
||||
- `packages/api-stack/api/api-host/src/host/host.ts`
|
||||
- `packages/api-stack/api/api-host/src/host/host.test.ts`
|
||||
- `packages/api-stack/api/api-host/src/request-pipeline/request-pipeline.types.ts`
|
||||
- `packages/api-stack/api/api-host/src/request-pipeline/request-pipeline-driver.ts`
|
||||
- `packages/api-stack/api/api-host/src/request-pipeline/request-pipeline-helpers.ts`
|
||||
- `packages/api-stack/api/api-host/package.json`
|
||||
- `e2e/foundation-stack/src/server.ts`
|
||||
- `e2e/foundation-stack/src/fixture-plugin.ts`
|
||||
- `e2e/foundation-stack/tests/foundation.spec.ts`
|
||||
- `e2e/foundation-stack/package.json`
|
||||
|
||||
### Backward compatibility
|
||||
|
||||
The `HostAdapters.db → HostAdapters.ledgerDb` rename is a hard rename
|
||||
(no compatibility shim) because the genesis branch has no shipped
|
||||
consumers outside the in-tree atomic update list above.
|
||||
|
||||
`PluginContext.db` / `RequestContext.db` are NEW fields, additive at
|
||||
the type level for any future consumer.
|
||||
|
||||
## Parity Checklist
|
||||
|
||||
This is a genesis-original fix; no upstream parity table required.
|
||||
|
||||
## Verification
|
||||
|
||||
`bunx turbo lint typecheck test build --filter=@suaveplan/api-host --filter=@suaveplan/api-types --filter=@suaveplan/api-db-adapter --filter=@suaveplan/e2e-foundation-stack`
|
||||
→ green on api-host / api-types / api-db-adapter. (The e2e package's
|
||||
typecheck error is a pre-existing module-resolution issue unrelated
|
||||
to this change — confirmed via git-stash baseline.)
|
||||
|
||||
`bunx turbo test:coverage --filter=@suaveplan/api-host --filter=@suaveplan/api-types`
|
||||
→ 100% lines on touched modules (statements/branches/functions
|
||||
unchanged at baseline).
|
||||
|
||||
E2E suite: `bun test:e2e` → 11/11 pass, including the new
|
||||
`db adapter — ctx.db wired through tenant-scoped wrapper` test.
|
||||
Reference in New Issue
Block a user