From a37c2887dc0f7d7de8ca2363dd12e6de2f93bfff Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Sun, 11 Oct 2026 00:17:48 +0000 Subject: [PATCH] Dispose the wave-6 class-1-window observations (release-contract-window-close) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pre-release pass's last contract-text dispositions, each dated in-place citing the 2026-10-11 close-out pass (ADR-017 §2's terminal window): - Publish→wake ordering tolerance: documented tolerance (decided with the user) — core-contract.md streams paragraph + delivery-obligations bullet, ADR-015 §4 companion annotation; the wake = offset-order ADR amendment declined (commit-ordered pg visibility; hint-shaped wake posture). - ADR-023 §2: heartbeat(extend) and save_offset(offset) join the boundary/offset row (total — negatives well-defined), with the home rationale annotated; core-contract's domain paragraph mirrors; the backlog numeric-domain row registers the suite-duty follow-up. - ADR-021 §5: EventReceiver::try_recv's closed shape pinned (Err(Closed), mirroring ADR-008 §3); core-contract subscribe arms sentence extended. - get_job prose: core-contract queues section + queues.md's reads sentence now say the uniform id-global / get_job_tx-filtered split. - Mem-arithmetic observation: no-action disposition recorded in the task Notes (byte-level transplants; equivalence suite-pinned three-way). Suite stamps checked — no accumulation required (no cited § text changed meaning). Docs-only; gates green: build, workspace tests, clippy -D warnings, fmt, fuzz replay, rustdoc -D warnings, taskgraph validate (79 tasks). --- docs/architecture/core-contract.md | 103 +++++++++++++---- .../decisions/015-streams-depth.md | 13 +++ .../021-tx-reads-and-value-shape-fixes.md | 14 +++ .../decisions/023-fourth-review-round.md | 24 +++- docs/architecture/queues.md | 12 +- tasks/release-contract-window-close.md | 109 +++++++++++++++++- 6 files changed, 244 insertions(+), 31 deletions(-) diff --git a/docs/architecture/core-contract.md b/docs/architecture/core-contract.md index 8fa3931..9417fbf 100644 --- a/docs/architecture/core-contract.md +++ b/docs/architecture/core-contract.md @@ -1,8 +1,6 @@ --- status: draft -last_updated: "2026-10-10 (ADR-024 — the mem engine joins the family; -the Store concept prose admits the engine-native constructor -exception)" +last_updated: "2026-10-11 (the pre-release class-1 close-out pass — the publish→wake ordering tolerance recorded; ADR-023 §2's `heartbeat(extend)`/`save_offset` classifications; `EventReceiver::try_recv`'s closed shape; `get_job`'s id-global prose)" --- # Core contract @@ -138,9 +136,18 @@ the engine's storage layer): chain); an exclusion mechanism must not silently hand back a lease the caller believes it holds. - **Boundaries/offsets** (`trim_to(horizon)`, enqueue `delay`/ - `run_at`/`expires`) — total: any `i64` is well-defined (a negative - horizon deletes nothing; a negative delay resolves to a ready - time in the past, i.e. ready now). + `run_at`/`expires`, `heartbeat(extend)`, `save_offset(offset)`) — + total: any `i64` is well-defined (a negative horizon deletes + nothing; a negative delay resolves to a ready time in the past, + i.e. ready now; a negative `heartbeat(extend)` — the renewed claim + deadline is `now + extend` — shortens or voids the claim, and the + validity predicate then refuses the ops, never an error; a negative + offset save is stored, reads resume forward, and saves at-or-below + the checkpoint are the monotone no-ops) + *(the two 2026-10-11 classifications annotated in + [ADR-023](decisions/023-fourth-review-round.md) §2 by the + close-out pass; before that date the table covered only the first + three arguments)*. ```text store.notify(channel, payload) handle.notify_tx(channel, payload) @@ -259,12 +266,40 @@ business-tx shape). Depth pinned by publish, informational, **not an ordering field** (offset is the only one); `payload_as` decodes (the error is `Codec`). - **Ordering guarantee row** ([ADR-015](decisions/015-streams-depth.md) - §4, extending [ADR-006](decisions/006-wake-and-delivery-contract.md) - §2's streams row): `read_since`/`subscribe` yield `offset ASC` — - global FIFO per stream; committed-event visibility and - replay-on-attach as already pinned; offsets immutable. The - contract suite pins cross-engine equivalence against this row - (same publish sequence → same offset sequence → same read order). + §4, extending [ADR-006](decisions/006-wake-and-delivery-contract.md) + §2's streams row): `read_since`/`subscribe` yield `offset ASC` — + global FIFO per stream; committed-event visibility and + replay-on-attach as already pinned; offsets immutable. The + contract suite pins cross-engine equivalence against this row + (same publish sequence → same offset sequence → same read order). +- **Wake-fire ordering tolerance** *(documented tolerance, 2026-10-11 + — the pre-release class-1 close-out pass, + [ADR-017](decisions/017-contract-versioning.md) §2; disposes the + wave-6 review gate's recorded observation)*: nothing in the + contract pins wake-fire order to offset order. Offset allocation + precedes insert+wake on a multi-threaded runtime (the mem engine; + its documented current-thread posture never exercises it) and the + offset is sequence-assigned pre-commit with the wake fired + post-commit (the Postgres engine — commit order can invert + sequence order), so two concurrent publishes can complete out of + offset-allocation order. A subscriber's wake-driven drain that + finishes between the two completions can checkpoint past the + later-completing, lower-offset event: **the event stays in the + log** — direct `read_since` always sees it, and a fresh + `subscribe(consumer)` whose saved checkpoint is below it consumes + it normally — but the live subscriber whose cursor passed it is + not re-delivered it by the later wake. This is a documented + consequence of the wake contract's best-effort posture (hints, not + delivery promises); the offset-ASC read guarantee above is + unaffected — reads always run over the committed log in offset + order regardless of wake timing. Consumers requiring per-event + completeness across concurrent same-stream publishers need the + defensive re-read recipe (a lagged checkpoint, or a direct + `read_since` sweep below it). Pinned as a tolerance, not an + enforced guarantee (the heavier wake = offset-order amendment was + weighed and declined with the user: enforcement against commit- + ordered visibility is a redesign, and the wake mechanism's posture + is hint-shaped by construction). - `read_since` / `read_from_consumer(offset)` — cursor-based reads; `get_offset(consumer)` — checkpoint inspection. A read from a trimmed-away offset region (below) resumes at the trim horizon's @@ -304,10 +339,14 @@ business-tx shape). Depth pinned by consumption: attach, read to current tail, resume after restart from the stored offset; explicit `save_offset` on the receiver (shape in [ADR-008](decisions/008-contract-v1-pinning.md) §8). - **Error and close arms pinned** - ([ADR-021](decisions/021-tx-reads-and-value-shape-fixes.md) §5): - `recv()`'s `Err` arm carries `Database` only (payloads cross raw; - `Codec` lives at `payload_as`; `Closed` is the `None` arm); + **Error and close arms pinned** + ([ADR-021](decisions/021-tx-reads-and-value-shape-fixes.md) §5): + `recv()`'s `Err` arm carries `Database` only (payloads cross raw; + `Codec` lives at `payload_as`; `Closed` is the `None` arm); + the poll form's arms pin identically — `try_recv()`: `Ok(None)` = + idle (no event pending right now), `Err(Closed)` = the receiver + closed, `Database` otherwise (the closed shape annotated + 2026-10-11, the close-out pass); close is terminal and its *cause* is the documented engine asymmetry — SQLite's receiver closes on watcher death (POC-pinned), the pg receiver stays open across forwarder reconnects (reconnect @@ -399,9 +438,17 @@ obligations: ([ADR-010](decisions/010-queue-semantics-depth.md) §2). Dead letters: move-to-dead storage, `get_job` sees dead rows (with `last_error`/`died_at`), retention via `dead_letter_retention_s` - (default forever), no redrive API - ([ADR-010](decisions/010-queue-semantics-depth.md) §1–§4). - `QueueOpts` stamp onto the job row at enqueue (§3a) — queues are + (default forever), no redrive API + ([ADR-010](decisions/010-queue-semantics-depth.md) §1–§4). + `get_job(job_id)` on the handle is an **id-global lookup** — the + handle carries the queue, but the lookup keys on the id alone and + resolves rows in any queue (uniform on all engines; annotated + 2026-10-11, the close-out pass — the wave-6 review's recorded + prose ambiguity); the tx-side `get_job_tx(queue, job_id)` takes + the queue name and **is** queue-filtered + ([ADR-019](decisions/019-mechanism-handle-surfaces.md) §1, + [ADR-021](decisions/021-tx-reads-and-value-shape-fixes.md) §1). + `QueueOpts` stamp onto the job row at enqueue (§3a) — queues are names, not config owners. The remaining v1-skeleton ops (`ack_batch` — the batch ack applies the uniform predicate per id, lapsed or non-claimed ids silently not counted; `cancel` — unconditional @@ -522,7 +569,12 @@ row is [ADR-009](decisions/009-scheduler-collapse.md) §4's. This spec inherits them and adds the consumer obligations: - wake idempotence (notify's best-effort, coalescing behavior); -- explicit offset saves (streams); +- explicit offset saves (streams); wake-fire ordering is a + documented tolerance, not a pinned guarantee — wake order need not + match offset order and a wake-driven subscriber can drain past an + event whose publish completed out of offset order (the streams + section's tolerance paragraph, 2026-10-11); recovery rides the + offset-ordered re-read the wake contract already obligates; - visibility-timeout budgeting — heartbeat inside the deadline for long work; the dual-execution window and reclaim-eats-attempt rules are documented consumer obligations @@ -734,9 +786,14 @@ before the engine specs are called `stable`: clamp to empty (`claim_batch(n <= 0)` claims nothing; stream reads with `limit <= 0` read nothing, never the whole queue/stream), so the SQLite `LIMIT -1` dialect artifact is dead on both engines; - durations reject (`try_lock`/`renew` with `ttl <= 0` are opaque - `Err`s on both engines); boundaries are total (a negative - `trim_to` horizon deletes nothing, idempotently). + durations reject (`try_lock`/`renew` with `ttl <= 0` are opaque + `Err`s on both engines); boundaries are total (a negative + `trim_to` horizon deletes nothing, idempotently; the same + totality over non-positive values covers `heartbeat(extend)`'s + relative-deadline argument and `save_offset`'s offset — both + classified 2026-10-11 by the close-out pass, the ADR-023 §2 + annotation; their suite rows are the follow-up that + classification implies). - **`encode_payload` typed failure** ([ADR-023](decisions/023-fourth-review-round.md) §1) — the helper returns `Result, Error::Codec>`; enqueue/publish store and diff --git a/docs/architecture/decisions/015-streams-depth.md b/docs/architecture/decisions/015-streams-depth.md index f1b4da9..68c4c69 100644 --- a/docs/architecture/decisions/015-streams-depth.md +++ b/docs/architecture/decisions/015-streams-depth.md @@ -201,6 +201,19 @@ never compared.)* It is deliberately *not* stronger than both engines can implement by a shared SQL shape (`ORDER BY offset ASC` is already both engines' claim path) and not weaker than the mechanism's purpose (replay demands monotone positions). +*(Annotation, 2026-10-11 — the pre-release class-1 close-out pass +([ADR-017](017-contract-versioning.md) §2), disposing the wave-6 +review gate's recorded ordering observation with the user's +documented-tolerance call: this row pins *read* order — `offset ASC` +over the committed log — and pins nothing about **wake-fire order**; +wake-fire order need not match offset order, and a wake-driven +subscriber's drain can checkpoint past an event whose publish +completed out of offset order (the event stays in the log; a fresh +subscribe whose checkpoint is below it sees it). The tolerance's full +text and the consumer recipe live in +[core-contract.md](../../architecture/core-contract.md)'s streams +section — the delivery-guarantee obligations bullet carries it too. +The heavier wake = offset-order amendment was weighed and declined.)* ### 5. Retention: `trim_to` on the stream handle — a consumer-invoked bounded-growth op diff --git a/docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md b/docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md index a454b3d..113b2a1 100644 --- a/docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md +++ b/docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md @@ -258,6 +258,20 @@ The pinned shape's unpinned arms: absent-consumer = 0 rule, [ADR-019](019-mechanism-handle-surfaces.md) §1, already defines the pre-save state). +- *(Annotation, 2026-10-11 — the pre-release class-1 close-out pass + ([ADR-017](017-contract-versioning.md) §2), disposing the wave-6 + review gate's recorded unpinned shape: **`EventReceiver::try_recv`'s + closed shape is `Err(Closed)`.** §5 pinned only `recv()`'s arms; + the poll form's arms are the same taxonomy applied without the + wait — `Ok(None)` = no event pending right now (idle), `Err(Closed)` + = the receiver closed (terminal — the same causes the `None` arm + documents, engine asymmetry included), and the rest of the `Err` + arm carries `Database` only, exactly like `recv()`. The shape + mirrors `WakeReceiver::try_recv` + ([ADR-008](008-contract-v1-pinning.md) §3, where closed and idle are + distinguishable states by the same construction) and is uniform on + all three engines; core's rustdoc pinned it from landing, and the + mem engine's suite pins it in test.)* ## Consequences diff --git a/docs/architecture/decisions/023-fourth-review-round.md b/docs/architecture/decisions/023-fourth-review-round.md index f13abd4..094472b 100644 --- a/docs/architecture/decisions/023-fourth-review-round.md +++ b/docs/architecture/decisions/023-fourth-review-round.md @@ -117,7 +117,7 @@ classified by argument **kind**, not call site: |---|---|---| | **Extent** ("at most this many") | `claim_batch(n)`, `read_since(limit)`, `read_from_consumer(limit)` | `n <= 0` → **empty value result** (claims nothing / reads nothing), not an error | | **Duration** (seconds of lease/TTL semantics) | `try_lock(ttl)`, `renew(ttl)` | `ttl <= 0` → **`Err`, opaque** (engine detail in the source chain, `Database`) — the substrate's existing guard (`ttl_s <= 0`), now pinned contract-side | -| **Boundary / offset** (`<=` predicates, absolute or relative instants) | `trim_to(horizon)`, enqueue `delay`/`run_at`/`expires` | total — any `i64` is well-defined (negative horizon deletes nothing; negative delay → ready in the past → ready now); no clamping, no rejection | +| **Boundary / offset** (`<=` predicates, absolute or relative instants) | `trim_to(horizon)`, enqueue `delay`/`run_at`/`expires`; `heartbeat(extend)`, `save_offset(offset)` *(annotated 2026-10-11)* | total — any `i64` is well-defined (negative horizon deletes nothing; negative delay → ready in the past → ready now; negative extension → the renewed deadline `now + extend` is in the past, voiding the claim through the validity predicate, never an error; negative offset → stored, reads resume forward); no clamping, no rejection | The rule the table pins: **extents clamp to empty (no-work is a value, the pinned claims vocabulary), durations error, boundaries and @@ -149,6 +149,28 @@ offsets are total.** Each disposition answers to a decided principle: - **Boundaries/offsets.** The remaining numerics are total by accident of their SQL today; the table makes it rule, not accident — an implementer reading the table has nothing to improvise. + *(Annotation, 2026-10-11 — the pre-release class-1 close-out pass + ([ADR-017](017-contract-versioning.md) §2), disposing the wave-6 + review gate's recorded under-classifications. Two arguments join + the boundary/offset row, and deliberately not the duration row: + `heartbeat(extend)`'s seconds-shaped argument is not lease/TTL — + `extend` is the new full deadline in seconds from now, so a + non-positive value is not a handed-back lease the caller believes + it holds (the duration rule's rejection rationale never applies); + it is a relative instant like `delay`, and the three engines' + uniform arithmetic (`saturating_add` / plain SQL integer add — + code of record, mem `queue.rs`, substrate `queue_ops.rs`, pg + `queue.rs`) is total over non-positive values: a negative extension + shortens the deadline, a past one is voided by the uniform + validity predicate on the *next* op, and the heartbeat itself + reports the successful renewal (`true`) exactly when the row was + processing and unexpired at call time. And `save_offset`'s offset + is literally an offset: a negative is stored as the checkpoint, + reads resume forward past it, and saves at-or-below the stored + checkpoint are the [ADR-019](019-mechanism-handle-surfaces.md) §6 + monotone no-ops — rejections were never the behavior, so pinning + the duration row's shape here would have contradicted all three + engines.)* This is a **core-contract amendment** (doc text on `claim_batch`, both `read` forms, `try_lock`/`renew`, and a shared domain-rule diff --git a/docs/architecture/queues.md b/docs/architecture/queues.md index 2f018cc..021efd6 100644 --- a/docs/architecture/queues.md +++ b/docs/architecture/queues.md @@ -1,6 +1,6 @@ --- status: draft -last_updated: "2026-10-07 (ADR-021 + third-round follow-through: handle-form sweep_expired, ack_batch predicate, opts types)" +last_updated: "2026-10-11 (close-out pass: the reads sentence now says the uniform shapes — get_job id-global on the handle, get_job_tx queue-filtered)" --- # Queues, scheduler, outbox — semantics depth @@ -44,9 +44,13 @@ made under; the ADRs carry the WHY. [ADR-020](decisions/020-enqueue-opt-semantics-and-bridges.md) §1/§2); `ack / retry / fail / heartbeat` on the boxed `JobHandle` a claim returns ([ADR-019](decisions/019-mechanism-handle-surfaces.md)); - reads (`get_job`, and tx-side `get_job_tx` — - [ADR-021](decisions/021-tx-reads-and-value-shape-fixes.md) §1) are - name-taking pure reads, tx-shaped on the handle. + reads are pure reads, in two shapes — `get_job` on the queue handle + is an **id-global lookup** (the handle carries the queue, the + lookup keys on the id alone), the tx-side `get_job_tx` + ([ADR-021](decisions/021-tx-reads-and-value-shape-fixes.md) §1) is + name-taking and **queue-filtered** (2026-10-11 close-out pass — + core-contract's queues section carries the split; the wave-6 + review's recorded prose ambiguity). - **Cut-flag context**: result storage is [ADR-002](decisions/002-feature-scope.md)'s cut-flag row; [ADR-010](decisions/010-queue-semantics-depth.md) §7 reconsidered it diff --git a/tasks/release-contract-window-close.md b/tasks/release-contract-window-close.md index cc8d9d2..2e17aec 100644 --- a/tasks/release-contract-window-close.md +++ b/tasks/release-contract-window-close.md @@ -1,7 +1,7 @@ --- id: release-contract-window-close name: Class-1 window's last dispositions — the wave-6 recorded observations -status: pending +status: completed depends_on: [] scope: moderate risk: medium @@ -92,8 +92,111 @@ accumulation. ## Notes -> To be filled by implementation agent +All five dispositions landed 2026-10-11 as dated in-place annotations +citing this pass (the pre-release class-1 close-out pass, +[ADR-017](../docs/architecture/decisions/017-contract-versioning.md) +§2's terminating window). Docs-only — no code change (item 1's +enforced-guarantee alternative was declined with the user, so no +follow-up code task spawns). + +1. **Publish→wake ordering tolerance — decided with the user, + documented tolerance.** The two candidates were raised with the + user (2026-10-11) and the documented-tolerance posture was chosen + over the ADR amendment (wake order per stream = offset order) — + the amendment is arguably unachievable on Postgres while offsets + are sequence-assigned pre-commit (commit order inverts sequence + order; enforcement needs hole-filling/redesign) and contradicts + the wake mechanism's hint-shaped best-effort posture. Landed: + core-contract.md's streams section carries the tolerance paragraph + (the full text: the mem multithreaded-runtime shape, the pg + sequence/commit shape, the event-stays-in-the-log promise, the + consumer recipe — lagged checkpoints or direct `read_since` sweeps + below them), the delivery-guarantee obligations list carries the + consumer-obligation bullet, and ADR-015 §4 carries the dated + companion annotation (the ordering row pins *read* order only; + wake order unpinned). +2. **`heartbeat(extend)` + `save_offset(offset)` — both join the + ADR-023 §2 boundary/offset row**, annotated in place with the + home rationale: the duration row's rejection rationale never + applies (a non-positive `extend` is a relative instant like + `delay`, not a lease handout — a negative shortens/voids the + claim and the uniform validity predicate governs; the three + engines' arithmetic — `saturating_add`/SQL integer add — is total + over non-positive values, and the heartbeat reports `true` when + the row was processing and unexpired at call time), and + `save_offset`'s offset is literally an offset (negative stored, + reads resume forward, regressions are the ADR-019 §6 monotone + no-ops) — pinning rejection would have contradicted all three + engines. core-contract.md's numeric-domain paragraph mirrors the + extension. The verification-backlog numeric-domain row was + extended to register the suite-duty follow-up those two + classifications imply (their suite rows did not land here — + docs-only task); before release-readiness, the review-wave-8 gate + owns the audit. +3. **`EventReceiver::try_recv`'s closed shape — ADR-021 §5 dated + annotation**: `Err(Closed)` (terminal; the `None` arm's causes), + `Ok(None)` = idle, `Database` otherwise — mirroring + `WakeReceiver::try_recv` (ADR-008 §3). Home is §5 so one + normative section governs every receiver Err/close arm. Verified + uniform by code read (mem `stream.rs`, sqlite `stream.rs`, pg + `stream.rs` all map channel disconnect → `Err(Closed)`); core's + rustdoc carried the shape from landing; the mem suite pins it. +4. **`get_job` prose — core-contract.md's queues section now says + the uniform behavior**: id-global lookup on the handle (rows in + any queue), `get_job_tx(queue, job_id)` queue-filtered. queues.md's + reads sentence — which mischaracterized both as "name-taking pure + reads" — corrected in the same pass. Code read verified the + uniform shapes (mem `queue.rs`/`tx.rs`'s `merged_get_job`; + SQLite substrate `get_job(conn, id)` vs the tx path; pg). ADR-019 + §1's "queue-scoped claim/maintenance ops" phrasing stands — it + names claim/maintenance ops only, and the corrected core-contract + text now disambiguates the neighborhood. +5. **Mem-arithmetic observation — no-action disposition, recorded**: + the mem copies are byte-level transplants of the SQLite + implementations (`resolution.rs`, `scheduler.rs`'s `@every` + parser and `skip_forward`); equivalence is suite-pinned three-way + (`backoff_curve_equivalence`, `enqueue_opts_resolution` green on + all three columns, re-verified this session). ADR-012 §2's + one-owner rule is satisfied exactly as written (mem owns its + modules; the suite is the honesty instrument) — no code or doc + change warranted; the record here is the disposition. + +**Suite stamps checked** (the task's accumulation duty): no existing +row's cited § text changed meaning, so no stamp accumulates. The four +rows citing ADR-023 §2 (`extent_clamp_semantics`, +`duration_refusal_on_non_positive_ttl`, the enqueue-opts resolution +row, the backoff row) test classifications the amendments left +meaning-identical — rows were *added* to the §2 table and annotated, +existing cells' semantics untouched; the receiver-arms row citing +ADR-021 §5 tests `recv()`/`save_offset`/close arms the annotation +left verbatim. The two new classified behaviors' suite rows are the +registered follow-up (Notes 2). ## Summary -> To be filled on completion \ No newline at end of file +`release-contract-window-close` completed 2026-10-11: all five +wave-6 recorded observations disposed as contract/ADR text with +dated annotations before ADR-017 §2's class-1 window terminates at +first release. Item 1 decided with the user — documented tolerance +for the publish→wake ordering observation, landed in core-contract.md +(streams tolerance paragraph + delivery-guarantee obligations bullet) +with the ADR-015 §4 companion annotation; the wake = offset-order ADR +amendment was presented and declined (unachievable against commit- +ordered pg visibility without redesign; contradictorily sharpen a +hint-shaped mechanism). Items 2–3: ADR-023 §2's boundary/offset row +gained `heartbeat(extend)` and `save_offset(offset)` (total — +negatives well-defined, with the homes' rationale annotated, the +core-contract domain paragraph mirrored, and the backlog numeric- +domain row registering the suite-duty follow-up); ADR-021 §5 gained +the `EventReceiver::try_recv` closed-shape annotation (`Err(Closed)`, +mirroring ADR-008 §3). Item 4: core-contract.md's `get_job` prose now +says the uniform id-global/`get_job_tx`-filtered split (queues.md's +mischaracterizing reads sentence corrected alongside). Item 5: the +mem-arithmetic observation's no-action disposition recorded above. +Suite-stamp accumulation checked — none required (no cited § text +changed meaning). Verified docs-only: `cargo build`, workspace tests +green (mem 102+25, SQLite 192+25, pg 125+25+9, core 25 — three-way +equivalence rows green), clippy `--all-targets -D warnings` clean, +`cargo fmt --check` clean, fuzz corpus replay green (6/6), +`RUSTDOCFLAGS="-D warnings" cargo doc --no-deps` zero warnings, +`taskgraph validate` green (79 tasks). \ No newline at end of file