- `KvEngine::Postgres` slotted in: all six kv-op dispatch arms, the `KvCursor::Postgres` materializing body behind `AnyCursor`'s kv arm (the recorded sub-enum design point, landed as predicted), and the engine-neutral `ensure_gc_schema` call creating `gc_pins` + `gc_window` in the fresh schema at construction (the fleet host's both-tables row, ADR-012 §5) - The two named constructors behind feature `postgres` (default-off): `dual_tier_postgres_local(config, opts, root, threshold, window_delay)` — the fleet-capable-kv production shape — and `kv_only_postgres(config, opts, threshold, window_delay)`; the DSN connection settings + engine opts ride the constructor parameters, never invented defaults. `PgOpts` is pub and re-exported from `lib.rs` (it is on the public constructor signature now) - The sweep's durable form runs on the postgres host: the form body extracted into `sweep_window_durable<W: EngineWindowState>` (sqlite's arm delegates, behavior unchanged), both SQL-backed arms keyed off the kv-engine enum, never a flag — wave 5's pg-lo dormancy slots in without reshaping - Non-fleet posture recorded on both constructors (ADR-012 §3): implicitly `fleet: false`, the ADR-005 in-process protocol verbatim, the `fleet: true` declaration is wave 6 and slots in without reshaping - Stale scope notes updated to the landed state (engine-representation doc, `KvCursor` design point, fleet-declaration paragraph, one-window-host paragraph, postgres module doc, gc.rs companion-seam note); the batch-delete helper's scope note stays (wave 6 consumer) - 5 new env-driven construction tests (skipping server-less): the modes construct and introspect, both GC tables exist in the fresh schema, the window-delay default is the pinned 5-min constant and tunable (`0` legal), the kv-only rejection wiring is unchanged, the dual-tier shape round-trips through both tiers, and the durable form is observed staging/executing across sweeps on the postgres host Verification: `cargo test` 69/19/3 ok; `cargo test --features postgres` 102/19/3 ok live (pglo-poc harness) and green server-less; `cargo test --no-default-features --features postgres` (the pg-pure build, ADR-013 §4) 75/2/3 ok server-less; `cargo test --all-features` 157/54/4 ok; clippy `-D warnings` green (default, postgres, pg-pure, all-features); `cargo fmt --check` green; `cargo doc --no-deps` clean.
215 lines
12 KiB
Markdown
215 lines
12 KiB
Markdown
---
|
|
id: store-postgres-construction
|
|
name: postgres constructor wiring — the fleet-capable store shapes
|
|
status: completed
|
|
depends_on: [engine-postgres, engine-postgres-fleet]
|
|
scope: narrow
|
|
risk: low
|
|
impact: component
|
|
level: implementation
|
|
tags: [wave-4, store, postgres, construction]
|
|
---
|
|
|
|
## Description
|
|
|
|
Slot postgres into the facade's engine representation — the slotting-in
|
|
pattern `src/store.rs`'s module doc pinned ("adding an enum variant and
|
|
a named constructor is slotting in"):
|
|
|
|
- **`KvEngine::Postgres`** variant behind `#[cfg(feature =
|
|
"postgres")]` + the dispatch arms (`put`/`get`/`has`/`size`/
|
|
`delete`/`list`). The kv cursor dispatch slots the postgres
|
|
materializing body into **`KvCursor`** (the recorded sub-enum design
|
|
point: "postgres (wave 4) slots one arm in here" — the store.rs doc
|
|
note is updated to the landed state).
|
|
- **Named constructors**, feature-gated on `postgres` (default-off —
|
|
they construct under `--features postgres`):
|
|
- **dual-tier** `kv = postgres + large = local` — the
|
|
fleet-capable-kv production shape (non-fleet here; see below);
|
|
fallible (config parse, connect, schema bootstrap, the local root
|
|
creation). Size-threshold dispatch at the constructor-tunable
|
|
threshold as in the sqlite shape.
|
|
- **kv-only(postgres)** — no large tier; `threshold` is the put-time
|
|
rejection point (ADR-012 §6.2; the rejection machinery is the put
|
|
seam's, already landed — only the constructor slots in).
|
|
- Both take the **connection settings + engine opts** (recorded
|
|
design point: the DSN form — the tokio-postgres `Config`-parseable
|
|
string, the alkstore `open(config, PgOpts)` pin adapted to the
|
|
named-constructor shape — and the opts shape carrying schema name,
|
|
pool size, `synchronous_commit`; engine-configuration concerns
|
|
ride the constructor parameters, never invented defaults) and the
|
|
**delete-window delay** parameter (`Duration`, default
|
|
`DEFAULT_DELETE_WINDOW_DELAY`, `0` the legal degenerate tuning —
|
|
the sqlite constructors' signature shape).
|
|
- **Non-fleet posture** — these constructors are implicitly
|
|
`fleet: false` (ADR-012 §3): the ADR-005 in-process protocol applies
|
|
verbatim regardless of engine; pins are in-process guards, the sweep
|
|
lease is the in-process lock, and none of the `EngineFleetState`
|
|
clauses run. **The `fleet: true` declaration is wave 6** (the
|
|
fleet-validity predicate + constructor declarations) — no fleet
|
|
parameter is added here; wave 6 slots it in without reshaping.
|
|
Recorded in the constructor docs so the wave-6 slotting is a
|
|
non-event.
|
|
- **`ensure_gc_schema` at construction** — the store-core call
|
|
(engine-neutral; the postgres arm creates `gc_pins` + `gc_window`
|
|
per the fleet host's applicability row). A construction failure is
|
|
`Err(Error::Io)` per the fallible-constructor pattern.
|
|
- **The one-window-host rule's store-core posture** — already recorded
|
|
(the durable window hosts on the kv engine when it is SQL-backed);
|
|
the postgres arm slots in under it with no reshaping. Verify the
|
|
recorded posture's wording covers postgres (it names "sqlite or
|
|
postgres" already — ADR-012 §5) and that the form branch keys off
|
|
the kv-engine enum, never a flag.
|
|
- **Stale scope notes updated** — the engine-representation doc's
|
|
"postgres (wave 4)" forward references, the `KvCursor` design-point
|
|
note, and any `#![allow(dead_code)]` scope notes whose scope changes
|
|
(the batch-delete helper's note stays — its consumer is still wave
|
|
6).
|
|
- **Constructor unit tests**: the modes construct and introspect
|
|
correctly (`mode()`/`threshold()`), `ensure_gc_schema` ran (both GC
|
|
tables exist in the fresh schema), the window-delay default is the
|
|
pinned constant, kv-only rejection wiring unchanged, the dual-tier
|
|
shape round-trips end-to-end (a smoke put/get through both tiers).
|
|
Env-driven, skipping cleanly server-less (the engine tests'
|
|
convention).
|
|
- **The pg-pure build** — `cargo check --no-default-features
|
|
--features postgres` (and the tests target under it): ADR-013 §4's
|
|
supported non-default configuration first becomes constructible
|
|
here; verify it compiles clean.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [x] `KvEngine::Postgres` slots in; all six kv ops dispatch; the kv
|
|
cursor body slots into `KvCursor` (the design-point note updated
|
|
to the landed state)
|
|
- [x] `dual_tier_postgres_local` + `kv_only_postgres` constructors
|
|
exist behind feature `postgres`, take connection settings +
|
|
engine opts + threshold + window delay, fallible where I/O is
|
|
fallible
|
|
- [x] `ensure_gc_schema` runs at construction (both GC tables in the
|
|
fresh schema); the window-delay shipped default is 5 min
|
|
(pinned constant) and constructor-tunable; `0` legal
|
|
- [x] The non-fleet posture recorded (in-process protocol verbatim;
|
|
the `fleet: true` declaration is wave 6, slotting in without
|
|
reshaping)
|
|
- [x] The one-window-host posture verified to cover postgres; the form
|
|
branch keys off the kv-engine enum
|
|
- [x] The pg-pure build (`--no-default-features --features postgres`)
|
|
compiles clean
|
|
- [x] `cargo test` (default) green; `cargo test --features postgres`
|
|
green server-less (skipping); `cargo clippy --all-targets -- -D
|
|
warnings` and `cargo fmt --check` green (default +
|
|
`--features postgres`)
|
|
|
|
## References
|
|
|
|
- src/store.rs (the engine-representation design point; the
|
|
constructor modes; the slotting-in pattern; the `KvCursor`
|
|
sub-enum design point)
|
|
- docs/architecture/decisions/011-vocabulary-tiers-engines-and-fleet-state.md
|
|
§4 (modes; the constructor table)
|
|
- docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md
|
|
§3 (fleet activation is a declaration — wave 6), §5 (the
|
|
one-window-host rule), §6.3 (dual-tier shapes)
|
|
- docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md
|
|
§2 (the window delay, default 5 min)
|
|
- docs/architecture/decisions/013-family-composition-reactive-boundary-and-feature-graph.md
|
|
§4 (the feature graph; the pg-pure build)
|
|
- tasks/engine-postgres.md, tasks/engine-postgres-fleet.md (the engine
|
|
+ seam bodies this wires)
|
|
- tasks/store-sqlite-construction.md (the structural twin's recorded
|
|
design points)
|
|
|
|
## Notes
|
|
|
|
> Implemented in `src/store.rs` + `src/postgres.rs` + `src/lib.rs`
|
|
> (wave 4, following `store-sqlite-construction` — the structural
|
|
> twin — point for point). Recorded design points, as resolved:
|
|
>
|
|
> - **Opts on the public surface** — `PgOpts` went `pub` (and is
|
|
> re-exported from `lib.rs` behind the feature gate): the
|
|
> constructors' engine-opts parameter is on the public constructor
|
|
> signature, so the type must be nameable there (the alkstore
|
|
> `open(config, PgOpts)` pin adapted to the named-constructor shape;
|
|
> the connection settings remain the separate DSN-string argument).
|
|
> - **`KvCursor` slotting** — postgres's materializing body slotted
|
|
> into the recorded sub-enum exactly as predicted: one variant, two
|
|
> `ReadCursor` impl arms, no reshaping of `AnyCursor`/`Blob`. The
|
|
> store.rs design-point note reads landed.
|
|
> - **`ensure_gc_schema`** rides the engine-neutral `KvEngine` call —
|
|
> the postgres arm forwards to the `EngineWindowState` clause (the
|
|
> fleet host's both-tables body: `gc_pins` + `gc_window` in the
|
|
> fresh schema), and both constructors dispatch through it (the
|
|
> store core calls the kv engine, never a typed postgres path).
|
|
> Construction failure is `Err(Error::Io)` per the fallible-
|
|
> constructor pattern (`?` throughout).
|
|
> - **The sweep's form branch** — the durable-form body was extracted
|
|
> into `sweep_window_durable<W: EngineWindowState>` (behavior
|
|
> unchanged for sqlite, whose arm now delegates); both SQL-backed
|
|
> arms call it, so the form branch still keys off the kv-engine
|
|
> enum, never a flag, and wave 5's pg-lo dormancy slots in without
|
|
> reshaping. The one-window-host posture's wording now names both
|
|
> SQL-backed hosts (module doc + the sweep doc).
|
|
> - **Non-fleet posture** — both constructors' docs carry the
|
|
> ADR-012 §3 recording verbatim: implicitly `fleet: false`, the
|
|
> ADR-005 in-process protocol applies regardless of engine (in-
|
|
> process pins, in-process sweep lease, no `EngineFleetState` clause
|
|
> runs), and the `fleet: true` declaration is wave 6, slotting in
|
|
> without reshaping — no fleet parameter carried.
|
|
> - **Signature shape** — `dual_tier_postgres_local(config, opts,
|
|
> root, threshold, window_delay)` / `kv_only_postgres(config, opts,
|
|
> threshold, window_delay)`: connection settings first (the
|
|
> tokio-postgres `Config`-parseable DSN string), engine opts second,
|
|
> then the sqlite twins' remaining parameters (root/threshold/
|
|
> window delay). The DSN is `&str` — `PostgresBackend::new` parses;
|
|
> no invented defaults anywhere.
|
|
> - **Clippy notes** — `KvEngine` needed a scoped
|
|
> `#[allow(clippy::large_enum_variant)]` under the postgres
|
|
> configs (the payloads are structurally dissimilar — one `Arc` vs
|
|
> the pooled-connection posture inline — and all dispatch rides the
|
|
> enum by reference, so the size difference costs nothing; recorded
|
|
> on the enum doc). The store-construction `table_exists` probe
|
|
> (pg_tables, schema-scoped) mirrors the sqlite engine's
|
|
> `#[cfg(test)]` instrument.
|
|
> - **Tests (5 new, env-driven, skipping server-less)** — dual-tier
|
|
> construction + routing + both-GC-tables schema check; kv-only
|
|
> construction + rejection wiring (immediate, overflow, zero
|
|
> residue, at-threshold lands); the window-delay default/tunings/
|
|
> zero; the dual-tier round-trip through both tiers with tier-
|
|
> placement assertions; and a durable-form sweep smoke (zero-delay:
|
|
> first sweep stages and executes nothing — the inline form would
|
|
> delete in-sweep, so this is the form-branch-is-postgres proof —
|
|
> the second sweep executes the overdue set re-arbitrated at
|
|
> execution time). The test-side `KvEngine` matches in the existing
|
|
> test modules gained `Postgres` arms for `--all-features`
|
|
> exhaustiveness.
|
|
> - Stale scope notes updated to the landed state: the engine-
|
|
> representation doc, the `KvCursor` design point, the fleet-
|
|
> declaration paragraph, the one-window-host paragraph, the
|
|
> postgres module doc's forward reference — and `gc.rs`'s
|
|
> companion-seam note (the fleet family now "waits for wave 6", its
|
|
> clause bodies landed with wave 4). The batch-delete helper's
|
|
> scope note stays (its consumer is still wave 6).
|
|
|
|
## Summary
|
|
|
|
> Completed 2026-10-12 (wave 4). Postgres slotted into the facade:
|
|
> `KvEngine::Postgres` with all six kv-op dispatch arms, the
|
|
> `KvCursor::Postgres` materializing body, the `ensure_gc_schema`
|
|
> engine-neutral call creating `gc_pins` + `gc_window` in the fresh
|
|
> schema at construction, and the two named feature-gated
|
|
> constructors (`dual_tier_postgres_local`, `kv_only_postgres`) taking
|
|
> the DSN connection settings + `PgOpts` (now public and re-exported) +
|
|
> threshold + the constructor-tunable delete-window delay
|
|
> (`DEFAULT_DELETE_WINDOW_DELAY` pinned at 5 min, `0` legal) — both
|
|
> implicitly non-fleet per ADR-012 §3 with wave 6's declaration
|
|
> recorded as a non-reshaping slotting. The sweep's durable form runs
|
|
> on the postgres host through the kv-engine-enum-keyed branch
|
|
> (`sweep_window_durable`, shared with sqlite's arm). Verification:
|
|
> `cargo test` 69/19/3 ok (default), `cargo test --features postgres`
|
|
> 102/19/3 ok live and green server-less, `cargo test
|
|
> --no-default-features --features postgres` (the pg-pure build, ADR-
|
|
> 013 §4's first constructible configuration) 75/2/3 ok server-less,
|
|
> `cargo test --all-features` 157/54/4 ok, clippy `-D warnings` green
|
|
> on default + postgres + pg-pure + all-features, `cargo fmt --check`
|
|
> green, `cargo doc --no-deps` clean. |