Skip to content

fix(sagas): register KV adapter in generated runtime glue - #1193

Merged
rickylabs merged 8 commits into
mainfrom
fix/sagas-kv-glue-registration
Aug 4, 2026
Merged

fix(sagas): register KV adapter in generated runtime glue#1193
rickylabs merged 8 commits into
mainfrom
fix/sagas-kv-glue-registration

Conversation

@rickylabs

@rickylabs rickylabs commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary

Fix generated saga background glue at its regeneration authority so default Redis/Garnet scaffolds
register the existing KV adapter before opening the durable saga store. The generated saga resource
also exposes a supervisor-backed health endpoint, and the KV-backed API can start without optional
Prisma saga projections while the Prisma backend remains strict.

Scope

Slices

Owner verification protocol

Full evidence is quoted in
.llm/runs/fix-sagas-kv-glue-registration--w2-f/worklog.md; decisive artifacts follow.

  1. Fresh user scaffold, default cache. The normal local CLI created a Postgres/default-Redis
    project and installed the saga plugin. The unfixed emitted file contained only:

    import { runSagaRunner } from '@netscript/plugin-sagas/runtime';

    The fixed fresh scaffold emitted registration before startup:

    import '@netscript/kv/redis';
    import { startSagaRunner } from '@netscript/plugin-sagas/runtime';
  2. Genuine populated health. aspire describe sagas reported:

    state=Running healthStatus=Healthy
    sagas_http_/health_200_check=Healthy
    200 {"status":"running","adapter":"native","definitionCount":2}
    
  3. Terminal and compensation paths. Four real API publishes returned 200 for start, step,
    complete, and rollback. Redis held distinct durable envelopes:

    issue1184-protocol:issue1184-terminal-d version=3 status=completed
    steps=[started,step,completed]
    issue1184-protocol:issue1184-compensate-e version=1 status=compensating
    steps=[rollback-requested]
    
  4. OTEL traces, spans, logs, and correlation. The required aspire otel traces, spans, and
    logs commands showed:

    started  instance=...terminal-d correlation=terminal-d outcome=success
    step     instance=...terminal-d correlation=terminal-d outcome=success
    complete instance=...terminal-d correlation=terminal-d outcome=success
    rollback instance=...compensate-e correlation=compensate-e outcome=compensated
    

    The three terminal steps stayed on one instance; compensation stayed on a separate instance.
    Logs independently showed Redis selection, adapter initialization, connection, and API startup.

  5. RED first. The generated-artifact assertion failed 0 passed | 1 failed because the emitted
    runtime lacked import '@netscript/kv/redis';. The actual unfixed generated runtime then exited
    through getKv -> openSagaRuntimeKv -> startSagaRunner with:

    KvConnectionError: Redis/Garnet was selected but no Redis adapter is registered.
    
  6. Restart durability. sagas-api changed PID 275673 -> 278465 and the background runner
    changed 275672 -> 280444; the populated health report remained healthy and Redis returned the
    exact same version-3 completed and version-1 compensating envelopes after both restarts.

  7. Artifacts, not exits. Evidence is emitted source, populated health reports and HTTP bodies,
    Redis envelopes, and OTEL payloads. Final aspire ps is empty; ownership-aware leak-check reports
    no owned survivor and leaves two foreign wave-4 containers untouched.

CACHE_PROVIDER=denokv was also selected in a fixed generated project while the registration module
was loaded; a real Deno-KV write/read returned {"value":"denokv"}.

Validation

  • PLAN-EVAL — composed per milestone-run.md and owner/orchestrator ruling D6.
  • Generated glue RED/GREEN — expected RED, then 6/6 resource tests pass.
  • Saga AppHost generator — 17/17 steps pass.
  • KV/Prisma policy — 3/3 tests pass.
  • Scoped check/lint/fmt — 79 saga files + 22 CLI-helper files, zero findings.
  • deno task quality:gate — pass; zero quality findings and zero doctrine failures.
  • Doc-lint — unchanged baseline: 15 private refs, 0 missing JSDoc.
  • Saga publish dry-run — pass.
  • deno.lock — no churn; no new lint ignores.
  • Published-package confirmation — milestone canary point 2, outside this local PR gate.

Merge-readiness blocker

The required exact command was run from an empty AppHost preflight:

deno task e2e:cli run scaffold.runtime --cleanup --format pretty

The final clean artifact passed all saga readiness gates and failed later in unrelated users DB
health:

