--- id: store-fleet-construction name: the fleet declaration — the composite fleet-validity predicate at the constructor status: completed depends_on: [] scope: moderate risk: medium impact: component level: implementation tags: [wave-6, store, construction, fleet] --- ## Description Slot the **`fleet: true` constructor declaration** into the fleet-capable constructors (ADR-012 §3; the recorded non-event the wave-4/5 constructor tasks pinned: "the `fleet: true` declaration is wave 6, slotting in without reshaping") — the composite fleet-validity predicate enforced at the constructor, the fleet constructor parameters, and the store's fleet state. Nothing here turns the fleet *mechanism* on (the joint-tx put driver is `store-fleet-put`, the fleet sweep is `store-fleet-sweep`); this task is the admission gate and the state those tasks consume. - **The declaration is explicit, never inferred** (ADR-012 §3): a store instance is constructed with fleet mode on or off. Under `fleet: false` (every existing constructor's implicit posture, unchanged): the ADR-005 in-process protocol verbatim regardless of engine. Under `fleet: true`: the composite fleet-validity predicate is enforced at construction, and the fleet machinery activates (the later tasks' wiring). - **The composite fleet-validity predicate** (backends-and-dispatch.md "The composite fleet-validity rule", one sentence, both tiers): a configuration is fleet-valid iff **kv = postgres AND (large = pg-lo on the same pg instance as the kv engine OR large = local on declared shared media OR large = none with the re-routing posture carrying pool large content)** — plus the explicit `fleet: true` declaration. `fleet: true` is a **constructor error** for every non-fleet-valid configuration (ADR-012 §3): any kv engine other than postgres, `mem` anywhere, `local` without the shared-media declaration, `pg-lo` on a different pg instance than the kv engine. The predicate is enforced where the enforceable seam is — the constructor sees only its own node; cross-node truth (is the declared shared media actually shared? is the undeclared instance sharing our pool?) is the deployment's verified invariant (ADR-008 §3's seam; ADR-012 §3's misconfiguration reading — the detection symptom documented, not constructor-provable). - **The fleet constructor parameters** (ADR-008 §2: "fleet constructor parameters, not API"): - **The pin TTL** — default 60 s (`DEFAULT_PIN_TTL_SECS`, already a postgres backend field awaiting exactly this wiring — the wave-4 note), constructor-tunable. The store owns the TTL and the TTL/3 renewal cadence; the engine's `pin_renew` successor-time body reads the TTL it was constructed with (the wave-4 recorded design point: "constructor-tunable when wave 6's fleet constructor lands"). - **The large-tier declaration** for `large = local` under fleet — the operator's explicit shared-media assertion (ADR-008 §3's enforceable-seam bullet: a fleet-mode constructor requires an explicit large-tier declaration — `local` with the assertion, routed (kv-only), or `pg-lo`). **Named design point — the declaration's type shape**: how the assertion rides the constructor signature (a dedicated declaration type the caller must name — e.g. a fleet-opts shape carrying the shared-media assertion — versus a bare flag) — decide consistent with ADR-008 §3's "explicit declaration" wording (a named type the caller cannot construct accidentally is the reading the ADR's enforceable-seam posture supports) and record it. - **kv-only re-routing posture**: `kv_only_postgres` under `fleet: true` is valid (large = none; the re-routing posture carries pool large content via the ops surface — wave 7; the client-node shape is this constructor plus that composition, ADR-008 §3). The over-threshold put-time rejection (ADR-012 §6.2, already landed) is unchanged under fleet. - **The pg-lo same-instance clause** (ADR-012 §4 — the checkable clause that makes the joint entry+pin tx expressible): under `fleet: true`, `dual_tier_postgres_pglo`'s two DSN+opts pairs must resolve to the **same pg instance**. Cross-instance is valid only as `fleet: false`. **Named design point — the same-instance probe**: textual DSN comparison is insufficient (aliases, IP vs hostname); decide the server-side check (the instance's `system_identifier` via `pg_control_system()` — PG14+ — compared across one connection per engine, is the natural shape; the harness server's PG 16.15 carries it) and record it. A mismatch is the constructor error. - **The store's fleet state** — what the Store carries once declared: the fleet flag (the put/sweep paths branch on it — never on re-deriving from the engine set), the pin TTL, and the **store-instance id** (`owner` — ADR-011's vocabulary; the pin row's identity half). **Named design point — the owner id's minting**: the instance id's generation (random bytes at construction is the natural shape — unique per instance, stable for the instance's life, carried as the `owner` bytes of every `PinRow` the store mints) and its width/encoding; record it. The id is crate-internal (never public API — ADR-008: fleet parameters, not API). - **The one-window-host rule under fleet** — verify the landed posture composes: every fleet-valid configuration has kv = postgres (SQL-backed), so the durable window hosts on the kv engine and the pg-lo window clauses stay dormant (the landed consolidation shape already carries no `gc_window` in the pg-lo schema). The predicate's enforcement must not disturb the form branch (it keys off the engine representation, never a flag). - **Constructor docs updated** — the "implicitly `fleet: false`" / "wave 6 slots in without reshaping" recordings in the postgres constructors' docs (and the store.rs module doc's fleet-declaration paragraph) updated to the landed state. - **Constructor unit tests** (env-driven, skipping cleanly server-less): every fleet-valid configuration constructs (pg-lo same-instance, local + shared-media declaration, kv-only re-routing) and introspects its fleet state (flag, TTL, owner id); every non-fleet-valid configuration errors (`mem` anywhere, sqlite, `local` without the declaration, pg-lo cross-instance — two distinct schemas on the harness server are the same instance, so the cross-instance negative needs two DSNs that resolve to different instances; if the dev environment has only one, the negative is exercised by pointing one DSN at a non-existent instance and asserting the probe errors closed — a probe failure is a constructor error, never a silent pass); `fleet: false` postures unchanged (the existing constructor tests stay green). **Tests need a live server** — the alkstore harness convention: env-driven (`ALKBLOBS_PG_*`), skip cleanly server-less, acceptance requires green against the harness server (`pglo-poc`, :15432, db `blobs`, `postgres`/`poc` — verified live 2026-10-12). ## Acceptance Criteria - [ ] The fleet declaration slots into the fleet-capable constructors without reshaping them (the recorded non-event lands as recorded); `fleet: false` postures byte-unchanged in behavior - [ ] The composite fleet-validity predicate enforced at the constructor: every fleet-valid configuration constructs; every non-fleet-valid configuration is a constructor error (unit- tested per clause: kv≠postgres, mem anywhere, local without the shared-media declaration, pg-lo cross-instance) - [ ] The pg-lo same-instance probe decided and recorded; a mismatch or a failed probe is a constructor error (never a silent pass) - [ ] The pin TTL is a fleet constructor parameter (default 60 s) wired to the engine's renewal body; the shared-media declaration's type shape decided and recorded - [ ] The store carries its fleet state (flag, TTL, owner id); the owner id's minting decided and recorded (crate-internal) - [ ] The one-window-host posture verified intact under fleet-valid configurations; the form branch still keys off the engine representation - [ ] Constructor docs updated to the landed state (the wave-6 forward references resolved) - [ ] `cargo test` (default) green; `cargo test --features postgres` green server-less (skipping) and against the harness server at acceptance; `cargo clippy --all-targets -- -D warnings` and `cargo fmt --check` green (default + `--features postgres`); `cargo doc --no-deps` clean ## References - src/store.rs (the constructors and their recorded non-fleet postures; the module doc's fleet-declaration paragraph) - docs/architecture/backends-and-dispatch.md ("The composite fleet-validity rule" — the one-sentence predicate) - docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §3 (the declaration, never inferred; the constructor-error set), §4 (the GC-state host; the pg-lo same-instance clause; the pin-first/publish-second ordering this task's declaration admits) - docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md §2 (the TTL, fleet constructor parameters), §3 (the enforceable seam; the explicit large-tier declarations) - docs/architecture/decisions/011-vocabulary-tiers-engines-and-fleet-state.md §4 (the constructor table) - src/postgres.rs (`DEFAULT_PIN_TTL_SECS` — the wave-4 note awaiting this wiring) - tasks/store-postgres-construction.md, tasks/store-pg-lo-construction.md (the recorded slotting-in postures this task lands) ## Notes Landed 2026-10-12. Design decisions (each recorded in-code as a named design point; all keyed off the landed ADR text): - **The declaration slots in as `_fleet` twin constructors, without reshaping (`kv_only_postgres_fleet`, `dual_tier_postgres_local_fleet`, `dual_tier_postgres_pglo_fleet`).** Every pre-existing constructor's signature and behavior is byte-unchanged and stays implicitly `fleet: false` (the ADR-005 in-process protocol verbatim) — the recorded non-event landed as recorded; no fleet parameter rides the non-fleet signatures. The store carries `fleet: Option` — `Some` exactly under the declaration, the flag the put/sweep paths branch on (never re-derived from the engine set). - **The declaration's type shape (named design point):** the pin TTL rides as a `Duration` parameter (mirroring `window_delay`'s shape, shipped default the re-exported `DEFAULT_PIN_TTL`, 60 s), and the shared-media assertion is a **sealed dedicated type** — `FleetSharedMedia` with a private seal field; the caller cannot construct it accidentally and must name `FleetSharedMedia::asserted()` at the call site (the reading ADR-008 §3's "explicit declaration" wording supports). No bare flag anywhere. - **The composite fleet-validity predicate** is one function (`fleet_validity_error` over engine-representation-derived shape descriptors `FleetKvShape`/`FleetLargeShape`), one sentence, both tiers, run inside every fleet constructor keyed off the engine representation like every other dispatch in this store. **Enforcement map (recorded):** the structural clauses (kv = postgres, mem never, sqlite never, `local` needs the declaration) are enforced by the constructor set's shape itself — no `_fleet` constructor is named for a mem/sqlite kv engine (the recorded "not fleet-anything" postures carry no fleet parameter) — with the predicate's rejection arms unit-tested per clause at the predicate level (the same error a would-be construction carries); the pg-lo shape's runtime-checkable clause probes at its constructor. - **The same-instance probe (named design point):** the instance's `system_identifier` via `pg_control_system()` (PG14+) read across one pooled connection per engine (`PostgresBackend::system_identifier` / `PgLoBackend::system_identifier`) and compared — server-side instance identity, immune to DSN aliases (textual DSN comparison rejected as specified). **A mismatch or any probe failure is a constructor error (errors closed, never a silent pass).** The probe is instance-level, not database-level: verified positively with two distinct *databases* on one instance (one `system_identifier` — the data directory's). - **The owner id's minting (named design point):** 32 raw bytes, a SHA-256 fold over process id + wall-clock nanos + a process-global instance counter + an ASLR anchor; minted once at construction, stable for the instance's life; uniqueness is the contract (the counter separates instances in one process; time+pid+ASLR separate processes), not secrecy; crate-internal, never public API. Carried as the `owner` bytes of every `PinRow` the store will mint. - **The pin TTL's wiring:** `PostgresBackend::new_with_pin_ttl` (the fleet constructors' instrument; `new` keeps the shipped default) — proven against the live server: a backend opened through the constructor renews a live pin row to `now + pin_ttl` (the constructor-carried value, not the default). `Duration::ZERO` is a constructor error at entry, before any I/O (the TTL/3 cadence degenerates at zero). - **The one-window-host posture verified intact:** every fleet-valid configuration has kv = postgres, and the fleet constructors' tests assert the kv host's both-tables GC schema and the pg-lo schema's dormancy (no `gc_window`, no `gc_pins`) — the form branch untouched (keys off the engine representation, never a flag); a behavioral test additionally proves the declaration turns nothing else on (a fleet store's put/sweep run exactly the non-fleet machinery until the put/sweep driver tasks land). - **Fleet constructor parameters, not API (ADR-008 §3):** `FleetState`, `fleet_validity_error`, the shape descriptors, and `mint_owner_id` are crate-internal; the public surface adds only the three constructors, `FleetSharedMedia`, and `DEFAULT_PIN_TTL` (feature `postgres`). - **Docs updated to the landed state:** the store.rs module doc's fleet-declaration paragraph, the three postgres constructors' "Non-fleet (ADR-012 §3)" recordings, the `#![allow(dead_code)]` scope note, the postgres.rs pin-TTL design points (`new_with_pin_ttl` landed), the gc.rs fleet-family note, and the pg-lo probe note. The remaining wave-6 forward references (joint-tx put driver, fleet sweep, joint contribution) are the later tasks', accurately scoped. - **Doc hygiene:** `cargo doc --no-deps` zero warnings in the default build (the PGLO-1 class avoided: the module doc de-links the feature-gated/private fleet items rather than widening gates; the pre-existing gated-build doc-link warnings were counted before and after — identical, not this change's). ## Summary The fleet declaration landed: three `_fleet` constructors (`kv_only_postgres_fleet`, `dual_tier_postgres_local_fleet`, `dual_tier_postgres_pglo_fleet`) carry the explicit `fleet: true` declaration with the composite fleet-validity predicate enforced at the constructor (kv = postgres AND large = pg-lo same-instance / local on the sealed shared-media declaration / none-the-re-routing posture) and the fleet parameters (pin TTL, default 60 s, wired through `new_with_pin_ttl` to the engine's renewal body; `FleetSharedMedia` sealed assertion; the probe = `pg_control_system().system_identifier` compared across one connection per engine, mismatch or failed probe a constructor error). The store carries its fleet state (`FleetState`: flag, TTL, the 32-byte minted owner id) — `fleet: false` postures byte-unchanged (all existing suites green untouched). Per-clause tests: every fleet-valid shape constructs and introspects against the live harness server (including the two-databases-one-instance probe shape and the kv-host window/dormancy assertions); mem, sqlite, and local- without-declaration reject per the predicate's tested arms; a unresolvable-instance DSN errors closed; a zero TTL rejects at entry. Verified: `cargo test` (default) green; `--features postgres` and `--features "postgres,pg-lo"` green server-less (skipping cleanly) and against the harness server (pglo-poc, :15432, PG 16.15 — verified live 2026-10-12); `--all-features` green; clippy `-D warnings` green (all four feature combinations); `cargo fmt --check` green; `cargo doc --no-deps` clean. Wave 6's remaining tasks (`store-fleet-put`, `store-fleet-sweep`, `engine-pg-lo-joint`, `suite-column-fleet`) consume this task's declaration and state.