Files
alkblobs/tasks/store-fleet-sweep.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

10 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
store-fleet-sweep the fleet GC protocol — SQL sweep lease, SQL-level arbitration, pin reaping, the fleet liveness verb pending
store-fleet-construction
broad high phase implementation
wave-6
store
gc
fleet
sweep

Description

Grow the sweep and the delete paths into their fleet forms under fleet: true (ADR-008 §2; ADR-010 §2; ADR-012 §1/§5/§6.6/§6.7; ADR-013 §2) — the architecture's most intricate state machine extended across instances, its invariants unchanged (a visible pool entry is never deleted while liveness protects it; an in-flight put is never deleted by a sweep started before it committed). The non-fleet forms (inline + durable, single-node) are byte-unchanged.

  • The sweep lease (ADR-013 §2's named exclusive semantics; the shipped provider is the wave-4 advisory-lock clause): under fleet mode the sweep acquires sweep_lock_acquire() on the fleet host before sweeping and holds it for the whole sweep; contention is the GcAbortCause::SweeperLock report abort (Ok(SweepReport), nothing deleted — ADR-012 §1); holdership ends at release, owner death, or session loss (the clause's session-scoped semantics, wave 4). The in-process single-flight flag composes (both held — the instance- local guard stays cheap and uniform). Named design point — the lease's hold across the sweep body: the lease's held checkout must not deadlock the sweep's own engine work (the wave-4 lease holds one pooled connection for its duration; the sweep's other clauses ride further checkouts — verify the pool sizing composes and record the posture).
  • SQL-level delete arbitration (ADR-008 §2): under fleet mode the delete-time decision is the seam's arbitrate(key) — the SELECT … FOR UPDATE finger-lock folding un-expired pin rows + registered liveness tables into one answer — on both the direct delete() path (protected → Error::GcRefuse, the facade owns the refusal) and the durable window's execution-time re-arbitration. Named design point — the two arbitration domains' composition: the in-process GcHome machinery (markers, in-process pins, callbacks, in-process sources) and the SQL arbitrate both run — the in-process domain guards this instance's in-flight state (the marker mechanism closes the local sweep-vs-put race without engine I/O under the lock), the SQL domain is the cross-instance authority; decide the composition order (in-process first — cheap, local; SQL second — fleet-authoritative) and record it. The engine-side pin_check classification stays available to the store core where a pins-only answer suffices (its consumer beyond arbitrate may be wave 7's ops renewal probe — do not force it here).
  • The expired-pin reaping maintenance step (ADR-008 §2's GC-of-GC cleanup: "an expired pin is abandoned … and is reaped by the sweeper's maintenance step"): the fleet sweep gains the maintenance step deleting expired pin rows. Named design point — the clause home: EngineFleetState has no reap clause; the seam is the named home for fleet-clause growth (ADR-010 §2: "If fleet clauses ever grow, they grow here") — add the clause body on the postgres host (e.g. pin_reap(now) → count, one statement, contract-tested per the applicability row) rather than any raw-SQL side-channel (rejected by ADR-010 §2). The step runs under the lease, before or alongside the overdue execution (record the ordering).
  • The fleet liveness registration verb (ADR-012 §6.6): "the same verb with a fleet-shaped argument" — the facade's register_liveness_source gains its fleet form, registering a named table reference in the shared engine (the embedder's own table per ADR-008 §2; the store core reads it, never owns it — the schema-ownership rule). The engine-side registration landed wave 4 (PostgresBackend::register_liveness_source — quoted-identifier boundary, idempotent re-registration, malformed refs error). Named design points — the verb's shape: how the fleet form rides the public verb (a fleet-shaped argument vs a sibling method — decide consistent with §6.6's "same verb" wording and the existing signature's infallibility: the engine-side registration is fallible, so the fleet form's error surface needs deciding), and whether in-process LivenessSource registrations remain legal under fleet mode (ADR-008: in-process callback views are not a fleet liveness form — an instance-local registration's protection is instance-local only; decide allow-and-document vs reject and record it). Deregistration composes (the correction flow, ADR-012 §6.4).
  • The protect callback's fleet posture (ADR-008 §2): single-node- only — under fleet mode the callback remains consultable by this instance's sweeps (its protection is instance-local; the embedder's fleet-wide protection materializes into its liveness table or pin rows before invoking sweep). Record the posture in the verb docs; no new machinery.
  • The fleet sweep body (per sweep, under the lease): the protect consult (instance-local, abort ProtectFailed precedes everything) → the maintenance step (expired-pin reaping) → execute overdue (window_take on the postgres host — the one-window-host rule holds: every fleet-valid configuration's window hosts on the kv engine; each overdue candidate re-arbitrated at execution time via the SQL arbitration, deleted where it lives — the fall-through delete across both tiers) → mark (the pool enumerated; the live set from the in-process sources — the SQL liveness tables are consulted at arbitration time, not enumerated into the mark set) → stage at visible_after = mark_end + window → release the lease. Report counts exact relative to the schedule (the durable form's reading carries: staged-this-sweep vs executed-this-sweep are different sets).
  • The sweep-vs-put race under fleet, closed by the row: a fleet put's pin row commits atomically with its entry (the joint tx, store-fleet-put), so a sweep's window execution can never observe a visible-unpinned entry; a put landing during the window delay has its row committed before its entry is visible and the execution-time SQL arbitration cancels the candidate. Unit-test the race across the delay in its fleet form (the wave-3 durable-form race test's fleet edition).
  • Unit tests (env-driven, skipping cleanly server-less; the harness server pglo-poc, :15432, db blobs, postgres/poc — verified live 2026-10-12): the lease's fleet form (contention between two instances of one store shape → the second aborts SweeperLock with nothing deleted; release/loss reaping); SQL arbitration on the direct-delete path (a pin row from a foreign owner id refuses the delete — the cross-instance protection proof; GcRefuse); the maintenance step reaps exactly the expired set (un-expired rows survive); the fleet liveness verb registers a test-owned embedder table and its rows protect (the schema- ownership rule — the engine never creates the table); the two-instance exact-count sweep shape (instance A pins, instance B sweeps — the pinned entry survives; unpinned twins delete); the race across the delay; the non-fleet forms unchanged (all existing suites green).

Acceptance Criteria

  • Under fleet: true, the sweep acquires the SQL lease (the ADR-013 §2 semantics: atomic test-and-set, one sweeper per pool across instances, contention = SweeperLock report abort with nothing deleted); the in-process flag composes; under fleet: false the sweep forms are byte-unchanged
  • Delete-time arbitration is SQL-level under fleet mode on both the direct path (GcRefuse) and the window execution (execution-time re-arbitration); a foreign owner's un-expired pin row protects (cross-instance proof); the two-domain composition decided and recorded
  • The expired-pin reaping maintenance step landed as a new EngineFleetState clause on the postgres host (the seam is the named home; no raw-SQL side-channel), contract-tested, run under the lease
  • The fleet liveness registration verb landed (the named table reference form; the verb-shape and in-process-source design points decided and recorded; the schema-ownership rule holds)
  • The protect callback's fleet posture recorded (instance-local; materialization is the embedder's fleet-wide duty)
  • The fleet race property unit-tested across the window delay (a put landing during the delay survives via the row + the execution-time SQL re-arbitration)
  • 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 sweep's two forms; arbitrated_delete; the fleet flag from store-fleet-construction)
  • src/gc.rs (GcHome — the in-process domain; EngineFleetState — the clauses; the seam-as-named-home note)
  • src/postgres.rs (the lease, arbitrate, pin_check — the wave-4 clause bodies this drives; the liveness registration)
  • docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md §2 (the fleet mechanism: SQL arbitration, one sweeper per pool, the maintenance step, the protect callback's single-node-only posture)
  • docs/architecture/decisions/013-family-composition-reactive-boundary-and-feature-graph.md §2 (the named exclusive sweep lease — the semantics this implements)
  • docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §1 (abort-as-data), §5 (the one-window-host rule), §6.4 (the full protection set), §6.6 (the fleet liveness verb's API home), §6.7 (the executor is the next sweep)
  • docs/architecture/decisions/010-backend-io-seams-and-fleet-state-home.md §2 (the seam clauses; the raw-SQL rejection)
  • tasks/store-sweep-durable-window.md (the durable form's shape — the single-node structural twin)
  • tasks/store-fleet-put.md (the joint puts whose rows this sweep arbitrates against)

Notes

To be filled by implementation agent

Summary

To be filled on completion