- The column (tests/conformance/postgres_column.rs, feature `postgres`, default-off): the factories are the alkstore pg-factory pattern reused — `dual-tier postgres+local` (kv = postgres + large = local at the column-declared threshold 1024, window delay `Duration::ZERO`) and `kv-only(postgres)` at 1024 (the rejection row's host); a fresh engine-owned schema per `open()` (unique per call, seeded per tag/pid/time — racing opens included), registry-tracked per instance, teardown `DROP SCHEMA IF EXISTS … CASCADE` over exactly the minted schemas + the vended temp roots (idempotent, owned, panicking-row-safe) - The SKIP posture: connection settings ride the environment (ALKBLOBS_PG_HOST/PORT/USER/PASSWORD/DB), every runner gates behind a reachability probe, server-less runs skip cleanly (a skip is not a failure); the acceptance run is green against the harness server (dockerized `pglo-poc`, :15432 — the alkstore harness's same server) - Rows: the form-independent reference rows mirror verbatim (INV-1, INV-6, the NoLivenessSources/ProtectFailed abort shapes, the kv-only rejection row); the sqlite column's durable-schedule sweep family mirrors (schedule-relative INV-2/INV-3 readings, the two-sweep exact counts over the full protection set, the race across the window delay, the holder-stages-only lease shape, INV-5 list correctness); the dispatch rows adapt the placement oracle by medium (independent- connection counts of the schema's rows vs the root's committed files) plus the virgin-store row; every row ADR-stamped, traced to the backlog - Structural factory tests: fresh isolated opens (two opens mint distinct schemas and share nothing) and teardown against a panicking row (schemas really dropped, pg_namespace-verified) - README amended: the postgres rows table in §Columns beyond the reference set; the column plan's SKIP-posture note names the landed column; current state (four columns, waves 2–4) Verification: cargo test (default) 69/19/3 ok — the column compiles out; cargo test --features postgres 102/36/3 ok against the harness server (and green skipping server-less); cargo clippy --all-targets -- -D warnings green (default, postgres, all-features); cargo fmt --check green; pg_namespace verified schema-clean after live runs.
198 lines
11 KiB
Markdown
198 lines
11 KiB
Markdown
---
|
||
id: suite-column-postgres
|
||
name: Conformance suite — the postgres column (the SKIP-posture column)
|
||
status: completed
|
||
depends_on: [store-postgres-construction]
|
||
scope: moderate
|
||
risk: medium
|
||
impact: phase
|
||
level: implementation
|
||
tags: [wave-4, suite, postgres]
|
||
---
|
||
|
||
## Description
|
||
|
||
Grow the **postgres column** — the suite's first SKIP-posture column
|
||
(README §SKIP posture: SQL-attached factories ride a server; when no
|
||
server is reachable the column **skips cleanly** — a skip is not a
|
||
failure — and the wave's acceptance requires green **against the
|
||
server**). The column runs under `--features postgres` (feature
|
||
`postgres`, default-off).
|
||
|
||
- **Factories** (`tests/conformance/postgres_column.rs`):
|
||
- dual-tier `kv = postgres + large = local` at a column-declared
|
||
threshold and the **test tuning of the window delay (`0` —
|
||
execute-on-next-sweep)**;
|
||
- `kv-only(postgres)` at a column-declared threshold (the rejection
|
||
row's host; threshold materializable per the README's
|
||
configuration contract).
|
||
**The alkstore pg-factory pattern, reused** (`alkstore-postgres`
|
||
tests/contract_suite.rs): a **fresh engine-owned schema per
|
||
`open()`** — unique per call (seeded per tag/pid/time so two factory
|
||
instances never share a schema name, racing opens included), tracked
|
||
per-instance in a schema registry, teardown
|
||
`DROP SCHEMA IF EXISTS … CASCADE` over exactly the schemas the
|
||
instance minted (idempotent, owned — never the shared server's other
|
||
schemas; safe against an abandoned store: `CASCADE` removes
|
||
dependents server-side while the store's pooled connections fail
|
||
closed on next use). Panicking-row-safe — the sqlite column's
|
||
instance-tracks-its-own-site pattern over schemas instead of temp
|
||
dirs.
|
||
- **Connection settings ride the environment** — the alkstore harness
|
||
convention: `ALKBLOBS_PG_HOST/PORT/USER/PASSWORD/DB` (db defaulting
|
||
`postgres` if unset), a reachability probe gating the rows (the SKIP
|
||
posture's factory-owner responsibility). **The harness server**:
|
||
dockerized `pglo-poc` (`postgres:16-alpine`) on :15432, db `blobs`,
|
||
user/password `postgres`/`poc` — verified live 2026-10-12; the
|
||
container is long-running in the dev environment (the alkstore
|
||
harness's same server).
|
||
- **Mirror the form-independent reference rows** (README §The
|
||
reference row set): INV-1 round-trips (content matrix × both put
|
||
paths, in-body), INV-6 stat discipline, the `NoLivenessSources`/
|
||
`ProtectFailed` abort shapes (form-independent — abort before
|
||
staging), and the kv-only rejection row (threshold-agnostic by
|
||
discovery, unchanged).
|
||
- **The durable-schedule sweep rows** — the sqlite column's family
|
||
(README §The schedule-relative reading for SQL-backed columns):
|
||
INV-2 dedup and INV-3 stage hygiene with counts read against the
|
||
staged schedule, the two-sweep exact-count row over the full
|
||
protection set (both tiers, the window observed), the
|
||
sweep-vs-put race across the window delay (execution-time
|
||
re-arbitration), the holder-stages-only lease shape, and INV-5 list
|
||
correctness through durable-schedule outcomes.
|
||
- **The dual-tier dispatch rows** mirror the sqlite column's family
|
||
(pure-function routing, threshold boundaries, fall-through per op)
|
||
with the placement oracle adapted by medium: kv entries live as rows
|
||
in the pg schema's `blobs` table, large entries under the local
|
||
root — the oracle distinguishes by medium (an independent
|
||
connection counting the schema's rows vs the root's committed
|
||
files).
|
||
- **Virgin-store row**: reads are no-ops on a fresh schema (pool,
|
||
both GC tables, and committed tree all empty) — the constructor
|
||
always ensures the schema (the engine's recorded posture), this row
|
||
being the facade form.
|
||
- **Structural factory tests** (the mem/sqlite columns' pattern):
|
||
factory isolation (fresh schema per open, nothing shared — two
|
||
opens never observe one another) and teardown-against-a-panicking-row
|
||
(schemas really dropped).
|
||
- **README amendments** (the convention's normative test-side home):
|
||
the postgres rows table in §Columns beyond the reference set; the
|
||
column plan's SKIP-posture note now naming a landed column; current
|
||
state (four columns; the first SKIP-posture column, green against
|
||
the harness server).
|
||
|
||
## Acceptance Criteria
|
||
|
||
- [ ] The postgres column green **against the harness server**
|
||
(`pglo-poc`, :15432): the mirrored form-independent reference
|
||
rows + the durable-schedule sweep rows + the dispatch rows + the
|
||
virgin-store row, every row ADR-stamped and traceable to the
|
||
backlog
|
||
- [ ] Server-less runs skip cleanly (the reachability probe; the
|
||
default-build gates stay green with the column skipped)
|
||
- [ ] Factory isolation + idempotent teardown hold (fresh schema per
|
||
open; `DROP SCHEMA … CASCADE` over exactly the minted schemas;
|
||
teardown safe against a panicking row), structurally exercised
|
||
- [ ] README amendments recorded (the postgres rows table; current
|
||
state)
|
||
- [ ] `cargo test` (default) green — the column compiles out;
|
||
`cargo test --features postgres` green server-less (skipping)
|
||
and green against the server at acceptance;
|
||
`cargo clippy --all-targets -- -D warnings` and
|
||
`cargo fmt --check` green (default + `--features postgres`)
|
||
|
||
## References
|
||
|
||
- tests/conformance/README.md (the conventions this grows against;
|
||
§SKIP posture, §Columns beyond the reference set, §The
|
||
schedule-relative reading for SQL-backed columns)
|
||
- tests/conformance/factory.rs (the factory contract this implements)
|
||
- tests/conformance/rows.rs (the reference row set being mirrored)
|
||
- tests/conformance/sqlite_column.rs (the SQL-backed column pattern —
|
||
the durable-schedule rows' first host)
|
||
- /workspace/@alkdev/alkstore/alkstore-postgres/tests/contract_suite.rs
|
||
(the pg-factory pattern reused: fresh schema per open, the schema
|
||
registry, the CASCADE teardown, the env-driven DSN)
|
||
- docs/architecture/store-api.md (§Invariants — the test gate)
|
||
- docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md
|
||
§6.7 (the schedule the sweep rows assert against)
|
||
- docs/architecture/decisions/007-two-kv-engines-sqlite-and-postgres.md
|
||
§5 (the exact-count sweep-outcome gate against dockerized postgres)
|
||
|
||
## Notes
|
||
|
||
> Implemented in `tests/conformance/postgres_column.rs` + `main.rs` +
|
||
> `README.md` (wave 4, following `suite-column-sqlite` — the
|
||
> SQL-backed structural twin — and the alkstore pg-factory pattern).
|
||
> Recorded design points, as resolved:
|
||
>
|
||
> - **Factories as specced** — `DualTierPostgresFactory` (kv = postgres
|
||
> + large = local at the column-declared `TUNED_THRESHOLD` = 1024,
|
||
> window delay `WINDOW_DELAY` = `Duration::ZERO`, the test tuning)
|
||
> and `KvOnlyPostgresFactory` (`KV_ONLY_THRESHOLD` = 1024, the
|
||
> rejection row's host). Both hold the DSN, a schema sequence
|
||
> counter, and the per-instance schema registry (`Mutex<Vec<String>>,
|
||
> poisoned-lock via `unwrap_or_else(|e| e.into_inner())` per
|
||
> convention); `open()` mints `alkblobs_suite_{tag}_{pid}_{nanos}_{seq}`
|
||
> — unique per call, racing opens included — plus a fresh private
|
||
> temp root for the large tier (dual-tier; kv-only needs none),
|
||
> tracked per-instance. Teardown `DROP SCHEMA IF EXISTS "…" CASCADE`
|
||
> over exactly the minted schemas (one admin connection, then the
|
||
> drops) plus `remove_dir_all` over the vended roots (NotFound
|
||
> tolerated) — idempotent, owned, panicking-row-safe.
|
||
> - **SKIP posture as specced** — `harness_dsn()` rides
|
||
> `ALKBLOBS_PG_HOST/PORT/USER/PASSWORD/DB` (host required, non-empty;
|
||
> port/user/password/db defaulting to the harness server's values —
|
||
> :15432, `postgres`/`poc`, db `blobs` — the src/postgres.rs engine
|
||
> tests' exact convention, the alkblobs adaptation of the alkstore
|
||
> harness convention), `harness_ready()` probes with a 3 s-timed
|
||
> admin connection, every runner gates on it first, and the skip
|
||
> note prints once per skipped test. The acceptance run below is
|
||
> against the harness server — a skip never substituted.
|
||
> - **The medium oracle, adapted by medium** — an independent admin
|
||
> connection per count (`SELECT COUNT(*) FROM "schema".blobs` /
|
||
> `gc_window`) vs the root's committed files; `schema_exists` (the
|
||
> `pg_namespace` probe) instruments the structural teardown
|
||
> assertions.
|
||
> - **Rows** — the sqlite column's inventory mirrored point for point
|
||
> (the schedule-relative rows, the dispatch rows with the oracle's
|
||
> medium swapped, the virgin-store row read against a fresh schema,
|
||
> the structural factory tests adapted to schemas: two opens mint
|
||
> distinct schemas and share nothing, teardown-against-a-panicking
|
||
> row really drops the schemas); stamps cite the postgres rows of
|
||
> ADR-007/012 (ADR-007 §5 replacing the sqlite arm's citations).
|
||
> - **One cleanup caught in review-of-diff**: the `dual_tier` open
|
||
> tracks the temp *base* dir and constructs the store against
|
||
> `base.join("local-root")` — teardown removes the base directory
|
||
> wholesale (the root's parent), so the site removal is one
|
||
> operation like the sqlite column's.
|
||
> - The `pglo-poc` container was already running in the dev
|
||
> environment (verified with `docker ps` before implementation); no
|
||
> environment changes were needed.
|
||
|
||
## Summary
|
||
|
||
> Completed 2026-10-12 (wave 4). The postgres column — the suite's
|
||
> first SKIP-posture column — landed green against the harness server
|
||
> (`pglo-poc`, :15432): 17 conformance tests (the mirrored
|
||
> form-independent reference rows — INV-1 round-trips, INV-6 stat
|
||
> discipline, the `NoLivenessSources`/`ProtectFailed` abort shapes,
|
||
> the kv-only rejection row — the durable-schedule sweep rows (INV-2
|
||
> and INV-3 schedule-relative readings, the two-sweep exact-count row
|
||
> over the full protection set, the sweep-vs-put race across the
|
||
> window delay, the holder-stages-only lease shape, INV-5 list
|
||
> correctness), the dispatch rows with the placement oracle adapted to
|
||
> the pg medium, and the virgin-store row), every row ADR-stamped and
|
||
> traced to the backlog. Factory isolation (fresh schema per open,
|
||
> registry-tracked) and idempotent `DROP SCHEMA … CASCADE` teardown
|
||
> are structurally exercised (panicking-row-safe; `pg_namespace`
|
||
> verified empty after runs — the shared server carries no residue).
|
||
> README amended: the postgres rows table in §Columns beyond the
|
||
> reference set, the column plan's SKIP-posture note naming the
|
||
> landed column, and current state (four columns). Verification:
|
||
> `cargo test` (default) 69/19/3 ok — the column compiles out;
|
||
> `cargo test --features postgres` 102/36/3 ok green against the
|
||
> server, and green skipping server-less (17 skip-noted columns rows;
|
||
> default-build gates unaffected); `cargo clippy --all-targets -- -D
|
||
> warnings` green (default, `--features postgres`, `--all-features`);
|
||
> `cargo fmt --check` green. |