- LargeEngine::PgLo slots in behind `pg-lo` + all six large-op dispatch arms; the large cursor/staging bodies land as the LargeCursor/LargeStaging sub-enums behind AnyCursor/AnyStaging's one large arm (the recorded KvCursor pattern's large-tier twin) - dual_tier_postgres_pglo (the consolidation posture; two DSN+opts pairs, implicitly non-fleet, completing the fleet-valid engine set) and dual_tier_mem_pglo (the one-window-host rule's named test topology), both carrying the constructor-tunable delete-window delay - ensure_gc_schema_at_construction: the one-window-host rule's store-core dispatch (kv host on dual-SQL — pg-lo's window clauses dormant; pg-lo host on kv=mem); the sweep's mem arm gains the large-host delegation, the branch keyed off the engine representation never a flag - stale scope notes updated to the landed state (store.rs module doc, LargeEngine, the sweep docs, PUT_CHUNK, pg_lo.rs, gc.rs) - 7 new env-driven constructor tests (dedicated-database janitor discipline; consolidation + mem-pglo both shapes Verified live against the pglo-poc harness server: cargo test default 69/19/3, --features pg-lo 92/19/3, --features "pg-lo,mem" 151/54/4 (server-less 124/37/4), --no-default-features "postgres,pg-lo" 102/19/3 (both live and server-less), --all-features 188/71/4; clippy -D warnings and fmt --check green on all four configurations; cargo doc clean. The literal kv-less pg-lo config re-confirmed structurally uncompilable (d69d9a3's finding; not a gate).
287 lines
17 KiB
Markdown
287 lines
17 KiB
Markdown
---
|
|
id: store-pg-lo-construction
|
|
name: pg-lo constructor wiring — the consolidation shape and the window-host completion
|
|
status: completed
|
|
depends_on: [engine-pg-lo, engine-pg-lo-window]
|
|
scope: moderate
|
|
risk: medium
|
|
impact: component
|
|
level: implementation
|
|
tags: [wave-5, store, pg-lo, construction]
|
|
---
|
|
|
|
## Description
|
|
|
|
Slot pg-lo 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"). This task also completes the
|
|
one-window-host rule's store-core wiring, which is more than slotting:
|
|
the durable window gains its large-engine host arm.
|
|
|
|
- **`LargeEngine::PgLo`** variant behind `#[cfg(feature = "pg-lo")]` +
|
|
the six large-op dispatch arms (`put_staged`/`get`/`has`/`size`/
|
|
`delete`/`list`).
|
|
- **The large cursor bodies slot in** — `AnyCursor::Large` and
|
|
`AnyStaging::Large` are currently **concrete over the local
|
|
bodies** (`LocalCursor`/`LocalStaging`). **Named design point (the
|
|
recorded `KvCursor` sub-enum pattern's large-tier twin)**: grow a
|
|
`LargeCursor`/`LargeStaging` sub-enum behind `AnyCursor`/`AnyStaging`'s
|
|
one large arm (local + pg-lo variants) rather than one `AnyCursor`
|
|
variant per large engine — the same bounded-memory argument as the
|
|
kv side, recorded for the review gate, with the store.rs design-point
|
|
notes updated to the landed state.
|
|
- **Named constructors**, feature-gated on `pg-lo` (default-off):
|
|
- **`dual_tier_postgres_pglo`** — kv = postgres + large = pg-lo: the
|
|
**consolidation posture** (ADR-009's "one engine to operate"); its
|
|
landing **completes the fleet-valid engine set** (the store.rs
|
|
module doc's recorded forward reference — pg-lo's wave-5
|
|
constructor is the last fleet-valid engine). **Implicitly
|
|
`fleet: false`** (ADR-012 §3): the ADR-005 in-process protocol
|
|
applies verbatim; the `fleet: true` declaration is wave 6 (the
|
|
composite fleet-validity predicate + constructor declarations)
|
|
slotting in without reshaping — no fleet parameter carried;
|
|
recorded in the constructor doc. **Connection-settings design
|
|
point**: two DSN + opts parameter pairs (kv and large) —
|
|
cross-instance kv=postgres + large=pg-lo is valid non-fleet
|
|
(ADR-012 §4), and the consolidation shape passes the same
|
|
DSN/opts to both; the suite factory's schema-sharing corollary
|
|
(one minted schema passed to both engines vs two schemas) is
|
|
recorded with it.
|
|
- **`dual_tier_mem_pglo`** — kv = mem + large = pg-lo (features
|
|
`mem` + `pg-lo`): **the one-window-host rule's named test
|
|
topology** (ADR-012 §5: the durable window hosts on the large
|
|
engine when the kv engine is not SQL-backed). Non-fleet (mem is
|
|
never fleet-valid).
|
|
- **No `kv_only(pg-lo)`** — pg-lo is a large engine; kv-only modes
|
|
take kv engines only. **No sqlite+pg-lo constructor this wave** —
|
|
valid non-fleet per ADR-012 §5 but not named by the plan; added on
|
|
demand (recorded).
|
|
- Both take the **delete-window delay** parameter (the
|
|
`DEFAULT_DELETE_WINDOW_DELAY` signature shape; `0` the legal
|
|
degenerate tuning) — the durable form's cadence knob on either
|
|
host.
|
|
- **The one-window-host rule's store-core completion** (the substance
|
|
of this task):
|
|
- **`ensure_gc_schema` at construction** — the call currently
|
|
dispatches on the kv-engine enum only. It must follow the host
|
|
rule: kv SQL-backed (sqlite/postgres) → the kv host's call (pg-lo's
|
|
window clauses dormant — the consolidation shape's pg-lo schema
|
|
carries **no `gc_window`**); kv = mem + large = pg-lo → the
|
|
**pg-lo host's call** (`gc_window` in the pg-lo schema). The
|
|
dispatch consults the large engine only when the kv engine is not
|
|
SQL-backed; it keys off the engine representation, never a flag.
|
|
- **The sweep form branch** — currently `KvEngine::Mem` runs the
|
|
inline form unconditionally. It gains the large-host arm: mem kv +
|
|
`LargeEngine::PgLo` runs the **durable form on the pg-lo host**
|
|
(`sweep_window_durable` is already generic over
|
|
`W: EngineWindowState` — the pg-lo arm slots in); mem kv +
|
|
`LargeEngine::Local` (or no large tier) stays inline. The
|
|
sqlite/postgres arms are untouched (their hosts win the window per
|
|
the rule). The module doc's recorded "pg-lo dormancy slots in
|
|
without reshaping" note is updated to the landed state (dormancy
|
|
did; the large-host arm is the reshaping the rule always named).
|
|
- **Stale scope notes / forward references updated** — the store.rs
|
|
module doc's wave-5 mentions (the engine-representation note, the
|
|
fleet-valid-set note, the one-window-host paragraph, the
|
|
`LargeEngine` doc's "pg-lo slots in at wave 5"), the `PUT_CHUNK` doc
|
|
note ("pg-lo's measured 512 KiB `lowrite` knee is that engine wave's
|
|
concern" — now landed; the engine's constant is the authority), and
|
|
any `#![allow(dead_code)]` scope notes whose scope changes (the
|
|
batch-delete helper's wave-6 note stays).
|
|
- **Constructor unit tests**: the modes construct and introspect
|
|
correctly (`mode()`/`threshold()`); `ensure_gc_schema` ran on the
|
|
**right host** in both shapes (consolidation: `gc_pins` + `gc_window`
|
|
on the kv schema, **no `gc_window` on the pg-lo schema** — the
|
|
dormancy assertion; mem-pglo: `gc_window` on the pg-lo schema); the
|
|
window-delay default is the pinned constant, tunable, `0` legal; the
|
|
dual-tier shapes round-trip end-to-end (a smoke put/get through both
|
|
tiers with LO placement asserted — the companion row + LO present,
|
|
kv entries not in pg); a mem-pglo durable-form sweep smoke
|
|
(zero-delay: first sweep stages into the pg-lo schema's `gc_window`
|
|
and executes nothing, second sweep executes the overdue set
|
|
re-arbitrated at execution time — the form-branch-is-large-host
|
|
proof). Env-driven (`ALKBLOBS_PG_*`), skipping cleanly server-less
|
|
(the engine tests' convention); the janitor discipline rides from
|
|
the start (amendment A2).
|
|
- **The pg-lo pure builds** — the supported non-default configurations
|
|
are `cargo check/test --no-default-features --features "pg-lo,mem"`
|
|
(the one-window-host topology's build; the mem-pglo constructor
|
|
constructible) and `cargo check --no-default-features --features
|
|
"postgres,pg-lo"` (ADR-013 §4's pg-pure consolidation build); verify
|
|
both compile clean. **The literal kv-less config
|
|
(`--no-default-features --features pg-lo`) is not a gate and cannot
|
|
compile the whole crate** — do not burn time on it: with no kv
|
|
feature enabled, `KvEngine`/`KvCursor` go empty (E0004) and the
|
|
facade's by-reference dispatch matches are non-exhaustive
|
|
(references are always considered inhabited, so an empty enum behind
|
|
`&` still requires arms). This is structural, not a bug: per ADR-011
|
|
§4 every constructor mode pairs a kv engine, so a build with zero kv
|
|
engines is not a supported configuration (ADR-013 §4's supported
|
|
non-default configurations all include one). The shared pieces
|
|
themselves (pg_common, the engines) compile in the literal config —
|
|
only store.rs errors. The finding is the wave-5 engine task's
|
|
(d69d9a3, recorded in its Notes); this task's verification uses the
|
|
two meaningful builds above.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [x] `LargeEngine::PgLo` slots in; all six large ops dispatch; the
|
|
large cursor/staging bodies slot through the recorded sub-enum
|
|
design point (the store.rs notes updated to the landed state)
|
|
- [x] `dual_tier_postgres_pglo` + `dual_tier_mem_pglo` constructors
|
|
exist behind feature `pg-lo`, take connection settings + opts +
|
|
threshold + window delay, fallible where I/O is fallible; the
|
|
consolidation constructor's doc records the implicitly-non-fleet
|
|
posture and the fleet-valid-set completion
|
|
- [x] `ensure_gc_schema` follows the one-window-host rule at
|
|
construction (kv host on dual-SQL — pg-lo schema carries no
|
|
`gc_window`; pg-lo host on kv=mem — contract-tested both shapes)
|
|
- [x] The sweep form branch runs the durable form on the pg-lo host
|
|
for kv=mem + large=pg-lo and the inline form otherwise; the
|
|
branch keys off the engine representation, never a flag
|
|
- [x] The connection-settings design point (two DSN+opts pairs; the
|
|
consolidation corollary) decided and recorded
|
|
- [x] The pg-lo pure builds (`--no-default-features --features
|
|
"pg-lo,mem"` and `--features "postgres,pg-lo"`) compile clean
|
|
(the literal kv-less config is not a gate — see the Description
|
|
bullet)
|
|
- [x] `cargo test` (default) green; `cargo test --features pg-lo` and
|
|
`--features "pg-lo,mem"` green server-less (skipping);
|
|
`cargo clippy --all-targets -- -D warnings` and `cargo fmt
|
|
--check` green (default + the pg-lo feature variants)
|
|
|
|
## References
|
|
|
|
- src/store.rs (the engine-representation design point; the
|
|
constructor modes; the slotting-in pattern; the `KvCursor` sub-enum
|
|
design point; the sweep form branch; the one-window-host paragraph)
|
|
- docs/architecture/decisions/011-vocabulary-tiers-engines-and-fleet-state.md
|
|
§4 (the constructor table; the consolidation posture's mode reading)
|
|
- docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md
|
|
§3 (fleet activation is a declaration — wave 6), §4 (the GC-state
|
|
host; cross-instance valid non-fleet), §5 (the one-window-host rule
|
|
and the pg-lo dormancy), §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/009-pg-lo-large-tier-engine.md (the
|
|
consolidation posture this constructor ships)
|
|
- docs/architecture/decisions/013-family-composition-reactive-boundary-and-feature-graph.md
|
|
§4 (the feature graph; the pg-lo-pure builds)
|
|
- tasks/engine-pg-lo.md, tasks/engine-pg-lo-window.md (the engine +
|
|
seam bodies this wires)
|
|
- tasks/store-postgres-construction.md (the structural twin's recorded
|
|
design points)
|
|
|
|
## Notes
|
|
|
|
> Implemented in `src/store.rs` + `src/pg_lo.rs` + `src/gc.rs` (wave 5,
|
|
> following `store-postgres-construction` — the structural twin — point
|
|
> for point). Recorded design points, as resolved:
|
|
>
|
|
> - **The large-tier sub-enums landed** — `LargeCursor` and
|
|
> `LargeStaging` behind `AnyCursor`/`AnyStaging`'s one large arm
|
|
> (the `KvCursor` pattern's large-tier twin, on the same
|
|
> bounded-variant argument; recorded for the review gate): local +
|
|
> pg-lo variants, `LargeStaging` carrying a scoped
|
|
> `#[allow(clippy::large_enum_variant)]` (the file-descriptor
|
|
> posture vs the held pooled checkout + tx — payloads structurally
|
|
> dissimilar, dispatch by reference/consumption; the `KvEngine`
|
|
> enum's recorded allow posture). No reshaping of `AnyCursor`/
|
|
> `AnyStaging`/`Blob`.
|
|
> - **The one-window-host rule's store-core completion** —
|
|
> `ensure_gc_schema_at_construction(kv, large)`: the store-core
|
|
> dispatch the constructors call, keyed off the engine
|
|
> representation (the kv arm on a SQL-backed kv engine; the large
|
|
> arm consulted only when the kv engine is not SQL-backed; in-
|
|
> process combinations structurally nothing). The sqlite and
|
|
> postgres constructors were re-routed through it (`kv_only_*` pass
|
|
> `None`; the dual-tier locals pass `Some(&large)`) — their
|
|
> semantics unchanged, and the mem arm's large-host branch is where
|
|
> the rule completes. The sweep's form branch gained exactly that
|
|
> arm: `KvEngine::Mem` matches on `self.large()` — `LargeEngine::PgLo`
|
|
> runs `sweep_window_durable` on the pg-lo host (already generic
|
|
> over `W: EngineWindowState`, so the arm is a delegation), anything
|
|
> else stays inline; sqlite/postgres arms untouched.
|
|
> - **Connection-settings design point** — the consolidation
|
|
> constructor takes **two DSN + opts pairs** (kv first, large
|
|
> second): cross-instance is valid non-fleet (ADR-012 §4), and the
|
|
> consolidation shape passes the same DSN/opts to both. Recorded
|
|
> with it: the suite factory's corollary (one minted schema passed
|
|
> to both engines vs two schemas — both engines' table names are
|
|
> distinct, so either mint is legitimate). The mem-pglo constructor
|
|
> takes one pair (kv = mem takes none).
|
|
> - **No `kv_only(pg-lo)`** (pg-lo is a large engine) and **no
|
|
> sqlite+pg-lo constructor this wave** (valid non-fleet per
|
|
> ADR-012 §5, not named by the plan) — both recorded in the
|
|
> store.rs module doc's constructor-modes section.
|
|
> - **Stale scope notes updated to the landed state** — the
|
|
> engine-representation doc's wave references, the dual-tier
|
|
> shapes' wave bullets, the fleet-declaration paragraph (the
|
|
> fleet-valid engine set is complete in the constructors — wave 6
|
|
> is the declaration's predicate and parameter alone), the
|
|
> one-window-host paragraph (dormancy landed; the large-host arm is
|
|
> the reshaping the rule always named), the `LargeEngine` doc, the
|
|
> `KvEngine::ensure_gc_schema` doc (now the kv-host arm the helper
|
|
> consumes), the sweep's docs (two forms' host sets), the
|
|
> `PUT_CHUNK` note (the engine's `LOWRITE_CHUNK` constant is the
|
|
> authority — landed), and the pg_lo/gc.rs module docs' forward
|
|
> references. The batch-delete helper's wave-6 note stays.
|
|
> - **Clippy scope note** — one `doc list item without indentation`
|
|
> fixup during the gate: a doc line beginning `+ large=pg-lo)`
|
|
> re-wrapped (the `+` was a markdown list marker).
|
|
> - **Tests (7 new, env-driven `ALKBLOBS_PG_*`, skipping cleanly
|
|
> server-less, janitor discipline from the start — amendment A2)** —
|
|
> two modules keyed to the constructor feature gates. The mem-pglo
|
|
> module (4 tests, on per-test dedicated databases — the C7 lesson's
|
|
> shape — with `DatabaseJanitor`): construction + introspection +
|
|
> the pg-lo-host schema assertions (`gc_window` present, `gc_pins`
|
|
> never); the end-to-end round-trip with LO placement asserted (kv
|
|
> entries never in the pg database, companion row present, size
|
|
> exact, LO content byte-exact); the window-delay
|
|
> default/tunings/zero; and the durable-form sweep smoke (zero
|
|
> delay: first sweep stages into the pg-lo schema's `gc_window` and
|
|
> executes nothing — the form-branch-is-large-host proof — second
|
|
> sweep executes the overdue set re-arbitrated at execution time).
|
|
> The consolidation module (3 tests, same dedicated-database
|
|
> discipline): construction + the kv-host-wins assertions (both GC
|
|
> tables in the kv schema, no `gc_window` in the pg-lo schema — two
|
|
> distinct schemas so the dormancy assertion observes genuine
|
|
> absence); the round-trip in the recorded corollary form (the same
|
|
> DSN + one minted schema to both engines, LO placement asserted);
|
|
> and the window-delay tunings. The test-side `plant_large` helpers
|
|
> in the existing test modules gained `PgLo` arms (the same
|
|
> all-features-exhaustiveness pattern as wave 4's `KvEngine` arms).
|
|
> - **The literal kv-less config (`--no-default-features --features
|
|
> pg-lo`) remains structurally uncompilable** (E0004 on the empty
|
|
> kv set, by-reference match arms requiring inhabitated variants)
|
|
> — the d69d9a3 finding, not a gate; verification used the two
|
|
> meaningful pure builds, both clean.
|
|
|
|
## Summary
|
|
|
|
> Completed 2026-10-12 (wave 5). pg-lo slotted into the facade:
|
|
> `LargeEngine::PgLo` with all six large-op dispatch arms, the
|
|
> `LargeCursor`/`LargeStaging` sub-enums behind `AnyCursor`/`AnyStaging`'s
|
|
> one large arm (the recorded `KvCursor` pattern's large-tier twin),
|
|
> the one-window-host rule's store-core completion
|
|
> (`ensure_gc_schema_at_construction` — kv host on dual-SQL, pg-lo
|
|
> host on kv=mem; the sweep's mem arm gains the large-host delegation,
|
|
> the branch keyed off the engine representation never a flag), and
|
|
> the two named constructors (`dual_tier_postgres_pglo` — the
|
|
> consolidation posture, two DSN+opts pairs, implicitly non-fleet,
|
|
> completing the fleet-valid engine set — and `dual_tier_mem_pglo` —
|
|
> the one-window-host rule's named test topology), both carrying the
|
|
> constructor-tunable delete-window delay (`DEFAULT_DELETE_WINDOW_
|
|
> DELAY` pinned at 5 min, `0` legal). Stale scope notes updated to the
|
|
> landed state (store.rs module doc, `LargeEngine`, the sweep docs,
|
|
> `PUT_CHUNK`, pg_lo.rs, gc.rs). Verification (harness server live
|
|
> 2026-10-12): `cargo test` 69/19/3 ok (default); `cargo test
|
|
> --features pg-lo` 92/19/3 ok live and green server-less; `cargo test
|
|
> --features "pg-lo,mem"` 151/54/4 ok live, 124/37/4 ok server-less;
|
|
> `cargo test --no-default-features --features "postgres,pg-lo"`
|
|
> 102/19/3 ok live and server-less; `cargo test --all-features`
|
|
> 188/71/4 ok (7 new constructor tests green live); clippy `-D
|
|
> warnings` green on default, all-features, `pg-lo,mem`, and
|
|
> `postgres,pg-lo`; `cargo fmt --check` green; `cargo doc --no-deps`
|
|
> clean. The literal kv-less config re-confirmed structurally
|
|
> uncompilable (d69d9a3's finding; not a gate). |