Stack 5/5: Durability & the closing release — tolerant replay, fsync_every, doc referee, suggestions (rounds 13-15)#5
Conversation
- Tolerant journal replay (the recovery default): every whole line is salvaged; torn, mis-encoded, or shape-broken lines land on state.damage with line number and reason instead of raising. Recovery tools must never be the second thing that fails. - Strict replay mode for audit tools: mode: :strict raises Errors::JournalDamagedError naming the damaged line, including task events missing a String task_id. - fsync_every: group-commit knob on the journal constructor, with the durability trade named in its docs (a crash may lose up to n-1 acknowledged events); #sync forces the window closed. Modernizes the asking examples: hostile_inputs flips to a green acceptance test with both reader postures demonstrated, and write_path_profile benches the real fsync_every: 20 knob. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
A plan's live state as composed terminal components - badge, gauge, tree, frame - each testable alone, driven by lifecycle hooks with structure from the graph's own depth stats. Fourth persona cast begins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
A Flipper-shaped gate (boolean, actor, deterministic percentage) deciding per run whether the fact-check step joins the plan, spliced in with rewire_task - the step is a plan shape, not an if, so the graph stays honest and the off state has zero residue. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Backwards chunked reads with byte-offset cursors: the last page of a 20,000-event journal costs 16KB and 0.3ms against a 3.2s full replay. Cursors survive append; page numbers don't - the kaminari lesson applied to append-only files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
A plan wrapped in a CLI honoring all four channels: data to stdout, diagnostics-with-hints to stderr, verdicts as exit codes (EX_USAGE 64 distinct from failure 1), JSON on request - proven by invoking itself with injected streams the way scripts would. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Every require in lib/ classified against the gemspec and the gemification schedule. First run caught two live hazards - logger (bundled in 3.5) and cgi (trimmed in 3.5) - both now declared in the gemspec with reasons. A transitive require is a loan, and rubies refinance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
One invoice, two arithmetics: floats confess their IEEE 754 tail while integer cents sign a contract floats cannot - integer as tripwire type, banker's rounding as named policy at one point, and an adds_up rule so the books balance by rule, not hope. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Plans as transition systems: one-method operational semantics,
the full state space enumerated by BFS, completion proved total
by exhaustion for the diamond, and the cycle exhibited as an
empty machine whose only terminal state is {}.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
An ActiveJob-shaped adapter in forty lines: retry_on maps to the retry policy (accounting preserved), discard_on is backstopped by the hopeless convention, and in-plan healing resumes work instead of re-running it through the queue. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Three runnable API shapes for the fsync_every knob - constructor kwarg, policy object, per-call override - judged at the call site. The kwarg deserved to ship: durability contracts belong to the object, and one integer hasn't earned a policy wardrobe yet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Every @example block and README ruby fence harvested and executed in sandboxed subprocesses: 11 of 30 are alive. Dead examples split into fragments-posing-as-programs and API drift; the round-14 ask is runnable-or-annotated docs, Rust doctest style. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Adds the Round 13 table - a fourth cast of ten prolific Rubyists (piotrmurach, jnunemaker, amatsuda, davetron5000, hsbt, noelrap, tomstuart, excid3, kaspth, steveklabnik) - and findings to the perspectives index, and regenerates the examples catalog (121 examples). Next asks recorded: runnable-or-annotated docs, and revive-or-retire the learning-system corner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
- The doctest runner is now a referee: every @example and README fence must run or carry a deliberate annotation ((illustrative: reason) in titles, <!-- doctest: illustrative --> before fences); unannotated failure exits 1. Result: 26 run, 4 annotated, 0 dead. - Fixed the drifted docs: PlanOrchestrator fence uses the current API, fragments became self-contained programs, the compose fence registers its capabilities and executes, plugin example conforms to the plugin contract. - Revived the learning corner: three more missing stdlib requires (time x2, digest), ExecutionHistoryStore no longer double-counts records (memory cache + files are now deduped by id), and the never-functional register_with_orchestrator (it called an #on API that never existed) is replaced by Learning.lifecycle_hooks, the same construction-time seam the journal uses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Plan execution over a real loopback socket: thread pool, one shared mutexed quota across request threads, and a graceful drain proven with a request in flight - close the listener first, finish what you hold, join, exit. Fifth persona cast begins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Bundler-style resolution over the never-resolved dependencies: field: backtracking search, highest-still-compatible selection, and a conflict error with both demand chains and suggested moves - because when resolution fails, the error message is the product. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
RBS signatures generated from capability contracts - required: projects as record-key optionality, shape vs law divided on principle (RBS carries what static checkers can check, the validator carries what needs values), agreement spot-checked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
A compliance file in a dependency-free 30-line mspec: six boundary choices (closed ceilings, resize vs old stamps, nil presence, success-erases-failure) promoted from behavior to executable specification - the document a porter needs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
A 40-line Levenshtein engine on three error seams: capability lookups, contract violations (missing-plus-similar-extra is a typo's signature), and rewire targets. The error was holding the candidate list all along; round-15 ask filed to make suggestions a framework property. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Mini-profiler's heresy for plans: a badge on every run, budgets
that name the offender ('fix summarize first' is an assignment; a
p95 chart is a vibe), and a self-audit proving always-on costs
144 microseconds per plan.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
A master preforks three plan workers: shared-pipe work queue, SIGTERM as finish-then-exit, reaping by pid and status, per-worker flock'd journals. The drill taught two live lessons: require what you use, and a pipe is a queue but not a fair one under burst. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Every interesting framework value judged by Ractor.shareable?: stats and order cross as-is, the frozen snapshot is a shallow promise, and the RateLimit's refusal is load-bearing - send facts, keep machines. The auditor's first draft froze the evidence; verdicts now come from Marshal copies. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
SolidQueue's concurrency_key over the framework's limiters: at most one sync per tenant with cross-tenant parallelism measured (not assumed), both overflow postures named at the call site, and a lock-guarded registry so rival limiters can't be minted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Shrine's cache/promote two-phase pattern as a journaled plan: derivative names as idempotency keys, crash resuming at the exact thumbnail it died on, the record committing only after every derivative exists, and the double-submit deriving nothing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Adds the Round 14 table - a fifth cast of ten prolific Rubyists (evanphx, indirect, soutaro, eregon, yuki24, samsaffron, rtomayko, marcandre, rosa, janko) - and findings to the perspectives index, and regenerates the examples catalog (131 examples). Next asks recorded: did-you-mean suggestions in framework errors, and fiber-vs-thread guarantees pinned as behavior specs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
- Agentic::Suggestions: a conservative Levenshtein engine (silence beats a confident wrong answer), threaded into the framework's errors. ValidationError diagnoses renamed keys from missing-plus- similar-extra (structured hints + message), and the rewire/remove errors suggest close task names - the candidate lists were already in scope at every raise site. - The concurrency contract, pinned: spec/agentic/ concurrency_contract_spec.rb promises per-method guarantees (journal record thread-safe, windowed limiter thread-safe, concurrency-mode limiter fiber-scoped, registry thread-safe), with @note Concurrency contract: documentation on the methods. Modernizes the asking examples: did_you_mean.rb flips from retrofit to native demonstration; behavior_spec.rb points at the delivered contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Adds the Round 15 section (did-you-mean as infrastructure, the concurrency contract pinned) and the series retrospective: fifteen rounds, fifty personas across five casts, thirteen releases built from field notes, 131 offline examples, and an empty asks list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
- Durations measured on the monotonic clock (stack 1 panel, tenderlove): wall clocks step under NTP and every journal baseline downstream would eat the noise; all orchestrator timing deltas now use Process.clock_gettime(CLOCK_MONOTONIC). - typo_hints detects missing keys structurally (stack 5 panel, jeremyevans/yuki24): violations.keys - given.keys instead of string-matching dry-schema's message text, which is not an API. - Concurrency contract pins the high-water mark under threads (stack 4 panel, headius follow-through on the counter mutex). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
codenamev
left a comment
There was a problem hiding this comment.
Persona review panel: Mike Dalessio, Jean Boussier, Yuki Nishijima. Verified locally: 610 examples, 0 failures at HEAD (including this stack's review-fix commits); timing-dependent examples re-smoked after the monotonic-clock change.
Mike Dalessio (flavorjones) — Tolerant replay is exactly the posture a recovery parser owes its callers: salvage every whole line, record torn/mis-encoded/shape-broken lines on state.damage with line numbers and reasons, and never let the recovery tool be the second thing that fails. The two-door design (:tolerant default for recovery, :strict raising JournalDamagedError for auditors) is the right resolution of the tension I raised — one format, two reader postures, both legitimate, and the strict error carries line_number as data, not just prose. line.scrub before parse handles the encoding-garbage case in the same sweep. The hostile-inputs probe staying in-tree as the acceptance test is how this stays fixed. Approve.
Jean Boussier (byroot) — fsync_every: is the group-commit knob done the way durability knobs must be done: the trade is named in the constructor's docs (n-fold throughput, up to n-1 acknowledged events at risk — "a different durability contract, not a faster same one") instead of living in a wiki. #sync gives the explicit close-the-window call, and the write-path profile example prices the whole decision (fsync is 99.6% of the write; JSON was always innocent). Also endorsing this stack's review-fix commit: durations on CLOCK_MONOTONIC — every percentile baseline in the journal was one NTP step away from a phantom regression. Approve.
Yuki Nishijima (yuki24) — The suggestions work is my ask, delivered better than I filed it. Agentic::Suggestions is conservative where it must be (length-scaled threshold; hint returns "" rather than guess — a wrong suggestion is worse than none), and the ValidationError integration diagnoses the rename case specifically: missing-plus-similar-extra → "You sent :weight_kilo - did you mean :weight_kg?", in the message AND as structured hints for programmatic consumers (the self-correcting-output loop feeds these straight back to a model). One thing I'd flagged in draft is already fixed in this stack's review commit: missing keys are now detected structurally (violations.keys - given.keys) instead of matching dry-schema's message text, which is not an API. rewire/remove suggesting across ids and descriptions is the right candidate pool. Approve.
Panel verdict: approve (as comment; self-approval disallowed). All action items from panels 1-4 are resolved in this slice; nothing carried forward. Merging closes the stack.
Generated by Claude Code
Final slice (rounds 13-15), stacked on #4. Merging this brings the branch to the series' closing state: 610 specs green, 131 offline examples, empty asks list.
Framework
state.damage;mode: :strictraisesJournalDamagedErrornaming the line — recovery tools must never be the second thing that failsfsync_every:group commit: the durability trade named in the constructor (n-fold throughput vs up to n-1 acknowledged events at risk), plus#sync@example/README fence runs or carries a deliberateillustrativeannotation (26 run, 4 annotated, 0 dead); drifted fences fixed against current APIsregister_with_orchestratorreplaced byLearning.lifecycle_hooksAgentic::Suggestions: did-you-mean threaded intoValidationError(renamed-key diagnosis via missing-plus-similar-extra, structuredhints) and rewire/remove errorsspec/agentic/concurrency_contract_spec.rb) +@note Concurrency contract:docsExamples & docs
Review focus: replay modes in
execution_journal.rb,suggestions.rb, the learning-corner fixes.🤖 Generated with Claude Code
https://claude.ai/code/session_01FeZLdZ3M4q4cho4DZPfSkF
Generated by Claude Code