Summary
NetScript ships every part of a production command and no composition of them: withTransaction is
exported and has zero callers, idempotency exists only for worker deliveries, and "outbox" and
"audit" do not exist anywhere in the codebase. Consumers therefore hand-roll the boundary that
decides whether a retried request charges twice or a committed state change is never announced — the
Wave-6 billing run, the only GO-grade run of three, wrote its entire command layer in app space. This
issue tracks ratification of RFC-B, which proposes a DB-adapter-neutral command composition kit
and, equally important, states per adapter where that boundary cannot exist. Ratification only —
implementation is a separate issue in a later milestone.
Evidence
- RFC draft:
.llm/runs/plan-fable5-remediation-roadmap--seed/fable-5-remediation-plan/rfcs/RFC-B-command-composition-kit.md
(seed run; not yet a repo file).
packages/database/mod.ts:128 — withTransaction(client, fn, options) is exported and documented
(docs/site/reference/database/index.md:52); grep -rn "withTransaction" across packages/,
plugins/, docs/ finds no caller. $transaction appears in no scaffold template and in no
docs/site/services-sdk page.
packages/cli/src/kernel/assets/service/routers/v1.ts.template:25-53 — the generated write path is
a bare Prisma delegate call with no transaction, no version condition, and no receipt.
packages/plugin-workers-core/src/ports/worker-idempotency-port.ts — claim/markApplied/release
with caller/message-id/payload-hash resolution exists, KV-backed, scoped to worker deliveries
only.
grep -rln "outbox" over packages/, plugins/, docs/ → no match. No audit-record primitive.
packages/telemetry/src/attributes/helpers.ts has job/saga/execution attribute helpers and no
command vocabulary; packages/telemetry/src/attributes/spans.ts:45-46 has rpc.client/rpc.server
only.
- Corpus:
research/preplan-package.md item H; research/wave-6-runs.md §R3 (billing product owns
its command layer; two FAIL_FIX rounds before state advanced; empty trigger_events /
job_execution_history relational projections while authority lived in KV) and §R2 (app-owned
retry/compensation executor, plugin-sagas never adopted).
Current surface
@netscript/service gives a builder, per-request context (ctx.db, ctx.principal,
ctx.traceHeaders — packages/service/src/builder/service-builder-impl.ts:259-282) and oRPC
handlers. @netscript/database gives an unused transaction helper and an isolation vocabulary
(packages/database/ports/database-client.ts:59-77). @netscript/plugin-sagas-core gives
sagaCompensate/send/spawn (src/public/mod.ts:43). Nothing connects them: there is no unit of
work at the handler seam, no expected-version condition, no idempotency receipt, no same-commit side
records, and no command span. commonErrorMap
(packages/contracts/src/application/contract-primitives.ts:21-52) has no conflict code, so an
optimistic-concurrency failure can only surface as a 500.
Target contract
RFC-B is ratified (accepted, rejected, or accepted-with-amendments) with, at minimum, a recorded
decision on: the kit's public home and shape; the unit-of-work port and its published
UnitOfWorkCapabilities; the idempotency key + request-hash + replay-receipt semantics; the
same-commit rule for audit and outbox and the relay that delivers them; the command telemetry
vocabulary; the injected-failure conformance suite; the per-adapter capability table including the
explicit statement that no portable atomic boundary exists across two stores; and the refusal
boundary where a command becomes a saga. The three forks in RFC-B §8 (receipt-storage owner, package
home, expectedVersion transport) are answered rather than deferred.
Acceptance
Boundaries
Do not duplicate: #1123 (OpenAPI→MCP RFC — agent legibility of an existing API surface, not how a
command commits); #922/#928 (frontend contribution contracts); #884/#885 (org-aware
identity/authorization contracts and the auth conformance kit — the kit consumes Principal, it does
not define authorization); #742 (saga definition versioning); #1278 (type-soundness
ratification — this RFC must not restate the cast inventory); #1332 (DB-schema-first docs);
#1263 (generated by-id handler returns 500 instead of a defined 404 — a contract-error defect in
the existing CRUD template, fixed independently of this seam). This issue does not implement
anything: no packages/ or plugins/ change lands under it.
Docs/consumer proof
Ratification is proven by the decision record, not by adoption. Adoption proof belongs to the
implementation issue: a generated project whose non-CRUD command uses the kit, a services-sdk how-to
that replaces the hand-rolled pattern, and a docs example that type-checks against the published
export map.
Provenance
Seed run plan-fable5-remediation-roadmap--seed, PR #1347, 2026-08-08. Pack T3 of the Fable-5
remediation plan (SYNTHESIS.md §4); source item H in research/preplan-package.md. Checked
against the dedup checklist in research/github-board-open.md §7 — no existing owner for
transactional/idempotent command composition. Draft only; no board mutation performed.
Filed from planning seed PR #1347 · source Draft-ID T3-01 · live issue #1361.
Summary
NetScript ships every part of a production command and no composition of them:
withTransactionisexported and has zero callers, idempotency exists only for worker deliveries, and "outbox" and
"audit" do not exist anywhere in the codebase. Consumers therefore hand-roll the boundary that
decides whether a retried request charges twice or a committed state change is never announced — the
Wave-6 billing run, the only GO-grade run of three, wrote its entire command layer in app space. This
issue tracks ratification of RFC-B, which proposes a DB-adapter-neutral command composition kit
and, equally important, states per adapter where that boundary cannot exist. Ratification only —
implementation is a separate issue in a later milestone.
Evidence
.llm/runs/plan-fable5-remediation-roadmap--seed/fable-5-remediation-plan/rfcs/RFC-B-command-composition-kit.md(seed run; not yet a repo file).
packages/database/mod.ts:128—withTransaction(client, fn, options)is exported and documented(
docs/site/reference/database/index.md:52);grep -rn "withTransaction"acrosspackages/,plugins/,docs/finds no caller.$transactionappears in no scaffold template and in nodocs/site/services-sdkpage.packages/cli/src/kernel/assets/service/routers/v1.ts.template:25-53— the generated write path isa bare Prisma delegate call with no transaction, no version condition, and no receipt.
packages/plugin-workers-core/src/ports/worker-idempotency-port.ts—claim/markApplied/releasewith
caller/message-id/payload-hashresolution exists, KV-backed, scoped to worker deliveriesonly.
grep -rln "outbox"overpackages/,plugins/,docs/→ no match. No audit-record primitive.packages/telemetry/src/attributes/helpers.tshas job/saga/execution attribute helpers and nocommand vocabulary;
packages/telemetry/src/attributes/spans.ts:45-46hasrpc.client/rpc.serveronly.
research/preplan-package.mditem H;research/wave-6-runs.md§R3 (billing product ownsits command layer; two
FAIL_FIXrounds before state advanced; emptytrigger_events/job_execution_historyrelational projections while authority lived in KV) and §R2 (app-ownedretry/compensation executor,
plugin-sagasnever adopted).Current surface
@netscript/servicegives a builder, per-request context (ctx.db,ctx.principal,ctx.traceHeaders—packages/service/src/builder/service-builder-impl.ts:259-282) and oRPChandlers.
@netscript/databasegives an unused transaction helper and an isolation vocabulary(
packages/database/ports/database-client.ts:59-77).@netscript/plugin-sagas-coregivessagaCompensate/send/spawn(src/public/mod.ts:43). Nothing connects them: there is no unit ofwork at the handler seam, no expected-version condition, no idempotency receipt, no same-commit side
records, and no command span.
commonErrorMap(
packages/contracts/src/application/contract-primitives.ts:21-52) has no conflict code, so anoptimistic-concurrency failure can only surface as a 500.
Target contract
RFC-B is ratified (accepted, rejected, or accepted-with-amendments) with, at minimum, a recorded
decision on: the kit's public home and shape; the unit-of-work port and its published
UnitOfWorkCapabilities; the idempotency key + request-hash + replay-receipt semantics; thesame-commit rule for audit and outbox and the relay that delivers them; the command telemetry
vocabulary; the injected-failure conformance suite; the per-adapter capability table including the
explicit statement that no portable atomic boundary exists across two stores; and the refusal
boundary where a command becomes a saga. The three forks in RFC-B §8 (receipt-storage owner, package
home,
expectedVersiontransport) are answered rather than deferred.Acceptance
sagaCompensate.Part of #<this issue>before this issue closes.packages/andplugins/are unchanged by the ratifying PR.Boundaries
Do not duplicate: #1123 (OpenAPI→MCP RFC — agent legibility of an existing API surface, not how a
command commits); #922/#928 (frontend contribution contracts); #884/#885 (org-aware
identity/authorization contracts and the auth conformance kit — the kit consumes
Principal, it doesnot define authorization); #742 (saga definition versioning); #1278 (type-soundness
ratification — this RFC must not restate the cast inventory); #1332 (DB-schema-first docs);
#1263 (generated by-id handler returns 500 instead of a defined 404 — a contract-error defect in
the existing CRUD template, fixed independently of this seam). This issue does not implement
anything: no
packages/orplugins/change lands under it.Docs/consumer proof
Ratification is proven by the decision record, not by adoption. Adoption proof belongs to the
implementation issue: a generated project whose non-CRUD command uses the kit, a services-sdk how-to
that replaces the hand-rolled pattern, and a docs example that type-checks against the published
export map.
Provenance
Seed run
plan-fable5-remediation-roadmap--seed, PR #1347, 2026-08-08. Pack T3 of the Fable-5remediation plan (
SYNTHESIS.md§4); source item H inresearch/preplan-package.md. Checkedagainst the dedup checklist in
research/github-board-open.md§7 — no existing owner fortransactional/idempotent command composition. Draft only; no board mutation performed.
Filed from planning seed PR #1347 · source Draft-ID T3-01 · live issue #1361.