Files
alkblobs/tasks/store-fleet-put.md
T
glm-5.3-flash 009de420e1 docs(tasks): decompose wave 6 — the fleet GC mechanism, the architecture's most intricate state machine under concurrency
- store-fleet-construction: the fleet: true declaration slotting into
  the fleet-capable constructors (the recorded non-event), the
  composite fleet-validity predicate enforced at the constructor
  (kv=postgres AND pg-lo-same-instance OR local-on-declared-shared-
  media OR kv-only re-routing), the TTL/owner-id fleet state, the
  same-instance probe design point
- engine-pg-lo-joint: the pg-lo joint contribution — staged-put
  mechanics (512 KiB knee, CAS, transactional LO creation) into the
  store-held PgJointTx, the wave-5 deferred API-shape design point
- store-fleet-put: the joint entry+pin tx driver (amendment A1's
  drop discipline lands here — its recorded owner), the pin guard's
  TTL/3 renewal form, the dedup upsert-renewal, pin-first/
  publish-second for large=local, the consolidation one-tx put
- store-fleet-sweep: the SQL sweep lease (ADR-013 §2 semantics),
  SQL-level delete arbitration on the direct + window-execution
  paths, the expired-pin reaping clause (the seam as the named home
  for fleet-clause growth), the fleet liveness registration verb,
  the two-domain arbitration composition
