- Remove the wave-2 lint suppressions from substrate/mod.rs; the
six genuinely dead surfaces the removal exposed are cut, not
suppressed, and registered D-32..D-36 in PROVENANCE.md
(arg_opt_i64, ops::now_unix, queue_next_claim_at,
Writer::try_acquire, UpdateWatcher::spawn,
SharedUpdateWatcher::new); test-observation items
(subscriber_count, the poll-interval default re-export) are
honestly #[cfg(test)]-gated
- Contract suite: eight new version-stamped backlog rows
(extent-clamp + boundary totality, duration-refusal,
encode_payload round-trip, PayloadTooLarge-never-produced SQLite
arm, drop=rollback no-ghosts, in-tx read-your-own-writes,
enqueue-opts resolution, receiver close/save arms)
- Fix the exemplar row's real-engine sequencing defect: the held tx
handle across the with_tx leg deadlocked any single-writer factory
(mock-invisible; ADR-007's parking is the pinned behavior)
- SQLite factory: SqliteFactory in the new tests/contract_suite.rs
target; all nine rows green against it; the factory contract
(isolation + idempotent teardown) pinned
- Engine lib docs: the single-host and writer-parking posture
statements surfaced under # Posture
- Gates: build/test/clippy -D warnings/fmt green; coverage 93.6%
lines, misses confined to error arms
Task core-engine-value-constructors (wave-3 pre-work). All four value
types are #[non_exhaustive] (ADR-017 §3), so downstream engine crates
cannot struct-literal-construct them (E0639). Give engines a sanctioned
construction path without weakening the consumer posture: pub
#[doc(hidden)] full-field constructors (Job::from_row, StreamEvent::
from_row, Schedule::new, Wake::new), each doc-commented as engine-
construction-only — not contract surface, not covered by ADR-017's
semver-minor field-addition promise; a field addition changes the
signature and is a lockstep-duty event (ADR-017 §5). Core tests now
construct through the new constructors; no behavior change.
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.