runtime.wait.postgres ... PASSED
runtime.wait.sagas-api ... PASSED
runtime.wait.sagas ... PASSED
behavior.db-status-preserves-apphost ... PASSED
behavior.service-health ... FAILED
cleanup.aspire-stop ... PASSED
Summary: passed=51 failed=1

Live inspection proved the nominal preserve-AppHost gate changed the dependent database endpoint:

live postgres: Healthy, postgres_check=Healthy, localhost:44973
users /health: 503, Prisma still queries 127.0.0.1:50564

The orchestrator accepted this 51/1 result as environmental DB/endpoint churn rather than a #1184
defect. The PR nevertheless remains draft with status:ci-fail: the expensive-gate slot is held for
the dedicated #1190 delivery slice. After #1190 merges, this branch will rebase onto main and run
one joint verification—one-pass scaffold.runtime plus the full seven-point lifecycle on both
default Redis/Garnet and explicit Deno KV. No IMPL-EVAL pass or ready-merge claim is made before
that joint run is green.

Harness

  • Run dir: .llm/runs/fix-sagas-kv-glue-registration--w2-f/
  • PLAN-EVAL row: composed per milestone-run.md (orchestrator waiver)
  • Full failure and endpoint evidence: worklog.md + drift.md

Drift / Debt

Definition of Done

  • Generated sagas/runtime.ts registers the Redis adapter at the regeneration source.
  • RED evidence captures the unfixed emitted-glue failure and real-scaffold KvConnectionError.
  • A fresh default-cache scaffold shows populated saga health reports, not empty-check health.
  • Real saga runs reach terminal and compensating states with correlated step spans/logs/traces.
  • Runner restart preserves the correct durable saga state.
  • CACHE_PROVIDER=denokv remains working.
  • Scoped wrappers, quality:gate, package-surface checks, lock hygiene, and leak checks pass.
  • One-pass scaffold.runtime recorded (51/1, red = baseline fix(scaffold): users service Prisma binds a stale Postgres endpoint — DB health check fails on a clean scaffold.runtime run #1202, cloud source-of-truth per D13); composed review + orchestrator pre-merge gate complete; close gate green on ticked issue evidence.
issue: 1184
entries:
  - box-index: 1
    evidence: "runtime.stub.ts registration; fixed fresh emitted artifact quoted in the owner protocol"
  - box-index: 2
    evidence: "populated saga health report and direct supervisor health body; no KvConnectionError"
  - box-index: 3
    evidence: "resources.test.ts RED 0/1 before fix and GREEN after fix over emitted glue"
  - box-index: 4
    evidence: "fixed generated project selected denokv and round-tripped {value: denokv}"
  - box-index: 5
    evidence: "fresh scaffold terminal + compensation Redis envelopes and four correlated saga.handle spans"

@rickylabs

Copy link
Copy Markdown
Owner Author

[PHASE: RESEARCH]

Re-baselined the amended issue against main at 2c8865e8.

Findings

  1. The install adapter emits sagas/runtime.ts from runtime.stub.ts; the current source imports only runSagaRunner.
  2. Existing resource coverage checks emitted paths but never inspects the generated runtime contents.
  3. openSagaRuntimeKv() delegates to getKv(), which explicitly throws when Redis/Garnet is detected without prior @netscript/kv/redis registration.
  4. CACHE_PROVIDER=denokv selects the Deno-KV branch independently of whether the Redis factory is registered.
  5. Shared-host preflight found no running AppHost or scaffold runtime. Protected aspire mcp start processes and foreign Postgres containers were left untouched.

Next

  • Capture the generated-artifact and real-scaffold RED before changing the stub.

@rickylabs

Copy link
Copy Markdown
Owner Author

[PHASE: PLAN]

Plan and Design are locked in .llm/runs/fix-sagas-kv-glue-registration--w2-f/.

Locked decisions

  1. Register the existing adapter with import '@netscript/kv/redis'; in the source stub, before the runner import.
  2. Keep registration unconditional at this backend composition edge; provider selection still preserves CACHE_PROVIDER=denokv.
  3. Test the collected install artifact semantically, including import order, and preserve a real-scaffold RED.
  4. Treat populated health reports, terminal + compensating lifecycle, correlation, OTEL, and restart durability as mandatory closure evidence.

Gates

  • Scoped check/lint/fmt wrappers, quality:gate, doc-lint/publish audit, owner runtime protocol, serialized one-pass scaffold.runtime, lock/leak hygiene.

Next

  • Proceed under the explicit milestone PLAN-EVAL composition waiver.

@rickylabs

Copy link
Copy Markdown
Owner Author

[PHASE: PLAN-EVAL] [VERDICT: APPROVED]

Composed per .llm/harness/workflow/milestone-run.md and owner/orchestrator ruling D6.

No local formal PLAN-EVAL was spawned or awaited. Research currency, locked decisions, open-decision sweep, five commit slices, risk register, full gate set, deferred scope, and JSR surface baseline are recorded in plan-eval.md; implementation proceeds in the same run. Per-PR evaluation remains the draft→ready augment review, OpenHands label surface, and orchestrator pre-merge gate.

@augmentcode

augmentcode Bot commented Aug 3, 2026

Copy link
Copy Markdown

Looks like you're out of credits for this review. Head to your account settings to top up and keep reviews running. https://app.augmentcode.com/account/subscription

@rickylabs

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: S1-RED]

