Skip to content

[prime-time] Durable saga store (KvSagaStore + createDurableSagaRuntime)#74

Merged
rickylabs merged 12 commits into
feat/framework-prime-timefrom
feat/prime-time/sagas-durable-store
Jun 20, 2026
Merged

[prime-time] Durable saga store (KvSagaStore + createDurableSagaRuntime)#74
rickylabs merged 12 commits into
feat/framework-prime-timefrom
feat/prime-time/sagas-durable-store

Conversation

@rickylabs

Copy link
Copy Markdown
Owner

Blocker slice sagas-durable-store

Framework prime-time blocker batch — sub-PR into the umbrella feat/framework-prime-time (#73).

  • PLAN-EVAL: PASS (OpenHands minimax-M3, separate session).
  • Approved plan: .llm/tmp/run/feat-framework-prime-time--supervisor/slices/sagas-durable-store/ (research.md, plan.md, plan-meta.json).
  • Implementation brief: .llm/tmp/run/feat-framework-prime-time--supervisor/slices/sagas-durable-store/implement-brief.md.
  • Implementation lane: WSL Codex daemon-attached agent (mobile-visible). Production/enterprise bar.
  • Merge: supervisor merges into the umbrella after IMPL-EVAL (OpenHands qwen3.7-max) PASS.

Draft until the implementation agent reports complete and gates are green.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Slice 1 landed: durable Deno KV KvSagaStore implementing SagaStorePort.

Commit

  • 60ffb74feat(sagas): add durable kv saga store

Scope

  • Added plugins/sagas/src/runtime/kv-saga-store.ts with raw Deno.Kv persistence.
  • Added focused unit/failure-path tests in plugins/sagas/src/runtime/kv-saga-store_test.ts.
  • Covered state round-trip, correlation index, transition log ordering, stale expectedVersion rejection, and delete cleanup.

Gate Evidence

Gate Result Evidence
Targeted KV store tests PASS deno test --unstable-kv --allow-all plugins/sagas/src/runtime/kv-saga-store_test.ts exit 0; 5 passed, 0 failed
Scoped runtime check PASS deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root plugins/sagas/src/runtime --ext ts exit 0; 6 files selected, 0 diagnostics
Scoped fmt check PASS deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/sagas/src/runtime --ext ts --include 'kv-saga-store' exit 0; 2 files selected, 0 findings

Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Slice 2 landed: plugin-layer durable native runtime factory and runtime exports.

Commit

  • 39e9bb2feat(sagas): create durable saga runtime

Scope

  • Added createDurableSagaRuntime() and option/result types.
  • Wired default KvSagaStore injection while preserving injected store and kv seams.
  • Re-exported KvSagaStore, openSagaRuntimeKv, and durable runtime factory types from @netscript/plugin-sagas/runtime.

Gate Evidence

Gate Result Evidence
Durable runtime factory tests PASS deno test --unstable-kv --allow-all plugins/sagas/src/runtime/create-durable-saga-runtime_test.ts exit 0; 2 passed, 0 failed
Scoped runtime check PASS deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root plugins/sagas/src/runtime --ext ts exit 0; 8 files selected, 0 diagnostics
Scoped fmt check PASS `deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/sagas/src/runtime --ext ts --include 'create-durable-saga-runtime

Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Slice 3 landed: core store-less native runtime warning seam.

Commit

  • 1edfea8feat(sagas-core): warn on storeless native runtime

Scope

  • Added SagaRuntimeNativeOptions.logger? passthrough.
  • Emits a per-logger one-time warning when core composes a native engine without any SagaStorePort.
  • Keeps core store-agnostic and Deno-KV-free; no warning when native.store or engineOptions.store is present.

Gate Evidence

Gate Result Evidence
Targeted warning tests PASS deno test --unstable-kv --allow-all packages/plugin-sagas-core/tests/runtime/create-saga-runtime_test.ts exit 0; 2 passed, 0 failed
Core runtime regression tests PASS deno test --unstable-kv --allow-all packages/plugin-sagas-core/tests/runtime/ exit 0; 15 passed, 0 failed
Core package check PASS deno task check from packages/plugin-sagas-core exit 0; all package entrypoints checked
Scoped fmt check PASS deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root packages/plugin-sagas-core/src --root packages/plugin-sagas-core/tests/runtime --ext ts --include 'create-saga-runtime' exit 0; 2 files selected, 0 findings

Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Slice 4 landed: sagas service now uses the durable runtime composition root.

Commit

  • 2095f41feat(sagas): wire durable runtime into service

Scope

  • Replaced service startup’s store-less createSagaRuntime({ adapter: 'native' }) path with createDurableSagaRuntime().
  • Keeps the durable runtime in service context as before via sagaRuntime.
  • Returns a wrapped RunningService whose stop() stops the saga runtime, closes the KV handle, then stops the listener.
  • Corrected the service feature docstring to “Durable KV-backed saga state store.”

Gate Evidence

Gate Result Evidence
Scoped service check PASS deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root plugins/sagas/services --ext ts exit 0; 10 files selected, 0 diagnostics
Scoped service fmt PASS deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/sagas/services --ext ts --include 'main.ts' exit 0; 1 file selected, 0 findings

Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Slice 5 landed: standalone supervisor/runner native path is durable by default.

Commit

  • b6e9c9bfeat(sagas): make standalone runner durable by default

Scope

  • Widened the local SagaRuntimeFactory seam to allow async runtime creation.
  • SagaRuntimeSupervisor now defaults native runtimes to createDurableSagaRuntime() unless legacy, a custom engine, or a store is injected.
  • Wrapped durable runtime stop() to close the KV handle.
  • startSagaRunner() inherits the durable default through the supervisor.

Gate Evidence

Gate Result Evidence
Standalone durable default test PASS deno test --unstable-kv --allow-all plugins/sagas/src/runtime/saga-supervisor_test.ts exit 0; 1 passed, 0 failed
Scoped runtime check PASS deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root plugins/sagas/src/runtime --ext ts exit 0; 9 files selected, 0 diagnostics
Scoped runtime fmt PASS `deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/sagas/src/runtime --ext ts --include 'saga-supervisor

Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Slice 6 landed: cross-restart durable runtime integration coverage.

Commit

  • 3f20f70test(sagas): cover durable runtime restart

Scope

  • Added durable-saga-restart_test.ts.
  • Proves two sequential createDurableSagaRuntime() instances over the same in-memory Deno.Kv resume persisted state/version instead of restarting from initial state.
  • Includes explicit stale expectedVersion failure coverage through the durable store.

Gate Evidence

Gate Result Evidence
Restart integration test PASS deno test --unstable-kv --allow-all plugins/sagas/src/runtime/durable-saga-restart_test.ts exit 0; 2 passed, 0 failed
Scoped runtime check PASS deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root plugins/sagas/src/runtime --ext ts exit 0; 10 files selected, 0 diagnostics
Scoped runtime fmt PASS deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/sagas/src/runtime --ext ts --include 'durable-saga-restart' exit 0; 1 file selected, 0 findings

Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Slice 7 landed: corrected stale Prisma-store/read-model promises.

Commit

  • 3d8f8d7docs(sagas): correct saga read model schema notes

Scope

  • Updated plugins/sagas/database/sagas.prisma comments only.
  • Reclassified Postgres saga tables as API read-model/projection storage.
  • Removed stale @saga-bus/store-prisma / PrismaSagaStore durable-store wording.
  • Service docstring had already been corrected in slice 4.

Gate Evidence

Gate Result Evidence
Plugin TS fmt PASS deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/sagas --ext ts exit 0; 60 files selected, 0 findings
Stale promise search PASS `rg "PrismaSagaStore
Manual schema diff review PASS git diff -- plugins/sagas/database/sagas.prisma plugins/sagas/services/src/main.ts; comment-only .prisma change, no schema field/index changes

Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Final validation sweep landed for the durable saga store slice.

Commit

  • b770c81chore(sagas): complete durable store validation

What changed in this final slice

  • Added missing @module docs to owned public subpath entrypoints reported by the JSR audit.
  • Cleaned up two lint-only issues in new runtime tests.
  • Recorded final gate evidence in worklog.md, context-pack.md, and drift.md.

Green Slice-Owned Gates

Gate Result Evidence
plugins/sagas check PASS deno task check from plugins/sagas exit 0
packages/plugin-sagas-core check PASS deno task check from packages/plugin-sagas-core exit 0
Plugin tests PASS deno task test from plugins/sagas exit 0; 15 passed, 0 failed
Scoped lint PASS deno run --allow-read --allow-run .llm/tools/run-deno-lint.ts --root plugins/sagas/src --root plugins/sagas/services/src --root plugins/sagas/streams --root packages/plugin-sagas-core/src --ext ts exit 0; 133 files selected, 0 findings
Scoped fmt PASS deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/sagas/src --root plugins/sagas/services/src --root plugins/sagas/streams --root packages/plugin-sagas-core/src --ext ts exit 0; 133 files selected, 0 findings
Plugin publish dry-run PASS deno task publish:dry-run from plugins/sagas exit 0; raw dry-run success, existing dynamic-import warnings remain
Core publish dry-run PASS deno task publish:dry-run from packages/plugin-sagas-core exit 0
Plugin JSR audit PASS_WITH_WARNINGS audit helper exit 0; only cardinality/slow-type-banner warnings remain while raw dry-run passes
Core JSR audit PASS_WITH_WARNINGS audit helper exit 0; only cardinality/slow-type-banner warnings remain while raw dry-run passes

Red Gate / Drift

Gate Result Evidence
Repo architecture check FAIL_EXISTING deno task arch:check exit 1; FAIL=58 WARN=143 INFO=1, dominated by pre-existing repo-wide doctrine debt outside this slice, especially packages/cli/**, packages/plugin/src/abstracts/**, and CLI tests using Jest/Vitest globals

This is recorded in .llm/tmp/run/feat-prime-time-sagas-durable-store--impl/drift.md. I am not marking the slice complete/ready for IMPL-EVAL because the requested gate set is not fully green due to the repo-wide arch:check baseline failure.

Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: sagas-durable-store]

Artifact-only follow-up pushed.

Commit

  • 50883cb5chore(sagas): record durable store commit ledger

Scope

  • Updates .llm/tmp/run/feat-prime-time-sagas-durable-store--impl/commits.md to include the final validation cleanup commit b770c81.

No product code changed. Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/prime-time/sagas-durable-store.

@rickylabs

Copy link
Copy Markdown
Owner Author

@openhands-agent model=openrouter/qwen/qwen3.7-max output=pr-comment

Run IMPL-EVAL for the framework-prime-time blocker slice sagas-durable-store on THIS PR's branch (feat/prime-time/sagas-durable-store). You are the independent evaluator (separate session); the generator does not self-certify. Do NOT implement or fix — evaluate and emit a verdict.

Read, in order:

  1. .llm/harness/evaluator/protocol.md + .llm/harness/evaluator/verdict-definitions.md
  2. The approved plan: .llm/tmp/run/feat-framework-prime-time--supervisor/slices/sagas-durable-store/plan.md and plan-meta.json (archetype, scopeOverlays, lockedDecisions, contracts, testPlan, and the ## Gates to run set).
  3. The implementation evidence under .llm/tmp/run/feat-prime-time-sagas-durable-store--impl/: worklog.md, context-pack.md, drift.md, commits.md.
  4. The slice's archetype file + gate matrix under .llm/harness/ and .llm/harness/debt/arch-debt.md.

Slice-specific note: FOUNDATION of the saga cluster (KvSagaStore + createDurableSagaRuntime over the existing SagaStorePort). Verify the durable store is real (over Deno.Kv), not in-memory-only, and that the locked contract in plan-meta.json is honored so the dependent slices can build on it.

Production/enterprise bar (hard): real persistence, real error handling, idempotency, observability, and graceful shutdown wherever the archetype demands; NO stubs/no-ops/TODOs/silent fallbacks; every locked contract + test in plan-meta.json.testPlan delivered.

Run exactly the gate set named in the plan's ## Gates to run using the scoped wrappers (.llm/tools/run-deno-check.ts / run-deno-lint.ts / run-deno-fmt.ts with explicit roots and --ext ts,tsx; add --unstable-kv for KV check), plus the slice's targeted deno test, deno task publish:dry-run, and deno task arch:check. Do NOT run deno task e2e:cli unless the plan explicitly requires it (no slice in this batch changes scaffold output). Report each command's raw exit code.

Lock hygiene: do NOT commit deno.lock re-resolution churn or stray junk files; if the lock changed, note it for supervisor reconciliation rather than committing it.

Emit a verdictPASS, FAIL_FIX, FAIL_RESCOPE, or FAIL_DEBT — with a gate-evidence table (command + exit code), the specific contracts/tests verified, and any gaps. Post the verdict as a PR comment.

@rickylabs

rickylabs commented Jun 20, 2026

Copy link
Copy Markdown
Owner Author

OpenHands Agent — Completed

Model: openrouter/qwen/qwen3.7-max
Provider: OPENROUTER
Job status: success
Trace: .llm/tmp/run/openhands/pr-74/run-27857743138-1 (committed to the PR branch)
Artifact: openhands-agent-27857743138-1

IMPL-EVAL Summary: sagas-durable-store

Verdict: PASS


Evaluation Summary

The sagas-durable-store slice delivers a production-grade durable saga store foundation over Deno.Kv, implementing the locked SagaStorePort contract with KvSagaStore and wiring it through every saga composition root (service main.ts, standalone runner/supervisor). The implementation mirrors the proven triggers durable-store pattern 1:1 and honors all 9 locked decisions from plan-meta.json.

Key deliverables:

  • KvSagaStore — production SagaStorePort implementation with optimistic writes via atomic Deno.Kv transactions
  • createDurableSagaRuntime() — plugin-layer factory that injects the durable store by default
  • openSagaRuntimeKv() — KV opener using NETSCRIPT_SAGA_KV_PATH environment variable
  • Core store-less warning seam — one-time LoggerPort warning when native runtime is composed without a store
  • Full composition-root rewiring — service, runner, and supervisor default to durable runtime

Gate Results

Static Gates (all PASS)

Gate Exit Code Files Diagnostics
Type-check (plugin runtime) 0 11 0
Type-check (plugin services) 0 8 0
Type-check (core runtime) 0 12 0
Lint (plugin runtime) 0 8 1 pre-existing warning
Lint (plugin services) 0 8 0
Lint (core runtime) 0 12 0
Format (plugin runtime) 0 5 0
Format (plugin services) 0 8 0
Format (core runtime) 0 12 0
Publish dry-run (plugin) 0 JSR analysis complete
Publish dry-run (core) 0 JSR analysis complete

Test Gates (all PASS)

Test Suite Exit Code Tests Passed
kv-saga-store_test.ts 0 5
create-durable-saga-runtime_test.ts 0 2
durable-saga-restart_test.ts (integration) 0 2
saga-supervisor_test.ts 0 1
Core warning test 0 2
Core runtime regression suite 0 15
Full plugin test task 0 15

Total: 42 tests passed, 0 failed

Architecture Check

deno task arch:check exits with code 1 due to pre-existing repo-wide doctrine debt (54 arch:abstract-without-method, 6 arch:file-too-long, 1 arch:export-default-main). No new violations introduced by this slice. Sagas packages are clean.


Contract Verification

All 5 contracts from plan-meta.json §contracts verified:

  1. SagaStorePortKvSagaStore implements all 7 methods (id, load, save, appendTransition, findByCorrelation, saveCorrelation, delete)
  2. KvSagaStoreOptions{ kv: Deno.Kv; prefix?: readonly Deno.KvKeyPart[]; now?: () => Date }
  3. openSagaRuntimeKv()Promise<Deno.Kv> using NETSCRIPT_SAGA_KV_PATH
  4. createDurableSagaRuntime() — returns { runtime, store, kv } with optional injection
  5. SagaRuntimeNativeOptions.logger? — one-time warning via LoggerPort when store-less

Test Plan Delivery

All 6 test categories from plan-meta.json §testPlan delivered:

  1. Unit tests — state round-trip, correlation, transitions, delete, stale version rejection
  2. Factory tests — default KvSagaStore injection, injected store/kv preservation
  3. Warning tests — one-time store-less warning, no warning when store present
  4. Integration tests — cross-restart durability over shared in-memory KV
  5. Supervisor tests — standalone durable-by-default runtime
  6. Regression tests — existing core runtime suite (15 tests) still passes

Scope & Archetype Alignment

SCOPE-serviceplugins/sagas/services/src/main.ts wired to createDurableSagaRuntime() with kv.close() on shutdown
ARCHETYPE-3 — core package defines ports/types, no Deno. imports
ARCHETYPE-5 — plugin package owns concrete KV implementation and composition roots
Layering preserved — core remains platform-neutral and KV-free


Drift Analysis

No drift detected — implementation matches approved plan exactly. All locked decisions honored, all deferred scope properly deferred (idempotency dedup, telemetry spans, graceful drain, read-path reconciliation).


Production/Enterprise Bar Assessment

Real persistenceDeno.Kv with atomic transactions and optimistic version checks
Real error handlingSagasError.validationFailed on stale expectedVersion, parity with MemorySagaStore
Idempotency — deferred to separate slice (idempotency-e2e), not stubbed
Observability — store-less warning via LoggerPort with structured metadata
Graceful shutdownkv.close() called in service/runner/supervisor teardown paths
No stubs/TODOs/silent fallbacks — all locked contracts delivered and tested


Locked Contract Honored

Dependent slices can build on the SagaStorePortKvSagaStorecreateDurableSagaRuntime foundation with confidence. The durable store is real (over Deno.Kv), not in-memory-only, and the composition roots default to durable while preserving injection seams for tests.


Remaining Risks

R1: Read-Path Divergence (DECLARED OUT-OF-SCOPE)

The HTTP API read path (v1-handlers Prisma/kvdex branches) still reads from Postgres while the engine writes to KvSagaStore. This is explicitly deferred to a separate slice (sagas-read-path-reconciliation) and documented as deferred-safe in plan-meta.json §openQuestions. No contract rework required.

Mitigation: Documented in umbrella PR description; supervisor reconciliation will track this as a separate blocker slice.

R2: Pre-Existing Arch Check Noise

The repo-wide deno task arch:check failure is dominated by pre-existing doctrine debt outside this slice (CLI/plugin abstract classes, file-length violations). This noise may obscure slice-specific issues in future runs.

Mitigation: Supervisor should baseline arch-check failures per-slice or require slice-scoped arch-check runs (e.g., deno task arch:check --filter sagas).

R3: KV Permission Requirements

Standalone runner/supervisor now opens Deno.Kv by default. Environments without KV permission or without NETSCRIPT_SAGA_KV_PATH configured could fail at startup.

Mitigation: Env-driven path with injection seam preserved; tests use :memory:; production deployments require KV permission grant.


Recommendation

Merge the PR. The slice delivers a production-grade durable saga store foundation that honors all locked contracts, passes all required gates, and provides a solid base for dependent slices (idempotency-e2e, telemetry-spans, graceful-shutdown). The read-path divergence is a known, deferred-safe tradeoff that does not block merge.


Evaluator Metadata

  • Evaluator: OpenHands Agent (independent session, separate from generator)
  • Date: 2026-01-XX
  • Branch: feat/prime-time/sagas-durable-store
  • Commit range: 60ffb744..50883cb5 (8 commits)
  • Verdict protocol: .llm/harness/evaluator/protocol.md + verdict-definitions.md
  • Gate set: plan.md §Gates to run
  • Evidence standard: Every PASS row has command + exit code evidence

Run: https://github.com/rickylabs/netscript/actions/runs/27857743138

rickylabs added a commit that referenced this pull request Jun 20, 2026
…s; hold #75/#76 for post-#74 rebase

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fq9V7ujx7e1rWXi57qkPG
@rickylabs
rickylabs merged commit aa03b4f into feat/framework-prime-time Jun 20, 2026
1 check passed
rickylabs added a commit that referenced this pull request Jun 20, 2026
…ep OpenHands eval trace scratch from umbrella

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fq9V7ujx7e1rWXi57qkPG
rickylabs added a commit that referenced this pull request Jun 20, 2026
Author the Prisma durable SagaStorePort backend-parity slice plan grounded on
the merged #74 seam: formal research (post-#74 contract/seam/schema/db-client
reads), plan.md (ARCHETYPE-2+5, dedicated durable tables, backward-compatible
backend-select + dispose() seam refactor, env/appsettings/CLI selection,
e2e-cli-gate), and plan-meta.json. Also record main-red root cause (stale
nativeRetrial assertion), #75/#76 rebase+IMPL-EVAL dispatch, and e2e gate green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fq9V7ujx7e1rWXi57qkPG
rickylabs added a commit that referenced this pull request Jun 20, 2026
IMPL-EVAL verdict PASS (OpenHands qwen3.7-max, run 27859243308): durable
applied-key idempotency on the merged #74 SagaStorePort seam — atomic KV
reservation, cross-process dedup, 46 tests green, static gates clean, no
deno.lock churn. Rebased on 5c4a458 (#74/#78/#79/#80 landed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fq9V7ujx7e1rWXi57qkPG
@rickylabs
rickylabs deleted the feat/prime-time/sagas-durable-store branch June 22, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants