ADR-012: forked-substrate design — contract-blind boundary, fidelity posture, port deltas

Follow-through on OQ-06/ADR-011: pin the fork's structural decisions
(alkstore-substrate as a vendored path-dep crate, contract-blind API
boundary with contract formulas computed engine-side and pinned
equivalent by the contract suite, keep-the-kept-half API fidelity for
cheap cherry-picks, the W-1/W-2/dead-man's-switch/W-4 port deltas
decided per item, bootstrap re-keying off error-string matching, no
rename migration, deliberate upstream tracking).

Consistency sweep across the doc set for the fork: annotate ADR-003/
005/009/010 and core-contract for superseded ownership facts, fix
schedule-storage table naming (ADR-009 §5, queues.md), re-key ADR-010
§6's notifications hygiene to the at-attach cap the fork scope
realizes, add OQ-11 (scaffold-time residue), and complete both ADR
indexes. Independent review: 0 critical, warnings addressed.
This commit is contained in:
glm-5.3-flash committed 2026-10-05 05:00:55 +00:00
1 parent befbe2e714
commit 2949612e2c
18 files changed
+491 -117

No files matched your search

@@ -135,9 +135,12 @@ no-renewal/expire-sweep model is not inherited):
in v1.
- Explicit `fail(err)` = immediate dead-letter (honker parity; it is
the "stop retrying this" operator). `retry` at exhausted budget =
dead-letter. Exhaustion via reclaim = dead-letter (the pre-claim
sweep of already-exhausted reclaimable rows is an engine-side
laziness optimization — SQLite rides honker's; pg re-derives).
dead-letter. Exhaustion via reclaim = dead-letter. *(The pre-claim
sweep of already-exhausted reclaimable rows — a laziness optimization
in both upstream lineages — is engine-side and optional; SQLite rides
the fork's re-derivation
([ADR-011](011-sqlite-substrate-fork.md)), pg re-derives it
([engine-postgres.md](../engine-postgres.md)).)*
### 3a. QueueOpts resolution: stamped at enqueue, per job
@@ -166,9 +169,14 @@ need a defined attachment point, and the contract pins one:
- SQLite realization note: honker's `claim_batch` takes one uniform
`timeout_s` per call, while per-job stamps make deadlines row-local —
bridging that gap (post-claim re-stamp, per-row claiming, or another
shape) is implementation work over honker's function surface and
rides the same OQ-06 assessment as §5's zombie fix. The *contract*
(deadline from the job's stamp) is engine-independent either way.
shape) was implementation work over honker's function surface and
rode the same OQ-06 assessment as §5's zombie fix. *(Resolved
2026-10-05: the fork fired ([ADR-011](011-sqlite-substrate-fork.md));
the claim statement is re-derived with per-row visibility from the
stamps, in owned
contract-blind substrate code ([ADR-012](012-forked-substrate-design.md)
§2).) The *contract* (deadline from the job's stamp) is
engine-independent either way.
### 4. Dead-letter: move, retention = never-expire by default, no redrive API
@@ -209,13 +217,13 @@ maintenance entry point):
property: an expired *processing* row whose worker died is
unreachable by claim (predicate requires future expiry), by
pre-claim dead-lettering (same), and by `sweep_expired` (pending
only) — the zombie hole, a real defect found in the reference read.
This ADR fixes it at the contract level; the Postgres engine
enforces it directly; the SQLite engine's realization over honker's
machinery is implementation work **contingent on OQ-06** (a
complement over honker's function surface, or the fork fires and
the fix lands in owned code — the concrete fork candidate the
quality read should weigh).
only) — the zombie hole, a real defect found in the reference read
(D-6 in the quality read's register). This ADR fixes it at the
contract level; the Postgres engine
enforces it directly; the SQLite engine's realization was
implementation work **contingent on OQ-06** — *(resolved
2026-10-05: the fork fired ([ADR-011](011-sqlite-substrate-fork.md))
and the both-states sweep lands in owned code.)*
- When `dead_letter_retention_s` is set, the same sweep also deletes
dead rows past their retention (the only sweeper dead rows ever
have — nothing runs without a caller).
@@ -246,9 +254,14 @@ maintenance entry point):
**out of the contract** (ADR-008 §8's disposition, resolved here by
disposition): the notifications table is the SQLite wake
mechanism's *transport* detail — consumers interact with wakes, not
rows. Its hygiene is engine-internal (capped at attach, engine-side
maintenance cadence, engine opts) — the fix for honker's unbounded
`_honker_notifications` growth must not become a consumer's chore.
rows. Its hygiene is engine-internal: **an at-attach pruning cap
(engine opts)** — the mechanism the fork scope realizes
([ADR-011](011-sqlite-substrate-fork.md)); no cadence, ambient or
engine-side, contradicts this section's no-ambient-sweeper bullet.
The fix for upstream's unbounded notifications growth must not become
a consumer's chore. *(Annotated 2026-10-05: the earlier "engine-side
maintenance cadence" wording was wrong — nothing in the fork scope
realizes a cadence; the at-attach cap is the pin.)*
### 7. Result storage: cut-flag stands
@@ -277,15 +290,18 @@ consumer-inventory row.
shape and keeps `queue(name)` a name, not a DDL operation — queue
creation is not registry-gated, per
[ADR-009](009-scheduler-collapse.md) §5). Per-queue config storage
is likewise unnecessary (opts stamp onto job rows, §3a).
is likewise stamped per §3a.
- **SQLite**: honker's `_honker_*` table family in the caller's
database file — storage-internal per
[ADR-008](008-contract-v1-pinning.md) §4; no new tables minted by
this ADR (job-stamped opts ride honker's existing columns and the
contract's stated resolution rule, no schema change needed — this
is exactly the seam the quality read (OQ-06) assesses). The
family's exact fate rides that read: a fork re-owns the names,
nothing consumer-visible changes.
[ADR-008](008-contract-v1-pinning.md) §4. *(Annotated
2026-10-05: the expectation that job-stamped opts would ride honker's
existing columns with no schema change was falsified by the quality
read — no stamp columns exist in the upstream schema (D-7). The
family's fate is resolved: the fork ([ADR-011](011-sqlite-substrate-fork.md))
re-owns the whole family as `__alkstore_*`, and the stamp columns +
`claimed_at` are added by the re-derivation on contract v1
([ADR-012](012-forked-substrate-design.md) §5). Nothing
consumer-visible changes.)*
### 9. Error taxonomy: no delta
@@ -322,9 +338,9 @@ delta this track produces.
consumers needing audit trails build them on the tx seam.
- Honker's zombie fix, dead-row `get_job` visibility, and per-job
visibility stamps over the uniform-claim-timeout function surface
require either an over-machinery complement or a fork on the SQLite
side — the fork calculus gains concrete candidates to weigh
(OQ-06).
required either an over-machinery complement or a fork on the SQLite
side — resolved by the fork ([ADR-011](011-sqlite-substrate-fork.md),
designed in [ADR-012](012-forked-substrate-design.md)).
- The backoff curve's 1-hour cap and jitter formula are pinned
constants — a consumer needing a different policy uses
`retry(err, Some(d))` per attempt (correct, but manual).
@@ -348,6 +364,8 @@ delta this track produces.
extends, §5's rule §9 applies, §8's dispositions §6 resolves.
- [ADR-009](009-scheduler-collapse.md) — the collapse machinery §6's
recipe composes with.
- OQ-06 — the SQLite-side fork candidates (§5, §3a realization note).
- OQ-06 — the SQLite-side fork candidates (§5, §3a realization note) —
resolved by the fork ([ADR-011](011-sqlite-substrate-fork.md),
designed in [ADR-012](012-forked-substrate-design.md)).
- [queues.md](../queues.md), [core-contract.md](../core-contract.md),
engine specs — the specs carrying this depth.