Commit b88c44b90 proves the generated-glue defect before the fix.

Scope

  • Added a semantic assertion over the collected install artefact sagas/runtime.ts.
  • Created a fresh local-source scaffold with Postgres and the default Redis cache; installed sagas and inspected the actual generated runtime plus Aspire cache/background wiring.

RED evidence

sagas install runtime glue registers Redis before starting the runner ... FAILED
AssertionError: Expected actual: "... import { runSagaRunner } from
'@netscript/plugin-sagas/runtime'; ..." to contain:
"import '@netscript/kv/redis';".
FAILED | 0 passed | 1 failed | 4 filtered out

The emitted file itself contains only the runner import, while generated Aspire wiring selects CACHE_PROVIDER: 'redis', binds the cache reference, and executes sagas/runtime.ts.

Gate state

@rickylabs

Copy link
Copy Markdown
Owner Author

IMPL — S2 generated-glue fix

Implemented the package-owned registration seam in runtime.stub.ts: emitted glue now loads @netscript/kv/redis before importing/starting the runner.

Evidence:

  • full adjacent resource test: 5 passed | 0 failed
  • fixed fresh artifact:
    import "@netscript/kv/redis";
    precedes the runner import
  • actual unfixed generated runtime failed through getKv → openSagaRuntimeKv → runSagaRunner with KvConnectionError
  • actual fixed generated project with CACHE_PROVIDER=denokv wrote/read {"value":"denokv"} while the registration module was loaded
  • scoped saga TypeScript format gate: 77 files, 0 findings

Commit: 175a90a. AppHost health/lifecycle/OTEL/restart evidence remains in progress; this is not yet a readiness claim.

@rickylabs

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL]

Generated saga glue now registers the Redis adapter at the regeneration source, exposes a
supervisor-backed health check, and preserves explicit Deno-KV selection. A real fresh scaffold
passes the amended owner protocol: populated saga health, terminal + compensated durable states,
correlated OTEL spans/logs/traces, RED KvConnectionError, and restart durability.

Evidence

  • Commits: b88c44b90, 175a90a51, 0a20858af
  • Harness record: .llm/runs/fix-sagas-kv-glue-registration--w2-f/worklog.md
  • Scoped wrappers: 79 saga + 22 CLI-helper files, zero findings
  • Focused tests: 6 resource + 3 KV policy + 39 generator BDD steps pass
  • Framework/package: quality:gate pass; doc-lint baseline; publish dry-run pass
  • Hygiene: no deno.lock churn, no new lint ignores, no owned resource survivor

Merge-readiness blocker

The exact scaffold.runtime --cleanup --format pretty run passes every saga readiness gate and then
fails the unrelated generated users health check (51 passed, 1 failed). Artifact inspection shows
healthy live Postgres at localhost:44973, while the resident users Prisma client still queries
127.0.0.1:50564 after behavior.db-status-preserves-apphost passes. Direct /health returns 503
with Can't reach database server.

This is recorded as blocking drift in drift.md. The PR remains draft and moves to
status:ci-fail; no IMPL-EVAL pass or ready-merge claim is made.

@rickylabs
rickylabs merged commit 62893db into main Aug 4, 2026
19 of 23 checks passed
@rickylabs rickylabs added the canary:0.0.5-canary.2 Published NetScript prerelease 0.0.5-canary.2 label Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:kv packages/kv area:sagas canary:0.0.5-canary.2 Published NetScript prerelease 0.0.5-canary.2 priority:p1 High status:ci-fail Blocked on a failing CI gate type:fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sagas: generated runtime glue registers no KV adapter — saga runner crashes on a default scaffold

1 participant