--- id: engine-pg-lo-window name: pg-lo engine-state window family — the conditional window host status: pending depends_on: [engine-pg-lo] scope: narrow risk: low impact: component level: implementation tags: [wave-5, engines, pg-lo, gc] --- ## Description Implement the engine-state companion seam's **window family** on the pg-lo backend (`src/pg_lo.rs`): the `EngineWindowState` impl per ADR-012 §5's pg-lo row — `ensure_gc_schema` creates **`gc_window` only**, the window clauses **conditional** per the one-window-host rule. **Nothing of `EngineFleetState` may exist on this engine** (the pg-lo row: pin clauses **no** — fleet pins live on the kv host, §4; sweep-lock clause **no**). The postgres engine's full-family impl (`src/postgres.rs`, wave 4) and the sqlite window-only impl (`src/sqlite.rs`, wave 3) are the reference implementations — same semantics, different dialect. - **`ensure_gc_schema`** — creates **`gc_window` only** (`gc_window (key bytea PRIMARY KEY, visible_after bigint)` per ADR-010 §2's schema, in the engine's own schema). Never `gc_pins` (contract-tested absent); the embedder's liveness table is never created here (ADR-008's schema-ownership rule — the sweep reads it and never owns it). **Whether the store core calls this clause at construction is the one-window-host rule's business** (`store-pg-lo-construction` wires it): the window hosts on the kv engine when it is SQL-backed (pg-lo's clauses **dormant** on a dual-SQL instance — kv=sqlite/postgres + large=pg-lo), and on pg-lo only when the kv engine is not SQL-backed (the kv=mem + large=pg-lo shape). The clause body exists and is contract-tested per applicability regardless of dormancy. - **`window_stage`** — stage candidates into the durable window, **idempotent per `(key, deadline)`** (the upsert discipline — a same-deadline re-stage is idempotent, a new-deadline re-stage updates the row; the sqlite/postgres engines' recorded semantics). - **`window_take(now)`** — take overdue candidates (`visible_after <= now`, the `<=` boundary the seam doc pins): the rows **leave the window table and return as keys** — one atomic step (`DELETE … RETURNING`, selection and removal together; a row is never handed out twice). Empty when nothing is overdue; virgin store: empty. - **Timestamp encoding** — the crate-wide encoding: signed i64 nanosecond count from the Unix epoch, carried as `BIGINT` (sub-second precision for the test tunings, pre-epoch negatives, full i64 range); per-engine bodies of the shared helpers (the shared-helper home decided in `engine-pg-lo`). - **Virgin-store tolerance split** — the postgres engine's recorded posture: `window_take` is a read (SQLSTATE 42P01 maps to empty on a schema-less database); `window_stage` is a write (surfaces the engine error — never silently creating schema; store construction always wires `ensure_gc_schema` when the engine hosts). - **Contract tests** per the applicability row (ADR-012 §5's table is the contract-test matrix): the schema creates the window table only (assert `gc_pins` does not exist); stage idempotence per `(key, deadline)` incl. the re-stage-at-new-deadline form; take returns exactly the overdue set, removes it, leaves future rows; the `<=` boundary incl. nanosecond slack; pre-epoch encoding; both virgin shapes. The store core drives these clauses only on the host topology (`store-pg-lo-construction`); this task ships the clauses and their engine-level contract tests. ## Acceptance Criteria - [ ] The pg-lo backend implements `EngineWindowState` — the window family only; no pin-clause or sweep-lock body exists anywhere in the pg-lo engine (nothing of `EngineFleetState`) - [ ] `ensure_gc_schema` creates `gc_window` only; `gc_pins` is never created by pg-lo (contract-tested); the embedder's liveness table is never created - [ ] `window_stage` idempotent per `(key, deadline)`; a re-stage at a new deadline updates the row - [ ] `window_take` returns exactly the overdue set (`<= now` boundary), removes it atomically, leaves future rows; empty on none/virgin - [ ] Contract tests env-driven (`ALKBLOBS_PG_*`), skipping cleanly server-less; green against the harness server (`pglo-poc`, :15432, db `blobs`, `postgres`/`poc`) at acceptance; the janitor discipline rides from the start (amendment A2) - [ ] `cargo test` (default) green; `cargo test --features pg-lo` green server-less (skipping); `cargo clippy --all-targets -- -D warnings` and `cargo fmt --check` green (default + `--features pg-lo`); the pg-lo pure builds clean (`--no-default-features --features "pg-lo,mem"` and `--features "postgres,pg-lo"` — the literal kv-less config is not a gate, see `store-pg-lo-construction`) ## References - src/gc.rs (`EngineWindowState` — the seam contract and its clause docs) - docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §5 (the applicability table — the pg-lo row; the one-window-host rule), §6.7 (the executor) - docs/architecture/decisions/010-backend-io-seams-and-fleet-state-home.md §2 (the clause bodies; the gc_window schema) - docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md §2 (the durable window's semantics) - src/sqlite.rs, src/postgres.rs (the window family's reference implementations — same semantics, different dialects) - tasks/engine-pg-lo.md (the driver posture this rides; the shared-helper design point) ## Notes > To be filled by implementation agent ## Summary > To be filled on completion