- suite-column-fleet: the fleet column — two-instance factories over
  one schema, the exact-count fleet sweep rows (the wave's gate),
  lease contention, cross-instance arbitration, TTL/renewal rows,
  the fleet-validity predicate rows
- review-wave-6: the fleet gate per the plan, plus a standing
  code-smell/hygiene block — cargo doc --no-deps asserted clean
  (the twice-bitten PGLO-1 rustdoc private-link class), the
  allow(dead_code) scope notes audited against their remainder,
  stale wave-6 forward references, and task-Summary-vs-diff
  correctness

Harness server cited in every server-touching task: dockerized
pglo-poc (postgres:16-alpine) on :15432, db blobs, postgres/poc
(verified live 2026-10-12); env-driven ALKBLOBS_PG_* settings, clean
server-less skips, acceptance requires green against the server.

Dependency graph validated: two parallel roots (construction, pg-lo
joint), put merging them, sweep parallel to put, the fleet column
merging, the review gate last; no cycles.
2026-10-12 14:22:55 +00:00

9.2 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
store-fleet-put the fleet put path — the joint entry+pin tx driver and the pin guard's fleet form pending
store-fleet-construction
engine-pg-lo-joint
broad high phase implementation
wave-6
store
gc
fleet
put

Description

Route the put paths through the joint entry+pin transaction under fleet: true (ADR-008 §2; ADR-010 §2; ADR-012 §3/§4) — the store core holds the tx from begin_joint_tx to pin_commit, engines contribute mechanics, and publish + protection land in one step — plus the pin guard's fleet form: the TTL/3 renewal duty on the guard. The non-fleet put paths are byte-unchanged (the ADR-005 in-process protocol verbatim; every wave-2/3/4/5 put test stays green).

  • The joint-tx driver (the store core, src/store.rs): under fleet mode, a put whose entry lands on the kv engine (postgres) runs begin_joint_tx → joint_put (the engine's CAS row write inside the held tx) → pin_commit(tx, [PinRow { key, owner, expiry }]) — the pin row carries the store-instance id (store-fleet-construction's owner id) and expiry = now + TTL (the store resolves the expiry; ADR-012 §2's rename — the TTL lives with the store's renewal schedule). The public put signature is unchanged; the routing branches on the fleet flag, never on re-deriving from the engine set.
  • Amendment A1 — the joint-tx drop discipline (the wave-4 gate's owner lands here): the driver owes tx termination on every path from begin_joint_tx onward — the natural ? propagation between the driver's steps must never return a mid-flight PgJointTx to the pool (deadpool's Fast recycle never resets transaction state — PG-2's hazard). Named design point — the termination design: catch-propagate-terminate (every error path between begin and commit terminates the tx before propagating) per A1's recorded options — an explicit abort verb would need a new ADR (the seam shape is pinned; pin_commit's terminal-consume reading stays). Record the design; the zero-residue atomicity is already the engine clause's contract (wave 4) — the driver's duty is never abandoning the tx mid-flight.
  • The pin guard's fleet form (ADR-008 §2: "the pin guard renews its row every TTL/3"): the Pin guard returned by a fleet put carries the renewal duty — while the guard lives, its pin row's expiry moves forward every TTL/3 (via the engine's pin_renew(key, owner) — the never-resurrect semantics: an expired row is never revived; the guard's renewal failing after expiry is the delete-then-recover backstop's territory, ADR-008's expiry semantics verbatim). Named design points — the renewal lifecycle: the duty's mechanism (a per-guard tokio task on a TTL/3 interval vs a shared renewal sweep keyed off the guard registry — decide, record), the abort-on-drop discipline (a dropped/converted/batch-contributed guard stops its renewal — no leaked tasks, no renewal past the guard's life), and the failure posture (a failed renewal is logged-and-continued or silent — the row's expiry is the protection, a missed renewal degrades to the expiry semantics, never an error on the put path). The guard's in-process refcount machinery continues to function (instance-local bookkeeping — the batch's one-step release, the ordered-step conversion); the row is the cross-instance protection. Batch puts (put_in_batch): each member's joint tx commits its row; the batch's one-step release ends the members' renewals (the rows expire and the sweeper's maintenance step reaps them — store-fleet-sweep).
  • The dedup re-put under fleet: CAS dedup means no new entry — the joint tx commits the pin row alone (an empty joint_put contribution is the engine's recorded CAS form) and the row upsert-renews (key, owner) (the wave-4 recorded shape). A different instance's re-put is a different pin row — protection composes by row (ADR-010 §2's refcount-in-rows reading).
  • large = local on declared shared media — pin-first, publish-second (ADR-012 §4): the joint tx is unachievable across media, so the ordering is pinned: the pin row commits on the kv engine (a joint tx carrying only the pin row — begin_joint_tx → pin_commit without joint_put) before the stage file's commit-rename publishes the entry. The invariant survives (an entry becomes visible only after its pin row is durable — sweep arbitration can never observe a visible-unpinned entry); the crash window moves to the harmless side (an orphan pin row, reaped by the expiry machinery — no new recovery mechanism). The reverse ordering is rejected (ADR-012 §4) — do not implement it.
  • The pg-lo consolidation put (kv = postgres + large = pg-lo, same instance): the large entry's content reaches the store-held tx through the pg-lo engine's joint contribution (engine-pg-lo-joint) — LO writes + companion-row insert inside the tx, the pin-row insert + commit via pin_commit. One tx over the shared instance; the dispatch threshold routes to the joint form exactly as the non-fleet path routes to the staged form.
  • Unit tests (env-driven, skipping cleanly server-less; the harness server pglo-poc, :15432, db blobs, postgres/poc — verified live 2026-10-12): the kv joint put publishes entry + pin row atomically (an independent connection sees both or neither); the forced-failure zero-residue form (A1's discipline exercised — a mid-driver failure leaves no dirty pooled session); the guard's renewal moves the row's expiry (a short test TTL; the renewal cadence observed); the never-resurrect form (an expired row is not renewed back to life); the batch form (members' rows commit; batch release ends renewals); the dedup re-put's upsert-renewal; the local-shared-media pin-first ordering (the pin row is durable before the committed file exists); the pg-lo consolidation round-trip through the public put (both tiers, one tx — the byte-exact large-entry form); the non-fleet paths unchanged (the existing suites green).

Acceptance Criteria

  • Under fleet: true, kv-tier puts route through the joint tx (entry + pin row in one step; an independent connection never observes one without the other); under fleet: false the put paths are byte-unchanged (all existing suites green)
  • Amendment A1 landed: the driver terminates the tx on every path from begin_joint_tx onward (the termination design recorded; a forced mid-driver failure leaves zero residue and returns no dirty session to the pool)
  • The pin guard's fleet form: renewal every TTL/3 while the guard lives; drop/conversion/batch-contribution stops the renewal with no leaked tasks; a failed renewal never resurrects an expired row (the lifecycle design points decided and recorded)
  • The dedup re-put commits the pin row alone (CAS; upsert- renewal); a different instance's re-put composes protection by row
  • large = local fleet puts: pin-row-first, publish-second (contract-tested — the pin row is durable before the committed file exists; the orphan-pin crash window is the expiry machinery's)
  • The pg-lo consolidation put round-trips through the public put (one tx over the shared instance; byte-exact large-entry form)
  • cargo test (default) green; cargo test --features postgres and --features "postgres,pg-lo" green server-less (skipping) and against the harness server at acceptance; cargo clippy --all-targets -- -D warnings and cargo fmt --check green (default + the postgres/pg-lo variants); cargo doc --no-deps clean

References

  • src/store.rs (the put seam's two internal paths; the fleet declaration's flag from store-fleet-construction)
  • src/gc.rs (EngineFleetState — the clauses the driver calls; PinRow; the ownership rule)
  • src/postgres.rs (PgJointTx — PG-2's hazard doc; the wave-4 joint-clause bodies)
  • src/pg_lo.rs (the joint contribution from engine-pg-lo-joint)
  • docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md §2 (pins are rows; the TTL/3 renewal; the expiry semantics)
  • docs/architecture/decisions/010-backend-io-seams-and-fleet-state-home.md §2 (the store holds the tx; the engine contributes mechanics), §4 (the guard-drops-at-response-time reading — the ops edition; the public-API guard lives as long as the caller holds it)
  • docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §3 (activation), §4 (the host; pin-first/publish-second for large=local; the one-tx consolidation)
  • docs/architecture/decisions/013-family-composition-reactive-boundary-and-feature-graph.md §1 (the renewal worker's cadence is embedder composition above the facade — the guard's own TTL/3 duty is the in-crate half)
  • tasks/review-wave-4.md (amendment A1 — this task is its owner)
  • tasks/store-fleet-construction.md, tasks/engine-pg-lo-joint.md (the declaration and the contribution this drives)

Notes

To be filled by implementation agent

Summary

To be filled on completion