Files
alkblobs/tasks/store-pg-lo-construction.md
T
glm-5.3-flash cddcea3cfa feat(store): the pg-lo constructor wiring — the consolidation shape and the window-host completion (wave 5)
- 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).
2026-10-12 08:04:19 +00:00

17 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
store-pg-lo-construction pg-lo constructor wiring — the consolidation shape and the window-host completion completed
engine-pg-lo
engine-pg-lo-window
moderate medium component implementation
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

  • 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)
  • 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
  • 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)
  • 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
  • The connection-settings design point (two DSN+opts pairs; the consolidation corollary) decided and recorded
  • 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)
  • 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).