Row-first gate: consumer-inventory.md gains an engine-tier section — the mem-engine need recorded operator-authority, dated 2026-10-10 (wasm32 sandboxing across the alk protocol family + downstream ffi/napi/python-adapter economics; rusqlite/tokio-postgres structurally out on wasm, so mem is the only triad member the sandbox can carry).
ADR-024 (decisions/024-mem-engine.md) pins the decision set: (1) separate `alkstore-mem` crate — discharges and amends ADR-001 §4 (superseded in part: full contract-v1 engine, not an "implementation convenience"; annotation on ADR-001 §4 + Status, class-1 window still open); (2) honest-ephemeral posture — no durability, single-process, ephemeral by design, never fleet-valid (ADR-010 §3's shared-pool predicate fails structurally), riding ADR-016's carriers unchanged (identity + docs + matrix); (3) full contract v1 tier with the asymmetry classification — `PayloadTooLarge` never produced (SQLite arm), no reconnection concept (reconnect-wake/watcher rows absent from mem's per-engine column), receiver close at engine drop, wake coalescing N/A; (4) `MemStore::new()` engine-native constructor — the one documented exception to the open-prose, core-contract.md Store concept amended; shared-instance (two opens → one engine) rejected with the ADR-016 §4-style re-entry gate (consumer-inventory row), register stays closed; (5) wasm32 — compile-clean for wasm32-unknown-unknown plus the suite's mem column green on host under a current-thread runtime flavor are wave-6 acceptance items; on-target suite execution scoped out with a named collapse condition (wasm-bindgen-test adapter crate) — a scope decision, not a pending-client hedge; (6) mem is not a core dev-dependency — core's doc examples stay mock-based, ADR-001 §4's doctest posture declines.
engine-mem.md (draft): the in-process mapping — guarded per-mechanism state (no pool, no schema bootstrap, no forwarder, no spawn_blocking seam), the tx overlay (staged *_tx effects merged atomically at commit; read-your-own-writes easy, drop-=-rollback trivial; wake-at-commit structural — the seam pg needed pg-fix-tx-wake for, mem pins from birth via the existing tx-commit-atomicity rows), ADR-012 §2 third owner of the curve/opts/@every arithmetic (three-way equivalence, ADR-022's StoreFactory reused verbatim — born pinned).
deployment.md: host-semantics row (single-process, ephemeral, never fleet-valid, wasm32-clean), mem connection-budget subsection (none — nothing to budget), durability-knobs row (the honest row is the absence), toolchain row (wasm32 subset + current-thread-clean, acceptance-cited). README/overview: engine-mem.md row, ADR-024 row, family table entry (alkstore-mem, no driver deps), current-state updated to the implementation phase with engine specs' stable statuses reflected.
implementation.md: wave table gains wave 6 (mem engine, depends waves 1 + 5) and renumbers release readiness to wave 7 (fuzzing decision — the one remaining decided-at-implementation deferral — rides wave 7); wave-6 section records the born-pinned posture, acceptance items, the one suite-harness pre-task (past_stamp_sleep blocking sleep → async sleep, review 003's properties.rs:1683 note), and the window riders (review 003 Finding 1: the pg transient-fault seam, MEDIUM, rides wave 6; Findings 2–3 follow their park into wave 7's pre-release); wave-6 review gate defined; Decided points updated (mem discharged, fuzzing renumbered); stale wave-6 references swept across review docs and the landed tasks' notes (release-readiness items renumbered or annotated).
Docs-only change; verified by cross-reference audit (all ADR/OQ/anchor references resolve, residual wave-6 mentions are correct under the new numbering or carry dated annotations).
- forwarder.rs's ListenerConnection doc corrected: NoTls is hardwired on
every connection path (pooled, listener, reconnect) — the pooled path
never rode the consumer's Config sslmode (a sslmode=require DSN fails
at connect); grep-audited no other in-crate doc repeats the claim
- PgOpts doc carries the corrected one-line TLS pointer (engine-crate-
docs posture, ADR-016 §2)
- deployment.md: new 'TLS posture (v1)' subsection (NoTls everywhere,
sslmode=require DSN fails at connect, topology-level confidentiality
is the v1 substitute, TLS a post-v1 deployment concern) and a new
'Consumer-obligation notes on engine options' section carrying the
QueueOpts trusted-as-given note with code-verified per-field symptoms
(max_attempts <= 0: never claimed, dead-lettered at the next claim
call's pre-claim sweep; negative visibility: instantly-reclaimable
claims; negative retention: every dead row at the next sweep_expired)
plus the PgOpts::max_size 0-guard counter-case; frontmatter advanced
- alkstore/src/opts.rs: QueueOpts struct doc mirrors the
consumer-obligation note (ADR-023 §2 scoping: the domain table covers
trait-surface arguments, not consumer-constructed constants)
- cross-file doc sweep over the fix batch's touched files (forwarder,
tx, scheduler, store) found no further doc-behavior mismatch
- gates: cargo build / clippy --all-targets -D warnings / fmt --check
all green (doc-only, no test touched)
Operator review of ADR-012's fork design re-litigated §1's crate
identity. alkstore-substrate misdescribed what the code is (unpublished,
path-dep-only, one consumer, SQLite-only — not a family-wide substrate);
the mechanical-diff hope was gone at fork time regardless (port deltas,
renames, re-derived half); and the alksocks F-1 lesson applies — a
vendored region under a second, weaker instruction set is a defect seam.
The fork folds into alkstore-sqlite as a bounded module subtree
(src/substrate/); ADR-012 §3–§6 retained verbatim, §2 retained with its
enforcement re-sited from the crate graph to diff fence + review +
contract-suite equivalence pins. OQ-11 item (1) dissolved.
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.
Quality read of honker-core's watcher/transactional core cross-checked
against the published crates.io artifact: the core itself is clean
(Writer/Readers, polling-watcher failure handling, WatcherDeathGuard
all verified), but published 0.5.0 predates upstream's unreleased fix
train carrying the issue-#133 savepoint hardening (silent job loss in
the dead-letter paths) and five .ok() error swallows — and ADR-010's
queue depth requires engine-owned queue SQL in any posture. Resolution:
fork honker-core at the reference revision, inherit the clean machinery
and test suites, re-derive queue ops on contract v1, rename tables to
__alkstore_*.
- docs/research/quality-read-honker-core.md — full evidence
- docs/architecture/decisions/011-sqlite-substrate-fork.md — decision
- OQ-06 resolved in open-questions.md; ADR-003/005/008, engine-sqlite,
queues, README annotated for consistency
- Convergence section added: the assembled recommendation (shape,
engines, contract starting shape, ownership, scope) in one place
- OQ register given consistent status lines (resolved / open —
<work-type> / open); OQ-ST-03 deduplicated (two duplicate
resolution paragraphs collapsed), OQ-ST-07's stale extraction
residue removed, OQ-ST-08 absorbs POC #2's pg multi-host input
- Front-matter changelog compressed; interface finding promoted to
a real heading (anchors were informal § prose references)
- Driver-conflict section updated to resolved state, corrections
folded; Phase 0 plan renumbered and marked final state
- Scope: no content decisions changed — restructure only
Review pass in this repo: contract suite re-verified (11/11 pass under
--test-threads=1 against the harness server; default parallel runs
interfere across tests via the shared db/channels engine_for_test
harness — each test spawns its own listener on poc:q/s/n and truncates
shared tables, so parallel tests receive each other's notifications and
race truncates). Recorded as a harness caveat in the findings with the
Phase 1 note (per-test namespaces), NOT as a contract failure — every
test passes in isolation. Findings invocation note + artifacts section
updated; phase-0 frontmatter carries the verification qualifier.
OQ-ST-03 closure text already folded by the POC session stands.
Findings: unified surface holds on tokio-postgres with the transactional
property intact (in-tx NOTIFY is commit-atomic; rollback drops all);
LISTEN wake beats poll 5-16x at p50 with 300/300 isolated delivery;
pooled-LISTEN discard (deadpool#360) verified and pinned as our own test;
postgres-notify 0.3.8 evaluated and passed over (lazy reconnect, no
initial-connect script, unquoted identifier LISTENs) in favor of the
~90-line hand-rolled forwarder with test-pinned pitfalls. sqlx PgListener
fallback retired unfired.
Two claims verified independently before folding: (1) deadpool-postgres
discards async notifications — upstream deadpool-rs/deadpool#360 (open,
Oct 2024) confirms the pool's connect task awaits the connection to
completion, dropping what only poll_message exposes; pooled LISTEN is
lost at recycle. The dedicated non-pooled LISTEN connection is now
upstream-verified required, not spec-preferred. (2) postgres-notify
0.3.8 exists as described (MIT, tokio-postgres, auto-reconnect with
backoff+jitter, multi-channel subscribe_notify, connect_script hook)
— admitted as sub-module L's second arm (hand-rolled forwarder vs
turnkey listener substrate), with in-probe verification required:
docs don't explicitly promise subscription restoration across
reconnect; connect_script is the mechanism; single-maintainer posture
recorded. New property test pinned: pooled-LISTEN-discard assertion
(our own evidence for the #360 behavior, flips if upstream fixes).
Probe 5 updated to budget accounting (listener conn outside the pool).
Completes OQ-ST-03: one driver posture (tokio-postgres + deadpool, the
POC #5/#7-validated stack) with three sub-modules — L (LISTEN plumbing:
dedicated connection, multi-channel, payload boundary), T (tx-seam over
the pool: caller-owned tx handle vs closure-scoped, both implemented
and compared — direct OQ-ST-04 input), W (wake-vs-poll parity, LISTEN
reconnect + the replay hole honesty). Property tests are the POC #1
suite's pg twin; seam probe mirrors the POC #1 workload for the
cross-engine relative claim. Gate: commit-atomicity via in-tx NOTIFY
(load-bearing), exactly-once claim, seam costs, LISTEN robustness -
failure names the sqlx PgListener fallback posture. Out of scope:
queue semantics depth (OQ-ST-05), pgboss-rs code adoption, multi-host
stress (OQ-ST-08). Register row added, plan updated (POC #2 running
closes OQ-ST-03).
Findings (poc-sqlite-posture-findings.md, run in a parallel session;
tests re-verified in this session — 4 passing): all three of Arm A's
gate conditions fired in its favor — bridged rusqlite ~2x sqlx
native-async at p50 (B's premise measured false), honker-core's
inherited watcher tighter than a re-derived one (p50 1.40 vs 2.15 ms,
max 29 vs 172 ms, battle-tested failure handling), and the .so runtime
dependency is packaging cost with no compensating advantage.
Transactional property holds identically on both (SQLite's property,
not the posture's). Constraints recorded: honker-core 0.5.0 pins
rusqlite ^0.40.1 (rustc >=1.99); mixed rusqlite+sqlx binaries need a
vendored libsqlite3-sys patch (OQ-ST-02's per-engine-crate split keeps
the engine binary single-driver). Fixed the findings' test-count
discrepancy (4 tests, verified running). Phase-0: OQ-ST-03 SQLite half
resolved (pg half remains), OQ-ST-04/05/06 carry POC input, register
row gains findings link + status, plan step 2 split into done/next,
frontmatter updated, POC crate added to references.
Arm A: honker-core linked on our rusqlite (bridge per REQ-TTY-01, honker's watcher). Arm B: honker extension .so over sqlx-sqlite (natively async call path, own watcher, per-pool-connection extension + bootstrap — stress-testing what the CI proof script doesn't cover: pool wiring, lost connections, full surface). Option 2 (honker-rs-as-substrate) dropped from scope with reasoning: its mutex-pinned sync transaction model is subsumed by both other postures' trade space. Five probes (async seam, watcher, transactional contract, packaging, cross-process interop), a decision gate including a legitimate hybrid verdict, and out-of-scope boundaries (postgres side, full surface, extension-as-consumer-feature regardless of outcome). Phase-0: POC register added, plan/frontmatter updated; AGENTS.md: POC-register convention codified.
Operator-named options, verified against the honker checkout @ f4e53c6:
(1) honker-core on our own rusqlite connection (attach_honker_functions,
the alknet-filesystem POC's usage); (2) honker-rs as the SQLite
substrate (max reuse, least control — own connections, mutex-pinned
transactions, sync-under-async-core); (3) raw SQL over sqlx-sqlite with
the honker loadable extension — CI-proven in the checkout's own ORM
proof suite (scripts/proof/orm/rust: transactional enqueue natively
async, rollback-drops-job asserted), which dissolves most of the async
tension on the SQLite side at the cost of a runtime .so dependency and
watcher ownership moving in-crate. Options 1/3 are compatible with
tokio-postgres on the postgres side under the OQ-ST-02 split. First-POC
candidate named: options-1-vs-3 comparison on the same surface.
The async-facing-trait + sync-bridge posture (blocking impl on dedicated
threads/spawn_blocking feeding tokio channels, documented as a supported
strategy not a workaround) is already family-standard twice over: alktty
REQ-TTY-01 and alkblobs' spawn_blocking-in-engine-impls execution
posture. Recorded verbatim-sourced in OQ-ST-03; reframes the honker-rs
sync→async port as bridge-at-the-trait-seam vs native-async-rewrite and
weakens sqlx's main differentiator on the sqlite side. alktty added to
references.
Supersedes the inventory's single-crate lean (which was inductive from
'feature sets do not diverge'). Reason recorded: the split isolates the
engines' real asymmetry of work — sqlite rides honker's machinery as
the baseline; postgres is the build-heavy side (LISTEN/NOTIFY +
pg-boss-family schema work) — and makes future engines additive rather
than feature-graph edits. The inventory's uniform-feature-family fact
stands, re-read as 'the core contract stays small'; correction noted in
both documents. Phase-0 plan updated (step 2 resolved, step 3 references
the core-crate trait surface).
The inventory graded streams absent because no paused consumer document
names it; the operator correction: type-filtered event watching from
several places (e.g. repo-change subscriptions in a git app at
gitea/gitlab scale) is a basic reactivity requirement — and notify
(fire-and-forget, no replay) cannot serve subscriptions honestly.
The wanters are applications above the paused crates, which is why the
docs don't carry the row.
Inventory: streams row recorded on operator authority (the REQ-2
recording convention from alkblobs requirements.md), confidence system
gains the operator-authority grade; rate-limits becomes the sole
first-cut candidate. phase-0: OQ-ST-01 summary and OQ-ST-04's
contract-candidates updated to match.
consumer-inventory.md: per-feature scope synthesis over the paused
consumers' written artifacts (alkfs phase-0, alkgit architecture,
alkblobs ADRs, alknet-filesystem POC) — dissolves the circular
'deferring to consumers who can't run until we exist' framing.
notify/locks pinned-or-documented (alkfs invalidation + writer coord,
alkblobs fleet sweeper); queues/outbox documented (alkfs sync outbox,
alkblobs embedder-owned cadence); scheduler documented-thin; streams/
rate-limits/result-storage have no named consumer — kept per working
posture with cut flags, to revisit before implementation.
phase-0.md: OQ-ST-01 answered by the inventory; OQ-ST-02 narrowed
(uniform feature family across engines favors single-crate shape);
OQ-ST-07 sharpened (no consumer needs the loadable-extension surface —
cut-only decision); OQ-ST-04 contract-pinning scoped to inventory rows;
plan step 1 marked done; references extended.
AGENTS.md: architecture context gains the inventory with its
add-a-row-before-assuming rule.
- complete the dangling honker prior-art sentence; fold the pg_notify
posture into the interface-finding paragraph instead of the
'restated conclusion' trailing paragraph
- reference checkouts are read freely but not for direct dependency
use; published versions unless vendored/forked (alksocks precedent)
- pin honker @ f4e53c6 (russellromney/honker) and pgboss-rs @ 98f7d9e
by path+revision per AGENTS.md §3
- reflow one hard-broken hyphen in the honker-rs limitations list
Read the four honker.dev guides (queues/streams/pubsub/scheduler) +
packages/honker-rs/src/lib.rs (v0.5.0, 1706 lines):
- honker's Rust binding exposes the exact surface shape alkstore wants
(queue claim/ack/visibility, streams with tx-aware offsets, notify/
listen, leader-elected scheduler, outbox, locks/rate-limits/results)
— the unified-API question shifts from shape-invention to contract-
pinning on that surface (new 'Interface finding' section)
- honker's own processing-guarantees table (per-binding auto-checkpoint
vs manual offset save) is the named seam a single-crate contract
cleans up
- honker-rs is sync-only (std threads, no tokio) — SQLite side is a
port-and-adapt under any posture, folded into driver-conflict
corrections + OQ-ST-03/04/06 refinements
- pgboss-rs LISTEN/NOTIFY absence (verified earlier) now stated as the
substantive fork-or-derive comparison point (OQ-ST-05)