From ad643e15d657eb2b8e7a2d741e690c028ce67dc9 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 18:50:01 +0200 Subject: [PATCH 01/10] chore(harness): activate command composition RFC run --- .../codex-thread-ids.md | 16 ++ .../context-pack.md | 75 ++++++++++ .../drift.md | 24 +++ .../implement.md | 75 ++++++++++ .../plan.md | 141 ++++++++++++++++++ .../research.md | 39 +++++ .../supervisor.md | 38 +++++ .../worklog.md | 120 +++++++++++++++ 8 files changed, 528 insertions(+) create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/drift.md create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/implement.md create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/plan.md create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/research.md create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/supervisor.md create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md new file mode 100644 index 0000000000..088031cda9 --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md @@ -0,0 +1,16 @@ +# rfc-command-kit — Codex implementation thread +- **Thread / session id:** `019fe242-2c45-7e03-a428-eebfb968eda0` +- **Rollout:** `/home/codex/.codex/sessions/2026/08/08/rollout-2026-08-08T18-43-35-019fe242-2c45-7e03-a428-eebfb968eda0.jsonl` +- **Worktree:** `/home/codex/repos/ns-rfc-command-kit` +- **Branch:** `docs/rfc-command-composition-kit` @ `fac9e3390` (NO upstream by design). +- **Push rule:** explicit refspec only — `git push origin HEAD:refs/heads/docs/rfc-command-composition-kit`. +- **Requested route:** provider=openai · model=gpt-5.6-sol · effort=xhigh +- **Observed route:** provider=openai · model=gpt-5.6-sol · effort=xhigh +- **Route verdict:** matched +- **Runtime:** approval=never · sandbox=dangerFullAccess +- **Brief (staged):** `/home/codex/rfc-command-kit-brief.md` +## Steering (same thread — never a second send-message-v2 at this worktree) +```bash +codex exec resume 019fe242-2c45-7e03-a428-eebfb968eda0 -- "" +``` +_Written by `.llm/tools/agentic/codex/launch-codex-slice.ts`._ \ No newline at end of file diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md new file mode 100644 index 0000000000..ae72e8b7e9 --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md @@ -0,0 +1,75 @@ +# Context Pack: production command composition kit RFC + +## Run Metadata + +| Field | Value | +| --- | --- | +| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Branch | `docs/rfc-command-composition-kit` | +| Current phase | `research` | +| Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | +| Scope overlays | `SCOPE-docs`, `SCOPE-service` | + +## Current State + +The run is activated on the exact requested branch/base in the sole daemon-attached Codex thread. +All named skills and required RFC/harness/doctrine/evaluator authority have been read. Bootstrap +artifacts are ready for the initial commit/explicit-refspec push/draft PR. Detailed proposal and API +re-baselining is the next slice; no product code or RFC file has been created yet. + +## Completed + +- Verified `HEAD == merge-base(HEAD, origin/main) == fac9e339042c...` and branch name. +- Preserved the staged `implement.md` and `codex-thread-ids.md` receipts. +- Read the RFC process/template, all current doctrine chapters, Archetypes 1–6, docs/service + overlays, lane/doc-audit policy, gate matrix, plan gate, and PLAN/IMPL evaluator protocols. +- Confirmed live #1361–#1364 and PR #1347 exist; #1361 is open and ratification-only. + +## In Progress + +- B0 bootstrap commit, explicit-refspec push, draft PR, required labels, and opening phase comment. + +## Next Steps + +1. Complete B0 and reconcile the live PR surface. +2. Read/re-baseline the proposal against current packages/docs/tests and primary adapter docs. +3. Lock the plan and author the RFC in S2/S3. +4. Run docs/RFC gates, write `final-handoff.md`, and stop at `status:plan-eval` for root-led review. + +## Key Decisions + +| Decision | Source | Notes | +| --- | --- | --- | +| Docs-only RFC; no package/plugin changes. | brief, #1361 | Implementation is separate. | +| One-store atomicity is the maximum portable claim. | brief, doctrine A11–A13 | Cross-store and exactly-once claims refused. | +| Generator will not launch PLAN/IMPL evaluators. | brief | Root orchestrator owns Fable/Qwen sessions. | + +## Files Changed + +| Path | Status | Notes | +| --- | --- | --- | +| `.llm/runs/docs-rfc-command-composition-kit--rfc/` | new | Mandatory harness artifacts plus staged session receipts. | + +## Gates + +| Gate family | Current status | Evidence | +| --- | --- | --- | +| Static | bootstrap PASS; final pending | `worklog.md` gate table | +| Fitness | planned-surface audit pending | `plan.md` and `research.md` | +| Runtime | N/A for docs PR | no product mutation | +| Consumer | analysis pending | S1 re-baseline | + +## Open Questions + +- Public owner/subpath, receipt schema and canonicalization, adapter truth, typed failures, + isolation, telemetry/redaction, and relay/saga boundary remain to be locked. + +## Drift and Debt + +- Drift: runtime controller identity correlation failed read-only; recorded in `drift.md`. +- Debt: no new or deepened architecture debt; existing package verdicts constrain the RFC. + +## Commits + +- See the draft PR's commit list + per-slice PR comments (V3 retired `commits.md`). + diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md new file mode 100644 index 0000000000..ee825ec22a --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md @@ -0,0 +1,24 @@ +# Drift Log: production command composition kit RFC + +Drift is append-only. Record facts that diverge from the carried proposal, plan, doctrine, or +current-state documentation. + +## 2026-08-08 — Runtime identity correlation unavailable + +- **What:** The desired-state runtime controller could not match this worktree to a persisted runtime identity. +- **Source:** `deno task agentic:runtime status --worktree /home/codex/repos/ns-rfc-command-kit`. +- **Expected:** A read-only session snapshot associated with the pre-staged Codex thread. +- **Actual:** Exit 3, `MISSING_IDENTITY`, zero sessions, `changed: no`. +- **Severity:** minor. +- **Action:** accept for this run; preserve the checked-in thread receipt and do not repair/restart an active daemon-attached session. +- **Evidence:** `codex-thread-ids.md`; `supervisor.md`. + +## 2026-08-08 — Owner-controlled evaluator routing + +- **What:** Formal review/evaluation is reserved for existing external sessions steered by the root orchestrator. +- **Source:** Owner implementation brief. +- **Expected:** Harness default would route a selected formal PLAN/IMPL evaluation via its canonical separate-session lanes. +- **Actual:** This generator must prepare inputs, stop at `status:plan-eval`, and must not trigger PLAN-EVAL/IMPL-EVAL itself; root will steer Fable cross-RFC review and a final Qwen adversarial pass. +- **Severity:** significant. +- **Action:** accept as explicit owner override; do not self-certify and do not launch a rival session. +- **Evidence:** `implement.md`; `supervisor.md`. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/implement.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/implement.md new file mode 100644 index 0000000000..e7ba9aff19 --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/implement.md @@ -0,0 +1,75 @@ +use harness + +# RFC-B implementation brief — production command composition kit + +You are the sole generator for a production-grade NetScript RFC. Work autonomously in +`/home/codex/repos/ns-rfc-command-kit` on branch `docs/rfc-command-composition-kit`, based on +`origin/main` at `fac9e339042c`. You are Codex GPT-5.6 Sol at xhigh reasoning, full-access/bypass +permissions. Do not create a rival session or delegate the core RFC authorship. + +## SKILL + +- `netscript-harness` — activate the full harness and RFC/docs design run; maintain every mandatory run artifact. +- `netscript-doctrine` — evaluate the cross-package command seam, runtime boundaries, extension axes, layering, anti-patterns, and debt. +- `netscript-pr` — open and maintain a draft RFC PR to `main`, with correct labels, phase comments, and no premature merge/closure. +- `netscript-tools` — use repo-native validation and compact evidence tooling. +- `netscript-deno-toolchain` — inspect current database/service/contracts/telemetry APIs through native Deno tools. +- `jsr-audit` — assess public export, subpath, slow-type, and publish-surface consequences. +- `netscript-cli` — analyze generated service/schema/worker surfaces and the proposed explicit generators without changing them. +- `rtk` — reduce read-heavy command output without changing semantics. +- `codex-wsl-remote` — preserve the daemon-attached, mobile-visible session and explicit-refspec push safety. + +## Objective + +Turn Claude Fable 5's RFC-B proposal into the actual lightweight RFC required by `rfcs/README.md`. +The input is a starting proposal, not ground truth: + +- proposal: `/home/codex/repos/netscript-fable5-remediation-plan/.llm/runs/plan-fable5-remediation-roadmap--seed/fable-5-remediation-plan/rfcs/RFC-B-command-composition-kit.md` +- tracking issue: `#1361` +- related filed issues: `#1362`–`#1364`, plus live dependencies named by the proposal +- source roadmap PR: `#1347` + +Re-baseline every claim against current `origin/main`, current docs, doctrine, exports, database +adapters, services SDK, contracts, telemetry, workers, sagas, tests, and live issue/PR state. +Determine the smallest honest public composition seam for one-store transactional commands. Prove +where atomicity ends, how optimistic concurrency and idempotent replay compose, how audit/outbox +records share the commit, and how the relay boundary joins workers/sagas without exactly-once +fiction. Resolve or explicitly frame store capabilities, receipt ownership/schema generation, +canonical request hashing, actor/correlation propagation, typed errors, isolation, failure +injection, telemetry cardinality/redaction, adapter portability, and the precise refusal boundary. +No billing-specific vocabulary and no speculative distributed transaction framework. + +## Required output + +1. Activate a new harness run at `.llm/runs/docs-rfc-command-composition-kit--rfc/` with + `supervisor.md`, `research.md`, `plan.md`, `worklog.md` (including `## Design`), + `context-pack.md`, `drift.md`, and a final handoff. Select `SCOPE-docs` plus every underlying + archetype required by the described service/database/contracts/telemetry/runtime surfaces; read + the RFC process, doctrine, gate matrix, plan gate, and evaluator protocol completely. +2. Produce `rfcs/0000-command-composition-kit.md` from `rfcs/0000-template.md`, keeping `0000` + until maintainer acceptance. It must include exact contracts and examples; semantic laws; + adapter capability matrix; transaction/idempotency/audit/outbox invariants; worker/saga boundary; + security/privacy; typed failure model; OTEL vocabulary; injected-failure conformance plan; + compatibility/migration; rejected alternatives; unresolved FCP questions; staged implementation; + docs/scaffold impacts; and issue/epic decomposition. +3. Challenge Claude's proposal against actual code and primary database/runtime documentation. + Use focused non-product probes when needed to validate adapter or type claims. Do not implement + product/framework code in this RFC PR. +4. Make an initial harness/bootstrap commit, push only with an explicit refspec, and open a draft PR + against `main` in the same session. Reference `#1361` without closing it; carry `rfc`, + `type:docs`, `area:service`, `area:database`, `priority:p1`, `ci:skip-e2e`, `ci:skip-scaffold`, + and exactly one lifecycle status. Move to `status:plan-eval` only when ready for Fable review. + Never assign an RFC number, merge, create/close issues, or mutate milestones. +5. Commit coherent slices with run-artifact updates and PR phase comments. Run applicable docs/RFC + gates and record exact evidence. Do not trigger PLAN-EVAL/IMPL-EVAL yourself: the root + orchestrator will steer the existing Claude Fable 5 session for cross-RFC review and then run the + final Qwen adversarial pass. +6. Finish with `final-handoff.md`: PR URL/number, HEAD SHA, run-dir, locked decisions, unresolved + questions, validation evidence, board reconciliation proposal, and exact Fable-review handoff. + Report back to the root orchestrator. + +Quality bar: the RFC must make the seam implementable without hiding store limitations, must reuse +existing NetScript primitives, and must preserve contract-first/type-safe/observable composition. +It is a narrow production command kit—not a billing framework, ORM, event-sourcing platform, or +distributed transaction claim. + diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md new file mode 100644 index 0000000000..b75d5ff21d --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md @@ -0,0 +1,141 @@ +# Plan: production command composition kit RFC + +## Run Metadata + +| Field | Value | +| --- | --- | +| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Branch | `docs/rfc-command-composition-kit` | +| Phase | `research` | +| Target | `rfcs/0000-command-composition-kit.md` plus harness evidence | +| Archetype | Documentation overlay describing Archetypes 1, 2, 3, 4, 5, and 6 implementation surfaces | +| Scope overlays | `SCOPE-docs`, `SCOPE-service` | + +## Archetype + +This PR changes docs only, so `SCOPE-docs` is the active delivery profile. The RFC nevertheless +specifies a future cross-package seam: Archetype 4 is the primary public DSL shape (`@netscript/service`), +Archetype 2 covers database/telemetry ports and adapters, Archetype 1 covers receipt/schema +contracts, Archetype 3 covers the outbox relay and worker/saga delivery boundary, Archetype 5 covers +thin plugin adoption, and Archetype 6 covers explicit scaffold generators. The final plan will map +each staged implementation issue to one owning archetype rather than treating one package as all six. + +## Current Doctrine Verdict + +- `@netscript/service` (Archetype 4): **Refactor** — presets/assets clarity. +- `@netscript/database` (Archetype 2): **Refactor** — ports naming and a single composition root. +- `@netscript/telemetry` (Archetype 2): **Refactor** — confirm port/adapter split and OTEL subpath. +- `@netscript/workers` (Archetype 3): **Restructure**; `@netscript/sagas` (Archetype 3): **Refactor**. +- `@netscript/contracts` (Archetype 4): **Keep** with export/folder review. +- `plugins/*` (Archetype 5) remain thin consumers; `@netscript/cli` (Archetype 6) is **Restructure**. + +## Axioms in Play + +| Axiom | Why it matters | +| --- | --- | +| A1–A3 | Public contracts and the guide example must precede implementation and keep the 80% path coherent. | +| A6–A7 | Canonical request hashing must use Web Crypto/Web Platform primitives, not a vague helper. | +| A9–A11 | Ownership, package archetype, composition root, and store/relay extension axes must be explicit. | +| A12–A13 | The relay handoff, at-least-once delivery, crash boundaries, and saga refusal line must be honest. | +| A14 | Adapter conformance, injected failures, docs, and public-surface checks are part of the design. | + +## Goal + +Publish an implementable, domain-neutral RFC for one-store command composition that commits business +state, replay receipt, audit record, and outbox messages in one supported transaction, while refusing +cross-store atomicity and exactly-once delivery claims. + +## Scope + +- Re-baseline the proposal against current code, exports, tests, live issues/PRs, and primary store/runtime docs. +- Lock exact TypeScript contracts, semantic laws, adapter capability claims, error and telemetry vocabulary. +- Specify conformance/failure-injection tests, compatibility, staged implementation, docs/scaffold impacts, and issue decomposition. +- Maintain a draft PR and complete harness evidence; leave evaluation to the root orchestrator. + +## Non-Scope + +- No framework, package, plugin, generated-project, schema, or workflow implementation. +- No billing-domain vocabulary, distributed transaction coordinator, event-sourcing platform, ORM, or exactly-once claim. +- No RFC number assignment, merge, issue creation/closure, or milestone mutation. + +## Hidden Scope + +- Receipt schema ownership and migrations; canonical byte-level request hashing; actor/correlation privacy. +- Isolation and retry interaction; typed errors; OTEL cardinality/redaction; adapter refusal semantics. +- Relay lease/ack/retry behavior and the exact transition from local command to saga. + +## Locked Decisions + +| ID | Decision | Rationale | +| --- | --- | --- | +| L0 | This PR is a ratification document only and changes no product code. | Issue #1361 and the owner brief make implementation a separate later issue. | +| L1 | The claim ceiling is one transaction on one store; cross-store atomicity is refused. | Prevents distributed-transaction and exactly-once fiction. | +| L2 | Business state, receipt, audit, and outbox rows are atomic only when one adapter transaction can write all four. | The public seam must expose capability rather than simulate missing guarantees. | + +## Open-Decision Sweep + +| Decision | Status | Notes | +| --- | --- | --- | +| Public package/subpath home and exact API shape | must resolve now | Re-baseline package dependencies and exports first. | +| Receipt ownership/schema generation and canonical hash bytes | must resolve now | Deferral would force adapter and migration rework. | +| Capabilities, isolation, typed failures, telemetry vocabulary | must resolve now | These define conformance and caller behavior. | +| FCP policy choices that do not invalidate the contract core | safe to defer | Must be listed explicitly in the final RFC. | + +## Risk Register + +| Risk | Mitigation | +| --- | --- | +| Proposal overstates current APIs or adapter guarantees. | Verify each claim against `origin/main`, `deno doc`, focused tests, and primary adapter docs. | +| A convenient API hides transaction-client coupling or two-store impossibility. | Publish capabilities and refusal errors; include negative conformance cases. | +| Receipt/hash or OTEL design leaks sensitive/high-cardinality data. | Define canonicalization, keyed identities, redaction, and allowed attribute values explicitly. | +| RFC grows into a workflow/ORM framework. | Keep handler effects inside one transaction and hand durable multi-step work to outbox + workers/sagas. | + +## Anti-Patterns to Resolve or Avoid + +| AP | Status | Plan | +| --- | --- | --- | +| AP-3 | risk | Keep the unit-of-work port capability-scoped, not a backend god interface. | +| AP-8/AP-9 | risk | No DI container or speculative distributed abstraction. | +| AP-11/AP-12 | risk | Require injected transaction/store/clock/telemetry dependencies and no hidden globals. | +| AP-14 | risk | Do not re-export Prisma, KV, OTEL, or hashing libraries. | +| AP-19 | risk | Specify permissions and data handling for adapters/relay. | +| AP-24 | risk | Adapter selection is a typed registry/composition decision, not command-internal switching. | + +## Fitness Gates + +| Gate | Required | Expected evidence | +| --- | --- | --- | +| SCOPE-docs source alignment, scope separation, links, terminology | yes | Changed-file audit plus repo-native docs/link checks. | +| F-5 public-surface/JSR design audit | design-time | `deno doc` and export-map evidence for every proposed owner. | +| F-6/F-7 publish consequences | design-time | JSR audit recorded; no package mutation in this PR. | +| F-13 runtime invariants | design-time | Relay/saga laws and injected-failure conformance plan. | +| CLI/scaffold consumer gate | design-time | Current generator analysis; implementation gate deferred to #1363. | + +## Arch-Debt Implications + +| Entry | Action | Notes | +| --- | --- | --- | +| Existing package verdict/debt entries | none in RFC PR | Cite constraints; do not deepen or close package debt without code. | + +## Validation Plan + +| Order | Gate | Command or check | Expected result | +| --- | --- | --- | --- | +| 1 | RFC structure/source alignment | Manual template/RFC-process audit plus focused `rg` checks | Required sections, no billing vocabulary, no product changes. | +| 2 | Local links | `deno task docs:links` when applicable plus direct path checks | Exit 0 / every referenced local path exists. | +| 3 | Markdown format | Repo-native formatting check scoped to owned Markdown | Exit 0. | +| 4 | API accuracy | `deno doc`/`--filter` on affected public entrypoints | Signatures match RFC rationale. | +| 5 | Diff/lock hygiene | Raw git status/diff against pinned base | Docs/run artifacts only; no lock churn. | + +## Dependencies + +- Tracking RFC issue #1361; implementation issue #1363; service-layout issue #1362; related issue #1364. +- Typed-error repair and any live issues discovered during re-baseline. +- Primary documentation for every database adapter whose guarantees appear in the capability matrix. + +## Drift Watch + +- Proposal claims invalidated by current code, exports, live board state, or primary adapter docs. +- Package ownership or dependency cycles that force a narrower public home. +- Any capability that cannot be proven uniformly and must become adapter-specific or refused. + diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md new file mode 100644 index 0000000000..1b3721e255 --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md @@ -0,0 +1,39 @@ +# Research — docs-rfc-command-composition-kit--rfc + +## Re-baseline + +- Carried-in source: + `/home/codex/repos/netscript-fable5-remediation-plan/.llm/runs/plan-fable5-remediation-roadmap--seed/fable-5-remediation-plan/rfcs/RFC-B-command-composition-kit.md` +- Re-derived against `origin/main` at `fac9e339042c5394bf882311657d8981d353a1c3` on 2026-08-08. +- Bootstrap status: RFC process, all current doctrine chapters, selected archetype profiles, + `SCOPE-docs`, `SCOPE-service`, gate matrix, plan gate, and evaluator protocols have been read. + Proposal/code/API/adapter claim verification is in progress. + +## Findings + +| # | Finding | How to verify | +| - | --- | --- | +| 1 | The requested branch, HEAD, and merge-base exactly match the pinned baseline; only the staged run brief/thread receipt were initially untracked. | Raw `git rev-parse HEAD`, `git merge-base HEAD origin/main`, and `git status --short --branch` on 2026-08-08. | +| 2 | Tracking issue #1361 is open and explicitly scopes this PR to ratification with no `packages/` or `plugins/` implementation. | Live GitHub issue #1361, fetched 2026-08-08. | +| 3 | The final RFC must keep public-package targets separate: contracts and command DSL are Archetypes 1/4; database and telemetry adapters are Archetype 2; relay/runtime behavior is Archetype 3; plugin consumers are Archetype 5; explicit generators are Archetype 6. | Doctrine chapter 06 and `.llm/harness/archetypes/ARCHETYPE-{1..6}*.md`. | + +## jsr-audit surface scan (planned public surface) + +- Surface to scan: the current export maps and `deno doc` surfaces for `@netscript/database`, + `@netscript/service`, `@netscript/contracts`, `@netscript/telemetry`, workers/sagas core packages, + and the future public home proposed by the RFC. +- Risks to resolve in the RFC: export-home ambiguity, accidental root-surface growth, subpath and + package-cycle consequences, explicit return types under `isolatedDeclarations`, and inherited + oRPC slow-type carve-outs. +- No product package changes are permitted in this RFC PR; JSR findings constrain staged + implementation issues rather than changing exports here. + +## Open questions + +- Which existing package owns the narrow command API without creating a cross-package cycle? +- Which current adapters can truthfully supply a single-store transaction plus same-commit receipt, + audit, and outbox writes? +- What exact receipt, request-hash, actor/correlation, error, isolation, and telemetry contracts can + be frozen in the RFC without hiding adapter limitations? +- Which decisions remain legitimate FCP questions, and which must be locked before review? + diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/supervisor.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/supervisor.md new file mode 100644 index 0000000000..d54a5e36f2 --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/supervisor.md @@ -0,0 +1,38 @@ +# Supervisor Identity — docs-rfc-command-composition-kit--rfc + +Written at run start per `workflow/lane-policy.md` § Supervisor identity. This is a single-generator +RFC/docs design run; no implementation sub-agents or rival worktree sessions are authorized. + +| Field | Value | +| --- | --- | +| Model | OpenAI GPT-5.6 Sol (`gpt-5.6-sol`), xhigh reasoning | +| Session | Codex thread `019fe242-2c45-7e03-a428-eebfb968eda0` | +| Host | Linux / WSL user `codex`; danger-full-access; approval policy `never` | +| Checkout | `/home/codex/repos/ns-rfc-command-kit` | +| Worktree | `/home/codex/repos/ns-rfc-command-kit` (native WSL filesystem) | +| Branch | `docs/rfc-command-composition-kit` (no upstream by design) | +| Baseline | `origin/main` at `fac9e339042c5394bf882311657d8981d353a1c3` on 2026-08-08 | +| Run ID | `docs-rfc-command-composition-kit--rfc` | + +## Routes in force + +| Task lane | Provider / model / effort | Role in this run | +| --- | --- | --- | +| RFC generator (owner override of complex implementation lane) | OpenAI / GPT-5.6 Sol / xhigh | Sole researcher and RFC author | +| Cross-RFC review | Existing Claude Fable 5 session, steered by root orchestrator | Pending; generator must not launch it | +| Final adversarial evaluation | Qwen session selected and launched by root orchestrator | Pending; generator must not launch it | + +Reference `.llm/harness/workflow/lane-policy.md`; evaluator-session separation remains mandatory. + +## Recorded lane/eval overrides + +- Owner brief pins this generator to GPT-5.6 Sol at xhigh, above the canonical complex-implementation + lane's usual high effort. The observed route matches the requested route; see + `codex-thread-ids.md`. +- Owner brief reserves PLAN-EVAL / cross-RFC review and the final adversarial pass for the root + orchestrator. This generator will prepare complete evaluator inputs and stop at + `status:plan-eval`; it will not self-evaluate or launch a rival session. +- `deno task agentic:runtime status --worktree /home/codex/repos/ns-rfc-command-kit` exited 3 with + `MISSING_IDENTITY` and made no change. The pre-staged thread receipt is the session identity; + daemon repair is neither necessary nor authorized while this attached turn is active. + diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md new file mode 100644 index 0000000000..3eda0a7eee --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md @@ -0,0 +1,120 @@ +# Worklog: production command composition kit RFC + +## Run Metadata + +| Field | Value | +| --- | --- | +| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Branch | `docs/rfc-command-composition-kit` | +| Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | +| Scope overlays | `SCOPE-docs`, `SCOPE-service` | + +## Design + +This checkpoint records the RFC/document surface before the RFC file is created. Exact product +types remain research inputs until the re-baseline slice locks them. + +### Public Surface + +- `rfcs/0000-command-composition-kit.md` — draft RFC only; no product export changes. +- Future public command entrypoint, unit-of-work capability contract, receipt/audit/outbox records, + typed failures, and command telemetry vocabulary — names and ownership must be locked in S1/S2. + +### Domain Vocabulary + +- command — one caller intent applied within one supported store transaction. +- receipt — durable idempotency outcome keyed by command identity and canonical request hash. +- audit record — same-commit actor/correlation evidence, not a mutable event log. +- outbox message — same-commit delivery intent relayed at least once after commit. +- capability/refusal — adapter truth describing which guarantees exist and why execution may refuse. + +### Ports + +- unit-of-work store capability — needed only where a database adapter can expose one transaction-scoped client. +- outbox relay store/transport — separate post-commit runtime seam; it cannot enlarge the transaction boundary. +- telemetry/redaction policy — injected observability seam with bounded attributes. + +### Constants + +- RFC status: `Draft`; RFC number: `0000` until maintainer acceptance. +- Claim vocabulary: `one-store`, `at-least-once`, `idempotent replay`, `same-commit`, `refused`. +- Lifecycle status progression for this run: `status:research` → `status:plan` → `status:plan-eval`. + +### Commit Slices + +| # | Slice | Gate | Files | +| - | --- | --- | --- | +| B0 | Activate the harness and expose the run on a draft PR. | raw git identity/status; artifact presence | `.llm/runs/docs-rfc-command-composition-kit--rfc/*` | +| S1 | Re-baseline proposal, code, exports, tests, docs, live board, and primary adapter guarantees; lock the plan. | evidence inventory; `deno doc`; plan-gate readiness check | run `research.md`, `plan.md`, `worklog.md`, `context-pack.md`, `drift.md` | +| S2 | Define the exact public contracts, semantic laws, capability matrix, failure/telemetry/security model, and examples. | source-alignment audit; focused probes | RFC plus run artifacts | +| S3 | Complete worker/saga boundary, conformance/failure injection, compatibility, staging, docs/scaffold impact, issue decomposition, and handoff. | docs/RFC/link/format/diff gates | RFC, run artifacts, `final-handoff.md` | + +### Deferred Scope + +- Product/package/plugin implementation — belongs to #1363 and follow-on implementation slices. +- Cross-store coordination and distributed transactions — explicitly refused. +- Relay deployment/operations — specified only as the narrow boundary necessary to consume outbox rows. +- Formal cross-RFC review and final adversarial evaluation — launched by the root orchestrator, not this generator. + +### Contributor Path + +Start at the RFC's semantic laws and capability matrix; implement contract-first in the staged issue +order, then add each adapter only after its injected-failure conformance suite proves the advertised +capabilities. + +## Progress Log + +| Time | Slice | Step | Notes | +| --- | --- | --- | --- | +| 2026-08-08 | B0 | bootstrap | Read all named skills and required RFC/harness/doctrine/evaluator authority; verified pinned branch/base. | +| 2026-08-08 | B0 | session health | Agentic runtime status made no changes and returned `MISSING_IDENTITY`; preserved the staged attached-thread receipt. | +| 2026-08-08 | B0 | live issue check | Confirmed #1361–#1364 and source PR #1347 exist; detailed re-baseline continues in S1. | + +## Decisions + +| Decision | Reason | Source | +| --- | --- | --- | +| Keep this PR docs-only and RFC number `0000`. | RFC lifecycle and issue #1361 scope. | `rfcs/README.md`, #1361 | +| Use all Archetypes 1–6 as implementation-surface constraints, with docs/service overlays for this run. | The design crosses contracts, adapters, DSL, runtime, plugins, and CLI generators but this PR changes none of them. | Doctrine chapter 06; harness archetypes | +| Do not launch evaluators or a second Codex session. | Owner reserves review/evaluation for the root orchestrator; mobile-visible thread must remain singular. | implementation brief; `codex-wsl-remote` | + +## Drift + +| Drift | Severity | Logged in drift.md | +| --- | --- | --- | +| Runtime controller could not correlate the active staged thread to persisted runtime identity. | minor | yes | + +## Gate Results + +### Static Gates + +| Gate | Command or check | Result | Notes | +| --- | --- | --- | --- | +| Branch/base identity | raw git `rev-parse`, `merge-base`, `status` | PASS | Branch and base exactly match the brief. | +| Mandatory authority read | complete file reads | PASS | RFC process, doctrine, gate/evaluator files and selected profiles read before RFC authoring. | +| Docs/link/format gates | pending S3 | NOT_RUN | No RFC file exists yet. | + +### Fitness Gates + +| Gate | Result | Evidence | Notes | +| --- | --- | --- | --- | +| F-5/F-6/F-7 planned surface audit | PENDING_SCRIPT | S1 `deno doc` and JSR/export scan | Design-time only; no package edits. | +| F-13 runtime invariants | PENDING_SCRIPT | S2/S3 RFC laws and conformance plan | Design-time only. | + +### Runtime Gates + +| Gate | Result | Evidence | Notes | +| --- | --- | --- | --- | +| Product runtime | N/A | RFC/docs-only scope | No product behavior changes. | + +### Consumer Gates + +| Consumer | Result | Evidence | Notes | +| --- | --- | --- | --- | +| Existing service/scaffold surfaces | NOT_RUN | S1 source analysis pending | Analysis only; no scaffold generation mutation. | + +## Handoff Notes + +- Root orchestrator should inspect the final RFC contracts and capability matrix first, then compare + every unresolved question with #1361 acceptance and the final `research.md` evidence table. + From e0b98f2897d8bcc2575a28198d8980e78a7d2a29 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 19:06:44 +0200 Subject: [PATCH 02/10] docs(harness): lock command kit RFC plan --- .../codex-thread-ids.md | 12 +- .../context-pack.md | 69 ++-- .../drift.md | 58 +++- .../implement.md | 36 +- .../plan.md | 321 +++++++++++------- .../research.md | 146 ++++++-- .../supervisor.md | 35 +- .../worklog.md | 121 ++++--- 8 files changed, 514 insertions(+), 284 deletions(-) diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md index 088031cda9..66b7e65684 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md @@ -1,16 +1,22 @@ # rfc-command-kit — Codex implementation thread + - **Thread / session id:** `019fe242-2c45-7e03-a428-eebfb968eda0` -- **Rollout:** `/home/codex/.codex/sessions/2026/08/08/rollout-2026-08-08T18-43-35-019fe242-2c45-7e03-a428-eebfb968eda0.jsonl` +- **Rollout:** + `/home/codex/.codex/sessions/2026/08/08/rollout-2026-08-08T18-43-35-019fe242-2c45-7e03-a428-eebfb968eda0.jsonl` - **Worktree:** `/home/codex/repos/ns-rfc-command-kit` - **Branch:** `docs/rfc-command-composition-kit` @ `fac9e3390` (NO upstream by design). -- **Push rule:** explicit refspec only — `git push origin HEAD:refs/heads/docs/rfc-command-composition-kit`. +- **Push rule:** explicit refspec only — + `git push origin HEAD:refs/heads/docs/rfc-command-composition-kit`. - **Requested route:** provider=openai · model=gpt-5.6-sol · effort=xhigh - **Observed route:** provider=openai · model=gpt-5.6-sol · effort=xhigh - **Route verdict:** matched - **Runtime:** approval=never · sandbox=dangerFullAccess - **Brief (staged):** `/home/codex/rfc-command-kit-brief.md` + ## Steering (same thread — never a second send-message-v2 at this worktree) + ```bash codex exec resume 019fe242-2c45-7e03-a428-eebfb968eda0 -- "" ``` -_Written by `.llm/tools/agentic/codex/launch-codex-slice.ts`._ \ No newline at end of file + +_Written by `.llm/tools/agentic/codex/launch-codex-slice.ts`._ diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md index ae72e8b7e9..53c3bf959a 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md @@ -2,20 +2,20 @@ ## Run Metadata -| Field | Value | -| --- | --- | -| Run ID | `docs-rfc-command-composition-kit--rfc` | -| Branch | `docs/rfc-command-composition-kit` | -| Current phase | `research` | -| Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | -| Scope overlays | `SCOPE-docs`, `SCOPE-service` | +| Field | Value | +| -------------- | --------------------------------------------------------------- | +| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Branch | `docs/rfc-command-composition-kit` | +| Current phase | `plan` | +| Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | +| Scope overlays | `SCOPE-docs`, `SCOPE-service` | ## Current State The run is activated on the exact requested branch/base in the sole daemon-attached Codex thread. -All named skills and required RFC/harness/doctrine/evaluator authority have been read. Bootstrap -artifacts are ready for the initial commit/explicit-refspec push/draft PR. Detailed proposal and API -re-baselining is the next slice; no product code or RFC file has been created yet. +Bootstrap commit `ad643e15...` is pushed by explicit refspec and draft PR #1389 is live. The full +proposal/API/store/runtime/CLI/board re-baseline and plan gate are complete; no product code or RFC +file has been created. S2 now authors the locked contract and semantic laws. ## Completed @@ -24,45 +24,53 @@ re-baselining is the next slice; no product code or RFC file has been created ye - Read the RFC process/template, all current doctrine chapters, Archetypes 1–6, docs/service overlays, lane/doc-audit policy, gate matrix, plan gate, and PLAN/IMPL evaluator protocols. - Confirmed live #1361–#1364 and PR #1347 exist; #1361 is open and ratification-only. +- Opened draft PR #1389 with required labels, `status:research`, and research phase comment. +- Proved the transaction callback typing defect and typed-error defect with removed focused probes. +- Locked future package ownership, logical row ownership, JCS hashing/codec contract, adapter + refusal rules, worker/saga boundary, telemetry redaction, and implementation decomposition. ## In Progress -- B0 bootstrap commit, explicit-refspec push, draft PR, required labels, and opening phase comment. +- S1 coherent research/plan commit, explicit-refspec push, plan phase comment, and status + transition. ## Next Steps -1. Complete B0 and reconcile the live PR surface. -2. Read/re-baseline the proposal against current packages/docs/tests and primary adapter docs. -3. Lock the plan and author the RFC in S2/S3. +1. Commit/push S1 and move the PR from `status:research` to `status:plan`. +2. Author exact contracts, rows, examples, laws, matrix, failure/security/telemetry model in S2. +3. Complete relay/conformance/migration/staging/docs/board sections in S3. 4. Run docs/RFC gates, write `final-handoff.md`, and stop at `status:plan-eval` for root-led review. ## Key Decisions -| Decision | Source | Notes | -| --- | --- | --- | -| Docs-only RFC; no package/plugin changes. | brief, #1361 | Implementation is separate. | -| One-store atomicity is the maximum portable claim. | brief, doctrine A11–A13 | Cross-store and exactly-once claims refused. | -| Generator will not launch PLAN/IMPL evaluators. | brief | Root orchestrator owns Fable/Qwen sessions. | +| Decision | Source | Notes | +| ------------------------------------------------------ | ------------------------------ | ------------------------------------------------------------------------------ | +| Docs-only RFC; no package/plugin changes. | brief, #1361 | Implementation is separate. | +| One-store atomicity is the maximum portable claim. | brief, doctrine A11–A13 | Cross-store and exactly-once claims refused. | +| Generator will not launch PLAN/IMPL evaluators. | brief | Root orchestrator owns Fable/Qwen sessions. | +| No weak command store; KV is refused in v1. | Deno KV/runtime research | Same-commit truth is encoded by conformance, not a boolean callers can ignore. | +| Service/database/contracts/telemetry focused subpaths. | doctrine + dependency analysis | No new package or root export growth; avoids package cycle. | +| Consumer-owned generated schemas with JCS codecs. | JSR/Prisma/provider analysis | No hidden migrations or provider-JSON fiction. | ## Files Changed -| Path | Status | Notes | -| --- | --- | --- | -| `.llm/runs/docs-rfc-command-composition-kit--rfc/` | new | Mandatory harness artifacts plus staged session receipts. | +| Path | Status | Notes | +| -------------------------------------------------- | ------ | --------------------------------------------------------- | +| `.llm/runs/docs-rfc-command-composition-kit--rfc/` | new | Mandatory harness artifacts plus staged session receipts. | ## Gates -| Gate family | Current status | Evidence | -| --- | --- | --- | -| Static | bootstrap PASS; final pending | `worklog.md` gate table | -| Fitness | planned-surface audit pending | `plan.md` and `research.md` | -| Runtime | N/A for docs PR | no product mutation | -| Consumer | analysis pending | S1 re-baseline | +| Gate family | Current status | Evidence | +| ----------- | ------------------------------------------------------------ | --------------------------- | +| Static | bootstrap/API probes PASS as classified; final pending | `worklog.md` gate table | +| Fitness | planned-surface and runtime-law design PASS | `plan.md` and `research.md` | +| Runtime | N/A for docs PR | no product mutation | +| Consumer | current CLI/scaffold analysis PASS; generated proof deferred | S1 re-baseline | ## Open Questions -- Public owner/subpath, receipt schema and canonicalization, adapter truth, typed failures, - isolation, telemetry/redaction, and relay/saga boundary remain to be locked. +- FCP policy only: idempotency required-by-default opt-out, SQLite release timing, correlation ID + telemetry opt-in, and retention defaults. These do not block the RFC core. ## Drift and Debt @@ -72,4 +80,3 @@ re-baselining is the next slice; no product code or RFC file has been created ye ## Commits - See the draft PR's commit list + per-slice PR comments (V3 retired `commits.md`). - diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md index ee825ec22a..83c771111c 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md @@ -5,20 +5,66 @@ current-state documentation. ## 2026-08-08 — Runtime identity correlation unavailable -- **What:** The desired-state runtime controller could not match this worktree to a persisted runtime identity. +- **What:** The desired-state runtime controller could not match this worktree to a persisted + runtime identity. - **Source:** `deno task agentic:runtime status --worktree /home/codex/repos/ns-rfc-command-kit`. - **Expected:** A read-only session snapshot associated with the pre-staged Codex thread. - **Actual:** Exit 3, `MISSING_IDENTITY`, zero sessions, `changed: no`. - **Severity:** minor. -- **Action:** accept for this run; preserve the checked-in thread receipt and do not repair/restart an active daemon-attached session. +- **Action:** accept for this run; preserve the checked-in thread receipt and do not repair/restart + an active daemon-attached session. - **Evidence:** `codex-thread-ids.md`; `supervisor.md`. ## 2026-08-08 — Owner-controlled evaluator routing -- **What:** Formal review/evaluation is reserved for existing external sessions steered by the root orchestrator. +- **What:** Formal review/evaluation is reserved for existing external sessions steered by the root + orchestrator. - **Source:** Owner implementation brief. -- **Expected:** Harness default would route a selected formal PLAN/IMPL evaluation via its canonical separate-session lanes. -- **Actual:** This generator must prepare inputs, stop at `status:plan-eval`, and must not trigger PLAN-EVAL/IMPL-EVAL itself; root will steer Fable cross-RFC review and a final Qwen adversarial pass. +- **Expected:** Harness default would route a selected formal PLAN/IMPL evaluation via its canonical + separate-session lanes. +- **Actual:** This generator must prepare inputs, stop at `status:plan-eval`, and must not trigger + PLAN-EVAL/IMPL-EVAL itself; root will steer Fable cross-RFC review and a final Qwen adversarial + pass. - **Severity:** significant. -- **Action:** accept as explicit owner override; do not self-certify and do not launch a rival session. +- **Action:** accept as explicit owner override; do not self-certify and do not launch a rival + session. - **Evidence:** `implement.md`; `supervisor.md`. + +## 2026-08-08 — Proposal outbox inventory is stale + +- **What:** The proposal says the repository has no outbox primitive. +- **Source:** Carried RFC-B §1.1 and §3.5. +- **Expected:** No `outbox` match in packages/plugins. +- **Actual:** `packages/plugin-sagas-core/src/ports/saga-outbox-port.ts` publicly defines a reserved + T2 `SagaOutboxPort`; it has no adapter/caller and cannot join a command transaction. +- **Severity:** significant. +- **Action:** cite it as narrow prior art, do not reuse it as atomicity proof, and define a + command-specific transaction-bound row/store contract. +- **Evidence:** `research.md` R9 and proposal-adjudication table. + +## 2026-08-08 — Proposal overstates current adapter/helper portability + +- **What:** The proposal treats `withTransaction` as reusable verbatim, SQLite as a current adapter, + `maxIsolation` as a truthful scalar, and #1293 as a MySQL command blocker. +- **Source:** Carried RFC-B §§3.1, 4, and 6. +- **Expected:** A sound transaction-client callback and current exported adapters for the full + matrix. +- **Actual:** The helper asserts the full root client; focused check compiled invalid root-only + calls; no SQLite adapter subpath exists; isolation is a provider set/configuration; #1293 targets + another package's class/error hook while `@netscript/database/adapters/mysql` already exists. +- **Severity:** significant. +- **Action:** require a true `TTx`, exact supported-level sets, separate feasibility/current-support + columns, treat SQLite as unproven, and classify #1293 as adjacent. +- **Evidence:** `research.md` R2/R3/R12/R13; focused probe transcript in `worklog.md`. + +## 2026-08-08 — Proposal concurrency and telemetry APIs are unsafe as written + +- **What:** The proposal offers `expectVersion(current)` and emits raw scope/key/version attributes. +- **Source:** Carried RFC-B §§3.3 and 3.6. +- **Expected:** A race-free portable version check and safe command telemetry. +- **Actual:** Read-then-compare does not make the mutation conditional; raw identifiers and versions + are high-cardinality and may contain sensitive application data. +- **Severity:** significant. +- **Action:** make CAS repository-specific with a zero-row typed conflict, and restrict default + telemetry to stable names, enums, booleans, and counts. +- **Evidence:** Prisma OCC docs; OTel attribute requirement/convention guidance; `research.md`. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/implement.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/implement.md index e7ba9aff19..ddcbace37c 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/implement.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/implement.md @@ -9,22 +9,29 @@ permissions. Do not create a rival session or delegate the core RFC authorship. ## SKILL -- `netscript-harness` — activate the full harness and RFC/docs design run; maintain every mandatory run artifact. -- `netscript-doctrine` — evaluate the cross-package command seam, runtime boundaries, extension axes, layering, anti-patterns, and debt. -- `netscript-pr` — open and maintain a draft RFC PR to `main`, with correct labels, phase comments, and no premature merge/closure. +- `netscript-harness` — activate the full harness and RFC/docs design run; maintain every mandatory + run artifact. +- `netscript-doctrine` — evaluate the cross-package command seam, runtime boundaries, extension + axes, layering, anti-patterns, and debt. +- `netscript-pr` — open and maintain a draft RFC PR to `main`, with correct labels, phase comments, + and no premature merge/closure. - `netscript-tools` — use repo-native validation and compact evidence tooling. -- `netscript-deno-toolchain` — inspect current database/service/contracts/telemetry APIs through native Deno tools. +- `netscript-deno-toolchain` — inspect current database/service/contracts/telemetry APIs through + native Deno tools. - `jsr-audit` — assess public export, subpath, slow-type, and publish-surface consequences. -- `netscript-cli` — analyze generated service/schema/worker surfaces and the proposed explicit generators without changing them. +- `netscript-cli` — analyze generated service/schema/worker surfaces and the proposed explicit + generators without changing them. - `rtk` — reduce read-heavy command output without changing semantics. -- `codex-wsl-remote` — preserve the daemon-attached, mobile-visible session and explicit-refspec push safety. +- `codex-wsl-remote` — preserve the daemon-attached, mobile-visible session and explicit-refspec + push safety. ## Objective Turn Claude Fable 5's RFC-B proposal into the actual lightweight RFC required by `rfcs/README.md`. The input is a starting proposal, not ground truth: -- proposal: `/home/codex/repos/netscript-fable5-remediation-plan/.llm/runs/plan-fable5-remediation-roadmap--seed/fable-5-remediation-plan/rfcs/RFC-B-command-composition-kit.md` +- proposal: + `/home/codex/repos/netscript-fable5-remediation-plan/.llm/runs/plan-fable5-remediation-roadmap--seed/fable-5-remediation-plan/rfcs/RFC-B-command-composition-kit.md` - tracking issue: `#1361` - related filed issues: `#1362`–`#1364`, plus live dependencies named by the proposal - source roadmap PR: `#1347` @@ -46,14 +53,14 @@ No billing-specific vocabulary and no speculative distributed transaction framew `context-pack.md`, `drift.md`, and a final handoff. Select `SCOPE-docs` plus every underlying archetype required by the described service/database/contracts/telemetry/runtime surfaces; read the RFC process, doctrine, gate matrix, plan gate, and evaluator protocol completely. -2. Produce `rfcs/0000-command-composition-kit.md` from `rfcs/0000-template.md`, keeping `0000` - until maintainer acceptance. It must include exact contracts and examples; semantic laws; - adapter capability matrix; transaction/idempotency/audit/outbox invariants; worker/saga boundary; +2. Produce `rfcs/0000-command-composition-kit.md` from `rfcs/0000-template.md`, keeping `0000` until + maintainer acceptance. It must include exact contracts and examples; semantic laws; adapter + capability matrix; transaction/idempotency/audit/outbox invariants; worker/saga boundary; security/privacy; typed failure model; OTEL vocabulary; injected-failure conformance plan; compatibility/migration; rejected alternatives; unresolved FCP questions; staged implementation; docs/scaffold impacts; and issue/epic decomposition. -3. Challenge Claude's proposal against actual code and primary database/runtime documentation. - Use focused non-product probes when needed to validate adapter or type claims. Do not implement +3. Challenge Claude's proposal against actual code and primary database/runtime documentation. Use + focused non-product probes when needed to validate adapter or type claims. Do not implement product/framework code in this RFC PR. 4. Make an initial harness/bootstrap commit, push only with an explicit refspec, and open a draft PR against `main` in the same session. Reference `#1361` without closing it; carry `rfc`, @@ -69,7 +76,6 @@ No billing-specific vocabulary and no speculative distributed transaction framew Report back to the root orchestrator. Quality bar: the RFC must make the seam implementable without hiding store limitations, must reuse -existing NetScript primitives, and must preserve contract-first/type-safe/observable composition. -It is a narrow production command kit—not a billing framework, ORM, event-sourcing platform, or +existing NetScript primitives, and must preserve contract-first/type-safe/observable composition. It +is a narrow production command kit—not a billing framework, ORM, event-sourcing platform, or distributed transaction claim. - diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md index b75d5ff21d..9eb21448c3 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md @@ -2,140 +2,205 @@ ## Run Metadata -| Field | Value | -| --- | --- | -| Run ID | `docs-rfc-command-composition-kit--rfc` | -| Branch | `docs/rfc-command-composition-kit` | -| Phase | `research` | -| Target | `rfcs/0000-command-composition-kit.md` plus harness evidence | -| Archetype | Documentation overlay describing Archetypes 1, 2, 3, 4, 5, and 6 implementation surfaces | -| Scope overlays | `SCOPE-docs`, `SCOPE-service` | - -## Archetype - -This PR changes docs only, so `SCOPE-docs` is the active delivery profile. The RFC nevertheless -specifies a future cross-package seam: Archetype 4 is the primary public DSL shape (`@netscript/service`), -Archetype 2 covers database/telemetry ports and adapters, Archetype 1 covers receipt/schema -contracts, Archetype 3 covers the outbox relay and worker/saga delivery boundary, Archetype 5 covers -thin plugin adoption, and Archetype 6 covers explicit scaffold generators. The final plan will map -each staged implementation issue to one owning archetype rather than treating one package as all six. - -## Current Doctrine Verdict - -- `@netscript/service` (Archetype 4): **Refactor** — presets/assets clarity. -- `@netscript/database` (Archetype 2): **Refactor** — ports naming and a single composition root. -- `@netscript/telemetry` (Archetype 2): **Refactor** — confirm port/adapter split and OTEL subpath. -- `@netscript/workers` (Archetype 3): **Restructure**; `@netscript/sagas` (Archetype 3): **Refactor**. -- `@netscript/contracts` (Archetype 4): **Keep** with export/folder review. -- `plugins/*` (Archetype 5) remain thin consumers; `@netscript/cli` (Archetype 6) is **Restructure**. - -## Axioms in Play - -| Axiom | Why it matters | -| --- | --- | -| A1–A3 | Public contracts and the guide example must precede implementation and keep the 80% path coherent. | -| A6–A7 | Canonical request hashing must use Web Crypto/Web Platform primitives, not a vague helper. | -| A9–A11 | Ownership, package archetype, composition root, and store/relay extension axes must be explicit. | -| A12–A13 | The relay handoff, at-least-once delivery, crash boundaries, and saga refusal line must be honest. | -| A14 | Adapter conformance, injected failures, docs, and public-surface checks are part of the design. | +| Field | Value | +| ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | +| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Branch | `docs/rfc-command-composition-kit` | +| Phase | `plan` | +| Target | `rfcs/0000-command-composition-kit.md` plus harness evidence | +| Delivery profile | `SCOPE-docs` with `SCOPE-service` consumer analysis | +| Described implementation | A1 contracts, A2 database/telemetry adapters, A3 relay runtime, A4 service DSL, A5 thin plugin consumers, A6 CLI generators | ## Goal -Publish an implementable, domain-neutral RFC for one-store command composition that commits business -state, replay receipt, audit record, and outbox messages in one supported transaction, while refusing -cross-store atomicity and exactly-once delivery claims. +Author an implementable, domain-neutral RFC for a production command seam whose maximum guarantee is +one transaction on one store: business writes, optional replay receipt, audit rows, and outbox rows +commit together; delivery after commit is at least once; unsupported stores and remote effects are +refused rather than disguised. ## Scope -- Re-baseline the proposal against current code, exports, tests, live issues/PRs, and primary store/runtime docs. -- Lock exact TypeScript contracts, semantic laws, adapter capability claims, error and telemetry vocabulary. -- Specify conformance/failure-injection tests, compatibility, staged implementation, docs/scaffold impacts, and issue decomposition. -- Maintain a draft PR and complete harness evidence; leave evaluation to the root orchestrator. +- Re-baseline Claude's proposal against current exports, APIs, tests, generators, live issues, and + primary database/runtime specifications. +- Freeze exact TypeScript contracts, durable logical rows, canonical hash bytes, semantic laws, + capability/refusal behavior, typed failures, telemetry, security, and examples. +- Define provider feasibility versus current NetScript support, adapter conformance, injected + faults, migration/compatibility, rollout stages, docs/scaffold impact, and board decomposition. +- Maintain the draft RFC PR with evidence and stop at `status:plan-eval` for root-owned review. ## Non-Scope -- No framework, package, plugin, generated-project, schema, or workflow implementation. -- No billing-domain vocabulary, distributed transaction coordinator, event-sourcing platform, ORM, or exactly-once claim. -- No RFC number assignment, merge, issue creation/closure, or milestone mutation. - -## Hidden Scope - -- Receipt schema ownership and migrations; canonical byte-level request hashing; actor/correlation privacy. -- Isolation and retry interaction; typed errors; OTEL cardinality/redaction; adapter refusal semantics. -- Relay lease/ack/retry behavior and the exact transition from local command to saga. - -## Locked Decisions - -| ID | Decision | Rationale | -| --- | --- | --- | -| L0 | This PR is a ratification document only and changes no product code. | Issue #1361 and the owner brief make implementation a separate later issue. | -| L1 | The claim ceiling is one transaction on one store; cross-store atomicity is refused. | Prevents distributed-transaction and exactly-once fiction. | -| L2 | Business state, receipt, audit, and outbox rows are atomic only when one adapter transaction can write all four. | The public seam must expose capability rather than simulate missing guarantees. | - -## Open-Decision Sweep - -| Decision | Status | Notes | -| --- | --- | --- | -| Public package/subpath home and exact API shape | must resolve now | Re-baseline package dependencies and exports first. | -| Receipt ownership/schema generation and canonical hash bytes | must resolve now | Deferral would force adapter and migration rework. | -| Capabilities, isolation, typed failures, telemetry vocabulary | must resolve now | These define conformance and caller behavior. | -| FCP policy choices that do not invalidate the contract core | safe to defer | Must be listed explicitly in the final RFC. | - -## Risk Register - -| Risk | Mitigation | -| --- | --- | -| Proposal overstates current APIs or adapter guarantees. | Verify each claim against `origin/main`, `deno doc`, focused tests, and primary adapter docs. | -| A convenient API hides transaction-client coupling or two-store impossibility. | Publish capabilities and refusal errors; include negative conformance cases. | -| Receipt/hash or OTEL design leaks sensitive/high-cardinality data. | Define canonicalization, keyed identities, redaction, and allowed attribute values explicitly. | -| RFC grows into a workflow/ORM framework. | Keep handler effects inside one transaction and hand durable multi-step work to outbox + workers/sagas. | - -## Anti-Patterns to Resolve or Avoid - -| AP | Status | Plan | -| --- | --- | --- | -| AP-3 | risk | Keep the unit-of-work port capability-scoped, not a backend god interface. | -| AP-8/AP-9 | risk | No DI container or speculative distributed abstraction. | -| AP-11/AP-12 | risk | Require injected transaction/store/clock/telemetry dependencies and no hidden globals. | -| AP-14 | risk | Do not re-export Prisma, KV, OTEL, or hashing libraries. | -| AP-19 | risk | Specify permissions and data handling for adapters/relay. | -| AP-24 | risk | Adapter selection is a typed registry/composition decision, not command-internal switching. | - -## Fitness Gates - -| Gate | Required | Expected evidence | -| --- | --- | --- | -| SCOPE-docs source alignment, scope separation, links, terminology | yes | Changed-file audit plus repo-native docs/link checks. | -| F-5 public-surface/JSR design audit | design-time | `deno doc` and export-map evidence for every proposed owner. | -| F-6/F-7 publish consequences | design-time | JSR audit recorded; no package mutation in this PR. | -| F-13 runtime invariants | design-time | Relay/saga laws and injected-failure conformance plan. | -| CLI/scaffold consumer gate | design-time | Current generator analysis; implementation gate deferred to #1363. | - -## Arch-Debt Implications - -| Entry | Action | Notes | -| --- | --- | --- | -| Existing package verdict/debt entries | none in RFC PR | Cite constraints; do not deepen or close package debt without code. | - -## Validation Plan - -| Order | Gate | Command or check | Expected result | -| --- | --- | --- | --- | -| 1 | RFC structure/source alignment | Manual template/RFC-process audit plus focused `rg` checks | Required sections, no billing vocabulary, no product changes. | -| 2 | Local links | `deno task docs:links` when applicable plus direct path checks | Exit 0 / every referenced local path exists. | -| 3 | Markdown format | Repo-native formatting check scoped to owned Markdown | Exit 0. | -| 4 | API accuracy | `deno doc`/`--filter` on affected public entrypoints | Signatures match RFC rationale. | -| 5 | Diff/lock hygiene | Raw git status/diff against pinned base | Docs/run artifacts only; no lock churn. | - -## Dependencies - -- Tracking RFC issue #1361; implementation issue #1363; service-layout issue #1362; related issue #1364. -- Typed-error repair and any live issues discovered during re-baseline. -- Primary documentation for every database adapter whose guarantees appear in the capability matrix. - -## Drift Watch - -- Proposal claims invalidated by current code, exports, live board state, or primary adapter docs. -- Package ownership or dependency cycles that force a narrower public home. -- Any capability that cannot be proven uniformly and must become adapter-specific or refused. - +- No product, package, plugin, schema, generated-workspace, CI, or release implementation. +- No domain-specific vocabulary, ORM/repository framework, event-sourcing platform, two-phase + commit, distributed transaction, cross-store rollback, or exactly-once delivery claim. +- No RFC numbering, merge, issue creation/closure, milestone mutation, evaluator launch, or second + Codex/Claude session. + +## Doctrine and archetype mapping + +| Future slice | Owner/archetype | Doctrine consequence | +| ---------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------- | +| Command contract error fragment | `@netscript/contracts/commands`, A1 | Contract first; literal error keys; no global base-map growth. | +| Transaction-bound store and SQL adapters | `@netscript/database/commands`, A2 | Port has one purpose; capabilities/refusals are explicit; no generated Prisma type leak. | +| Command definition/executor | `@netscript/service/commands`, A4 | Public DSL is a subpath and one explicit composition root; no hidden global runtime. | +| Command telemetry | existing telemetry attributes subpath, A2 | Stable bounded vocabulary; privacy/high cardinality excluded by default. | +| Outbox relay | generated worker plus store/sink ports, A3 | Owned lifecycle, lease/ack/retry, cancellation, and at-least-once boundary. | +| Worker/saga/webhook consumers | thin A5 integrations | Reuse existing runtime primitives; no semantic forks in plugin wrappers. | +| Explicit schema/command/relay generators | CLI A6 | Generate discoverable consumer-owned files; never silently inject schema. | + +The docs PR itself uses `SCOPE-docs`; it does not pretend a documentation file is all six +archetypes. Each implementation child must activate only its owning profile plus needed overlays. + +## Axioms in play + +| Axiom | Application | +| ------- | ------------------------------------------------------------------------------------------------- | +| A1–A3 | Contract, guide example, and reference laws precede implementation. | +| A6–A7 | RFC 8785 + Web Crypto SHA-256 replace bespoke unstable hashing. | +| A9–A11 | Package ownership, composition root, and adapter extension axes are explicit. | +| A12–A13 | Abort/timeout/failure states and relay/saga crash boundaries are named. | +| A14 | Adapter conformance, injected failures, surface gates, and consumer proof are part of acceptance. | + +## Locked decisions + +| ID | Decision | Rationale | +| --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| L0 | This PR is ratification documentation only and keeps RFC number `0000`. | RFC process, brief, and #1361. | +| L1 | Atomicity ends at one transaction on one store. | Prevents distributed-transaction fiction. | +| L2 | A `CommandStorePort` is conformant only when business, receipt, audit, and outbox writes share that commit. There is no weak port mode. | Capability truth is simpler and safer than an optional guarantee callers can overlook. | +| L3 | Command semantics live at `@netscript/service/commands`; transaction persistence/adapters at `@netscript/database/commands`; opt-in errors at `@netscript/contracts/commands`; telemetry extends `@netscript/telemetry/attributes`. | One-way service → database dependency; no database/service cycle; no new package or root export growth. | +| L4 | Receipt/audit/outbox tables are consumer-owned logical schemas emitted by explicit provider-aware generators. | Published packages cannot own product migrations or user Prisma models. | +| L5 | The request fingerprint is SHA-256 of RFC-8785 JCS bytes for an exact I-JSON object containing command name/version, scope, application fingerprint, actor subject, and string expected version. | Stable replay comparison without hashing roles, claims, keys, or raw transport bytes. | +| L6 | Replay output requires an explicit codec to/from canonical JSON text. | `unknown`, Date, BigInt, class instances, and provider JSON differences cannot silently corrupt receipts. | +| L7 | Optimistic concurrency is a command repository CAS, not `expectVersion(current)` and not a generic store flag. | Only the repository knows the model/version predicate; read-then-compare races. | +| L8 | Transaction callbacks are never automatically retried by the command executor. | Hidden callback replay is unsafe for captured state and makes failure injection ambiguous; retry is caller-driven with the same idempotency key. | +| L9 | External I/O in the command callback is unsupported. Remote intent is a same-commit outbox row; the relay is at least once. | A network effect cannot roll back with SQL. | +| L10 | Deno KV is not a v1 `CommandStorePort`; SQLite is unclaimed until a NetScript adapter passes conformance. | KV is atomic-batch, not interactive; current repo has no SQLite adapter export. | +| L11 | Command errors are route-opt-in and depend on #1350 for client-visible type preservation. | Avoids widening every contract and shipping fictional type safety. | +| L12 | Default telemetry excludes raw scope, actor, idempotency key/hash, request hash, expected version, payload, and arbitrary correlation identifiers. | Cardinality, PII, and secret leakage. | +| L13 | Worker and saga idempotency remain separate consumer-side delivery concerns; an outbox message keeps a stable ID across relay attempts. | Commit-once does not imply deliver-once or effect-once. | + +## Exact design skeleton + +The RFC will specify, with compilable examples: + +1. `defineCommand(spec)` with stable `name`, positive `definitionVersion`, isolation requirement, + idempotency policy, input-fingerprint function, replay codec, audit policy, and async handler. +2. `createCommandExecutor({ store, telemetry, clock, ids, limits })` and + `execute(definition, envelope, { signal }) -> CommandExecution`. +3. A narrowed envelope: validated input, actor subject/scheme, bounded correlation id, validated W3C + trace context, optional high-entropy idempotency key, and optional string expected version. +4. A transaction-bound `CommandTransaction` exposing `business`, receipt claim/complete, audit + append, and outbox append; every async port operation accepts cancellation. +5. Synchronous handler recorders `audit(...)` and `publish(...)`, plus a typed `conflict()` helper; + buffers flush before receipt completion and commit. +6. Logical receipt/audit/outbox/relay-lease schemas and the exact unique keys/invariants. +7. An opt-in command contract error map plus the internal typed failure union and presentation map. +8. Command span/attribute constants with exact allowed values and redaction rules. + +## Semantic laws to encode + +- **Atomic commit:** any pre-commit failure leaves no business, receipt, audit, or outbox delta. +- **Receipt replay:** same receipt key + same request hash returns the first decoded value and emits + no new business/audit/outbox writes. +- **Key mismatch:** same receipt key + different request hash never executes and returns the typed + idempotency-reuse conflict. +- **Concurrent claim:** one claimant commits; followers replay after it commits, proceed after its + rollback, or receive a bounded retryable busy result. No incomplete receipt is normally visible. +- **CAS:** a zero-match conditional mutation produces an optimistic conflict and rolls back every + buffered side record. +- **No hidden retry:** a serialization/deadlock/busy failure aborts the attempt; executor never + invokes the handler again itself. +- **Stable delivery identity:** one committed outbox row retains its ID across lease expiry and + relay redelivery; publish-then-crash may duplicate delivery. +- **Boundary refusal:** absent same-commit support, unsupported isolation, cross-store state, or + external effects fail composition/execution before an overbroad guarantee can be claimed. + +## Capability and adapter plan + +The RFC matrix will have two independent columns: storage/Prisma feasibility and current NetScript +integration. It will not label a provider “supported” merely because its engine has transactions. + +| Target | Planned position | +| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| PostgreSQL + Prisma | Reference adapter; full semantics after conformance. | +| MySQL + Prisma | Feasible; current DB subpath exists; no `Snapshot`; conformance required. #1293 is adjacent, not blocking. | +| SQL Server + Prisma | Feasible; `Snapshot` only when enabled; response/side payloads use text rather than a portable `Json` assumption. | +| SQLite + Prisma | Engine feasible but current NetScript adapter absent; no support claim until added and busy/fault tests pass. | +| Deno KV | Explicit v1 refusal; existing worker idempotency stays separate. | +| SQL + KV/stream/HTTP, or two SQL stores | No atomic adapter; use outbox and saga/consumer compensation. | + +## Error and compatibility plan + +- Internal failures distinguish optimistic conflict, key reuse, in-flight/busy, unsupported + capability/isolation, codec/fingerprint failure, corrupt receipt, store failure, relay failure, + and caller cancellation. +- Contract-visible command errors are only the safe client actions: conflict, key reuse, and + retryable in-progress. Configuration/codec/store bugs map to existing service-unavailable/internal + handling without leaking payloads or driver details. +- Existing CRUD/service code is unchanged; adoption is opt-in. No breaking label is required for + this RFC. New exports require coordinated minor releases and surface-diff review. +- Public command handler/client ergonomics do not release until #1350 is fixed. Core implementation + may be developed behind non-exported code, but no half-typed public promise ships. + +## Risk register + +| Risk | Mitigation | +| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| Generic API leaks Prisma/generated types. | Package-owned structural port; generated bridge owns delegates; `deno doc` consumer review. | +| Receipt claim races or commits incomplete state. | Unique constraint, tx-bound claim/complete, injected faults at every boundary, corruption test. | +| Canonicalization accepts non-I-JSON values. | Explicit fingerprint/response codecs, JCS validation, negative Date/BigInt/non-finite-number tests. | +| Long transactions or hidden retries duplicate captured effects. | No remote I/O, timeout/AbortSignal, no automatic callback retry. | +| Telemetry leaks IDs or explodes cardinality. | Closed low-cardinality attributes, forbidden-field tests, optional redaction policy. | +| Relay is mistaken for exactly-once. | Stable IDs, lease/ack crash tests, explicit at-least-once wording, downstream dedupe guidance. | +| RFC grows into a workflow platform. | One callback/one store; multi-step or compensating work hands off to sagas. | + +## Anti-patterns + +| Pattern | Resolution | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| AP-3 god port | Separate command store, relay store, sink, telemetry; no backend switch inside executor. | +| AP-8/AP-9 framework machinery | No DI container, ORM, distributed coordinator, or speculative package. | +| AP-11/AP-12 hidden globals | Explicit executor composition root with injected store/clock/IDs/telemetry. | +| AP-14 upstream leakage | No Prisma/oRPC/OTel types in package-owned public contracts except existing `IsolationLevel` ownership in database. | +| AP-19 implicit permissions | Handler authorization precedes execution; relay/store permissions documented separately. | +| AP-24 switch dispatch | Provider adapters register at composition, not inside command execution. | + +## Implementation/board decomposition proposal + +No board mutation is authorized. The RFC will recommend retaining #1363 as the umbrella and carving +implementation into PR-sized children: typed contracts; service executor; reference PostgreSQL +store; telemetry; relay; MySQL/MSSQL adapters; optional SQLite adapter; CLI/schema/service +generator; and docs/consumer proof. #1362 owns generated service layering, #1364 owns the +outbound-webhook recipe, and #1350 is the typed-error prerequisite. #1293 remains adjacent and +should not be made a false blocker. + +## Fitness and validation gates + +| Gate | This RFC PR | Future implementation | +| ----------------------------------- | --------------------------------- | ---------------------------------------------------------------------------- | +| Docs source/scope/links/terminology | Required | Docs additions required per slice. | +| F-5/F-6/F-7 public surface/JSR | Design audit | Surface diff, full-entrypoint doc lint, dry run, published consumer proof. | +| Type/slow-type soundness | API spellings reviewed | Positive/negative type fixtures with isolated declarations. | +| Adapter conformance | Exact plan only | Real provider runs and named fault injection. | +| F-13 runtime semantics | Laws and relay boundary | Crash/restart/lease/cancellation tests. | +| CLI consumer | Current command/template analysis | `check:emitted-samples` and full `scaffold.runtime` once at merge readiness. | + +Final docs gates: scoped Markdown format check, `docs:links`, `docs:accuracy` where applicable, +focused term/path/source assertions, raw `git diff --check`, diff/lock hygiene, and PR +metadata/thread audit. Product E2E is intentionally skipped for this docs-only PR under its CI +labels. + +## Plan-gate readiness + +| Question | Answer | +| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| Is the problem and non-scope precise? | Yes; one-store command atomicity and explicit refusal boundary. | +| Are target contracts named before implementation? | Yes; four focused subpaths, executor/store/envelope/rows/errors/telemetry. | +| Are failure and cancellation semantics explicit? | Yes; no hidden retry, bounded busy, rollback, signal, relay lease. | +| Are extension axes and anti-patterns handled? | Yes; store/sink/provider adapters and generated bridges are separate. | +| Are consumers and gates identified? | Yes; services, contracts, DB adapters, telemetry, workers/sagas, CLI/scaffold. | +| Are open questions non-blocking to drafting? | Yes; idempotency default, SQLite release timing, correlation telemetry, retention durations are isolated FCP policy choices. | + +Plan gate is ready for RFC authoring. Formal PLAN-EVAL is deliberately not triggered by this +generator; the owner-directed Fable review occurs after the complete draft and handoff. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md index 1b3721e255..86b8cb6da5 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md @@ -2,38 +2,116 @@ ## Re-baseline -- Carried-in source: - `/home/codex/repos/netscript-fable5-remediation-plan/.llm/runs/plan-fable5-remediation-roadmap--seed/fable-5-remediation-plan/rfcs/RFC-B-command-composition-kit.md` -- Re-derived against `origin/main` at `fac9e339042c5394bf882311657d8981d353a1c3` on 2026-08-08. -- Bootstrap status: RFC process, all current doctrine chapters, selected archetype profiles, - `SCOPE-docs`, `SCOPE-service`, gate matrix, plan gate, and evaluator protocols have been read. - Proposal/code/API/adapter claim verification is in progress. - -## Findings - -| # | Finding | How to verify | -| - | --- | --- | -| 1 | The requested branch, HEAD, and merge-base exactly match the pinned baseline; only the staged run brief/thread receipt were initially untracked. | Raw `git rev-parse HEAD`, `git merge-base HEAD origin/main`, and `git status --short --branch` on 2026-08-08. | -| 2 | Tracking issue #1361 is open and explicitly scopes this PR to ratification with no `packages/` or `plugins/` implementation. | Live GitHub issue #1361, fetched 2026-08-08. | -| 3 | The final RFC must keep public-package targets separate: contracts and command DSL are Archetypes 1/4; database and telemetry adapters are Archetype 2; relay/runtime behavior is Archetype 3; plugin consumers are Archetype 5; explicit generators are Archetype 6. | Doctrine chapter 06 and `.llm/harness/archetypes/ARCHETYPE-{1..6}*.md`. | - -## jsr-audit surface scan (planned public surface) - -- Surface to scan: the current export maps and `deno doc` surfaces for `@netscript/database`, - `@netscript/service`, `@netscript/contracts`, `@netscript/telemetry`, workers/sagas core packages, - and the future public home proposed by the RFC. -- Risks to resolve in the RFC: export-home ambiguity, accidental root-surface growth, subpath and - package-cycle consequences, explicit return types under `isolatedDeclarations`, and inherited - oRPC slow-type carve-outs. -- No product package changes are permitted in this RFC PR; JSR findings constrain staged - implementation issues rather than changing exports here. - -## Open questions - -- Which existing package owns the narrow command API without creating a cross-package cycle? -- Which current adapters can truthfully supply a single-store transaction plus same-commit receipt, - audit, and outbox writes? -- What exact receipt, request-hash, actor/correlation, error, isolation, and telemetry contracts can - be frozen in the RFC without hiding adapter limitations? -- Which decisions remain legitimate FCP questions, and which must be locked before review? +- Carried proposal: + `/home/codex/repos/netscript-fable5-remediation-plan/.llm/runs/plan-fable5-remediation-roadmap--seed/fable-5-remediation-plan/rfcs/RFC-B-command-composition-kit.md`. +- Authority baseline: `origin/main` at `fac9e339042c5394bf882311657d8981d353a1c3`, re-derived on + 2026-08-08. +- Live board: RFC issue #1361 (`0.0.6`), implementation #1363 (`0.0.8`), generated-service layout + #1362 (`0.0.8`), outbound-webhook recipe #1364 (`0.0.8`), typed-error repair #1350 (`0.0.7`), and + source roadmap PR #1347. +- Required authority read in full: `rfcs/README.md`, RFC template, current doctrine chapters, + archetypes 1–6, `SCOPE-docs`, `SCOPE-service`, gate matrix, plan gate, run loop, doc-audit, lane + policy, and both evaluator protocols/verdict definitions. +## Baseline findings + +| # | Finding | Evidence | +| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| R1 | Branch, HEAD, and merge-base began exactly at the requested baseline. | Raw `git rev-parse HEAD` and `git merge-base HEAD origin/main` both returned `fac9e339...`; branch was `docs/rfc-command-composition-kit`. | +| R2 | `withTransaction` has no production caller and its callback is publicly typed as the full root client through an assertion, not Prisma's narrower transaction client. | `packages/database/mod.ts:128-139`; focused `deno check --unstable-kv packages/database/rfc-command-probe.ts` exited 0 while the callback called root-only and nested `$transaction` methods. Probe was removed after execution. | +| R3 | `TransactionOptions` is usable, but `maxIsolation` would be a false capability abstraction: supported isolation levels are a provider-specific set and SQL Server `Snapshot` additionally depends on database configuration. | `packages/database/ports/database-client.ts:59-77`; Prisma transaction matrix; SQL Server official isolation docs. | +| R4 | The service builder dynamically injects `db`, `traceHeaders`, and authenticated `principal` into an open record. The public `ServiceContext` is a Hono `Context`, not that oRPC record. | `packages/service/src/builder/service-builder-impl.ts:256-281`; `packages/service/src/types.ts:239-272`. | +| R5 | A command subpath does not exist. Current service exports are root, `./auth`, and `./rpc-path`; database has no `./commands`; contracts has no command error fragment; telemetry's command vocabulary is absent. | The four package `deno.json` export maps plus `deno doc` on the public entrypoints. | +| R6 | The proposal's global `CONFLICT` approach would widen every route and is blocked by a real type defect. `baseContract` erases the literal error map, and `safe()` loses the error generic. | `packages/contracts/src/application/contract-primitives.ts:21-81`; `packages/sdk/src/client/errors.ts:49-90`; #1350. Focused SDK probe failed with `TS2339: Property 'code' does not exist on type 'never'`. | +| R7 | oRPC's current contract builder can add a route-local error fragment with `.errors(...)`; a global common-map addition is unnecessary. | Native `deno doc --filter ContractProcedureBuilder npm:@orpc/contract@1.14.6` shows sparse-merged `errors(errors)` on the builder. | +| R8 | Worker idempotency is a delivery claim/apply/release lifecycle in KV. It is neither response replay nor enrollable in a relational business transaction. | `packages/plugin-workers-core/src/ports/worker-idempotency-port.ts`; `src/stores/kv-worker-idempotency-store.ts`. | +| R9 | The proposal's “no outbox” claim is stale: a public `SagaOutboxPort` exists. It is explicitly reserved for saga T2 durability, has no transaction-bound handle or `AbortSignal`, and has no implementation/caller, so it cannot be reused as proof of command atomicity. | `packages/plugin-sagas-core/src/ports/saga-outbox-port.ts` and focused reference search. | +| R10 | Current telemetry exports `SpanNames` and builders from `@netscript/telemetry/attributes`, not the root. There is no command span or builder. Existing saga helpers can emit raw idempotency/correlation values, which is precedent to improve, not copy. | `packages/telemetry/deno.json`; `src/attributes/spans.ts`, `helpers.ts`, `saga.ts`. | +| R11 | Current generated Prisma CRUD handlers call delegates directly; they do not use a transaction or application layer. Explicit CLI surfaces already exist for `contract add-route` and `service add-handler`, but there is no command/schema/relay generator. | `packages/cli/src/kernel/assets/service/routers/v1.ts.template`; executed CLI `contract --help`, `service --help`, `db --help`, and `generate --help`. | +| R12 | The MySQL claim in the proposal conflates packages. `@netscript/database/adapters/mysql` currently exports `MysqlAdapter`; #1293 concerns the lower-level `@netscript/prisma-adapter-mysql` class/error hook and is adjacent, not a command-transaction blocker. | `packages/database/deno.json`; `adapters/mysql.adapter.ts`; live #1293. | +| R13 | PostgreSQL, MySQL, SQL Server, and SQLite can support one-store transaction semantics in Prisma, but current NetScript only publishes Postgres, MSSQL, and MySQL adapter subpaths. SQLite is named in `DatabaseProvider` yet has no NetScript adapter export. | `packages/database/deno.json`; provider type; Prisma transaction matrix. | +| R14 | Deno KV is an optimistic atomic batch, not an interactive transaction. Its checks/mutations and operation-size limits cannot host an arbitrary Prisma-style command callback or enroll SQL rows. | Deno KV transaction and API documentation. | +| R15 | SQLite permits multiple readers but only one simultaneous writer. “Serializable” in a matrix does not imply the same contention, timeout, or interactive-callback behavior as the SQL client/server adapters. | SQLite transaction documentation; Prisma matrix. | +| R16 | Exactly-once delivery cannot be inferred from a committed outbox row. A relay may publish and crash before marking the row, so message identity must be stable and consumers remain idempotent. | Doctrine chapter 08; current worker/saga delivery code; queue boundary analysis. | +| R17 | Trace propagation already uses W3C `traceparent`/`tracestate` across service, workers, and sagas. OTel producer/consumer spans or links can join deferred delivery without storing arbitrary trace attributes. | Service builder, worker dispatcher, saga delivery; W3C Trace Context and OTel tracing API. | +| R18 | #1361 is ratification-only and already has an implementation issue. #1362–#1364 are open at `0.0.8`; #1350 is open at `0.0.7`; no new issue is needed from this PR. | Live GitHub issue reads on 2026-08-08. | + +## Primary documentation + +| Topic | Primary source | Constraint carried into the RFC | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| Prisma transactions and isolation | [Prisma transaction reference](https://www.prisma.io/docs/orm/prisma-client/queries/transactions) | Interactive callback; `maxWait`/`timeout`; exact provider isolation sets; database default when omitted. | +| PostgreSQL isolation | [PostgreSQL 18 transaction isolation](https://www.postgresql.org/docs/current/transaction-iso.html) | PostgreSQL maps `ReadUncommitted` to `ReadCommitted`; serializable failures remain possible. | +| SQL Server isolation | [SQL Server `SET TRANSACTION ISOLATION LEVEL`](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-ver17) | `Snapshot` requires database configuration and is not an unconditional capability. | +| SQLite transactions | [SQLite transaction documentation](https://www.sqlite.org/lang_transaction.html) | One simultaneous writer; adapter must test busy/timeout paths rather than claim parity from a label. | +| Deno KV | [Deno KV transactions](https://docs.deno.com/deploy/kv/transactions/) and [Deno.Kv API](https://docs.deno.com/api/deno/~/Deno.Kv) | Optimistic `check` + atomic mutations with bounded checks, mutations, and bytes; refused from v1 command-store conformance. | +| Canonical JSON | [RFC 8785](https://www.rfc-editor.org/info/rfc8785/) | JCS over an I-JSON value before Web Crypto SHA-256; no `JSON.stringify` folklore. | +| Trace propagation | [W3C Trace Context](https://www.w3.org/TR/trace-context/) | Persist validated `traceparent`/`tracestate`, not an invented trace-id/correlation equivalence. | +| Deferred trace relationship | [OTel tracing API](https://opentelemetry.io/docs/specs/otel/trace/api/) | Relay spans are producer spans; deferred consumers may use propagated parent context or links. | +| Attribute safety | [OTel requirement levels](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) and [convention authoring](https://opentelemetry.io/docs/specs/semconv/how-to-write-conventions/) | Privacy-risk/high-cardinality values are not default attributes; enum attributes have a closed documented vocabulary. | + +## Proposal adjudication + +| Proposal statement | Verdict | RFC correction | +| ------------------------------------------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Reuse `withTransaction` verbatim. | Reject. | Preserve `TransactionOptions`/`IsolationLevel`, but first correct or bypass the full-client callback assertion; adapter conformance uses a true `TTx`. | +| Expose `maxIsolation`. | Reject. | Publish `supportedIsolationLevels` and configuration preconditions; levels are not one portable scalar ceiling. | +| Expose `conditionalWriteCount` as a store capability. | Reject. | Optimistic concurrency is a repository mutation contract. The command handler must perform a compare-and-set and map zero affected rows to `CommandFailure.conflict`; a read-then-compare helper is race-prone. | +| `expectVersion(current)` is sufficient. | Reject. | `expectedVersion` is a string in the envelope; the guide uses one conditional write inside the transaction. No generic command kit can synthesize a model-specific CAS. | +| Add `CONFLICT` globally. | Reject. | Add an opt-in `commandErrorMap` on `@netscript/contracts/commands` after #1350, preserving non-command routes. | +| Store an `unknown` replay response. | Reject. | Every command supplies an explicit output codec to/from canonical JSON text; Date/BigInt/class instances cannot silently cross the receipt boundary. | +| Hash “validated input + actor + expected version.” | Narrow. | Hash exact JCS bytes for `{command, definitionVersion, scope, inputFingerprint, actorSubject, expectedVersion}` with SHA-256. Roles/scopes/claims and the idempotency key are excluded. | +| In-flight receipt is a durable state. | Reject for the normal path. | Claim and completion are in one transaction, so incomplete claims never commit. Concurrent callers wait, replay, or receive a bounded retryable busy failure; a visible incomplete row is corruption. | +| Emit raw scope, key, and expected version in telemetry. | Reject. | Emit only registered command name, bounded enums/booleans/counts, isolation, and outcome. Raw actor, scope, request/key hashes, payload, version, and correlation are prohibited by default. | +| Deno KV receives weaker command semantics. | Reject from v1. | A store either conforms to same-commit command semantics or is not a `CommandStorePort`. KV delivery idempotency remains a separate runtime pattern. | +| SQLite is already a supported adapter. | Reject as current-state claim. | Matrix separates storage feasibility from shipped NetScript integration; SQLite stays “implementation prerequisite / unproven” until an adapter and fault suite exist. | +| There is no outbox primitive. | Reject as current-state claim. | Cite the reserved saga outbox port as prior art, but define a command-specific transaction-bound outbox record and relay store. | + +## Locked design inputs + +1. Public command semantics live at `@netscript/service/commands`; they are not root re-exports. +2. Transaction-bound persistence types and provider adapters live at `@netscript/database/commands`. + This preserves a one-way service → database dependency and avoids database → service → database. +3. Opt-in transport error schemas/map live at `@netscript/contracts/commands`; they do not enlarge + `baseContract` globally. +4. Command span names/attribute builders extend `@netscript/telemetry/attributes`. +5. Consumer-owned, provider-specific generated Prisma models own receipt/audit/outbox rows. The + framework ships logical row contracts and explicit generators, never hidden schema injection. +6. The command store is a conformant same-commit port. No false/weak capability branch is admitted. +7. A receipt key is `(scope, command name, SHA-256(idempotency key))`; request replay is guarded by + the separate canonical request hash. Keys must be high-entropy, are never logged, and are not + treated as authentication secrets. +8. The envelope carries a narrowed actor (`subject`, optional `scheme`), correlation id, validated + trace context, optional idempotency key, and string expected version. Authorization remains at + the service boundary; roles/scopes/claims are not copied into durable command metadata. +9. The runner does not automatically retry transaction callbacks. Serialization/deadlock/busy + failures are typed retryable outcomes; caller retry with the same key is the recovery path. +10. External I/O is forbidden inside the command callback. The only supported remote-effect path is + a same-commit outbox row followed by at-least-once relay. + +## JSR/public-surface audit + +| Surface | Planned consequence | Gate for implementation | +| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | +| `@netscript/service/commands` and `./commands/testing` | New explicit subpaths; no root-budget growth. Every exported generic needs an explicit return type and module/symbol docs. | Export-map diff, `deno doc --lint` across all service entrypoints, dry-run file-list review, consumer import fixture. | +| `@netscript/database/commands` and `./commands/testing` | Database publish include must intentionally include the new directory; transaction types must not expose generated Prisma or driver types. | Surface diff; slow-type gate; clean consumer with structural fake and real generated client. | +| `@netscript/contracts/commands` | Literal command error keys must survive isolated declarations; depends on #1350 fixing the base error-map widening. | Positive/negative type fixtures, `deno doc --lint`, publish dry-run for contracts. | +| `@netscript/telemetry/attributes` | Existing subpath grows; no new telemetry root export. Enum/value docs must be stable before publish. | Deno doc diff and exact attribute-map tests. | +| CLI-generated models/bridge/relay | Generated consumer files are not package exports, but templates and assets must be publish-safe generated constants. | Emitted-sample check, CLI scaffold runtime E2E in the implementation PR, no import-attribute/runtime file-read trap. | + +This RFC PR changes none of those exports. Its publish consequence is therefore design evidence, not +a claim that the future package surfaces already pass. The implementation must run the repository's +structured doc-lint and publish-dry-run gates on every changed package and must not use a green dry +run as a substitute for the published consumer gate. + +## Remaining FCP questions + +- Must a v1 command definition require idempotency, or may it explicitly declare `optional` and + surface `not_requested`? The RFC recommends required-by-default and permits opt-out only by an + explicit policy. +- Is SQLite a v1 release blocker or a later conforming adapter? Current NetScript has no SQLite + adapter to validate; the RFC recommends later, with no claim until conformance passes. +- Should command correlation IDs be opt-in telemetry attributes under a redaction policy, or stay + durable/log-only? The RFC recommends durable/log-only by default. +- What retention defaults apply to receipts, audit, and published outbox rows? The RFC fixes safety + constraints but leaves durations to FCP because they are operational policy, not atomicity. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/supervisor.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/supervisor.md index d54a5e36f2..35e47fd0aa 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/supervisor.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/supervisor.md @@ -3,36 +3,35 @@ Written at run start per `workflow/lane-policy.md` § Supervisor identity. This is a single-generator RFC/docs design run; no implementation sub-agents or rival worktree sessions are authorized. -| Field | Value | -| --- | --- | -| Model | OpenAI GPT-5.6 Sol (`gpt-5.6-sol`), xhigh reasoning | -| Session | Codex thread `019fe242-2c45-7e03-a428-eebfb968eda0` | -| Host | Linux / WSL user `codex`; danger-full-access; approval policy `never` | -| Checkout | `/home/codex/repos/ns-rfc-command-kit` | -| Worktree | `/home/codex/repos/ns-rfc-command-kit` (native WSL filesystem) | -| Branch | `docs/rfc-command-composition-kit` (no upstream by design) | +| Field | Value | +| -------- | ------------------------------------------------------------------------- | +| Model | OpenAI GPT-5.6 Sol (`gpt-5.6-sol`), xhigh reasoning | +| Session | Codex thread `019fe242-2c45-7e03-a428-eebfb968eda0` | +| Host | Linux / WSL user `codex`; danger-full-access; approval policy `never` | +| Checkout | `/home/codex/repos/ns-rfc-command-kit` | +| Worktree | `/home/codex/repos/ns-rfc-command-kit` (native WSL filesystem) | +| Branch | `docs/rfc-command-composition-kit` (no upstream by design) | | Baseline | `origin/main` at `fac9e339042c5394bf882311657d8981d353a1c3` on 2026-08-08 | -| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Run ID | `docs-rfc-command-composition-kit--rfc` | ## Routes in force -| Task lane | Provider / model / effort | Role in this run | -| --- | --- | --- | -| RFC generator (owner override of complex implementation lane) | OpenAI / GPT-5.6 Sol / xhigh | Sole researcher and RFC author | -| Cross-RFC review | Existing Claude Fable 5 session, steered by root orchestrator | Pending; generator must not launch it | -| Final adversarial evaluation | Qwen session selected and launched by root orchestrator | Pending; generator must not launch it | +| Task lane | Provider / model / effort | Role in this run | +| ------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------- | +| RFC generator (owner override of complex implementation lane) | OpenAI / GPT-5.6 Sol / xhigh | Sole researcher and RFC author | +| Cross-RFC review | Existing Claude Fable 5 session, steered by root orchestrator | Pending; generator must not launch it | +| Final adversarial evaluation | Qwen session selected and launched by root orchestrator | Pending; generator must not launch it | Reference `.llm/harness/workflow/lane-policy.md`; evaluator-session separation remains mandatory. ## Recorded lane/eval overrides -- Owner brief pins this generator to GPT-5.6 Sol at xhigh, above the canonical complex-implementation - lane's usual high effort. The observed route matches the requested route; see - `codex-thread-ids.md`. +- Owner brief pins this generator to GPT-5.6 Sol at xhigh, above the canonical + complex-implementation lane's usual high effort. The observed route matches the requested route; + see `codex-thread-ids.md`. - Owner brief reserves PLAN-EVAL / cross-RFC review and the final adversarial pass for the root orchestrator. This generator will prepare complete evaluator inputs and stop at `status:plan-eval`; it will not self-evaluate or launch a rival session. - `deno task agentic:runtime status --worktree /home/codex/repos/ns-rfc-command-kit` exited 3 with `MISSING_IDENTITY` and made no change. The pre-staged thread receipt is the session identity; daemon repair is neither necessary nor authorized while this attached turn is active. - diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md index 3eda0a7eee..2cc3ab6694 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md @@ -2,23 +2,27 @@ ## Run Metadata -| Field | Value | -| --- | --- | -| Run ID | `docs-rfc-command-composition-kit--rfc` | -| Branch | `docs/rfc-command-composition-kit` | -| Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | -| Scope overlays | `SCOPE-docs`, `SCOPE-service` | +| Field | Value | +| -------------- | --------------------------------------------------------------- | +| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Branch | `docs/rfc-command-composition-kit` | +| Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | +| Scope overlays | `SCOPE-docs`, `SCOPE-service` | ## Design -This checkpoint records the RFC/document surface before the RFC file is created. Exact product -types remain research inputs until the re-baseline slice locks them. +The S1 re-baseline locks the RFC contract before prose authoring. This PR remains docs-only; the +product names below are future surfaces whose implementation is decomposed after ratification. ### Public Surface - `rfcs/0000-command-composition-kit.md` — draft RFC only; no product export changes. -- Future public command entrypoint, unit-of-work capability contract, receipt/audit/outbox records, - typed failures, and command telemetry vocabulary — names and ownership must be locked in S1/S2. +- Future `@netscript/service/commands` executor/DSL and testing subpath. +- Future `@netscript/database/commands` transaction store, provider adapters, and conformance + subpath. +- Future opt-in `@netscript/contracts/commands` error map and existing telemetry attributes + extension. +- Explicit consumer-owned receipt/audit/outbox models and generated relay/command bridge. ### Domain Vocabulary @@ -30,8 +34,10 @@ types remain research inputs until the re-baseline slice locks them. ### Ports -- unit-of-work store capability — needed only where a database adapter can expose one transaction-scoped client. -- outbox relay store/transport — separate post-commit runtime seam; it cannot enlarge the transaction boundary. +- command store — conformant only where one transaction-scoped client can write business state, + receipt, audit, and outbox rows; no weaker implementation satisfies the port. +- outbox relay store/transport — separate post-commit runtime seam; it cannot enlarge the + transaction boundary. - telemetry/redaction policy — injected observability seam with bounded attributes. ### Constants @@ -42,19 +48,21 @@ types remain research inputs until the re-baseline slice locks them. ### Commit Slices -| # | Slice | Gate | Files | -| - | --- | --- | --- | -| B0 | Activate the harness and expose the run on a draft PR. | raw git identity/status; artifact presence | `.llm/runs/docs-rfc-command-composition-kit--rfc/*` | -| S1 | Re-baseline proposal, code, exports, tests, docs, live board, and primary adapter guarantees; lock the plan. | evidence inventory; `deno doc`; plan-gate readiness check | run `research.md`, `plan.md`, `worklog.md`, `context-pack.md`, `drift.md` | -| S2 | Define the exact public contracts, semantic laws, capability matrix, failure/telemetry/security model, and examples. | source-alignment audit; focused probes | RFC plus run artifacts | -| S3 | Complete worker/saga boundary, conformance/failure injection, compatibility, staging, docs/scaffold impact, issue decomposition, and handoff. | docs/RFC/link/format/diff gates | RFC, run artifacts, `final-handoff.md` | +| # | Slice | Gate | Files | +| -- | --------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------- | +| B0 | Activate the harness and expose the run on a draft PR. | raw git identity/status; artifact presence | `.llm/runs/docs-rfc-command-composition-kit--rfc/*` | +| S1 | Re-baseline proposal, code, exports, tests, docs, live board, and primary adapter guarantees; lock the plan. | evidence inventory; `deno doc`; plan-gate readiness check | run `research.md`, `plan.md`, `worklog.md`, `context-pack.md`, `drift.md` | +| S2 | Define the exact public contracts, semantic laws, capability matrix, failure/telemetry/security model, and examples. | source-alignment audit; focused probes | RFC plus run artifacts | +| S3 | Complete worker/saga boundary, conformance/failure injection, compatibility, staging, docs/scaffold impact, issue decomposition, and handoff. | docs/RFC/link/format/diff gates | RFC, run artifacts, `final-handoff.md` | ### Deferred Scope - Product/package/plugin implementation — belongs to #1363 and follow-on implementation slices. - Cross-store coordination and distributed transactions — explicitly refused. -- Relay deployment/operations — specified only as the narrow boundary necessary to consume outbox rows. -- Formal cross-RFC review and final adversarial evaluation — launched by the root orchestrator, not this generator. +- Relay deployment/operations — specified only as the narrow boundary necessary to consume outbox + rows. +- Formal cross-RFC review and final adversarial evaluation — launched by the root orchestrator, not + this generator. ### Contributor Path @@ -64,57 +72,72 @@ capabilities. ## Progress Log -| Time | Slice | Step | Notes | -| --- | --- | --- | --- | -| 2026-08-08 | B0 | bootstrap | Read all named skills and required RFC/harness/doctrine/evaluator authority; verified pinned branch/base. | -| 2026-08-08 | B0 | session health | Agentic runtime status made no changes and returned `MISSING_IDENTITY`; preserved the staged attached-thread receipt. | -| 2026-08-08 | B0 | live issue check | Confirmed #1361–#1364 and source PR #1347 exist; detailed re-baseline continues in S1. | +| Time | Slice | Step | Notes | +| ---------- | ----- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 2026-08-08 | B0 | bootstrap | Read all named skills and required RFC/harness/doctrine/evaluator authority; verified pinned branch/base. | +| 2026-08-08 | B0 | session health | Agentic runtime status made no changes and returned `MISSING_IDENTITY`; preserved the staged attached-thread receipt. | +| 2026-08-08 | B0 | live issue check | Confirmed #1361–#1364 and source PR #1347 exist; detailed re-baseline continues in S1. | +| 2026-08-08 | B0 | publish | Committed `ad643e15d657eb2b8e7a2d741e690c028ce67dc9`, pushed only as `HEAD:refs/heads/docs/rfc-command-composition-kit`, and opened draft PR #1389. | +| 2026-08-08 | B0 | PR metadata | Applied the required docs/RFC/area/priority/CI labels with exactly `status:research`; posted the opening `[PHASE: RESEARCH]` comment. | +| 2026-08-08 | S1 | public API re-baseline | Used native `deno doc` on database/service/contracts/telemetry/workers/sagas/SDK and oRPC; inspected export maps and source where the public surface was insufficient. | +| 2026-08-08 | S1 | focused probes | Proved `withTransaction` exposes root-only methods inside its callback (unexpected PASS) and reproduced #1350's `error.code` → `never` failure; removed both probes after execution. | +| 2026-08-08 | S1 | runtime/store research | Compared Prisma provider isolation, PostgreSQL, SQL Server, SQLite, Deno KV, RFC 8785, W3C Trace Context, and OTel primary documents. | +| 2026-08-08 | S1 | proposal challenge | Found the reserved saga outbox port, dynamic service context, missing SQLite adapter, route-local oRPC error composition, and #1293 package conflation; recorded corrections in `research.md`. | +| 2026-08-08 | S1 | plan lock | Locked package ownership, hash/codec rules, no-weak-port/no-hidden-retry laws, telemetry redaction, adapter truth, and board decomposition; plan gate is ready. | ## Decisions -| Decision | Reason | Source | -| --- | --- | --- | -| Keep this PR docs-only and RFC number `0000`. | RFC lifecycle and issue #1361 scope. | `rfcs/README.md`, #1361 | -| Use all Archetypes 1–6 as implementation-surface constraints, with docs/service overlays for this run. | The design crosses contracts, adapters, DSL, runtime, plugins, and CLI generators but this PR changes none of them. | Doctrine chapter 06; harness archetypes | -| Do not launch evaluators or a second Codex session. | Owner reserves review/evaluation for the root orchestrator; mobile-visible thread must remain singular. | implementation brief; `codex-wsl-remote` | +| Decision | Reason | Source | +| ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| Keep this PR docs-only and RFC number `0000`. | RFC lifecycle and issue #1361 scope. | `rfcs/README.md`, #1361 | +| Use all Archetypes 1–6 as implementation-surface constraints, with docs/service overlays for this run. | The design crosses contracts, adapters, DSL, runtime, plugins, and CLI generators but this PR changes none of them. | Doctrine chapter 06; harness archetypes | +| Do not launch evaluators or a second Codex session. | Owner reserves review/evaluation for the root orchestrator; mobile-visible thread must remain singular. | implementation brief; `codex-wsl-remote` | +| Put command semantics in service, transaction persistence in database, opt-in errors in contracts, and attributes in telemetry. | Preserves focused subpaths and one-way service → database dependency without a new package. | code/export re-baseline; doctrine A9–A11 | +| Reject a weak KV command mode and automatic callback retry. | Either all local rows share one commit or the adapter does not conform; caller retry is receipt-safe and observable. | Deno KV docs; doctrine A12–A13 | +| Reject read-then-compare concurrency and unknown receipt values. | CAS is repository-specific; explicit JCS fingerprints/codecs prevent races and serialization ambiguity. | Prisma OCC docs; RFC 8785; focused API analysis | +| Keep remote effects outside the callback and relay stable outbox IDs at least once. | SQL cannot roll back network effects; publish-then-crash can duplicate delivery. | worker/saga code; OTel/W3C docs; doctrine chapter 08 | ## Drift -| Drift | Severity | Logged in drift.md | -| --- | --- | --- | -| Runtime controller could not correlate the active staged thread to persisted runtime identity. | minor | yes | +| Drift | Severity | Logged in drift.md | +| ---------------------------------------------------------------------------------------------- | ----------- | ------------------ | +| Runtime controller could not correlate the active staged thread to persisted runtime identity. | minor | yes | +| Proposal says no outbox exists, but a reserved saga outbox port is public. | significant | yes | +| Proposal treats current SQLite/MySQL/package and transaction-helper surfaces too broadly. | significant | yes | ## Gate Results ### Static Gates -| Gate | Command or check | Result | Notes | -| --- | --- | --- | --- | -| Branch/base identity | raw git `rev-parse`, `merge-base`, `status` | PASS | Branch and base exactly match the brief. | -| Mandatory authority read | complete file reads | PASS | RFC process, doctrine, gate/evaluator files and selected profiles read before RFC authoring. | -| Docs/link/format gates | pending S3 | NOT_RUN | No RFC file exists yet. | +| Gate | Command or check | Result | Notes | +| ------------------------------ | -------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- | +| Branch/base identity | raw git `rev-parse`, `merge-base`, `status` | PASS | Branch and base exactly match the brief. | +| Mandatory authority read | complete file reads | PASS | RFC process, doctrine, gate/evaluator files and selected profiles read before RFC authoring. | +| Native public API inspection | `deno doc --filter` on database, service, SDK, telemetry, workers and oRPC | PASS | Exact current signatures and missing subpaths recorded in research. | +| Focused transaction type probe | `deno check --unstable-kv packages/database/rfc-command-probe.ts` | EXPECTED_FAIL_MISSED | Exit 0 proves the callback surface is too broad; temporary probe removed. | +| Focused typed-error probe | `deno check --unstable-kv packages/sdk/rfc-command-probe.ts` | EXPECTED_FAIL | Exit 1 with TS2339 on `error.code`; temporary probe removed. | +| Docs/link/format gates | pending S3 | NOT_RUN | RFC drafting begins in S2. | ### Fitness Gates -| Gate | Result | Evidence | Notes | -| --- | --- | --- | --- | -| F-5/F-6/F-7 planned surface audit | PENDING_SCRIPT | S1 `deno doc` and JSR/export scan | Design-time only; no package edits. | -| F-13 runtime invariants | PENDING_SCRIPT | S2/S3 RFC laws and conformance plan | Design-time only. | +| Gate | Result | Evidence | Notes | +| --------------------------------- | ----------- | ------------------------------------------ | ------------------------------------------------------------- | +| F-5/F-6/F-7 planned surface audit | PASS_DESIGN | `research.md` JSR/public-surface table | Design-time only; implementation gates specified per subpath. | +| F-13 runtime invariants | PASS_DESIGN | `plan.md` semantic laws and relay boundary | RFC must carry the exact injected-failure matrix in S2/S3. | ### Runtime Gates -| Gate | Result | Evidence | Notes | -| --- | --- | --- | --- | -| Product runtime | N/A | RFC/docs-only scope | No product behavior changes. | +| Gate | Result | Evidence | Notes | +| --------------- | ------ | ------------------- | ---------------------------- | +| Product runtime | N/A | RFC/docs-only scope | No product behavior changes. | ### Consumer Gates -| Consumer | Result | Evidence | Notes | -| --- | --- | --- | --- | -| Existing service/scaffold surfaces | NOT_RUN | S1 source analysis pending | Analysis only; no scaffold generation mutation. | +| Consumer | Result | Evidence | Notes | +| ---------------------------------- | ------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------- | +| Existing service/scaffold surfaces | PASS_ANALYSIS | Executed CLI help; CRUD template and add-route/add-handler source inspection | Current explicit commands and missing command/schema/relay paths recorded. | ## Handoff Notes - Root orchestrator should inspect the final RFC contracts and capability matrix first, then compare every unresolved question with #1361 acceptance and the final `research.md` evidence table. - From ad16c42f8e717c727ae00bb66c694f4073234a39 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 19:24:36 +0200 Subject: [PATCH 03/10] docs(rfc): define command composition kit --- .../context-pack.md | 26 +- .../plan.md | 7 +- .../research.md | 15 +- .../worklog.md | 50 +- rfcs/0000-command-composition-kit.md | 1693 +++++++++++++++++ 5 files changed, 1752 insertions(+), 39 deletions(-) create mode 100644 rfcs/0000-command-composition-kit.md diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md index 53c3bf959a..fe2f98038e 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md @@ -6,16 +6,17 @@ | -------------- | --------------------------------------------------------------- | | Run ID | `docs-rfc-command-composition-kit--rfc` | | Branch | `docs/rfc-command-composition-kit` | -| Current phase | `plan` | +| Current phase | `rfc-authoring` | | Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | | Scope overlays | `SCOPE-docs`, `SCOPE-service` | ## Current State -The run is activated on the exact requested branch/base in the sole daemon-attached Codex thread. -Bootstrap commit `ad643e15...` is pushed by explicit refspec and draft PR #1389 is live. The full -proposal/API/store/runtime/CLI/board re-baseline and plan gate are complete; no product code or RFC -file has been created. S2 now authors the locked contract and semantic laws. +The run is active on the exact requested branch/base in the sole daemon-attached Codex thread. +Bootstrap commit `ad643e15...` and research/plan commit `e0b98f289...` were pushed by explicit +refspec; draft PR #1389 is live at `status:plan`. The full re-baseline and plan gate are complete, +and the RFC now carries the exact contracts, semantic laws, adapter truth, relay boundary, +conformance plan, migration, and decomposition. No product code or export changed. ## Completed @@ -28,18 +29,20 @@ file has been created. S2 now authors the locked contract and semantic laws. - Proved the transaction callback typing defect and typed-error defect with removed focused probes. - Locked future package ownership, logical row ownership, JCS hashing/codec contract, adapter refusal rules, worker/saga boundary, telemetry redaction, and implementation decomposition. +- Authored `rfcs/0000-command-composition-kit.md` from the repository template, keeping `0000` and + `Draft` through maintainer discussion. +- Tightened the S2 surface with attempt identity across receipt/audit/outbox, schema-backed outbox + codecs, deterministic scope inputs, and explicit relay retry/terminal dispositions. ## In Progress -- S1 coherent research/plan commit, explicit-refspec push, plan phase comment, and status - transition. +- S2 source-alignment review and coherent RFC commit/push. ## Next Steps -1. Commit/push S1 and move the PR from `status:research` to `status:plan`. -2. Author exact contracts, rows, examples, laws, matrix, failure/security/telemetry model in S2. -3. Complete relay/conformance/migration/staging/docs/board sections in S3. -4. Run docs/RFC gates, write `final-handoff.md`, and stop at `status:plan-eval` for root-led review. +1. Commit/push S2 and post its implementation-phase evidence comment without starting evaluation. +2. Run docs/RFC, source-alignment, JSR-design, diff/lock, and PR/thread gates in S3. +3. Write `final-handoff.md`, update the PR/body, and stop at `status:plan-eval` for root-led review. ## Key Decisions @@ -57,6 +60,7 @@ file has been created. S2 now authors the locked contract and semantic laws. | Path | Status | Notes | | -------------------------------------------------- | ------ | --------------------------------------------------------- | | `.llm/runs/docs-rfc-command-composition-kit--rfc/` | new | Mandatory harness artifacts plus staged session receipts. | +| `rfcs/0000-command-composition-kit.md` | new | Draft RFC; no framework/product implementation. | ## Gates diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md index 9eb21448c3..4e31f612ef 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md @@ -6,7 +6,7 @@ | ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | | Run ID | `docs-rfc-command-composition-kit--rfc` | | Branch | `docs/rfc-command-composition-kit` | -| Phase | `plan` | +| Phase | `rfc-authoring` | | Target | `rfcs/0000-command-composition-kit.md` plus harness evidence | | Delivery profile | `SCOPE-docs` with `SCOPE-service` consumer analysis | | Described implementation | A1 contracts, A2 database/telemetry adapters, A3 relay runtime, A4 service DSL, A5 thin plugin consumers, A6 CLI generators | @@ -94,9 +94,12 @@ The RFC will specify, with compilable examples: append, and outbox append; every async port operation accepts cancellation. 5. Synchronous handler recorders `audit(...)` and `publish(...)`, plus a typed `conflict()` helper; buffers flush before receipt completion and commit. -6. Logical receipt/audit/outbox/relay-lease schemas and the exact unique keys/invariants. +6. Logical receipt/audit/outbox/relay-lease schemas, a per-attempt `executionId` joining side + records, and the exact unique keys/invariants. 7. An opt-in command contract error map plus the internal typed failure union and presentation map. 8. Command span/attribute constants with exact allowed values and redaction rules. +9. Schema-backed codecs for replay outputs and outbox payloads, plus an explicit retry/terminal + relay release union. ## Semantic laws to encode diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md index 86b8cb6da5..845a9f6400 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md @@ -35,6 +35,7 @@ | R16 | Exactly-once delivery cannot be inferred from a committed outbox row. A relay may publish and crash before marking the row, so message identity must be stable and consumers remain idempotent. | Doctrine chapter 08; current worker/saga delivery code; queue boundary analysis. | | R17 | Trace propagation already uses W3C `traceparent`/`tracestate` across service, workers, and sagas. OTel producer/consumer spans or links can join deferred delivery without storing arbitrary trace attributes. | Service builder, worker dispatcher, saga delivery; W3C Trace Context and OTel tracing API. | | R18 | #1361 is ratification-only and already has an implementation issue. #1362–#1364 are open at `0.0.8`; #1350 is open at `0.0.7`; no new issue is needed from this PR. | Live GitHub issue reads on 2026-08-08. | +| R19 | The package-neutral codec signature is structurally sound with Zod, but `@netscript/service` does not currently declare `@standard-schema/spec`; a future public signature must add that dependency directly. | Focused S2 type-shape probe initially failed import resolution, passed after using the workspace's locked `jsr:@standard-schema/spec@1.1.0`, and was removed; `deno why` confirmed the locked module. | ## Primary documentation @@ -91,13 +92,13 @@ ## JSR/public-surface audit -| Surface | Planned consequence | Gate for implementation | -| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | -| `@netscript/service/commands` and `./commands/testing` | New explicit subpaths; no root-budget growth. Every exported generic needs an explicit return type and module/symbol docs. | Export-map diff, `deno doc --lint` across all service entrypoints, dry-run file-list review, consumer import fixture. | -| `@netscript/database/commands` and `./commands/testing` | Database publish include must intentionally include the new directory; transaction types must not expose generated Prisma or driver types. | Surface diff; slow-type gate; clean consumer with structural fake and real generated client. | -| `@netscript/contracts/commands` | Literal command error keys must survive isolated declarations; depends on #1350 fixing the base error-map widening. | Positive/negative type fixtures, `deno doc --lint`, publish dry-run for contracts. | -| `@netscript/telemetry/attributes` | Existing subpath grows; no new telemetry root export. Enum/value docs must be stable before publish. | Deno doc diff and exact attribute-map tests. | -| CLI-generated models/bridge/relay | Generated consumer files are not package exports, but templates and assets must be publish-safe generated constants. | Emitted-sample check, CLI scaffold runtime E2E in the implementation PR, no import-attribute/runtime file-read trap. | +| Surface | Planned consequence | Gate for implementation | +| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| `@netscript/service/commands` and `./commands/testing` | New explicit subpaths; no root-budget growth. Every exported generic needs an explicit return type and module/symbol docs. `@standard-schema/spec` must be a direct package dependency. | Export-map diff, `deno doc --lint` across all service entrypoints, dry-run file-list review, consumer import fixture. | +| `@netscript/database/commands` and `./commands/testing` | Database publish include must intentionally include the new directory; transaction types must not expose generated Prisma or driver types. | Surface diff; slow-type gate; clean consumer with structural fake and real generated client. | +| `@netscript/contracts/commands` | Literal command error keys must survive isolated declarations; depends on #1350 fixing the base error-map widening. | Positive/negative type fixtures, `deno doc --lint`, publish dry-run for contracts. | +| `@netscript/telemetry/attributes` | Existing subpath grows; no new telemetry root export. Enum/value docs must be stable before publish. | Deno doc diff and exact attribute-map tests. | +| CLI-generated models/bridge/relay | Generated consumer files are not package exports, but templates and assets must be publish-safe generated constants. | Emitted-sample check, CLI scaffold runtime E2E in the implementation PR, no import-attribute/runtime file-read trap. | This RFC PR changes none of those exports. Its publish consequence is therefore design evidence, not a claim that the future package surfaces already pass. The implementation must run the repository's diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md index 2cc3ab6694..833fbace2e 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md @@ -11,8 +11,10 @@ ## Design -The S1 re-baseline locks the RFC contract before prose authoring. This PR remains docs-only; the -product names below are future surfaces whose implementation is decomposed after ratification. +The S1 re-baseline locked the RFC contract before prose authoring. S2 has now rendered those +decisions as exact guide/reference contracts in `rfcs/0000-command-composition-kit.md`. This PR +remains docs-only; the product names below are future surfaces whose implementation is decomposed +after ratification. ### Public Surface @@ -23,6 +25,8 @@ product names below are future surfaces whose implementation is decomposed after - Future opt-in `@netscript/contracts/commands` error map and existing telemetry attributes extension. - Explicit consumer-owned receipt/audit/outbox models and generated relay/command bridge. +- One attempt-scoped `executionId` joins receipt, audit, and outbox evidence; typed codecs guard + replay outputs and outbox payloads. ### Domain Vocabulary @@ -84,18 +88,25 @@ capabilities. | 2026-08-08 | S1 | runtime/store research | Compared Prisma provider isolation, PostgreSQL, SQL Server, SQLite, Deno KV, RFC 8785, W3C Trace Context, and OTel primary documents. | | 2026-08-08 | S1 | proposal challenge | Found the reserved saga outbox port, dynamic service context, missing SQLite adapter, route-local oRPC error composition, and #1293 package conflation; recorded corrections in `research.md`. | | 2026-08-08 | S1 | plan lock | Locked package ownership, hash/codec rules, no-weak-port/no-hidden-retry laws, telemetry redaction, adapter truth, and board decomposition; plan gate is ready. | +| 2026-08-08 | S2 | RFC contract draft | Authored the complete template-based RFC with exact service/store/contract/relay types, consumer-owned logical rows, JCS hashing, transaction algorithm, and semantic laws. | +| 2026-08-08 | S2 | production review | Added an attempt `executionId`, schema-backed outbox payloads, deterministic scope constraints, and an explicit retry/terminal relay release union after reviewing the exact contracts. | +| 2026-08-08 | S2 | boundary proof | Kept remote delivery post-commit and at least once; separated the existing saga outbox and worker delivery claims from the command receipt/store guarantee. | +| 2026-08-08 | S2 | surface design | Specified focused service/database/contracts subpaths and telemetry additions, JSR/slow-type/publish consequences, migration ownership, and staged implementation without changing exports. | +| 2026-08-08 | S2 | type-shape probe | Checked a synthetic command definition against current DB types, Zod, and Standard Schema. Initial resolution exposed the missing service dependency; direct JSR import passed; probe removed. | ## Decisions -| Decision | Reason | Source | -| ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | -| Keep this PR docs-only and RFC number `0000`. | RFC lifecycle and issue #1361 scope. | `rfcs/README.md`, #1361 | -| Use all Archetypes 1–6 as implementation-surface constraints, with docs/service overlays for this run. | The design crosses contracts, adapters, DSL, runtime, plugins, and CLI generators but this PR changes none of them. | Doctrine chapter 06; harness archetypes | -| Do not launch evaluators or a second Codex session. | Owner reserves review/evaluation for the root orchestrator; mobile-visible thread must remain singular. | implementation brief; `codex-wsl-remote` | -| Put command semantics in service, transaction persistence in database, opt-in errors in contracts, and attributes in telemetry. | Preserves focused subpaths and one-way service → database dependency without a new package. | code/export re-baseline; doctrine A9–A11 | -| Reject a weak KV command mode and automatic callback retry. | Either all local rows share one commit or the adapter does not conform; caller retry is receipt-safe and observable. | Deno KV docs; doctrine A12–A13 | -| Reject read-then-compare concurrency and unknown receipt values. | CAS is repository-specific; explicit JCS fingerprints/codecs prevent races and serialization ambiguity. | Prisma OCC docs; RFC 8785; focused API analysis | -| Keep remote effects outside the callback and relay stable outbox IDs at least once. | SQL cannot roll back network effects; publish-then-crash can duplicate delivery. | worker/saga code; OTel/W3C docs; doctrine chapter 08 | +| Decision | Reason | Source | +| ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| Keep this PR docs-only and RFC number `0000`. | RFC lifecycle and issue #1361 scope. | `rfcs/README.md`, #1361 | +| Use all Archetypes 1–6 as implementation-surface constraints, with docs/service overlays for this run. | The design crosses contracts, adapters, DSL, runtime, plugins, and CLI generators but this PR changes none of them. | Doctrine chapter 06; harness archetypes | +| Do not launch evaluators or a second Codex session. | Owner reserves review/evaluation for the root orchestrator; mobile-visible thread must remain singular. | implementation brief; `codex-wsl-remote` | +| Put command semantics in service, transaction persistence in database, opt-in errors in contracts, and attributes in telemetry. | Preserves focused subpaths and one-way service → database dependency without a new package. | code/export re-baseline; doctrine A9–A11 | +| Reject a weak KV command mode and automatic callback retry. | Either all local rows share one commit or the adapter does not conform; caller retry is receipt-safe and observable. | Deno KV docs; doctrine A12–A13 | +| Reject read-then-compare concurrency and unknown receipt values. | CAS is repository-specific; explicit JCS fingerprints/codecs prevent races and serialization ambiguity. | Prisma OCC docs; RFC 8785; focused API analysis | +| Keep remote effects outside the callback and relay stable outbox IDs at least once. | SQL cannot roll back network effects; publish-then-crash can duplicate delivery. | worker/saga code; OTel/W3C docs; doctrine chapter 08 | +| Join receipt, audit, and outbox evidence with one attempt `executionId`. | Correlation alone is neither unique nor a reliable ownership/join key; optional unkeyed attempts still need identity. | S2 exact-row review | +| Require a schema-backed codec for each outbox payload and model terminal relay release explicitly. | Producer type safety and exhaustion handling cannot exist only in prose. | S2 exact-port review | ## Drift @@ -109,14 +120,15 @@ capabilities. ### Static Gates -| Gate | Command or check | Result | Notes | -| ------------------------------ | -------------------------------------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- | -| Branch/base identity | raw git `rev-parse`, `merge-base`, `status` | PASS | Branch and base exactly match the brief. | -| Mandatory authority read | complete file reads | PASS | RFC process, doctrine, gate/evaluator files and selected profiles read before RFC authoring. | -| Native public API inspection | `deno doc --filter` on database, service, SDK, telemetry, workers and oRPC | PASS | Exact current signatures and missing subpaths recorded in research. | -| Focused transaction type probe | `deno check --unstable-kv packages/database/rfc-command-probe.ts` | EXPECTED_FAIL_MISSED | Exit 0 proves the callback surface is too broad; temporary probe removed. | -| Focused typed-error probe | `deno check --unstable-kv packages/sdk/rfc-command-probe.ts` | EXPECTED_FAIL | Exit 1 with TS2339 on `error.code`; temporary probe removed. | -| Docs/link/format gates | pending S3 | NOT_RUN | RFC drafting begins in S2. | +| Gate | Command or check | Result | Notes | +| ------------------------------ | -------------------------------------------------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------- | +| Branch/base identity | raw git `rev-parse`, `merge-base`, `status` | PASS | Branch and base exactly match the brief. | +| Mandatory authority read | complete file reads | PASS | RFC process, doctrine, gate/evaluator files and selected profiles read before RFC authoring. | +| Native public API inspection | `deno doc --filter` on database, service, SDK, telemetry, workers and oRPC | PASS | Exact current signatures and missing subpaths recorded in research. | +| Focused transaction type probe | `deno check --unstable-kv packages/database/rfc-command-probe.ts` | EXPECTED_FAIL_MISSED | Exit 0 proves the callback surface is too broad; temporary probe removed. | +| Focused typed-error probe | `deno check --unstable-kv packages/sdk/rfc-command-probe.ts` | EXPECTED_FAIL | Exit 1 with TS2339 on `error.code`; temporary probe removed. | +| Focused RFC type-shape probe | `deno check --unstable-kv packages/service/rfc-command-contract-probe.ts` | PASS_AFTER_FINDING | First run found missing service Standard Schema mapping; direct locked import passed; probe removed. | +| Docs/link/format gates | pending S3 | NOT_RUN | RFC drafting begins in S2. | ### Fitness Gates diff --git a/rfcs/0000-command-composition-kit.md b/rfcs/0000-command-composition-kit.md new file mode 100644 index 0000000000..29a23d2daa --- /dev/null +++ b/rfcs/0000-command-composition-kit.md @@ -0,0 +1,1693 @@ +--- +rfc: 0000 +title: Production command composition kit +status: Draft +authors: ['@rickylabs'] +created: 2026-08-08 +tracking-issue: https://github.com/rickylabs/netscript/issues/1361 +target-milestone: 0.0.6 +--- + +# Production command composition kit + +## Summary + +This RFC defines a small, opt-in NetScript command composition kit for a single transactional store. +A conforming command executes business writes and writes its idempotency receipt, audit records, and +outbox messages in the same commit. A retry with the same idempotency key and canonical request +returns the stored result without re-running the command. Remote delivery begins only after commit +through an at-least-once outbox relay. Stores that cannot provide the same commit, operations that +span stores, and network effects inside the transaction are refused rather than described as atomic. +This is a command boundary, not an ORM, workflow engine, event-sourcing system, or distributed +transaction protocol. + +## Motivation + +NetScript currently exposes useful pieces but no supported way to compose them into a production +command: + +- `@netscript/database` exports `withTransaction()` and transaction options, but the helper has no + production caller and types the callback as the full root client through an assertion. +- generated service handlers call Prisma delegates directly; +- `@netscript/plugin-workers-core` has KV-backed delivery claims, but they cannot join a relational + commit or replay a service response; +- `@netscript/plugin-sagas-core` exposes compensation and a reserved saga outbox port, but that port + has no adapter and is not transaction-bound to service business state; +- service, workers, and sagas propagate W3C trace context, while telemetry has no command + vocabulary; and +- consumers must invent receipt, audit, outbox, relay, failure, and migration conventions. + +The result is not merely duplicated code. Each application can choose a different answer to the hard +parts: whether a retry re-executes, what a reused key means, whether an audit record can commit +after the state it describes, whether an event is published before commit, and whether a remote side +effect is somehow considered transactional. + +The cost of doing nothing is a framework that generates CRUD well but leaves the first non-CRUD +state transition to application folklore. The proposed kit supplies one honest composition seam: + +> one command attempt, one store transaction, one durable answer, and zero remote effects before +> commit. + +It unlocks contract-first state transitions with optimistic concurrency, replay-safe HTTP or RPC +retries, durable operational evidence, and a visible bridge to workers and sagas. It does not make +every effect occur once. It makes the local commit indivisible and makes every boundary after that +commit explicit. + +## Guide-level explanation + +### The mental model + +A command is one validated caller intent that may change state. It has five stages: + +1. the service contract validates input and authenticates/authorizes the caller; +2. the executor computes an idempotency fingerprint and opens one supported store transaction; +3. the handler performs business writes through the transaction client and buffers audit/outbox + records; +4. the store writes the buffers and replay receipt, then commits them with the business state; and +5. a separate relay later publishes committed outbox messages at least once. + +If the operation needs another database, a KV mutation, or a remote call before it can be considered +successful, it is not one command transaction. Commit the local intent to the outbox and continue +through a worker or saga. + +### Define the contract first + +Command errors are opt-in. They do not enlarge every route built from `baseContract`. + +```ts +import { commandBaseContract, type CommandContractRoute } from '@netscript/contracts/commands'; +import { z } from 'zod'; + +export const renameProjectInput = z.object({ + id: z.string().min(1), + name: z.string().min(1).max(120), + expectedVersion: z.string().regex(/^\d+$/), + idempotencyKey: z.string().min(16).max(256), +}); + +export const projectOutput = z.object({ + id: z.string(), + name: z.string(), + version: z.string(), +}); + +export const projectRenamedPayload = z.object({ + projectId: z.string(), + name: z.string(), + version: z.string(), +}); + +export const renameProject: CommandContractRoute< + typeof renameProjectInput, + typeof projectOutput +> = commandBaseContract + .route({ method: 'POST', path: '/projects/{id}:rename' }) + .input(renameProjectInput) + .output(projectOutput); +``` + +`commandBaseContract` is `baseContract.errors(commandErrorMap)`. `commandErrorMap` adds only the +command failures a client can safely act on: `COMMAND_CONFLICT`, `IDEMPOTENCY_KEY_REUSE`, and +`COMMAND_IN_PROGRESS`. Normal authentication, authorization, validation, and service-unavailable +errors remain the existing contract vocabulary. + +### Define one command + +The command definition names its isolation, idempotency, replay codec, audit policy, and handler. +The example performs optimistic concurrency as a conditional update. It does not read a version and +compare it in memory. + +```ts +import { type CommandDefinition, defineCommand, jsonCodec } from '@netscript/service/commands'; +import type { PrismaTransactionClient } from '@database'; +import { z } from 'zod'; +import { projectOutput, projectRenamedPayload, renameProjectInput } from '../contracts/projects.ts'; + +export const renameProjectCommand = defineCommand({ + name: 'projects.rename', + definitionVersion: 1, + isolationLevel: 'ReadCommitted', + idempotency: { + mode: 'required', + scope: ({ input }) => input.id, + fingerprint: ({ id, name }) => ({ id, name }), + response: jsonCodec(projectOutput), + }, + records: { + audit: 'required', + outbox: 'optional', + }, + async handle(ctx) { + const updated = await ctx.tx.project.updateMany({ + where: { + id: ctx.envelope.input.id, + version: Number(ctx.envelope.expectedVersion), + }, + data: { + name: ctx.envelope.input.name, + version: { increment: 1 }, + }, + }); + + if (updated.count !== 1) { + ctx.conflict(); + } + + const project = await ctx.tx.project.findUniqueOrThrow({ + where: { id: ctx.envelope.input.id }, + }); + + ctx.audit({ + action: 'project.rename', + subject: { type: 'project', id: project.id }, + data: { version: String(project.version) }, + }); + + ctx.publish({ + destination: 'project-events', + topic: 'project.renamed.v1', + codec: jsonCodec(projectRenamedPayload), + payload: { + projectId: project.id, + name: project.name, + version: String(project.version), + }, + }); + + return { + id: project.id, + name: project.name, + version: String(project.version), + }; + }, +}) satisfies CommandDefinition< + 'projects.rename', + z.infer, + z.infer, + PrismaTransactionClient +>; +``` + +The handler may use the transaction client, injected clock/ID source, and synchronous recorders. It +must not call a remote service, enqueue directly, send email, or publish to a saga bus. Capturing +such a client in the closure is possible in TypeScript, but is outside the command guarantee and +fails conformance review. + +### Compose the executor explicitly + +The consumer owns the Prisma schema and generated client. An explicit generator adds the three +logical tables and a small bridge that binds their generated delegates to the package-owned store +port. + +```ts +import { createCommandExecutor } from '@netscript/service/commands'; +import { commandStore } from '../infrastructure/command-store.ts'; + +export const commands = createCommandExecutor({ + store: commandStore, + limits: { + auditRecords: 16, + outboxRecords: 32, + recordBytes: 64 * 1024, + }, +}); +``` + +The oRPC handler derives the envelope from already-validated input and the authenticated service +context. A system-triggered command must supply an explicit system actor; actor absence is never +silently treated as anonymous. + +```ts +import { throwCommandContractError } from '@netscript/contracts/commands'; + +export const renameProjectHandler = renameProject.handler( + async ({ input, context, errors }) => { + try { + const result = await commands.execute( + renameProjectCommand, + { + input, + actor: { + kind: 'principal', + subject: context.principal.subject, + scheme: context.principal.scheme, + }, + correlationId: context.correlationId, + trace: context.traceHeaders, + idempotencyKey: input.idempotencyKey, + expectedVersion: input.expectedVersion, + }, + { signal: context.signal }, + ); + return result.value; + } catch (error) { + throwCommandContractError(error, errors); + } + }, +); +``` + +The route returns exactly its declared output. Replay metadata is available to the handler and +telemetry but does not mutate the response shape. A contract that wants to expose replay state may +declare it in its own output. + +### What a retry does + +For an idempotency key `k`: + +- the first successful request commits the business writes, audit/outbox rows, and encoded response; +- the same key plus the same canonical request returns the first response and creates nothing new; +- the same key plus a different canonical request returns `IDEMPOTENCY_KEY_REUSE`; +- a concurrent follower either waits and replays, proceeds after the winner rolls back, or receives + the retryable `COMMAND_IN_PROGRESS` result when the adapter's bounded wait expires; and +- a failure after commit but before the HTTP response is repaired by the next retry, because receipt + completion was part of the commit. + +An optional-idempotency command may explicitly accept no key. That attempt remains atomic but is not +replay protected; telemetry records `not_requested`. Required-by-default versus permitting this +explicit opt-out is an FCP question. + +### Where the relay and saga begin + +An outbox row says that delivery is owed; it does not say delivery has happened. The generated relay +claims committed rows with leases, publishes each row's stable message ID, then marks it published. +If it publishes and crashes before marking, it publishes the same ID again. A worker, saga handler, +stream consumer, or webhook receiver must deduplicate or be idempotent. + +The command transaction ends before relay publication. A saga begins when later work needs multiple +durable steps, remote calls, time, retries, or compensation. `sagaCompensate()` is not called inside +the command transaction; the outbox can request a saga start after the local commit. + +## Reference-level explanation + +### Scope and terminology + +- **command** — one validated intent applied by one handler inside one supported store transaction; +- **attempt** — one invocation of that handler; the executor never repeats it automatically; +- **receipt key** — command scope, command name, and the SHA-256 digest of an idempotency key; +- **request hash** — SHA-256 of exact RFC-8785 canonical request material; +- **audit record** — immutable same-commit operational evidence supplied by the application; +- **outbox message** — same-commit remote-delivery intent with a stable message ID; +- **relay** — post-commit lease/publish/mark runtime with at-least-once delivery; +- **conformant store** — one that binds all local rows to the same transaction and passes the + injected-failure suite; and +- **refusal** — a typed failure before an unsupported guarantee is claimed. + +“Same commit” refers only to rows in the transaction's store. “Applied” means that transaction +committed. It does not mean a remote consumer observed the message. The RFC makes no end-to-end +exactly-once claim. + +### Package and export placement + +| Surface | Owner | Reason | +| -------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| `@netscript/service/commands` | command definition, executor, envelope, context, typed application failures | Commands are a service/application concern. A focused subpath preserves the root export budget. | +| `@netscript/service/commands/testing` | executor fixtures and fault controls | Testing-only public utilities stay off the production root. | +| `@netscript/database/commands` | transaction-bound store contracts and provider adapters | Database owns transaction/isolation vocabulary and the generated-client bridge. Service depends one way on this subpath. | +| `@netscript/database/commands/testing` | adapter conformance suite | Provider truth is tested at its owning adapter seam. | +| `@netscript/contracts/commands` | opt-in Zod schemas and command error map | Transport errors remain contract-first without changing all routes. | +| `@netscript/telemetry/attributes` | command span/attribute constants and builder | Extends the existing telemetry vocabulary where job/saga builders already live. | + +No `@netscript/commands` package is introduced. None of these symbols is re-exported from an +existing package root in v1. Internal imports within a package use relative paths, avoiding the +self-referential JSR subpath trap. + +### Value, identity, and envelope contracts + +```ts +import type { StandardSchemaV1 } from '@standard-schema/spec'; + +export type CommandJson = + | null + | boolean + | string + | number + | readonly CommandJson[] + | { readonly [key: string]: CommandJson }; + +export type CommandActor = + | Readonly<{ + kind: 'principal'; + subject: string; + scheme?: string; + }> + | Readonly<{ + kind: 'system'; + subject: string; + }>; + +export type CommandTraceContext = Readonly<{ + traceparent: string; + tracestate?: string; +}>; + +export type CommandEnvelope = Readonly<{ + input: TInput; + actor: CommandActor; + correlationId: string; + trace?: CommandTraceContext; + idempotencyKey?: string; + expectedVersion?: string; +}>; + +export interface CommandCodec { + encode(value: T): CommandJson; + decode(value: CommandJson): T; +} + +export function jsonCodec( + schema: StandardSchemaV1, +): CommandCodec; +``` + +`CommandJson` is a static convenience, not sufficient validation by itself. Codec output must be +I-JSON suitable for RFC 8785: object keys are strings; numbers are finite IEEE-754 values; lone +surrogates, `undefined`, sparse arrays, `Date`, `BigInt`, functions, symbols, class instances, and +cyclic values are rejected. Stored values are decoded and validated again; a database row is not +trusted merely because the framework wrote it. + +`actor.subject` reuses the authenticated principal identity, while roles, scopes, and claims do not +cross the durable command boundary. Authorization happens before execution. `scheme` may be stored +in audit evidence but is excluded from request identity so a credential mechanism change does not +turn a retry into another request. + +`expectedVersion` is a string. Consumers normalize integer, UUID, timestamp, or opaque version +tokens at their repository boundary rather than risk JavaScript numeric precision or a second +portable version algebra. + +`jsonCodec()` accepts the package-neutral `StandardSchemaV1` contract. It does not expose Zod in the +service public surface. + +### Command definition and execution contracts + +```ts +export type CommandIdempotencyMode = 'required' | 'optional'; +export type CommandRecordRequirement = 'required' | 'optional' | 'forbidden'; + +export type CommandIdempotency = Readonly<{ + mode: CommandIdempotencyMode; + scope(identity: Readonly<{ input: TInput; actor: CommandActor }>): string; + fingerprint(input: TInput): CommandJson; + response: CommandCodec; +}>; + +export type CommandDefinitionSpec< + TName extends string, + TInput, + TOutput, + TTx, +> = Readonly<{ + name: TName; + definitionVersion: number; + isolationLevel?: IsolationLevel; + idempotency: CommandIdempotency; + records: Readonly<{ + audit: CommandRecordRequirement; + outbox: CommandRecordRequirement; + }>; + handle(context: CommandContext): Promise; +}>; + +export interface CommandDefinition< + TName extends string, + TInput, + TOutput, + TTx, +> { + readonly name: TName; + readonly definitionVersion: number; + readonly isolationLevel?: IsolationLevel; + readonly idempotency: CommandIdempotency; + readonly records: Readonly<{ + audit: CommandRecordRequirement; + outbox: CommandRecordRequirement; + }>; +} + +export type CommandAuditInput = Readonly<{ + action: string; + subject: Readonly<{ type: string; id: string }>; + data?: CommandJson; +}>; + +export type CommandOutboxInput = Readonly<{ + destination: string; + topic: string; + payload: TPayload; + codec: CommandCodec; + dedupeKey?: string; + availableAt?: Date; +}>; + +export interface CommandContext { + readonly tx: TTx; + readonly envelope: CommandEnvelope; + readonly signal: AbortSignal; + now(): Date; + newId(): string; + audit(record: CommandAuditInput): void; + publish(message: CommandOutboxInput): void; + conflict(): never; +} + +export type CommandExecution = Readonly<{ + value: TOutput; + outcome: 'applied' | 'replayed'; + idempotency: 'committed' | 'replayed' | 'not_requested'; + correlationId: string; +}>; + +export interface CommandExecutor { + execute( + command: CommandDefinition, + envelope: CommandEnvelope, + options?: Readonly<{ signal?: AbortSignal }>, + ): Promise>; +} + +export interface CommandClock { + now(): Date; +} + +export interface CommandIdSource { + next(): string; +} + +export type CommandTelemetryStart = Readonly<{ + name: string; + definitionVersion: number; + isolation: IsolationLevel | 'default'; + provider: string; + idempotency: 'claimed' | 'not_requested'; +}>; + +export type CommandTelemetryResult = Readonly<{ + outcome: 'applied' | 'replayed' | 'conflict' | 'rejected' | 'failed' | 'cancelled'; + idempotency: 'claimed' | 'replayed' | 'not_requested' | 'missing' | 'mismatch' | 'busy'; + auditCount: number; + outboxCount: number; + errorType?: CommandFailure['kind']; +}>; + +export interface CommandTelemetrySpan { + finish(result: CommandTelemetryResult): void; +} + +export interface CommandTelemetryPort { + trace( + start: CommandTelemetryStart, + operation: (span: CommandTelemetrySpan) => Promise, + ): Promise; +} + +export type CommandExecutorOptions = Readonly<{ + store: CommandStorePort; + clock?: CommandClock; + ids?: CommandIdSource; + telemetry?: CommandTelemetryPort; + limits?: Readonly<{ + auditRecords: number; + outboxRecords: number; + recordBytes: number; + }>; +}>; + +export function defineCommand< + TName extends string, + TInput, + TOutput, + TTx, +>( + specification: CommandDefinitionSpec, +): CommandDefinition; + +export function createCommandExecutor( + options: CommandExecutorOptions, +): CommandExecutor; +``` + +`defineCommand()` validates names and policies once and returns an immutable definition. Command +names are 1–120 characters and match `^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$`; `definitionVersion` is a +positive safe integer. Names and versions are durable protocol data and cannot be changed as a +refactor. + +`now()` and `newId()` use executor-injected ports. `audit()` and `publish()` are synchronous +recorders; they do not write or call a transport. The executor enforces the declared required, +optional, or forbidden record counts before flushing. It also enforces configured count/byte limits +before asking the store to write. + +The exported `CommandDefinition` is read-only and does not expose a public constructor. The actual +handler remains part of the opaque definition returned by `defineCommand()`, preventing callers from +bypassing the executor by invoking a public `handle` member. + +### Transaction-bound store contracts + +The database subpath owns the transaction vocabulary and imports no service types. The business +transaction client and side-record methods are one bound handle: + +```ts +export type CommandStoreCapabilities = Readonly<{ + provider: DatabaseProvider; + transactionModel: 'interactive'; + sideRecordAtomicity: 'same_commit'; + callbackAttempts: 'one'; + cancellation: 'cooperative' | 'driver'; + supportedIsolationLevels: readonly IsolationLevel[]; +}>; + +export type CommandTransactionRequest = Readonly<{ + options?: TransactionOptions; +}>; + +export type ReceiptClaim = Readonly<{ + id: string; + scope: string; + commandName: string; + commandVersion: number; + keyHash: string; + requestHash: string; + actorKind: 'principal' | 'system'; + actorSubject: string; + correlationId: string; + createdAt: Date; +}>; + +export type StoredCommandReceipt = Readonly<{ + id: string; + requestHash: string; + commandVersion: number; + responseJson: string; + correlationId: string; + completedAt: Date; +}>; + +export type ReceiptClaimResult = + | Readonly<{ kind: 'execute'; receiptId: string }> + | Readonly<{ kind: 'replay'; receipt: StoredCommandReceipt }> + | Readonly<{ kind: 'mismatch' }> + | Readonly<{ kind: 'busy'; retryAfterMs?: number }>; + +export type StoredCommandAudit = Readonly<{ + id: string; + executionId: string; + commandName: string; + commandVersion: number; + action: string; + subjectType: string; + subjectId: string; + actorKind: 'principal' | 'system'; + actorSubject: string; + actorScheme?: string; + correlationId: string; + dataJson?: string; + occurredAt: Date; +}>; + +export type StoredCommandOutbox = Readonly<{ + id: string; + executionId: string; + commandName: string; + commandVersion: number; + destination: string; + topic: string; + payloadJson: string; + dedupeKey: string; + correlationId: string; + traceparent?: string; + tracestate?: string; + availableAt: Date; +}>; + +export interface CommandTransaction { + readonly business: TTx; + claimReceipt( + claim: ReceiptClaim, + signal?: AbortSignal, + ): Promise; + completeReceipt( + completion: Readonly<{ + receiptId: string; + responseJson: string; + completedAt: Date; + }>, + signal?: AbortSignal, + ): Promise; + appendAudit( + records: readonly StoredCommandAudit[], + signal?: AbortSignal, + ): Promise; + appendOutbox( + messages: readonly StoredCommandOutbox[], + signal?: AbortSignal, + ): Promise; +} + +export interface CommandStorePort { + readonly capabilities: CommandStoreCapabilities; + transaction( + request: CommandTransactionRequest, + work: (transaction: CommandTransaction) => Promise, + signal?: AbortSignal, + ): Promise; +} +``` + +A `CommandStorePort` with `sideRecordAtomicity: "same_commit"` must make that a construction +invariant, not a configuration promise. Its `CommandTransaction` is created inside the provider +callback, all four delegates are derived from that callback's `TTx`, and no root client is accepted +by the side-record bridge. + +`callbackAttempts: "one"` forbids an adapter from replaying `work` after serialization, deadlock, or +busy failures. The adapter may retry connection acquisition before invoking `work`, but once invoked +the result is commit, rollback, or a surfaced failure. + +`cancellation: "cooperative"` means the adapter checks the signal before beginning and between +framework-controlled steps but the driver cannot interrupt an already-issued query. Such an adapter +must also enforce a transaction timeout. `"driver"` may be advertised only when the actual driver +cancels in-flight operations. Cancellation never means rollback succeeded until the transaction +boundary reports it. + +The existing `withTransaction()` cannot implement this contract verbatim: it types its callback as +the full root client through an assertion. The reference implementation must first give that helper +a true `TRoot`/`TTx` signature or call the correctly typed Prisma callback directly. Nested +`$transaction`, connection lifecycle, and other root-only methods must be absent from `TTx`. + +### Logical row contracts + +The application owns the tables and migrations. The packages own these logical field contracts: + +#### Command receipt + +| Field | Logical type | Constraint | +| ---------------- | ---------------------------- | ----------------------------------------------------------- | +| `id` | UUID/string | primary key; generated before claim | +| `scope` | bounded UTF-8 string | 1–256 bytes; application receipt namespace | +| `commandName` | bounded string | validated command name | +| `commandVersion` | positive integer | definition version that produced the receipt | +| `keyHash` | 64 lowercase hex chars | SHA-256 of the UTF-8 idempotency key; raw key is not stored | +| `requestHash` | 64 lowercase hex chars | exact canonical request hash | +| `actorKind` | `principal \| system` | durable origin class | +| `actorSubject` | bounded string | authenticated/system subject; no roles/scopes/claims | +| `correlationId` | bounded string | durable application correlation value | +| `responseJson` | nullable canonical JSON text | null only inside the uncommitted claim | +| `createdAt` | UTC timestamp | claim time from injected clock | +| `completedAt` | nullable UTC timestamp | set with `responseJson` before commit | + +There is a unique key on `(scope, commandName, keyHash)`. `responseJson` and `completedAt` must be +both null or both non-null. A committed incomplete receipt is corruption, not “in progress”; normal +concurrency cannot observe the uncommitted claim. Provider-aware generated migrations add the check +constraint where the provider supports it, while conformance tests enforce the invariant on every +adapter. + +The idempotency key is not part of `requestHash`. It selects the receipt. Including it in the hash +would add no replay protection. The raw key is never persisted, logged, or emitted to telemetry. + +#### Command audit + +| Field | Logical type | Constraint | +| -------------------------------------------- | ---------------------------- | ------------------------------------ | +| `id` | UUID/string | primary key | +| `executionId` | UUID/string | originating command attempt | +| `commandName` / `commandVersion` | string / integer | durable command identity | +| `action` | bounded string | application-owned action vocabulary | +| `subjectType` / `subjectId` | bounded strings | application-owned target identity | +| `actorKind` / `actorSubject` / `actorScheme` | bounded strings | origin evidence; scheme nullable | +| `correlationId` | bounded string | copied from the envelope | +| `dataJson` | nullable canonical JSON text | application-owned, redacted metadata | +| `occurredAt` | UTC timestamp | injected clock | + +The kit does not define a domain audit taxonomy, authorization model, legal retention policy, or +tamper-proof log. It guarantees only that a valid audit row supplied by the handler shares the +business commit. Applications restrict update/delete privileges and choose retention according to +their requirements. + +#### Command outbox + +| Field | Logical type | Constraint | +| -------------------------------- | -------------------------- | --------------------------------------------------- | +| `id` | UUID/string | stable message ID and default downstream dedupe key | +| `executionId` | UUID/string | originating command attempt | +| `commandName` / `commandVersion` | string / integer | originating command | +| `destination` | bounded string | logical sink registry key | +| `topic` | bounded string | versioned application message type | +| `payloadJson` | canonical JSON text | validated codec output | +| `dedupeKey` | bounded string | handler value or `id` by default | +| `correlationId` | bounded string | durable application correlation | +| `traceparent` / `tracestate` | nullable validated strings | W3C propagation only | +| `availableAt` | UTC timestamp | earliest delivery time | +| `attemptCount` | non-negative integer | relay attempts | +| `claimToken` / `claimUntil` | nullable string/timestamp | expiring relay lease | +| `publishedAt` | nullable UTC timestamp | set only after sink acknowledgement | +| `terminalAt` | nullable UTC timestamp | set only when retry policy is exhausted | +| `lastFailure` | nullable bounded enum | classified failure, not raw payload/stack | + +The command transaction inserts only the immutable delivery intent and initial relay fields. +Lease/attempt/publication updates happen in later relay transactions. There is no arbitrary headers +map: sink adapters construct protocol headers, validate trace context, and retrieve credentials from +runtime configuration rather than durable rows. + +Payloads and responses use canonical JSON text, not a provider `Json` scalar. That avoids assuming +identical Prisma JSON support and native types across PostgreSQL, MySQL, SQL Server, and SQLite. +Provider generators may add efficient native projections, but the portable contract is text. + +### Schema and bridge ownership + +`netscript db command-store init --database ` is the proposed explicit generator. It: + +1. detects the configured Prisma provider; +2. appends provider-specific receipt/audit/outbox models using stable `NetScriptCommand*` names; +3. creates a reviewable migration, including unique/check/index definitions; +4. emits `database//command-store.ts`, which binds the generated delegates and true + transaction client to `CommandStorePort`; and +5. refuses to overwrite edited models or run a migration without the consumer's normal DB command. + +The package never injects models during import, service startup, `defineService()`, or relay +startup. The generated bridge is consumer-owned, checked in, and discoverable. Model renames require +an explicit bridge update; they do not change the public store contract. + +### Canonical request identity + +Before opening the transaction, the executor builds this exact value: + +```ts +type CanonicalCommandRequest = Readonly<{ + command: string; + definitionVersion: number; + scope: string; + input: CommandJson; + actor: Readonly<{ + kind: 'principal' | 'system'; + subject: string; + }>; + expectedVersion: string | null; +}>; +``` + +The steps are normative: + +1. validate command/envelope bounds and idempotency policy; +2. call the command's `scope({ input, actor })` and `fingerprint(input)` exactly once; +3. validate the result as I-JSON; +4. serialize the complete value with RFC 8785 JCS to UTF-8; +5. compute SHA-256 with `crypto.subtle.digest("SHA-256", bytes)`; and +6. encode the digest as 64 lowercase hexadecimal characters. + +The key digest separately hashes the UTF-8 idempotency key with the same SHA-256/hex encoding. The +request hash is a consistency token, not an authenticator or password hash. It must not be used for +authorization, message signing, or proof of possession. + +`fingerprint(input)` intentionally selects the semantic command input. Transport-only values such as +the idempotency key are excluded. The command author must include every input field that can change +the effect. Negative conformance mutates each contract field and proves either that the fingerprint +changes or that the field is explicitly classified transport-only. + +`scope()` is equally deterministic: it may use only the supplied input and narrowed actor, performs +no I/O, and excludes transport-only idempotency, trace, and correlation values. Scope partitions a +receipt namespace (for example by tenant or aggregate); it must not vary between retries of the same +intent. The restricted argument deliberately withholds the rest of `CommandEnvelope`. + +`definitionVersion` changes when request identity, response decoding, or command meaning changes. +Because the receipt unique key does not include that version, a retry crossing a deployment returns +`IDEMPOTENCY_KEY_REUSE` rather than executing a new command under the old key. This is safer than +silently applying the intent again. + +### Transaction algorithm + +For one `execute()` call: + +1. Validate command metadata, envelope bounds, actor, W3C trace context, required idempotency, store + atomicity, requested isolation, and buffer limits. Unsupported capabilities fail before the + handler. +2. Compute scope, input fingerprint, request hash, and key hash outside the transaction. Codec or + canonicalization failure is a typed non-retryable configuration/input failure. +3. Start `command.execute` as a child of the active RPC/server span when available. +4. Call `store.transaction()` once with the selected isolation/timeout and signal. +5. If a key is present, call `claimReceipt()`: + - `mismatch` becomes `idempotency_key_reuse` without running the handler; + - `busy` becomes `in_progress`; + - `replay` validates the stored hash/version, parses and decodes `responseJson`, and returns + without business, audit, or outbox writes; and + - `execute` continues with its receipt ID. +6. Invoke the handler exactly once with `transaction.business` and empty in-memory buffers. +7. Enforce required/optional/forbidden record policies and count/byte limits. +8. Encode the response, validate audit/outbox values, create one attempt `executionId` plus stable + record IDs, and canonicalize their JSON text. For a keyed attempt, the receipt ID is the + `executionId`; an unkeyed optional attempt still receives an `executionId` for its side records. +9. Append audit rows, append outbox rows, and complete the receipt, in that order, through the bound + transaction. A no-key optional attempt skips claim/completion. +10. Return from the transaction callback and wait for the adapter's commit result. +11. Record `applied` or `replayed` telemetry and return the decoded value. + +Any exception or cancellation before the successful commit rolls back all transaction writes. A +fault after commit but before step 11 may lose the response to that call; retry with the same key +loads the committed receipt. No post-commit “repair write” exists for receipts, audit, or outbox. + +The order in step 9 aids deterministic fault injection but does not create partial visibility: every +append and completion still belongs to the same transaction. A business error thrown by the handler +remains the handler's declared error; the executor does not wrap arbitrary application errors as +storage failures. + +### Semantic laws + +Every conforming implementation and adapter satisfies these laws: + +1. **Atomic rollback law.** A fault before commit leaves no business-state delta, completed receipt, + audit row, or outbox row. +2. **Same-commit law.** If any one local row from a successful attempt is visible, all local rows + from that attempt are visible. +3. **Replay law.** Same receipt key and request hash returns the first decoded response, sets + `outcome = replayed`, and produces no new business/audit/outbox rows. +4. **Key-reuse law.** Same receipt key and different request hash never invokes the handler and + returns the typed non-retryable key-reuse failure. +5. **Concurrent-claim law.** Of concurrent identical attempts, at most one handler commits. A + follower replays, runs only after the leader rolled back, or receives a bounded retryable busy + failure. +6. **Receipt-completion law.** A committed receipt is complete and decodable. An incomplete or + invalid committed receipt is corruption and never causes handler execution. +7. **CAS law.** A command requiring optimistic concurrency performs the version predicate in the + mutation. Zero matched rows becomes a conflict and rolls back every buffered record. +8. **No-hidden-retry law.** One executor call invokes the handler no more than once. +9. **Isolation-refusal law.** A requested level absent from `supportedIsolationLevels` is refused + before opening the transaction. +10. **Stable-message law.** A committed outbox row retains one `id`/`dedupeKey` across every relay + claim, lease expiry, retry, and redelivery. +11. **At-least-once relay law.** A successful sink acknowledgement eventually permits `publishedAt`, + but publish-before-crash may result in the same message being observed again. +12. **Boundary law.** No SQL+KV, SQL+stream, SQL+HTTP, two-database, or other cross-store operation + is represented as one command transaction. + +“At most one handler commits” is conditional on a supplied idempotency key. An optional attempt +without one retains only the atomic rollback and same-commit laws. + +### Optimistic concurrency and isolation + +The executor propagates `expectedVersion` and supplies `ctx.conflict()`. It cannot manufacture a +portable conditional mutation because only the application repository knows the model, key, version +column, and write set. + +The supported pattern is one provider query whose predicate includes the expected version and whose +result proves whether it matched. A preliminary read may be useful for business decisions but never +replaces the conditional write. The proposal's `expectVersion(current)` is rejected because another +transaction can write between comparison and mutation. + +Isolation is a set, not a scalar “maximum.” The command declares the minimum concrete level its +algorithm was tested with. Omitting `isolationLevel` uses the database default and records `default` +in command telemetry; it does not claim a portable effective level. Commands maintaining multi-row +invariants normally require `Serializable` or another provider-specific locking design and must test +serialization/deadlock outcomes. + +The executor does not automatically retry serialization, deadlock, or SQLite busy failures. Those +become retryable store outcomes. A caller can retry the entire request with the same key, which is +safe whether the original attempt rolled back or committed before its response was lost. + +### Adapter capability matrix + +“Engine feasible” and “currently integrated by NetScript” are deliberately separate: + +| Store | Engine/Prisma transaction facts | Current NetScript integration at `fac9e339` | RFC position | +| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | +| PostgreSQL + Prisma | interactive transactions; `ReadUncommitted` maps to `ReadCommitted`; `ReadCommitted`, `RepeatableRead`, `Serializable` available | Postgres adapter/root surface exists | reference v1 adapter after full conformance | +| MySQL + Prisma | interactive; `ReadUncommitted`, `ReadCommitted`, `RepeatableRead`, `Serializable`; no `Snapshot` | `@netscript/database/adapters/mysql` exists | conforming v1 target; #1293 is adjacent lower-level surface work, not an atomicity prerequisite | +| SQL Server + Prisma | interactive; all five current `IsolationLevel` values; `Snapshot` requires database enablement | `@netscript/database/adapters/mssql` exists | conforming v1 target; capability must omit `Snapshot` when not enabled | +| SQLite + Prisma | transactions are serializable in Prisma's matrix; multiple readers but one writer; busy/timeout behavior differs | provider enum exists, but no NetScript SQLite adapter export | feasible but unsupported/unclaimed until an adapter and real contention/fault suite land | +| Deno KV | optimistic atomic checks/mutations with operation limits; no interactive callback | `@netscript/kv` and worker idempotency exist | not a v1 `CommandStorePort`; no weaker command mode | +| two SQL stores or SQL + KV/stream/HTTP | no portable shared commit | components may exist separately | refused; commit an outbox intent and continue through a consumer/saga | + +Same-commit audit/outbox feasibility follows from using tables in the same database and the exact +transaction client. It does not follow from the provider name alone. Each provider becomes +“supported” only when its generated schema, transaction bridge, contention behavior, fault suite, +doc lint, publish gates, and consumer test pass. + +The current database helper's `IsolationLevel` vocabulary is reused. The RFC does not introduce a +second enum. Provider adapters publish the exact supported subset and relevant configuration +preconditions. + +### Typed failure model + +The service subpath exposes a discriminated failure payload on `CommandError`: + +```ts +export type CommandFailure = + | Readonly<{ + kind: 'invalid_envelope'; + retryable: false; + reason: + | 'actor' + | 'correlation' + | 'idempotency_required' + | 'trace_context'; + }> + | Readonly<{ + kind: 'optimistic_conflict'; + retryable: false; + }> + | Readonly<{ + kind: 'idempotency_key_reuse'; + retryable: false; + }> + | Readonly<{ + kind: 'in_progress'; + retryable: true; + retryAfterMs?: number; + }> + | Readonly<{ + kind: 'unsupported_capability'; + retryable: false; + capability: 'store_atomicity' | 'isolation' | 'transaction_model'; + }> + | Readonly<{ + kind: 'codec_failure'; + retryable: false; + phase: 'fingerprint' | 'response_encode' | 'response_decode' | 'side_record'; + }> + | Readonly<{ + kind: 'receipt_corrupt'; + retryable: false; + }> + | Readonly<{ + kind: 'store_failure'; + retryable: boolean; + phase: 'begin' | 'claim' | 'business' | 'flush' | 'complete' | 'commit'; + }> + | Readonly<{ + kind: 'aborted'; + retryable: true; + }>; + +export class CommandError extends Error { + readonly failure: CommandFailure; + + constructor(failure: CommandFailure, options?: ErrorOptions); +} +``` + +Driver codes, SQL text, payloads, actor IDs, scope, hashes, and stored response text are never +placed in the public failure. Adapters classify known serialization/deadlock/busy/timeout failures +behind `store_failure` while retaining the original error as a non-serialized `cause` for trusted +logs. + +Application/business errors thrown by the handler are outside this union and preserve their own +contract mapping. `ctx.conflict()` is the one convenience constructor because optimistic conflicts +are part of command composition rather than a domain-specific taxonomy. + +The opt-in contract fragment is: + +```ts +export const commandErrorMap = { + COMMAND_CONFLICT: { + status: 409, + message: 'The command no longer matches current state', + data: z.object({ + kind: z.literal('optimistic_conflict'), + retryable: z.literal(false), + }), + }, + IDEMPOTENCY_KEY_REUSE: { + status: 409, + message: 'The idempotency key was used for another request', + data: z.object({ + kind: z.literal('idempotency_key_reuse'), + retryable: z.literal(false), + }), + }, + COMMAND_IN_PROGRESS: { + status: 409, + message: 'An identical command is still in progress', + data: z.object({ + kind: z.literal('in_progress'), + retryable: z.literal(true), + retryAfterMs: z.number().int().nonnegative().optional(), + }), + }, +} as const; + +export const commandBaseContract = baseContract.errors(commandErrorMap); + +export type CommandContractErrors = MergedErrorMap< + BaseContractErrors, + typeof commandErrorMap +>; + +export type CommandContractRoute< + TInput extends AnySchema, + TOutput extends AnySchema, +> = ContractProcedureBuilderWithInputOutput< + TInput, + TOutput, + CommandContractErrors, + Record +>; + +export interface CommandErrorConstructors { + COMMAND_CONFLICT(options: { + message?: string; + data: { kind: 'optimistic_conflict'; retryable: false }; + }): unknown; + IDEMPOTENCY_KEY_REUSE(options: { + message?: string; + data: { kind: 'idempotency_key_reuse'; retryable: false }; + }): unknown; + COMMAND_IN_PROGRESS(options: { + message?: string; + data: { + kind: 'in_progress'; + retryable: true; + retryAfterMs?: number; + }; + }): unknown; +} + +export function throwCommandContractError( + error: unknown, + errors: CommandErrorConstructors, +): never; +``` + +Invalid envelopes map to existing validation handling. Unsupported capability is a deployment or +composition error and should normally fail startup/registration, not reach a client. Codec, +corruption, and unexpected store failures map through existing internal/service-unavailable +handling. That division keeps safe client action separate from operational detail. + +The client-visible typed-error path cannot ship honestly until #1350 preserves the error generic +through `baseContract`, the service client, `safe()`, and `isDefinedError()`. Runtime executor/store +work may be developed behind an unexported seam, but the command subpaths and docs are not released +as complete until the positive and negative #1350 type fixtures pass. + +### Relay, workers, sagas, and remote sinks + +The relay has its own ports: + +```ts +export type CommandRelayFailureClass = + | 'rejected' + | 'rate_limited' + | 'unavailable' + | 'timeout' + | 'invalid_response' + | 'misconfigured'; + +export type ClaimedCommandOutbox = Readonly<{ + id: string; + executionId: string; + destination: string; + topic: string; + payloadJson: string; + dedupeKey: string; + correlationId: string; + traceparent?: string; + tracestate?: string; + attemptCount: number; + claimToken: string; + claimUntil: Date; +}>; + +export type CommandOutboxDelivery = Readonly<{ + id: string; + destination: string; + topic: string; + payload: CommandJson; + dedupeKey: string; + correlationId: string; + trace?: CommandTraceContext; +}>; + +export type CommandOutboxRelease = + & Readonly<{ + id: string; + claimToken: string; + failure: CommandRelayFailureClass; + }> + & ( + | Readonly<{ disposition: 'retry'; retryAt: Date }> + | Readonly<{ disposition: 'terminal'; terminalAt: Date }> + ); + +export interface CommandOutboxRelayStore { + claim( + request: Readonly<{ + limit: number; + leaseMs: number; + now: Date; + }>, + signal?: AbortSignal, + ): Promise; + markPublished( + request: Readonly<{ + id: string; + claimToken: string; + publishedAt: Date; + }>, + signal?: AbortSignal, + ): Promise; + release( + request: CommandOutboxRelease, + signal?: AbortSignal, + ): Promise; +} + +export interface CommandOutboxSink { + readonly id: string; + publish( + message: CommandOutboxDelivery, + signal?: AbortSignal, + ): Promise; +} +``` + +Claims are bounded and leased. `markPublished` and `release` compare the claim token so an expired +worker cannot acknowledge another worker's lease. Provider adapters choose their correct locking +algorithm; the public port does not pretend `FOR UPDATE SKIP LOCKED` is portable SQL. + +`claim()` returns only rows that are unpublished, non-terminal, due, and either unclaimed or have an +expired lease. A retry release clears the lease and advances `availableAt`; a terminal release +clears the lease and sets `terminalAt`. Neither path changes the stable message ID or dedupe key. +Relay configuration owns bounded attempts and backoff; the row stores only the resulting state. + +The explicit generator emits a visible `defineJob("netscript.command-outbox-relay")` drain job and a +sink registry. Deleting or disabling that job visibly stops delivery without affecting command +commits. The job's own worker idempotency governs a job delivery, not an outbox row's remote effect, +and therefore does not replace row leases or stable message IDs. + +Sink rules: + +- **worker job:** set the queue/message idempotency or deduplication key to outbox `dedupeKey` and + propagate `traceparent`/`tracestate`; +- **saga:** publish a saga message only after local commit, with the outbox ID as idempotency input; + the saga handler still guards redelivery and owns later compensation; +- **stream:** use the stable producer/message identity supported by the stream and keep the consumer + idempotent; +- **HTTP/webhook:** #1364's recipe signs at publish time using runtime secrets and sends the stable + outbox ID as the receiver's idempotency key. Secrets and signatures are not stored in the row. + +A sink acknowledgement means only that the sink's documented acceptance boundary succeeded. The +relay marks the row afterward. A crash between those actions causes redelivery. Marking before +publish is forbidden because it can lose a message permanently. + +The existing saga outbox port is not merged into this port. It is reserved for atomic saga state and +cascade persistence and lacks this command transaction binding. Future implementation may share +private lease utilities after both contracts exist, but their public semantics remain independently +owned. + +### Precise refusal boundary + +The kit refuses these shapes: + +- business rows and receipt/audit/outbox rows cannot be written through the same `TTx`; +- a handler requires an isolation level the configured adapter cannot honor; +- one operation must commit state in two databases, SQL and KV, or any other two stores; +- success requires a remote response before the local transaction can commit; +- a network call, queue publish, saga publish, file write, or process invocation is placed in the + handler's transactional effect path; +- a provider offers only claim → effect → mark semantics rather than a replay receipt in the same + store; or +- a response/payload/fingerprint cannot be represented by the declared codec as canonical I-JSON. + +The remedy is not a “best effort” capability flag. Redesign the local command to commit an intent, +then use a worker or saga for later work. If later work fails, its retry/compensation is a runtime +concern; it cannot roll back the already committed command. + +### Security and privacy + +#### Identity and authorization + +Authentication and authorization complete before `execute()`. The command actor is a narrowed copy, +not a mutable reference to all principal claims. A missing authenticated principal on a +principal-required route is an envelope failure. Background/system commands use an explicit, +allow-listed system subject and do not forge `kind: "principal"`. + +Actor subject, system subject, scope, and correlation values are bounded and validated before any +query. None is interpolated into SQL, topic names, log templates, or telemetry attribute keys. +Correlation is an observability value, never an authorization credential. + +#### Idempotency and canonicalization + +Callers should generate at least 128 bits of idempotency entropy. Keys are 16–256 UTF-8 bytes, +transported only over authenticated/encrypted channels, hashed before storage, and never accepted as +proof of identity. Low-entropy keys remain vulnerable to guessing even when hashed; the digest is +data minimization, not password hardening. + +Fingerprint and response codecs impose depth, item-count, and byte limits before canonicalization. +Non-finite numbers and non-I-JSON values are rejected. Parsing a stored response repeats these +limits to avoid treating the database as trusted input. + +#### Audit/outbox data + +Applications put only the minimum operational data into `data` and `payload`. Credentials, session +tokens, raw authorization claims, encryption keys, and unredacted request bodies are forbidden. +Storage encryption, backups, retention, erasure, and row-level access remain deployment concerns. +The command DB role may insert audit/outbox rows; relay roles may lease/update outbox rows but +should not mutate business/audit/receipt tables. + +The sink registry is configured code, not a destination URL from an outbox row. That prevents an +untrusted command payload from choosing an arbitrary host. HTTP headers are constructed from an +allow-list, with CR/LF and W3C trace-context validation. + +#### Resource exhaustion + +The executor enforces maximum records, canonical bytes, string lengths, and transaction timeout. The +relay enforces batch size, lease duration, maximum attempts, backoff, and cancellation. A +permanently failing row moves to an explicitly configured terminal/dead-letter state; it is never +silently marked published. + +### OpenTelemetry vocabulary + +V1 adds these constants/builders to `@netscript/telemetry/attributes`: + +```ts +export const CommandSpanNames = { + EXECUTE: 'command.execute', + OUTBOX_RELAY: 'command.outbox.relay', + OUTBOX_PUBLISH: 'command.outbox.publish', +} as const; + +export const CommandAttributes = { + NAME: 'netscript.command.name', + DEFINITION_VERSION: 'netscript.command.definition.version', + OUTCOME: 'netscript.command.outcome', + IDEMPOTENCY: 'netscript.command.idempotency', + ISOLATION: 'netscript.command.isolation', + STORE_PROVIDER: 'netscript.command.store.provider', + AUDIT_COUNT: 'netscript.command.audit.count', + OUTBOX_COUNT: 'netscript.command.outbox.count', +} as const; +``` + +Allowed values are closed: + +| Attribute | Values / bound | Default | +| -------------------------------------- | --------------------------------------------------------------------- | ---------------------------- | +| `netscript.command.name` | registered definition name, max 120 | required | +| `netscript.command.definition.version` | positive integer | required | +| `netscript.command.outcome` | `applied`, `replayed`, `conflict`, `rejected`, `failed`, `cancelled` | required | +| `netscript.command.idempotency` | `claimed`, `replayed`, `not_requested`, `missing`, `mismatch`, `busy` | required | +| `netscript.command.isolation` | requested enum value or `default` | required | +| `netscript.command.store.provider` | adapter's bounded provider ID | required | +| audit/outbox counts | non-negative bounded integers | on successful handler/replay | + +The command execution span is `INTERNAL` beneath the active RPC/server span. Relay publish is a +`PRODUCER` span; a later worker/saga/stream creates its normal consumer span using propagated W3C +context or a span link where deferred/batch semantics require it. + +Default command telemetry must not contain raw scope, actor/system subject, idempotency key or +digest, request hash, expected/actual version, receipt/outbox/audit IDs, payload/response data, +arbitrary topic/destination, or correlation ID. Trace IDs already exist in span context. Application +logs may include a validated correlation ID under their redaction/access policy; telemetry +inclusion, if ever allowed, is an explicit opt-in FCP policy. + +Metrics may count executions and record duration by command name, outcome, idempotency state, and +provider only. No unbounded identifier becomes a metric dimension. Errors record `error.type` as the +stable failure kind, not a driver message or stack-derived value. + +### Injected-failure conformance + +`@netscript/service/commands/testing` exposes a test-only `CommandFaultController`. Production +constructors do not accept it. The canonical named seams are: + +| Seam | Expected invariant | +| ---------------------------- | -------------------------------------------------------------- | +| `before_transaction` | no store call and no rows | +| `after_claim` | claim rolls back; retry may execute | +| `after_handler` | business writes roll back; no side rows/receipt | +| `after_audit` | business and audit roll back; no outbox/receipt | +| `after_outbox` | business/audit/outbox roll back; no completed receipt | +| `after_receipt_complete` | every write rolls back because commit has not happened | +| `after_commit_before_return` | all rows exist once; same-key retry replays | +| `relay_after_claim` | lease expires/releases; message remains unpublished | +| `relay_after_publish` | message may be observed twice with the same stable ID | +| `relay_after_mark` | row remains published; another relay does not publish it again | + +The shared suite runs the following positive/negative matrix against every provider: + +1. successful applied command with 0/1/many allowed side records; +2. required/forbidden audit and outbox policy failures; +3. same-key/same-hash sequential replay; +4. same-key/different-hash rejection without handler invocation; +5. concurrent identical claims with a barrier around the handler; +6. leader rollback followed by follower execution; +7. bounded busy/timeout classification; +8. CAS zero-match rollback; +9. requested unsupported isolation refusal before begin; +10. serialization/deadlock/busy error with handler invocation count exactly one; +11. invalid/corrupt/incomplete stored receipt refusal without execution; +12. response/payload/fingerprint codec failures, including `Date`, `BigInt`, non-finite numbers, + cyclic values, depth, and byte overflow; +13. abort before begin, during handler, between flush steps, and during relay; +14. every named command fault seam; +15. relay lease expiry, stale-token mark/release, publish-then-crash redelivery, terminal failure, + and graceful shutdown; +16. forbidden telemetry fields and exact allowed enum/count attributes; and +17. a negative control that bypasses the executor or writes one side record with a root client and + proves the same-commit suite fails. + +PostgreSQL is the reference real-provider suite. MySQL and SQL Server must run the same semantic +suite, not mocks with provider labels. SQLite, if proposed, additionally runs multiple-connection +writer contention, busy timeout, process crash/reopen, and lease tests. No adapter earns a +capability row from a type-only fake. + +The suite records database/runtime versions, schema migration digest, exact command, exit code, and +failed test name. Tests clean only resources they positively own. Implementation merge readiness +also includes package tests, doc lint, publish dry run, and the full generated CLI runtime smoke +once after the explicit generators land. + +### Compatibility and migration + +This RFC is additive. Existing service builders, contracts, CRUD handlers, database adapters, worker +jobs, saga definitions, and telemetry keep their current behavior. No existing handler is +automatically wrapped, no table is created at startup, and no default scaffold starts a relay. +Therefore the RFC itself does not require a `breaking` label. + +Adding public subpaths is a coordinated minor release for `@netscript/service`, +`@netscript/database`, and `@netscript/contracts`; the telemetry attributes subpath gains symbols in +the same release train. Every new entrypoint needs module docs/examples, explicit isolated- +declaration-safe exports, `deno doc --lint` over the full package export map, surface-diff review, +clean publish file lists, and a consumer import fixture. The implementation must not make +self-referential bare imports inside those packages. + +Because `jsonCodec()` names `StandardSchemaV1` in a public signature, `@netscript/service` must +declare `@standard-schema/spec` directly in its package import map rather than rely on another +package's transitive resolution. The dependency is already used elsewhere in this workspace but is +not currently declared by the service package. Its exact version follows the normal Deno toolchain +update policy at implementation time. + +An existing application adopts the seam explicitly: + +1. upgrade after #1350 and the command package slices are published; +2. run `netscript db command-store init --database ` and review/apply the migration; +3. compose one `commandStore` and executor in the service infrastructure layer; +4. convert one non-CRUD mutation to a command, preserving its existing contract shape; +5. choose and document idempotency scope, semantic fingerprint, output codec, CAS, audit data, and + outbox topics; +6. run the adapter/failure suite against the application's database; +7. generate/configure the relay and one sink only if the command emits outbox messages; and +8. deploy the relay before depending on timely delivery, then monitor backlog/age/failure metrics. + +For an existing application-owned receipt or outbox, migration is not an automatic table copy. +Implement a bridge that satisfies the logical contract, prove it with conformance, and migrate keys +and encoded responses deliberately. Changing receipt scope, command name, fingerprint, codec, or +definition version without a retention/retry plan can turn valid retries into conflicts; those +changes require release notes and compatibility tests. + +Receipt retention must be at least the maximum advertised client retry window. Deleting a receipt +earlier permits the same key to execute again. Published outbox cleanup must not remove rows still +needed for operational reconciliation. Audit retention is application policy. Exact default +durations remain an FCP question. + +### CLI and scaffold impact + +The current CLI already has `contract add-route` and `service add-handler`. V1 extends those +explicit paths rather than changing every scaffold: + +- `netscript contract add-route --command` adds the opt-in command error map + and requires explicit input/output schemas; +- `netscript service add-handler --command --database ` emits a + command definition stub and router binding in the layered service shape owned by #1362; +- `netscript db command-store init --database ` emits provider-specific models, + migration, and transaction bridge; and +- `netscript generate command-relay --database ` emits the visible worker drain job and + sink registry. + +The proposed service layout is: + +```text +services//src/ + application/commands/.ts + infrastructure/command-store.ts + routers/.ts +database// + schema.prisma + command-store.ts +workers/jobs/ + command-outbox-relay.ts + command-outbox-sinks.ts +``` + +Generators refuse missing #1362 layering, unsupported providers, duplicate models, edited target +files, and routes without declared command errors. They print planned files before writing and never +run database migration/deploy implicitly. + +The normal `netscript init` and generated CRUD example remain unchanged initially. After the +implementation is stable, one neutral non-CRUD command may be added to the full scaffold runtime +fixture as consumer proof. That fixture must demonstrate a lost-response replay, CAS conflict, +same-commit audit/outbox, and relay redelivery without using domain-specific vocabulary. + +Required docs: + +- guide: “Write a transactional command”; +- reference: every new package subpath and logical row/error/telemetry contract; +- operations: relay deployment, backlog, lease, retry, terminal failure, and retention; +- explanation: command versus CRUD versus worker versus saga; +- database matrix with current support/configuration preconditions; +- security/privacy checklist and canonicalization examples; and +- #1364's outbound-webhook recipe using the stable outbox ID and at-least-once wording. + +### Staged implementation + +No product code belongs in this RFC PR. After acceptance, implementation is staged contract-first: + +| Stage | Owning archetype | Deliverable | Required gate | +| ----- | ---------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| 0 | A1/type repair | close #1350's literal error-map and client error-generic defects | positive/negative typed-error fixtures; contracts/SDK publish gates | +| 1 | A1 | `@netscript/contracts/commands` schemas/map and canonical JSON/codec contracts | isolated declarations, doc lint, slow-type, runtime codec negatives | +| 2 | A4 | `@netscript/service/commands` definition/executor over an in-memory conformant fake | semantic law suite, fault seams, forbidden remote/global design review | +| 3 | A2 | `@netscript/database/commands` true `TTx` store and PostgreSQL reference adapter/schema | real PostgreSQL concurrency/fault suite; surface/publish gates | +| 4 | A2 | command telemetry vocabulary and redaction tests | exact span/attribute assertions; forbidden-field tests | +| 5 | A3/A5 | relay store/sink ports and generated workers/saga/stream bridge | lease/crash/redelivery/shutdown tests; no deliver-once claim | +| 6 | A2 | MySQL and SQL Server adapters | same semantic suite on each real provider; SQL Server snapshot config negative | +| 7 | A2, optional | SQLite adapter | adapter export plus writer contention/crash/reopen conformance; otherwise remain unsupported | +| 8 | A6 | schema, route, service-command, and relay generators | emitted samples; focused CLI tests; one full `scaffold.runtime` merge-readiness run | +| 9 | docs | guide/reference/operations/security/compatibility and #1364 integration | docs links/accuracy, executable snippets, published consumer proof | + +Stages may use separate PRs and can be developed in parallel only where their contracts are already +merged. The public feature is not announced as complete until stages 0–6 and the required parts of +8–9 are green. SQLite is not a completeness requirement unless FCP makes it one. + +### Issue and epic decomposition + +No issues are created or mutated by this RFC PR. The recommended board reconciliation is: + +- keep #1361 as the RFC tracking record through discussion/FCP and follow the RFC process for + acceptance/numbering; +- keep #1363 as the `0.0.8` implementation umbrella rather than duplicating it; +- make #1350 a stage-0 dependency, not a vague “RFC-A” reference; +- let #1362 own generated service layering and make command-handler generation depend on it; +- let #1364 own the remote HTTP recipe/template and consume the command outbox when available; +- keep #1293 adjacent: it improves `@netscript/prisma-adapter-mysql` but does not block the current + database package's MySQL transaction subpath; and +- cross-reference the type-soundness umbrella #1278 without merging its broader scope into this + implementation. + +Suggested PR-sized children under #1363: + +| Proposed child | Labels (plus one lifecycle status) | Milestone | +| ------------------------------------------------------- | ------------------------------------------------------------ | ------------ | +| command contracts, errors, JCS codecs | `type:feat`, `area:contracts`, `area:service`, `priority:p1` | `0.0.8` | +| command executor and semantic/fault test kit | `type:feat`, `area:service`, `priority:p1` | `0.0.8` | +| true transaction-client port + PostgreSQL command store | `type:feat`, `area:database`, `priority:p1` | `0.0.8` | +| command OTel vocabulary and privacy tests | `type:feat`, `area:telemetry`, `priority:p1` | `0.0.8` | +| outbox relay and worker/saga sink adapters | `type:feat`, `area:service`, `area:database`, `priority:p1` | `0.0.8` | +| MySQL/SQL Server command-store conformance | `type:feat`, `area:database`, `priority:p1` | `0.0.8` | +| optional SQLite adapter/conformance | `type:feat`, `area:database`, `priority:p2` | FCP decision | +| explicit CLI generators and scaffold consumer | `type:feat`, `area:cli`, `area:service`, `priority:p1` | `0.0.8` | +| command/relay docs and executable examples | `type:docs`, `area:docs`, `area:service`, `priority:p1` | `0.0.8` | + +Each child PR that fully resolves its child issue uses a closing keyword in its body. Children +reference #1363 as an umbrella without closing it. The RFC PR references #1361 without a closing +keyword and never closes an epic/umbrella. + +## Drawbacks + +- The kit adds several public subpaths and durable concepts for what can look like “just a + transaction.” +- Consumer-owned models and migrations are honest but create setup and upgrade work. +- Response codecs and semantic fingerprints are explicit authoring burden. +- Holding an interactive transaction across application logic can increase contention; strict + timeouts and a no-network-I/O rule are necessary. +- Portability requires real-provider conformance, not one mock suite. SQL Server, MySQL, and + potentially SQLite materially increase CI/runtime cost. +- Receipt retention consumes storage and becomes part of API retry compatibility. +- Audit/outbox buffers add memory and transaction writes. +- The type system cannot prevent a closure from capturing a remote client. Review, generated shape, + tests, and doctrine must enforce that boundary. +- An at-least-once relay pushes deduplication responsibility to every downstream effect, which is + correct but not effortless. + +These costs are preferable to a smaller API that silently provides weaker semantics. + +## Rationale and alternatives + +### Why this design + +The design keeps one public promise that adapters can prove: all local records share one store +commit. It reuses current isolation types, Principal-derived identity, Web Crypto, W3C trace +context, telemetry placement, `defineJob`, and saga compensation. New abstractions exist only where +the repository has no equivalent: replay receipts, command-bound audit/outbox rows, an executor, and +adapter conformance. + +The store port is strong rather than configurable because a caller should not need to inspect a +boolean to discover that its audit or receipt is non-atomic. Provider variability still appears in +supported isolation sets, cancellation mode, and conformance status. + +### Rejected alternatives + +#### Reuse `withTransaction()` unchanged + +Rejected because its public callback is asserted as the full root client. It permits code that does +not exist on a real Prisma transaction client. The implementation must correct or bypass the helper +with a true `TTx`. + +#### Put everything in `@netscript/database` + +Rejected because command identity, actor propagation, contract errors, handler policy, and +presentation are application/service concerns. Database owns only the transaction-bound persistence +and providers. + +#### Add `@netscript/commands` now + +Rejected as premature surface growth. A service subpath is sufficient until a second independent +host proves package-level reuse. The database subpath keeps provider code out of service. + +#### Framework-owned hidden tables or startup migration + +Rejected because a published library cannot silently own a product database, migration history, +retention, or provider-specific native types. Explicit generated consumer files are reviewable and +migrable. + +#### Consumer-declared arbitrary receipt adapter without a generator + +Rejected as the only path because drift in unique keys, nullability, response encoding, or lease +fields would undermine conformance. The logical port remains structural, but the supported path +emits a reviewed schema/bridge. + +#### Global `CONFLICT` in `baseContract` + +Rejected because it widens non-command contracts and does not distinguish optimistic conflict from +idempotency misuse. Route-local command errors are more precise and depend explicitly on #1350. + +#### `expectVersion(current)` + +Rejected because read-then-compare is racy. Optimistic concurrency must be enforced by a conditional +mutation or provider-specific locking algorithm. + +#### `maxIsolation` + +Rejected because isolation support is a provider/configuration set, not one uniformly ordered +portable ceiling. SQL Server `Snapshot` alone demonstrates the configuration issue. + +#### Store arbitrary `unknown` responses or payloads + +Rejected because replay requires stable round trips across deployments and providers. Explicit +I-JSON codecs and canonical text make failure and compatibility visible. + +#### Automatic transaction retries + +Rejected because replaying an application callback can repeat captured non-transactional work, +clock/ID reads, or bugs. The receipt makes whole-request retry explicit and observable. + +#### Direct publish before or after commit + +Publishing before commit can announce state that rolls back. Publishing after commit can lose the +message if the process crashes. A same-commit outbox plus at-least-once relay is the narrow durable +answer. + +#### Weak KV command mode + +Rejected because claim → effect → mark has a crash window and cannot replay the relational response +inside the business commit. Existing worker idempotency remains valid for its delivery scope; it is +not relabeled as command atomicity. + +#### Use a saga for every local command + +Rejected because a saga is unnecessary overhead for one atomic store mutation and does not replace +the local transaction. Sagas begin at multiple commits, time, remote work, or compensation. + +#### Event sourcing + +Rejected because this RFC does not make events authoritative state, rebuild aggregates, or define an +event schema/runtime. The outbox is a delivery intent derived from an ordinary transaction. + +#### Ambient transaction context + +Rejected because async-local or global context hides ownership and makes tests, nesting, and +cancellation harder to reason about. The transaction client is an explicit handler field. + +### Impact of not doing this + +Applications continue to hand-roll incompatible receipt tables, request hashes, outbox leases, audit +ordering, failure mapping, and telemetry—or omit them. Generated non-CRUD examples cannot teach a +truthful production boundary, and adapters cannot be held to one portable conformance suite. + +## Breaking changes and migration + +The RFC is additive and opt-in. It changes no current export, handler, schema, or scaffold by +itself. Future implementation adds focused subpaths and generator commands in minor releases. +Applications migrate command by command as described above; no automatic CRUD conversion occurs. + +If FCP chooses to change an existing global contract error map or root export instead, that decision +must be re-evaluated for breaking surface impact. This draft does not propose either change. + +## Prior art + +- Prisma interactive transactions, transaction options, documented idempotent API design, and + optimistic concurrency establish the provider-facing mechanics. +- RFC 8785 JCS provides deterministic JSON bytes for hashing instead of a local key-sorting + convention. +- Deno KV versionstamp checks demonstrate optimistic atomic batches and, equally importantly, why + that model is not an interactive SQL transaction. +- NetScript's `WorkerIdempotencyPort` demonstrates claim/apply/release for delivery, while its + different crash boundary explains why command receipts remain separate. +- NetScript's saga message/compensation and queue delivery surfaces own multi-step work after the + command boundary. +- The reserved `SagaOutboxPort` establishes that saga durability needs an outbox, but its T2 + lifecycle and lack of command transaction binding keep the public contracts separate. +- NetScript telemetry already centralizes job/saga/execution attributes and W3C propagation; the + command vocabulary follows that placement with stricter cardinality defaults. + +Primary references: + +- [Prisma transactions and isolation](https://www.prisma.io/docs/orm/prisma-client/queries/transactions) +- [PostgreSQL transaction isolation](https://www.postgresql.org/docs/current/transaction-iso.html) +- [SQL Server transaction isolation](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-ver17) +- [SQLite transactions](https://www.sqlite.org/lang_transaction.html) +- [Deno KV transactions](https://docs.deno.com/deploy/kv/transactions/) +- [RFC 8785 JSON Canonicalization Scheme](https://www.rfc-editor.org/info/rfc8785/) +- [W3C Trace Context](https://www.w3.org/TR/trace-context/) +- [OpenTelemetry tracing API](https://opentelemetry.io/docs/specs/otel/trace/api/) +- [OpenTelemetry attribute requirement levels](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) + +## Unresolved questions + +These questions are intentionally reserved for discussion/FCP. None changes the one-store atomicity +contract: + +1. **Idempotency default.** Must every v1 command require a key, or may a definition explicitly + choose `mode: "optional"` and emit `not_requested`? Recommendation: required by default, explicit + optional only for controlled internal callers. +2. **SQLite release timing.** Is a real SQLite adapter and contention suite required for the first + stable command-kit release, or does SQLite remain unsupported until a later adapter PR? + Recommendation: later; do not delay the reference/client-server adapters or claim current + support. +3. **Correlation telemetry.** Should a validated correlation ID be an opt-in command attribute under + an explicit redaction/cardinality policy, or remain durable-row/log-only? Recommendation: + durable-row/log-only by default. +4. **Retention defaults.** What minimum receipt retry window and published-outbox cleanup defaults + should generators document? Recommendation: require explicit deployment values until operational + evidence establishes safe defaults; audit remains application policy. + +The following are not open: no hidden schema ownership, no weak KV semantics, no global conflict +error, no automatic callback retry, no read-then-compare concurrency, no remote I/O in the command +transaction, and no exactly-once delivery claim. + +## Future possibilities + +Possible later work, requiring its own evidence and possibly another RFC: + +- a second host proving that `@netscript/service/commands` should become an independent package; +- provider-native JSON projections behind the canonical-text contract; +- a formal schema registry for outbox payloads; +- configurable opt-in correlation telemetry with tested redaction; +- receipt archival/partition helpers; +- additional stores that can genuinely satisfy the same-commit port; +- tooling that statically flags known remote clients captured by command handlers; and +- a dashboard view joining a trace to durable command/audit/outbox state. + +These possibilities do not expand v1's transaction boundary. From 2dfe8c84135fd9fc52c7e76b53033ba09d853ebf Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 19:29:45 +0200 Subject: [PATCH 04/10] docs(harness): hand off command kit RFC review --- .../context-pack.md | 28 +++-- .../final-handoff.md | 117 ++++++++++++++++++ .../plan.md | 2 +- .../research.md | 1 + .../worklog.md | 25 ++-- 5 files changed, 153 insertions(+), 20 deletions(-) create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md index fe2f98038e..70a5c4aa2e 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md @@ -6,7 +6,7 @@ | -------------- | --------------------------------------------------------------- | | Run ID | `docs-rfc-command-composition-kit--rfc` | | Branch | `docs/rfc-command-composition-kit` | -| Current phase | `rfc-authoring` | +| Current phase | `plan-eval-ready` | | Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | | Scope overlays | `SCOPE-docs`, `SCOPE-service` | @@ -16,7 +16,8 @@ The run is active on the exact requested branch/base in the sole daemon-attached Bootstrap commit `ad643e15...` and research/plan commit `e0b98f289...` were pushed by explicit refspec; draft PR #1389 is live at `status:plan`. The full re-baseline and plan gate are complete, and the RFC now carries the exact contracts, semantic laws, adapter truth, relay boundary, -conformance plan, migration, and decomposition. No product code or export changed. +conformance plan, migration, and decomposition. Final docs/RFC/PR evidence is green. No product code +or export changed. ## Completed @@ -33,16 +34,19 @@ conformance plan, migration, and decomposition. No product code or export change `Draft` through maintainer discussion. - Tightened the S2 surface with attempt identity across receipt/audit/outbox, schema-backed outbox codecs, deterministic scope inputs, and explicit relay retry/terminal dispositions. +- Passed docs links/accuracy, scoped format/diff, RFC structural/terminology, review-thread, and PR + check reconciliation; captured current package doc-lint findings as future implementation bars. ## In Progress -- S2 source-alignment review and coherent RFC commit/push. +- Final handoff commit/push and PR transition to `status:plan-eval`. ## Next Steps -1. Commit/push S2 and post its implementation-phase evidence comment without starting evaluation. -2. Run docs/RFC, source-alignment, JSR-design, diff/lock, and PR/thread gates in S3. -3. Write `final-handoff.md`, update the PR/body, and stop at `status:plan-eval` for root-led review. +1. Commit/push the final evidence and handoff by explicit refspec. +2. Update the draft PR body and replace `status:plan` with `status:plan-eval`. +3. Root orchestrator steers the existing Fable session using `final-handoff.md`; this generator does + not launch or self-certify evaluation. ## Key Decisions @@ -64,12 +68,12 @@ conformance plan, migration, and decomposition. No product code or export change ## Gates -| Gate family | Current status | Evidence | -| ----------- | ------------------------------------------------------------ | --------------------------- | -| Static | bootstrap/API probes PASS as classified; final pending | `worklog.md` gate table | -| Fitness | planned-surface and runtime-law design PASS | `plan.md` and `research.md` | -| Runtime | N/A for docs PR | no product mutation | -| Consumer | current CLI/scaffold analysis PASS; generated proof deferred | S1 re-baseline | +| Gate family | Current status | Evidence | +| ----------- | ------------------------------------------------------------- | --------------------------- | +| Static | PASS; format/diff/docs/RFC/PR gates green | `worklog.md` gate table | +| Fitness | PASS_DESIGN with existing doc-lint baseline findings recorded | `plan.md` and `research.md` | +| Runtime | N/A for docs PR | no product mutation | +| Consumer | current CLI/scaffold analysis PASS; generated proof deferred | S1 re-baseline | ## Open Questions diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md new file mode 100644 index 0000000000..642744ab1a --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md @@ -0,0 +1,117 @@ +# Final Handoff: production command composition kit RFC + +## Delivery identity + +| Field | Value | +| ------------------------- | ---------------------------------------------------------------------------- | +| Draft PR | [rickylabs/netscript#1389](https://github.com/rickylabs/netscript/pull/1389) | +| Branch | `docs/rfc-command-composition-kit` | +| Pinned base | `origin/main@fac9e339042c5394bf882311657d8981d353a1c3` | +| Reviewed RFC content HEAD | `ad16c42f8e717c727ae00bb66c694f4073234a39` | +| Run directory | `.llm/runs/docs-rfc-command-composition-kit--rfc/` | +| RFC | `rfcs/0000-command-composition-kit.md` (`0000`, `Draft`) | + +The immutable final branch HEAD is the commit that contains this handoff. A Git commit cannot embed +its own not-yet-computed object ID; the exact post-push HEAD is therefore recorded in the final +`[PHASE: PLAN-EVAL]` PR comment and the root handoff response. `ad16c42f8...` is the reviewed RFC +content commit; the containing final commit changes harness evidence only. + +## Locked decisions + +1. The only atomicity claim is one transaction on one conformant store. Business writes, a keyed + replay receipt, audit rows, and outbox rows share that commit. +2. Command semantics live in `@netscript/service/commands`; transaction persistence in + `@netscript/database/commands`; opt-in client errors in `@netscript/contracts/commands`; command + telemetry extends `@netscript/telemetry/attributes`. No new package or root re-export is + proposed. +3. Consumer-owned, provider-aware generated schema/migrations bind side rows to the true transaction + client. Hidden framework tables, startup migrations, and a weak capability mode are rejected. +4. Receipt identity is `(scope, commandName, SHA-256(idempotencyKey))`; request identity is SHA-256 + over RFC-8785 JCS bytes for the exact versioned semantic request. Replay outputs and outbox + payloads use explicit Standard Schema-backed codecs. +5. Optimistic concurrency is a repository conditional mutation; zero rows becomes a typed conflict. + There is no read-then-compare helper and no hidden transaction-callback retry. +6. One `executionId` joins receipt/audit/outbox evidence. Replay creates no new rows. Committed + incomplete or undecodable receipts are corruption, never permission to execute again. +7. Remote I/O is outside the command callback. The relay uses stable message identity, leases, + stale-token checks, retry/terminal disposition, and at-least-once wording. Workers, sagas, + streams, and webhook receivers still own downstream deduplication/idempotency. +8. PostgreSQL is the reference target; MySQL and SQL Server are conforming targets only after the + same real-provider suite. SQLite remains unclaimed pending an adapter/contention suite. Deno KV + and every cross-store shape are refused in v1. +9. Default telemetry is bounded and redacted: no raw scope, actor, key/hash, request hash, version, + correlation ID, durable row ID, payload, response, or arbitrary destination/topic attribute. +10. This PR is documentation only. RFC numbering, FCP, implementation, issue/milestone mutation, + merge, and release remain maintainer/orchestrator work. + +## Unresolved FCP questions + +1. Whether idempotency is mandatory for every v1 command or may be explicitly optional for + controlled internal callers. Recommendation: required by default; explicit opt-out only. +2. Whether SQLite conformance is a first-release requirement. Recommendation: later and unclaimed + until real contention/crash tests pass. +3. Whether correlation ID may become an opt-in telemetry attribute. Recommendation: durable-row and + policy-controlled log only by default. +4. Receipt retry-window and published-outbox cleanup defaults. Recommendation: require explicit + deployment values until operational evidence exists; audit retention remains application policy. + +## Validation evidence + +| Evidence | Result | +| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| `deno fmt --check rfcs/0000-command-composition-kit.md .llm/runs/docs-rfc-command-composition-kit--rfc` | PASS; 10 owned Markdown files | +| `git diff --check` plus `origin/main...HEAD` changed-file audit | PASS; only RFC + required run artifacts, no package/plugin/lock change | +| `rtk proxy deno task docs:links` | PASS; 102 docs, 0 broken links, 0 broken anchors, 0 orphans | +| `rtk proxy deno task docs:accuracy` | PASS; repository accuracy/discoverability assertions | +| Focused RFC frontmatter/required-section/forbidden-vocabulary assertion | PASS; `0000`, `Draft`, #1361, all required sections; no forbidden domain terms | +| Focused transaction callback probe | Existing `withTransaction` incorrectly compiled root-only/nested transaction calls; defect proven, probe removed | +| Focused SDK typed-error probe | Expected TS2339 (`error.code` on `never`) reproduced #1350; probe removed | +| Focused future command type-shape probe | PASS after exposing the required direct `@standard-schema/spec` service dependency; probe removed | +| Structured full-entrypoint doc-lint baseline | Service `0`; database combined `0`; contracts `9` existing private-type findings; telemetry `7` existing findings; reports exited `0` | +| `agentic:review-threads` on #1389 | PASS; 0 threads, 0 unanswered | +| `agentic:pr-checks` on #1389 at RFC HEAD | PASS; 15 reconciled checks, 0 current failures; docs-only lanes intentionally skipped | +| Product/CLI runtime E2E | N/A by scope; no product, generated output, schema, package export, or lock changed | + +No evaluator verdict is claimed. The existing contracts/telemetry doc-lint findings are baseline +implementation constraints, not changes or waivers introduced by this PR. + +## Board reconciliation proposal + +No issue, milestone, or board item was mutated by this generator. + +- Keep #1361 as the RFC ratification record; this PR references it without a closing keyword. +- Keep #1363 as the `0.0.8` implementation umbrella and create PR-sized children only after RFC + acceptance. +- Treat #1350 as stage 0 for client-visible typed command errors. +- Let #1362 own generated service layering; command-handler generation depends on that shape. +- Let #1364 own the outbound HTTP/webhook recipe and consume stable command-outbox IDs. +- Keep #1293 adjacent rather than making the lower-level MySQL adapter hook a false atomicity + prerequisite; cross-reference #1278 for broader type-soundness work. +- Do not assign the RFC number, close #1361, close an umbrella, or move milestones from this PR. + +## Exact Fable-review handoff + +The root orchestrator should resume the existing Claude Fable 5 session and send exactly: + +> Review draft PR rickylabs/netscript#1389 as the separate PLAN-EVAL / cross-RFC reviewer. Do not +> author implementation code, open another session, assign an RFC number, merge, close issues, or +> mutate milestones. Read +> `.llm/runs/docs-rfc-command-composition-kit--rfc/{supervisor,research,plan,worklog,context-pack,drift,final-handoff}.md`, +> `rfcs/0000-command-composition-kit.md`, the carried RFC-B proposal, RFC-A/RFC-C where they share +> seams, current `origin/main@fac9e339042c`, and live #1361–#1364/#1350/#1293/#1278/#1347. Challenge +> package ownership and dependency direction; true transaction-client binding; receipt races and +> canonical request identity; CAS/isolation/provider claims; same-commit audit/outbox invariants; +> relay lease/terminal/crash semantics; worker/saga boundary; typed error feasibility; telemetry +> redaction/cardinality; JSR/slow-type/publish consequences; generator ownership; refusal boundary; +> and whether the four FCP questions are the only unresolved policy. Check specifically for hidden +> exactly-once, distributed-transaction, ORM, event-sourcing, or domain-specific assumptions. Return +> one structured PR comment beginning `**[PHASE: PLAN-EVAL] [VERDICT: APPROVED]**` or +> `**[PHASE: PLAN-EVAL] [VERDICT: CHANGES_REQUESTED]**`, with numbered findings tied to exact RFC +> sections and a concise next action. Do not edit this branch; the root orchestrator owns +> remediation and the later independent Qwen adversarial pass. + +## Generator stop condition + +After this handoff is pushed, the draft PR body is reconciled, and its sole lifecycle label is +`status:plan-eval`, generator work stops. Fable review and Qwen adversarial evaluation remain +external and pending; the PR stays draft and unmerged. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md index 4e31f612ef..16bbf11b13 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md @@ -6,7 +6,7 @@ | ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | | Run ID | `docs-rfc-command-composition-kit--rfc` | | Branch | `docs/rfc-command-composition-kit` | -| Phase | `rfc-authoring` | +| Phase | `plan-eval-ready` | | Target | `rfcs/0000-command-composition-kit.md` plus harness evidence | | Delivery profile | `SCOPE-docs` with `SCOPE-service` consumer analysis | | Described implementation | A1 contracts, A2 database/telemetry adapters, A3 relay runtime, A4 service DSL, A5 thin plugin consumers, A6 CLI generators | diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md index 845a9f6400..f27b728c48 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md @@ -36,6 +36,7 @@ | R17 | Trace propagation already uses W3C `traceparent`/`tracestate` across service, workers, and sagas. OTel producer/consumer spans or links can join deferred delivery without storing arbitrary trace attributes. | Service builder, worker dispatcher, saga delivery; W3C Trace Context and OTel tracing API. | | R18 | #1361 is ratification-only and already has an implementation issue. #1362–#1364 are open at `0.0.8`; #1350 is open at `0.0.7`; no new issue is needed from this PR. | Live GitHub issue reads on 2026-08-08. | | R19 | The package-neutral codec signature is structurally sound with Zod, but `@netscript/service` does not currently declare `@standard-schema/spec`; a future public signature must add that dependency directly. | Focused S2 type-shape probe initially failed import resolution, passed after using the workspace's locked `jsr:@standard-schema/spec@1.1.0`, and was removed; `deno why` confirmed the locked module. | +| R20 | Current full-entrypoint doc-lint is clean for service/database but already reports private-type/JSDoc findings in contracts and telemetry. The future subpaths must not hide behind that baseline and must add zero new findings. | Structured `run-deno-doc-lint.ts`: service `0`, database combined `0`, contracts `9` private-type findings, telemetry `7` combined findings (`6` private-type, `1` missing JSDoc); all report commands exited `0`. | ## Primary documentation diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md index 833fbace2e..617b5209f3 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md @@ -93,6 +93,9 @@ capabilities. | 2026-08-08 | S2 | boundary proof | Kept remote delivery post-commit and at least once; separated the existing saga outbox and worker delivery claims from the command receipt/store guarantee. | | 2026-08-08 | S2 | surface design | Specified focused service/database/contracts subpaths and telemetry additions, JSR/slow-type/publish consequences, migration ownership, and staged implementation without changing exports. | | 2026-08-08 | S2 | type-shape probe | Checked a synthetic command definition against current DB types, Zod, and Standard Schema. Initial resolution exposed the missing service dependency; direct JSR import passed; probe removed. | +| 2026-08-08 | S3 | docs/RFC gates | Scoped format/diff, repository docs links/accuracy, RFC frontmatter/section/terminology assertions, and docs-only changed-file audit passed. | +| 2026-08-08 | S3 | JSR baseline | Full-entrypoint doc-lint reported service 0, database combined 0, contracts 9 existing private-type findings, and telemetry 7 existing findings; no package file changed. | +| 2026-08-08 | S3 | PR reconciliation | Review-thread gate passed with 0 threads/unanswered; PR-check gate passed with 15 checks and 0 current failures (docs-only lanes intentionally skipped). | ## Decisions @@ -128,14 +131,21 @@ capabilities. | Focused transaction type probe | `deno check --unstable-kv packages/database/rfc-command-probe.ts` | EXPECTED_FAIL_MISSED | Exit 0 proves the callback surface is too broad; temporary probe removed. | | Focused typed-error probe | `deno check --unstable-kv packages/sdk/rfc-command-probe.ts` | EXPECTED_FAIL | Exit 1 with TS2339 on `error.code`; temporary probe removed. | | Focused RFC type-shape probe | `deno check --unstable-kv packages/service/rfc-command-contract-probe.ts` | PASS_AFTER_FINDING | First run found missing service Standard Schema mapping; direct locked import passed; probe removed. | -| Docs/link/format gates | pending S3 | NOT_RUN | RFC drafting begins in S2. | +| Markdown format | `deno fmt --check rfcs/... .llm/runs/...` | PASS | 10 owned Markdown files checked. | +| Diff hygiene | `git diff --check` and changed-file audit | PASS | Only the RFC and required run directory differ from the pinned base; no lock/product change. | +| Docs links | `rtk proxy deno task docs:links` | PASS | 102 docs; 0 broken links, 0 broken anchors, 0 orphans. | +| Docs accuracy | `rtk proxy deno task docs:accuracy` | PASS | Saga/storefront/path/CLI/Fresh accuracy checks passed. | +| RFC structure/terminology | focused `deno eval` frontmatter/section/forbidden-term assertion | PASS | Draft/0000/#1361 and all required sections present; forbidden domain vocabulary absent. | +| PR review threads | `rtk proxy deno task agentic:review-threads -- ... --pr 1389 --pretty` | PASS | 0 threads; 0 unanswered. | +| PR checks | `rtk proxy deno task agentic:pr-checks -- ... --pr 1389 --pretty` | PASS | 15 reconciled checks; 0 current failures; docs-only CI lanes skipped under explicit labels. | ### Fitness Gates -| Gate | Result | Evidence | Notes | -| --------------------------------- | ----------- | ------------------------------------------ | ------------------------------------------------------------- | -| F-5/F-6/F-7 planned surface audit | PASS_DESIGN | `research.md` JSR/public-surface table | Design-time only; implementation gates specified per subpath. | -| F-13 runtime invariants | PASS_DESIGN | `plan.md` semantic laws and relay boundary | RFC must carry the exact injected-failure matrix in S2/S3. | +| Gate | Result | Evidence | Notes | +| --------------------------------- | --------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | +| F-5/F-6/F-7 planned surface audit | PASS_DESIGN | `research.md` JSR/public-surface table | Design-time only; implementation gates specified per subpath. | +| F-13 runtime invariants | PASS_DESIGN | `plan.md` semantic laws and relay boundary | RFC must carry the exact injected-failure matrix in S2/S3. | +| Current package doc-lint baseline | PASS_WITH_BASELINE_FINDINGS | structured full-entrypoint reports | service/database combined 0; contracts 9 and telemetry 7 pre-existing findings; changed surface is docs-only. | ### Runtime Gates @@ -151,5 +161,6 @@ capabilities. ## Handoff Notes -- Root orchestrator should inspect the final RFC contracts and capability matrix first, then compare - every unresolved question with #1361 acceptance and the final `research.md` evidence table. +- Final handoff is `final-handoff.md`. The root orchestrator should inspect the RFC's public + contracts, semantic laws, adapter matrix, and refusal boundary first, then use the exact Fable + prompt there. No evaluator was launched by this generator. From 62304176ffafbb8d50417b36c405b0bf05ef364f Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 19:30:51 +0200 Subject: [PATCH 05/10] docs(harness): clarify external review handoff --- .../docs-rfc-command-composition-kit--rfc/final-handoff.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md index 642744ab1a..e4959e4680 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md @@ -13,8 +13,8 @@ The immutable final branch HEAD is the commit that contains this handoff. A Git commit cannot embed its own not-yet-computed object ID; the exact post-push HEAD is therefore recorded in the final -`[PHASE: PLAN-EVAL]` PR comment and the root handoff response. `ad16c42f8...` is the reviewed RFC -content commit; the containing final commit changes harness evidence only. +non-verdict PLAN-EVAL handoff PR comment and the root handoff response. `ad16c42f8...` is the +reviewed RFC content commit; the containing final commits change harness evidence only. ## Locked decisions From 122301d25f4055bfebffefeb3aec2b23c707cfca Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 20:18:05 +0200 Subject: [PATCH 06/10] =?UTF-8?q?docs(harness):=20record=20PLAN-EVAL=20ver?= =?UTF-8?q?dict=20for=20RFC-B=20=E2=80=94=20FAIL=5FPLAN=20cycle=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cross-family evaluator (Fable 5 high, owner-designated). Findings F-B1..F-B7; core transaction/receipt/relay laws verified honest. Deep-dive delegation recorded (wf_b3416478-edf, Opus 5 xhigh). Co-Authored-By: Claude Fable 5 --- .../plan-eval.md | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 .llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md new file mode 100644 index 0000000000..544cc3610e --- /dev/null +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md @@ -0,0 +1,132 @@ +# PLAN-EVAL — docs-rfc-command-composition-kit--rfc (RFC-B, PR #1389) + +| Field | Value | +| --- | --- | +| Verdict | **FAIL_PLAN** (PR-comment vocabulary: CHANGES_REQUESTED) — cycle 1 of 2 | +| Evaluator | Claude Fable 5 · high — owner-designated cross-family PLAN-EVAL authority (in-turn owner directive, 2026-08-08), separate session/family from the generator (Codex, per run supervisor.md) | +| Route override | Lane-policy Minimax route superseded by explicit owner direction (this Fable session evaluates; OpenRouter/OpenHands/Qwen prohibited here; root owns the later Qwen pass) | +| Evaluated | RFC `rfcs/0000-command-composition-kit.md` @ `ad16c42f8` (branch HEAD `62304176f`), run artifacts, PR #1389, live board (#1361–#1364, #1350, #1293, #1278, #1362), worktree source at baseline `fac9e339042c` | +| Delegations | Workflow `wf_b3416478-edf` (script committed pre-execution on the seed-run branch): `dd:rfc-b-semantics`, Opus 5 · xhigh, read-only/return-only; evidence reviewed and adopted by this evaluator | + +## Plan-gate checklist walk + +| Box | Status | Evidence | +| --- | --- | --- | +| Research present and current | ✓ | 20 baseline findings (R1–R20), several execution-verified (probe `deno check` runs, `deno doc` on the locked oRPC contract builder); carried proposal adjudicated row-by-row with 12 rejections | +| Decisions locked | ✓ | L0–L13 with rationale; refusal boundary and not-open list are exemplary honesty | +| Open-decision sweep | **✗** | The four FCP questions are individually safe (adjudicated below), but the sweep found **three undeclared decisions that force rework if deferred** (Findings 1–3) — automatic unchecked box | +| Commit slices | ✓ | Docs-run slices evidenced; implementation staged 0–9 with owning archetypes and gates | +| Risk register | ✓ | Present with mitigations | +| Gate set selected | ✓/− | Conformance suite (17-item matrix + fault seams) is the strongest artifact in either RFC; two gaps folded into Findings 4–5 | +| Deferred scope explicit | ✓ | Non-scope + not-open lists precise | +| jsr-audit | ✓ | Per-subpath publish-consequence table with gates; `@standard-schema/spec` direct-dependency requirement verified correct | + +## Verdict: FAIL_PLAN — findings (severity-ranked) + +**The core promise is verified honest and internally consistent**: one store transaction, explicit +`TTx` (no ambient state — grep-verified against the repo's existing ALS usage), DB-constraint +idempotency, at-least-once relay with stable identity, no hidden migrations, no exactly-once. The +failures are three boundary decisions taken silently plus citable corrections. + +### F-B1 (critical) — `claimReceipt`'s unique-violation-inside-transaction algorithm is unspecified + +The design correctly rejects check-then-act, but never says how a losing insert becomes +`{kind:'replay'}` **without aborting the enclosing transaction**. On PostgreSQL a unique +violation poisons the transaction (25P02) — a savepoint or `INSERT … ON CONFLICT DO NOTHING +RETURNING` + follow-up `SELECT` is mandatory; SQL Server (error 2627, statement-level) and MySQL +(`INSERT IGNORE`) diverge. The RFC grants adapter-algorithm freedom only for the **relay** claim, +and `callbackAttempts: 'one'` + "call `store.transaction()` once" forbids the retry-outside +strategy. The bounded `busy`/`retryAfterMs` path likewise needs provider lock-timeout mechanics +(`SET LOCAL lock_timeout` / `innodb_lock_wait_timeout` / `SET LOCK_TIMEOUT`) — unmentioned. +**Repair:** add a normative "receipt claim algorithm" subsection (per-provider strategies + +lock-timeout mechanics + conformance items proving no transaction poisoning), or add it as an +explicit FCP question with the provider strategies enumerated. Deferring silently reworks Stage 3. + +### F-B2 (critical) — Relay-port package ownership is a hole that can invert the dependency arrow + +`CommandOutboxRelayStore`/`CommandOutboxSink`/`CommandOutboxDelivery` have **no row** in the +ownership table; `CommandOutboxDelivery.payload: CommandJson` + `trace?: CommandTraceContext` +reference **service-owned** types; Stage 5 says archetype A3/A5 while the child-issue row says +`area:service, area:database`. Placing the relay ports in `database/commands` forces +database→service — the cycle the RFC's own L3 forbids. **Repair:** add the ownership rows and +decide the package now (e.g. relay store contract in `@netscript/database/commands` with the +delivery value types moved to a shared neutral location, or relay wholly in +`@netscript/service/commands` with database providing only the store adapter). Also state +explicitly that `service → database` is a **new** package edge and `packages/service/deno.json` +must declare it (verified absent today). + +### F-B3 (major) — Reuse-vs-reinvent against `@netscript/queue` is undecided and unrecorded + +`packages/queue/adapters/postgres.adapter.ts` already implements Postgres claim +(`FOR UPDATE SKIP LOCKED`, :373-396), visibility-timeout lease, redelivery, max-attempts, and a +dead-letter store — the exact mechanics the relay re-derives. The rejected-alternatives list has +no entry for it (A7 wrap-don't-reinvent; AGENTS.md rule 3). The *insert* side genuinely cannot +reuse the queue (it must join the business transaction); the *claim/lease/DLQ* side has no such +constraint. **Repair:** add the rejected-alternative entry with a real decision — reuse the +queue's claim/lease/DLQ mechanics behind the relay store port, or record precisely why not. +Related (same section): the queue's `ensureSchema()` issues runtime `CREATE TABLE IF NOT EXISTS` +(:319-369; dead-letter store :160-172) — the very pattern this RFC's no-hidden-migrations rule +forbids. Scope the rule to the command kit explicitly or call for the reconciliation issue; +otherwise the RFC ships doctrine a sibling package already violates. + +### F-B4 (major) — Scope instability silently defeats idempotency; no negative test + +`scope({input, actor})` is application code inside the receipt unique key. A scope that varies +across retries of the same intent lands the same idempotency key in a **different** receipt row — +the handler runs again and no law fires (key-reuse law is keyed on the full receipt key). Prose +says "must not vary" with no enforcement; conformance item 4 covers only same-key/different-hash. +**Repair:** add negative conformance items — same key + different scope, and same key + renamed +command — asserting the outcome the RFC intends (execute-as-new is the honest answer; say it), +plus a determinism requirement on `scope()` mirroring `fingerprint()`'s. + +### F-B5 (medium) — MySQL `SNAPSHOT` is an undeclared prerequisite of "conforming v1 target" + +`packages/prisma-adapter-mysql/src/adapter.ts:476-481` declares `'SNAPSHOT'` in its isolation +union and `:370-372` interpolates the level into SQL with no allow-list at the execution point — +an isolation MySQL cannot honor. Under the RFC's own isolation-refusal law the MySQL command +store must publish a `supportedIsolationLevels` that contradicts the type one layer down. +**Repair:** name this fix in Stage 6's exit condition (and note #1293 adjacency remains correct — +this is a different defect than #1293's surface work). + +### F-B6 (medium) — `PrismaTransactionClient` does not exist; the generator must own it + +The flagship example imports `PrismaTransactionClient` from `@database` — zero repo hits; the +`@database` alias maps to the root-client surface, and the `db command-store init` deliverable +list does not include emitting or typing the transaction-client type. **Repair:** add the +transaction-client type emission (or its documented derivation, e.g. +`Parameters[0]` equivalent) to the generator's deliverables, and +keep the already-correct requirement to fix `withTransaction()`'s root-client assertion. + +### F-B7 (minor, batch) + +(a) Stage-1 archetype: contracts is A4 per doctrine `06-archetypes.md:375`, not A1. (b) +`commandBaseContract` needs the literal-preserving explicit annotation — state that it must reuse +#1350's spelling or it re-introduces the erasure the RFC depends on #1350 to fix. (c) Vocabulary: +`CommandExecution.idempotency: 'committed'` vs telemetry `'claimed'` — one word per state. +(d) Frontmatter `target-milestone: 0.0.6` is the *ratification* milestone while children sit in +0.0.8 and blocking #1350 in 0.0.7 — add one clarifying sentence so the frontmatter is not read as +an implementation date. (e) `WorkerIdempotencyPort`'s doc-comment claims "exactly-once-effective" +(`plugin-workers-core/src/ports/worker-idempotency-port.ts:30`) — the exact claim-window this RFC +rejects; require its correction in Stage 5's docs. (f) Fold into FCP Q2: Prisma rejects +`isolationLevel` on SQLite entirely, so a future SQLite store's `supportedIsolationLevels` would +be `[]` and the refusal law would refuse `Serializable` — the one level SQLite always provides. +(g) `db command-store init` collides with the existing `db init` noun — name the sub-noun choice +deliberately. (h) Telemetry asymmetry: existing vocabulary already emits `netscript.correlation.id` +and `netscript.idempotency.key` (`attributes/messaging.ts:15`, `attributes/saga.ts:12`) while +command spans exclude both — FCP Q3 should acknowledge the operator-experience asymmetry and the +existing-precedent cleanup question. + +## FCP-question adjudication + +Q1 (idempotency default), Q3 (correlation telemetry, with F-B7h noted), Q4 (retention): **safe to +defer** — typed both ways, policy-only. Q2 (SQLite timing): safe to defer **after** F-B7f is +folded in. The three genuinely rework-forcing questions (F-B1 claim algorithm, F-B2 relay +ownership, F-B3 queue reuse) are **missing from FCP** and must be resolved in the RFC text or +added as explicit FCP questions before FCP closes. + +## Required for PASS (cycle 2) + +Resolve F-B1–F-B3 in the RFC text (or as enumerated FCP questions with the option space fully +specified); add F-B4's negative conformance items; land F-B5/F-B6 as stage-condition amendments; +F-B7 as a batch edit. No structural redesign is requested — the transaction/receipt/relay laws, +capability honesty, and refusal boundary all survived adversarial verification. From c98c08adabbd992a557ff7c596deae68b9c9cd62 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 20:47:35 +0200 Subject: [PATCH 07/10] docs(rfc): resolve command composition plan findings --- .../codex-thread-ids.md | 7 +- .../context-pack.md | 71 ++- .../drift.md | 67 +++ .../plan.md | 114 +++-- .../research.md | 119 +++-- .../worklog.md | 112 ++-- rfcs/0000-command-composition-kit.md | 479 ++++++++++++++---- 7 files changed, 700 insertions(+), 269 deletions(-) diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md index 66b7e65684..32a9d841d2 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md @@ -1,12 +1,10 @@ # rfc-command-kit — Codex implementation thread - **Thread / session id:** `019fe242-2c45-7e03-a428-eebfb968eda0` -- **Rollout:** - `/home/codex/.codex/sessions/2026/08/08/rollout-2026-08-08T18-43-35-019fe242-2c45-7e03-a428-eebfb968eda0.jsonl` +- **Rollout:** `/home/codex/.codex/sessions/2026/08/08/rollout-2026-08-08T18-43-35-019fe242-2c45-7e03-a428-eebfb968eda0.jsonl` - **Worktree:** `/home/codex/repos/ns-rfc-command-kit` - **Branch:** `docs/rfc-command-composition-kit` @ `fac9e3390` (NO upstream by design). -- **Push rule:** explicit refspec only — - `git push origin HEAD:refs/heads/docs/rfc-command-composition-kit`. +- **Push rule:** explicit refspec only — `git push origin HEAD:refs/heads/docs/rfc-command-composition-kit`. - **Requested route:** provider=openai · model=gpt-5.6-sol · effort=xhigh - **Observed route:** provider=openai · model=gpt-5.6-sol · effort=xhigh - **Route verdict:** matched @@ -14,7 +12,6 @@ - **Brief (staged):** `/home/codex/rfc-command-kit-brief.md` ## Steering (same thread — never a second send-message-v2 at this worktree) - ```bash codex exec resume 019fe242-2c45-7e03-a428-eebfb968eda0 -- "" ``` diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md index 70a5c4aa2e..0dc553affc 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md @@ -6,18 +6,19 @@ | -------------- | --------------------------------------------------------------- | | Run ID | `docs-rfc-command-composition-kit--rfc` | | Branch | `docs/rfc-command-composition-kit` | -| Current phase | `plan-eval-ready` | -| Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | +| Current phase | `plan-eval-remediation-cycle-1` | +| Archetype | Docs delivery describing A4/A2/A3/A5/A6 implementation surfaces | | Scope overlays | `SCOPE-docs`, `SCOPE-service` | ## Current State -The run is active on the exact requested branch/base in the sole daemon-attached Codex thread. -Bootstrap commit `ad643e15...` and research/plan commit `e0b98f289...` were pushed by explicit -refspec; draft PR #1389 is live at `status:plan`. The full re-baseline and plan gate are complete, -and the RFC now carries the exact contracts, semantic laws, adapter truth, relay boundary, -conformance plan, migration, and decomposition. Final docs/RFC/PR evidence is green. No product code -or export changed. +The run is active on the exact requested branch/base in the sole daemon-attached Codex thread. Draft +PR #1389 remains open and draft. Fable PLAN-EVAL cycle 1 is preserved at evaluator commit +`122301d25` with authoritative `FAIL_PLAN` findings F-B1–F-B7. This authoring turn is remediating +those findings without launching or approving evaluation. The RFC now locks provider receipt-claim +and timeout algorithms, the service → database relay split, queue non-reuse/runtime-DDL +reconciliation, identity-drift behavior, MySQL/SQLite capability truth, generated transaction +typing, and the batch corrections. No product code or export changed. ## Completed @@ -36,35 +37,47 @@ or export changed. codecs, deterministic scope inputs, and explicit relay retry/terminal dispositions. - Passed docs links/accuracy, scoped format/diff, RFC structural/terminology, review-thread, and PR check reconciliation; captured current package doc-lint findings as future implementation bars. +- Read `plan-eval.md` completely and preserved its evaluator commit/verdict. +- Re-verified queue, service/database dependency, MySQL, worker, telemetry, CLI, Prisma generated + type, and primary provider-lock surfaces for F-B1–F-B7. +- Reconciled the plan's open-decision sweep so no provider/package/migration/generator choice is + silently deferred. ## In Progress -- Final handoff commit/push and PR transition to `status:plan-eval`. +- Proportionate remediation validation, commit/push, PR phase comment/body/label reconciliation, and + exact cycle-2 handoff. ## Next Steps -1. Commit/push the final evidence and handoff by explicit refspec. -2. Update the draft PR body and replace `status:plan` with `status:plan-eval`. -3. Root orchestrator steers the existing Fable session using `final-handoff.md`; this generator does - not launch or self-certify evaluation. +1. Run scoped Markdown/RFC/link/type/diff checks and record exact results. +2. Commit and push only `HEAD:refs/heads/docs/rfc-command-composition-kit`. +3. Keep the PR draft, restore exactly `status:plan-eval`, and post the remediation phase comment. +4. Root orchestrator steers the existing Fable session using `final-handoff.md`; this generator does + not launch or self-certify cycle 2. ## Key Decisions -| Decision | Source | Notes | -| ------------------------------------------------------ | ------------------------------ | ------------------------------------------------------------------------------ | -| Docs-only RFC; no package/plugin changes. | brief, #1361 | Implementation is separate. | -| One-store atomicity is the maximum portable claim. | brief, doctrine A11–A13 | Cross-store and exactly-once claims refused. | -| Generator will not launch PLAN/IMPL evaluators. | brief | Root orchestrator owns Fable/Qwen sessions. | -| No weak command store; KV is refused in v1. | Deno KV/runtime research | Same-commit truth is encoded by conformance, not a boolean callers can ignore. | -| Service/database/contracts/telemetry focused subpaths. | doctrine + dependency analysis | No new package or root export growth; avoids package cycle. | -| Consumer-owned generated schemas with JCS codecs. | JSR/Prisma/provider analysis | No hidden migrations or provider-JSON fiction. | +| Decision | Source | Notes | +| ------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------ | +| Docs-only RFC; no package/plugin changes. | brief, #1361 | Implementation is separate. | +| One-store atomicity is the maximum portable claim. | brief, doctrine A11–A13 | Cross-store and exactly-once claims refused. | +| Generator will not launch PLAN/IMPL evaluators. | brief | Root orchestrator owns Fable/Qwen sessions. | +| No weak command store; KV is refused in v1. | Deno KV/runtime research | Same-commit truth is encoded by conformance, not a boolean callers can ignore. | +| Service/database/contracts/telemetry focused subpaths. | doctrine + dependency analysis | No new package or root export growth; avoids package cycle. | +| Consumer-owned generated schemas with JCS codecs. | JSR/Prisma/provider analysis | No hidden migrations or provider-JSON fiction. | +| Provider-specific receipt claims and bounded waits. | PLAN-EVAL F-B1 + primary docs | No generic duplicate catch or callback retry. | +| Relay runtime in service over raw database persistence. | PLAN-EVAL F-B2 + doctrine | New direct service → database edge; no reciprocal dependency. | +| No direct queue reuse in v1. | PLAN-EVAL F-B3 + queue source | Share algorithm/tests; reconcile runtime DDL before future code sharing. | +| Scope/name drift executes as new. | PLAN-EVAL F-B4 + unique key | Determinism tests and replay migration/alias required. | +| Generated transaction type + honest isolation split. | PLAN-EVAL F-B5–F-B7 + probes | MySQL allow-list; SQLite default-only FCP; explicit root-method omission. | ## Files Changed -| Path | Status | Notes | -| -------------------------------------------------- | ------ | --------------------------------------------------------- | -| `.llm/runs/docs-rfc-command-composition-kit--rfc/` | new | Mandatory harness artifacts plus staged session receipts. | -| `rfcs/0000-command-composition-kit.md` | new | Draft RFC; no framework/product implementation. | +| Path | Status | Notes | +| -------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------- | +| `.llm/runs/docs-rfc-command-composition-kit--rfc/` | modified | Evaluator artifact preserved; remediation evidence/handoff and launcher metadata reconciled. | +| `rfcs/0000-command-composition-kit.md` | modified | Draft RFC remediation only; no framework/product implementation. | ## Gates @@ -77,12 +90,14 @@ or export changed. ## Open Questions -- FCP policy only: idempotency required-by-default opt-out, SQLite release timing, correlation ID - telemetry opt-in, and retention defaults. These do not block the RFC core. +- FCP policy only: idempotency default, acceptance/timing of SQLite's default-only capability, + correlation telemetry plus existing-precedent cleanup, and retention defaults. Provider claims, + relay ownership, and queue reuse are resolved and not open. ## Drift and Debt -- Drift: runtime controller identity correlation failed read-only; recorded in `drift.md`. +- Drift: runtime identity, cycle-1 undeclared boundary decisions, queue runtime DDL, identity drift, + isolation truth, and launcher metadata reconciliation are recorded in `drift.md`. - Debt: no new or deepened architecture debt; existing package verdicts constrain the RFC. ## Commits diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md index 83c771111c..32f5b4ba64 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/drift.md @@ -68,3 +68,70 @@ current-state documentation. - **Action:** make CAS repository-specific with a zero-row typed conflict, and restrict default telemetry to stable names, enums, booleans, and counts. - **Evidence:** Prisma OCC docs; OTel attribute requirement/convention guidance; `research.md`. + +## 2026-08-08 — PLAN-EVAL cycle 1 exposed three undeclared boundary decisions + +- **What:** The first RFC draft left receipt duplicate recovery/timeout, relay type ownership, and + queue reuse-versus-rejection to implementation inference. +- **Source:** Authoritative `plan-eval.md` findings F-B1–F-B3; verdict `FAIL_PLAN`. +- **Expected:** The plan's open-decision sweep should have resolved every choice that could rework + provider or package boundaries. +- **Actual:** The core laws were sound, but these three decisions were absent from both locked plan + and FCP questions. +- **Severity:** critical. +- **Action:** lock provider-specific claim algorithms, split database raw relay persistence from + service decoded runtime/sinks, reject queue-package reuse in v1, and propose queue runtime-DDL + reconciliation before future code sharing. +- **Evidence:** RFC normative claim/relay/queue sections; `research.md` R21–R25; `plan.md` L14–L16. + +## 2026-08-08 — Receipt identity drift was described more strongly than the key can enforce + +- **What:** The first draft said scope must be stable but did not state that a changed scope or + renamed command creates a different unique-key namespace. +- **Source:** `plan-eval.md` F-B4. +- **Expected:** Same raw idempotency key would appear protected by the key-reuse law. +- **Actual:** `(scope, commandName, keyHash)` changes, so no conflicting receipt exists and the + handler honestly executes as new. +- **Severity:** significant. +- **Action:** add deterministic identity fixtures, execute-as-new negative conformance, and a + breaking replay migration/alias rule for scope/name changes. +- **Evidence:** RFC canonical identity, semantic law 13, conformance items 5–6. + +## 2026-08-08 — Isolation vocabulary needs provider allow-lists and default-only truth + +- **What:** Existing planning treated MySQL/SQLite capability as a supported-level set only. +- **Source:** `plan-eval.md` F-B5/F-B7f and current adapter source. +- **Expected:** MySQL omits unsupported `Snapshot`; SQLite could advertise its serializable engine + level directly. +- **Actual:** The lower MySQL adapter union includes/interpolates `SNAPSHOT`; the evaluator found + SQLite's Prisma selection surface unavailable even though its engine default is serializable. +- **Severity:** significant. +- **Action:** replace the capability with `selectableIsolationLevels` plus `defaultIsolation`, make + MySQL four-level allow-list/removal a Stage-6 gate, and put SQLite's default-only acceptance in + FCP Q2. +- **Evidence:** RFC capability matrix; `research.md` R27/R29; `plan.md` L18/L20. + +## 2026-08-08 — Queue runtime DDL is baseline drift, not command-kit precedent + +- **What:** `@netscript/queue` already creates PostgreSQL queue/DLQ schema from runtime adapter + initialization. +- **Source:** `packages/queue/adapters/postgres.adapter.ts` and dead-letter adapter; F-B3. +- **Expected:** The RFC's no-hidden-migration law might read as a repository-wide current invariant. +- **Actual:** It is a normative rule for new command-kit/relay paths; the sibling queue behavior is + existing drift requiring separate reconciliation before reuse. +- **Severity:** significant. +- **Action:** scope the immediate law to command-kit paths and propose a migration-free queue slice; + create no issue in this RFC run. +- **Evidence:** RFC queue-decision/rejected-alternative/board sections. + +## 2026-08-08 — Launcher metadata formatting arrived with evaluator handoff + +- **What:** `.llm/runs/docs-rfc-command-composition-kit--rfc/codex-thread-ids.md` had a pre-existing + launcher metadata formatting edit when remediation began. +- **Source:** worktree at evaluator HEAD `122301d25`. +- **Expected:** Evaluator commit plus clean authored state. +- **Actual:** The metadata lines were reflowed without changing thread/session identities. +- **Severity:** minor. +- **Action:** preserve and include the formatting reconciliation with run-artifact updates; do not + discard or regenerate launcher identity state. +- **Evidence:** final raw diff and commit slice S4. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md index 16bbf11b13..6b1e19eec8 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md @@ -2,14 +2,14 @@ ## Run Metadata -| Field | Value | -| ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | -| Run ID | `docs-rfc-command-composition-kit--rfc` | -| Branch | `docs/rfc-command-composition-kit` | -| Phase | `plan-eval-ready` | -| Target | `rfcs/0000-command-composition-kit.md` plus harness evidence | -| Delivery profile | `SCOPE-docs` with `SCOPE-service` consumer analysis | -| Described implementation | A1 contracts, A2 database/telemetry adapters, A3 relay runtime, A4 service DSL, A5 thin plugin consumers, A6 CLI generators | +| Field | Value | +| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | +| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Branch | `docs/rfc-command-composition-kit` | +| Phase | `plan-eval-remediation-cycle-1` | +| Target | `rfcs/0000-command-composition-kit.md` plus harness evidence | +| Delivery profile | `SCOPE-docs` with `SCOPE-service` consumer analysis | +| Described implementation | A4 contracts/service DSL, A2 database/telemetry adapters, A3 runtime discipline, A5 thin plugin consumers, A6 CLI generators | ## Goal @@ -38,15 +38,15 @@ refused rather than disguised. ## Doctrine and archetype mapping -| Future slice | Owner/archetype | Doctrine consequence | -| ---------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------- | -| Command contract error fragment | `@netscript/contracts/commands`, A1 | Contract first; literal error keys; no global base-map growth. | -| Transaction-bound store and SQL adapters | `@netscript/database/commands`, A2 | Port has one purpose; capabilities/refusals are explicit; no generated Prisma type leak. | -| Command definition/executor | `@netscript/service/commands`, A4 | Public DSL is a subpath and one explicit composition root; no hidden global runtime. | -| Command telemetry | existing telemetry attributes subpath, A2 | Stable bounded vocabulary; privacy/high cardinality excluded by default. | -| Outbox relay | generated worker plus store/sink ports, A3 | Owned lifecycle, lease/ack/retry, cancellation, and at-least-once boundary. | -| Worker/saga/webhook consumers | thin A5 integrations | Reuse existing runtime primitives; no semantic forks in plugin wrappers. | -| Explicit schema/command/relay generators | CLI A6 | Generate discoverable consumer-owned files; never silently inject schema. | +| Future slice | Owner/archetype | Doctrine consequence | +| ------------------------------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | +| Command contract error fragment | `@netscript/contracts/commands`, A4 | Literal-preserving builder annotation from #1350; no global base-map growth. | +| Transaction command/relay stores and SQL adapters | `@netscript/database/commands`, A2 | Raw ports/adapters own provider truth; no service or generated-client type leaks. | +| Command definition/executor | `@netscript/service/commands`, A4 | Public DSL is a subpath and one explicit composition root; no hidden global runtime. | +| Relay supervisor/sinks | `@netscript/service/commands/relay`, A4 with A3 runtime discipline folded | Service consumes database persistence; owned lifecycle, leases, cancellation, at-least-once boundary. | +| Command telemetry | existing telemetry attributes subpath, A2 | Stable bounded vocabulary; privacy/high cardinality excluded by default. | +| Worker/saga/webhook consumers | A3 core runtimes plus thin A5 integrations | Existing runtime primitives compose after commit; no semantic forks in plugins. | +| Explicit schema/command/relay generators | CLI A6 | `db command-store add` emits discoverable consumer-owned files/types; no hidden migration. | The docs PR itself uses `SCOPE-docs`; it does not pretend a documentation file is all six archetypes. Each implementation child must activate only its owning profile plus needed overlays. @@ -79,6 +79,30 @@ archetypes. Each implementation child must activate only its owning profile plus | L11 | Command errors are route-opt-in and depend on #1350 for client-visible type preservation. | Avoids widening every contract and shipping fictional type safety. | | L12 | Default telemetry excludes raw scope, actor, idempotency key/hash, request hash, expected version, payload, and arbitrary correlation identifiers. | Cardinality, PII, and secret leakage. | | L13 | Worker and saga idempotency remain separate consumer-side delivery concerns; an outbox message keeps a stable ID across relay attempts. | Commit-once does not imply deliver-once or effect-once. | +| L14 | Receipt-claim algorithms are provider-specific and locked: PostgreSQL conflict-safe insert, MySQL savepoint/1062 recovery, SQL Server named-index range lock; all have bounded lock waits. | A generic unique-error catch would poison or misclassify transactions and force Stage-3 rework. | +| L15 | Relay raw rows/store/release types live in database; decoded delivery/sink/supervisor types live in `service/commands/relay`; service adds the new direct database dependency. | Preserves the only dependency arrow `service → database`; database never imports service. | +| L16 | V1 does not wrap or depend on `@netscript/queue`; it reuses the proven lease algorithm/test pattern and proposes a separate runtime-DDL reconciliation before future code sharing. | Queue ack/DLQ/schema semantics differ from retained token-settled outbox rows. | +| L17 | Scope/fingerprint are pure deterministic identity functions; different scope or command name is a new receipt namespace and executes as new. | This is the honest unique-key behavior; renames/scope changes require compatibility aliases or receipt migration. | +| L18 | Capabilities separate explicitly selectable isolation levels from the omitted-option default. SQLite's future shape is selectable `[]`, default `Serializable`, pending FCP. | Avoids claiming an explicit API the evaluator found unavailable and keeps the refusal law coherent. | +| L19 | `db command-store add` emits `CommandTransactionClient` from generated `Prisma.TransactionClient` with root/lifecycle methods explicitly omitted. | The type is model-specific and cannot be a framework fake; current Prisma deny-list retains nested `$transaction`. | +| L20 | MySQL cannot pass Stage 6 until `SNAPSHOT` is removed/denied and SQL isolation tokens are allow-listed; #1293 remains separate. | Current lower adapter contradicts engine truth and interpolates the upstream union. | + +## Open-decision sweep after PLAN-EVAL cycle 1 + +| Decision | Disposition | Rework risk | +| -------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------ | +| Provider receipt claim + bounded wait | Resolved by L14 and normative provider table. | None deferred. | +| Relay port/type package ownership | Resolved by L15; service adds a direct database dependency, never the reverse. | None deferred. | +| Queue reuse vs rejection / runtime DDL | Resolved by L16; direct reuse rejected, reconciliation proposed before future sharing. | None deferred. | +| Scope/command identity drift | Resolved by L17 and explicit execute-as-new conformance/migration law. | None deferred. | +| MySQL `SNAPSHOT` contradiction | Stage-6 prerequisite locked by L20. | Cannot be waived by #1293. | +| Generated transaction-client type | Generator ownership/type derivation locked by L19. | Cannot be deferred past emitted command samples. | +| Idempotency required-by-default | Safe FCP policy question. | Both modes already typed; no package boundary change. | +| SQLite default-only acceptance/timing | Safe FCP after L18 capability shape. | Adapter release timing only; no false current support. | +| Cross-runtime correlation telemetry | Safe FCP privacy/operations policy question with existing-asymmetry cleanup named. | No command atomicity or package ownership change. | +| Receipt/outbox retention defaults | Safe FCP operations policy question. | Safety floors are fixed; only durations remain. | + +No undeclared package, algorithm, migration, or generator decision remains before implementation. ## Exact design skeleton @@ -100,6 +124,11 @@ The RFC will specify, with compilable examples: 8. Command span/attribute constants with exact allowed values and redaction rules. 9. Schema-backed codecs for replay outputs and outbox payloads, plus an explicit retry/terminal relay release union. +10. Exact provider receipt-claim SQL/lock-timeout/session-restoration algorithms and no-poisoning + conformance. +11. Split relay ownership with raw database rows below decoded service deliveries, plus the explicit + queue non-reuse/hidden-migration reconciliation decision. +12. Generator-owned `CommandTransactionClient` derivation and positive/negative emitted fixtures. ## Semantic laws to encode @@ -118,6 +147,8 @@ The RFC will specify, with compilable examples: relay redelivery; publish-then-crash may duplicate delivery. - **Boundary refusal:** absent same-commit support, unsupported isolation, cross-store state, or external effects fail composition/execution before an overbroad guarantee can be claimed. +- **Identity drift:** same raw key under a different scope/name executes as new; changed version in + the same receipt namespace mismatches; deterministic identity fixtures make this visible. ## Capability and adapter plan @@ -127,9 +158,9 @@ integration. It will not label a provider “supported” merely because its eng | Target | Planned position | | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | PostgreSQL + Prisma | Reference adapter; full semantics after conformance. | -| MySQL + Prisma | Feasible; current DB subpath exists; no `Snapshot`; conformance required. #1293 is adjacent, not blocking. | +| MySQL + Prisma | Feasible only after four-level allow-list and removal/rejection of current `SNAPSHOT`; #1293 remains separate. | | SQL Server + Prisma | Feasible; `Snapshot` only when enabled; response/side payloads use text rather than a portable `Json` assumption. | -| SQLite + Prisma | Engine feasible but current NetScript adapter absent; no support claim until added and busy/fault tests pass. | +| SQLite + Prisma | Future default-only shape: selectable `[]`, default `Serializable`; release timing and acceptance remain FCP. | | Deno KV | Explicit v1 refusal; existing worker idempotency stays separate. | | SQL + KV/stream/HTTP, or two SQL stores | No atomic adapter; use outbox and saga/consumer compensation. | @@ -148,15 +179,16 @@ integration. It will not label a provider “supported” merely because its eng ## Risk register -| Risk | Mitigation | -| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| Generic API leaks Prisma/generated types. | Package-owned structural port; generated bridge owns delegates; `deno doc` consumer review. | -| Receipt claim races or commits incomplete state. | Unique constraint, tx-bound claim/complete, injected faults at every boundary, corruption test. | -| Canonicalization accepts non-I-JSON values. | Explicit fingerprint/response codecs, JCS validation, negative Date/BigInt/non-finite-number tests. | -| Long transactions or hidden retries duplicate captured effects. | No remote I/O, timeout/AbortSignal, no automatic callback retry. | -| Telemetry leaks IDs or explodes cardinality. | Closed low-cardinality attributes, forbidden-field tests, optional redaction policy. | -| Relay is mistaken for exactly-once. | Stable IDs, lease/ack crash tests, explicit at-least-once wording, downstream dedupe guidance. | -| RFC grows into a workflow platform. | One callback/one store; multi-step or compensating work hands off to sagas. | +| Risk | Mitigation | +| -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| Generic API leaks Prisma/generated types. | Package-owned structural port; generated bridge owns delegates; `deno doc` consumer review. | +| Receipt claim races, poisons the callback, or leaks session timeout. | Locked provider algorithms; duplicate/timeout/leader tests; connection restore/discard conformance. | +| Canonicalization accepts non-I-JSON values. | Explicit fingerprint/response codecs, JCS validation, negative Date/BigInt/non-finite-number tests. | +| Long transactions or hidden retries duplicate captured effects. | No remote I/O, timeout/AbortSignal, no automatic callback retry. | +| Telemetry leaks IDs or explodes cardinality. | Closed low-cardinality attributes, forbidden-field tests, optional redaction policy. | +| Relay is mistaken for exactly-once. | Stable IDs, lease/ack crash tests, explicit at-least-once wording, downstream dedupe guidance. | +| Queue reuse imports hidden runtime migrations or wrong settlement. | Reject direct dependency; share tests/algorithm only; propose explicit queue reconciliation. | +| RFC grows into a workflow platform. | One callback/one store; multi-step or compensating work hands off to sagas. | ## Anti-patterns @@ -176,7 +208,8 @@ implementation into PR-sized children: typed contracts; service executor; refere store; telemetry; relay; MySQL/MSSQL adapters; optional SQLite adapter; CLI/schema/service generator; and docs/consumer proof. #1362 owns generated service layering, #1364 owns the outbound-webhook recipe, and #1350 is the typed-error prerequisite. #1293 remains adjacent and -should not be made a false blocker. +should not be made a false blocker. A separate queue runtime-DDL reconciliation is proposed before +future code sharing; this RFC run creates no issue. ## Fitness and validation gates @@ -196,14 +229,15 @@ labels. ## Plan-gate readiness -| Question | Answer | -| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| Is the problem and non-scope precise? | Yes; one-store command atomicity and explicit refusal boundary. | -| Are target contracts named before implementation? | Yes; four focused subpaths, executor/store/envelope/rows/errors/telemetry. | -| Are failure and cancellation semantics explicit? | Yes; no hidden retry, bounded busy, rollback, signal, relay lease. | -| Are extension axes and anti-patterns handled? | Yes; store/sink/provider adapters and generated bridges are separate. | -| Are consumers and gates identified? | Yes; services, contracts, DB adapters, telemetry, workers/sagas, CLI/scaffold. | -| Are open questions non-blocking to drafting? | Yes; idempotency default, SQLite release timing, correlation telemetry, retention durations are isolated FCP policy choices. | - -Plan gate is ready for RFC authoring. Formal PLAN-EVAL is deliberately not triggered by this -generator; the owner-directed Fable review occurs after the complete draft and handoff. +| Question | Answer | +| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| Is the problem and non-scope precise? | Yes; one-store command atomicity and explicit refusal boundary. | +| Are target contracts named before implementation? | Yes; service command/relay, database command/provider/testing, contracts, and telemetry subpaths with a one-way dependency graph. | +| Are failure and cancellation semantics explicit? | Yes; no hidden retry, bounded busy, rollback, signal, relay lease. | +| Are extension axes and anti-patterns handled? | Yes; provider claims are exact, relay ownership is split, queue non-reuse is decided, and generated bridges are separate. | +| Are consumers and gates identified? | Yes; services, contracts, DB adapters, telemetry, workers/sagas, CLI/scaffold. | +| Are open questions non-blocking to drafting? | Yes; idempotency default, SQLite release timing, correlation telemetry, retention durations are isolated FCP policy choices. | + +Cycle-1 `FAIL_PLAN` is not self-overridden. After the RFC/artifacts/gates/commit/PR metadata are +reconciled, this plan returns to `status:plan-eval` for the root orchestrator to steer the existing +Fable session through cycle 2. This author does not launch or approve that evaluation. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md index f27b728c48..3f02ace13f 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/research.md @@ -15,54 +15,75 @@ ## Baseline findings -| # | Finding | Evidence | -| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| R1 | Branch, HEAD, and merge-base began exactly at the requested baseline. | Raw `git rev-parse HEAD` and `git merge-base HEAD origin/main` both returned `fac9e339...`; branch was `docs/rfc-command-composition-kit`. | -| R2 | `withTransaction` has no production caller and its callback is publicly typed as the full root client through an assertion, not Prisma's narrower transaction client. | `packages/database/mod.ts:128-139`; focused `deno check --unstable-kv packages/database/rfc-command-probe.ts` exited 0 while the callback called root-only and nested `$transaction` methods. Probe was removed after execution. | -| R3 | `TransactionOptions` is usable, but `maxIsolation` would be a false capability abstraction: supported isolation levels are a provider-specific set and SQL Server `Snapshot` additionally depends on database configuration. | `packages/database/ports/database-client.ts:59-77`; Prisma transaction matrix; SQL Server official isolation docs. | -| R4 | The service builder dynamically injects `db`, `traceHeaders`, and authenticated `principal` into an open record. The public `ServiceContext` is a Hono `Context`, not that oRPC record. | `packages/service/src/builder/service-builder-impl.ts:256-281`; `packages/service/src/types.ts:239-272`. | -| R5 | A command subpath does not exist. Current service exports are root, `./auth`, and `./rpc-path`; database has no `./commands`; contracts has no command error fragment; telemetry's command vocabulary is absent. | The four package `deno.json` export maps plus `deno doc` on the public entrypoints. | -| R6 | The proposal's global `CONFLICT` approach would widen every route and is blocked by a real type defect. `baseContract` erases the literal error map, and `safe()` loses the error generic. | `packages/contracts/src/application/contract-primitives.ts:21-81`; `packages/sdk/src/client/errors.ts:49-90`; #1350. Focused SDK probe failed with `TS2339: Property 'code' does not exist on type 'never'`. | -| R7 | oRPC's current contract builder can add a route-local error fragment with `.errors(...)`; a global common-map addition is unnecessary. | Native `deno doc --filter ContractProcedureBuilder npm:@orpc/contract@1.14.6` shows sparse-merged `errors(errors)` on the builder. | -| R8 | Worker idempotency is a delivery claim/apply/release lifecycle in KV. It is neither response replay nor enrollable in a relational business transaction. | `packages/plugin-workers-core/src/ports/worker-idempotency-port.ts`; `src/stores/kv-worker-idempotency-store.ts`. | -| R9 | The proposal's “no outbox” claim is stale: a public `SagaOutboxPort` exists. It is explicitly reserved for saga T2 durability, has no transaction-bound handle or `AbortSignal`, and has no implementation/caller, so it cannot be reused as proof of command atomicity. | `packages/plugin-sagas-core/src/ports/saga-outbox-port.ts` and focused reference search. | -| R10 | Current telemetry exports `SpanNames` and builders from `@netscript/telemetry/attributes`, not the root. There is no command span or builder. Existing saga helpers can emit raw idempotency/correlation values, which is precedent to improve, not copy. | `packages/telemetry/deno.json`; `src/attributes/spans.ts`, `helpers.ts`, `saga.ts`. | -| R11 | Current generated Prisma CRUD handlers call delegates directly; they do not use a transaction or application layer. Explicit CLI surfaces already exist for `contract add-route` and `service add-handler`, but there is no command/schema/relay generator. | `packages/cli/src/kernel/assets/service/routers/v1.ts.template`; executed CLI `contract --help`, `service --help`, `db --help`, and `generate --help`. | -| R12 | The MySQL claim in the proposal conflates packages. `@netscript/database/adapters/mysql` currently exports `MysqlAdapter`; #1293 concerns the lower-level `@netscript/prisma-adapter-mysql` class/error hook and is adjacent, not a command-transaction blocker. | `packages/database/deno.json`; `adapters/mysql.adapter.ts`; live #1293. | -| R13 | PostgreSQL, MySQL, SQL Server, and SQLite can support one-store transaction semantics in Prisma, but current NetScript only publishes Postgres, MSSQL, and MySQL adapter subpaths. SQLite is named in `DatabaseProvider` yet has no NetScript adapter export. | `packages/database/deno.json`; provider type; Prisma transaction matrix. | -| R14 | Deno KV is an optimistic atomic batch, not an interactive transaction. Its checks/mutations and operation-size limits cannot host an arbitrary Prisma-style command callback or enroll SQL rows. | Deno KV transaction and API documentation. | -| R15 | SQLite permits multiple readers but only one simultaneous writer. “Serializable” in a matrix does not imply the same contention, timeout, or interactive-callback behavior as the SQL client/server adapters. | SQLite transaction documentation; Prisma matrix. | -| R16 | Exactly-once delivery cannot be inferred from a committed outbox row. A relay may publish and crash before marking the row, so message identity must be stable and consumers remain idempotent. | Doctrine chapter 08; current worker/saga delivery code; queue boundary analysis. | -| R17 | Trace propagation already uses W3C `traceparent`/`tracestate` across service, workers, and sagas. OTel producer/consumer spans or links can join deferred delivery without storing arbitrary trace attributes. | Service builder, worker dispatcher, saga delivery; W3C Trace Context and OTel tracing API. | -| R18 | #1361 is ratification-only and already has an implementation issue. #1362–#1364 are open at `0.0.8`; #1350 is open at `0.0.7`; no new issue is needed from this PR. | Live GitHub issue reads on 2026-08-08. | -| R19 | The package-neutral codec signature is structurally sound with Zod, but `@netscript/service` does not currently declare `@standard-schema/spec`; a future public signature must add that dependency directly. | Focused S2 type-shape probe initially failed import resolution, passed after using the workspace's locked `jsr:@standard-schema/spec@1.1.0`, and was removed; `deno why` confirmed the locked module. | -| R20 | Current full-entrypoint doc-lint is clean for service/database but already reports private-type/JSDoc findings in contracts and telemetry. The future subpaths must not hide behind that baseline and must add zero new findings. | Structured `run-deno-doc-lint.ts`: service `0`, database combined `0`, contracts `9` private-type findings, telemetry `7` combined findings (`6` private-type, `1` missing JSDoc); all report commands exited `0`. | +| # | Finding | Evidence | +| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| R1 | Branch, HEAD, and merge-base began exactly at the requested baseline. | Raw `git rev-parse HEAD` and `git merge-base HEAD origin/main` both returned `fac9e339...`; branch was `docs/rfc-command-composition-kit`. | +| R2 | `withTransaction` has no production caller and its callback is publicly typed as the full root client through an assertion, not Prisma's narrower transaction client. | `packages/database/mod.ts:128-139`; focused `deno check --unstable-kv packages/database/rfc-command-probe.ts` exited 0 while the callback called root-only and nested `$transaction` methods. Probe was removed after execution. | +| R3 | `TransactionOptions` is usable, but `maxIsolation` would be a false capability abstraction: supported isolation levels are a provider-specific set and SQL Server `Snapshot` additionally depends on database configuration. | `packages/database/ports/database-client.ts:59-77`; Prisma transaction matrix; SQL Server official isolation docs. | +| R4 | The service builder dynamically injects `db`, `traceHeaders`, and authenticated `principal` into an open record. The public `ServiceContext` is a Hono `Context`, not that oRPC record. | `packages/service/src/builder/service-builder-impl.ts:256-281`; `packages/service/src/types.ts:239-272`. | +| R5 | A command subpath does not exist. Current service exports are root, `./auth`, and `./rpc-path`; database has no `./commands`; contracts has no command error fragment; telemetry's command vocabulary is absent. | The four package `deno.json` export maps plus `deno doc` on the public entrypoints. | +| R6 | The proposal's global `CONFLICT` approach would widen every route and is blocked by a real type defect. `baseContract` erases the literal error map, and `safe()` loses the error generic. | `packages/contracts/src/application/contract-primitives.ts:21-81`; `packages/sdk/src/client/errors.ts:49-90`; #1350. Focused SDK probe failed with `TS2339: Property 'code' does not exist on type 'never'`. | +| R7 | oRPC's current contract builder can add a route-local error fragment with `.errors(...)`; a global common-map addition is unnecessary. | Native `deno doc --filter ContractProcedureBuilder npm:@orpc/contract@1.14.6` shows sparse-merged `errors(errors)` on the builder. | +| R8 | Worker idempotency is a delivery claim/apply/release lifecycle in KV. It is neither response replay nor enrollable in a relational business transaction. | `packages/plugin-workers-core/src/ports/worker-idempotency-port.ts`; `src/stores/kv-worker-idempotency-store.ts`. | +| R9 | The proposal's “no outbox” claim is stale: a public `SagaOutboxPort` exists. It is explicitly reserved for saga T2 durability, has no transaction-bound handle or `AbortSignal`, and has no implementation/caller, so it cannot be reused as proof of command atomicity. | `packages/plugin-sagas-core/src/ports/saga-outbox-port.ts` and focused reference search. | +| R10 | Current telemetry exports `SpanNames` and builders from `@netscript/telemetry/attributes`, not the root. There is no command span or builder. Existing saga helpers can emit raw idempotency/correlation values, which is precedent to improve, not copy. | `packages/telemetry/deno.json`; `src/attributes/spans.ts`, `helpers.ts`, `saga.ts`. | +| R11 | Current generated Prisma CRUD handlers call delegates directly; they do not use a transaction or application layer. Explicit CLI surfaces already exist for `contract add-route` and `service add-handler`, but there is no command/schema/relay generator. | `packages/cli/src/kernel/assets/service/routers/v1.ts.template`; executed CLI `contract --help`, `service --help`, `db --help`, and `generate --help`. | +| R12 | The MySQL claim in the proposal conflates packages. `@netscript/database/adapters/mysql` currently exports `MysqlAdapter`; #1293 concerns the lower-level `@netscript/prisma-adapter-mysql` class/error hook and is adjacent, not a command-transaction blocker. | `packages/database/deno.json`; `adapters/mysql.adapter.ts`; live #1293. | +| R13 | PostgreSQL, MySQL, SQL Server, and SQLite can support one-store transaction semantics in Prisma, but current NetScript only publishes Postgres, MSSQL, and MySQL adapter subpaths. SQLite is named in `DatabaseProvider` yet has no NetScript adapter export. | `packages/database/deno.json`; provider type; Prisma transaction matrix. | +| R14 | Deno KV is an optimistic atomic batch, not an interactive transaction. Its checks/mutations and operation-size limits cannot host an arbitrary Prisma-style command callback or enroll SQL rows. | Deno KV transaction and API documentation. | +| R15 | SQLite permits multiple readers but only one simultaneous writer. “Serializable” in a matrix does not imply the same contention, timeout, or interactive-callback behavior as the SQL client/server adapters. | SQLite transaction documentation; Prisma matrix. | +| R16 | Exactly-once delivery cannot be inferred from a committed outbox row. A relay may publish and crash before marking the row, so message identity must be stable and consumers remain idempotent. | Doctrine chapter 08; current worker/saga delivery code; queue boundary analysis. | +| R17 | Trace propagation already uses W3C `traceparent`/`tracestate` across service, workers, and sagas. OTel producer/consumer spans or links can join deferred delivery without storing arbitrary trace attributes. | Service builder, worker dispatcher, saga delivery; W3C Trace Context and OTel tracing API. | +| R18 | #1361 is ratification-only and already has an implementation issue. #1362–#1364 are open at `0.0.8`; #1350 is open at `0.0.7`; this RFC PR creates/mutates no issue. Cycle-1 review additionally requires a proposed queue runtime-DDL reconciliation before future code reuse. | Live GitHub issue reads on 2026-08-08 plus authoritative `plan-eval.md`; proposal only, no board mutation. | +| R19 | The package-neutral codec signature is structurally sound with Zod, but `@netscript/service` does not currently declare `@standard-schema/spec`; a future public signature must add that dependency directly. | Focused S2 type-shape probe initially failed import resolution, passed after using the workspace's locked `jsr:@standard-schema/spec@1.1.0`, and was removed; `deno why` confirmed the locked module. | +| R20 | Current full-entrypoint doc-lint is clean for service/database but already reports private-type/JSDoc findings in contracts and telemetry. The future subpaths must not hide behind that baseline and must add zero new findings. | Structured `run-deno-doc-lint.ts`: service `0`, database combined `0`, contracts `9` private-type findings, telemetry `7` combined findings (`6` private-type, `1` missing JSDoc); all report commands exited `0`. | + +## PLAN-EVAL cycle-1 remediation findings + +`plan-eval.md` was read completely at evaluator commit `122301d25`. Its F-B1–F-B7 findings and +Required-for-PASS list are authoritative for this authorship cycle. + +| # | Finding | Evidence and design consequence | +| --- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| R21 | A plain losing receipt insert cannot be normalized generically inside the transaction. | PostgreSQL uses `ON CONFLICT DO NOTHING RETURNING` with transaction-local `lock_timeout`; MySQL uses a savepoint/plain insert and recovers only 1062 with session `innodb_lock_wait_timeout`; SQL Server uses a named-index `UPDLOCK,HOLDLOCK` range lookup with `SET LOCK_TIMEOUT`. Timeout paths terminate and roll back the callback. | +| R22 | PostgreSQL's conflict-safe insert avoids 25P02, while stronger isolation may still choose a serialization victim. | PostgreSQL 18 `INSERT` docs, `lock_timeout`, `set_config`; the RFC permits retryable 40001 without callback replay and adds no-poisoning/leader commit/leader rollback integration cases. | +| R23 | MySQL timeout and duplicate behavior is statement-scoped by default, but server configuration can roll back more. | MySQL 8.4 InnoDB error handling says 1062 rolls back the statement and lock timeout rolls back the statement unless `innodb_rollback_on_timeout`; the adapter always aborts/rolls back the outer callback and restores the session timeout before pool return. | +| R24 | Relay ownership must preserve the one-way edge. | `packages/service/deno.json` has no direct database import today. Database will own raw relay-row/lease/release types and adapters; `@netscript/service/commands/relay` owns decoded delivery/sink/supervisor types and adds the direct service → database dependency. | +| R25 | `@netscript/queue` is algorithmic prior art, not a compatible relay adapter. | `postgres.adapter.ts:319-369` performs runtime schema creation; `:373-396` claims with `SKIP LOCKED`; ack deletes rows and nack uses queue DLQ semantics. V1 rejects a queue dependency, reuses the lease/test pattern, and proposes a separate migration-free queue reconciliation before future code sharing. | +| R26 | Scope or command-name drift changes the receipt key and honestly executes as new. | The unique key is `(scope, commandName, keyHash)`. Determinism fixtures and negative conformance now assert changed-scope/renamed-command execute-as-new, while same key/name/scope plus changed definition version mismatches. | +| R27 | MySQL currently advertises a false isolation token. | `packages/prisma-adapter-mysql/src/adapter.ts:476-481` includes `SNAPSHOT`; `startTransaction()` interpolates the upstream token. Stage 6 must remove it, allow-list/map the four MySQL levels, and add type/runtime negatives; #1293 remains separate. | +| R28 | The generated Prisma client supplies the consumer-specific transaction source type. | A temporary Prisma 7.8 `prisma-client` probe generated `Prisma.TransactionClient = Omit`. The current deny-list omits nested `$transaction`, so `db command-store add` must emit `CommandTransactionClient = Omit` and compile positive/negative samples. Probe artifacts were removed. | +| R29 | SQLite requires separate selectable/default capability truth. | Per the evaluator, a future SQLite command store advertises `selectableIsolationLevels: []` and `defaultIsolation: 'Serializable'`; explicit `Serializable` remains refused while the omitted default path can be considered by FCP Q2. | +| R30 | Existing telemetry/worker vocabulary contains claims the command kit must not copy. | Messaging emits `netscript.correlation.id`; saga defines `netscript.idempotency.key`; `WorkerIdempotencyPort` says “exactly-once-effective.” FCP Q3 now names the cross-runtime asymmetry, and Stage 5 corrects worker docs to at-least-once claim-window wording. | ## Primary documentation -| Topic | Primary source | Constraint carried into the RFC | -| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| Prisma transactions and isolation | [Prisma transaction reference](https://www.prisma.io/docs/orm/prisma-client/queries/transactions) | Interactive callback; `maxWait`/`timeout`; exact provider isolation sets; database default when omitted. | -| PostgreSQL isolation | [PostgreSQL 18 transaction isolation](https://www.postgresql.org/docs/current/transaction-iso.html) | PostgreSQL maps `ReadUncommitted` to `ReadCommitted`; serializable failures remain possible. | -| SQL Server isolation | [SQL Server `SET TRANSACTION ISOLATION LEVEL`](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-ver17) | `Snapshot` requires database configuration and is not an unconditional capability. | -| SQLite transactions | [SQLite transaction documentation](https://www.sqlite.org/lang_transaction.html) | One simultaneous writer; adapter must test busy/timeout paths rather than claim parity from a label. | -| Deno KV | [Deno KV transactions](https://docs.deno.com/deploy/kv/transactions/) and [Deno.Kv API](https://docs.deno.com/api/deno/~/Deno.Kv) | Optimistic `check` + atomic mutations with bounded checks, mutations, and bytes; refused from v1 command-store conformance. | -| Canonical JSON | [RFC 8785](https://www.rfc-editor.org/info/rfc8785/) | JCS over an I-JSON value before Web Crypto SHA-256; no `JSON.stringify` folklore. | -| Trace propagation | [W3C Trace Context](https://www.w3.org/TR/trace-context/) | Persist validated `traceparent`/`tracestate`, not an invented trace-id/correlation equivalence. | -| Deferred trace relationship | [OTel tracing API](https://opentelemetry.io/docs/specs/otel/trace/api/) | Relay spans are producer spans; deferred consumers may use propagated parent context or links. | -| Attribute safety | [OTel requirement levels](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) and [convention authoring](https://opentelemetry.io/docs/specs/semconv/how-to-write-conventions/) | Privacy-risk/high-cardinality values are not default attributes; enum attributes have a closed documented vocabulary. | +| Topic | Primary source | Constraint carried into the RFC | +| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| Prisma transactions and isolation | [Prisma transaction reference](https://www.prisma.io/docs/orm/prisma-client/queries/transactions) | Interactive callback; `maxWait`/`timeout`; exact provider isolation sets; database default when omitted. | +| PostgreSQL isolation | [PostgreSQL 18 transaction isolation](https://www.postgresql.org/docs/current/transaction-iso.html) | PostgreSQL maps `ReadUncommitted` to `ReadCommitted`; serializable failures remain possible. | +| PostgreSQL receipt claim | [`INSERT ... ON CONFLICT`](https://www.postgresql.org/docs/current/sql-insert.html), [`lock_timeout`](https://www.postgresql.org/docs/current/runtime-config-client.html), and [`set_config`](https://www.postgresql.org/docs/current/functions-admin.html) | Conflict-safe insert does not poison the callback; a bounded transaction-local lock wait controls the duplicate race. | +| MySQL receipt claim/isolation | [InnoDB error handling](https://dev.mysql.com/doc/refman/8.4/en/innodb-error-handling.html), [`innodb_lock_wait_timeout`](https://dev.mysql.com/doc/refman/8.4/en/innodb-parameters.html), and [`SET TRANSACTION`](https://dev.mysql.com/doc/refman/8.4/en/set-transaction.html) | Only four isolation levels; savepoint recovery is duplicate-specific; session timeout requires restoration. | +| SQL Server isolation | [SQL Server `SET TRANSACTION ISOLATION LEVEL`](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-ver17) | `Snapshot` requires database configuration and is not an unconditional capability. | +| SQL Server receipt claim | [`SET LOCK_TIMEOUT`](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-lock-timeout-transact-sql?view=sql-server-ver17), [table hints](https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver17), and [key-range locking](https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide?view=sql-server-ver17) | Named-index `UPDLOCK,HOLDLOCK` protects an absent singleton without duplicate-error recovery. | +| SQLite transactions | [SQLite transaction documentation](https://www.sqlite.org/lang_transaction.html) | One simultaneous writer; adapter must test busy/timeout paths rather than claim parity from a label. | +| Deno KV | [Deno KV transactions](https://docs.deno.com/deploy/kv/transactions/) and [Deno.Kv API](https://docs.deno.com/api/deno/~/Deno.Kv) | Optimistic `check` + atomic mutations with bounded checks, mutations, and bytes; refused from v1 command-store conformance. | +| Canonical JSON | [RFC 8785](https://www.rfc-editor.org/info/rfc8785/) | JCS over an I-JSON value before Web Crypto SHA-256; no `JSON.stringify` folklore. | +| Trace propagation | [W3C Trace Context](https://www.w3.org/TR/trace-context/) | Persist validated `traceparent`/`tracestate`, not an invented trace-id/correlation equivalence. | +| Deferred trace relationship | [OTel tracing API](https://opentelemetry.io/docs/specs/otel/trace/api/) | Relay spans are producer spans; deferred consumers may use propagated parent context or links. | +| Attribute safety | [OTel requirement levels](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) and [convention authoring](https://opentelemetry.io/docs/specs/semconv/how-to-write-conventions/) | Privacy-risk/high-cardinality values are not default attributes; enum attributes have a closed documented vocabulary. | ## Proposal adjudication | Proposal statement | Verdict | RFC correction | | ------------------------------------------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Reuse `withTransaction` verbatim. | Reject. | Preserve `TransactionOptions`/`IsolationLevel`, but first correct or bypass the full-client callback assertion; adapter conformance uses a true `TTx`. | -| Expose `maxIsolation`. | Reject. | Publish `supportedIsolationLevels` and configuration preconditions; levels are not one portable scalar ceiling. | +| Expose `maxIsolation`. | Reject. | Publish `selectableIsolationLevels`, separate `defaultIsolation`, and configuration preconditions; levels are not one portable scalar ceiling. | | Expose `conditionalWriteCount` as a store capability. | Reject. | Optimistic concurrency is a repository mutation contract. The command handler must perform a compare-and-set and map zero affected rows to `CommandFailure.conflict`; a read-then-compare helper is race-prone. | | `expectVersion(current)` is sufficient. | Reject. | `expectedVersion` is a string in the envelope; the guide uses one conditional write inside the transaction. No generic command kit can synthesize a model-specific CAS. | | Add `CONFLICT` globally. | Reject. | Add an opt-in `commandErrorMap` on `@netscript/contracts/commands` after #1350, preserving non-command routes. | | Store an `unknown` replay response. | Reject. | Every command supplies an explicit output codec to/from canonical JSON text; Date/BigInt/class instances cannot silently cross the receipt boundary. | -| Hash “validated input + actor + expected version.” | Narrow. | Hash exact JCS bytes for `{command, definitionVersion, scope, inputFingerprint, actorSubject, expectedVersion}` with SHA-256. Roles/scopes/claims and the idempotency key are excluded. | +| Hash “validated input + actor + expected version.” | Narrow. | Hash exact JCS bytes for `{command, definitionVersion, scope, input, actor: {kind, subject}, expectedVersion}` with SHA-256. Roles/scopes/claims and the idempotency key are excluded. | | In-flight receipt is a durable state. | Reject for the normal path. | Claim and completion are in one transaction, so incomplete claims never commit. Concurrent callers wait, replay, or receive a bounded retryable busy failure; a visible incomplete row is corruption. | | Emit raw scope, key, and expected version in telemetry. | Reject. | Emit only registered command name, bounded enums/booleans/counts, isolation, and outcome. Raw actor, scope, request/key hashes, payload, version, and correlation are prohibited by default. | | Deno KV receives weaker command semantics. | Reject from v1. | A store either conforms to same-commit command semantics or is not a `CommandStorePort`. KV delivery idempotency remains a separate runtime pattern. | @@ -90,16 +111,21 @@ failures are typed retryable outcomes; caller retry with the same key is the recovery path. 10. External I/O is forbidden inside the command callback. The only supported remote-effect path is a same-commit outbox row followed by at-least-once relay. +11. Raw relay persistence types/adapter live in database; decoded delivery/sink/supervisor live in + service. The new dependency is service → database only. +12. V1 does not depend on or wrap `@netscript/queue`; runtime DDL and incompatible settlement + semantics require a separately proposed queue reconciliation before code reuse. +13. Provider receipt claims and bounded wait mechanics are locked now, not deferred to FCP. ## JSR/public-surface audit -| Surface | Planned consequence | Gate for implementation | -| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| `@netscript/service/commands` and `./commands/testing` | New explicit subpaths; no root-budget growth. Every exported generic needs an explicit return type and module/symbol docs. `@standard-schema/spec` must be a direct package dependency. | Export-map diff, `deno doc --lint` across all service entrypoints, dry-run file-list review, consumer import fixture. | -| `@netscript/database/commands` and `./commands/testing` | Database publish include must intentionally include the new directory; transaction types must not expose generated Prisma or driver types. | Surface diff; slow-type gate; clean consumer with structural fake and real generated client. | -| `@netscript/contracts/commands` | Literal command error keys must survive isolated declarations; depends on #1350 fixing the base error-map widening. | Positive/negative type fixtures, `deno doc --lint`, publish dry-run for contracts. | -| `@netscript/telemetry/attributes` | Existing subpath grows; no new telemetry root export. Enum/value docs must be stable before publish. | Deno doc diff and exact attribute-map tests. | -| CLI-generated models/bridge/relay | Generated consumer files are not package exports, but templates and assets must be publish-safe generated constants. | Emitted-sample check, CLI scaffold runtime E2E in the implementation PR, no import-attribute/runtime file-read trap. | +| Surface | Planned consequence | Gate for implementation | +| ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `@netscript/service/commands`, `./commands/relay`, and `./commands/testing` | New explicit subpaths; no root-budget growth. Every exported generic needs an explicit return type and module/symbol docs. `@standard-schema/spec` and release-matched `@netscript/database` must be direct package dependencies. | Export/dependency-graph diff, `deno doc --lint` across all service entrypoints, dry-run file-list review, consumer import fixture. | +| `@netscript/database/commands`, provider adapter subpaths, and `./commands/testing` | Database publish include must intentionally include the new directory; raw relay/store contracts expose no service, generated Prisma, or driver type. | Surface/dependency diff; slow-type gate; clean consumer with structural fake and real generated client. | +| `@netscript/contracts/commands` | Literal command error keys must survive isolated declarations; depends on #1350 fixing the base error-map widening. | Positive/negative type fixtures, `deno doc --lint`, publish dry-run for contracts. | +| `@netscript/telemetry/attributes` | Existing subpath grows; no new telemetry root export. Enum/value docs must be stable before publish. | Deno doc diff and exact attribute-map tests. | +| CLI-generated models/bridge/relay | Generated consumer files are not package exports, but templates and assets must be publish-safe generated constants. | Emitted-sample check, CLI scaffold runtime E2E in the implementation PR, no import-attribute/runtime file-read trap. | This RFC PR changes none of those exports. Its publish consequence is therefore design evidence, not a claim that the future package surfaces already pass. The implementation must run the repository's @@ -111,9 +137,12 @@ run as a substitute for the published consumer gate. - Must a v1 command definition require idempotency, or may it explicitly declare `optional` and surface `not_requested`? The RFC recommends required-by-default and permits opt-out only by an explicit policy. -- Is SQLite a v1 release blocker or a later conforming adapter? Current NetScript has no SQLite - adapter to validate; the RFC recommends later, with no claim until conformance passes. +- Does v1 accept SQLite's default-only shape (`selectableIsolationLevels: []`, + `defaultIsolation: 'Serializable'`), and is that adapter a first-release blocker? The RFC + recommends accepting the shape but releasing later, with no support claim until conformance. - Should command correlation IDs be opt-in telemetry attributes under a redaction policy, or stay - durable/log-only? The RFC recommends durable/log-only by default. + durable/log-only, and should existing messaging/saga correlation/idempotency attributes be + separately deprecated/redacted to remove operator asymmetry? The RFC recommends durable/log-only + commands and separate cleanup. - What retention defaults apply to receipts, audit, and published outbox rows? The RFC fixes safety constraints but leaves durations to FCP because they are operational policy, not atomicity. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md index 617b5209f3..a764131231 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md @@ -2,12 +2,12 @@ ## Run Metadata -| Field | Value | -| -------------- | --------------------------------------------------------------- | -| Run ID | `docs-rfc-command-composition-kit--rfc` | -| Branch | `docs/rfc-command-composition-kit` | -| Archetype | Docs delivery describing Archetypes 1–6 implementation surfaces | -| Scope overlays | `SCOPE-docs`, `SCOPE-service` | +| Field | Value | +| -------------- | ------------------------------------------------------------------------------------------------------------------- | +| Run ID | `docs-rfc-command-composition-kit--rfc` | +| Branch | `docs/rfc-command-composition-kit` | +| Archetype | Docs delivery describing A4 contracts/service, A2 adapters/telemetry, A3 runtime discipline, A5 plugins, and A6 CLI | +| Scope overlays | `SCOPE-docs`, `SCOPE-service` | ## Design @@ -19,12 +19,14 @@ after ratification. ### Public Surface - `rfcs/0000-command-composition-kit.md` — draft RFC only; no product export changes. -- Future `@netscript/service/commands` executor/DSL and testing subpath. -- Future `@netscript/database/commands` transaction store, provider adapters, and conformance - subpath. +- Future `@netscript/service/commands` executor/DSL plus `./commands/relay` decoded runtime/sink and + testing subpaths. +- Future `@netscript/database/commands` raw command/relay stores, provider adapter subpaths, and + conformance subpath; service adds a direct database dependency and database never imports service. - Future opt-in `@netscript/contracts/commands` error map and existing telemetry attributes extension. -- Explicit consumer-owned receipt/audit/outbox models and generated relay/command bridge. +- Explicit consumer-owned receipt/audit/outbox models and `db command-store add` generated + relay/command bridge plus `CommandTransactionClient`. - One attempt-scoped `executionId` joins receipt, audit, and outbox evidence; typed codecs guard replay outputs and outbox payloads. @@ -40,8 +42,9 @@ after ratification. - command store — conformant only where one transaction-scoped client can write business state, receipt, audit, and outbox rows; no weaker implementation satisfies the port. -- outbox relay store/transport — separate post-commit runtime seam; it cannot enlarge the - transaction boundary. +- outbox relay store — database-owned raw lease/token/release port; no decoded service type. +- relay sink/supervisor — service-owned decoded post-commit runtime seam; it cannot enlarge the + transaction boundary and does not make database depend on service. - telemetry/redaction policy — injected observability seam with bounded attributes. ### Constants @@ -58,6 +61,7 @@ after ratification. | S1 | Re-baseline proposal, code, exports, tests, docs, live board, and primary adapter guarantees; lock the plan. | evidence inventory; `deno doc`; plan-gate readiness check | run `research.md`, `plan.md`, `worklog.md`, `context-pack.md`, `drift.md` | | S2 | Define the exact public contracts, semantic laws, capability matrix, failure/telemetry/security model, and examples. | source-alignment audit; focused probes | RFC plus run artifacts | | S3 | Complete worker/saga boundary, conformance/failure injection, compatibility, staging, docs/scaffold impact, issue decomposition, and handoff. | docs/RFC/link/format/diff gates | RFC, run artifacts, `final-handoff.md` | +| S4 | Remediate authoritative PLAN-EVAL cycle-1 findings F-B1–F-B7 without self-evaluation. | provider/source probes; docs/type/link/diff checks | RFC, research/plan/worklog/context/drift/final handoff, launcher metadata | ### Deferred Scope @@ -76,48 +80,60 @@ capabilities. ## Progress Log -| Time | Slice | Step | Notes | -| ---------- | ----- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 2026-08-08 | B0 | bootstrap | Read all named skills and required RFC/harness/doctrine/evaluator authority; verified pinned branch/base. | -| 2026-08-08 | B0 | session health | Agentic runtime status made no changes and returned `MISSING_IDENTITY`; preserved the staged attached-thread receipt. | -| 2026-08-08 | B0 | live issue check | Confirmed #1361–#1364 and source PR #1347 exist; detailed re-baseline continues in S1. | -| 2026-08-08 | B0 | publish | Committed `ad643e15d657eb2b8e7a2d741e690c028ce67dc9`, pushed only as `HEAD:refs/heads/docs/rfc-command-composition-kit`, and opened draft PR #1389. | -| 2026-08-08 | B0 | PR metadata | Applied the required docs/RFC/area/priority/CI labels with exactly `status:research`; posted the opening `[PHASE: RESEARCH]` comment. | -| 2026-08-08 | S1 | public API re-baseline | Used native `deno doc` on database/service/contracts/telemetry/workers/sagas/SDK and oRPC; inspected export maps and source where the public surface was insufficient. | -| 2026-08-08 | S1 | focused probes | Proved `withTransaction` exposes root-only methods inside its callback (unexpected PASS) and reproduced #1350's `error.code` → `never` failure; removed both probes after execution. | -| 2026-08-08 | S1 | runtime/store research | Compared Prisma provider isolation, PostgreSQL, SQL Server, SQLite, Deno KV, RFC 8785, W3C Trace Context, and OTel primary documents. | -| 2026-08-08 | S1 | proposal challenge | Found the reserved saga outbox port, dynamic service context, missing SQLite adapter, route-local oRPC error composition, and #1293 package conflation; recorded corrections in `research.md`. | -| 2026-08-08 | S1 | plan lock | Locked package ownership, hash/codec rules, no-weak-port/no-hidden-retry laws, telemetry redaction, adapter truth, and board decomposition; plan gate is ready. | -| 2026-08-08 | S2 | RFC contract draft | Authored the complete template-based RFC with exact service/store/contract/relay types, consumer-owned logical rows, JCS hashing, transaction algorithm, and semantic laws. | -| 2026-08-08 | S2 | production review | Added an attempt `executionId`, schema-backed outbox payloads, deterministic scope constraints, and an explicit retry/terminal relay release union after reviewing the exact contracts. | -| 2026-08-08 | S2 | boundary proof | Kept remote delivery post-commit and at least once; separated the existing saga outbox and worker delivery claims from the command receipt/store guarantee. | -| 2026-08-08 | S2 | surface design | Specified focused service/database/contracts subpaths and telemetry additions, JSR/slow-type/publish consequences, migration ownership, and staged implementation without changing exports. | -| 2026-08-08 | S2 | type-shape probe | Checked a synthetic command definition against current DB types, Zod, and Standard Schema. Initial resolution exposed the missing service dependency; direct JSR import passed; probe removed. | -| 2026-08-08 | S3 | docs/RFC gates | Scoped format/diff, repository docs links/accuracy, RFC frontmatter/section/terminology assertions, and docs-only changed-file audit passed. | -| 2026-08-08 | S3 | JSR baseline | Full-entrypoint doc-lint reported service 0, database combined 0, contracts 9 existing private-type findings, and telemetry 7 existing findings; no package file changed. | -| 2026-08-08 | S3 | PR reconciliation | Review-thread gate passed with 0 threads/unanswered; PR-check gate passed with 15 checks and 0 current failures (docs-only lanes intentionally skipped). | +| Time | Slice | Step | Notes | +| ---------- | ----- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 2026-08-08 | B0 | bootstrap | Read all named skills and required RFC/harness/doctrine/evaluator authority; verified pinned branch/base. | +| 2026-08-08 | B0 | session health | Agentic runtime status made no changes and returned `MISSING_IDENTITY`; preserved the staged attached-thread receipt. | +| 2026-08-08 | B0 | live issue check | Confirmed #1361–#1364 and source PR #1347 exist; detailed re-baseline continues in S1. | +| 2026-08-08 | B0 | publish | Committed `ad643e15d657eb2b8e7a2d741e690c028ce67dc9`, pushed only as `HEAD:refs/heads/docs/rfc-command-composition-kit`, and opened draft PR #1389. | +| 2026-08-08 | B0 | PR metadata | Applied the required docs/RFC/area/priority/CI labels with exactly `status:research`; posted the opening `[PHASE: RESEARCH]` comment. | +| 2026-08-08 | S1 | public API re-baseline | Used native `deno doc` on database/service/contracts/telemetry/workers/sagas/SDK and oRPC; inspected export maps and source where the public surface was insufficient. | +| 2026-08-08 | S1 | focused probes | Proved `withTransaction` exposes root-only methods inside its callback (unexpected PASS) and reproduced #1350's `error.code` → `never` failure; removed both probes after execution. | +| 2026-08-08 | S1 | runtime/store research | Compared Prisma provider isolation, PostgreSQL, SQL Server, SQLite, Deno KV, RFC 8785, W3C Trace Context, and OTel primary documents. | +| 2026-08-08 | S1 | proposal challenge | Found the reserved saga outbox port, dynamic service context, missing SQLite adapter, route-local oRPC error composition, and #1293 package conflation; recorded corrections in `research.md`. | +| 2026-08-08 | S1 | plan lock | Locked package ownership, hash/codec rules, no-weak-port/no-hidden-retry laws, telemetry redaction, adapter truth, and board decomposition; plan gate is ready. | +| 2026-08-08 | S2 | RFC contract draft | Authored the complete template-based RFC with exact service/store/contract/relay types, consumer-owned logical rows, JCS hashing, transaction algorithm, and semantic laws. | +| 2026-08-08 | S2 | production review | Added an attempt `executionId`, schema-backed outbox payloads, deterministic scope constraints, and an explicit retry/terminal relay release union after reviewing the exact contracts. | +| 2026-08-08 | S2 | boundary proof | Kept remote delivery post-commit and at least once; separated the existing saga outbox and worker delivery claims from the command receipt/store guarantee. | +| 2026-08-08 | S2 | surface design | Specified focused service/database/contracts subpaths and telemetry additions, JSR/slow-type/publish consequences, migration ownership, and staged implementation without changing exports. | +| 2026-08-08 | S2 | type-shape probe | Checked a synthetic command definition against current DB types, Zod, and Standard Schema. Initial resolution exposed the missing service dependency; direct JSR import passed; probe removed. | +| 2026-08-08 | S3 | docs/RFC gates | Scoped format/diff, repository docs links/accuracy, RFC frontmatter/section/terminology assertions, and docs-only changed-file audit passed. | +| 2026-08-08 | S3 | JSR baseline | Full-entrypoint doc-lint reported service 0, database combined 0, contracts 9 existing private-type findings, and telemetry 7 existing findings; no package file changed. | +| 2026-08-08 | S3 | PR reconciliation | Review-thread gate passed with 0 threads/unanswered; PR-check gate passed with 15 checks and 0 current failures (docs-only lanes intentionally skipped). | +| 2026-08-08 | S4 | evaluator intake | Preserved evaluator commit `122301d25`; read `plan-eval.md` completely and accepted `FAIL_PLAN`/F-B1–F-B7/Required-for-PASS as authoritative. | +| 2026-08-08 | S4 | provider verification | Re-read doctrine/harness authority; checked queue runtime DDL/lease semantics, service/database dependencies, MySQL isolation, telemetry/worker vocabulary, current CLI `db` help, and primary lock docs. | +| 2026-08-08 | S4 | Prisma type probe | Generated a temporary Prisma 7.8 client, confirmed `Prisma.TransactionClient`, found current deny-list retains `$transaction`, locked the generator-owned explicit `Omit`, and removed the probe. | +| 2026-08-08 | S4 | RFC remediation | Added normative PostgreSQL/MySQL/SQL Server receipt claims/timeouts, relay ownership, queue rejection/reconciliation, identity drift laws, MySQL/SQLite truth, generated typing, and F-B7 batch corrections. | ## Decisions -| Decision | Reason | Source | -| ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | -| Keep this PR docs-only and RFC number `0000`. | RFC lifecycle and issue #1361 scope. | `rfcs/README.md`, #1361 | -| Use all Archetypes 1–6 as implementation-surface constraints, with docs/service overlays for this run. | The design crosses contracts, adapters, DSL, runtime, plugins, and CLI generators but this PR changes none of them. | Doctrine chapter 06; harness archetypes | -| Do not launch evaluators or a second Codex session. | Owner reserves review/evaluation for the root orchestrator; mobile-visible thread must remain singular. | implementation brief; `codex-wsl-remote` | -| Put command semantics in service, transaction persistence in database, opt-in errors in contracts, and attributes in telemetry. | Preserves focused subpaths and one-way service → database dependency without a new package. | code/export re-baseline; doctrine A9–A11 | -| Reject a weak KV command mode and automatic callback retry. | Either all local rows share one commit or the adapter does not conform; caller retry is receipt-safe and observable. | Deno KV docs; doctrine A12–A13 | -| Reject read-then-compare concurrency and unknown receipt values. | CAS is repository-specific; explicit JCS fingerprints/codecs prevent races and serialization ambiguity. | Prisma OCC docs; RFC 8785; focused API analysis | -| Keep remote effects outside the callback and relay stable outbox IDs at least once. | SQL cannot roll back network effects; publish-then-crash can duplicate delivery. | worker/saga code; OTel/W3C docs; doctrine chapter 08 | -| Join receipt, audit, and outbox evidence with one attempt `executionId`. | Correlation alone is neither unique nor a reliable ownership/join key; optional unkeyed attempts still need identity. | S2 exact-row review | -| Require a schema-backed codec for each outbox payload and model terminal relay release explicitly. | Producer type safety and exhaustion handling cannot exist only in prose. | S2 exact-port review | +| Decision | Reason | Source | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| Keep this PR docs-only and RFC number `0000`. | RFC lifecycle and issue #1361 scope. | `rfcs/README.md`, #1361 | +| Select A4 for contracts/service DSLs, A2 for database/telemetry adapters, A3 for relay runtime discipline, A5 for thin plugin integrations, and A6 for generators; A1 was read but is not selected. | The design crosses those implementation surfaces, while this PR changes documentation only. | Doctrine chapter 06; harness archetypes | +| Do not launch evaluators or a second Codex session. | Owner reserves review/evaluation for the root orchestrator; mobile-visible thread must remain singular. | implementation brief; `codex-wsl-remote` | +| Put command semantics in service, transaction persistence in database, opt-in errors in contracts, and attributes in telemetry. | Preserves focused subpaths and one-way service → database dependency without a new package. | code/export re-baseline; doctrine A9–A11 | +| Reject a weak KV command mode and automatic callback retry. | Either all local rows share one commit or the adapter does not conform; caller retry is receipt-safe and observable. | Deno KV docs; doctrine A12–A13 | +| Reject read-then-compare concurrency and unknown receipt values. | CAS is repository-specific; explicit JCS fingerprints/codecs prevent races and serialization ambiguity. | Prisma OCC docs; RFC 8785; focused API analysis | +| Keep remote effects outside the callback and relay stable outbox IDs at least once. | SQL cannot roll back network effects; publish-then-crash can duplicate delivery. | worker/saga code; OTel/W3C docs; doctrine chapter 08 | +| Join receipt, audit, and outbox evidence with one attempt `executionId`. | Correlation alone is neither unique nor a reliable ownership/join key; optional unkeyed attempts still need identity. | S2 exact-row review | +| Require a schema-backed codec for each outbox payload and model terminal relay release explicitly. | Producer type safety and exhaustion handling cannot exist only in prose. | S2 exact-port review | +| Lock provider-specific receipt algorithms and treat claim timeout as callback-terminal. | Prevents PostgreSQL poisoning, MySQL error over-swallowing, SQL Server race, and session timeout leakage. | PLAN-EVAL F-B1; primary provider docs | +| Split relay persistence into database and decoded runtime/sinks into service. | Preserves dependency direction while giving every public relay type an owner. | PLAN-EVAL F-B2; doctrine ports/layering | +| Reject direct queue-package reuse in v1 and propose runtime-DDL reconciliation first. | Queue deletes/acks/DLQs and hidden schema creation do not implement retained token-settled outbox semantics. | PLAN-EVAL F-B3; queue source | +| Treat changed scope/name as execute-as-new and require determinism/compatibility fixtures. | The unique key cannot detect identity in another namespace; migration law must match actual behavior. | PLAN-EVAL F-B4 | +| Separate selectable/default isolation and require MySQL four-level allow-list. | Makes SQLite default-only behavior and MySQL's false `SNAPSHOT` token honest. | PLAN-EVAL F-B5/F-B7f | +| Generate `CommandTransactionClient` from the consumer's Prisma namespace and explicitly omit root methods. | Model delegates are consumer-specific, and current Prisma deny-list retains nested `$transaction`. | PLAN-EVAL F-B6; focused probe | ## Drift -| Drift | Severity | Logged in drift.md | -| ---------------------------------------------------------------------------------------------- | ----------- | ------------------ | -| Runtime controller could not correlate the active staged thread to persisted runtime identity. | minor | yes | -| Proposal says no outbox exists, but a reserved saga outbox port is public. | significant | yes | -| Proposal treats current SQLite/MySQL/package and transaction-helper surfaces too broadly. | significant | yes | +| Drift | Severity | Logged in drift.md | +| ----------------------------------------------------------------------------------------------------- | ----------- | ------------------ | +| Runtime controller could not correlate the active staged thread to persisted runtime identity. | minor | yes | +| Proposal says no outbox exists, but a reserved saga outbox port is public. | significant | yes | +| Proposal treats current SQLite/MySQL/package and transaction-helper surfaces too broadly. | significant | yes | +| Cycle-1 evaluator found receipt algorithms, relay ownership, and queue reuse were silently deferred. | critical | yes | +| Queue's existing runtime schema creation conflicts with the new command-kit no-hidden-migration rule. | significant | yes | ## Gate Results diff --git a/rfcs/0000-command-composition-kit.md b/rfcs/0000-command-composition-kit.md index 29a23d2daa..21dfb367f9 100644 --- a/rfcs/0000-command-composition-kit.md +++ b/rfcs/0000-command-composition-kit.md @@ -21,6 +21,10 @@ span stores, and network effects inside the transaction are refused rather than This is a command boundary, not an ORM, workflow engine, event-sourcing system, or distributed transaction protocol. +The frontmatter `target-milestone: 0.0.6` is the target for **RFC ratification only**. It is not an +implementation availability date: the implementation umbrella is #1363 in `0.0.8`, and the +literal-error prerequisite #1350 is currently targeted to `0.0.7`. + ## Motivation NetScript currently exposes useful pieces but no supported way to compose them into a production @@ -119,7 +123,7 @@ compare it in memory. ```ts import { type CommandDefinition, defineCommand, jsonCodec } from '@netscript/service/commands'; -import type { PrismaTransactionClient } from '@database'; +import type { CommandTransactionClient } from '@database'; import { z } from 'zod'; import { projectOutput, projectRenamedPayload, renameProjectInput } from '../contracts/projects.ts'; @@ -184,7 +188,7 @@ export const renameProjectCommand = defineCommand({ 'projects.rename', z.infer, z.infer, - PrismaTransactionClient + CommandTransactionClient >; ``` @@ -299,19 +303,27 @@ exactly-once claim. ### Package and export placement -| Surface | Owner | Reason | -| -------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -| `@netscript/service/commands` | command definition, executor, envelope, context, typed application failures | Commands are a service/application concern. A focused subpath preserves the root export budget. | -| `@netscript/service/commands/testing` | executor fixtures and fault controls | Testing-only public utilities stay off the production root. | -| `@netscript/database/commands` | transaction-bound store contracts and provider adapters | Database owns transaction/isolation vocabulary and the generated-client bridge. Service depends one way on this subpath. | -| `@netscript/database/commands/testing` | adapter conformance suite | Provider truth is tested at its owning adapter seam. | -| `@netscript/contracts/commands` | opt-in Zod schemas and command error map | Transport errors remain contract-first without changing all routes. | -| `@netscript/telemetry/attributes` | command span/attribute constants and builder | Extends the existing telemetry vocabulary where job/saga builders already live. | +| Surface | Owner | Reason | +| -------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | +| `@netscript/service/commands` | command definition, executor, envelope, context, typed application failures | Commands are a service/application concern. A focused subpath preserves the root export budget. | +| `@netscript/service/commands/relay` | relay supervisor, decoded delivery value, sink port, registry, shutdown handle | Runtime delivery policy consumes database persistence; it does not leak service value types into database. | +| `@netscript/service/commands/testing` | executor and relay fixtures plus fault controls | Testing-only public utilities stay off production roots. | +| `@netscript/database/commands` | transaction-bound command-store and relay-store persistence contracts | Database owns transaction, isolation, raw persisted-row, claim-token, and release vocabulary. It imports no service type. | +| `@netscript/database/commands/adapters/` | PostgreSQL/MySQL/SQL Server command and relay store adapters | Technology-specific adapters remain behind database-owned ports and provider subpaths. | +| `@netscript/database/commands/testing` | command-store and relay-store adapter conformance suites | Provider truth is tested at its owning adapter seam. | +| `@netscript/contracts/commands` | opt-in Zod schemas and command error map | Transport errors remain contract-first without changing all routes. | +| `@netscript/telemetry/attributes` | command span/attribute constants and builder | Extends the existing telemetry vocabulary where job/saga builders already live. | No `@netscript/commands` package is introduced. None of these symbols is re-exported from an existing package root in v1. Internal imports within a package use relative paths, avoiding the self-referential JSR subpath trap. +The dependency arrow is exactly `@netscript/service` → `@netscript/database`: the executor and relay +runtime consume database-owned ports. This is a new direct package edge. The implementation must add +a pinned `@netscript/database` entry to `packages/service/deno.json`, prove it with +`deno info`/consumer-import checks, and include it in the service publish surface. Database never +imports `CommandJson`, `CommandTraceContext`, a sink, a worker, or any other service/runtime type. + ### Value, identity, and envelope contracts ```ts @@ -453,7 +465,7 @@ export interface CommandContext { export type CommandExecution = Readonly<{ value: TOutput; outcome: 'applied' | 'replayed'; - idempotency: 'committed' | 'replayed' | 'not_requested'; + idempotency: 'claimed' | 'replayed' | 'not_requested'; correlationId: string; }>; @@ -505,6 +517,7 @@ export type CommandExecutorOptions = Readonly<{ clock?: CommandClock; ids?: CommandIdSource; telemetry?: CommandTelemetryPort; + receiptClaimWaitMs?: number; limits?: Readonly<{ auditRecords: number; outboxRecords: number; @@ -540,6 +553,11 @@ The exported `CommandDefinition` is read-only and does not expose a public const handler remains part of the opaque definition returned by `defineCommand()`, preventing callers from bypassing the executor by invoking a public `handle` member. +`receiptClaimWaitMs` is a bounded executor policy, not a caller-controlled envelope value. The +executor validates it against the store's advertised minimum, maximum, and granularity before +opening a transaction and passes the normalized value in `CommandTransactionRequest`. An adapter +must report its effective wait when its engine has coarser units (MySQL rounds up to whole seconds). + ### Transaction-bound store contracts The database subpath owns the transaction vocabulary and imports no service types. The business @@ -552,11 +570,18 @@ export type CommandStoreCapabilities = Readonly<{ sideRecordAtomicity: 'same_commit'; callbackAttempts: 'one'; cancellation: 'cooperative' | 'driver'; - supportedIsolationLevels: readonly IsolationLevel[]; + selectableIsolationLevels: readonly IsolationLevel[]; + defaultIsolation: IsolationLevel | 'provider_configured'; + receiptClaimWait: Readonly<{ + minimumMs: number; + maximumMs: number; + granularityMs: number; + }>; }>; export type CommandTransactionRequest = Readonly<{ options?: TransactionOptions; + receiptClaimWaitMs: number; }>; export type ReceiptClaim = Readonly<{ @@ -661,6 +686,11 @@ by the side-record bridge. busy failures. The adapter may retry connection acquisition before invoking `work`, but once invoked the result is commit, rollback, or a surfaced failure. +`ReceiptClaimResult.kind: "busy"` is terminal for the current callback. The executor issues no more +store query, throws its internal claim-busy sentinel, waits for `transaction()` to report rollback, +and only then exposes `CommandError({ kind: "in_progress" })`. `retryAfterMs`, when present, is the +adapter's normalized effective wait/backoff hint, not proof that the leader will finish by then. + `cancellation: "cooperative"` means the adapter checks the signal before beginning and between framework-controlled steps but the driver cannot interrupt an already-issued query. Such an adapter must also enforce a transaction timeout. `"driver"` may be advertised only when the actual driver @@ -752,14 +782,36 @@ Provider generators may add efficient native projections, but the portable contr ### Schema and bridge ownership -`netscript db command-store init --database ` is the proposed explicit generator. It: +`netscript db command-store add --database ` is the proposed explicit generator. The +sub-noun is deliberate: existing `netscript db init` creates/applies the database's initial Prisma +migration, while `db command-store add` adds one optional feature to an already configured database. +It: 1. detects the configured Prisma provider; 2. appends provider-specific receipt/audit/outbox models using stable `NetScriptCommand*` names; 3. creates a reviewable migration, including unique/check/index definitions; 4. emits `database//command-store.ts`, which binds the generated delegates and true - transaction client to `CommandStorePort`; and -5. refuses to overwrite edited models or run a migration without the consumer's normal DB command. + transaction client to `CommandStorePort`; +5. emits and re-exports the consumer-specific transaction type shown below; and +6. refuses to overwrite edited models or run a migration without the consumer's normal DB command. + +```ts +// generated in database//command-store.ts +import type { Prisma } from './schema/.generated/client.ts'; + +export type CommandTransactionClient = Omit< + Prisma.TransactionClient, + '$transaction' | '$connect' | '$disconnect' | '$on' | '$use' | '$extends' +>; +``` + +The configured engine module re-exports `CommandTransactionClient` and `commandStore`, so the +workspace's existing `@database` facade supports the guide import. This alias is generated because +it depends on the consumer's models. A focused Prisma 7.8 probe at RFC time confirmed that the +generated client exports `Prisma.TransactionClient`; the explicit `Omit` is still required because +the current Prisma deny-list does not remove nested `$transaction`. Emitted-sample type tests prove +that model delegates are present and that every listed root/lifecycle method is rejected. The +framework packages do not invent a model-agnostic fake transaction-client export. The package never injects models during import, service startup, `defineService()`, or relay startup. The generated bridge is consumer-owned, checked in, and discoverable. Model renames require @@ -801,10 +853,21 @@ the idempotency key are excluded. The command author must include every input fi the effect. Negative conformance mutates each contract field and proves either that the fingerprint changes or that the field is explicitly classified transport-only. -`scope()` is equally deterministic: it may use only the supplied input and narrowed actor, performs -no I/O, and excludes transport-only idempotency, trace, and correlation values. Scope partitions a -receipt namespace (for example by tenant or aggregate); it must not vary between retries of the same -intent. The restricted argument deliberately withholds the rest of `CommandEnvelope`. +`scope()` has the same purity and determinism obligation as `fingerprint()`: for the same deeply +frozen `{ input, actor }` it returns the same bounded UTF-8 string across processes, retries, and +deployments. It may use only that argument, performs no I/O, reads no clock/random/global/config +state, and excludes transport-only idempotency, trace, and correlation values. Scope partitions a +receipt namespace (for example by tenant or aggregate). The restricted argument deliberately +withholds the rest of `CommandEnvelope`. `@netscript/service/commands/testing` supplies an identity +fixture that invokes `scope()` and `fingerprint()` repeatedly with equivalent frozen values and +fails nondeterministic definitions; production execution still evaluates each exactly once. + +The unique key makes the consequence of identity drift explicit. The same raw idempotency key under +a **different scope** or **different command name** is a different receipt key and therefore +executes as new. The framework cannot label it reuse because no row exists in that namespace. This +is not a loophole to exploit: changing scope logic or renaming a command is a breaking replay +migration. Keep the old definition/name as an alias through the maximum receipt retry window, or +migrate receipt keys and prove the mapping before deploying the new identity. `definitionVersion` changes when request identity, response decoding, or command meaning changes. Because the receipt unique key does not include that version, a retry crossing a deployment returns @@ -847,6 +910,46 @@ append and completion still belongs to the same transaction. A business error th remains the handler's declared error; the executor does not wrap arbitrary application errors as storage failures. +### Normative receipt-claim algorithms + +The generated unique key is the concurrency primitive; adapters do not run an unprotected +select-then-insert and do not retry the transaction callback. `claimReceipt()` is the first +persistence operation in the callback. Every adapter implements the following state machine: + +1. attempt one provider-safe claim for `(scope, commandName, keyHash)` with the bounded claim wait; +2. if this transaction inserted the row, return `execute`; +3. if a committed row won, load it and return `replay` or `mismatch` after comparing + `requestHash`/`commandVersion` and completeness; and +4. if lock acquisition times out, terminate the callback, roll back the whole transaction, and map + the provider error to `busy`. No query is issued in that transaction after `busy`. + +Unexpected constraint/data errors are never treated as duplicates. Serialization/deadlock victims +surface as retryable `store_failure`; `callbackAttempts: "one"` remains true. At stronger isolation, +a provider may choose a serialization victim rather than a replay winner, and the caller retries the +whole request with the same key. + +Provider mechanics are normative for v1: + +| Provider | Claim statement/lock | Bounded-wait mechanics | Leader commits | Leader rolls back | +| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | +| PostgreSQL | `INSERT ... ON CONFLICT (scope, command_name, key_hash) DO NOTHING RETURNING id`; empty `RETURNING` is followed by one indexed `SELECT` | Save `current_setting('lock_timeout')`; call parameterized `set_config('lock_timeout', 'ms', true)` before the insert and restore the saved value after a successful claim path. SQLSTATE `55P03` becomes `busy` and the outer transaction rolls back. | The insert waits, returns no row, and the next `READ COMMITTED` statement loads the winner. At `REPEATABLE READ`/`SERIALIZABLE`, a legitimate `40001` is a retryable store failure. | The waiting insert proceeds and returns its generated receipt ID, so the follower executes. | +| MySQL/InnoDB | `SAVEPOINT netscript_receipt_claim`; plain `INSERT`; only error `1062` rolls back to/releases that savepoint and performs the indexed `SELECT`. `INSERT IGNORE` is forbidden because it can downgrade non-duplicate data errors to warnings. | On the leased connection, read `@@SESSION.innodb_lock_wait_timeout`, set the validated `ceil(ms / 1000)` whole-second value before claim, and restore it in connection `finally` after commit/rollback. Error `1205` becomes `busy`; error `1213` is a retryable store failure. The outer transaction always rolls back after either, independent of `innodb_rollback_on_timeout`. A failed restore discards the pooled connection. | The waiting insert receives `1062`; savepoint recovery leaves the transaction usable and the indexed select loads the winner. | The waiting insert succeeds and the follower executes. | +| SQL Server | First select the exact generated unique index with `WITH (UPDLOCK, HOLDLOCK, INDEX([UX_NetScriptCommandReceipt_scope_command_key]))`; return replay/mismatch when found, otherwise insert while the serializable key-range update lock is held. `MERGE` and catch-and-continue on 2601/2627 are not used. | Read `@@LOCK_TIMEOUT`, issue `SET LOCK_TIMEOUT ` on the leased connection, and restore the prior integer after commit/rollback. Error `1222` becomes `busy`; deadlock victim `1205` is a retryable store failure. A failed restore discards the pooled connection. | The follower's range-lock read resumes and observes the committed row. | The follower's range-lock read resumes, observes no row, inserts, and executes. | + +All identifiers in these statements come from generated, provider-quoted schema constants. Values +are bound parameters. The timeout literals are adapter-created decimal integers after range +validation; caller text is never interpolated. PostgreSQL's transaction-local setting resets on +rollback. MySQL and SQL Server settings are session-scoped, so acquiring one connection for the +whole transaction and restoring/discarding it before pool return is part of conformance, not an +optimization. + +The PostgreSQL follow-up select is intentionally tied to `READ COMMITTED` replay behavior. At a +stronger snapshot level, a serialization outcome is safer than executing against an invisible +winner. The SQL Server query's `HOLDLOCK` gives the receipt lookup serializable range semantics even +when the surrounding command uses another advertised isolation; `UPDLOCK` also forces locking under +snapshot modes. Generated migrations must keep the named composite unique index that makes the +singleton/range lock possible. + ### Semantic laws Every conforming implementation and adapter satisfies these laws: @@ -867,7 +970,7 @@ Every conforming implementation and adapter satisfies these laws: 7. **CAS law.** A command requiring optimistic concurrency performs the version predicate in the mutation. Zero matched rows becomes a conflict and rolls back every buffered record. 8. **No-hidden-retry law.** One executor call invokes the handler no more than once. -9. **Isolation-refusal law.** A requested level absent from `supportedIsolationLevels` is refused +9. **Isolation-refusal law.** A requested level absent from `selectableIsolationLevels` is refused before opening the transaction. 10. **Stable-message law.** A committed outbox row retains one `id`/`dedupeKey` across every relay claim, lease expiry, retry, and redelivery. @@ -875,6 +978,9 @@ Every conforming implementation and adapter satisfies these laws: but publish-before-crash may result in the same message being observed again. 12. **Boundary law.** No SQL+KV, SQL+stream, SQL+HTTP, two-database, or other cross-store operation is represented as one command transaction. +13. **Deterministic-identity law.** Equivalent frozen identity values produce identical scope and + fingerprint results. A changed scope or command name is explicitly a new receipt namespace and + executes as new; a changed definition version under the same receipt key is a mismatch. “At most one handler commits” is conditional on a supplied idempotency key. An optional attempt without one retains only the atomic rollback and same-commit laws. @@ -890,11 +996,13 @@ result proves whether it matched. A preliminary read may be useful for business replaces the conditional write. The proposal's `expectVersion(current)` is rejected because another transaction can write between comparison and mutation. -Isolation is a set, not a scalar “maximum.” The command declares the minimum concrete level its -algorithm was tested with. Omitting `isolationLevel` uses the database default and records `default` -in command telemetry; it does not claim a portable effective level. Commands maintaining multi-row -invariants normally require `Serializable` or another provider-specific locking design and must test -serialization/deadlock outcomes. +Isolation is a set, not a scalar “maximum.” `selectableIsolationLevels` means levels the Prisma +transaction API and configured adapter accept explicitly; `defaultIsolation` separately describes +the omitted-option path. The command declares the concrete selectable level its algorithm was tested +with. Omitting `isolationLevel` uses the database default and records `default` in command +telemetry; it does not claim a portable effective level when the capability says +`provider_configured`. Commands maintaining multi-row invariants normally require `Serializable` or +another provider-specific locking design and must test serialization/deadlock outcomes. The executor does not automatically retry serialization, deadlock, or SQLite busy failures. Those become retryable store outcomes. A caller can retry the entire request with the same key, which is @@ -904,14 +1012,14 @@ safe whether the original attempt rolled back or committed before its response w “Engine feasible” and “currently integrated by NetScript” are deliberately separate: -| Store | Engine/Prisma transaction facts | Current NetScript integration at `fac9e339` | RFC position | -| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | -| PostgreSQL + Prisma | interactive transactions; `ReadUncommitted` maps to `ReadCommitted`; `ReadCommitted`, `RepeatableRead`, `Serializable` available | Postgres adapter/root surface exists | reference v1 adapter after full conformance | -| MySQL + Prisma | interactive; `ReadUncommitted`, `ReadCommitted`, `RepeatableRead`, `Serializable`; no `Snapshot` | `@netscript/database/adapters/mysql` exists | conforming v1 target; #1293 is adjacent lower-level surface work, not an atomicity prerequisite | -| SQL Server + Prisma | interactive; all five current `IsolationLevel` values; `Snapshot` requires database enablement | `@netscript/database/adapters/mssql` exists | conforming v1 target; capability must omit `Snapshot` when not enabled | -| SQLite + Prisma | transactions are serializable in Prisma's matrix; multiple readers but one writer; busy/timeout behavior differs | provider enum exists, but no NetScript SQLite adapter export | feasible but unsupported/unclaimed until an adapter and real contention/fault suite land | -| Deno KV | optimistic atomic checks/mutations with operation limits; no interactive callback | `@netscript/kv` and worker idempotency exist | not a v1 `CommandStorePort`; no weaker command mode | -| two SQL stores or SQL + KV/stream/HTTP | no portable shared commit | components may exist separately | refused; commit an outbox intent and continue through a consumer/saga | +| Store | Engine/Prisma transaction facts | Capability truth required by this RFC | RFC position | +| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | +| PostgreSQL + Prisma | interactive transactions; `ReadUncommitted` maps to `ReadCommitted`; `ReadCommitted`, `RepeatableRead`, `Serializable` available | selectable set omits `Snapshot`; provider/configured default recorded separately | reference v1 adapter after full conformance | +| MySQL + Prisma | interactive; `ReadUncommitted`, `ReadCommitted`, `RepeatableRead`, `Serializable`; no `Snapshot` | exactly those four selectable values. Current lower adapter's exported `SNAPSHOT` and unchecked SQL interpolation must be fixed before conformance | conforming v1 target; #1293 remains adjacent, not this isolation defect | +| SQL Server + Prisma | interactive; all five current `IsolationLevel` values; `Snapshot` requires database enablement | selectable set includes `Snapshot` only after an enablement probe; otherwise the four lock-based levels | conforming v1 target after real configuration/conformance | +| SQLite + Prisma | engine default is serializable; current generated/Prisma surface does not provide a portable explicit isolation-selection path | future adapter advertises `selectableIsolationLevels: []`, `defaultIsolation: 'Serializable'`; explicit `Serializable` is still refused | default-only conformance and release timing remain FCP Q2; no current support claim | +| Deno KV | optimistic atomic checks/mutations with operation limits; no interactive callback | cannot advertise interactive/same-commit SQL capabilities | not a v1 `CommandStorePort`; no weaker command mode | +| two SQL stores or SQL + KV/stream/HTTP | no portable shared commit | no capability can make the commits shared | refused; commit an outbox intent and continue through a consumer/saga | Same-commit audit/outbox feasibility follows from using tables in the same database and the exact transaction client. It does not follow from the provider name alone. Each provider becomes @@ -919,8 +1027,11 @@ transaction client. It does not follow from the provider name alone. Each provid doc lint, publish gates, and consumer test pass. The current database helper's `IsolationLevel` vocabulary is reused. The RFC does not introduce a -second enum. Provider adapters publish the exact supported subset and relevant configuration -preconditions. +second enum. Provider adapters publish the exact **selectable** subset and separate default truth. +Stage 6 cannot pass while `packages/prisma-adapter-mysql` exports `SNAPSHOT` or interpolates an +unchecked upstream isolation token: it must use a four-value allow-list/mapping before SQL, remove +`SNAPSHOT` from `PrismaMySqlIsolationLevel`, reject it in positive/negative type/runtime fixtures, +and prove all four supported values on a real server. This is a distinct prerequisite from #1293. ### Typed failure model @@ -1019,15 +1130,20 @@ export const commandErrorMap = { retryAfterMs: z.number().int().nonnegative().optional(), }), }, -} as const; - -export const commandBaseContract = baseContract.errors(commandErrorMap); +} as const satisfies ErrorMap; export type CommandContractErrors = MergedErrorMap< BaseContractErrors, typeof commandErrorMap >; +export const commandBaseContract: ContractBuilder< + Schema, + Schema, + CommandContractErrors, + Record +> = baseContract.errors(commandErrorMap); + export type CommandContractRoute< TInput extends AnySchema, TOutput extends AnySchema, @@ -1073,11 +1189,35 @@ through `baseContract`, the service client, `safe()`, and `isDefinedError()`. Ru work may be developed behind an unexported seam, but the command subpaths and docs are not released as complete until the positive and negative #1350 type fixtures pass. +The annotation above deliberately repeats #1350's literal-preserving form instead of +`ReturnType` or `ReturnType`. Stage 0 must first make +the base spelling equivalent to: + +```ts +export type BaseContractErrors = MergedErrorMap< + Record, + typeof commonErrorMap +>; + +export const baseContract: ContractBuilder< + Schema, + Schema, + BaseContractErrors, + Record +> = oc.errors(commonErrorMap); +``` + +The command subpath then imports that exported `BaseContractErrors` and uses the same four generic +positions. Type fixtures must prove the three command codes and six base codes narrow precisely and +that an undeclared code is rejected; an open `ErrorMap` index signature is a release blocker. + ### Relay, workers, sagas, and remote sinks -The relay has its own ports: +Relay persistence stays in the database package. These types contain only raw persisted values and +database-owned state vocabulary: ```ts +// @netscript/database/commands export type CommandRelayFailureClass = | 'rejected' | 'rate_limited' @@ -1086,7 +1226,7 @@ export type CommandRelayFailureClass = | 'invalid_response' | 'misconfigured'; -export type ClaimedCommandOutbox = Readonly<{ +export type ClaimedCommandOutboxRow = Readonly<{ id: string; executionId: string; destination: string; @@ -1101,16 +1241,6 @@ export type ClaimedCommandOutbox = Readonly<{ claimUntil: Date; }>; -export type CommandOutboxDelivery = Readonly<{ - id: string; - destination: string; - topic: string; - payload: CommandJson; - dedupeKey: string; - correlationId: string; - trace?: CommandTraceContext; -}>; - export type CommandOutboxRelease = & Readonly<{ id: string; @@ -1130,7 +1260,7 @@ export interface CommandOutboxRelayStore { now: Date; }>, signal?: AbortSignal, - ): Promise; + ): Promise; markPublished( request: Readonly<{ id: string; @@ -1144,6 +1274,27 @@ export interface CommandOutboxRelayStore { signal?: AbortSignal, ): Promise; } +``` + +The service relay subpath owns decoding, runtime policy, sinks, and lifecycle: + +```ts +// @netscript/service/commands/relay +import type { + ClaimedCommandOutboxRow, + CommandOutboxRelayStore, + CommandRelayFailureClass, +} from '@netscript/database/commands'; + +export type CommandOutboxDelivery = Readonly<{ + id: string; + destination: string; + topic: string; + payload: CommandJson; + dedupeKey: string; + correlationId: string; + trace?: CommandTraceContext; +}>; export interface CommandOutboxSink { readonly id: string; @@ -1152,8 +1303,36 @@ export interface CommandOutboxSink { signal?: AbortSignal, ): Promise; } + +export type CommandOutboxRelayOptions = Readonly<{ + store: CommandOutboxRelayStore; + sinks: ReadonlyMap; + clock: CommandClock; + ids: CommandIdSource; + batchSize: number; + leaseMs: number; + maxAttempts: number; + classify(error: unknown): CommandRelayFailureClass; + retryAt(attempt: number, now: Date): Date; +}>; + +export interface RunningCommandOutboxRelay { + drainOnce(signal?: AbortSignal): Promise; + stop(): Promise; +} + +export function createCommandOutboxRelay( + options: CommandOutboxRelayOptions, +): RunningCommandOutboxRelay; ``` +`@netscript/service/commands/relay` parses `payloadJson` with the command I-JSON limits, validates +W3C fields, constructs `CommandOutboxDelivery`, resolves the configured sink, and maps sink failure +to the bounded database-owned release class. `@netscript/database/commands` never sees decoded +`CommandJson` or `CommandTraceContext`; it leases and settles rows. This keeps the only +cross-package edge `service → database` and gives the database adapter no worker/saga/service +dependency. + Claims are bounded and leased. `markPublished` and `release` compare the claim token so an expired worker cannot acknowledge another worker's lease. Provider adapters choose their correct locking algorithm; the public port does not pretend `FOR UPDATE SKIP LOCKED` is portable SQL. @@ -1168,6 +1347,11 @@ sink registry. Deleting or disabling that job visibly stops delivery without aff commits. The job's own worker idempotency governs a job delivery, not an outbox row's remote effect, and therefore does not replace row leases or stable message IDs. +Stage 5 must also correct `WorkerIdempotencyPort`'s current “exactly-once-effective” doc comment. +Its claim → effect → mark/release window provides at-least-once delivery with an applied-key guard; +a crash after an external effect and before `markApplied()` can repeat that effect. Worker docs must +use that wording before they are cited by command/relay guidance. + Sink rules: - **worker job:** set the queue/message idempotency or deduplication key to outbox `dedupeKey` and @@ -1188,6 +1372,32 @@ cascade persistence and lacks this command transaction binding. Future implement private lease utilities after both contracts exist, but their public semantics remain independently owned. +#### Decision: do not wrap `@netscript/queue` in v1 + +The current PostgreSQL queue adapter is valuable prior art but is not a compatible relay port. Its +public `MessageQueue.listen()` owns the loop and exposes handler `ack()`/`nack()`; its PostgreSQL +adapter claims with `FOR UPDATE SKIP LOCKED`, deletes on acknowledgement, moves exhausted messages +to a queue-specific dead-letter store, and hides claim tokens. The command outbox must retain the +original row, compare an expiring token on mark/release, preserve `publishedAt`/`terminalAt`, and +let the service sink registry own publication. More importantly, `ensureClient()` currently calls +`ensureSchema()` and executes runtime `CREATE TABLE IF NOT EXISTS`, so wrapping it would import the +hidden-migration behavior this RFC forbids. The transactional insert side also cannot call queue +enqueue because it must use the business transaction's `TTx`. + +V1 therefore rejects a direct `@netscript/queue` dependency or adapter wrapper. It reuses the proven +algorithmic pattern—bounded `FOR UPDATE SKIP LOCKED` claims, visibility leases, redelivery, attempt +limits, terminal handling, and the corresponding contention tests—behind the different +`CommandOutboxRelayStore` contract. This is reuse of verified behavior and test cases, not a false +type adapter between different durability semantics. + +The no-hidden-migration law is normative for every new command-kit/relay path. The queue package's +existing runtime DDL is acknowledged baseline drift, not precedent and not silently widened into +this RFC. Before any future implementation sharing is proposed, a separate queue reconciliation +slice must externalize its schema/migration lifecycle, retain queue compatibility, and expose a +schema-agnostic lease seam with no runtime DDL. This RFC PR does not create that issue; the board +proposal below names it for maintainer filing. Until that prerequisite lands, the packages may share +conformance cases and SQL design only, not code or a dependency edge. + ### Precise refusal boundary The kit refuses these shapes: @@ -1294,6 +1504,14 @@ arbitrary topic/destination, or correlation ID. Trace IDs already exist in span logs may include a validated correlation ID under their redaction/access policy; telemetry inclusion, if ever allowed, is an explicit opt-in FCP policy. +This is intentionally stricter than today's neighboring vocabulary. Messaging currently emits +`netscript.correlation.id`, and saga telemetry defines `netscript.idempotency.key`. That creates an +operator-experience asymmetry: a cross-runtime query cannot assume the same identifiers are present +on command spans. FCP Q3 must choose whether command telemetry remains privacy-first and a separate +telemetry cleanup deprecates/redacts those existing attributes, or whether a bounded opt-in policy +is proven for all three domains. Existing emission is not sufficient precedent for putting raw +command keys or unbounded correlation values into spans. + Metrics may count executions and record duration by command name, outcome, idempotency state, and provider only. No unbounded identifier becomes a metric dimension. Errors record `error.type` as the stable failure kind, not a driver message or stack-derived value. @@ -1322,21 +1540,31 @@ The shared suite runs the following positive/negative matrix against every provi 2. required/forbidden audit and outbox policy failures; 3. same-key/same-hash sequential replay; 4. same-key/different-hash rejection without handler invocation; -5. concurrent identical claims with a barrier around the handler; -6. leader rollback followed by follower execution; -7. bounded busy/timeout classification; -8. CAS zero-match rollback; -9. requested unsupported isolation refusal before begin; -10. serialization/deadlock/busy error with handler invocation count exactly one; -11. invalid/corrupt/incomplete stored receipt refusal without execution; -12. response/payload/fingerprint codec failures, including `Date`, `BigInt`, non-finite numbers, +5. same raw key plus a changed scope executes as new in a second receipt namespace, while the + deterministic-identity helper rejects time/random/global-dependent scope or fingerprint code; +6. same raw key plus a renamed command executes as new, while same name/scope/key plus a changed + `definitionVersion` is mismatch without handler invocation; +7. concurrent identical claims with a barrier around the handler: leader commit makes the follower + replay and the duplicate-loser path can still execute a harmless subsequent transaction query; +8. leader rollback followed by follower insertion/execution; +9. bounded busy/timeout classification at the advertised unit, whole-callback rollback, pooled + session-setting restoration, and a clean subsequent transaction; +10. provider-specific negative controls: PostgreSQL never emits/continues after a unique violation, + MySQL swallows only 1062 and never warning-converts another error, and SQL Server uses the named + range-locking index rather than catch-and-continue or `MERGE`; +11. CAS zero-match rollback; +12. requested unsupported selectable isolation refusal before begin, plus an omitted-isolation + default-path fixture; +13. serialization/deadlock/busy error with handler invocation count exactly one; +14. invalid/corrupt/incomplete stored receipt refusal without execution; +15. response/payload/fingerprint codec failures, including `Date`, `BigInt`, non-finite numbers, cyclic values, depth, and byte overflow; -13. abort before begin, during handler, between flush steps, and during relay; -14. every named command fault seam; -15. relay lease expiry, stale-token mark/release, publish-then-crash redelivery, terminal failure, +16. abort before begin, during handler, between flush steps, and during relay; +17. every named command fault seam; +18. relay lease expiry, stale-token mark/release, publish-then-crash redelivery, terminal failure, and graceful shutdown; -16. forbidden telemetry fields and exact allowed enum/count attributes; and -17. a negative control that bypasses the executor or writes one side record with a root client and +19. forbidden telemetry fields and exact allowed enum/count attributes; and +20. a negative control that bypasses the executor or writes one side record with a root client and proves the same-commit suite fails. PostgreSQL is the reference real-provider suite. MySQL and SQL Server must run the same semantic @@ -1369,10 +1597,16 @@ package's transitive resolution. The dependency is already used elsewhere in thi not currently declared by the service package. Its exact version follows the normal Deno toolchain update policy at implementation time. +The same direct-dependency rule applies to the new `service → database` edge: service declares the +release-matched `@netscript/database` specifier itself; database declares no reciprocal service +dependency. Surface fixtures import every commands/relay/provider subpath from a clean consumer, and +publish dry runs inspect the emitted import specifiers rather than trusting workspace-only +resolution. + An existing application adopts the seam explicitly: 1. upgrade after #1350 and the command package slices are published; -2. run `netscript db command-store init --database ` and review/apply the migration; +2. run `netscript db command-store add --database ` and review/apply the migration; 3. compose one `commandStore` and executor in the service infrastructure layer; 4. convert one non-CRUD mutation to a command, preserving its existing contract shape; 5. choose and document idempotency scope, semantic fingerprint, output codec, CAS, audit data, and @@ -1383,9 +1617,11 @@ An existing application adopts the seam explicitly: For an existing application-owned receipt or outbox, migration is not an automatic table copy. Implement a bridge that satisfies the logical contract, prove it with conformance, and migrate keys -and encoded responses deliberately. Changing receipt scope, command name, fingerprint, codec, or -definition version without a retention/retry plan can turn valid retries into conflicts; those -changes require release notes and compatibility tests. +and encoded responses deliberately. Changing receipt scope or command name without a migration makes +an old raw key execute as new; changing fingerprint or definition version under the same receipt key +produces key-reuse mismatch; changing a response codec can make committed replay undecodable. Each +is a breaking replay change requiring an old-name/scope compatibility alias or receipt migration, +release notes, and positive/negative compatibility fixtures through the retained retry window. Receipt retention must be at least the maximum advertised client retry window. Deleting a receipt earlier permits the same key to execute again. Published outbox cleanup must not remove rows still @@ -1401,11 +1637,16 @@ explicit paths rather than changing every scaffold: and requires explicit input/output schemas; - `netscript service add-handler --command --database ` emits a command definition stub and router binding in the layered service shape owned by #1362; -- `netscript db command-store init --database ` emits provider-specific models, - migration, and transaction bridge; and +- `netscript db command-store add --database ` emits provider-specific models, + migration, transaction bridge, `CommandTransactionClient`, and engine-module re-export; and - `netscript generate command-relay --database ` emits the visible worker drain job and sink registry. +`command-store` is a nested database feature noun with the verb `add`; it does not overload or alias +the existing `netscript db init` command. Help and negative CLI tests must show both routes and +refuse `netscript db command-store init` so scripts cannot accidentally invoke the migration-init +flow. + The proposed service layout is: ```text @@ -1444,18 +1685,20 @@ Required docs: No product code belongs in this RFC PR. After acceptance, implementation is staged contract-first: -| Stage | Owning archetype | Deliverable | Required gate | -| ----- | ---------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -| 0 | A1/type repair | close #1350's literal error-map and client error-generic defects | positive/negative typed-error fixtures; contracts/SDK publish gates | -| 1 | A1 | `@netscript/contracts/commands` schemas/map and canonical JSON/codec contracts | isolated declarations, doc lint, slow-type, runtime codec negatives | -| 2 | A4 | `@netscript/service/commands` definition/executor over an in-memory conformant fake | semantic law suite, fault seams, forbidden remote/global design review | -| 3 | A2 | `@netscript/database/commands` true `TTx` store and PostgreSQL reference adapter/schema | real PostgreSQL concurrency/fault suite; surface/publish gates | -| 4 | A2 | command telemetry vocabulary and redaction tests | exact span/attribute assertions; forbidden-field tests | -| 5 | A3/A5 | relay store/sink ports and generated workers/saga/stream bridge | lease/crash/redelivery/shutdown tests; no deliver-once claim | -| 6 | A2 | MySQL and SQL Server adapters | same semantic suite on each real provider; SQL Server snapshot config negative | -| 7 | A2, optional | SQLite adapter | adapter export plus writer contention/crash/reopen conformance; otherwise remain unsupported | -| 8 | A6 | schema, route, service-command, and relay generators | emitted samples; focused CLI tests; one full `scaffold.runtime` merge-readiness run | -| 9 | docs | guide/reference/operations/security/compatibility and #1364 integration | docs links/accuracy, executable snippets, published consumer proof | +| Stage | Owning archetype | Deliverable | Required gate | +| ----- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| 0 | A4 (`contracts` + `sdk`) | land #1350's literal-preserving `ContractBuilder` annotation and client error generic | positive/negative real-export type fixtures; contracts/SDK doc lint and publish gates | +| 1 | A4 (`contracts`) | `@netscript/contracts/commands` schemas, literal error map, JCS/codec contracts | isolated declarations, exact code-union negatives, slow-type/doc lint, runtime codec negatives | +| 2 | A4 (`service`) | `@netscript/service/commands` definition/executor over an in-memory conformant fake; add direct database dependency | semantic/identity laws, fault seams, dependency graph, forbidden remote/global design review | +| 3 | A2 (`database`) | true-`TTx` store, generated schema/bridge contract, PostgreSQL receipt-claim reference algorithm | real concurrent leader commit/rollback, lock-timeout/no-poisoning, callback-count, surface/publish gates | +| 4 | A2 (`telemetry`) | command telemetry vocabulary, existing-attribute asymmetry decision, and redaction tests | exact span/attribute assertions, bounded-cardinality and forbidden-field tests | +| 5a | A2 (`database`) | raw relay-store port and PostgreSQL lease/settlement adapter; no queue dependency/runtime DDL | token/lease/crash/redelivery tests plus queue-divergence negative control | +| 5b | A4 (`service`, A3 runtime discipline folded) | decoded delivery/sink ports, relay supervisor/registry, drain/stop lifecycle | failure classification, shutdown, publish-then-crash, no deliver-once claim | +| 5c | A3/A5 (`plugin-*-core` + thin plugins) | worker/saga/stream integration contracts and correction of `WorkerIdempotencyPort` exactly-once wording | at-least-once claim-window docs/tests; thin-plugin/dependency gates | +| 6 | A2 (`database` adapters) | MySQL and SQL Server command/relay adapters | same real-provider suite; MySQL four-level allow-list and `SNAPSHOT` removal; SQL Server snapshot-probe negative | +| 7 | A2, optional (`database`) | default-only SQLite adapter if FCP accepts it | `selectableIsolationLevels: []`, serializable default proof, contention/crash/reopen/lease suite | +| 8 | A6 (`cli`) | `db command-store add`, route/service-command, generated transaction-type, and relay generators | emitted alias/root-method negatives, migration-no-write previews, focused CLI tests, one full `scaffold.runtime` run | +| 9 | docs scope | guide/reference/operations/security/compatibility, queue non-reuse/reconciliation, and #1364 integration | docs links/accuracy, executable snippets, published consumer proof | Stages may use separate PRs and can be developed in parallel only where their contracts are already merged. The public feature is not announced as complete until stages 0–6 and the required parts of @@ -1471,24 +1714,26 @@ No issues are created or mutated by this RFC PR. The recommended board reconcili - make #1350 a stage-0 dependency, not a vague “RFC-A” reference; - let #1362 own generated service layering and make command-handler generation depend on it; - let #1364 own the remote HTTP recipe/template and consume the command outbox when available; -- keep #1293 adjacent: it improves `@netscript/prisma-adapter-mysql` but does not block the current - database package's MySQL transaction subpath; and +- keep #1293 adjacent: its surface work is not the MySQL `SNAPSHOT`/allow-list defect, which must be + fixed in the Stage-6 child regardless; propose a separate queue reconciliation child before any + future command-relay/queue code sharing; and - cross-reference the type-soundness umbrella #1278 without merging its broader scope into this implementation. Suggested PR-sized children under #1363: -| Proposed child | Labels (plus one lifecycle status) | Milestone | -| ------------------------------------------------------- | ------------------------------------------------------------ | ------------ | -| command contracts, errors, JCS codecs | `type:feat`, `area:contracts`, `area:service`, `priority:p1` | `0.0.8` | -| command executor and semantic/fault test kit | `type:feat`, `area:service`, `priority:p1` | `0.0.8` | -| true transaction-client port + PostgreSQL command store | `type:feat`, `area:database`, `priority:p1` | `0.0.8` | -| command OTel vocabulary and privacy tests | `type:feat`, `area:telemetry`, `priority:p1` | `0.0.8` | -| outbox relay and worker/saga sink adapters | `type:feat`, `area:service`, `area:database`, `priority:p1` | `0.0.8` | -| MySQL/SQL Server command-store conformance | `type:feat`, `area:database`, `priority:p1` | `0.0.8` | -| optional SQLite adapter/conformance | `type:feat`, `area:database`, `priority:p2` | FCP decision | -| explicit CLI generators and scaffold consumer | `type:feat`, `area:cli`, `area:service`, `priority:p1` | `0.0.8` | -| command/relay docs and executable examples | `type:docs`, `area:docs`, `area:service`, `priority:p1` | `0.0.8` | +| Proposed child | Labels (plus one lifecycle status) | Milestone | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ | +| command contracts, errors, JCS codecs | `type:feat`, `area:contracts`, `area:service`, `priority:p1` | `0.0.8` | +| command executor and semantic/fault test kit | `type:feat`, `area:service`, `priority:p1` | `0.0.8` | +| true transaction-client port + PostgreSQL command store | `type:feat`, `area:database`, `priority:p1` | `0.0.8` | +| command OTel vocabulary and privacy tests | `type:feat`, `area:telemetry`, `priority:p1` | `0.0.8` | +| outbox relay and worker/saga sink adapters | `type:feat`, `area:service`, `area:database`, `priority:p1` | `0.0.8` | +| MySQL/SQL Server command-store conformance | `type:feat`, `area:database`, `priority:p1` | `0.0.8` | +| queue runtime-DDL reconciliation (future reuse prerequisite) | `type:fix`, `area:database`, `priority:p2` | `0.0.8` | +| optional SQLite adapter/conformance | `type:feat`, `area:database`, `priority:p2` | FCP decision | +| explicit CLI generators and scaffold consumer | `type:feat`, `area:cli`, `area:service`, `priority:p1` | `0.0.8` | +| command/relay docs and executable examples | `type:docs`, `area:docs`, `area:service`, `priority:p1` | `0.0.8` | Each child PR that fully resolves its child issue uses a closing keyword in its body. Children reference #1363 as an umbrella without closing it. The RFC PR references #1361 without a closing @@ -1589,6 +1834,15 @@ Publishing before commit can announce state that rolls back. Publishing after co message if the process crashes. A same-commit outbox plus at-least-once relay is the narrow durable answer. +#### Wrap `@netscript/queue` as the command relay + +Rejected for v1. Its public handler/ack/nack contract deletes acknowledged queue rows, owns a +queue-specific DLQ and runtime listener, does not expose the command outbox's compare-token +settlement, and its PostgreSQL adapter currently creates schema at runtime. The command insert also +must join the business `TTx`, which queue enqueue cannot do. The relay reuses the queue adapter's +proven `SKIP LOCKED`/lease/redelivery/attempt test patterns, while code sharing waits for the +separately proposed migration-free, schema-agnostic queue reconciliation. + #### Weak KV command mode Rejected because claim → effect → mark has a crash window and cannot replay the relational response @@ -1646,7 +1900,16 @@ Primary references: - [Prisma transactions and isolation](https://www.prisma.io/docs/orm/prisma-client/queries/transactions) - [PostgreSQL transaction isolation](https://www.postgresql.org/docs/current/transaction-iso.html) +- [PostgreSQL `INSERT ... ON CONFLICT`](https://www.postgresql.org/docs/current/sql-insert.html) +- [PostgreSQL `lock_timeout`](https://www.postgresql.org/docs/current/runtime-config-client.html) +- [PostgreSQL `current_setting` / `set_config`](https://www.postgresql.org/docs/current/functions-admin.html) +- [MySQL transaction isolation](https://dev.mysql.com/doc/refman/8.4/en/set-transaction.html) +- [MySQL InnoDB error handling](https://dev.mysql.com/doc/refman/8.4/en/innodb-error-handling.html) +- [MySQL `innodb_lock_wait_timeout`](https://dev.mysql.com/doc/refman/8.4/en/innodb-parameters.html) - [SQL Server transaction isolation](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-ver17) +- [SQL Server `SET LOCK_TIMEOUT`](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-lock-timeout-transact-sql?view=sql-server-ver17) +- [SQL Server table hints](https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver17) +- [SQL Server key-range locking](https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide?view=sql-server-ver17) - [SQLite transactions](https://www.sqlite.org/lang_transaction.html) - [Deno KV transactions](https://docs.deno.com/deploy/kv/transactions/) - [RFC 8785 JSON Canonicalization Scheme](https://www.rfc-editor.org/info/rfc8785/) @@ -1662,20 +1925,30 @@ contract: 1. **Idempotency default.** Must every v1 command require a key, or may a definition explicitly choose `mode: "optional"` and emit `not_requested`? Recommendation: required by default, explicit optional only for controlled internal callers. -2. **SQLite release timing.** Is a real SQLite adapter and contention suite required for the first - stable command-kit release, or does SQLite remain unsupported until a later adapter PR? - Recommendation: later; do not delay the reference/client-server adapters or claim current - support. -3. **Correlation telemetry.** Should a validated correlation ID be an opt-in command attribute under - an explicit redaction/cardinality policy, or remain durable-row/log-only? Recommendation: - durable-row/log-only by default. +2. **SQLite default-only capability and release timing.** SQLite's engine isolation is serializable, + but the current generated/Prisma surface does not expose a portable explicit selection path. A + future store would therefore advertise `selectableIsolationLevels: []` and + `defaultIsolation: 'Serializable'`: an omitted isolation may run, while an explicitly requested + `Serializable` is refused by the isolation law. Does v1 accept that default-only capability, and + if so must its real contention/crash/lease suite land in the first stable release? + Recommendation: accept the capability shape but release it later; do not delay the client/server + adapters or claim current SQLite support. +3. **Cross-runtime correlation/idempotency telemetry.** Should validated correlation be an opt-in + command attribute under a redaction/cardinality policy, or remain durable-row/log-only? Existing + messaging spans emit `netscript.correlation.id` and saga vocabulary defines + `netscript.idempotency.key`, so either outcome also needs an operator-facing decision: explicitly + document the command asymmetry, or schedule a separate deprecation/redaction cleanup of those + existing attributes. Raw command idempotency keys remain forbidden. Recommendation: keep command + correlation durable-row/log-only by default and reconcile the older telemetry surface separately. 4. **Retention defaults.** What minimum receipt retry window and published-outbox cleanup defaults should generators document? Recommendation: require explicit deployment values until operational evidence establishes safe defaults; audit remains application policy. The following are not open: no hidden schema ownership, no weak KV semantics, no global conflict error, no automatic callback retry, no read-then-compare concurrency, no remote I/O in the command -transaction, and no exactly-once delivery claim. +transaction, and no exactly-once delivery claim. PostgreSQL/MySQL/SQL Server receipt claims use the +normative algorithms above; relay runtime ownership is service over database-owned persistence; and +v1 does not wrap or depend on `@netscript/queue`. ## Future possibilities From 6c2043d915ea2afbe7020bbb88d90ea4d0ea16a5 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 20:52:40 +0200 Subject: [PATCH 08/10] docs(harness): record command RFC cycle 2 handoff --- .../context-pack.md | 35 +-- .../final-handoff.md | 217 ++++++++++-------- .../plan.md | 9 +- .../worklog.md | 35 +-- 4 files changed, 168 insertions(+), 128 deletions(-) diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md index 0dc553affc..ccb25ba0da 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/context-pack.md @@ -6,19 +6,19 @@ | -------------- | --------------------------------------------------------------- | | Run ID | `docs-rfc-command-composition-kit--rfc` | | Branch | `docs/rfc-command-composition-kit` | -| Current phase | `plan-eval-remediation-cycle-1` | +| Current phase | `plan-eval-ready-cycle-2` | | Archetype | Docs delivery describing A4/A2/A3/A5/A6 implementation surfaces | | Scope overlays | `SCOPE-docs`, `SCOPE-service` | ## Current State -The run is active on the exact requested branch/base in the sole daemon-attached Codex thread. Draft -PR #1389 remains open and draft. Fable PLAN-EVAL cycle 1 is preserved at evaluator commit -`122301d25` with authoritative `FAIL_PLAN` findings F-B1–F-B7. This authoring turn is remediating -those findings without launching or approving evaluation. The RFC now locks provider receipt-claim -and timeout algorithms, the service → database relay split, queue non-reuse/runtime-DDL -reconciliation, identity-drift behavior, MySQL/SQLite capability truth, generated transaction -typing, and the batch corrections. No product code or export changed. +The run remains on the requested branch/base in the sole daemon-attached Codex thread. Draft PR +#1389 is open, draft, and ready for root-steered PLAN-EVAL cycle 2. Fable cycle 1 remains preserved +at evaluator commit `122301d25` with its authoritative `FAIL_PLAN`; no author verdict overrides it. +RFC remediation content commit `c98c08ada` resolves F-B1–F-B7 by locking provider claims/timeouts, +the service → database relay split, queue non-reuse/runtime-DDL reconciliation, identity drift, +MySQL/SQLite capability truth, generated transaction typing, and the correction batch. Proportionate +format/type/link/diff/PR gates are green. No product code or export changed. ## Completed @@ -42,19 +42,22 @@ typing, and the batch corrections. No product code or export changed. type, and primary provider-lock surfaces for F-B1–F-B7. - Reconciled the plan's open-decision sweep so no provider/package/migration/generator choice is silently deferred. +- Committed and pushed the RFC remediation slice as `c98c08adabbd992a557ff7c596deae68b9c9cd62` using + the required explicit refspec. +- Passed scoped format, RFC assertion, current public-entrypoint Deno check, docs links/accuracy, + diff/lock hygiene, review-thread, and PR-check reconciliation for the remediation content. -## In Progress +## Ready Handoff -- Proportionate remediation validation, commit/push, PR phase comment/body/label reconciliation, and - exact cycle-2 handoff. +- The final evidence commit, PR body, exact `status:plan-eval` label, and non-verdict phase comment + are reconciled by the closing commands of this authoring turn. The exact resulting branch HEAD is + carried in that PR comment and the root response. ## Next Steps -1. Run scoped Markdown/RFC/link/type/diff checks and record exact results. -2. Commit and push only `HEAD:refs/heads/docs/rfc-command-composition-kit`. -3. Keep the PR draft, restore exactly `status:plan-eval`, and post the remediation phase comment. -4. Root orchestrator steers the existing Fable session using `final-handoff.md`; this generator does - not launch or self-certify cycle 2. +1. Root orchestrator resumes the existing Fable session with the exact prompt in `final-handoff.md`. +2. Fable records the formal cycle-2 verdict without changing the authored RFC. +3. The later independent Qwen adversarial pass remains root-owned; this generator launches neither. ## Key Decisions diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md index e4959e4680..eb2203b353 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/final-handoff.md @@ -2,116 +2,147 @@ ## Delivery identity -| Field | Value | -| ------------------------- | ---------------------------------------------------------------------------- | -| Draft PR | [rickylabs/netscript#1389](https://github.com/rickylabs/netscript/pull/1389) | -| Branch | `docs/rfc-command-composition-kit` | -| Pinned base | `origin/main@fac9e339042c5394bf882311657d8981d353a1c3` | -| Reviewed RFC content HEAD | `ad16c42f8e717c727ae00bb66c694f4073234a39` | -| Run directory | `.llm/runs/docs-rfc-command-composition-kit--rfc/` | -| RFC | `rfcs/0000-command-composition-kit.md` (`0000`, `Draft`) | - -The immutable final branch HEAD is the commit that contains this handoff. A Git commit cannot embed -its own not-yet-computed object ID; the exact post-push HEAD is therefore recorded in the final -non-verdict PLAN-EVAL handoff PR comment and the root handoff response. `ad16c42f8...` is the -reviewed RFC content commit; the containing final commits change harness evidence only. +| Field | Value | +| ------------------------------------ | ---------------------------------------------------------------------------- | +| Draft PR | [rickylabs/netscript#1389](https://github.com/rickylabs/netscript/pull/1389) | +| Branch | docs/rfc-command-composition-kit | +| Pinned base | origin/main@fac9e339042c5394bf882311657d8981d353a1c3 | +| Cycle-1 evaluator commit | 122301d25f4055bfebffefeb3aec2b23c707cfca | +| Cycle-2 RFC remediation content HEAD | c98c08adabbd992a557ff7c596deae68b9c9cd62 | +| Run directory | .llm/runs/docs-rfc-command-composition-kit--rfc/ | +| RFC | rfcs/0000-command-composition-kit.md (0000, Draft) | +| Review state | Cycle 2 ready; no generator verdict | + +The immutable final branch HEAD is the commit containing this handoff and its validation evidence. A +Git commit cannot embed its own not-yet-computed object ID. The exact post-push branch HEAD is +therefore recorded in the final non-verdict PLAN-EVAL PR comment and the root response; +c98c08adabbd992a557ff7c596deae68b9c9cd62 is the exact RFC remediation content under review. ## Locked decisions -1. The only atomicity claim is one transaction on one conformant store. Business writes, a keyed - replay receipt, audit rows, and outbox rows share that commit. -2. Command semantics live in `@netscript/service/commands`; transaction persistence in - `@netscript/database/commands`; opt-in client errors in `@netscript/contracts/commands`; command - telemetry extends `@netscript/telemetry/attributes`. No new package or root re-export is - proposed. -3. Consumer-owned, provider-aware generated schema/migrations bind side rows to the true transaction - client. Hidden framework tables, startup migrations, and a weak capability mode are rejected. -4. Receipt identity is `(scope, commandName, SHA-256(idempotencyKey))`; request identity is SHA-256 - over RFC-8785 JCS bytes for the exact versioned semantic request. Replay outputs and outbox - payloads use explicit Standard Schema-backed codecs. -5. Optimistic concurrency is a repository conditional mutation; zero rows becomes a typed conflict. - There is no read-then-compare helper and no hidden transaction-callback retry. -6. One `executionId` joins receipt/audit/outbox evidence. Replay creates no new rows. Committed - incomplete or undecodable receipts are corruption, never permission to execute again. -7. Remote I/O is outside the command callback. The relay uses stable message identity, leases, - stale-token checks, retry/terminal disposition, and at-least-once wording. Workers, sagas, - streams, and webhook receivers still own downstream deduplication/idempotency. -8. PostgreSQL is the reference target; MySQL and SQL Server are conforming targets only after the - same real-provider suite. SQLite remains unclaimed pending an adapter/contention suite. Deno KV - and every cross-store shape are refused in v1. -9. Default telemetry is bounded and redacted: no raw scope, actor, key/hash, request hash, version, - correlation ID, durable row ID, payload, response, or arbitrary destination/topic attribute. -10. This PR is documentation only. RFC numbering, FCP, implementation, issue/milestone mutation, - merge, and release remain maintainer/orchestrator work. +1. One conformant store transaction is the maximum atomicity claim. Business writes, the replay + receipt, audit rows, and outbox rows use the same generated transaction client and commit or roll + back together. +2. Receipt identity is (scope, commandName, SHA-256(idempotencyKey)); request identity is SHA-256 + over RFC 8785 JCS bytes for the exact versioned semantic request. Same scope/name/key plus a + changed request or definition version is mismatch; a changed scope or command name is a new + namespace and executes as new. +3. PostgreSQL claims with INSERT ... ON CONFLICT DO NOTHING RETURNING plus an indexed select and a + transaction-local lock_timeout. MySQL claims with a savepoint/plain INSERT, recovers only 1062, + aborts on 1205/1213, and restores or discards the session after changing + innodb_lock_wait_timeout. SQL Server claims with the generated named unique index and + UPDLOCK/HOLDLOCK, bounded by SET LOCK_TIMEOUT. A busy result is callback-terminal and every + timeout path rolls back. +4. The service package owns command semantics and decoded relay delivery/sinks/supervision. The + database package owns the true transaction, raw receipt/audit/outbox rows, raw relay + lease/token/release types, and provider adapters. The only new edge is service → database; + database imports no service type. +5. V1 does not wrap or depend on @netscript/queue. It reuses the verified lease algorithm and + conformance pattern, not queue's delete-on-ack/DLQ/public-loop contract or runtime schema + creation. A separate queue runtime-DDL reconciliation is proposed before future code sharing. +6. The explicit netscript db command-store add generator owns consumer Prisma models, reviewable + migrations, the bridge, and CommandTransactionClient derived from the generated + Prisma.TransactionClient with root/lifecycle methods explicitly omitted. Hidden migrations and a + framework fake transaction client are rejected. +7. Capabilities distinguish selectableIsolationLevels from defaultIsolation. MySQL is blocked until + SNAPSHOT is removed/rejected and all SQL tokens are allow-listed. A future SQLite shape selects + no explicit levels and reports a Serializable default; explicit Serializable remains refused. +8. Optimistic concurrency is an application repository conditional mutation. Zero matched rows is a + typed conflict. The executor performs no read-then-compare shortcut and never retries the + callback automatically. +9. Remote I/O is outside the transaction. A committed outbox message retains its stable ID across + at-least-once relay attempts; publish-then-crash may duplicate delivery. Workers, sagas, streams, + and receivers own downstream deduplication and compensation. +10. Command-visible contract errors use the literal-preserving four-generic ContractBuilder spelling + owned by #1350. Contract and service surfaces are A4; database/telemetry adapters A2; relay + runtime discipline A3; thin integrations A5; generators A6. +11. Default command telemetry is bounded and redacted. Existing messaging correlation and saga + idempotency attributes are acknowledged as an operator-experience asymmetry, not precedent for + raw command identifiers. +12. The RFC remains documentation-only, Draft, and numbered 0000. Numbering, acceptance, issue + creation/closure, milestone changes, merge, and later implementation remain maintainer/root + work. ## Unresolved FCP questions -1. Whether idempotency is mandatory for every v1 command or may be explicitly optional for - controlled internal callers. Recommendation: required by default; explicit opt-out only. -2. Whether SQLite conformance is a first-release requirement. Recommendation: later and unclaimed - until real contention/crash tests pass. -3. Whether correlation ID may become an opt-in telemetry attribute. Recommendation: durable-row and - policy-controlled log only by default. +1. Whether idempotency is required for every v1 command or may be explicitly optional for controlled + internal callers. Recommendation: required by default; explicit opt-out only. +2. Whether the future SQLite default-only capability is accepted and whether it is required for the + first release. Recommendation: accept the honest shape, release later, and make no support claim + until real contention/crash/lease tests pass. +3. Whether validated correlation may be an opt-in command telemetry attribute, and whether the + existing messaging/saga identifier attributes should be separately deprecated or redacted. + Recommendation: durable-row/policy-controlled logs only for commands by default, plus a separate + vocabulary cleanup. 4. Receipt retry-window and published-outbox cleanup defaults. Recommendation: require explicit deployment values until operational evidence exists; audit retention remains application policy. +Provider claim algorithms, relay ownership, queue reuse, identity-drift behavior, generated +transaction typing, and MySQL isolation truth are resolved design inputs, not FCP questions. + ## Validation evidence -| Evidence | Result | -| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| `deno fmt --check rfcs/0000-command-composition-kit.md .llm/runs/docs-rfc-command-composition-kit--rfc` | PASS; 10 owned Markdown files | -| `git diff --check` plus `origin/main...HEAD` changed-file audit | PASS; only RFC + required run artifacts, no package/plugin/lock change | -| `rtk proxy deno task docs:links` | PASS; 102 docs, 0 broken links, 0 broken anchors, 0 orphans | -| `rtk proxy deno task docs:accuracy` | PASS; repository accuracy/discoverability assertions | -| Focused RFC frontmatter/required-section/forbidden-vocabulary assertion | PASS; `0000`, `Draft`, #1361, all required sections; no forbidden domain terms | -| Focused transaction callback probe | Existing `withTransaction` incorrectly compiled root-only/nested transaction calls; defect proven, probe removed | -| Focused SDK typed-error probe | Expected TS2339 (`error.code` on `never`) reproduced #1350; probe removed | -| Focused future command type-shape probe | PASS after exposing the required direct `@standard-schema/spec` service dependency; probe removed | -| Structured full-entrypoint doc-lint baseline | Service `0`; database combined `0`; contracts `9` existing private-type findings; telemetry `7` existing findings; reports exited `0` | -| `agentic:review-threads` on #1389 | PASS; 0 threads, 0 unanswered | -| `agentic:pr-checks` on #1389 at RFC HEAD | PASS; 15 reconciled checks, 0 current failures; docs-only lanes intentionally skipped | -| Product/CLI runtime E2E | N/A by scope; no product, generated output, schema, package export, or lock changed | - -No evaluator verdict is claimed. The existing contracts/telemetry doc-lint findings are baseline -implementation constraints, not changes or waivers introduced by this PR. +| Evidence | Result | +| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | +| Scoped deno fmt --check over authored RFC/remediation/handoff Markdown | PASS; generated launcher metadata kept in its launcher-emitted form and audited separately | +| git diff --check and origin/main...HEAD changed-file/lock audit | PASS; only the RFC and mandatory run artifacts; no package, plugin, schema, generated product, or deno.lock change | +| rtk proxy deno task docs:links | PASS; 102 docs, 0 broken links, 0 broken anchors, 0 orphans | +| rtk proxy deno task docs:accuracy | PASS; repository accuracy/discoverability assertions | +| Focused RFC frontmatter/F-B1–F-B7/forbidden-vocabulary assertion | PASS; 17 required claims, 3 forbidden-pattern classes | +| rtk proxy deno check --no-lock --unstable-kv on database/service/contracts/telemetry public entrypoints | PASS; existing peer/build-script warnings only | +| Focused Prisma 7.8 generated-client probe | PASS; Prisma.TransactionClient exists and current deny-list retains nested $transaction; probe removed | +| agentic:review-threads on #1389 | PASS; 0 threads, 0 unanswered | +| agentic:pr-checks on #1389 at c98c08ada | PASS; 15 reconciled checks, 0 current failures; docs-only lanes skipped | +| Product/CLI runtime E2E | N/A by scope; no package, generator, schema, scaffold, runtime, export, or lock changed | + +No evaluator verdict is claimed. Existing contracts/telemetry doc-lint findings remain recorded +future implementation bars, not new findings or waivers in this docs PR. ## Board reconciliation proposal -No issue, milestone, or board item was mutated by this generator. +No issue, milestone, or board item was created, closed, or mutated by this generator. -- Keep #1361 as the RFC ratification record; this PR references it without a closing keyword. -- Keep #1363 as the `0.0.8` implementation umbrella and create PR-sized children only after RFC - acceptance. -- Treat #1350 as stage 0 for client-visible typed command errors. +- Keep #1361 as the 0.0.6 RFC ratification record; this PR references it without a closing keyword. +- Keep #1363 as the 0.0.8 implementation umbrella. +- Keep #1350 as the 0.0.7 literal-error prerequisite. - Let #1362 own generated service layering; command-handler generation depends on that shape. - Let #1364 own the outbound HTTP/webhook recipe and consume stable command-outbox IDs. -- Keep #1293 adjacent rather than making the lower-level MySQL adapter hook a false atomicity - prerequisite; cross-reference #1278 for broader type-soundness work. -- Do not assign the RFC number, close #1361, close an umbrella, or move milestones from this PR. - -## Exact Fable-review handoff - -The root orchestrator should resume the existing Claude Fable 5 session and send exactly: - -> Review draft PR rickylabs/netscript#1389 as the separate PLAN-EVAL / cross-RFC reviewer. Do not -> author implementation code, open another session, assign an RFC number, merge, close issues, or -> mutate milestones. Read -> `.llm/runs/docs-rfc-command-composition-kit--rfc/{supervisor,research,plan,worklog,context-pack,drift,final-handoff}.md`, -> `rfcs/0000-command-composition-kit.md`, the carried RFC-B proposal, RFC-A/RFC-C where they share -> seams, current `origin/main@fac9e339042c`, and live #1361–#1364/#1350/#1293/#1278/#1347. Challenge -> package ownership and dependency direction; true transaction-client binding; receipt races and -> canonical request identity; CAS/isolation/provider claims; same-commit audit/outbox invariants; -> relay lease/terminal/crash semantics; worker/saga boundary; typed error feasibility; telemetry -> redaction/cardinality; JSR/slow-type/publish consequences; generator ownership; refusal boundary; -> and whether the four FCP questions are the only unresolved policy. Check specifically for hidden -> exactly-once, distributed-transaction, ORM, event-sourcing, or domain-specific assumptions. Return -> one structured PR comment beginning `**[PHASE: PLAN-EVAL] [VERDICT: APPROVED]**` or -> `**[PHASE: PLAN-EVAL] [VERDICT: CHANGES_REQUESTED]**`, with numbered findings tied to exact RFC -> sections and a concise next action. Do not edit this branch; the root orchestrator owns -> remediation and the later independent Qwen adversarial pass. +- Keep #1293 adjacent; it does not repair the distinct MySQL SNAPSHOT/allow-list defect. +- Propose, for maintainer filing after acceptance, a PR-sized queue runtime-DDL reconciliation child + before command-relay/queue code sharing. This RFC run does not create it. +- Keep optional SQLite conformance as the FCP-timed child and cross-reference #1278 without + importing its broader type-soundness scope. +- Do not assign the RFC number, close an umbrella, or move any milestone from this PR. + +## Exact Fable cycle-2 re-evaluation handoff + +The root orchestrator should resume the existing Claude Fable 5 evaluator session and send exactly: + +> Run PLAN-EVAL cycle 2 for draft PR rickylabs/netscript#1389. Stay in the existing Fable 5 +> evaluator session; do not launch or delegate to another evaluator. Read +> .llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md completely and treat every cycle-1 +> finding F-B1 through F-B7 and every Required for PASS item as the acceptance checklist. Review the +> current branch HEAD named in the latest non-verdict [PHASE: PLAN-EVAL] PR comment; the exact RFC +> remediation content commit is c98c08adabbd992a557ff7c596deae68b9c9cd62, based on evaluator commit +> 122301d25f4055bfebffefeb3aec2b23c707cfca. Read the RFC and +> supervisor/research/plan/worklog/context-pack/drift/final-handoff artifacts, and compare the +> carried proposal, current origin/main@fac9e339042c, relevant source, and primary provider +> documentation. Verify specifically: (1) PostgreSQL/MySQL/SQL Server receipt claims, bounded lock +> waits, rollback/no-poison and session restoration; (2) raw database relay ownership versus decoded +> service runtime ownership and the new one-way service → database dependency; (3) the explicit +> rejection of direct queue reuse and the hidden-runtime-migration reconciliation; (4) deterministic +> scope/fingerprint behavior plus execute-as-new changed-scope/renamed-command conformance and +> migration law; (5) MySQL's four-level isolation gate distinct from #1293; (6) generator-owned +> CommandTransactionClient typing; and (7) the complete archetype, ContractBuilder, vocabulary, +> milestone, worker, SQLite, telemetry, and CLI correction batch. Preserve the one-store +> transaction, receipt, relay, capability-honesty, and refusal laws. Record the formal cycle-2 +> verdict and evidence in plan-eval.md and the structured PLAN-EVAL PR comment according to the +> evaluator protocol. Do not edit the RFC or other author artifacts, number the RFC, approve on +> behalf of the generator, merge, close/create issues, mutate milestones, or trigger IMPL-EVAL/Qwen. ## Generator stop condition -After this handoff is pushed, the draft PR body is reconciled, and its sole lifecycle label is -`status:plan-eval`, generator work stops. Fable review and Qwen adversarial evaluation remain -external and pending; the PR stays draft and unmerged. +After the handoff evidence commit is pushed, the PR body is reconciled, its sole lifecycle label is +status:plan-eval, and the final non-verdict PR comment carries the exact branch HEAD, generator work +stops. Fable cycle 2 and the later Qwen adversarial evaluation remain external and pending; the PR +stays draft and unmerged. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md index 6b1e19eec8..52a482072b 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan.md @@ -6,7 +6,7 @@ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | Run ID | `docs-rfc-command-composition-kit--rfc` | | Branch | `docs/rfc-command-composition-kit` | -| Phase | `plan-eval-remediation-cycle-1` | +| Phase | `plan-eval-ready-cycle-2` | | Target | `rfcs/0000-command-composition-kit.md` plus harness evidence | | Delivery profile | `SCOPE-docs` with `SCOPE-service` consumer analysis | | Described implementation | A4 contracts/service DSL, A2 database/telemetry adapters, A3 runtime discipline, A5 thin plugin consumers, A6 CLI generators | @@ -238,6 +238,7 @@ labels. | Are consumers and gates identified? | Yes; services, contracts, DB adapters, telemetry, workers/sagas, CLI/scaffold. | | Are open questions non-blocking to drafting? | Yes; idempotency default, SQLite release timing, correlation telemetry, retention durations are isolated FCP policy choices. | -Cycle-1 `FAIL_PLAN` is not self-overridden. After the RFC/artifacts/gates/commit/PR metadata are -reconciled, this plan returns to `status:plan-eval` for the root orchestrator to steer the existing -Fable session through cycle 2. This author does not launch or approve that evaluation. +Cycle-1 `FAIL_PLAN` is not self-overridden. F-B1–F-B7 and every Required-for-PASS item are now +addressed in the authored plan/RFC and the remediation gates are green. The draft returns to +`status:plan-eval` for the root orchestrator to steer the existing Fable session through cycle 2. +This author does not launch or approve that evaluation. diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md index a764131231..fa9f43d8fa 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/worklog.md @@ -104,6 +104,9 @@ capabilities. | 2026-08-08 | S4 | provider verification | Re-read doctrine/harness authority; checked queue runtime DDL/lease semantics, service/database dependencies, MySQL isolation, telemetry/worker vocabulary, current CLI `db` help, and primary lock docs. | | 2026-08-08 | S4 | Prisma type probe | Generated a temporary Prisma 7.8 client, confirmed `Prisma.TransactionClient`, found current deny-list retains `$transaction`, locked the generator-owned explicit `Omit`, and removed the probe. | | 2026-08-08 | S4 | RFC remediation | Added normative PostgreSQL/MySQL/SQL Server receipt claims/timeouts, relay ownership, queue rejection/reconciliation, identity drift laws, MySQL/SQLite truth, generated typing, and F-B7 batch corrections. | +| 2026-08-08 | S4 | remediation publish | Committed `c98c08adabbd992a557ff7c596deae68b9c9cd62`, pushed only as `HEAD:refs/heads/docs/rfc-command-composition-kit`, and posted a non-verdict `[PHASE: PLAN]` remediation comment. | +| 2026-08-08 | S4 | remediation gates | Scoped authored-Markdown format, 17-claim RFC assertion, public-entrypoint Deno check, docs links/accuracy, diff/lock hygiene, review threads, and PR checks passed. | +| 2026-08-08 | S4 | cycle-2 handoff | Reconciled plan/context/final handoff for root-steered re-evaluation; no evaluator was launched and cycle-1 `FAIL_PLAN` remains authoritative until Fable reports cycle 2. | ## Decisions @@ -139,21 +142,23 @@ capabilities. ### Static Gates -| Gate | Command or check | Result | Notes | -| ------------------------------ | -------------------------------------------------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------- | -| Branch/base identity | raw git `rev-parse`, `merge-base`, `status` | PASS | Branch and base exactly match the brief. | -| Mandatory authority read | complete file reads | PASS | RFC process, doctrine, gate/evaluator files and selected profiles read before RFC authoring. | -| Native public API inspection | `deno doc --filter` on database, service, SDK, telemetry, workers and oRPC | PASS | Exact current signatures and missing subpaths recorded in research. | -| Focused transaction type probe | `deno check --unstable-kv packages/database/rfc-command-probe.ts` | EXPECTED_FAIL_MISSED | Exit 0 proves the callback surface is too broad; temporary probe removed. | -| Focused typed-error probe | `deno check --unstable-kv packages/sdk/rfc-command-probe.ts` | EXPECTED_FAIL | Exit 1 with TS2339 on `error.code`; temporary probe removed. | -| Focused RFC type-shape probe | `deno check --unstable-kv packages/service/rfc-command-contract-probe.ts` | PASS_AFTER_FINDING | First run found missing service Standard Schema mapping; direct locked import passed; probe removed. | -| Markdown format | `deno fmt --check rfcs/... .llm/runs/...` | PASS | 10 owned Markdown files checked. | -| Diff hygiene | `git diff --check` and changed-file audit | PASS | Only the RFC and required run directory differ from the pinned base; no lock/product change. | -| Docs links | `rtk proxy deno task docs:links` | PASS | 102 docs; 0 broken links, 0 broken anchors, 0 orphans. | -| Docs accuracy | `rtk proxy deno task docs:accuracy` | PASS | Saga/storefront/path/CLI/Fresh accuracy checks passed. | -| RFC structure/terminology | focused `deno eval` frontmatter/section/forbidden-term assertion | PASS | Draft/0000/#1361 and all required sections present; forbidden domain vocabulary absent. | -| PR review threads | `rtk proxy deno task agentic:review-threads -- ... --pr 1389 --pretty` | PASS | 0 threads; 0 unanswered. | -| PR checks | `rtk proxy deno task agentic:pr-checks -- ... --pr 1389 --pretty` | PASS | 15 reconciled checks; 0 current failures; docs-only CI lanes skipped under explicit labels. | +| Gate | Command or check | Result | Notes | +| ------------------------------ | ----------------------------------------------------------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------- | +| Branch/base identity | raw git `rev-parse`, `merge-base`, `status` | PASS | Branch and base exactly match the brief. | +| Mandatory authority read | complete file reads | PASS | RFC process, doctrine, gate/evaluator files and selected profiles read before RFC authoring. | +| Native public API inspection | `deno doc --filter` on database, service, SDK, telemetry, workers and oRPC | PASS | Exact current signatures and missing subpaths recorded in research. | +| Focused transaction type probe | `deno check --unstable-kv packages/database/rfc-command-probe.ts` | EXPECTED_FAIL_MISSED | Exit 0 proves the callback surface is too broad; temporary probe removed. | +| Focused typed-error probe | `deno check --unstable-kv packages/sdk/rfc-command-probe.ts` | EXPECTED_FAIL | Exit 1 with TS2339 on `error.code`; temporary probe removed. | +| Focused RFC type-shape probe | `deno check --unstable-kv packages/service/rfc-command-contract-probe.ts` | PASS_AFTER_FINDING | First run found missing service Standard Schema mapping; direct locked import passed; probe removed. | +| Focused Prisma generated type | temporary Prisma 7.8 generate/check probe | PASS | Confirmed generated `Prisma.TransactionClient`; current deny-list retains nested `$transaction`; probe removed. | +| Current public entrypoint type | `deno check --no-lock --unstable-kv` over database/service/contracts/telemetry mods | PASS | Existing peer/build-script warnings only; no lock mutation. | +| Markdown format | scoped `deno fmt --check` over authored RFC/remediation/handoff Markdown | PASS | Generated launcher metadata retained in launcher-emitted form and audited separately. | +| Diff hygiene | `git diff --check` and changed-file audit | PASS | Only the RFC and required run directory differ from the pinned base; no lock/product change. | +| Docs links | `rtk proxy deno task docs:links` | PASS | 102 docs; 0 broken links, 0 broken anchors, 0 orphans. | +| Docs accuracy | `rtk proxy deno task docs:accuracy` | PASS | Saga/storefront/path/CLI/Fresh accuracy checks passed. | +| RFC structure/terminology | focused `deno eval` frontmatter/section/forbidden-term assertion | PASS | Draft/0000/#1361 and all required sections present; forbidden domain vocabulary absent. | +| PR review threads | `rtk proxy deno task agentic:review-threads -- ... --pr 1389 --pretty` | PASS | 0 threads; 0 unanswered. | +| PR checks | `rtk proxy deno task agentic:pr-checks -- ... --pr 1389 --pretty` | PASS | At `c98c08ada`: 15 reconciled checks; 0 current failures; docs-only CI lanes skipped. | ### Fitness Gates From 57b51128fbc28187b55e1e377cd3e1777332dfa1 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Sat, 8 Aug 2026 21:01:18 +0200 Subject: [PATCH 09/10] =?UTF-8?q?docs(harness):=20PLAN-EVAL=20cycle=202=20?= =?UTF-8?q?=E2=80=94=20RFC-B=20PASS/APPROVED?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All F-B1..F-B7 verified resolved at c98c08ada; per-provider claim table exceeds the asked bar; labels remain honest (docs-only diff). Co-Authored-By: Claude Fable 5 --- .../plan-eval.md | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md index 544cc3610e..181385b461 100644 --- a/.llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md +++ b/.llm/runs/docs-rfc-command-composition-kit--rfc/plan-eval.md @@ -1,5 +1,47 @@ # PLAN-EVAL — docs-rfc-command-composition-kit--rfc (RFC-B, PR #1389) +## CYCLE 2 — VERDICT: **PASS** (PR vocabulary: APPROVED) — 2026-08-08 + +Evaluator: same owner-designated Fable 5 · high session as cycle 1. Evaluated: RFC @ remediation +commit `c98c08ada` (branch HEAD `6c2043d91`), updated research/plan/worklog/drift/final-handoff. +Verification: section-level re-read of every finding anchor against the amended text plus the +handoff's evidence table (author's Prisma 7.8 `Prisma.TransactionClient` probe accepted with the +worktree `Omit` spelling verified at L802-811). + +### Mechanical re-evaluation F-B1…F-B7 + +| # | Cycle-2 status | Evidence (amended RFC) | +| --- | --- | --- | +| F-B1 | **RESOLVED — exceeds the asked bar** | Normative per-provider claim table (L935-949): PG `INSERT … ON CONFLICT DO NOTHING RETURNING` + indexed `SELECT`, transaction-local `set_config('lock_timeout')` with save/restore, `55P03`→busy, `40001` retryable; MySQL savepoint + **only** 1062 recovered (`INSERT IGNORE` explicitly forbidden with the warning-downgrade reason), session `innodb_lock_wait_timeout` save/restore with failed-restore-discards-connection; MSSQL `UPDLOCK, HOLDLOCK` on the named generated unique index + `SET LOCK_TIMEOUT` restore, `MERGE`/catch-2627 rejected. Busy is callback-terminal; every timeout path rolls back. Conformance item added (L1553). Primary-source citations appended | +| F-B2 | **RESOLVED** | Ownership completed: `@netscript/service/commands/relay` owns decoded delivery/sink/supervisor (L309); database owns raw rows + lease/token/release types; "the only cross-package edge is `service → database`" with the direct-dependency declaration requirement stated (L1333, L1600); stage split 5a/5b reflects it | +| F-B3 | **RESOLVED** | §"Decision: do not wrap `@netscript/queue` in v1" (L1375-1390) + rejected-alternatives entry (L1837): reuses the verified lease algorithm/test pattern, not queue's delete-on-ack/DLQ/public-loop contract or runtime schema creation; a queue runtime-DDL reconciliation child is proposed for maintainer filing before any code sharing | +| F-B4 | **RESOLVED** | Execute-as-new law stated where identity is defined (L866-867, L983) + negative conformance items 5 and 6 (same key/changed scope; same key/renamed command; changed definitionVersion = mismatch) (L1543-1545); scope determinism requirement mirrors fingerprint's | +| F-B5 | **RESOLVED** | Capability matrix: MySQL "exactly those four selectable values; current lower adapter's exported `SNAPSHOT` and unchecked SQL interpolation must be fixed before conformance" (L1018); Stage 6 cannot pass while `prisma-adapter-mysql` exports `SNAPSHOT` or interpolates unvalidated tokens (L1031-1033); #1293 correctly kept adjacent | +| F-B6 | **RESOLVED** | `CommandTransactionClient = Omit` generator-owned with engine-module re-export (L802-811); in the `db command-store add` deliverables (L1641); `withTransaction` root-client repair retained | +| F-B7 | **RESOLVED (all eight)** | (a) stage archetypes corrected to A4 for contracts/service (L1690-1696); (b) locked decision 10 pins #1350's literal-preserving `ContractBuilder` spelling; (c) vocabulary unified on `claimed` (L468); (d) frontmatter footnote: 0.0.6 = ratification-only (L24); (e) Stage 5 must correct `WorkerIdempotencyPort`'s "exactly-once-effective" doc comment (L1350); (f) SQLite future shape `selectableIsolationLevels: []` + `defaultIsolation: 'Serializable'` folded into FCP Q2 (L1020) — with the improved `selectable`/`default` capability split resolving the refusal-law wart; (g) generator renamed `db command-store add` with the `db init` distinction stated (L785-787); (h) FCP Q3 + locked decision 11 acknowledge the messaging/saga attribute asymmetry and propose the separate vocabulary cleanup | + +### FCP-question adjudication (amended set of 4) + +All four are policy-only and safe to defer; the three cycle-1 rework-forcing gaps are now resolved +design inputs, not FCP items — exactly the required repair shape. + +### Residual advisories (non-blocking) + +1. The `selectableIsolationLevels`/`defaultIsolation` split is an improvement over cycle 1's + reviewed shape — carried into the store capabilities without breaking any law; no action. +2. PR labels (`type:docs` + skips) remain honest for this branch: the diff is RFC + run artifacts + only (changed-file audit confirms no package/lock change). + +**PASS.** One-store transaction, receipt, relay, capability-honesty, and refusal laws all +preserved; the plan is implementable without guessing. Hard-stop lifted for stages 0–2 pending +owner ratification and the root-owned Qwen adversarial acceptance pass. Accepted content SHA of +record: **`c98c08adabbd992a557ff7c596deae68b9c9cd62`** (branch HEAD +`6c2043d915ea2afbe7020bbb88d90ea4d0ea16a5`). + +--- + +# Cycle 1 record (2026-08-08, superseded by the PASS above) + | Field | Value | | --- | --- | | Verdict | **FAIL_PLAN** (PR-comment vocabulary: CHANGES_REQUESTED) — cycle 1 of 2 | From 81e799edeb111b949fe111135a0e3f614a40c643 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Tue, 11 Aug 2026 22:19:20 +0200 Subject: [PATCH 10/10] docs(rfc): accept production command composition as RFC 0003 --- ...and-composition-kit.md => 0003-command-composition-kit.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename rfcs/{0000-command-composition-kit.md => 0003-command-composition-kit.md} (99%) diff --git a/rfcs/0000-command-composition-kit.md b/rfcs/0003-command-composition-kit.md similarity index 99% rename from rfcs/0000-command-composition-kit.md rename to rfcs/0003-command-composition-kit.md index 21dfb367f9..e0c374a761 100644 --- a/rfcs/0000-command-composition-kit.md +++ b/rfcs/0003-command-composition-kit.md @@ -1,7 +1,7 @@ --- -rfc: 0000 +rfc: 0003 title: Production command composition kit -status: Draft +status: Accepted authors: ['@rickylabs'] created: 2026-08-08 tracking-issue: https://github.com/rickylabs/netscript/issues/1361