general review 004 (pre-release, whole workspace): one HIGH slot-poisoning fix, two contract-observable divergence fixes, robustness + doc corrections — all gates re-run green

- sqlite scheduler tick: a failed COMMIT (or ROLLBACK) left the connection
  released with a stuck-open transaction, wedging the writer slot forever —
  the one commit site missing the drop-+-reopen-replenish arm; tick now
  takes the conn by value with a poisoned disposition (drop + replenish),
  the commit-fault seam reaches the tick, and
  failed_tick_commit_replenishes_the_writer_slot pins the arm
- pg save_offset_tx stored GREATEST($3,0) where the wave-8 gate's
  negative-seed fix (raw seed, ADR-023 §2 2026-10-11 annotation) covered
  only the auto-commit form; mem's merged in-tx read clamped a staged
  negative seed against a phantom zero; both fixed and the tx-form
  totality pinned by a new stamped suite leg (in_tx_reads_see_own_writes)
  green on all three columns vs the live harness server
- pg: a failed forwarder register leaked the channel refcount forever
  (no receiver to drop it) — listen/spawn_bridge now unregister on the
  register error, mirroring the subscribe-failure arm; register doc
  corrected to put the failure disposition at the call site
- pg forwarder: nine poisoned-mutex expect() panics converted to the
  mem crate's into_inner recovery idiom (no-expect-outside-tests rule)
- core encode_payload: a deeply-nested Value aborted the process in
  serde_json's unguarded serializer recursion and the fuzz pin blessed
  storing bytes no decoder could read back; encode now rejects nesting
  past 127 containers (the empirically-verified decode limit) with typed
  Codec — decode-aligned boundary pins added to the fuzz invariant and
  value_type_tests, applied pre-publish within the open class-1 window
- scheduler sleep deadlines: Instant + Duration overflow caps (MAX_SLEEP_S,
  tick-and-resleep) on all three engines for far-future boundaries;
  sqlite tick claim stamp now saturating_add
- docs read true again: Error::Closed scope (stream try_recv arm),
  validation whitespace wording, sqlite lib.rs phantom durability knobs,
  pg lock.rs honest autocommit wording, mem tx/stream merge + wake-
  granularity wording; wakes.rs stale allow(dead_code) removed
- tests: value_type_tests exercised its own map_err instead of the
  function under test (fixed); unwrap_or_default reference encodes
  panic with cause
- docs/reviews/004-pre-release-general-review.md records nine fixed +
  sixteen parked findings (sqlite seam panic-safety armor, watcher
  post-death-subscribe hang + initial-stat self-kill, pg forwarder
  TOCTOU/hang/diagnosability, pg BIGINT server-side stamp overflow, mem
  growth/outbox notes, pg identifier-truncation doc note, smaller) and
  two false positives caught on verification; implementation.md
  review-rounds entry + core-contract backlog rows updated
- gates: build, workspace tests (sqlite 194, core 27, suite legs new),
  full live pg column 127+25+9, clippy -D warnings, fmt, fuzz replay
  6/6, wasm32 check, doc gate -D warnings — all green
This commit is contained in:
glm-5.3-flash committed 2026-10-11 09:25:59 +00:00
1 parent 5385f6bee3
commit 029f885aa1
24 files changed
+738 -103

No files matched your search

+25 -10
View File
@@ -22,9 +22,11 @@
//! invisible to every other view until its commit — no isolation
//! questions can arise across handles).
//! - **Commit-merge + wake-at-commit**: `commit` consumes the handle;
//! the merge is one guarded operation (queues → streams, the
//! canonical lock order) and the overlay's pending wakes fire in the
//! same operation, after the merged state is visible — a tx-staged
//! the merge lands queues then streams (the canonical lock order;
//! two sequential guarded sections on a non-awaiting path — each
//! section's committed view is self-consistent at its boundary) and
//! the overlay's pending wakes fire after the merged state is
//! visible — a tx-staged
//! notify delivers nothing until the merge, one wake per staged
//! notify (per-notify, never coalesced). That discipline is what the
//! pg engine had to fix retroactively (`pg-fix-tx-wake`); here it is
@@ -58,7 +60,7 @@ use crate::resolution::{
use crate::state::Guard;
use crate::state::{EventRow, JobRow, State};
use crate::stream::{
get_offset_row, insert_event, read_events, save_offset_row, stream_wake_channel,
get_offset_row, has_offset_row, insert_event, read_events, save_offset_row, stream_wake_channel,
};
use crate::wakes::WakeBus;
@@ -152,14 +154,27 @@ fn merged_read_since(
/// The merged checkpoint read (absent everywhere = 0).
fn merged_get_offset(overlay: &Overlay, state: &State, stream: &str, consumer: &str) -> i64 {
let committed = {
let (committed, present) = {
let s = state.streams.guard();
get_offset_row(&s, stream, consumer)
(
get_offset_row(&s, stream, consumer),
has_offset_row(&s, stream, consumer),
)
};
let staged = overlay
.saves
.get(&(stream.to_string(), consumer.to_string()));
staged.map_or(committed, |s| (*s).max(committed))
// The in-tx read shows what the commit would produce: a staged
// save against an existing checkpoint rides the monotone guard
// (the staged save only merges when it is ahead, so the read is
// the max), while a staged save *seeding* an absent checkpoint is
// stored raw — a negative seed reads raw in-tx too (ADR-023 §2's
// boundary/offset annotation), not clamped against a phantom zero.
match staged {
Some(s) if present => (*s).max(committed),
Some(s) => *s,
None => committed,
}
}
fn event_of(row: EventRow, stream: &str) -> StreamEvent {
@@ -420,9 +435,9 @@ impl MemTxHandle {
}
/// The commit-merge: move every staged effect into the committed state
/// under one guarded operation (the canonical queues → streams lock
/// order; each section's committed view is self-consistent at its
/// boundary), then fire the overlay's pending wakes — the
/// (queues then streams, the canonical lock order; two sequential
/// guarded sections on a non-awaiting path) then fire the overlay's
/// pending wakes — the
/// wake-at-commit discipline: nothing delivers until the merge lands.
fn merge_and_wake(state: Arc<State>, wakes: Arc<WakeBus>, mut overlay: Overlay) {
{