Wave-3 review gate: contract conformance clean; two findings fixed inline — substrate boundary move (open_writer_connection → seam.rs), writer-slot release on with_writer/begin/commit error arms + regression tests (task review-wave-3)

This commit is contained in:
glm-5.3-flash committed 2026-10-08 20:57:10 +00:00
1 parent a82c543b40
commit ecb8211694
8 files changed
+290 -34

No files matched your search

+41
View File
@@ -118,6 +118,47 @@ async fn notify_never_produces_payload_too_large() {
cleanup(&dir);
}
/// Acceptance: an auto-commit op's *error* arm releases the writer
/// slot — the lease-out-both-arms property (ADR-007's seam posture):
/// after a notify whose statement fails at the storage layer, the slot
/// is free again and a subsequent writer op succeeds without parking.
#[tokio::test(flavor = "multi_thread")]
async fn failed_notify_releases_the_writer_slot() {
let dir = temp_dir("err-arm-release");
let path = temp_path("err-arm-release");
let store = open_store(path.to_str().unwrap(), Default::default()).unwrap();
let side = rusqlite::Connection::open(&path).unwrap();
side.execute_batch(
"CREATE TRIGGER block_notify BEFORE INSERT ON __alkstore_notifications
BEGIN SELECT RAISE(ABORT, 'notify insert blocked'); END",
)
.unwrap();
let err = store.notify("orders", json!({"x": 1})).await.unwrap_err();
let source = match &err {
Error::Database(source) => source.to_string(),
other => panic!("the induced failure surfaces as Database, got {other:?}"),
};
assert!(
source.contains("notify insert blocked"),
"the source chain carries the trigger's message, got: {source}"
);
side.execute_batch("DROP TRIGGER block_notify;").unwrap();
drop(side);
let deadline = tokio::time::Instant::now() + Duration::from_secs(5);
let landed = tokio::time::timeout_at(deadline, store.notify("orders", json!({"x": 2})))
.await
.expect(
"the failed op must release the writer slot — the slot is free again, \
never parked",
);
landed.expect("the notify lands after a failed op released the slot");
store.close();
cleanup(&dir);
}
/// Acceptance: `listen` returns a working receiver — wakes arrive
/// after commits by other connections, and `Wake { channel }` carries
/// the channel name only. The honest posture: the watcher fans out on