diff --git a/.gitignore b/.gitignore index 144f451..5ef0bf1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ dist/ .planning/ .agents/ skills-lock.json + +# Runtime-generated demo output (golden-path bootstrap writes here). +examples/service-operator-golden-path/output/ +examples/service-operator-bootstrap/output/ diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md new file mode 100644 index 0000000..248c0bc --- /dev/null +++ b/.planning/ROADMAP.md @@ -0,0 +1,68 @@ +# Planning Roadmap + +Generated: 2026-05-18 +Refreshed: 2026-05-28 + +## Invariant at Stake + +Planning may compile product intent into proposed work. It must not become authority, and it must not silently import archived or draft artifacts as completed truth. + +## Current Track (`.planning/phases/`) + +This is the active planning track. The legacy `docs/plans/` track is preserved at the bottom for provenance. + +| Phase | Folder | Status | Last update | +|-------|--------|--------|-------------| +| 02 | [`02-address-concerns`](./phases/02-address-concerns/) | **Complete** — see [02-VERIFICATION.md](./phases/02-address-concerns/02-VERIFICATION.md) and [02-UAT.md](./phases/02-address-concerns/02-UAT.md) | 2026-05-28 | +| 03 | [`03-close-enforcement-gaps`](./phases/03-close-enforcement-gaps/) | **Complete** — see [03-VERIFICATION.md](./phases/03-close-enforcement-gaps/03-VERIFICATION.md) | 2026-05-28 | +| 04 | [`04-service-agent-gating`](./phases/04-service-agent-gating/) | **Complete** — see [04-VERIFICATION.md](./phases/04-service-agent-gating/04-VERIFICATION.md) and [04-UAT.md](./phases/04-service-agent-gating/04-UAT.md) | 2026-05-29 | +| 05 | [`05-product-coherence`](./phases/05-product-coherence/) | **Complete** — see [05-VERIFICATION.md](./phases/05-product-coherence/05-VERIFICATION.md) and [05-UAT.md](./phases/05-product-coherence/05-UAT.md) | 2026-05-29 | + +### Phase 05 framing + +Phase 05 is the post-Phase-04 product unification pass. It is **not** a new mechanism layer. It covers four buckets: + +- **A — Phase-04 deferred lane** (service mutation manifest, HTTP profile adapter conformance expansion, dual-enforcement inventory slice, operator runbooks, D-25 per-customer scaffolds) +- **B — Surface scrub** (live evidence fetch parity across CLI/SDK/MCP, one-import agent ergonomics, intent-compilation projection stage, correlation index, hosted-admission consolidation polish) +- **C — Narrative polish** (README + protocol-layman category-claim integrity, developer-experience-index persona golden paths, Diataxis doc coverage, forbidden-copy lint expansion, concierge demand test scaffold) +- **D — Keel-integrity audit** (10-invariant re-verification, gateway-held credential custody for x402 signer, adversarial architecture test promotion, global transition admission matrix at HTTP, mandatory generated-execution-graph for agent-origin compilations) + +Comprehensive-scale (target ~10–14 plans). Phase 05 plans assume Phase 04 lands first. + +## Current Phase + +**Phases 04 and 05 are complete locally** (2026-05-29). Remote ship (PR/merge/npm publish) is deferred until gh and npm credentials are available. + +**Phase 04** — service-agent gating: operator golden path, dual-enforcement doctrine, structural HTTP/example gating, tier gates 10/10 + 15/15. See [04-VERIFICATION.md](./phases/04-service-agent-gating/04-VERIFICATION.md). + +**Phase 05** — product coherence: deferred lane, live-fetch spine, narrative + forbidden-copy lint, gateway-held x402 custody (Mechanism A), keel audit. See [05-VERIFICATION.md](./phases/05-product-coherence/05-VERIFICATION.md). + +## Smallest Next Mechanism + +Push branch, open PR, and run remote CI/npm publish when tooling allows. Optional hygiene: pre-existing manifest-coverage and repo-naming-posture test residuals. + +--- + +## Historical Track (legacy `docs/plans/`) + +The earlier planning track lived under `docs/plans/`. Retained for provenance; **not the current source of truth**. The active track is `.planning/phases/` above. + +**Completed (legacy):** + +- `docs/plans/01-plan-eng-review-primitive-fields-state.md` +- `docs/plans/01a-plan-eng-review-protocol-migration.md` + +**Current (legacy):** + +- `docs/plans/02-plan-eng-review-authority-hardening.md` + +**Archived / not executable:** + +- `docs/plans/archive/02-plan-eng-review-agent-requirements.md` +- `.planning/archive/agent-native-product-requirements-handoff/*` + +**Next (legacy):** + +- `docs/plans/03-plan-protected-mcp-cli-preview-deploy.md` + +Treat the `docs/plans/` track as historical context for the kernel and authority-hardening work that fed the current `.planning/phases/` track. Do not promote legacy plans into CI names, exports, or product claims without re-anchoring them in the current phase structure. diff --git a/.planning/STATE.md b/.planning/STATE.md new file mode 100644 index 0000000..65e7184 --- /dev/null +++ b/.planning/STATE.md @@ -0,0 +1,73 @@ +--- +gsd_state_version: 1.0 +milestone: v1.0 +milestone_name: milestone +status: phases_04_05_complete_local +last_updated: "2026-05-29T00:00:00Z" +progress: + total_phases: 5 + completed_phases: 5 + total_plans: 42 + completed_plans: 42 + percent: 100 +--- + +# Local Planning State + +Generated: 2026-05-24 +Updated: 2026-05-29 (Phase 04 + 05 local close-out) + +## Current Mode + +Planning scratch is local-only. Canonical repo truth lives in `AGENTS.md`, `README.md`, +`QUALITY.md`, `STRUCTURE.md`, and `docs/internal/*`. + +## Current State + +**Phases 04 + 05 complete** on branch `phase-05-product-coherence` @ `4509826`, +**pushed to origin** (`origin/phase-05-product-coherence`). Phase 04 is an ancestor of +Phase 05, so this single branch carries both phases. `phase-04-service-agent-gating` is +also on origin @ `74ff1f1`. Operator tier **10/10** and full tier **15/15** gates green; +`npx tsc --noEmit` clean; `bun test` **849 pass / 3 fail** (acceptable residuals only; +HR-01 classifier-doctrine fix landed @ `e60fc87`). + +**Remote land — partial:** branch pushed ✓. Still pending (require credentials absent in +this environment): +- **PR + merge to main** — `gh` CLI absent; create via web: + `https://github.com/CreasyBear/handshake-protocol-source/compare/main...phase-05-product-coherence` +- **npm publish** — `npm whoami` returns 401; needs `npm login` (or a token in `~/.npmrc`) + before `npm publish`. Confirm version (`package.json` 0.2.7) is not already taken. + +## Phase Status + +| Phase | Folder | Status | +|-------|--------|--------| +| 02 | `02-address-concerns` | Complete | +| 03 | `03-close-enforcement-gaps` | Complete | +| 04 | `04-service-agent-gating` | Complete — [04-VERIFICATION.md](./phases/04-service-agent-gating/04-VERIFICATION.md) `passed` | +| 05 | `05-product-coherence` | Complete — [05-VERIFICATION.md](./phases/05-product-coherence/05-VERIFICATION.md) `passed` | + +## Locked Premise + +Current scratch reference: + +- `.planning/macro/PLAN.md` + +It is scratch coordination only. Promote durable decisions into canonical docs or +source tests before relying on them. + +## Do Not Do + +- Do not treat `.planning/` as repo truth. +- Do not use old Tier 2/preview-deploy planning state as current product direction. +- Do not choose a first adapter or shipment path unless tracked source and docs support it. +- Do not treat human personas, dashboards, public routes, or Cloud surfaces as the first unit of product planning. +- Do not claim gateway enforcement unless a gateway check owns the mutation boundary. +- Do not expand canonical product docs from scratch planning without source-backed tests. + +## Smallest Next Mechanism + +Remote ship when tooling allows: push `phase-05-product-coherence`, open PR, run CI, +and npm publish per release policy. Optional: fix pre-existing manifest-coverage and +repo-naming-posture residuals; await `05-REVIEW.md` if a sibling code-review agent +still lands it. diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md index b14c03f..ab19ecc 100644 --- a/.planning/codebase/ARCHITECTURE.md +++ b/.planning/codebase/ARCHITECTURE.md @@ -1,308 +1,437 @@ - + # Architecture -**Analysis Date:** 2026-05-25 +**Analysis Date:** 2026-05-29 ## System Overview +Handshake is a TypeScript protocol kernel for protected action infrastructure. The kernel records exact action contracts, policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, and optional terminal certificates. Product surfaces (CLI, MCP, SDK, surfaces) propose and read evidence; they do not create authority. Reference gateway adapters in `src/adapters/` perform protected-surface mutation only after a verified `gatewayCheck` transition. + +Core model (authority chain): + +```text +Principal vague intent + │ + ▼ +Intent compilation (candidate actions, overreach/refusal markers) + `src/protocol/areas/intent-compilation/` + │ + ▼ +CandidateAction → ActionContract (exact commitment) + `src/protocol/areas/action-contract/` + │ + ▼ +Atomic policy evaluation (greenlight / refusal / review / halt / quarantine) + `src/protocol/areas/policy-greenlight/transitions.ts` + │ + ▼ +Gateway check before mutation (enforcement boundary) + `src/protocol/areas/gateway-gate/transitions.ts` + │ + ▼ +Adapter mutation (only after VerifiedGatewayCheck) + `src/adapters/*` + │ + ▼ +Receipt / refusal / proof-gap / optional authority certificate + `src/protocol/areas/operation-lifecycle/`, `refusal/`, `proof-gap/` +``` + ```text -Product and integration surfaces -`src/cli`, `src/mcp`, `src/sdk`, `src/http`, `src/runtime`, `src/surfaces` - | - v -HTTP admission and route dispatch -`src/http/app.ts`, `src/http/admission/index.ts`, -`src/http/routes/transition-route-registry.ts`, -`src/http/routes/transition-invokers.ts` - | - v -Protocol authority kernel -`src/protocol/kernel.ts`, `src/protocol/areas/*` - | - v -Protocol store and reconstruction state -`src/protocol/store/port.ts`, `src/storage/*`, `migrations/0001_protocol_kernel.sql` - | - +--> Gateway adapters before mutation - | `src/adapters/x402-payment/wallet-gateway.ts`, - | `src/adapters/package-install/gateway.ts` - | - +--> Evidence projections and read models - `src/protocol/evidence-projections/*`, - `src/http/handlers/evidence-read.ts` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Product surfaces (no authority) │ +├──────────────┬──────────────┬──────────────┬──────────────┬───────────────┤ +│ `src/cli/` │ `src/mcp/` │ `src/sdk/` │`src/surfaces/│`src/x402- │ +│ evidence, │ stdio tools, │ Handshake │ readbacks, │protected-tool/│ +│ service- │ resources, │ Client + │ proof │ facade, │ +│ operator │ x402 propose │ role clients │ packets │ readiness │ +└──────┬───────┴──────┬───────┴──────┬───────┴──────┬───────┴───────┬───────┘ + │ │ │ │ │ + │ HTTP/SDK │ HTTP/SDK │ POST /v0.2 │ store read │ runtime + │ or local │ or ref │ transitions │ projections │ ingress + ▼ ▼ ▼ ▼ ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Transport & admission (`src/http/`, `src/hosted-admission/`) │ +│ `app.ts` → admission → mutation manifest parity → sequence matrix → │ +│ `transition-invokers` → `HandshakeKernel` │ +│ Handlers lane: read-only allowlist (evidence, verifier, hosted readiness) │ +└────────────────────────────────────┬────────────────────────────────────────┘ + │ + ┌─────────────────────────────┼─────────────────────────────┐ + ▼ ▼ ▼ +┌──────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ +│ `src/runtime/` │ │ `src/protocol/` │ │ `src/adapters/` │ +│ ingress, │───▶│ kernel + areas │◀───│ x402 wallet gateway, │ +│ proposals, │ │ (state transitions) │ │ package-install, etc. │ +│ generated graphs │ │ │ │ mutate AFTER gate │ +└──────────────────┘ └──────────┬───────────┘ └──────────────────────┘ + │ + ▼ + ┌──────────────────────────────────────┐ + │ `src/storage/` — `ProtocolStore` port │ + │ `memory/`, `d1/`, `kv/` + `migrations/` │ + └──────────────────────────────────────┘ ``` ## Component Responsibilities | Component | Responsibility | File | |-----------|----------------|------| -| Canonical repo doctrine | Defines current product kernel, authority invariants, and scratch-vs-canon boundaries. | `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, `docs/internal/decisions.md`, `docs/internal/protocol-notes.md` | -| Protocol kernel facade | Coordinates protocol transitions and persists append-only state through the store port. | `src/protocol/kernel.ts` | -| Protocol areas | Own source-level schemas, transition inputs, transition outputs, and state-machine rules for each protected-action primitive. | `src/protocol/areas/*` | -| Policy greenlight area | Produces policy decisions and one-use greenlights without performing gateway checks or mutations. | `src/protocol/areas/policy-greenlight/transitions.ts`, `src/protocol/areas/policy-greenlight/policy-record/index.ts` | -| Gateway gate area | Verifies exact greenlight, contract, idempotency, isolation, path posture, credential binding, and drift before consequence. | `src/protocol/areas/gateway-gate/transitions.ts`, `src/protocol/areas/gateway-gate/artifacts.ts` | -| Runtime ingress | Compiles runtime/tool observations into candidate actions and contracts; it is proposal-only. | `src/runtime/ingress/index.ts`, `src/runtime/ingress/registry.ts` | -| HTTP transport | Enforces caller custody/read admission and dispatches route IDs to kernel transitions. | `src/http/app.ts`, `src/http/admission/index.ts`, `src/http/routes/transition-route-registry.ts`, `src/http/routes/transition-invokers.ts` | -| Gateway adapters | Hold mutation-side integration logic and only execute after a verified gateway check. | `src/adapters/x402-payment/wallet-gateway.ts`, `src/adapters/package-install/gateway.ts` | -| Evidence projections | Build redacted review/readback models from stored protocol records. | `src/protocol/evidence-projections/projections.ts`, `src/protocol/evidence-projections/assembly.ts` | -| Storage adapters | Implement append-only events, current indexes, greenlight consumption, idempotency ledgers, and scoped reads. | `src/storage/memory/index.ts`, `src/storage/d1/index.ts`, `src/protocol/store/port.ts` | -| Architecture tests | Freeze import posture, package surfaces, surface authority boundaries, and public claims. | `test/architecture/*` | +| HandshakeKernel | Facade over all protocol transitions; no transport | `src/protocol/kernel.ts` | +| Protocol areas | Owned primitives: contract, policy, gateway gate, negotiation, etc. | `src/protocol/areas/*` | +| ProtocolRecorder | Append-only events + atomic record commits | `src/protocol/events/records.ts` | +| ProtocolStore | Durable records, stream tail, greenlight consumption, gate commits | `src/protocol/store/port.ts` | +| FailureClass taxonomy | Cross-surface failure classification (HTTP/MCP/SDK) | `src/protocol/foundation/failure-class/index.ts` | +| HTTP app | Hono routes, admission, transition dispatch, evidence reads | `src/http/app.ts` | +| Mutation route manifest | Frozen POST inventory; drift guard at app construction | `src/http/mutation-route-manifest.ts` | +| Transition sequence matrix | Declared prerequisite routes; acyclic drift guard | `src/http/admission/transition-sequence-matrix.ts` | +| Transition invokers | Map route IDs to kernel methods (+ runtime ingress bridge) | `src/http/routes/transition-invokers.ts` | +| Runtime ingress | Compile dispatch blocks into candidates/contracts (observer lane) | `src/runtime/ingress/index.ts` | +| HandshakeClient | Typed HTTP transition + evidence calls | `src/sdk/client.ts` | +| Role surface clients | Custody-scoped clients (policy, gateway, evidence, etc.) | `src/sdk/surface-clients/` | +| Reference adapters | Gateway fixtures; enforcement before mutation | `src/adapters/x402-payment/wallet-gateway.ts`, etc. | +| MCP stdio server | Proposal tool + redacted evidence resources | `src/mcp/stdio/server.ts` | +| CLI runner | Command manifest, projections, service-operator bootstrap | `src/cli/main.ts` | +| Surfaces | Boundary manifest, proof packets, A2A readback, integrator parity | `src/surfaces/boundary-manifest.ts` | +| Hosted admission | Provider-neutral caller identity evidence contracts | `src/hosted-admission/` | +| Worker entry | Cloudflare `fetch` → `createApp()` | `src/worker.ts` | +| Package exports | Curated public API | `src/index.ts` | ## Pattern Overview -**Overall:** Source-owned protocol kernel with narrow transport/adapters, append-only receipts, and redacted projection read models. +**Overall:** Layered authority boundary with a single kernel facade, append-only evidence store, and dual-enforcement transport posture (Phase 04–05). -**Key Characteristics:** -- Authority lives in protocol transitions and gateway checks, not in CLI, SDK, MCP, review UI, runtime ingress, public exports, or generated demos. -- Policy greenlights are exact, one-use, gateway-bound records; they are not execution proof and do not perform mutation. -- Gateway adapters hold the final mutation boundary and must obtain `VerifiedGatewayCheck` evidence before calling an external surface. -- Evidence read models are projections assembled from protocol records; they support review and recovery but do not create authority. -- `.planning/` is scratch; tracked source, root docs, and `docs/internal/*` are the current repo truth. +**Key characteristics:** +- Every consequential path reduces to an exact `ActionContract`, then policy, then one-use greenlight, then `gatewayCheck` before mutation. +- Runtime and MCP/CLI are proposal and readback lanes; they never substitute for gateway enforcement. +- HTTP admission binds caller custody role per transition; hosted routes add scope checks via `src/hosted-admission/hosted-caller-identity.ts`. +- HTTP handlers are read-only; all protocol mutation goes through POST transition routes inventoried in `mutation-route-manifest.ts`. +- Example and adapter runners must call `run*Gateway` before protected mutation (`test/architecture/http-handler-mutation-gating.test.ts`). +- Gateway adapters are the only place that should touch payment/signing/install mutation credentials after a passed gate. ## Layers -**Canonical Doctrine:** -- Purpose: Define the current product boundary and the vocabulary future work must obey. -- Location: `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, `docs/internal/decisions.md`, `docs/internal/protocol-notes.md` -- Contains: Product kernel, decisions, quality rules, source ownership rules, protocol notes. -- Depends on: No source implementation. -- Used by: Planning, implementation, architecture tests, package-surface claims. - -**Surface and Client Layer:** -- Purpose: Expose Handshake through CLI, MCP, SDK role clients, demos, and public package exports without becoming authority. -- Location: `src/cli`, `src/mcp`, `src/sdk`, `src/surfaces`, `src/index.ts`, `src/experimental.ts` -- Contains: Command manifests, MCP server glue, role clients, renderable surfaces, curated package exports, experimental reference fixtures. -- Depends on: Public protocol/surface contracts and HTTP clients. -- Used by: Consumers, examples, package exports, conformance demos. - -**Runtime Proposal Layer:** -- Purpose: Convert runtime/tool observations into intent compilation records and proposed action contracts. -- Location: `src/runtime/ingress/index.ts`, `src/runtime/ingress/families.ts`, `src/runtime/ingress/registry.ts` -- Contains: Proposal-only family registry for `package.install`, `x402_payment.exact`, and `auth.md.protected_api_call`; generated graph and tool-call draft recording. -- Depends on: Protocol kernel transitions that create proposal records. -- Used by: HTTP transition route `runtimeIngress.proposeActionContracts` and demos. - -**Admission and Transport Layer:** -- Purpose: Admit or reject HTTP callers by custody role, entitlement, route metadata, tenant/org scope, and hosted scope posture. -- Location: `src/http/app.ts`, `src/http/admission/index.ts`, `src/http/routes/*`, `src/http/handlers/*` -- Contains: Hono app, transition route registry, transition invokers, evidence read routes, record-read handlers, readiness/verifier handlers. -- Depends on: `src/protocol/kernel.ts`, `src/storage/*`, request headers, route metadata. -- Used by: Cloudflare Worker entry point `src/worker.ts`, SDK/CLI/MCP clients, hosted or local HTTP deployments. - -**Protocol Authority Kernel:** -- Purpose: Own the state machine that turns exact contracts into policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, isolation, and certificates. -- Location: `src/protocol/kernel.ts`, `src/protocol/areas/*` -- Contains: Source-owned schemas, transition inputs, transition outputs, digest/canonicalization helpers, status transitions, receipts, isolation records. -- Depends on: Protocol store port and protocol-local utilities. -- Used by: HTTP transport, tests, adapters, projection assembly. - -**Gateway Adapter Layer:** -- Purpose: Bridge verified gateway checks to real mutation surfaces. -- Location: `src/adapters/x402-payment/wallet-gateway.ts`, `src/adapters/package-install/gateway.ts` -- Contains: Adapter-specific gateway execution, credential resolution evidence, official signer custody for x402, package-install surface invocation. -- Depends on: `src/protocol/areas/gateway-gate/artifacts.ts`, kernel gateway-check transitions, adapter-specific mutation APIs. -- Used by: External integration examples and runtime-gateway flows. - -**Persistence Layer:** -- Purpose: Persist append-only events and current-state indexes required for reconstruction and replay protection. -- Location: `src/protocol/store/port.ts`, `src/storage/memory/index.ts`, `src/storage/d1/index.ts`, `src/storage/kv`, `migrations/0001_protocol_kernel.sql` -- Contains: Store interface, in-memory implementation, D1 implementation, Cloudflare KV helpers, SQL tables for current ledgers and stream events. -- Depends on: Protocol record types. -- Used by: Kernel, HTTP app, projections, tests. - -**Projection and Read Model Layer:** -- Purpose: Build scoped, redacted evidence views for review, recovery, and diagnostics. -- Location: `src/protocol/evidence-projections/projections.ts`, `src/protocol/evidence-projections/assembly.ts`, `src/http/routes/evidence-read-route-registry.ts`, `src/http/handlers/evidence-read.ts`, `src/http/handlers/internal-record-read.ts` -- Contains: Contract evidence projection, transaction envelope projection, timeline projection, read-route role/scope metadata, raw record guardrails. -- Depends on: Store reads and protocol record types. -- Used by: Review custody and runtime evidence read endpoints. - -## Authority Boundary - -**Authority lives here:** -- `src/protocol/areas/policy-greenlight/transitions.ts` evaluates policy and records policy decisions while explicitly keeping gateway checks and mutation attempts false. -- `src/protocol/areas/policy-greenlight/policy-record/index.ts` creates `Greenlight` records bound to contract digest, policy pack, gateway, idempotency key, and `maxUses: 1`. -- `src/protocol/areas/gateway-gate/transitions.ts` verifies the exact greenlight, observed request digest, isolation state, protected path posture, delegated authority binding, gateway credential binding, sequence dependencies, idempotency ledger, and gateway policy drift before committing a gateway plan. -- `src/protocol/areas/gateway-gate/artifacts.ts` exposes `verifiedGatewayCheckFromResult` only when the gateway check passes and a mutation attempt/surface operation reference exists. -- `src/adapters/x402-payment/wallet-gateway.ts` signs x402 payloads only after deriving verified gateway evidence from the kernel. -- `src/adapters/package-install/gateway.ts` calls the package-install mutation surface only after verified gateway evidence exists. -- `src/storage/memory/index.ts`, `src/storage/d1/index.ts`, and `migrations/0001_protocol_kernel.sql` enforce replay-sensitive current indexes such as greenlight consumption, idempotency ledger, isolation current state, protected path operation claims, and receipt lookup. - -**Authority does not live here:** -- `src/runtime/ingress/index.ts` records proposed contracts and sets non-authority posture; it does not issue greenlights, gateway checks, or mutation proof. -- `src/http/admission/index.ts` admits callers to routes and evidence reads; admission is custody/read entitlement, not permission to mutate. -- `src/protocol/evidence-projections/*` builds read models; projections never write greenlights or gateway checks. -- `src/cli`, `src/mcp`, `src/sdk`, `src/surfaces`, and `examples/*` expose product surfaces and demos; they must not become hidden policy or gateway authority. -- `src/index.ts` curates public exports and intentionally excludes the kernel class, stores, internal recorder, and reference gateway runners from the root package surface. - -## Passport, Admission, Service Gateway, Principal-Agent Link - -**Current source-owned shapes:** -- Passport-like identity is represented as evidence binding, not authority: `ParticipantIdentityBinding` in `src/protocol/areas/catalog-envelope/schemas.ts` and `OperatingEnvelope.participantIdentityBindings` in `src/protocol/areas/catalog-envelope/schemas.ts`. -- The principal-agent link is already explicit on `OperatingEnvelope` in `src/protocol/areas/catalog-envelope/schemas.ts`, copied onto `ActionContract` in `src/protocol/areas/action-contract/schemas.ts`, and bound through `DelegatedAuthorityRef` in `src/protocol/areas/delegated-authority/schemas.ts`. -- Admission is HTTP route custody and read entitlement in `src/http/admission/index.ts`, using metadata from `src/http/routes/transition-route-registry.ts` and `src/http/routes/evidence-read-route-registry.ts`. -- Service gateway concepts map to `GatewayRegistryEntry` in `src/protocol/areas/catalog-envelope/schemas.ts`, `GatewayCredentialRef` and custody proof packets in `src/protocol/areas/credential-custody/schemas.ts`, and gateway checks in `src/protocol/areas/gateway-gate/*`. - -**Simplification rule:** -- Do not add a separate `Passport` protocol primitive unless it narrows exact gateway enforcement. Treat passport as a projection/readback name over `ParticipantIdentityBinding`, `OperatingEnvelope`, `ActionContract`, and `DelegatedAuthorityRef`. -- Do not make admission a source of protected-action authority. Keep admission as caller custody and route entitlement, then let policy greenlight and gateway check decide consequence. -- Do not introduce a new service-gateway layer beside the existing gateway registry, credential custody, and gateway gate. Rename or project if needed, but keep the mutation boundary in `src/protocol/areas/gateway-gate/*` and adapter gateway files. -- Keep the principal-agent link as canonical source data on envelope, contract, and delegated authority references; avoid duplicating it into a reusable auth token. +**Protocol kernel (`src/protocol/`):** +- Purpose: Source-owned state machine, schemas, canonicalization, transition guards. +- Location: `src/protocol/` +- Contains: `kernel.ts`, `areas/*`, `foundation/*` (including `failure-class/`), `events/*`, `public/*`, `evidence-projections/*`, `navigation/*`, `store/port.ts` +- Depends on: Nothing outside protocol (per `src/protocol/LANE.md`) +- Used by: HTTP invokers, SDK, storage implementations, tests + +**HTTP transport (`src/http/`):** +- Purpose: Worker/Hono app, OpenAPI, transition routes, evidence read routes, verifier projections. +- Location: `src/http/` +- Contains: `app.ts`, `routes/`, `handlers/` (read-only allowlist), `admission/`, `errors/`, `mutation-route-manifest.ts` +- Depends on: Protocol kernel, storage resolution, hosted-admission helpers +- Used by: `src/worker.ts`, integration tests, SDK default transport +- Construction guards: `assertMutationRouteManifestParity()` and `assertTransitionSequenceMatrixCoverage()` run at module load in `src/http/app.ts` + +**Runtime observer (`src/runtime/`):** +- Purpose: Generated-execution evidence, ingress dispatch parsing, family-specific action proposals. +- Location: `src/runtime/ingress/`, `src/runtime/codemode-multi-action/`, per-family folders +- Depends on: Protocol types, adapter proposal configs +- Used by: `transitionInvokers.proposeRuntimeIngressActionContracts`, CLI/MCP bridges + +**Reference adapters (`src/adapters/`):** +- Purpose: Gateway registry fixtures, wallet gateway (gateway-held custody), protected-tool facade wiring, bypass probes. +- Location: `src/adapters/x402-payment/`, `src/adapters/package-install/`, `src/adapters/auth-md/`, etc. +- Depends on: Protocol records, runtime ingress shapes; must not own protocol meaning +- Used by: Integration tests, `src/x402-protected-tool/`, experimental exports + +**Product surfaces (`src/cli/`, `src/mcp/`, `src/sdk/`, `src/surfaces/`):** +- Purpose: Ergonomic proposal, evidence projection, conformance status, readbacks, integrator-parity navigation. +- Depends on: HTTP/SDK or in-process test clients +- Must not: Evaluate policy, issue greenlights, perform gateway checks, or mutate protected surfaces directly + +**Storage (`src/storage/`):** +- Purpose: `ProtocolStore` implementations (memory for tests, D1 for Worker, KV plumbing). +- Location: `src/storage/memory/`, `src/storage/d1/`, `src/storage/kv/` +- Schema: `migrations/` (canonical D1) ## Data Flow -### Primary Protected-Action Path +### Primary protected-action chain (kernel) + +Applies to all action classes including `x402_payment.exact`: + +1. **Catalog / install setup** — `putCatalogObject`, `registerInstallProposalCompiledRecords` (`src/http/routes/transition-invokers.ts` → `src/protocol/kernel.ts`) +2. **Runtime evidence** — `createRuntimeExecution`, optional `createGeneratedExecutionGraph`, `createToolCallDraft` (`src/protocol/areas/runtime-evidence/`, `generated-execution-graph/`, `tool-call-draft/`) +3. **Intent → contract** — `compileIntent` (`src/protocol/areas/intent-compilation/candidate-decision.ts` derives `CandidateAction` contractability) then `proposeActionContract` (`src/protocol/areas/action-contract/`) +4. **Credential custody evidence** — `registerGatewayCredentialRef`, `recordGatewayCustodyProofPacket`, `recordCredentialResolutionEvidence` (`src/protocol/areas/credential-custody/`) — records only, no secrets +5. **Policy** — `evaluatePolicy` issues greenlight, refusal, review, halt, or quarantine (`src/protocol/areas/policy-greenlight/transitions.ts`) +6. **Gateway check (enforcement boundary)** — `gatewayCheck` (`src/protocol/areas/gateway-gate/transitions.ts`) +7. **Downstream observation** — `reconcileSurfaceOperation`, receipts, proof gaps, optional `createAuthorityCertificate` (`src/protocol/areas/operation-lifecycle/`, `authority-certificate/`) + +**State management:** All authority-bearing state lives in `ProtocolStore` via `ProtocolRecorder` commits. `ActionAttemptLifecycle` is derived evidence in `src/protocol/areas/action-attempt-lifecycle/`, not a separate authority object. Idempotency is enforced in `src/protocol/areas/idempotency-ledger/` before greenlight consumption. + +### x402 protected action path (first wedge) + +End-to-end local/reference flow (integration anchor: `test/integration/x402-d1-http.test.ts`): + +```text +Agent runtime / codemode dispatch + │ + ▼ +Runtime ingress block (x402 family) + `src/runtime/ingress/` + `src/adapters/x402-payment/action-proposal.ts` + │ + ▼ +HTTP POST proposeRuntimeIngressActionContracts OR kernel.proposeActionContract + `src/http/routes/transition-invokers.ts` + │ + ▼ +evaluatePolicy → one-use Greenlight (bound to exact contract digest) + `src/protocol/areas/policy-greenlight/` + │ + ▼ +╔═══════════════════════════════════════════════════════════════════╗ +║ GATEWAY CHECK BOUNDARY — `kernel.gatewayCheck()` ║ +║ `src/protocol/areas/gateway-gate/transitions.ts` ║ +║ Verifies: greenlight binding, params digest, isolation, ║ +║ protected-path posture, credential refs, idempotency, drift ║ +║ Records: gate attempt, receipt, refusal, replay refusal, proof gap ║ +║ Does NOT: sign payments or call protected HTTP APIs ║ +╚═══════════════════════════════════════════════════════════════════╝ + │ + ▼ +Reference wallet gateway (gateway-held custody, D-64) + `src/adapters/x402-payment/wallet-gateway.ts` + `assertGatewayHeldSigningCommand()` — signer requires VerifiedGatewayCheck + + gate-bound `used_by_gateway` credential resolution evidence + Mutation + signer use ONLY after gateDecision === passed + │ + ▼ +recordCredentialResolutionEvidence (post-gate use evidence) +reconcileSurfaceOperation (downstream finality, no retry authority) +``` + +**MCP proposal path:** `src/mcp/x402-proposal.ts` → runtime client → same transition chain; tool name `handshake.actions.x402_payment.propose` (`src/mcp/catalog.ts`). MCP exposes redacted `handshake://evidence/*` resources (`src/mcp/resources.ts`), not raw records. MCP tool outcomes attach `FailureClass` via `classifyFailureClassFromReasonCodes` (`src/mcp/output.ts`). + +**Protected-tool facade path:** `src/x402-protected-tool/index.ts` re-exports `prepareProtectedX402ToolDispatch` from `src/adapters/x402-payment/protected-tool-facade/` — packages readiness snapshots and dispatch preparation for host activation profiles (`src/adapters/x402-payment/protected-tool-profile/*`). + +**CLI path:** `src/cli/x402/*`, `src/cli/demo/x402.ts`, `src/cli/simulate/x402-payment.ts` drive install, probes, and evidence views via `src/cli/main.ts`; they render APS/evidence, not gateway custody. Service-operator bootstrap lives at `src/cli/service-operator/bootstrap.ts` (command id `service.bootstrap` in `src/cli/command-manifest.ts`). + +### HTTP request path + +1. Request hits `createApp()` route (`src/http/app.ts`) +2. Construction-time guards already verified mutation manifest parity and sequence matrix coverage +3. `authorizeTransitionAdmission` — role token + optional hosted identity (`src/http/admission/`) +4. Body parsed against route `requestSchema` (`src/http/routes/transition-route-registry.ts`) +5. `kernelFor` constructs `HandshakeKernel` with store + request context (`src/http/store/resolution.ts`) +6. `transitionInvokers[routeId](kernel, body)` executes transition +7. JSON 201 or structured `TransitionErrorEnvelope` with `failureClass` (`src/http/errors/transition-error-envelope.ts`) + +Evidence reads use GET handlers in `src/http/handlers/evidence-read.ts` and `src/http/routes/evidence-read-route-registry.ts` — read-only projections from `src/protocol/evidence-projections/` (including `store-reader.ts` for in-process readback). + +### SDK client path + +`HandshakeClient` in `src/sdk/client.ts` posts to `/v0.2/*` transition paths with caller role headers from `src/http/admission/caller-auth.ts`. Specialized clients in `src/sdk/surface-clients/` (control-plane, runtime, policy, gateway, install, evidence) wrap the same transport under explicit custody roles per `src/surfaces/boundary-manifest.ts` and integrator-parity table in `docs/internal/integrator-parity-transitions.md`. SDK transport maps HTTP status to `FailureClass` via `failureClassFromHttpStatus` (`src/sdk/surface-clients/transport.ts`); `src/sdk/repair.ts` derives remediation hints from failure class. + +## Dual-enforcement gating (Phase 04–05) + +Handshake enforces mutation authority at two complementary layers: + +**Layer 1 — HTTP handler allowlist (transport):** +- All first-party HTTP handlers under `src/http/handlers/` must be read-only (evidence, verifier, hosted readiness, internal record read). +- Enforced by `test/architecture/http-handler-mutation-gating.test.ts` against `readOnlyHandlerAllowlist`. +- Handlers must not import `run*Gateway` or perform direct mutation patterns. + +**Layer 2 — Adapter-gated runners (mutation side):** +- Protected mutation happens only in `src/adapters/*` after `VerifiedGatewayCheck`. +- Example runners (`examples/x402-protected-spend/run.ts`, etc.) must call `run*Gateway` before mutation. +- Every POST transition row in `src/http/mutation-route-manifest.ts` carries `requiresAdapterGatewayCheck: true` — documenting that HTTP transitions record authority steps; actual protected-surface mutation remains adapter-side after gate pass. + +**Service mutation route manifest:** +- Frozen inventory at `src/http/mutation-route-manifest.ts` mirrors `transitionRouteDefinitions` exactly. +- `assertMutationRouteManifestParity()` throws at app construction on drift (missing/extra POST paths). +- Separate from `src/surfaces/boundary-manifest.ts` surface ownership (adjudication #7). + +**Transition sequence matrix:** +- `src/http/admission/transition-sequence-matrix.ts` documents canonical prerequisite routes (e.g. `gatewayCheck` requires `proposeActionContract`). +- `assertTransitionSequenceMatrixCoverage()` verifies coverage, referential integrity, and acyclicity at app construction. +- Admission ordering contract only — per-request rejection still comes from kernel guards and scope resolvers. + +## FailureClass taxonomy + +Central definition: `src/protocol/foundation/failure-class/index.ts`. -1. Caller reaches the Worker/Hono app (`src/worker.ts`, `src/http/app.ts`). -2. HTTP route metadata selects custody requirements and the kernel invoker (`src/http/routes/transition-route-registry.ts`, `src/http/routes/transition-invokers.ts`). -3. Admission checks caller role, route family, hosted scope, tenant/org scope, and evidence-read posture (`src/http/admission/index.ts`). -4. Runtime ingress or explicit transition creates intent compilation, contract, catalog envelope, authority reference, credential posture, and related records (`src/runtime/ingress/index.ts`, `src/protocol/kernel.ts`). -5. Policy evaluation records decision and, when allowed, a one-use greenlight bound to the exact contract and gateway (`src/protocol/areas/policy-greenlight/transitions.ts`, `src/protocol/areas/policy-greenlight/policy-record/index.ts`). -6. Gateway check revalidates current state, exact request digest, idempotency, isolation, delegated authority, credential custody, protected path posture, sequencing, and policy drift (`src/protocol/areas/gateway-gate/transitions.ts`). -7. Adapter performs external mutation only after verified gateway evidence exists (`src/adapters/x402-payment/wallet-gateway.ts`, `src/adapters/package-install/gateway.ts`). -8. Receipt, refusal, proof gap, reconciliation, recovery, isolation, or certificate records are appended to the store (`src/protocol/kernel.ts`, `src/protocol/store/port.ts`, `src/storage/*`). +| FailureClass | Meaning | Typical sources | +|--------------|---------|-----------------| +| `auth` | Caller custody / bearer failure | HTTP 401, `caller_auth_*` codes | +| `hosted_admission` | Hosted caller identity/config failure | `hosted_*` codes (non-stale) | +| `stale_admission` | Stale protected-path or hosted posture | `hosted_caller_identity_stale`, posture stale codes | +| `protected_action_refusal` | Policy/gateway/isolation refusal | Policy/gateway decision codes, refusals | +| `replay_refusal` | Replay or duplicate authority | `idempotency_duplicate_authority`, replay codes | +| `proof_gap` | Missing or incomplete evidence | HTTP 422, MCP binding/install codes, recovery with proofRef | +| `internal` | Misconfiguration or server fault | HTTP 5xx, unregistered transition errors | -### Evidence Read Path +**Surface wiring:** +- HTTP: `src/http/errors/transition-error-envelope.ts` — `failureClassForProtocolError`, `httpStatusForFailureClass` +- MCP: `src/mcp/output.ts`, `src/mcp/x402-proposal.ts` — `mcpFailureClassEvidenceRef(failureClass)` +- SDK: `src/sdk/client.ts`, `src/sdk/surface-clients/transport.ts`, `src/sdk/repair.ts` -1. Caller requests a read route declared in `src/http/routes/evidence-read-route-registry.ts`. -2. Admission validates role, read scope, tenant/org scope, and artifact posture (`src/http/admission/index.ts`). -3. Handler loads only needed protocol records from the store (`src/http/handlers/evidence-read.ts`, `src/http/handlers/internal-record-read.ts`). -4. Projection code redacts and assembles review/readback views (`src/protocol/evidence-projections/projections.ts`, `src/protocol/evidence-projections/assembly.ts`). -5. HTTP response returns evidence projection, not raw authority or mutation permission (`src/http/handlers/evidence-read.ts`). +Reason-code metadata may pre-classify failures via `classifiedFailure` in `src/protocol/foundation/reason-codes.ts`. -### Runtime Ingress Proposal Path +## Gateway check boundary -1. Runtime ingress receives tool/action observations and declared runtime posture (`src/runtime/ingress/index.ts`). -2. Registry selects a proposal-only action family (`src/runtime/ingress/registry.ts`, `src/runtime/ingress/families.ts`). -3. Kernel records runtime execution, generated action graph, tool-call draft, intent compilation, and action contract (`src/runtime/ingress/index.ts`, `src/protocol/kernel.ts`). -4. Response declares candidate actions and explicitly marks policy, greenlight, gateway check, mutation, receipt, certificate, and permission as false (`src/runtime/ingress/index.ts`). +**Where authority ends and enforcement begins:** `HandshakeKernel.gatewayCheck()` → `src/protocol/areas/gateway-gate/transitions.ts`. -**State Management:** -- State is append-only plus current-index ledgers. `migrations/0001_protocol_kernel.sql` defines durable D1 tables for stream events, greenlight consumption, idempotency current state, isolation current state, protected path operation claims, and receipt lookup. `src/storage/memory/index.ts` mirrors those semantics for tests and local runs. +**Inside the boundary (kernel records):** +- Exact greenlight-to-contract binding and one-time consumption (`GreenlightConsumption` via store commit) +- Observed params digest vs contract (`protectedActionParamsDigest` in `src/protocol/foundation/canonical.ts`) +- Isolation state, protected-path posture, delegated authority, gateway credential ref bindings +- Gate attempt, receipt, mutation attempt index, replay refusal (`src/protocol/areas/gateway-gate/replay-refusal/`) + +**Outside the boundary (adapters only, after pass):** +- Wallet signing, x402 challenge/response HTTP, package manager exec, repo writes +- Implementations live under `src/adapters/*`; conformance probes in `src/conformance/` + +**x402 gateway-held custody (D-64):** `assertGatewayHeldSigningCommand` in `src/adapters/x402-payment/wallet-gateway.ts` structurally refuses signing unless the command carries a genuine `VerifiedGatewayCheck` and gate-bound `used_by_gateway` credential resolution evidence with redacted material posture. + +**Anti-advisory rule:** Calling `evaluatePolicy` or holding a greenlight does not authorize mutation. Skipping `gatewayCheck` or reusing a greenlight is ambient authority, not Handshake. Admission alone is advisory, not Handshake enforcement (`test/architecture/dual-enforcement-posture.test.ts`). + +## Integrator-parity surfaces + +Bounded HTTP/SDK surface for service integrators (Phase 04 operator TTHW): + +- Navigation tags: `test/architecture/integrator-parity.test.ts` verifies every integrator-parity transition in `src/protocol/navigation/index.ts` +- Role client mapping: `ControlPlaneClient`, `InstallClient`, `RuntimeClient`, `PolicyClient`, `GatewayClient` in `src/sdk/surface-clients/` +- Reference walkthrough: `test/sdk/role-clients-walkthrough.test.ts` +- Appendix: `docs/internal/integrator-parity-transitions.md` +- Runnable wedge in phase 04: x402 only; auth.md and package-install families marked proof-gap + +Surface boundary manifest (`src/surfaces/boundary-manifest.ts`) maps surface IDs to route families, custody roles, authority postures, and non-authority flags for CLI/MCP/SDK/x402/surfaces. ## Key Abstractions -**Operating Envelope:** -- Purpose: Bounds attempts, runtime context, participant bindings, catalog references, gateway registry references, and evidence expectations. -- Examples: `src/protocol/areas/catalog-envelope/schemas.ts`, `src/protocol/areas/action-contract/contract-record.ts` -- Pattern: Source data copied into exact contracts; it authorizes attempts, not mutations. - -**Action Contract:** -- Purpose: Exact proposed commitment derived from intent compilation and bound to principal, agent, tenant, organization, gateway, idempotency, protected path, payload, and evidence expectations. -- Examples: `src/protocol/areas/action-contract/schemas.ts`, `src/protocol/areas/action-contract/transitions.ts`, `src/protocol/areas/action-contract/contract-record.ts` -- Pattern: Deterministic contract record before policy and gateway. - -**Policy Decision and Greenlight:** -- Purpose: Machine-checkable decision and one-use authorization candidate for a gateway check. -- Examples: `src/protocol/areas/policy-greenlight/transitions.ts`, `src/protocol/areas/policy-greenlight/policy-record/index.ts` -- Pattern: Policy can allow/refuse/review/halt/quarantine; greenlight is exact and consumed once. - -**Gateway Check:** -- Purpose: Final enforcement proof before mutation. -- Examples: `src/protocol/areas/gateway-gate/transitions.ts`, `src/protocol/areas/gateway-gate/artifacts.ts` -- Pattern: Revalidate exact binding and current posture, then produce verified gateway evidence or refusal/proof gap. - -**Delegated Authority Reference:** -- Purpose: Binds principal, agent, runtime, envelope, gateway, allowed actions, resource bounds, and spend/amount limits without creating mutation authority or secret material. -- Examples: `src/protocol/areas/delegated-authority/schemas.ts`, `src/protocol/areas/delegated-authority/transitions.ts` -- Pattern: Reference and status evidence, checked later by gateway transitions. - -**Credential Custody:** -- Purpose: Records gateway-held credential posture and proof packets while keeping secret material outside protocol records. -- Examples: `src/protocol/areas/credential-custody/schemas.ts`, `src/protocol/areas/credential-custody/transitions.ts` -- Pattern: Evidence of custody and resolution; adapters hold signing/mutation capability. - -**Evidence Projection:** -- Purpose: Read model for review/recovery that omits raw secrets and authority-bearing material. -- Examples: `src/protocol/evidence-projections/projections.ts`, `src/protocol/evidence-projections/assembly.ts` -- Pattern: Redacted projection assembled from stored protocol records. +**ActionContract:** +- Purpose: Exact proposed commitment for one protected mutation attempt +- Examples: `src/protocol/areas/action-contract/` +- Pattern: Canonical digest binding; proposed via `proposeActionContract` -## Entry Points +**CandidateAction / IntentCompilation:** +- Purpose: Compiled candidate from vague intent with contractability status +- Examples: `src/protocol/areas/intent-compilation/candidate-decision.ts` +- Pattern: `deriveCandidateDecision` → `contractable` or `rejected` with reason codes -**Worker HTTP Entry:** -- Location: `src/worker.ts` -- Triggers: Cloudflare Worker fetch events. -- Responsibilities: Instantiate `createApp()` and delegate HTTP handling. +**Greenlight / PolicyDecision:** +- Purpose: Machine-checkable policy outcome bound to one contract +- Examples: `src/protocol/areas/policy-greenlight/` +- Pattern: One-use; consumed at gateway check -**HTTP App Factory:** -- Location: `src/http/app.ts` -- Triggers: Worker, tests, local server runners. -- Responsibilities: Bind store environment, register transition/read routes, run admission, call invokers, format JSON responses. +**GatewayCheckResult:** +- Purpose: Gate attempt + receipt (+ optional mutation attempt record) +- Examples: `src/protocol/areas/gateway-gate/artifacts.ts` +- Pattern: `verifiedGatewayCheckFromResult` exported from `src/index.ts` for clients -**Protocol Kernel:** -- Location: `src/protocol/kernel.ts` -- Triggers: HTTP transition invokers, tests, adapter flows. -- Responsibilities: Execute protocol transitions and write protocol records through `ProtocolStore`. +**ProtocolRecord / object registry:** +- Purpose: Typed persisted objects with stable IDs and digests +- Examples: `src/protocol/areas/object-registry/schemas.ts` -**Public Package Root:** -- Location: `src/index.ts` -- Triggers: Package consumers importing `handshake-protocol-kernel`. -- Responsibilities: Export public contract types, role clients, surfaces, and non-internal helpers while excluding kernel/store internals. +**Evidence projections:** +- Purpose: Redacted read models for CLI/MCP/HTTP evidence routes +- Examples: `src/protocol/evidence-projections/projections.ts`, `store-reader.ts` -**Experimental Surface:** -- Location: `src/experimental.ts` -- Triggers: Explicit `./experimental` imports. -- Responsibilities: Export reference fixtures and helpers with experimental naming. +**Surface boundary manifest:** +- Purpose: Maps product surfaces to allowed route families and custody roles +- Examples: `src/surfaces/boundary-manifest.ts` -**Adapter Gateways:** -- Location: `src/adapters/x402-payment/wallet-gateway.ts`, `src/adapters/package-install/gateway.ts` -- Triggers: Adapter-specific protected action execution. -- Responsibilities: Run gateway checks and perform external mutation only after verified gateway evidence. +## Entry Points + +**npm package root:** +- Location: `src/index.ts` (package `handshake-protocol-kernel@0.2.7`) +- Triggers: `import from "handshake-protocol-kernel"` +- Responsibilities: Curated exports (HTTP app factory, SDK client, protocol schemas, verifier helpers) + +**CLI:** +- Location: `bin/handshake` → `src/cli/main.ts` via `src/cli/index.ts` +- Triggers: `handshake ` +- Responsibilities: Operator/evidence commands; `service bootstrap` via `src/cli/service-operator/bootstrap.ts`; no kernel mutation authority + +**MCP stdio:** +- Location: `bin/handshake-mcp` → `src/mcp/stdio/server.ts` +- Triggers: MCP host launches stdio server +- Responsibilities: x402 proposal tool + static evidence resources + +**Cloudflare Worker:** +- Location: `src/worker.ts` → `src/http/app.ts` +- Triggers: Worker `fetch` +- Responsibilities: Hosted/local HTTP API with D1 bindings via `wrangler.toml` + +**Subpath exports:** +- `./runtime`, `./sdk/role-clients`, `./mcp`, `./cli`, `./x402-protected-tool`, `./surfaces/*`, `./hosted-admission`, `./adapter-sdk`, `./conformance` — see `package.json` `exports` ## Architectural Constraints -- **Threading:** TypeScript runs on a single JavaScript event loop in local and Worker-style environments. Concurrency safety is modeled through store-level conflict detection, greenlight consumption, and idempotency ledgers, not threads. -- **Global state:** Runtime ingress action families are registered in module-level maps in `src/runtime/ingress/families.ts` and `src/runtime/ingress/registry.ts`; architecture tests keep them proposal-only. -- **Circular imports:** Architecture tests require protocol areas and the kernel to import area packages through lane-owned public indexes instead of deep sibling internals (`test/architecture/import-posture.test.ts`). -- **Protocol/storage separation:** `src/protocol/areas/*` must not import `src/storage/*`; persistence flows through `src/protocol/store/port.ts`. -- **Transport/protocol separation:** HTTP route metadata, invokers, and response schemas stay in separate files under `src/http/routes`. -- **Projection/authority separation:** Observer and projection files are blocked from importing policy greenlight, gateway gate, delegated authority, credential custody, receipt, isolation, or certificate authority internals. -- **Official signer custody:** The official x402 signer factory remains in `src/adapters/x402-payment/wallet-gateway.ts`; tests block it from SDK, CLI, MCP, root exports, runtime ingress, and generated outputs. +- **Threading:** Node ≥20 ESM; Worker is single-request isolate. No shared mutable kernel state across requests — store is per-binding/per-test instance. +- **Global state:** Avoid module-level mutable protocol state. `HandshakeKernel` holds `store` + `ProtocolRecorder` per instance (`src/protocol/kernel.ts`). +- **Import posture:** Protocol must not import HTTP, SDK, adapters, or storage implementations (`src/protocol/LANE.md`). Enforced by `test/architecture/import-posture.test.ts`. +- **Dependency direction:** Kernel must not depend on surfaces; surfaces create no authority. Each first-level `src/*` lane maintains `LANE.md` with authority owner and forbidden imports. +- **Body size:** Transition POST bodies capped at 256 KiB (`src/http/app.ts`). +- **Catalog immutability:** `putCatalogObject` rejects digest conflicts for same object id. ## Anti-Patterns -### Admission As Authority +### Product surface performs gateway enforcement + +**What happens:** CLI/MCP/SDK code signs, pays, or installs based on policy output alone. -**What happens:** HTTP admission allows a route call and the caller treats that as permission to mutate. -**Why it's wrong:** Admission only proves caller custody/read entitlement; it does not bind an exact action contract, one-use greenlight, gateway check, or mutation attempt. -**Do this instead:** Admit the caller in `src/http/admission/index.ts`, then require policy greenlight and gateway verification through `src/protocol/areas/policy-greenlight/*` and `src/protocol/areas/gateway-gate/*`. +**Why it's wrong:** Policy and greenlight are not execution authority; receipt cannot distinguish advisory checks from gateway checks. -### Projection As Proof +**Do this instead:** Route mutation through adapter code only after `gatewayCheck` passes; use surfaces for proposal and `src/protocol/evidence-projections/` readback. -**What happens:** A review/readback projection is treated as raw evidence or execution proof. -**Why it's wrong:** Projection code intentionally redacts fields such as contract parameters, secret refs, and contract signatures; it is a read model. -**Do this instead:** Use `src/protocol/evidence-projections/*` for review/readback, then trace raw records through scoped store reads and protocol receipts where the caller has authority. +### HTTP handler performs mutation -### Runtime Ingress As Permission +**What happens:** A handler under `src/http/handlers/` calls gateway runners or protected APIs directly. -**What happens:** Candidate actions produced by runtime ingress are treated as executable authority. -**Why it's wrong:** Runtime ingress is proposal-only and explicitly reports no policy decision, greenlight, gateway check, mutation attempt, receipt, certificate, or permission. -**Do this instead:** Continue through policy and gateway routes after candidate contract creation (`src/runtime/ingress/index.ts`, `src/protocol/areas/policy-greenlight/*`, `src/protocol/areas/gateway-gate/*`). +**Why it's wrong:** Violates dual-enforcement handler allowlist; bypasses mutation manifest inventory. -### New Passport Primitive +**Do this instead:** Add a transition route + invoker; keep handlers read-only per `test/architecture/http-handler-mutation-gating.test.ts`. -**What happens:** Passport/admission/service gateway/principal-agent link becomes a parallel protocol object beside existing envelope, contract, delegated authority, credential custody, and gateway registry records. -**Why it's wrong:** It duplicates authority-adjacent state and creates room for reusable ambient permission. -**Do this instead:** Project a passport read model from `ParticipantIdentityBinding`, `OperatingEnvelope`, `ActionContract`, `DelegatedAuthorityRef`, and credential/gateway evidence without adding a new authority-bearing record. +### Runtime ingress treated as permission + +**What happens:** `proposeRuntimeIngressActionContracts` or `compileIntent` outcomes used directly to mutate. + +**Why it's wrong:** Runtime lane records evidence and candidates; it does not evaluate policy or verify greenlight binding. + +**Do this instead:** Follow kernel chain through `evaluatePolicy` and `gatewayCheck` (`src/runtime/ingress/index.ts` → HTTP transitions). + +### HTTP handler embeds policy rules + +**What happens:** Route handlers interpret contract fields or approve spend. + +**Why it's wrong:** `src/http/` must not own protocol meaning (`STRUCTURE.md` ownership table). + +**Do this instead:** Add rules in `src/protocol/areas/policy-greenlight/` and invoke via `transitionInvokers.evaluatePolicy`. + +### Negotiation records imply authority + +**What happens:** Accepted A2A offer or linked agreement used as reusable auth. + +**Why it's wrong:** `src/protocol/areas/negotiation/` is evidence-only; policy may require an active `AgreementObligationBinding` but does not replace gateway check. + +**Do this instead:** Bind obligation to exact contract, then run normal policy + gateway path (`docs/internal/decisions.md`). ## Error Handling -**Strategy:** Protocol transitions return structured decisions, refusals, proof gaps, conflict statuses, and evidence records instead of throwing across authority boundaries. +**Strategy:** Typed `HandshakeProtocolError` with HTTP mapping via `transitionErrorResult` (`src/protocol/foundation/errors.ts`, `src/http/errors/transition-error-envelope.ts`). All surfaces share `FailureClass` taxonomy from `src/protocol/foundation/failure-class/index.ts`. **Patterns:** -- Gateway checks return passed/refused/proof-gap outcomes with specific failure posture in `src/protocol/areas/gateway-gate/transitions.ts`. -- Store writes detect greenlight consumption, idempotency conflicts, protected-path conflicts, receipt conflicts, and isolation-current conflicts in `src/storage/memory/index.ts` and `src/storage/d1/index.ts`. -- HTTP handlers catch typed transition outcomes and return JSON with route identity headers in `src/http/app.ts`. -- Missing evidence is recorded as proof gap or diagnostic posture rather than converted into success in `src/protocol/areas/*`. +- Transition guards return refusal codes before commit (`src/protocol/foundation/transition-guards.ts`) +- Gateway refusals recorded as gate decisions with reason codes (`src/protocol/areas/gateway-gate/gateway-policy.ts`) +- Store commit conflicts surface as 409 or structured retryability on envelope +- MCP/SDK attach failure class for operator remediation (`src/sdk/repair.ts`) ## Cross-Cutting Concerns -**Logging:** Runtime and protocol evidence is structured as records in the store, not free-form logs. Console output is limited to examples and scripts such as `examples/*/run.mjs` and `scripts/*`. -**Validation:** Source-owned schema validation lives beside each protocol area in files such as `src/protocol/areas/action-contract/schemas.ts`, `src/protocol/areas/catalog-envelope/schemas.ts`, and `src/protocol/areas/credential-custody/schemas.ts`. -**Authentication:** HTTP admission validates caller role, route family, hosted verifier entitlement, and scope in `src/http/admission/index.ts`; protected-action authority still requires policy and gateway records. -**Receipts:** Receipts, reconciliation, certificates, recovery, and proof gaps are protocol records assembled into projections by `src/protocol/evidence-projections/assembly.ts`. -**Package Boundaries:** `package.json`, `src/index.ts`, `src/experimental.ts`, and `test/architecture/package-surface.test.ts` keep internal authority surfaces out of public root exports. +**Logging:** No centralized logger; CLI uses structured `cliOutput` (`src/cli/output.ts`). Prefer proof gaps and recorded refusals over log-only evidence. + +**Validation:** Zod schemas at HTTP boundary and area inputs (`src/protocol/public/schemas.ts`, per-area `schemas.ts`). + +**Authentication:** Transition caller roles via bearer tokens in `src/http/admission/caller-auth.ts`; hosted routes add `hosted-admission` evidence (`src/hosted-admission/`). Admission authorizes transition custody, not principal authority over mutations. + +**Redaction:** Evidence routes and MCP resources use redaction profiles; raw internal records gated at `src/http/handlers/internal-record-read.ts`. --- -*Architecture analysis: 2026-05-25* +*Architecture analysis: 2026-05-29* diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md index cf90452..6bf59a1 100644 --- a/.planning/codebase/CONCERNS.md +++ b/.planning/codebase/CONCERNS.md @@ -1,287 +1,304 @@ # Codebase Concerns -**Analysis Date:** 2026-05-25 - -## Map Scope - -- This document treats `.planning/` as scratch context. Canonical repo truth lives in tracked source and docs such as `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, `docs/internal/decisions.md`, and `docs/internal/protocol-notes.md`. -- No `TODO`, `FIXME`, `HACK`, or `XXX` markers are detected in tracked source, tests, or canonical docs under `src/`, `test/`, `tests/`, `docs/`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, or `AGENTS.md`. -- No source-owned `Passport`, `PrincipalAgentLink`, or standalone service-gateway kernel object is detected. The source model already carries principal/agent identity evidence, delegated attempt authority, gateway registry binding, credential custody, HTTP admission evidence, and gateway checks. -- Existing service gateway references are fixture or endpoint refs, not a kernel object: `test/support/auth-md-flow.ts`, `test/adapters/auth-md-gateway.test.ts`, and `test/adapters/auth-md-adapter.test.ts`. - -## Protocol / Kernel Simplification Risks - -**Passport/admission/service-gateway/principal-agent object pressure:** -- Issue: Adding a new kernel object named `Passport`, `Admission`, `ServiceGateway`, or `PrincipalAgentLink` duplicates existing protocol responsibilities instead of clarifying authority. -- Files: `src/protocol/areas/catalog-envelope/schemas.ts`, `src/protocol/areas/delegated-authority/schemas.ts`, `src/protocol/areas/delegated-authority/transitions.ts`, `src/http/admission/hosted-caller-identity.ts`, `src/http/admission/request-context.ts`, `src/protocol/areas/object-registry/schemas.ts`. -- Impact: A second object can blur whether authority comes from identity evidence, route admission, delegated authority, gateway custody, or the verified gateway check. That creates ambient permission language around a chain that is meant to stay exact and one-use. -- Fix approach: Reuse the existing primitives. Put principal/agent identity evidence in `ParticipantIdentityBinding` on `OperatingEnvelope`; put scoped attempt authority in `DelegatedAuthorityRef`; put service mutation custody in `GatewayRegistryEntry` and `GatewayCredentialRef`; put transport caller evidence in `TransitionCallerIdentity` and `transition_request_context`; put any "passport" view in a projection or packet under `src/surfaces/` or `src/adapters/`, not a new `src/protocol/areas/` object. - -**Kernel object registry expansion is high-friction by design:** -- Issue: New protocol object types require schema ownership, registry posture, navigation, route roles, storage, export/read posture, evidence projection, claim tests, and migration decisions. -- Files: `src/protocol/areas/object-registry/schemas.ts`, `src/protocol/areas/object-registry/index.ts`, `src/protocol/navigation.ts`, `src/http/routes/transition-route-registry.ts`, `src/http/routes/evidence-read-route-registry.ts`, `src/storage/d1/index.ts`, `migrations/0001_protocol_kernel.sql`. -- Impact: A new object that only renames an existing relation increases protocol surface without increasing enforceable control. The likely debt is inconsistent read posture, incomplete isolation scope refs, missing D1 indexes, root export confusion, and product language overclaim. -- Fix approach: Add a kernel object only when it records a distinct terminal or state-transition event that cannot be represented by the existing protocol areas. Otherwise, add a typed projection, proof packet, or adapter profile. - -**Principal-agent link already has an evidence-only shape:** -- Issue: A standalone principal-agent link object is redundant with the envelope identity-binding and delegated-authority model. -- Files: `src/protocol/areas/catalog-envelope/schemas.ts`, `test/protocol/participant-identity-binding.test.ts`, `src/protocol/areas/delegated-authority/schemas.ts`, `src/protocol/areas/delegated-authority/transitions.ts`. -- Impact: If the link object reads as permission, it violates the boundary that principal/agent identity is evidence and that delegated authority authorizes only attempts, not mutation. -- Fix approach: Keep participant identity bindings evidence-only and canonicalized into the envelope digest. Use `DelegatedAuthorityRef` for scoped principal-agent-runtime-envelope-gateway attempt authority, with `greenlightCreated: false` and `mutationAuthorityCreated: false`. - -**Service gateway is an adapter/gateway role, not a protocol role:** -- Issue: "Service gateway" can be modeled as gateway custody or a protected API adapter, but making it a kernel object creates overlap with gateway registry, credential custody, and gateway check semantics. -- Files: `src/protocol/areas/catalog-envelope/schemas.ts`, `src/protocol/areas/credential-custody/schemas.ts`, `src/adapters/auth-md/gateway.ts`, `src/adapters/x402-payment/wallet-gateway.ts`, `src/http/routes/transition-route-registry.ts`. -- Impact: A service-gateway object can launder operational integration into authority. The authority boundary remains `gatewayCheck`, not service discovery, admission, endpoint registration, or credential provenance. -- Fix approach: Keep service-specific behavior in adapter packages such as `src/adapters/auth-md/` and `src/adapters/x402-payment/`. Promote only generic evidence or terminal protocol state to `src/protocol/areas/`. - -## Product-Language Confusion - -**"Admission" is overloaded across product, HTTP, gateway, and surface packets:** -- Issue: Admission means expansion admission in `docs/internal/decisions.md`, hosted route admission in `src/http/admission/index.ts`, gateway-admission status in receipt export schemas, and auth.md+x402 admission packets in product surfaces. -- Files: `docs/internal/decisions.md`, `src/http/admission/index.ts`, `src/http/admission/hosted-admission-config.ts`, `src/protocol/areas/receipt-export/schemas.ts`, `src/surfaces/proof-packets.ts`, `src/surfaces/product-launch-gate-resolution.ts`. -- Impact: The word can make read admission, readiness, or a launch packet sound like execution authority. That is advisory, not Handshake, unless the chain reaches exact contract, policy, one-use greenlight, gateway check, and receipt/refusal/proof gap. -- Fix approach: Use narrower names in new work: `route admission`, `expansion evidence packet`, `gateway check posture`, or `launch gate packet`. Avoid standalone `Admission` as a kernel noun. - -**auth.md + x402 interlock surfaces are evidence, not composite execution:** -- Issue: The interlock packet verifies structural conditions and proof gaps, but it does not make auth.md credential issuance or x402 payment signing a composite live authority path. -- Files: `src/adapters/auth-md-x402-interlock/packet.ts`, `test/architecture/auth-md-x402-interlock-packet.test.ts`, `src/surfaces/proof-packets.ts`, `src/surfaces/product-launch-gate-resolution.ts`, `docs/internal/decisions.md`. -- Impact: Naming it as admission can imply the service call is already cleared. The packet is a launch/evidence surface; authority remains per protected API call and per x402 exact payment action. -- Fix approach: Keep `readyForCompositeExecution: false` as a hard non-claim until the composite path has exact action contracts, policy decisions, one-use greenlights, verified gateway checks, credential/payment evidence, receipts, refusals, and proof gaps. - -**Certificate/passport language risks permission drift:** -- Issue: `AuthorityCertificate` is terminal evidence, but passport-style naming can suggest reusable entry permission. -- Files: `README.md`, `QUALITY.md`, `docs/internal/decisions.md`, `src/protocol/areas/authority-certificate/schemas.ts`, `src/protocol/areas/authority-certificate/transitions.ts`. -- Impact: A certificate or passport label can be mistaken for identity, permission, settlement, hosted trust, or reusable auth. That is ambient authority wearing a badge if it authorizes later calls. -- Fix approach: Use `certificate` only for terminal evidence and use `proof packet` for reviewable surface state. Do not create reusable passport credentials inside the kernel. - -## Tech Debt - -**Exact protected-action policy is triggered by parameter keys:** -- Issue: `exactProtectedActionPolicyApplies` identifies exact protected-action policy by checking parameter keys such as `gatewayReadinessRef`, `gatewayReadinessDigest`, `policyVersionRef`, `policyVersionDigest`, and `paymentRequirementsDigest`. -- Files: `src/protocol/areas/policy-greenlight/transitions.ts`, `test/protocol/policy-greenlight.test.ts`, `test/protocol/x402-payment-contract.test.ts`. -- Impact: A new action family can accidentally enter this branch by using similar keys, or miss the branch by expressing equivalent evidence under different keys. That makes expansion brittle and can produce inconsistent refusal/greenlight behavior. -- Fix approach: Bind protected-action policy evaluation to explicit action type or policy-pack capability under `src/protocol/areas/policy-greenlight/`, not incidental parameter names. - -**D1 conflict classification depends on database error text:** -- Issue: D1 conflict handling classifies failures by matching substrings from SQLite/D1 error messages and by intentionally forcing a `NOT NULL` constraint in mismatch cases. -- Files: `src/storage/d1/index.ts`, `src/storage/d1/statements.ts`, `migrations/0001_protocol_kernel.sql`, `test/protocol/protocol-store-atomicity-contract.test.ts`, `test/http/d1-http.test.ts`. -- Impact: D1 or SQLite message drift can turn a structured idempotency or one-use-greenlight refusal into an unclassified storage error. -- Fix approach: Prefer deterministic post-failure readbacks and table-specific invariant checks for conflict classification. Keep the current atomicity tests as the minimum regression net. - -**Surface-boundary posture is enforced by string scans:** -- Issue: The boundary manifest and architecture tests check imports, forbidden terms, and credential shapes through source text patterns. -- Files: `src/surfaces/boundary-manifest.ts`, `test/architecture/surface-boundary-posture.test.ts`, `test/architecture/claim-boundary.test.ts`. -- Impact: String scans can miss dynamic imports, re-export indirection, alias changes, generated code paths, or semantic authority drift. They are claim guardrails, not a runtime enforcement boundary. -- Fix approach: Continue using the tests for product-language discipline, but keep real authority in HTTP route roles, protocol transitions, gateway checks, and storage invariants. - -**Large projection/profile files concentrate unrelated risk:** -- Issue: Several files mix schema projection, claim language, evidence transformation, and product gate posture in large modules. -- Files: `src/surfaces/proof-packets.ts`, `src/adapters/auth-md/profiles.ts`, `src/cli/x402/index.ts`, `src/mcp/x402-proposal.ts`, `src/protocol/evidence-projections/projections.ts`, `src/protocol/areas/policy-greenlight/transitions.ts`. -- Impact: Small copy or schema changes can silently alter product claims, packet readiness, and protocol evidence shape in the same edit. Review burden is high. -- Fix approach: Split by owned concern when edits touch these files: schemas, builders, product-gate verdicts, and text projections. Do not combine behavior changes with language cleanup. - -**Role clients and root exports are deliberately narrow but easy to blur:** -- Issue: The package exposes curated root exports plus deeper role clients and adapter/runtime subpaths. A convenience export can accidentally imply broader authority or make a proposal-only surface look executable. -- Files: `src/index.ts`, `src/sdk/role-clients/index.ts`, `src/sdk/LANE.md`, `test/architecture/root-exports.test.ts`, `README.md`. -- Impact: Import ergonomics can turn package availability into perceived authority, especially around MCP, runtime ingress, and role clients. -- Fix approach: Keep authority-sensitive helpers behind explicit subpaths and preserve `test/architecture/root-exports.test.ts` as a gate for new exports. - -## Known Bugs - -**No reproducible source bug detected in the concern scan:** -- Symptoms: No concrete tracked-source bug is identified by `TODO`/`FIXME` markers or by the targeted passport/admission/service-gateway/principal-agent search. -- Files: `src/`, `test/`, `docs/internal/decisions.md`, `docs/internal/protocol-notes.md`. -- Trigger: Not applicable. -- Workaround: Treat documented proof gaps and cut lines as product boundaries, not hidden bugs. - -**Live/provider x402 execution is intentionally refused:** -- Symptoms: Non-reference provider environments are rejected before x402 signing. -- Files: `src/adapters/x402-payment/wallet-gateway.ts`, `test/adapters/x402-wallet-gateway.test.ts`, `docs/internal/decisions.md`, `README.md`. -- Trigger: Use of a provider environment posture other than `local_reference_sandbox`. -- Workaround: Keep live/provider x402 claims out of docs and demos until provider custody, facilitator behavior, gateway installation, and settlement evidence are proven. - -## Security Considerations - -**Hosted admission verifier is a seam, not a production auth system:** -- Risk: A weak `HostedCallerVerifier` can return a validly shaped `TransitionCallerIdentity` for the wrong caller, tenant, org, project, role, or scope. -- Files: `src/http/admission/index.ts`, `src/http/admission/hosted-caller-identity.ts`, `src/http/admission/hosted-admission-config.ts`, `src/http/LANE.md`, `test/http/http.test.ts`. -- Current mitigation: Hosted admission validates identity shape, freshness, roles, hosted read scopes, route scope, and request context evidence. The hosted config explicitly reports no hosted mutation authority, no payment management, no settlement authority, and no provider custody. -- Recommendations: Treat provider verification, org auth, service credential issuance, and hosted operation as deployment-specific security work outside the kernel. Keep hosted operation in proof-gap language until a concrete verifier implementation and threat model exist. - -**Static bearer role tokens are reference transport credentials:** -- Risk: `CallerAuthTokens` can be mistaken for production organization authentication. -- Files: `src/http/admission/caller-auth.ts`, `src/sdk/client.ts`, `src/sdk/surface-clients/transport.ts`, `src/sdk/LANE.md`, `README.md`. -- Current mitigation: Tokens are role-scoped and constant-time compared; hosted caller identity is modeled separately. -- Recommendations: Use static tokens only for local/reference deployments. Production paths need a hosted verifier with tenant/org/project/role/scope evidence. - -**Credential redaction is heuristic in adapter profiles:** -- Risk: auth.md credential material detection relies on structured schemas plus regex/base64 heuristics that can miss provider-specific secret formats. -- Files: `src/adapters/auth-md/profiles.ts`, `src/adapters/auth-md/gateway.ts`, `src/protocol/areas/credential-custody/schemas.ts`, `docs/internal/protocol-notes.md`. -- Current mitigation: Evidence schemas reject raw credential material and keep `GatewayCredentialRef` opaque. Gateway adapters record credential resolution after verified gateway checks. -- Recommendations: Add provider-specific credential fixtures, fuzzing, and negative tests before any live credential custody claim. - -**Runtime ingress is caller-observed evidence, not host containment:** -- Risk: Raw or sibling tool paths can bypass runtime ingress, especially browser-side tools, shell commands, package managers, or direct network calls outside a wrapper. -- Files: `src/runtime/ingress/schemas.ts`, `src/runtime/ingress/index.ts`, `src/runtime/LANE.md`, `docs/internal/protocol-notes.md`. -- Current mitigation: Runtime ingress records wrapped/raw-sibling/ambiguous posture and emits proposals only. It does not create policy, greenlights, gateway checks, or receipts. -- Recommendations: Do not claim broad runtime interception or sandbox containment. For each runtime integration, document raw bypass posture and prove the protected mutation must pass through the gateway. - -**MCP surfaces are proposal/evidence only:** -- Risk: Registry availability or MCP tool exposure can be misread as executable protection. -- Files: `src/mcp/server.ts`, `src/mcp/x402-proposal.ts`, `server.json`, `README.md`, `test/architecture/root-exports.test.ts`. -- Current mitigation: README and claim-boundary tests state MCP has no policy decisions, greenlights, gateway checks, signers, mutations, receipt export, hosted operation, or broad protection. -- Recommendations: Keep MCP Registry discoverability as a proof gap until acceptance and lookup are verified, and keep MCP authority claims out of package surfaces. - -## Performance Bottlenecks - -**In-memory store uses scans and is not a scaling store:** -- Problem: The local store keeps protocol records in memory and resolves many queries by iterating maps or arrays. -- Files: `src/storage/memory/index.ts`, `test/protocol/protocol-store-atomicity-contract.test.ts`. -- Cause: It is designed as local/test/reference storage, not tenant-scale persistence. -- Improvement path: Keep production-facing performance claims on D1 or a real durable store, not `createInMemoryProtocolStore`. - -**Evidence projection and proof packet construction parse large JSON records:** -- Problem: Projection paths fetch protocol records and reconstruct evidence views in process. -- Files: `src/protocol/evidence-projections/projections.ts`, `src/surfaces/proof-packets.ts`, `src/storage/d1/index.ts`. -- Cause: Projection code favors reconstructability and schema validation over precomputed read models. -- Improvement path: Add explicit read models or indexed projection tables only after profiling real tenant workloads. Do not make projection caches authority-bearing. - -**Runtime ingress has bounded dispatch but no broader throughput model:** -- Problem: Dispatch proposal input is capped and validated, but runtime ingestion is not modeled as high-volume event streaming. -- Files: `src/runtime/ingress/schemas.ts`, `src/runtime/ingress/index.ts`. -- Cause: The runtime path is a proposal compiler for known dispatch families, not a host-wide telemetry pipeline. -- Improvement path: Keep the cap as a safety control. Add backpressure and event-stream storage only when a concrete runtime integration requires it. - -## Fragile Areas - -**Gateway check consumption and idempotency are correctness-critical:** -- Files: `src/protocol/areas/gateway-gate/transitions.ts`, `src/protocol/areas/gateway-gate/gateway-policy.ts`, `src/storage/d1/index.ts`, `migrations/0001_protocol_kernel.sql`, `test/protocol/protocol-store-atomicity-contract.test.ts`. -- Why fragile: The one-use greenlight invariant depends on exact digest checks, gateway-policy drift checks, idempotency ledger entries, and durable consumption records staying aligned. -- Safe modification: Change gateway consumption, idempotency, or D1 statements only with atomicity tests and replay/refusal tests. Do not loosen digest comparisons to improve ergonomics. -- Test coverage: Strong local and D1 tests exist, but conflict classification remains tied to D1 error behavior. - -**Policy evaluation mixes generic and family-specific checks:** -- Files: `src/protocol/areas/policy-greenlight/transitions.ts`, `src/protocol/areas/action-contract/schemas.ts`, `src/protocol/areas/delegated-authority/transitions.ts`. -- Why fragile: Policy checks cover isolation, protected path, sequence deps, gateway credential refs, delegated authority refs, x402-like exact payment parameters, and action-specific matching in one transition area. -- Safe modification: Add explicit evaluators per protected action family while keeping all evaluators under the policy-greenlight transition boundary. -- Test coverage: x402 and delegated-authority tests cover current behavior, but a new action family needs negative tests for accidental policy-branch entry. - -**auth.md adapter profiles contain secret-redaction and provenance logic together:** -- Files: `src/adapters/auth-md/profiles.ts`, `src/adapters/auth-md/gateway.ts`, `test/adapters/auth-md-adapter.test.ts`, `test/adapters/auth-md-gateway.test.ts`. -- Why fragile: Credential provenance, identity assertions, lifecycle evidence, gateway intake, and secret-redaction checks share one profile module. -- Safe modification: Keep raw credential rejection tests green for every profile edit. Split helper modules before adding provider-specific credential formats. -- Test coverage: Good reference tests exist; provider-specific fuzzing and live provider fixtures are gaps. - -**Surface packets can harden or distort product truth:** -- Files: `src/surfaces/proof-packets.ts`, `src/surfaces/product-launch-gate-resolution.ts`, `test/architecture/claim-boundary.test.ts`. -- Why fragile: These files turn protocol evidence into product-facing claims. A field rename can imply a stronger boundary than the kernel enforces. -- Safe modification: Update product packets with claim-boundary tests and canonical docs in the same review. -- Test coverage: Claim-boundary tests are broad, but they remain text and schema checks rather than formal product-proof validation. - -## Scaling Limits - -**Per-call spend is modeled; aggregate spend is not enforced:** -- Current capacity: `DelegatedAuthorityRef` supports per-action atomic limits such as `maxAtomicAmountPerAction`, and policy inputs include per-call amount checks. -- Limit: The kernel does not enforce aggregate budget depletion, rolling spend windows, or multi-call balance reservation. -- Scaling path: Add budget ledger semantics only as a new explicit protocol area or transition, with one-use reservation/consumption/refund evidence. Do not overload `DelegatedAuthorityRef` into aggregate spend. - -**One official x402 buyer-side exact action is the live proof lane:** -- Current capacity: The official wedge is one buyer-side `x402_payment.exact` per-call protected action. -- Limit: Broad x402 compatibility, seller/facilitator finality, provider custody, settlement proof, and cross-merchant payment management are proof gaps. -- Scaling path: Expand by adding action-specific contracts and gateway checks, not by broadening the meaning of the existing x402 contract. - -**Hosted operation is read/admission evidence, not provider enforcement:** -- Current capacity: Hosted admission config and caller identity model route and scope transition/read access. -- Limit: The kernel does not prove production hosted mutation authority, customer gateway installation, provider-side enforcement, or org-wide identity governance. -- Scaling path: Add deployment-specific verifier and gateway-install evidence before claiming hosted operation. - -**Protocol object count is already broad:** -- Current capacity: The object registry includes catalog, envelope, delegated authority, credential custody, runtime evidence, intent compilation, action contract, policy, review, gateway gate, mutation, receipt, recovery, certificate, and stream-event objects. -- Limit: Adding synonyms rather than distinct state transitions increases cognitive load and migration cost. -- Scaling path: Prefer projections and packets for new views; promote to protocol object only for new enforceable state. - -## Dependencies at Risk - -**MCP alpha packages:** -- Risk: `@modelcontextprotocol/client` and `@modelcontextprotocol/server` are alpha-version dependencies. -- Impact: API or protocol drift can break MCP proposal/evidence tooling. -- Migration plan: Keep MCP under proposal/evidence-only subpaths and preserve smoke tests around `src/mcp/` before broadening docs or exports. - -**x402 SDK packages:** -- Risk: `@x402/core`, `@x402/evm`, and `@x402/fetch` are external protocol SDK dependencies. -- Impact: Exact payment schema, signature generation, selected payment requirement handling, or provider behavior can drift from local assumptions. -- Migration plan: Keep x402 signing behind `src/adapters/x402-payment/wallet-gateway.ts` and conformance tests. Treat live provider behavior as unproven until tested against real providers. - -**Cloudflare D1/Wrangler behavior:** -- Risk: D1 SQL constraints, conflict messages, and Worker runtime behavior are external to the TypeScript kernel. -- Impact: Storage atomicity can fail noisily or classify errors incorrectly if runtime messages change. -- Migration plan: Prefer durable invariant readbacks over message parsing, and keep D1 tests in `test/http/d1-http.test.ts` and `test/integration/x402-d1-http.test.ts`. - -**Bun/TypeScript pre-release stack:** -- Risk: The repo targets Bun and TypeScript 6-era tooling. -- Impact: Build, typecheck, and module-resolution behavior can drift under dependency upgrades. -- Migration plan: Keep `bun.lock`, `tsconfig.json`, `package.json`, and repo gates aligned; run `npm run check:repo` for release-sensitive edits. - -## Missing Critical Features - -**Provider-grade auth.md credential custody:** -- Problem: auth.md credential provenance and redacted gateway intake exist as reference evidence, not provider-grade secret lifecycle proof. -- Blocks: Live protected API custody claims and broad service-gateway claims. -- Files: `src/adapters/auth-md/profiles.ts`, `src/adapters/auth-md/gateway.ts`, `docs/internal/protocol-notes.md`, `docs/internal/decisions.md`. - -**Composite auth.md + x402 execution:** -- Problem: The interlock packet is a non-authority readiness/evidence surface; composite paid credentialed API calls are not a finished official execution lane. -- Blocks: Claims that auth.md identity/credential issuance plus x402 payment are cleared as one composite service gateway event. -- Files: `src/adapters/auth-md-x402-interlock/packet.ts`, `src/surfaces/product-launch-gate-resolution.ts`, `test/architecture/auth-md-x402-interlock-packet.test.ts`. - -**Hosted operation proof:** -- Problem: Hosted route admission and readiness exist, but production hosted mutation authority and provider/customer gateway installation are proof gaps. -- Blocks: SaaS-style hosted trust claims. -- Files: `src/http/admission/hosted-admission-config.ts`, `src/http/admission/index.ts`, `docs/internal/decisions.md`, `README.md`. - -**Aggregate budget management:** -- Problem: Per-call spend controls exist, but no aggregate spend ledger or reservation lifecycle exists. -- Blocks: Customer budget products and multi-call payment limits. -- Files: `src/protocol/areas/delegated-authority/schemas.ts`, `src/protocol/areas/delegated-authority/transitions.ts`, `src/protocol/areas/policy-greenlight/transitions.ts`. - -**Broad runtime interception:** -- Problem: Runtime ingress supports selected dispatch families and bypass posture evidence; it does not intercept all generated code, browser-side tools, shells, package managers, or network clients. -- Blocks: Claims of host-wide agent containment. -- Files: `src/runtime/ingress/schemas.ts`, `src/runtime/ingress/index.ts`, `src/runtime/LANE.md`. - -## Test Coverage Gaps - -**New passport/admission/service-gateway language:** -- What's not tested: No test enforces that `Passport`, standalone `Admission`, `ServiceGateway`, or `PrincipalAgentLink` remains out of the kernel as an authority-bearing object. -- Files: `test/architecture/claim-boundary.test.ts`, `test/architecture/root-exports.test.ts`, `test/protocol/participant-identity-binding.test.ts`, `src/protocol/areas/object-registry/schemas.ts`. -- Risk: A future object or export can introduce permission semantics outside exact contract and gateway check. -- Priority: High. - -**Provider-specific credential redaction and custody:** -- What's not tested: Broad provider credential formats, malformed auth.md credentials, and fuzzed encoded secret shapes. -- Files: `src/adapters/auth-md/profiles.ts`, `test/adapters/auth-md-adapter.test.ts`, `test/adapters/auth-md-gateway.test.ts`. -- Risk: Secret material can enter evidence or receipts if new formats bypass heuristics. -- Priority: High. - -**Live x402 provider/facilitator behavior:** -- What's not tested: Real provider payment requirements, facilitator responses, settlement/finality evidence, and provider custody outside local reference sandbox. -- Files: `src/adapters/x402-payment/wallet-gateway.ts`, `test/adapters/x402-wallet-gateway.test.ts`, `test/integration/x402-d1-http.test.ts`. -- Risk: Local exact-payment proof can be mistaken for live payment finality. -- Priority: High. - -**Semantic boundary enforcement for surfaces:** -- What's not tested: AST-level import restrictions, dynamic imports, generated code, and semantic authority claims in surfaces. -- Files: `src/surfaces/boundary-manifest.ts`, `test/architecture/surface-boundary-posture.test.ts`, `test/architecture/claim-boundary.test.ts`. -- Risk: A surface can import or imply authority through a path that string scans miss. -- Priority: Medium. - -**Policy evaluator expansion:** -- What's not tested: Negative cases for new protected-action families that share parameter names with x402-like exact protected actions. -- Files: `src/protocol/areas/policy-greenlight/transitions.ts`, `test/protocol/policy-greenlight.test.ts`. -- Risk: Expansion paths can receive wrong policy behavior without obvious type errors. -- Priority: Medium. +**Analysis Date:** 2026-05-29 +**Branch:** `phase-05-product-coherence` @ `aef9478` +**Prior map:** 2026-05-28 (authority-boundary narrative; superseded by this pass) + +This document lists **open** technical debt, proof gaps, and operational blockers verified against the tree at HEAD. Closed Phase 05 security mitigations (Mechanism A custody, import confinement) are cited only where an **accepted residual** remains. + +--- + +## Open proof gaps (distribution and posture) + +### MCP Registry discoverability unverified + +| Field | Detail | +|-------|--------| +| **What** | Public npm publication does not prove MCP Registry acceptance or lookup. Launch `distribution_bar` stays blocked. | +| **Where** | `src/surfaces/product-launch-gate-resolution.ts:81-101` (`blockerReasonCodes`: `mcp_registry_submission_not_accepted`, `mcp_registry_discoverability_not_verified`; registry GET 404 + empty search); `src/surfaces/proof-packets/distribution-provenance.ts:153-164`; `docs/internal/decisions.md:77`, `:244`, `:613`; `README.md:24`; `AGENTS.md:154` | +| **Severity** | **High** (blocks distribution launch language; not an authority bug) | +| **Why open** | Registry submission/lookup not verified in this checkout; source records honest blockers. | +| **Closes when** | Official MCP Registry returns server by `io.github.CreasyBear/handshake-protocol-kernel` name/version; update `productLaunchGateResolutions` + distribution readback inputs; re-run `scripts/check-distribution-provenance.mjs` / product-completion gates. | + +### Whole-repo export surface vs published npm (manifest + distribution) + +| Field | Detail | +|-------|--------| +| **What** | Local `package.json` `exports` omits `./hosted-admission` and `./surfaces/service-workflow-admission` even though `src/hosted-admission/` and `src/surfaces/service-workflow-admission/` exist and `boundary-manifest.ts` registers `surfaces.hosted_admission` / `surfaces.service_workflow_admission`. `test/architecture/manifest-coverage.test.ts` fails; published npm@0.2.7 cannot expose the same subpaths as the repo intends. | +| **Where** | `package.json:26-77` (exports list — subpaths absent); `test/architecture/manifest-coverage.test.ts:21-28`, `:128-131` (expects both exports); `src/surfaces/boundary-manifest.ts:849-884` (`sourceRoots` present); `src/surfaces/proof-packets/distribution-provenance.ts:50-57`, `:137-142` (`missingLocalExports` gap when published tarball lacks local export keys) | +| **Severity** | **High** | +| **Why open** | Exports not added to `package.json` / build bundles after hosted-admission and service-workflow surfaces landed; pre-Phase-04 baseline gap, still open at `aef9478` (see `05-VERIFICATION.md` acceptable_failures). | +| **Closes when** | Add `./hosted-admission` and `./surfaces/service-workflow-admission` to `package.json` `exports`, extend `scripts/build-package-bundles.mjs` / `dist/` outputs, publish new npm version, confirm `manifest-coverage` and distribution readback green. | + +### Integrator raw x402 SDK bypass (security F-01 / T-12) + +| Field | Detail | +|-------|--------| +| **What** | Host or integrator code can call `@x402/core/client` / `@x402/evm` outside `runX402WalletGateway` / `assertGatewayHeldSigningCommand`. That path produces **no** Handshake clearance evidence; it is not repo-wide enforceable. | +| **Where** | `docs/internal/decisions.md:365-367` (explicit proof gap); `.planning/phases/05-product-coherence/05-SECURITY.md:55-63` (F-01); `test/architecture/import-posture.test.ts:283-298` (confines SDK imports to `src/adapters/x402-payment/wallet-gateway.ts` only **inside this repo**); `src/adapters/x402-payment/wallet-gateway.ts:143-187`, `:301`, `:375` (guard on canonical paths) | +| **Severity** | **Medium** (accepted) | +| **Why open** | Phase 05 disposition: mitigate in-repo, **accept** external bypass as proof gap (D-25-style consumer inventory deferred). | +| **Closes when** | Integrator conformance gate / documented mandatory wrapper entrypoints + optional consumer-repo CI; not claimed closed by kernel-only import rules. | + +### HTTP transition sequence matrix ≠ per-request gate (security F-02 / T-08) + +| Field | Detail | +|-------|--------| +| **What** | `transitionSequenceMatrix` is a **construction-time** drift guard (matrix/registry parity, acyclicity). It does **not** reject out-of-order HTTP requests by itself. Per-request ordering comes from route `recordScope` + kernel transition guards. | +| **Where** | `src/http/admission/transition-sequence-matrix.ts:4-15`, `:74-85` (comments + `assertTransitionSequenceMatrixCoverage`); `src/http/app.ts:33-34` (wired at app build); `.planning/phases/05-product-coherence/05-SECURITY.md:65-73` (F-02); `.planning/phases/05-product-coherence/05-KEEL-AUDIT.md:73-86` | +| **Severity** | **Medium** (accepted) | +| **Why open** | By design — adding request-time matrix rejection would duplicate kernel guards and risk “second policy engine” theatre. | +| **Closes when** | N/A for acceptance; only “closes” if product docs stop implying matrix is per-request enforcement (already labeled drift guard in source). | + +--- + +## Deferred remote operations (not done at HEAD) + +### PR / merge to main / npm publish + +| Field | Detail | +|-------|--------| +| **What** | Phase 04+05 work lives on stacked branches locally; `origin/main` is behind local `main` (8 commits ahead per local tracking). Full phase stack (`phase-05-product-coherence`) is **139 commits** ahead of `origin/main` merge-base — not merged/pushed as a unit in this mapping pass. npm publish to expose new export surface blocked operationally (401) when attempted outside trusted-publish workflow. | +| **Where** | Git state at map time: branch `phase-05-product-coherence` @ `aef9478`; `05-VERIFICATION.md:27-28` verified @ `6e23848`; `docs/internal/decisions.md:760-762` (`actually_published` / `registry_discoverable` definitions) | +| **Severity** | **High** (release/process) | +| **Why open** | No `gh` merge + no successful maintainer npm publish of export-complete artifact in this session; operator tooling constraints (per plan context). | +| **Closes when** | PR merged to `main`, `npm publish` with provenance for version containing full export surface, registry verification, tags aligned with `CHANGELOG.md`. | + +### CI: check-only, no publish-on-merge + +| Field | Detail | +|-------|--------| +| **What** | GitHub Actions runs `npm run check:repo` only — no release, no npm publish, no registry push on merge. | +| **Where** | `.github/workflows/check.yml:14-24` (`bun install` + `npm run check:repo`); `test/architecture/naming-posture.test.ts:161-168` (asserts workflow lacks `trusted-publish` / `npm publish`) | +| **Severity** | **Medium** | +| **Why open** | Trusted publish workflow exists in **release projection** artifact (`.github/workflows/trusted-publish.yml` in projected tree — see `test/architecture/release-repository-projection.test.ts:61-66`), not in live repo CI on every push. | +| **Closes when** | Add trusted-publish (or equivalent) workflow to default branch with OIDC/npm provenance; document in `docs/internal/release-admin-runbook.md`. | + +--- + +## Test residuals (environmental / baseline) + +### Repo naming posture (2 failures) + +| Field | Detail | +|-------|--------| +| **What** | `test/architecture/naming-posture.test.ts` fails on workspace junk and scratch paths — not authority regressions. | +| **Where** | `:54-60` — `.DS_Store` under `src/**`, `test/`, etc. (21 paths at map run); `:121-124` — `.agents`, `skills-lock.json` still on disk (`nonCanonicalScratchFiles`) | +| **Severity** | **Low** (environmental) | +| **Why open** | macOS metadata + local agent scaffold not removed; Phase 05 verification explicitly lists both as **acceptable_failures** (`05-VERIFICATION.md:10-13`). | +| **Closes when** | Delete `.DS_Store` from tree (or add to global gitignore outside test scope); remove or quarantine `.agents` / `skills-lock.json` per `planning-scratch-quarantine` policy. | + +### Manifest coverage (1 failure) + +| Field | Detail | +|-------|--------| +| **What** | `manifest coverage > maps each product surface export…` fails: `package.json missing expected export ./hosted-admission` and `./surfaces/service-workflow-admission`. | +| **Where** | `test/architecture/manifest-coverage.test.ts:143` | +| **Severity** | **Medium** (baseline debt; blocks full green `bun test`) | +| **Why open** | Same root cause as export/npm gap above. | +| **Closes when** | Add exports to `package.json` (manifest entries already exist). | + +### Release repository projection + +| Field | Detail | +|-------|--------| +| **What** | At `aef9478`, isolated test **passes** (~1.5s). Not among the three recorded failures in `05-VERIFICATION.md`. If full-suite CI times out, treat as environmental (Node spawn + temp dir), not a logic failure. | +| **Where** | `test/architecture/release-repository-projection.test.ts:10-88`; `scripts/project-release-repository.js` | +| **Severity** | **Low** (watch) | +| **Why open** | N/A unless reproduced under `npm run check:repo` timeout. | +| **Closes when** | If flaky: increase CI timeout or cache npm for projection smoke; otherwise no code change. | + +**Current architecture test tally (this pass):** `bun test` on naming + manifest + release projection → **17 pass / 3 fail** (matches verification doc modulo HEAD `aef9478` vs `6e23848`). + +--- + +## Phase 05 security — accepted MEDs (not fixed) + +Source: `.planning/phases/05-product-coherence/05-SECURITY.md` (audited `6e23848`; branch now `aef9478`). + +| ID | Severity | Status | Evidence | Closes when | +|----|----------|--------|----------|-------------| +| **F-01** | Medium | **Accepted** | Raw integrator SDK bypass — see proof gap above | D-25 integrator inventory / adoption conformance | +| **F-02** | Medium | **Accepted** | Matrix drift guard only — see proof gap above | Documentation only; do not promote to per-request gate | +| F-03 | Low | Open (optional) | `createLocalX402SandboxSigningSurface` delegates guard to official surface (`05-SECURITY.md:77-84`) | Redundant `assertGatewayHeldSigningCommand` at wrapper entry | +| F-04 | Low | Open (optional) | `src/experimental.ts:22-32` exports wallet types; unstable boundary (`05-SECURITY.md:86-93`) | Keep off `src/index.ts`; custody contract tests if promoted | +| F-05 | Low | Accepted | Test literal `"test-secret"` in fixtures (`05-SECURITY.md:95-102`) | Continue redaction tests; no repo real keys | + +--- + +## Phase 05 review — deferred MEDs (non-blocking, not fixed) + +Source: `.planning/phases/05-product-coherence/05-REVIEW.md` (SHIP-WITH-FIXES @ `e60fc87`; HR-01/MR-01 resolved). + +| ID | Severity | Status | Where | Why deferred | +|----|----------|--------|-------|--------------| +| **MR-02** | Medium | **Deferred** | `src/protocol/foundation/failure-class/index.ts:55-61`; consumers `src/sdk/surface-clients/transport.ts:76-87`, `src/sdk/client.ts:328-339` | Empty/non-JSON error bodies collapse 409 subtypes via `failureClassFromHttpStatus`; structured envelopes preserve replay vs refusal. Accepted degradation until optional `x-handshake-failure-class` header or documented intentional collapse. | +| **MR-03** | Medium | **Deferred** | `src/adapters/auth-md/gateway.ts:251-265` (cf. x402 `wallet-gateway.ts:143-187`, `:301`, `:375`) | D-64 Mechanism A structural for x402 only; auth.md lacks shared `assertGatewayHeldExecutionCommand` before I/O. Custom `AuthMdProtectedApiCallSurface` could ignore resolution evidence. Needs architecture test analogous to `x402-gateway-credential-custody.test.ts`. | +| **MR-04** | Medium | **Deferred** | `src/adapters/x402-payment/wallet-gateway.ts:332-357` | Bare `catch` maps custody/signing throws to generic `payment_signature_failed`; operators cannot distinguish custody violation from downstream signing failure without parsing message prefix. | + +**HR-01 / MR-01 (same hunk):** **Resolved** @ `e60fc87` — registry-first classification; refusal kinds no longer mislabeled as `proof_gap`. + +**Phase 05 mitigate threats (T-01–T-11):** marked **CLOSED** in security audit with code pins (wallet gateway custody, import posture, gateway invariants, agent-origin graph). Do not re-list as open unless regressions appear. + +--- + +## Phase 04 review — deferred HIGH/MED status at HEAD + +Source: `.planning/phases/04-service-agent-gating/04-REVIEW.md` (SHIP-WITH-FIXES, 2026-05-29). + +| ID | Original | At `aef9478` | Evidence | +|----|----------|--------------|----------| +| **H-01** | Policy refusals → `proof_gap` | **Largely fixed** | `src/protocol/foundation/reason-codes.ts:188-197` — `decisionPolarity: "refusal"` on `envelope_not_active`, `action_class_outside_envelope`, `prior_action_not_greenlit`, etc.; `failure-class/index.ts:79-82` honors polarity | +| **H-02** | `"proof"` substring misclassification | **Fixed** | Broad `code.includes("proof")` removed from `classifyFailureClassFromReasonCode`; metadata-driven path only (`failure-class/index.ts:139-167`) | +| **H-03** | Integrator HTTP routes ungated | **Partial** | `src/http/mutation-route-manifest.ts:1-82` + `test/architecture/http-handler-mutation-gating.test.ts:52-84` inventory first-party handlers/examples; **arbitrary integrator services still out of scope** (same as F-01/D-25) | +| **H-04** | SDK loses taxonomy on malformed body | **Partial** | `src/sdk/surface-clients/transport.ts:72-90`, `src/sdk/client.ts:324-342` — malformed body uses `failureClassFromHttpStatus` (409→refusal, 422→proof_gap); typed reason codes still lost without envelope | +| M-01 | Dual-enforcement test doc-only | **Unchanged** | `test/architecture/dual-enforcement-posture.test.ts` — prose guard only; paired with mutation manifest for structural inventory | +| M-02 | Recovery reason-code path | **Improved** | `failure-class/index.ts:85-86` — recovery uses `proofRef` option in metadata path | +| M-03 | Auth.md gateway throws plain `Error` | **Not re-verified this pass** | Still listed in 04-REVIEW; spot-check before claiming closed | +| M-04 | Install proposal plain `Error` | **Not re-verified this pass** | Still listed in 04-REVIEW | +| M-05 | Unknown errors → `internal` | **Partial** | `failure-class/index.ts:119-123` — 4xx without metadata → `protected_action_refusal`; 5xx → `internal` | + +**04-REVIEW explicit deferrals to Phase 05:** mutation manifest (shipped `05-01`), MCP registry proof gap (still open), manifest export mapping (still open), failureClass parity hardening (H-01/H-02 largely addressed). + +**Note:** No `04-SECURITY.md` artifact in `.planning/phases/04-service-agent-gating/`; security posture for Phase 04 is in `04-REVIEW.md` + Phase 05 `05-SECURITY.md`. + +--- + +## Tech debt (authority and surfaces — still relevant) + +### Boundary manifest vs new CLI handlers + +- **Issue:** Several CLI handler files are listed in `manifest-coverage.test.ts:40-57` and covered by expanded `cli.*` roots, but export/subpath drift remains the gating failure — not missing CLI roots. +- **Files:** `src/surfaces/boundary-manifest.ts`, `src/cli/command-manifest.ts`, `test/architecture/surface-boundary-posture.test.ts` +- **Impact:** New commands can ship without export-level discoverability even when manifest roots cover handlers. +- **Fix approach:** Export map + manifest export test green together. + +### A2A surfaces — product tests only + +- **Issue:** `src/surfaces/a2a-negotiation-support/` and `./surfaces/a2a-negotiation-readback` export exist in `package.json:52-56` and manifest (`manifest-coverage.test.ts:29-32`) but A2A negotiation support folder is **not** in `surfaceIds` / `expectedSurfaceIds` in older concern text — verify `boundary-manifest.ts` for `surfaces.a2a_readback` before extending. +- **Impact:** Weaker architecture posture enforcement than MCP/CLI for negotiation ingress. +- **Fix approach:** Add manifest surface IDs + `surface-boundary-posture` expected IDs for A2A support tree. + +### Product completion gates still incomplete by design + +- **Issue:** `pack:check` and product-completion projectors expect **blocked/incomplete** for host containment, live paid retry, distribution, dual-enforcement evidence unless inputs prove otherwise. +- **Files:** `src/surfaces/proof-packets/product-completion.ts:185-207` (`dual_enforcement_posture` needs `dualEnforcementPostureTestPassed` + `mutationManifestGatingTestPassed` in input); `scripts/check-product-completion.mjs` +- **Impact:** Blocked readbacks are correct; marketing must not read them as live proof. +- **Fix approach:** Feed gate JSON from passing architecture tests + real distribution readback. + +### Per-customer bypass scaffold (D-25 / D-54) + +- **Issue:** Scaffold only; blocked unless first-party dogfood customer id present. +- **Files:** `src/surfaces/proof-packets/per-customer-bypass-scaffold/index.ts:1-47` +- **Impact:** No per-customer containment claims for external integrators. +- **Fix approach:** Named dogfood evidence only; never auto-complete product completion. + +--- + +## Security considerations (ongoing) + +### Host-generated-code containment — blocked proof surface + +- **Risk:** Containment proof does not prove host-wide interception. +- **Files:** `src/surfaces/proof-packets/host-generated-code-containment.ts`, `scripts/check-host-generated-code-containment.mjs` +- **Mitigation:** `--expect-status blocked` in pack checks. +- **Recommendations:** Keep blocked until live host transcript evidence exists. + +### Hosted raw reads and scope narrowing + +- **Risk:** `hosted-record-scope` may not narrow project/workspace when payload omits those fields. +- **Files:** `src/http/handlers/hosted-record-scope.ts`, `src/http/handlers/internal-record-read.ts`, `src/http/handlers/raw-read-audit.ts` +- **Mitigation:** Fail-closed without audit sink; 404 posture. +- **Recommendations:** Object-specific redacted projections per `object-registry` types. + +### SDK repair is not recovery authority + +- **Risk:** Misuse of `explainHandshakeError` to justify retry without new contract. +- **Files:** `src/sdk/repair.ts`, `src/protocol/foundation/reason-code-remediation/index.ts` +- **Mitigation:** `authorityCreatedByRepair: false`, `requiresNewContract` from remediations. + +### Gateway custody transition_errors map to `internal` + +- **Risk:** `gateway_custody_proof_*` codes use `kind: "transition_error"` → `failureClass: "internal"` (`failure-class/index.ts:89-90`) unless `classifiedFailure` set per code (`reason-codes.ts:174-186` — no `classifiedFailure` on those lines). +- **Impact:** MCP/SDK taxonomy may show “internal” for custody mismatches (residual of 04-REVIEW H-02 class). +- **Recommendations:** Add `classifiedFailure: "protected_action_refusal"` or `"proof_gap"` per custody code in reason-code registry. + +--- + +## Fragile areas + +### Live x402 paid retry vs local/reference gateway + +- **Files:** `src/adapters/x402-payment/wallet-gateway.ts`, `src/surfaces/proof-packets/live-x402/paid-retry.ts` +- **Why fragile:** Sandbox/local posture only; live customer-gateway path not proven. +- **Test coverage:** Wallet gateway unit/architecture tests; live funded retry fixture missing. + +### One-use greenlight / storage atomicity + +- **Files:** `src/storage/d1/index.ts`, `src/storage/memory/index.ts`, `src/protocol/areas/policy-greenlight/transitions.ts` +- **Why fragile:** OCC/idempotency conflicts corrupt reconstruction if misclassified. + +### Product launch gates vs external reality + +- **Files:** `src/surfaces/product-launch-gate-resolution.ts`, `docs/internal/decisions.md` +- **Why fragile:** Narrative can outpace `resolved_blocked` distribution and registry evidence. + +--- + +## Test coverage gaps (priority) + +| Area | What's missing | Files | Risk | Priority | +|------|----------------|-------|------|----------| +| Integrator HTTP mutation inventory | Routes outside `src/http/handlers` allowlist | `src/http/mutation-route-manifest.ts`, `http-handler-mutation-gating.test.ts` | False sense of full-service gating | High | +| Export/manifest/npm parity | Published tarball export keys | `package.json`, `manifest-coverage.test.ts`, `distribution-provenance.ts` | Consumers cannot import hosted/service-workflow subpaths | High | +| MCP/registry readback | Live registry acceptance | `distribution-provenance.ts`, `product-launch-gate-resolution.ts` | False discoverability claims | High | +| Credential custody taxonomy | `gateway_custody_proof_*` failureClass | `reason-codes.ts`, `failure-class/index.ts` | Wrong retry semantics on custody failures | Medium | +| Malformed SDK HTTP body | Typed codes when envelope parse fails | `src/sdk/client.ts`, `surface-clients/transport.ts` | 04-REVIEW H-04 residual | Medium | +| Hosted raw-read matrix | All `audit_read` types under scope rules | `object-registry/index.ts`, `internal-record-read.ts` | Scope leak at tenant/org | High | +| Runtime host-wide interception | Shell/browser/MCP outside registered families | `src/runtime/ingress/`, `host-generated-code-containment` | Ingress evidence ≠ enforcement | High | + +--- + +## Missing critical features (unchanged intent) + +| Feature | Blocks | Key files | +|---------|--------|-----------| +| Customer-gateway live x402 paid retry | Live paid execution claims | `src/surfaces/proof-packets/live-x402/paid-retry.ts`, `wallet-gateway.ts` | +| Provider-grade credential custody | Hosted/live custody marketing | `src/protocol/areas/credential-custody/` | +| Host-wide generated-code containment | Whole-host bypass claims | `host-generated-code-containment.ts` | +| Hosted customer-safe readback/search | Hosted operation | `src/hosted-admission/`, `internal-record-read.ts` | +| Current-surface public distribution | Product completion / registry | `package.json`, `product-launch-gate-resolution.ts` | +| Auth.md + x402 composite execution | Composite marketing | `src/adapters/auth-md-x402-interlock/packet.ts` | + +--- + +## Source markers: TODO / FIXME / proof gap + +| Scan | Result | +|------|--------| +| `grep TODO\|FIXME\|HACK\|XXX` in `src/` | **No matches** | +| `proof gap` in `src/` | **Domain vocabulary** (protocol transitions, readbacks, launch gates) — not outstanding engineering TODOs. Examples: `src/protocol/navigation/index.ts:467`, `src/surfaces/product-launch-gate-resolution.ts:127`, `src/surfaces/a2a-negotiation-readback/index.ts:204-226`. | + +Do not treat protocol `proof_gap` record types as “missing implementation tickets” without reading the surrounding transition or readback contract. + +--- + +## Dependencies at risk + +| Dependency | Risk | Files | +|------------|------|-------| +| Cloudflare D1/KV | D1 is authority store; KV must stay cache-only | `src/storage/d1/index.ts`, `src/storage/kv/index.ts` | +| x402 SDK | Drift vs local/reference claims | `wallet-gateway.ts`, x402 proof packets | +| MCP Registry / npm | External; must not drive policy | `product-launch-gate-resolution.ts`, `distribution-provenance.ts` | + +--- + +## Scaling limits (unchanged) + +- **Runtime ingress:** Three registered families in `src/runtime/ingress/registry.ts` — each new family needs registry + tests + bypass probes. +- **Hosted operation:** Admission modules exist; hosted custody/settlement/marketplace not closed (`docs/internal/decisions.md` Hosted Admission Lock). +- **Object registry:** New protocol objects need hosted projection declarations (`src/protocol/areas/object-registry/index.ts`). --- -*Concerns audit: 2026-05-25* +*Concerns audit: 2026-05-29 @ `aef9478`* diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md index 4e6138e..40ca6d7 100644 --- a/.planning/codebase/CONVENTIONS.md +++ b/.planning/codebase/CONVENTIONS.md @@ -1,177 +1,243 @@ # Coding Conventions -**Analysis Date:** 2026-05-25 +**Analysis Date:** 2026-05-29 + +Canonical repo guidance lives in `QUALITY.md`, `STRUCTURE.md`, `AGENTS.md`, and lane manifests (`src/**/LANE.md`). This document captures enforceable patterns the executor should follow when writing or changing code. ## Naming Patterns -**Files:** -- Use kebab-case files named by owned protocol concepts: `src/protocol/areas/action-contract/transitions.ts`, `src/protocol/areas/gateway-gate/artifacts.ts`, `src/runtime/package-install/action-proposal.ts`. -- Use `index.ts` as the public face for multi-file folders. `test/architecture/naming-posture.test.ts` enforces this for source folders with more than three TypeScript files. -- Keep protocol primitives under `src/protocol/areas//`. Do not add root-level compatibility shims such as `src/protocol/policy.ts`; `test/architecture/import-posture.test.ts` asserts removed shim paths stay absent. -- Do not create bucket directories named `utils`, `helpers`, `common`, `misc`, `stuff`, `manager`, or `service` under `src/**`; `test/architecture/naming-posture.test.ts` fails on those path segments. -- Every first-level source lane needs a `LANE.md` or `README.md` with ownership fields. Existing lanes include `src/protocol/LANE.md`, `src/runtime/LANE.md`, `src/mcp/LANE.md`, `src/sdk/LANE.md`, `src/cli/LANE.md`, `src/surfaces/LANE.md`, and `src/conformance/LANE.md`. -- Tests live in domain folders under `test/`: `test/protocol/`, `test/runtime/`, `test/adapters/`, `test/http/`, `test/architecture/`, `test/mcp/`, `test/cli/`, `test/product/`, `test/conformance/`, `test/integration/`, `test/sdk/`, and `test/adapter-sdk/`. Do not add loose root `test/*.test.ts` files. - -**Functions:** -- Use camelCase for functions and methods: `proposeActionContract()` in `src/protocol/areas/action-contract/transitions.ts`, `evaluatePolicy()` in `src/protocol/areas/policy-greenlight/transitions.ts`, `gatewayCheck()` in `src/protocol/areas/gateway-gate/transitions.ts`. -- Protocol write functions should make the write explicit with verbs such as `record*`, `persist*`, `commit*`, `consume*`, `mark*`, or `activate*`. Examples include `recordCredentialResolutionEvidence()` in `src/protocol/kernel.ts` and `commitGatewayCheckPlan()` in `src/protocol/areas/gateway-gate/transitions.ts`. -- Read and derivation functions should use `get*`, `list*`, `derive*`, `build*`, `format*`, `resolve*`, or `project*`. Examples include `deriveGatewayConstraintEvaluation()` in `src/protocol/areas/gateway-gate/transitions.ts`, `buildPolicyInput()` in `src/protocol/areas/policy-greenlight/transitions.ts`, and `projectProtectedActionMetadata()` in `src/protocol/areas/protected-action-representation/projections.ts`. -- Avoid vague protocol mutation verbs such as `handle*`, `process*`, `do*`, and `run*` inside `src/protocol/**`. Runtime and adapter runner entrypoints may use `run*`, such as `runX402WalletGateway()` in `src/adapters/x402-payment/wallet-gateway.ts`. -- Avoid overclaiming function names such as `ensureSafe*`, `guarantee*`, `proveExecution*`, `trustedAgent*`, and `secureApproval*`; `test/architecture/naming-posture.test.ts` enforces this in source. +**Files and folders:** +- Name by owned concept, not generic buckets. Banned path segments under `src/**`: `utils`, `helpers`, `common`, `misc`, `stuff`, `manager`, `service` (enforced in `test/architecture/naming-posture.test.ts`). +- The `service` ban is why CLI operator code lives at `src/cli/service-operator/` (not `src/cli/service/`). Product docs use `service-operator-*` filenames (for example `docs/internal/service-operator-golden-path.md`), not internal planning tier labels. +- Protocol primitives live under `src/protocol/areas//` with focused filenames (`transitions.ts`, `schemas.ts`, `inputs.ts`, `index.ts`). +- Product and transport lanes mirror ownership: `src/http/`, `src/cli/`, `src/mcp/`, `src/surfaces/`, `src/adapters//`. +- Every first-level `src/` lane must ship `LANE.md` or `README.md` with the manifest fields listed in `QUALITY.md` / `STRUCTURE.md` (validated by `test/architecture/import-posture.test.ts`). -**Variables:** -- Use camelCase for local variables and object members. Use precise suffixes for authority-bearing refs and digests: `actionContractId`, `greenlightId`, `candidateDigest`, `gatewayRegistryDigest`, `policyInputDigest`. -- Use uppercase constants for version and fixed-registry values: `PROTOCOL_VERSION` in `src/protocol/foundation/schema-core.ts`, `CANONICALIZER_VERSION` in `src/protocol/foundation/canonical.ts`, and `MAX_STREAM_COMMIT_RETRIES` in `src/protocol/areas/gateway-gate/transitions.ts`. -- Use explicit non-authority booleans on projection and surface outputs: `authorityCreated`, `greenlightCreated`, `gatewayCheckPerformed`, `mutationAttempted`, `rawInternalRecordIncluded`, `credentialMaterialIncluded`, `receiptExportCreated`, and `authorityCertificateMinted`. +**Banned planning labels (repo-facing surfaces):** +- Internal planning-stage vocabulary must not appear in repo-facing paths, scripts, CI names, README, canonical docs, exported symbols, or test titles. +- Specifically forbidden in repo-facing files (see `test/architecture/naming-posture.test.ts`): `Tier 1`–`Tier 4`, `tier1`, `tier doctrine`, and similar stage labels. +- Use product/protocol nouns instead — for example `integrator-parity` (`test/architecture/integrator-parity.test.ts`, `docs/internal/integrator-parity-transitions.md`) rather than legacy tier numbering. +- Repo-facing roots scanned: `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, `docs/internal`, `examples`, `package.json`, `.github`, `src`, `test`. -**Types:** -- Use PascalCase for TypeScript types and classes: `HandshakeKernel` in `src/protocol/kernel.ts`, `ActionContract` in `src/protocol/areas/action-contract/schemas.ts`, `GatewayCheckResult` in `src/protocol/areas/gateway-gate/artifacts.ts`. -- Pair Zod schemas with inferred types using the `FooSchema` / `type Foo = z.infer` pattern. Examples: `ActionContractSchema` and `ActionContract` in `src/protocol/areas/action-contract/schemas.ts`; `GatewayCheckAttemptSchema` and `GatewayCheckAttempt` in `src/protocol/areas/gateway-gate/schemas.ts`. -- Public transition inputs use named input schemas: `ProposeActionContractInputSchema`, `EvaluatePolicyInputSchema`, `GatewayCheckInputSchema`, `CreateRuntimeExecutionInputSchema`. -- Literal registries use readonly arrays with `as const`, then derive union types from them. Examples: `surfaceIds`, `surfaceRouteFamilies`, and `surfaceAuthorityPostures` in `src/surfaces/boundary-manifest.ts`. +**Functions (protocol modules):** +- Durable writes: `record*`, `persist*`, `commit*`, `consume*`, `mark*`, `activate*`. -## Code Style +```typescript +// src/protocol/areas/negotiation/transitions.ts +export async function recordNegotiationSession(/* ... */) { /* ... */ } +export async function recordA2AIngressCheckpoint(/* ... */) { /* ... */ } +``` -**Formatting:** -- Use Prettier from `.prettierrc.json`: `printWidth: 120`, semicolons enabled, double quotes, trailing commas. -- Use `.editorconfig`: UTF-8, LF endings, two-space indentation, final newline, trimmed trailing whitespace except Markdown. -- TypeScript is strict. `tsconfig.json` enables `strict`, `noUncheckedIndexedAccess`, and `exactOptionalPropertyTypes`. Treat optional values and array indexing as explicit proof obligations. - -**Linting:** -- ESLint config is `eslint.config.js` with `typescript-eslint` recommended rules. -- Use type-only imports where possible; `@typescript-eslint/consistent-type-imports` is an error and uses separate type imports. -- Unused variables are errors unless prefixed with `_`. -- `console` is an error except `console.warn` and `console.error`; use structured protocol records, receipts, refusals, proof gaps, or CLI JSON instead of incidental logs. - -**Quality gates:** -- Full closeout gate: `npm run check:repo`. -- Focused claim gate: `npm run quality:claims`. -- Focused architecture gate: `npm run quality:architecture`. -- Focused storage/kernel gate: `npm run quality:storage`. -- Package gate: `npm run pack:check`. -- Base local checks: `npm run check:types`, `npm run lint`, `npm run format:check`, `npm run test`, and `git diff --check`. +- Reads and derivations: `get*`, `list*`, `derive*`, `build*`, `format*`, `resolve*`. +- Avoid vague mutation names in protocol code: `handle*`, `process*`, `do*`, `run*` (runtime public runner entrypoints may use `run*` when they are explicit runners, e.g. `runX402WalletGateway` in `src/adapters/x402-payment/wallet-gateway.ts`). +- Avoid overclaiming names: `ensureSafe*`, `guarantee*`, `proveExecution*`, `trustedAgent*`, `secureApproval*`. -## Import Organization +**Types and protocol objects:** +- Use exact protocol nouns: `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheck`, `Receipt`, `Refusal`, `ProofGap`, `IsolationState`. +- Export result types beside transition functions: -**Order:** -1. External packages and Node builtins: `zod`, `bun:test`, `node:fs`, `node:path`, `@x402/*`. -2. Source value imports from the nearest owning module or public index. -3. Source type imports using `import type`. -4. Test support imports from `test/support/*`. +```typescript +// src/protocol/areas/operation-lifecycle/transitions.ts +export type SurfaceOperationReconciliationResult = { + reconciliation: SurfaceOperationReconciliation; + resolvedProofGaps: ProofGap[]; + createdProofGap: ProofGap | null; +}; +``` -**Path Aliases:** -- No TypeScript path aliases are configured in `tsconfig.json`. Use relative imports. -- Protocol modules should import other protocol areas through public area indexes where possible, such as `../policy-greenlight` rather than internal transition files. `test/architecture/import-posture.test.ts` enforces public-index imports between protocol areas. +**Variables:** +- Prefer descriptive protocol IDs (`actionContractId`, `greenlightId`, `mutationAttemptId`) over abbreviations. +- Prefix intentionally unused bindings with `_` to satisfy ESLint (`argsIgnorePattern`, `varsIgnorePattern` in `eslint.config.js`). -**Layer constraints:** -- `src/protocol/**` must not import `src/http/**`, `src/storage/**`, `src/runtime/**`, `src/sdk/**`, or adapter fixtures. Use the `ProtocolStore` port in `src/protocol/store/port.ts`. -- `src/http/**` owns transport, route metadata, handlers, errors, admission, and store resolution; it must not define protocol meaning. `test/architecture/import-posture.test.ts` keeps route registry metadata separate from invokers and response schemas. -- `src/runtime/**` is proposal-only. `test/architecture/import-posture.test.ts` checks `src/runtime/ingress/registry.ts` for `authorityPosture: "proposal_only"`, `compileInputAuthority: "candidate_only"`, and `rawBypassPosture: "bypass_evidence_only"`. -- `src/mcp/**` is proposal/evidence only. `test/architecture/mcp-surface-posture.test.ts` forbids imports of `protocol/kernel`, policy/gateway internals, adapters, storage, experimental surfaces, and `sdk/client`. -- Official x402 signer and paid-client imports are allowed only in `src/adapters/x402-payment/wallet-gateway.ts`; `test/architecture/import-posture.test.ts` forbids `@x402/core/client`, `@x402/fetch`, `@x402/axios`, and `@x402/evm*` elsewhere in `src/**`. +**Tests:** +- Mirror source ownership in path: `test/protocol/kernel-operation-lifecycle.test.ts`, `test/product/service-operator-bootstrap.test.ts`. +- Describe blocks name the guarded boundary, not the file: -## Error Handling +```typescript +describe("repo naming posture", () => { /* ... */ }); +describe("planning scratch quarantine", () => { /* ... */ }); +describe("Handshake kernel invariants: operation lifecycle", () => { /* ... */ }); +``` -**Patterns:** -- Validate public transition inputs with Zod at the boundary. Examples: `ProposeActionContractInputSchema.parse()` in `src/protocol/areas/action-contract/transitions.ts`, `EvaluatePolicyInputSchema.parse()` in `src/protocol/areas/policy-greenlight/transitions.ts`, and `GatewayCheckInputSchema.parse()` in `src/protocol/areas/gateway-gate/transitions.ts`. -- Throw `HandshakeProtocolError` from `src/protocol/foundation/errors.ts` with stable `code`, message, HTTP-like `status`, and optional metadata for retryability, commit state, proof refs, and refusal refs. -- Use `HandshakeAmbiguousCommitError` for ambiguous transition commits; it sets retryability to `ambiguous` and commit state to `unknown`. -- HTTP error responses go through `transitionErrorResult()` and `TransitionErrorResponseSchema` in `src/http/errors/transition-error-envelope.ts`. Do not return ad hoc error JSON from handlers. -- Record refusals and proof gaps instead of smoothing missing evidence. `test/protocol/kernel-policy-gateway.test.ts`, `test/protocol/evidence-projections.test.ts`, and `test/adapters/x402-wallet-gateway.test.ts` assert refusal/proof-gap outcomes at the authority boundary. -- Test helpers may throw plain `Error` for impossible fixture states, such as `requireCandidateDigest()` in `test/support/fixtures.ts`. Production protocol code should prefer typed `HandshakeProtocolError`. +## Module And Directory Layout -## Logging +**Directory + `index.ts` posture (not loose files):** +- A source folder with more than three `.ts` files (excluding `index.ts`) must expose an `index.ts` public face. +- A source folder must not exceed seven loose `.ts` files (excluding `index.ts`). +- Area modules stay under `src/protocol/areas/*`; foundation helpers use directory modules such as `src/protocol/foundation/failure-class/index.ts` (not a loose `failure-class.ts` at the foundation root). +- Protocol area folders use `transitions.ts`, `schemas.ts`, `inputs.ts`, `guards.ts`, and `index.ts` as the standard layout. -**Framework:** console is restricted by `eslint.config.js`. +**First-level `src/` lanes with `LANE.md` (authority boundary files):** +- `src/adapters/LANE.md` +- `src/adapter-sdk/LANE.md` +- `src/cli/LANE.md` +- `src/conformance/LANE.md` +- `src/hosted-admission/LANE.md` +- `src/http/LANE.md` +- `src/install/LANE.md` +- `src/mcp/LANE.md` +- `src/protocol/LANE.md` +- `src/runtime/LANE.md` +- `src/sdk/LANE.md` +- `src/storage/LANE.md` +- `src/surfaces/LANE.md` +- `src/x402-protected-tool/LANE.md` -**Patterns:** -- Do not use logs as protocol evidence. Durable evidence lives in protocol records, stream events, receipts, refusals, proof gaps, and redacted projections. -- CLI and surface outputs must carry explicit non-authority flags. `test/architecture/cli-command-posture.test.ts` requires every CLI JSON output to include fields such as `authorityCreated`, `greenlightCreated`, `gatewayCheckPerformed`, and `mutationAttempted`. -- Surface helpers should return schema-validated objects. `surfaceOutcomeBase()` in `src/surfaces/outcome.ts` always sets authority-related fields to `false` or `null`. +Each manifest must include all fourteen required `##` sections listed in `STRUCTURE.md` (Authority owner through Scope boundary). -## Comments +## `.planning/` Scratch Quarantine -**When to Comment:** -- Prefer schemas, precise names, `LANE.md` files, and tests over explanatory comments. -- Add comments only when a complex transition or evidence boundary is not obvious from function names and types. -- Use lane manifests for durable ownership notes. Each first-level `src/*/LANE.md` states authority owner, proof claim, use cases, constraints, allowed imports, forbidden imports, guarding tests, and scope boundary. +**Rule:** Files under `.planning/` are scratch. They must not leak into repo-facing source paths, `package.json` scripts, CI workflow names, exported symbols, or canonical docs (`AGENTS.md` line 221; `STRUCTURE.md`). -**JSDoc/TSDoc:** -- Not broadly used. Do not introduce large docblocks as a substitute for typed schemas or tests. -- Public behavior should be encoded in `src/protocol/public/*`, package exports in `src/index.ts`, package subpaths in `package.json`, and executable tests under `test/**`. +**Enforced markers (D-62)** — must not appear in `src/`, `test/`, `docs/`, `README.md`, or `package.json` scripts (`test/architecture/planning-scratch-quarantine.test.ts`): +- `.planning/macro-plan` +- `.planning/macro/concierge` +- `concierge-demand-test-scaffold` -## Function Design +**Also quarantined from active canon** (naming posture): +- `Agent-Founder.md` +- `.agents` skill bundles +- `skills-lock.json` + +When `.planning/codebase/*` informs work, tracked source, canonical docs, and passing tests win on factual disagreements (`STRUCTURE.md`). -**Size:** Transition functions may orchestrate several steps, but keep phase helpers small and named by their role. The dominant pattern is parse -> load context -> derive constraints -> build plan -> commit plan -> return typed response. +## Surfaces Must Not Create Authority -**Parameters:** Public and protocol transition functions should take one object input type, not positional argument clusters. Examples include `EvaluatePolicyInput`, `GatewayCheckInput`, `CreateRuntimeExecutionInput`, and `ProposeActionContractInput`. +Product surfaces (CLI, MCP, SDK readbacks, `src/surfaces/*`) expose proposal, evidence, and readback only. They must not create policy decisions, greenlights, gateway checks, mutation attempts, or certificates. -**Return Values:** Return schema-shaped records or explicit outcome objects. Authority-bearing responses must distinguish policy decisions, one-use greenlights, gateway checks, mutation attempts, refusals, receipts, and proof gaps. +**Manifest contract:** `src/surfaces/boundary-manifest.ts` defines `surfaceNonAuthorityFlags` and per-surface `requiredNonAuthorityFlags`. Every model-facing and operator-facing surface must require all flags to be `false`: -**Transition pattern:** ```typescript -export async function evaluatePolicy( - store: ProtocolStore, - recorder: ProtocolRecorder, - inputValue: EvaluatePolicyInput, -): Promise { - const input = EvaluatePolicyInputSchema.parse(inputValue); - const context = await getPolicyEvaluationContext(recorder, input); - assertTransition(guardPolicyEvaluation(context.contract, context.envelope)); - const constraints = await derivePolicyConstraintEvaluation(store, context); - // build, commit, then return explicit authority/non-authority posture -} +export const surfaceNonAuthorityFlags = [ + "authorityCreated", + "credentialMaterialIncluded", + "gatewayCheckPerformed", + "greenlightCreated", + "mutationAttempted", + "mutationCommandIncluded", + "rawInternalRecordIncluded", + "receiptExportCreated", + "authorityCertificateMinted", +] as const; ``` -Use this shape when adding new kernel transitions under `src/protocol/areas/*`. +**Guarding tests:** +- `test/architecture/surface-boundary-posture.test.ts` — manifest completeness, forbidden authority route families, required non-authority flags, forbidden credential/output shapes. +- `test/architecture/negotiation-no-authority-surface.test.ts` — negotiation area does not import protected-action control areas; only `record*` transitions exported. +- `test/architecture/cli-non-authority-copy.test.ts` — CLI copy must not imply authority (D-60). +- `test/architecture/claim-boundary.test.ts` — canonical docs must state projection/readback "without creating authority". -## Module Design +**Product test assertion pattern:** -**Exports:** -- Keep package root exports curated in `src/index.ts`. `test/architecture/root-exports.test.ts` asserts the exact root export list and keeps internals such as `HandshakeKernel`, `ProtocolRecorder`, `InMemoryProtocolStore`, and `D1ProtocolStore` off the root surface. -- Public subpaths are declared in `package.json`: `.`, `./conformance`, `./adapter-sdk`, `./runtime`, `./sdk/role-clients`, `./cli`, `./mcp`, `./x402-protected-tool`, and `./experimental`. -- Adapter authoring helpers belong on `src/adapter-sdk/index.ts`; runtime ingress belongs on `src/runtime/index.ts`; conformance checks belong on `src/conformance/index.ts`. +```typescript +expect(output).toMatchObject({ + authorityCreated: false, + greenlightCreated: false, + gatewayCheckPerformed: false, + mutationAttempted: false, + rawInternalRecordIncluded: false, + credentialMaterialIncluded: false, +}); +``` -**Barrel Files:** -- Use local `index.ts` files as intentional public faces, not dumping grounds. -- `src/protocol/public/schemas.ts` and `src/protocol/public/inputs.ts` are aggregators only; `test/architecture/import-posture.test.ts` fails if they contain lines other than `export * from ...`. -- Area `types.ts` files are local-only faces. `test/architecture/import-posture.test.ts` restricts them to allowed schema/input exports. +Role-scoped SDK policy/gateway clients are policy transition transport — not product authority surfaces (`surface-boundary-posture.test.ts` distinguishes `sdk.policy`). -## Authority-Language Rules +## Code Style -Use the exact product/protocol vocabulary from `QUALITY.md`, `STRUCTURE.md`, `AGENTS.md`, `docs/internal/decisions.md`, and `docs/internal/protocol-notes.md`. +**Formatting (Prettier — `.prettierrc.json`):** +- `printWidth`: 120 +- `semi`: true +- `singleQuote`: false (double quotes) +- `trailingComma`: `"all"` -- Say `protected actions for automated decision making`, not engineering-agent-only category language. -- Say `cleared protected-action event` for one terminal event with reconstructable evidence. -- Say `protocol kernel` for source-owned state machine and schemas. -- Say `product surface` for CLI, MCP, SDK, docs, demo, or readback surfaces that expose proposal/evidence/readback without creating authority. -- Say `AuthorityCertificate` is terminal evidence, not permission, identity, settlement, hosted trust, or reusable auth. -- Say public npm availability and MCP Registry discoverability are distribution facts, not authority. -- Say missing provider custody, hosted operation, settlement/finality, aggregate spend, host-wide containment, and broad x402 compatibility are proof gaps, outside claims, or cut lines until source and gates change. +Run `npm run format:check` in CI; `npm run format` to fix locally. -The claim-boundary gate is executable in `test/architecture/claim-boundary.test.ts`; update that test when simplifying canonical language so the simplification keeps the invariant rather than weakening it. +**TypeScript (`tsconfig.json`):** +- Target ES2022, module ESNext, `moduleResolution`: `"Bundler"`. +- Strict mode with `noUncheckedIndexedAccess: true` and `exactOptionalPropertyTypes: true`. +- Types from `@cloudflare/workers-types` and `bun-types`. +- Build declarations via `tsconfig.build.json` (`rootDir`: `src`, `emitDeclarationOnly`). -## Projection Vs Authority +**Linting (`eslint.config.js`):** +- Scope: `src/**/*.ts`, `test/**/*.ts`; ignores `dist/`, `coverage/`, `node_modules/`, `docs/internal/archive/**`. +- Extends `typescript-eslint` recommended. +- Key rules: + - `@typescript-eslint/consistent-type-imports`: `"prefer": "type-imports"`, `"fixStyle": "separate-type-imports"`. + - `@typescript-eslint/no-unused-vars` with `^_` ignore patterns. + - `no-console`: error except `console.warn` and `console.error`. -Projection code must expose readback without becoming authority. +Run `npm run lint` (`--max-warnings=0`). Zero warnings is required for closeout. + +## Import Organization -- Projection helpers use `project*` names and return non-authority fields. Examples: `projectProtectedActionMetadata()` and `projectProtectedActionChallengeFromRefusal()` in `src/protocol/areas/protected-action-representation/projections.ts`. -- Surface outputs in `src/surfaces/outcome.ts` set `authorityCreated`, `greenlightCreated`, `gatewayCheckPerformed`, `mutationAttempted`, `credentialMaterialIncluded`, `rawInternalRecordIncluded`, `receiptExportCreated`, and `authorityCertificateMinted` to `false`. -- `src/surfaces/boundary-manifest.ts` declares `authorityPosture`, `allowedRouteFamilies`, `forbiddenRouteFamilies`, forbidden credential shapes, forbidden output fields, and claim-boundary labels for each product surface. -- `test/architecture/surface-boundary-posture.test.ts`, `test/architecture/cli-command-posture.test.ts`, and `test/architecture/mcp-surface-posture.test.ts` enforce that SDK, CLI, MCP, and x402 protected-tool surfaces do not import or expose authority internals. +**Order (observed pattern):** +1. Test/runtime imports (`bun:test`, Node built-ins). +2. Value imports from `src/` (kernel, adapters, surfaces). +3. Separate `import type { ... }` lines for types only. -Do not simplify kernel language by merging projection, evidence, policy, gateway, and mutation terms. Use shorter words only when the state boundary remains explicit. +**Path style:** +- Use relative paths from the importing file (`../../src/...`, `../support/...`). No path aliases in `tsconfig.json`. +- Import protocol meaning through public faces (`src/protocol/public/schemas`, `src/protocol/public/inputs`) from transport, SDK, and product code — not through deep `src/protocol/areas/*` internals (guarded by `test/architecture/import-posture.test.ts`). -## Simplification Rules +**Barrel files:** +- Folders with more than three `.ts` files (excluding `index.ts`) must expose an `index.ts` public face. +- Curated package exports live in `src/index.ts` and `package.json` `exports`; do not re-export internal kernel/store objects at root (`test/architecture/root-exports.test.ts`). + +## Error Handling + +**Protocol errors:** +- Throw `HandshakeProtocolError` from `src/protocol/foundation/errors` for invariant violations. +- Classify transport-facing failures through `src/protocol/foundation/failure-class/index.ts` (`FailureClassSchema`: `auth`, `hosted_admission`, `protected_action_refusal`, `proof_gap`, `replay_refusal`, `stale_admission`, `internal`). +- Parse inputs with Zod schemas at transition boundaries. + +**HTTP/SDK:** +- Map protocol errors to typed HTTP envelopes via `src/http/errors/transition-error-envelope.ts`. +- SDK clients surface structured rejections; tests use `rejects.toMatchObject` / `rejects.toThrow`. + +**Fail closed:** +- Missing custody, schema invalidity, and isolation blocks must refuse — never silently succeed. + +## Logging + +**Framework:** No unstructured logging in `src/` — ESLint blocks `console.log` / `console.info` / `console.debug`. + +**Allowed:** `console.warn` and `console.error` only where explicitly needed (typically CLI or scripts outside the linted kernel tree). + +**Evidence over logs:** Prefer recorded `ProofGap`, `Refusal`, and receipt timeline evidence over log lines for reconstructability. + +## Comments + +**When to comment:** +- Lane manifests (`LANE.md`) carry design intent, import posture, and guarding tests — prefer updating the manifest over inline essays. +- Inline comments only for non-obvious invariant rationale (e.g., why telemetry must not create authority). + +**JSDoc/TSDoc:** +- Sparse; types and schema names are the primary documentation. + +## Function Design + +**Size:** +- Transition functions orchestrate guard → plan → commit; keep helper types file-local when they clarify commit phases. + +**Parameters:** +- Pass explicit IDs and digests; avoid passing loose `Record` at protocol boundaries. +- Use `satisfies` for fixture constants that must conform to auth or schema types. + +**Return values:** +- Transition functions return structured result objects with both primary record and side effects (`resolvedProofGaps`, `createdProofGap`). +- CLI/MCP commands return envelope objects with authority boundary fields and `reasonCodes`. + +## Module Design -When simplifying confusing kernel language: +**Exports:** +- Each lane's `index.ts` re-exports the public surface declared in its `LANE.md`. +- Package subpaths match `package.json` `exports` — do not add root exports without updating `test/architecture/root-exports.test.ts` and `test/architecture/claim-boundary.test.ts`. -- Preserve the chain: exact contract -> policy decision -> one-use greenlight or refusal -> gateway check -> receipt/refusal/proof gap. -- Prefer shorter nouns already accepted in `QUALITY.md`: `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheck`, `Receipt`, `Refusal`, `ProofGap`, and `IsolationState`. -- Do not rename a projection to imply enforcement. A `project*` function cannot evaluate policy, create a greenlight, perform a gateway check, mutate, or mint terminal evidence. -- Do not remove non-claim fields from public outputs; they are part of the boundary contract. -- Update canonical docs and their tests together: `QUALITY.md`, `STRUCTURE.md`, `docs/internal/decisions.md`, `docs/internal/protocol-notes.md`, `test/architecture/claim-boundary.test.ts`, `test/architecture/active-vocabulary.test.ts`, and `test/architecture/naming-posture.test.ts`. +**Forbidden patterns:** +- Generic bucket directories under `src/`. +- Internal planning labels in repo-facing scripts, README, CI names, or test titles. +- Compatibility shims listed as removed in `test/architecture/import-posture.test.ts` (e.g. `src/protocol/policy.ts`). --- -*Convention analysis: 2026-05-25* +*Convention analysis: 2026-05-29* diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md index 6ff8698..a77ac86 100644 --- a/.planning/codebase/INTEGRATIONS.md +++ b/.planning/codebase/INTEGRATIONS.md @@ -1,246 +1,170 @@ # External Integrations -**Analysis Date:** 2026-05-25 - -## Integration Boundary Summary - -Handshake currently integrates with external rails as evidence, proposal, transport, storage, and distribution surfaces. Those surfaces do not become authority by existing. - -**Current enforcement boundary:** -- `src/protocol/areas/action-contract/` binds one exact proposed protected action. -- `src/protocol/areas/policy-greenlight/` evaluates one exact contract and may issue one-use `Greenlight` evidence. -- `src/protocol/areas/gateway-gate/` verifies exact greenlight binding before mutation. -- Mutation-capable adapter fixtures under `src/adapters/` run only after `VerifiedGatewayCheck`. -- Receipts, refusals, replay refusals, proof gaps, and terminal certificates are terminal evidence, not permission. - -**Simplification mapping:** -- "Passport" is not an integration in the current codebase. External identity is carried as evidence-only `participantIdentityBindings` on `OperatingEnvelopeSchema` and `ActionContractSchema` in `src/protocol/areas/catalog-envelope/schemas.ts` and `src/protocol/areas/action-contract/schemas.ts`. -- "Admission" is HTTP transition/read custody in `src/http/admission/`. It gates who can write or read protocol records, not who may mutate a protected surface. -- "Service gateway" is the combination of `GatewayRegistryEntry`, `GatewayCredentialRef`, gateway custody proof, role-scoped `GatewayClient`, and the `gatewayCheck` transition. Source files: `src/protocol/areas/catalog-envelope/schemas.ts`, `src/protocol/areas/credential-custody/schemas.ts`, `src/sdk/surface-clients/gateway-client.ts`, and `src/protocol/areas/gateway-gate/`. -- "Principal-agent link" is protocol evidence on `OperatingEnvelope`, `DelegatedAuthorityRef`, runtime/candidate records, and exact `ActionContract`. It is not reusable auth and does not skip policy or gateway checks. +**Analysis Date:** 2026-05-29 ## APIs & External Services -**Cloudflare Worker Runtime:** -- Cloudflare Workers - Hosts the Hono protocol app. - - SDK/Client: `wrangler` ^4.92.0 and `@cloudflare/workers-types` ^4.20260517.1 in `package.json`. - - Implementation: `src/worker.ts`, `src/http/app.ts`, and `src/http/app-options.ts`. - - Auth: Local bearer role tokens in `src/http/admission/caller-auth.ts`; hosted caller verifier interface in `src/http/admission/hosted-caller-identity.ts`. - - Config: `wrangler.toml` declares Worker name `handshake-protocol-kernel`, D1 binding `DB`, and KV binding `CACHE`. - -**x402 Payment Protocol:** -- x402 exact buyer-side payment rail - First official protected-action wedge is one buyer-side `x402_payment.exact` per-call path. - - SDK/Client: `@x402/core` 2.12.0, `@x402/evm` 2.12.0, and dev/test `@x402/fetch` 2.12.0 in `package.json`. - - Implementation: `src/adapters/x402-payment/upstream-evidence.ts`, `src/adapters/x402-payment/install-proposal.ts`, `src/adapters/x402-payment/action-proposal.ts`, `src/adapters/x402-payment/wallet-gateway.ts`, `src/adapters/x402-payment/protected-tool-readiness/`, `src/adapters/x402-payment/protected-tool-facade/`, and `src/x402-protected-tool/index.ts`. - - Auth: No raw x402 secret env var is read by source. Signing is injected through `ClientEvmSigner` into the gateway-held signing surface in `src/adapters/x402-payment/wallet-gateway.ts`. - - Authority boundary: `PaymentPayload` and `PAYMENT-SIGNATURE` creation occur only inside the gateway signing surface after `verifiedGatewayCheckFromResult()` returns a `VerifiedGatewayCheck`. - - Current non-claims: no facilitator operation, seller middleware, settlement finality, broad x402 compatibility, provider custody, live hosted payment management, or aggregate spend-window enforcement. - -**MCP Local Stdio:** -- Model Context Protocol - Local proposal/evidence server for model-facing x402 protected action candidates. - - SDK/Client: `@modelcontextprotocol/server` and `@modelcontextprotocol/client` 2.0.0-alpha.2 in `package.json`. - - Server: `src/mcp/stdio/server.ts` and `src/mcp/stdio/entry.ts`. - - Registry metadata: `server.json`. - - Tool: `handshake.actions.x402_payment.propose` in `src/mcp/catalog.ts`. - - Resources: `handshake://metadata/*`, `handshake://challenges/*`, `handshake://evidence/*`, `handshake://health/*`, and `handshake://certificates/*` in `src/mcp/resources.ts`. - - Auth: MCP is not an enforcement auth boundary. It bridges to runtime proposal and redacted evidence only. - -**npm And MCP Registry Distribution:** -- npm package registry - Distribution target for `handshake-protocol-kernel@0.2.7`. - - Package metadata: `package.json`. - - Package allowlist: `package.json#files`. - - Package checks: `scripts/check-package-surface.mjs`, `scripts/check-published-entrypoints.mjs`, `scripts/check-clean-installed-activation.mjs`, and `scripts/check-release-proof.mjs`. - - Auth: npm publish credentials are external to the repo. `.npmrc` was not read. - - Boundary: Publication is distribution evidence only. It does not create protocol authority. -- MCP Registry - Discoverability metadata for the local stdio MCP package. - - Config: `server.json` uses schema `https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json`. - - Package: npm/stdio entry points to `handshake-protocol-kernel` version `0.2.7`. - - Boundary: Registry acceptance and lookup are distribution facts only. - -**auth.md / OAuth Metadata Profiles:** -- auth.md profile lane - Models credential discovery, registration provenance, lifecycle evidence, protected API-call contracts, and auth.md/x402 interlock packets. - - SDK/Client: No external provider SDK detected. - - Implementation: `src/adapters/auth-md/profiles.ts`, `src/adapters/auth-md/action-proposal.ts`, `src/adapters/auth-md/gateway.ts`, `src/adapters/auth-md/revocation.ts`, `src/adapters/auth-md/bypass-probes.ts`, and `src/adapters/auth-md-x402-interlock/packet.ts`. - - Auth: Issued credential material is represented only as gateway custody evidence and `GatewayCredentialRef` inputs; raw credential material is rejected/redacted by auth.md schemas. - - Boundary: auth.md metadata and credential issuance are provenance. They are not protected-action authority, an OAuth server, an identity provider, a service gateway, or a WorkOS-style managed auth product. - -**Agent Host Profiles:** -- Host activation artifacts - Bind x402 protected-tool readiness to host-specific tool/profile descriptors. - - Codex local: `src/adapters/x402-payment/protected-tool-profile/codex-activation.ts`. - - Claude Code managed MCP: `src/adapters/x402-payment/protected-tool-profile/claude-code-activation.ts`. - - Hermes tool packet: `src/adapters/x402-payment/protected-tool-profile/hermes-activation.ts`. - - OpenClaw tool packet: `src/adapters/x402-payment/protected-tool-profile/openclaw-activation.ts`. - - Generic MCP stdio: `src/adapters/x402-payment/protected-tool-profile/generic-mcp-activation.ts`. - - Public subpath: `src/x402-protected-tool/index.ts`. - - Boundary: Host profiles can prepare activation/readiness artifacts and raw sibling posture evidence. They do not mutate host config by default, certify native hosts, contain host-wide bypass, invoke signers, or perform gateway checks. - -**HTTP Client Surfaces:** -- Handshake HTTP SDK - Typed client for protocol transition and evidence routes. - - Low-level client: `src/sdk/client.ts`. - - Role-scoped clients: `src/sdk/surface-clients/`. - - Auth: Bearer role credentials are supplied through `HandshakeClientOptions` in `src/sdk/client.ts` or one role credential in `src/sdk/surface-clients/transport.ts`. - - Boundary: SDK clients send requests and parse responses. They do not infer authority from evidence reads or command success. - -**CI Service:** -- GitHub Actions - Runs the repository quality gate. - - Config: `.github/workflows/check.yml`. - - Auth: Not detected in source. - - Commands: `bun install --frozen-lockfile`, then `npm run check:repo`. +**x402 payment (first product wedge):** +- Protocol: x402 v2 with `exact` scheme only for the live wedge (`src/surfaces/proof-packets/live-x402-requirement.ts`, `src/adapters/x402-payment/wallet-gateway.ts`). +- SDK: `@x402/core` (schemas, HTTP client), `@x402/evm` (EVM exact client signer hook). +- Usage: parse 402 PAYMENT-REQUIRED, bind selected requirement to action contract, run gateway check before signer invocation; live readback proofs in `src/surfaces/proof-packets/live-x402/` and gate scripts `scripts/check-live-x402-paid-retry.mjs`, `scripts/check-live-x402-proof.mjs`. +- **Gateway-held custody (D-64):** `assertGatewayHeldSigningCommand()` in `src/adapters/x402-payment/wallet-gateway.ts` refuses signing unless the command carries a passed `VerifiedGatewayCheck` and gate-bound credential resolution evidence with `credentialMaterialPosture: "gateway_held_redacted"`. Caller-only paths holding a raw `gatewayCredentialRefId` cannot reach `signPayment`. +- Auth: customer gateway custody is evidence-only in proofs; live credentials are never persisted by Handshake surfaces. + +**Model Context Protocol (local product surface):** +- Registry metadata: `server.json` (schema `https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json`, version `0.2.7`). +- Transport: stdio via npm package `handshake-protocol-kernel` / bins `handshake-mcp`, `handshake-protocol-kernel`. +- Implementation: `src/mcp/stdio/server.ts`, entry `src/mcp/stdio/entry.ts` → bundled `dist/bin/handshake-mcp.mjs`. +- Tool surface: `handshake.actions.x402_payment.propose` and read-only resources (`src/mcp/catalog.ts`, `src/mcp/resources.ts`). +- Client proof: `handshake mcp doctor --stdio` uses `@modelcontextprotocol/client` (`src/mcp/stdio/process-proof.ts`). +- **MCP Registry discoverability: proof gap** — `server.json` and `package.json#mcpName` are distribution facts only; registry acceptance and lookup are not verified (`docs/internal/decisions.md` D-244; `scripts/check-release-proof.mjs` asserts decision text references registry acceptance as a release gate, not as completed proof). +- Auth: no hosted MCP authority; proposal/evidence only per product doctrine. + +**Hosted identity (adapter contract module):** +- Canonical module: `src/hosted-admission/` (`index.ts`, `LANE.md`). +- Provider kinds: `clerk`, `oauth_oidc`, `cloudflare_access`, `custom_jwt`, `service_credential`, `test_fixture`, `other` (`src/hosted-admission/hosted-caller-identity.ts`). +- Integration pattern: implement `HostedVerifierAdapter` in `src/hosted-admission/hosted-verifier-adapter.ts`; HTTP layer re-exports via thin shims in `src/http/admission/hosted-*.ts` (guarded by `test/architecture/hosted-admission-reexport-only.test.ts`). +- HTTP wiring: `authMode: "hosted"` on `createApp()` options (`src/http/app-options.ts`); hosted readiness handler `src/http/handlers/hosted-readiness.ts`. +- **Package export status:** `src/hosted-admission/LANE.md` documents target subpath `handshake-protocol-kernel/hosted-admission`, and `test/architecture/manifest-coverage.test.ts` expects `./hosted-admission` in `package.json#exports`, but that subpath is **not present** in current `package.json` and is not bundled in `scripts/build-package-bundles.mjs` — integrators currently consume hosted admission via HTTP app options and HTTP re-export types on the package root, not a dedicated npm subpath. +- Auth: redacted caller identity evidence only; provider sessions, raw claims persistence, and org/workspace IDs do not authorize protected actions. + +**Integrator parity HTTP/SDK surface:** +- Bounded transition set for service integrators: `integratorParityTransitionIds` in `src/protocol/navigation/index.ts` (11 transitions tagged `integratorParity: true`). +- Documented in `docs/internal/integrator-parity-transitions.md`; validated by `test/architecture/integrator-parity.test.ts` (HTTP route role/path parity with protocol navigation). +- SDK walkthrough: `test/sdk/role-clients-walkthrough.test.ts`; service bootstrap example: `examples/service-operator-bootstrap/run.ts`. +- Runnable in phase 04: x402 install/clearance paths only; auth.md and package-install families remain proof-gap per integrator appendix. + +**auth.md protected API call (adjacent adapter profile):** +- Profile: `auth_md_protected_api_call.exact.v0` in `src/adapters/auth-md/action-proposal.ts`. +- Shared HTTP transport canonicalization: `src/adapters/http-profile/`. +- Usage: OAuth/authorization-server metadata and gateway credential refs as provenance for protected HTTP API calls; interlock with x402 in `src/adapters/auth-md-x402-interlock/`. +- Auth: registration and OAuth scopes are provenance only; Handshake policy + gateway check still required. + +**Engineering-agent host runtimes (activation/readiness evidence, not enforcement):** +- Host profiles and activation transcripts — `src/adapters/x402-payment/protected-tool-profile/`, proof packets `src/surfaces/proof-packets/codex-host-activation.ts`, scripts `scripts/check-codex-host-activation.mjs`, `scripts/install-codex-host-activation.mjs`. +- CLI: `handshake host doctor --host ` (`src/cli/host/doctor.ts`). +- Integration: documents wrapper targets and raw sibling bypass posture; does not read or mutate live host config. ## Data Storage **Databases:** -- Cloudflare D1 - Durable reconstruction source for the reference implementation. - - Connection: Worker binding `DB` in `wrangler.toml` and `src/http/app-options.ts`. - - Client: `D1ProtocolStore` in `src/storage/d1/index.ts`. - - Schema: `migrations/0001_protocol_kernel.sql`. - - Stores: `protocol_records`, `protocol_record_action_contract_refs`, `stream_events`, `greenlight_consumptions`, `greenlight_issuances`, `idempotency_ledger_current`, `recovery_terminal_claims`, `protected_path_posture_current`, `isolation_state_current`, `protected_surface_operation_claim_current`, and `receipt_by_mutation_attempt`. -- In-memory store - Test/demo fixture and invariant oracle. - - Client: `InMemoryProtocolStore` in `src/storage/memory/index.ts`. - - Usage: Injected through `AppOptions.store` or `allowEphemeralStore` in `src/http/app.ts`. - -**File Storage:** -- Local CLI project state: `.handshake/project.json` generated/read by `src/cli/local-project/index.ts`. -- External local CLI refs: `XDG_STATE_HOME` or `~/.local/state/handshake` paths used by `src/cli/local-project/index.ts`. -- Demo outputs: `examples/self-hosted-activation/output/`, `examples/x402-protected-spend/output/`, `examples/external-adapter-sdk/output/`, `examples/x402-protected-tool-profiles/output/`, and `examples/mcp-reference-transcript/output/`. -- Package output: `dist/` generated by `npm run build`. +- Cloudflare D1 (SQLite at edge) + - Binding: `DB` in `wrangler.toml` + - Client: `D1ProtocolStore` in `src/storage/d1/index.ts` + - Schema: `migrations/0001_protocol_kernel.sql` + - Resolution: `src/http/store/resolution.ts` requires D1 or injected ephemeral store for stateful HTTP routes. + +**Ephemeral / test storage:** +- `InMemoryProtocolStore` in `src/storage/memory/` — tests and `allowEphemeralStore` app option (`src/http/app.ts`). **Caching:** -- Cloudflare KV - Non-authoritative isolation cache posture only. - - Connection: Worker binding `CACHE` in `wrangler.toml` and `src/http/app-options.ts`. - - Client: `KvIsolationCache` in `src/storage/kv/index.ts`. - - Boundary: KV must not become protocol authority or durable reconstruction truth. +- Cloudflare KV namespace `CACHE` — isolation state snapshot cache via `KvIsolationCache` in `src/storage/kv/index.ts`; optional; D1 remains authoritative for commits. + +**Local filesystem (CLI operator state, not protocol authority):** +- Project marker: `.handshake/project.json` (`src/cli/local-project/index.ts`). +- State dir: `$XDG_STATE_HOME/handshake` or `~/.local/state/handshake` for local x402 readiness/install artifacts. +- Demo outputs: `examples/*/output/`, quickstart dossiers written by `handshake quickstart x402` / `handshake demo x402`. +- Service operator bootstrap output: `examples/service-operator-bootstrap/output/`. ## Authentication & Identity -**Auth Provider:** -- Custom local bearer-token admission. - - Implementation: `src/http/admission/caller-auth.ts`. - - Roles: `control_plane`, `runtime_evidence`, `gateway_custody`, and `review_custody`. - - Env vars: `HANDSHAKE_CONTROL_PLANE_TOKEN`, `HANDSHAKE_RUNTIME_EVIDENCE_TOKEN`, `HANDSHAKE_GATEWAY_CUSTODY_TOKEN`, and `HANDSHAKE_REVIEW_CUSTODY_TOKEN`. -- Pluggable hosted caller verifier. - - Interface: `HostedCallerVerifier` in `src/http/admission/hosted-caller-identity.ts`. - - Config schema: `src/http/admission/hosted-admission-config.ts`. - - Supported strategy labels: `local_test_verifier`, `cloudflare_access_jwt`, `pinned_jwks`, and `custom_server_verifier`. - - Provider implementation: Not detected. These are local schema/interface hooks, not a managed identity integration. - -**Principal-Agent Link:** -- `OperatingEnvelopeSchema` in `src/protocol/areas/catalog-envelope/schemas.ts` binds `principalId`, `agentId`, optional evidence-only `participantIdentityBindings`, allowed action classes, allowed gateways, allowed resources, policy pack, issued time, expiry, and revocation time. -- `ParticipantIdentityBindingSchema` can carry external identity provider refs, subject refs/digests, claims digests, and verification evidence refs. Its `authorityPosture` is fixed to `evidence_only`. -- `ActionContractSchema` in `src/protocol/areas/action-contract/schemas.ts` copies `principalId`, `agentId`, participant identity bindings, gateway registry binding, credential custody posture, gateway authority holder, delegated authority refs, and exact params digest into the proposed commitment. -- `DelegatedAuthorityRefSchema` in `src/protocol/areas/delegated-authority/schemas.ts` records bounded attempt authority for spend, mutation, or API calls. It includes `mutationAuthorityCreated: false` and `greenlightCreated: false`. - -**Credential Custody:** -- `GatewayCredentialRefSchema` in `src/protocol/areas/credential-custody/schemas.ts` records opaque provider-neutral credential refs and explicitly sets `secretMaterialIncluded: false`. -- `GatewayCustodyProofPacketSchema` records redacted custody/posture evidence and explicitly sets `authorityCreated: false`. -- `CredentialResolutionEvidenceSchema` records post-gate gateway credential use evidence and explicitly sets `credentialMaterialIncluded: false`. - -## Protocol Rails - -**x402 protected spend:** -- Install proposal: `src/adapters/x402-payment/install-proposal.ts` compiles `x402_payment.exact` setup records, gateway registry entries, operating envelopes, credential refs, delegated spend refs, spend bounds, and bypass probe plans. -- Runtime proposal: `src/adapters/x402-payment/action-proposal.ts` builds x402 payment attempts, validates per-call bounds, binds payment requirement digests, and proposes contracts through runtime/protocol APIs. -- Gateway signing: `src/adapters/x402-payment/wallet-gateway.ts` runs `gatewayCheck`, records credential resolution evidence, signs through an injected gateway signing surface, reconciles downstream payment status, and returns proof gaps when downstream finality is unknown. -- Protected tool facade: `src/adapters/x402-payment/protected-tool-facade/index.ts` prepares proposal-only runtime dispatch blocks after readiness and metadata preflight; it emits no authority. -- Host profile readiness: `src/adapters/x402-payment/protected-tool-readiness/index.ts` and `src/adapters/x402-payment/protected-tool-profile/index.ts` bind pre-contract readiness, custody proof, raw sibling posture, and host profile descriptors. - -**auth.md protected API call:** -- Discovery/profile evidence: `src/adapters/auth-md/profiles.ts`. -- Runtime proposal: `src/adapters/auth-md/action-proposal.ts`. -- Gateway execution fixture: `src/adapters/auth-md/gateway.ts`. -- Lifecycle/revocation evidence: `src/adapters/auth-md/revocation.ts`. -- Composite admission/proof packet with x402: `src/adapters/auth-md-x402-interlock/packet.ts`. -- Boundary: auth.md stays provenance and gateway-custody evidence until a protected API call clears through exact contract, policy, one-use greenlight, gateway check, and post-gate credential resolution. - -**Package install / repo write / preview deploy proof contexts:** -- Package install reference adapter: `src/adapters/package-install/`. -- Repo write reference gateway: `src/adapters/repo-write/gateway.ts`. -- Preview deploy reference gateway: `src/adapters/preview-deploy/gateway.ts`. -- Runtime helpers: `src/runtime/package-install/action-proposal.ts`, `src/runtime/repo-write/action-proposal.ts`, and `src/runtime/preview-deploy/action-proposal.ts`. -- Boundary: These are proof contexts and adapter fixtures unless a source admission packet names generated execution shape, protected path, gateway authority holder, credential holder, candidate/refusal boundary, bypass posture, evidence path, proof-gap model, recovery/isolation path, non-claims, and gates. +**Worker transition custody (local/hosted HTTP):** +- Role-scoped bearer tokens bound to Worker secrets or `CallerAuthTokens` in app options (`src/http/admission/caller-auth.ts`): + - `HANDSHAKE_CONTROL_PLANE_TOKEN` + - `HANDSHAKE_RUNTIME_EVIDENCE_TOKEN` + - `HANDSHAKE_GATEWAY_CUSTODY_TOKEN` + - `HANDSHAKE_REVIEW_CUSTODY_TOKEN` +- Roles map in `src/hosted-admission/roles.ts`; admission orchestration in `src/http/admission/`. + +**Hosted caller verification:** +- Custom adapter implements `verify()` returning redacted claims; fails closed on non-current membership (`src/hosted-admission/hosted-verifier-adapter.ts`). +- Supported verification postures: `provider_sdk_verified`, `provider_jwks_verified`, `provider_webhook_verified`, `service_credential_verified`, `fixture_verified`, `custom_verified`. +- FailureClass mapping for stale hosted identity: `stale_admission` via `src/protocol/foundation/failure-class/index.ts` (used in HTTP envelopes — `test/http/transition-error-failure-class.test.ts`). + +**Request context headers (non-auth):** +- `x-handshake-protocol-version`, `x-handshake-request-identity`, `x-handshake-originating-identity` (`src/http/admission/request-context.ts`). + +**Authority certificate verifier (hosted read path):** +- JWKS/metadata/status handlers in `src/http/handlers/verifier.ts` for terminal certificate verification material supplied via `AppOptions`. + +## HTTP mutation inventory + +**Service mutation route manifest:** +- `src/http/mutation-route-manifest.ts` — frozen inventory of existing POST transition routes mapped to `SurfaceRouteFamily` values; `assertMutationRouteManifestParity()` guards drift against `src/http/routes/transition-route-registry.ts`. +- All manifest rows set `requiresAdapterGatewayCheck: true`. +- Not a separate top-level package path (`src/service-mutation-route-manifest/` does not exist; architecture test `test/architecture/operator-product-completion-contract.test.ts` asserts absence of that legacy path). ## Monitoring & Observability **Error Tracking:** -- None detected. No Sentry, Datadog, OpenTelemetry, Honeycomb, or similar dependency appears in `package.json`. +- Not detected (no Sentry/Datadog/etc. dependencies in `package.json`). **Logs:** -- No external log service detected. -- HTTP failures return structured transition error envelopes from `src/http/errors/transition-error-envelope.ts`. -- Protocol observability is durable evidence: records, stream events, receipts, refusals, proof gaps, redacted projections, terminal certificates, and support bundles. -- ESLint allows only `console.warn` and `console.error` in `eslint.config.js`. +- Worker/CLI: structured JSON error envelopes via `transitionErrorResult` (`src/http/errors/transition-error-envelope.ts`) including `failureClass` from FailureClass taxonomy; CLI commands generally JSON-first (`src/cli/output.ts`). +- ESLint restricts `console` to warn/error in `src/` and `test/`. + +**Proof / release telemetry (repo-local, not SaaS):** +- Proof packets under `src/surfaces/proof-packets/` (distribution, product completion, live x402, host activation, npm maintainer posture). +- Gate scripts write or assert JSON proof artifacts (`scripts/check-product-completion.mjs`, `scripts/build-publish-handoff-packet.mjs`, `scripts/check-service-agent-gating-phase.mjs`). ## CI/CD & Deployment **Hosting:** -- Cloudflare Workers target via `wrangler.toml` and `src/worker.ts`. -- D1 binding `DB` is required for durable HTTP protocol endpoints unless an explicit injected test store is supplied. -- Hosted operation is not proven by this repo alone. `src/http/admission/hosted-admission-config.ts` models hosted readiness/admission posture, not provider custody or hosted mutation authority. +- Cloudflare Workers for HTTP protocol kernel API (`wrangler.toml`, `src/worker.ts`). +- npm registry for installable package `handshake-protocol-kernel` (CLI, SDK, MCP stdio server). **CI Pipeline:** -- GitHub Actions in `.github/workflows/check.yml`. -- CI uses pinned `actions/checkout` and `oven-sh/setup-bun`, installs Bun `1.3.9`, runs `bun install --frozen-lockfile`, then `npm run check:repo`. +- GitHub Actions workflow `.github/workflows/check.yml` on push/PR. +- Steps: checkout → `oven-sh/setup-bun@v2` (1.3.9) → `bun install --frozen-lockfile` → `npm run check:repo`. +- `check:repo` chains build, typecheck, lint, prettier check, full test suite, and `pack:check` release surface proofs. -**Package Gate:** -- `npm run pack:check` in `package.json` runs `npm run build`, `scripts/check-package-surface.mjs`, `scripts/check-published-entrypoints.mjs`, `scripts/check-clean-installed-activation.mjs`, and `scripts/check-release-proof.mjs`. -- Package checks verify package allowlist, exports, bins, local CLI schema output, MCP stdio process behavior, role-client subpath, x402 protected-tool subpath, and installed-artifact smoke. +**Release / distribution checks (Node scripts, not CI-only):** +- `scripts/check-published-entrypoints.mjs`, `scripts/check-package-surface.mjs`, `scripts/check-release-proof.mjs`, `scripts/check-npm-maintainer-posture.mjs`, `scripts/check-clean-installed-activation.mjs`, `scripts/build-publish-handoff-packet.mjs`. ## Environment Configuration -**Required env vars:** -- Local bearer admission: - - `HANDSHAKE_CONTROL_PLANE_TOKEN` - - `HANDSHAKE_RUNTIME_EVIDENCE_TOKEN` - - `HANDSHAKE_GATEWAY_CUSTODY_TOKEN` - - `HANDSHAKE_REVIEW_CUSTODY_TOKEN` -- Cloudflare bindings: - - `DB` - - `CACHE` -- Optional local state: - - `XDG_STATE_HOME` +**Worker bindings (configure in Cloudflare dashboard / Wrangler secrets, not in repo):** +- `DB` — D1 database binding (required for durable hosted routes). +- `CACHE` — KV namespace (optional isolation cache). +- `HANDSHAKE_CONTROL_PLANE_TOKEN`, `HANDSHAKE_RUNTIME_EVIDENCE_TOKEN`, `HANDSHAKE_GATEWAY_CUSTODY_TOKEN`, `HANDSHAKE_REVIEW_CUSTODY_TOKEN` — transition route custody. +- Hosted-mode secrets referenced in tests as patterns only (e.g. `HANDSHAKE_HOSTED_TEST_SECRET` in `test/http/http.test.ts`); treat as operator-supplied, never commit values. + +**Local / CLI (operator machine):** +- Project cwd and `.handshake/` tree for install/probe/readiness JSON consumed by x402 CLI commands. +- `XDG_STATE_HOME` overrides local state root for Handshake CLI artifacts. +- Live x402 proof scripts accept `--input-file` evidence paths (`scripts/check-live-x402-paid-retry.mjs`); missing file → blocked proof status. + +**Package / MCP metadata (committed, non-secret):** +- `package.json` version `0.2.7` and `server.json` version must stay aligned for MCP Registry publication checks (`scripts/check-published-entrypoints.mjs`, `scripts/check-release-proof.mjs`). **Secrets location:** -- Secrets are not stored in the repo. -- `.gitignore` excludes `.dev.vars`, `.env`, `.env.local`, `.env.*.local`, `*.pem`, and `*.key`. -- Cloudflare secrets should live in platform bindings. -- npm/MCP Registry credentials are external to this checkout. -- x402 signer material must be held behind the gateway signing surface, not in runtime, MCP, CLI, docs, examples, or protocol records. +- Cloudflare Worker secrets and local operator credential material stay outside the repo. ## Webhooks & Callbacks **Incoming:** -- No webhook endpoints detected. -- Protocol transition routes are registered in `src/http/routes/transition-route-registry.ts`. -- Redacted evidence read routes are registered in `src/http/routes/evidence-read-route-registry.ts`. -- Additional HTTP endpoints in `src/http/app.ts`: `/health`, `/openapi.json`, `/v0.2/hosted/readiness`, `/v0.2/verifier/metadata`, `/v0.2/verifier/key-set`, `/v0.2/verifier/jwks.json`, `/v0.2/verifier/status/:subjectKind/:subjectRef`, `/v0.2/verifier/authority-certificates/verify`, and `/v0.2/records/:objectType/:objectId`. -- MCP incoming requests are stdio tool/resource calls handled by `src/mcp/stdio/server.ts`. +- HTTP transition and evidence-read routes on Worker app (`src/http/routes/transition-route-registry.ts`, `src/http/routes/evidence-read-route-registry.ts`). +- Mutation inventory tracked separately in `src/http/mutation-route-manifest.ts`. +- OpenAPI document served from `src/http/openapi` (referenced in `src/http/app.ts`). +- No generic public webhook receiver detected beyond protocol HTTP API. **Outgoing:** -- SDK clients call a configured Handshake base URL through `fetch` in `src/sdk/client.ts` and `src/sdk/surface-clients/transport.ts`. -- Reference adapters call injected surfaces rather than hard-coded provider APIs: - - `src/adapters/x402-payment/wallet-gateway.ts` calls an injected `X402WalletSigningSurface`. - - `src/adapters/auth-md/gateway.ts` calls an injected `AuthMdProtectedApiCallSurface`. - - `src/adapters/package-install/gateway.ts`, `src/adapters/repo-write/gateway.ts`, and `src/adapters/preview-deploy/gateway.ts` use caller-supplied mutation surfaces. -- No production webhook/callback delivery integration detected. - -## Distribution Surfaces - -**npm package:** -- Public package shape is `handshake-protocol-kernel` with executable bins and subpath exports in `package.json`. -- `scripts/check-package-surface.mjs` keeps private source, tests, planning scratch, scripts, examples, migrations, and internal docs out of the package artifact. - -**MCP Registry:** -- `server.json` advertises one npm/stdio package entry for the MCP server. -- MCP Registry discoverability is separate from npm publication and does not create authority. - -**Examples:** -- `examples/self-hosted-activation/run.ts` emits local self-hosted activation evidence. -- `examples/x402-protected-spend/run.ts` emits local/reference protected-spend evidence. -- `examples/external-adapter-sdk/run.ts` emits definition-only adapter SDK readback. -- `examples/x402-protected-tool-profiles/run.ts` emits protected tool host profile artifacts. -- `examples/mcp-reference-transcript/run.ts` emits local MCP transcript evidence. -- Example outputs are product/readback samples, not production storage or authority. +- x402 gateway HTTP retries via `@x402/core` client after verified gateway check and gateway-held custody gate in `src/adapters/x402-payment/wallet-gateway.ts`. +- MCP stdio subprocess spawn for local doctor/proof flows only. +- npm registry readback commands in release scripts (`npm view`, maintainer posture) — operator/CI invoked, not runtime hot path. + +## Integration Boundaries (prescriptive) + +When adding a new external integration: + +1. Place protocol meaning in `src/protocol/`; wire transport in `src/http/` or `src/adapters/`. +2. Do not let provider SDKs, MCP tools, or CLI commands issue greenlights, gateway checks, or mutations. +3. Record proof gaps explicitly in `src/surfaces/proof-packets/` rather than implying production operation (including MCP Registry discoverability). +4. For identity, extend `HostedIdentityProviderKind` and adapter verification postures in `src/hosted-admission/` instead of importing authority into product surfaces. +5. For integrator-facing transitions, tag navigation metadata with `integratorParity: true` in `src/protocol/navigation/index.ts` and keep HTTP/SDK parity tests green in `test/architecture/integrator-parity.test.ts`. +6. For payments, keep the wedge on `x402_payment.exact` and enforce gateway-held custody via `assertGatewayHeldSigningCommand()` until a second action family passes expansion gates. +7. Add new POST transitions to `src/http/mutation-route-manifest.ts` in the same change as `transition-route-registry.ts`. --- -*Integration audit: 2026-05-25* +*Integration audit: 2026-05-29* diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md index 08cb152..c582baf 100644 --- a/.planning/codebase/STACK.md +++ b/.planning/codebase/STACK.md @@ -1,170 +1,149 @@ # Technology Stack -**Analysis Date:** 2026-05-25 - -## Protocol Kernel Shape - -**Current package:** -- `handshake-protocol-kernel@0.2.7` in `package.json`. -- MCP package name is `io.github.CreasyBear/handshake-protocol-kernel` in `package.json` and `server.json`. -- Runtime requirement is Node.js `>=20` in `package.json`; the current local shell reports `node --version` as `v25.2.1`. - -**Kernel boundary:** -- The source-owned protocol kernel lives under `src/protocol/`. Its transition facade is `src/protocol/kernel.ts`. -- The kernel records exact contracts, policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, isolation, recovery, review binding, generated-execution evidence, delegated-authority evidence, gateway-credential evidence, and terminal `AuthorityCertificate` evidence. -- Product surfaces live outside protocol meaning: `src/cli/`, `src/mcp/`, `src/sdk/`, `src/runtime/`, `src/adapters/`, `src/x402-protected-tool/`, and `examples/`. These surfaces may expose proposal, readiness, redacted readback, demos, or host activation artifacts, but they must not create authority unless they call the protocol and gateway path. - -**Authority sequence:** -- Runtime or generated execution evidence is recorded by `src/protocol/areas/runtime-evidence/`, `src/protocol/areas/generated-execution-graph/`, and `src/protocol/areas/tool-call-draft/`. -- Intent compilation and exact contract proposal live in `src/protocol/areas/intent-compilation/` and `src/protocol/areas/action-contract/`. -- Policy and one-use greenlights live in `src/protocol/areas/policy-greenlight/`. -- Gateway enforcement lives in `src/protocol/areas/gateway-gate/`; mutation-capable reference adapters use `verifiedGatewayCheckFromResult()` from `src/protocol/areas/gateway-gate/`. -- Reconstruction lives in `src/protocol/events/`, `src/protocol/evidence-projections/`, `src/protocol/areas/receipt-export/`, `src/protocol/areas/proof-gap/`, and `src/protocol/areas/authority-certificate/`. - -**Passport / admission / service gateway / principal-agent link:** -- There is no standalone `Passport` primitive in tracked source. Do not add one unless it reduces ambiguity more than the current typed records. -- HTTP caller admission is transport custody in `src/http/admission/`; it authenticates transition callers and read entitlements, not protected-action authority. -- The protected-action principal-agent link is `principalId`, `agentId`, and evidence-only `participantIdentityBindings` on `OperatingEnvelopeSchema` in `src/protocol/areas/catalog-envelope/schemas.ts`, then copied into `ActionContractSchema` in `src/protocol/areas/action-contract/schemas.ts`. -- Attempt authority is represented by `DelegatedAuthorityRefSchema` in `src/protocol/areas/delegated-authority/schemas.ts`; it records principal/agent/runtime/envelope/gateway scoped bounds and can be revoked or expired into isolation, but it is not a greenlight. -- Service gateway authority is represented by `GatewayRegistryEntrySchema` in `src/protocol/areas/catalog-envelope/schemas.ts`, `GatewayCredentialRefSchema` and `GatewayCustodyProofPacketSchema` in `src/protocol/areas/credential-custody/schemas.ts`, and the final `gatewayCheck()` transition in `src/protocol/kernel.ts`. +**Analysis Date:** 2026-05-29 ## Languages **Primary:** -- TypeScript 6.0.3 - All source, tests, examples, protocol schemas, HTTP routes, SDK clients, CLI, MCP server, adapters, and storage implementations under `src/`, `test/`, and `examples/`. +- TypeScript (`typescript` `^6.0.3`, `target: ES2022`) — protocol kernel, HTTP Worker app, CLI, MCP, SDK, adapters, surfaces, hosted admission, and tests under `src/` and `test/`. **Secondary:** -- JavaScript ESM - Build and package verification scripts under `scripts/`, including `scripts/build-package-bundles.mjs`, `scripts/check-package-surface.mjs`, `scripts/check-published-entrypoints.mjs`, and `scripts/check-release-proof.mjs`. -- SQL - Cloudflare D1 schema in `migrations/0001_protocol_kernel.sql`. -- Markdown - Canonical repo docs in `README.md`, `AGENTS.md`, `QUALITY.md`, `STRUCTURE.md`, and `docs/internal/*.md`; example docs under `examples/*/README.md`. -- TOML/JSON/YAML - Worker config in `wrangler.toml`, package metadata in `package.json`, MCP Registry metadata in `server.json`, TypeScript config in `tsconfig.json`, formatting/lint config in `.prettierrc.json` and `eslint.config.js`, and CI in `.github/workflows/check.yml`. +- JavaScript (ESM) — release/proof orchestration in `scripts/*.mjs` and `scripts/*.js`. +- SQL — durable protocol store schema in `migrations/0001_protocol_kernel.sql`. +- JSON / TOML — package and MCP metadata (`package.json`, `server.json`), Worker bindings (`wrangler.toml`), CI (`.github/workflows/check.yml`). ## Runtime **Environment:** -- Node.js `>=20` - Required by `package.json#engines`; Node ESM bundles are executed by `bin/handshake` and `bin/handshake-mcp`. -- Bun `1.3.9` - Declared in `package.json#packageManager`, present in `bun.lock`, used by `.github/workflows/check.yml`, used for tests and bundling. -- Cloudflare Workers - Worker entrypoint is `src/worker.ts`; `wrangler.toml` points `main` to that file. +- Node.js `>=20` — declared in `package.json#engines`; `bin/handshake` and `bin/handshake-mcp` are thin Node launchers that import bundled ESM from `dist/bin/`. +- Bun `1.3.9` — `packageManager` in `package.json`; default test runner (`bun test`), local demos (`bun run ./examples/...`), and ESM bundle step in `scripts/build-package-bundles.mjs`. +- Cloudflare Workers — production HTTP surface via `src/worker.ts` → `createApp()` from `src/http/app.ts`; local dev via `npm run dev` → `wrangler dev`. +- Cloudflare compatibility date `2026-05-17` — `wrangler.toml`. **Package Manager:** -- Bun `1.3.9` - Primary install/test package manager. -- npm `11.7.0` observed locally - Used by `package.json#scripts` and package checks such as `npm pack --dry-run --json`. -- Lockfile: `bun.lock` present. +- Bun `1.3.9` +- Lockfile: `bun.lock` (present) +- CI install: `bun install --frozen-lockfile` in `.github/workflows/check.yml` ## Frameworks **Core:** -- `hono` ^4.12.19 - HTTP/Worker app and route dispatch in `src/http/app.ts`. -- Cloudflare Workers + Wrangler ^4.92.0 - Deployment/runtime target configured by `wrangler.toml`; Worker/D1/KV types supplied by `@cloudflare/workers-types`. -- `zod` ^4.4.3 - Runtime validation and schema backbone across `src/protocol/**`, `src/http/**`, `src/runtime/**`, `src/adapters/**`, `src/cli/**`, `src/mcp/**`, and `src/x402-protected-tool/**`. -- MCP TypeScript SDK 2.0.0-alpha.2 - Local stdio MCP server/client proof in `src/mcp/stdio/server.ts`, `src/mcp/stdio/process-proof.ts`, and `scripts/check-published-entrypoints.mjs`. -- x402 SDK 2.12.0 - Official buyer-side exact payment evidence/signing path in `src/adapters/x402-payment/upstream-evidence.ts`, `src/adapters/x402-payment/action-proposal.ts`, and `src/adapters/x402-payment/wallet-gateway.ts`. +- Hono `^4.12.19` — HTTP routing, middleware, OpenAPI-backed Worker app in `src/http/`. +- Zod `^4.4.3` — runtime schemas and parsing across protocol areas, adapters, hosted admission, CLI inputs, and FailureClass taxonomy (`src/protocol/foundation/failure-class/index.ts`). +- `@modelcontextprotocol/server` / `@modelcontextprotocol/client` `^2.0.0-alpha.2` — stdio MCP server (`src/mcp/stdio/server.ts`) and doctor/process-proof client (`src/mcp/stdio/process-proof.ts`). +- `@x402/core` / `@x402/evm` `2.12.0` — x402 v2 payment-required validation and EVM exact-scheme gateway client in `src/adapters/x402-payment/` (including gateway-held custody in `wallet-gateway.ts`). **Testing:** -- Bun test - Test runner via `package.json#scripts.test`. -- TypeScript compiler - Type gate via `npm run check:types` and `npm run typecheck`. -- Architecture and claim tests - Focused repo-boundary tests under `test/architecture/`. +- Bun built-in test runner — `npm run test` → `bun test`; no separate Jest/Vitest config. +- Targeted quality scripts — `quality:architecture`, `quality:claims`, `quality:storage` in `package.json#scripts` filter architecture and protocol test subsets. -**Build/Dev:** -- TypeScript declarations - `npm run build:types` runs `tsc -p tsconfig.build.json`. -- Bun bundler - `scripts/build-package-bundles.mjs` bundles package entrypoints and bins into `dist/`. -- ESLint 10.4.0 + `typescript-eslint` 8.59.4 - Linting configured by `eslint.config.js`. -- Prettier 3.8.3 - Formatting configured by `.prettierrc.json`. -- Wrangler - `npm run dev` runs `wrangler dev`. +**Build / Dev:** +- TypeScript `tsc` — declaration emit via `tsconfig.build.json` → `dist/**/*.d.ts`. +- Bun `build` — ESM bundles for package exports and CLI/MCP bins via `scripts/build-package-bundles.mjs`. +- Wrangler `^4.92.0` — Worker dev/deploy tooling. +- ESLint `^10.4.0` + `typescript-eslint` `^8.59.4` — `eslint.config.js`. +- Prettier `^3.8.3` — `.prettierrc.json` (120 print width, semicolons, trailing commas). ## Key Dependencies -**Critical:** -- `zod` ^4.4.3 - Defines strict protocol, adapter, MCP, CLI, hosted admission, and evidence schemas. -- `hono` ^4.12.19 - Owns HTTP routing for `/health`, `/openapi.json`, transition routes, evidence routes, hosted readiness, verifier routes, and internal record reads in `src/http/app.ts`. -- `@x402/core` 2.12.0 - Validates `PaymentRequired` and `PaymentPayload` evidence in `src/adapters/x402-payment/upstream-evidence.ts` and `src/adapters/x402-payment/wallet-gateway.ts`. -- `@x402/evm` 2.12.0 - Provides `ExactEvmScheme` and `ClientEvmSigner` for gateway-held exact EVM signing in `src/adapters/x402-payment/wallet-gateway.ts`. -- `@modelcontextprotocol/server` 2.0.0-alpha.2 - Builds `handshake-mcp` local stdio server in `src/mcp/stdio/server.ts`. -- `@modelcontextprotocol/client` 2.0.0-alpha.2 - Verifies the local MCP process in `src/mcp/stdio/process-proof.ts` and `scripts/check-published-entrypoints.mjs`. - -**Infrastructure:** -- `@cloudflare/workers-types` ^4.20260517.1 - Worker, D1, and KV TypeScript bindings used by `src/http/app-options.ts`, `src/storage/d1/index.ts`, and `src/storage/kv/index.ts`. -- `wrangler` ^4.92.0 - Cloudflare Worker local development and deployment CLI. -- `typescript` ^6.0.3 - Strict source checking with `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes` in `tsconfig.json`. -- `eslint` ^10.4.0 and `typescript-eslint` ^8.59.4 - Type import, unused variable, and console discipline in `eslint.config.js`. -- `prettier` ^3.8.3 - Formatting for source, docs, and generated example outputs. -- `@x402/fetch` 2.12.0 - Dev/test fixture dependency used by `test/conformance/x402-upstream-exact-fixtures.test.ts`. -- `@types/bun` ^1.3.14 - Bun type support for tests, scripts, and examples. -- `@cfworker/json-schema` ^4.1.1 - Listed in `package.json`; no active source import detected under `src/`, `test/`, `scripts/`, or `examples/`. +**Critical (product wedge):** +- `@x402/core` `2.12.0` — PAYMENT-REQUIRED parsing, HTTP client, payment payload validation (`src/adapters/x402-payment/wallet-gateway.ts`, `src/surfaces/proof-packets/live-x402-requirement.ts`). +- `@x402/evm` `2.12.0` — `ExactEvmScheme` and `ClientEvmSigner` for buyer-side exact payments after gateway check. +- `hono` — protocol transition HTTP API, mutation route manifest parity, and evidence read routes (`src/http/routes/`, `src/http/handlers/`, `src/http/mutation-route-manifest.ts`). +- `zod` — canonical input validation at protocol and product boundaries. + +**Infrastructure / platform:** +- `@cloudflare/workers-types` `^4.20260517.1` — Worker/D1/KV typings in `tsconfig.json`. +- `@cfworker/json-schema` `^4.1.1` — direct dependency; also satisfies MCP SDK optional peer for JSON Schema validation. + +**Dev-only integration helpers:** +- `@x402/fetch` `2.12.0` (devDependency) — fetch-layer x402 helpers for tests and proof scripts. ## Configuration +**TypeScript:** +- Base: `tsconfig.json` — `strict`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `moduleResolution: Bundler`, `lib: ["ES2022","WebWorker"]`, `types: ["@cloudflare/workers-types","bun-types"]`. +- Build emit: `tsconfig.build.json` — `declaration` only into `dist/` from `src/`. + +**Lint / format:** +- `eslint.config.js` — recommended TypeScript rules; `consistent-type-imports`, `no-console` (warn/error only). +- `.prettierrc.json` — repo-wide formatting. + +**Worker / storage:** +- `wrangler.toml` — `main = "src/worker.ts"`, D1 binding `DB` → database `handshake_protocol`, KV binding `CACHE`. +- `migrations/0001_protocol_kernel.sql` — canonical D1 tables for protocol records, greenlight consumption, streams, isolation, etc. + **Environment:** -- Worker D1 binding `DB` and KV binding `CACHE` are declared in `wrangler.toml`. -- Local bearer transition admission reads `HANDSHAKE_CONTROL_PLANE_TOKEN`, `HANDSHAKE_RUNTIME_EVIDENCE_TOKEN`, `HANDSHAKE_GATEWAY_CUSTODY_TOKEN`, and `HANDSHAKE_REVIEW_CUSTODY_TOKEN` in `src/http/admission/caller-auth.ts`. -- Hosted admission is configured through `AppOptions.authMode`, `AppOptions.hostedAdmissionConfig`, and `AppOptions.hostedCallerVerifier` in `src/http/app-options.ts`; provider strategy values are schema-only in `src/http/admission/hosted-admission-config.ts`. -- CLI local project state uses `.handshake/project.json` and external local state refs managed by `src/cli/local-project/index.ts`. -- `.env`, `.env.local`, `.env.*.local`, `.dev.vars`, `*.pem`, and `*.key` are ignored by `.gitignore`. No `.env*` file contents were read. +- Do not commit secrets. No `.env` files detected in repo root (operators configure Worker secrets locally). +- Worker role tokens are binding names in `src/http/admission/caller-auth.ts` (`HANDSHAKE_*_TOKEN`), not hardcoded values. +- Local CLI state defaults to `.handshake/project.json` under cwd and optional XDG state under `~/.local/state/handshake` (`src/cli/local-project/index.ts`). **Build:** -- `tsconfig.json` targets `ES2022`, uses `module: ESNext`, `moduleResolution: Bundler`, `lib: ["ES2022", "WebWorker"]`, strict checking, Worker/Bun types, and `outDir: dist`. -- `tsconfig.build.json` emits declarations only from `src/` into `dist/`. -- `scripts/build-package-bundles.mjs` bundles package entrypoints: `src/index.ts`, `src/conformance/index.ts`, `src/adapter-sdk/index.ts`, `src/surfaces/index.ts`, `src/runtime/index.ts`, `src/sdk/surface-clients/index.ts`, `src/cli/index.ts`, `src/mcp/index.ts`, `src/x402-protected-tool/index.ts`, `src/experimental.ts`, `src/cli/main.ts`, and `src/mcp/stdio/entry.ts`. -- `eslint.config.js` ignores `dist/**`, `coverage/**`, `node_modules/**`, and `docs/internal/archive/**`; it enforces consistent type imports, unused-var cleanup, and no `console` except `warn` and `error`. -- `.prettierrc.json` sets `printWidth: 120`, semicolons, double quotes, and trailing commas. - -## Package Surface - -**npm package:** -- Package name/version: `handshake-protocol-kernel` `0.2.7` in `package.json`. -- License: Apache-2.0 in `package.json`, with package files `LICENSE` and `NOTICE`. -- Published allowlist is `bin`, `dist`, `server.json`, `README.md`, `CHANGELOG.md`, `LICENSE`, and `NOTICE` in `package.json#files`. -- `scripts/check-package-surface.mjs` rejects packaged `.planning/`, `.agents/`, `skills-lock.json`, `src/`, `test/`, `scripts/`, `examples/`, `migrations/`, `docs/internal/`, old docs trees, root canon files such as `AGENTS.md`, `QUALITY.md`, `STRUCTURE.md`, and `bun.lock`. - -**Exports:** -- `.` -> root protocol/HTTP/SDK curated API from `src/index.ts`. -- `./conformance` -> reference conformance checks from `src/conformance/index.ts`. -- `./adapter-sdk` -> definition-only adapter pack surface from `src/adapter-sdk/index.ts`. -- `./runtime` -> proposal-only runtime ingress surface from `src/runtime/index.ts`. -- `./sdk/role-clients` -> role-scoped clients from `src/sdk/surface-clients/index.ts`. -- `./cli` -> CLI helper surface from `src/cli/index.ts`. -- `./mcp` -> MCP catalog/resource/proposal surface from `src/mcp/index.ts`. -- `./x402-protected-tool` -> normal-agent-tool facade, readiness, host profile, and activation artifacts from `src/x402-protected-tool/index.ts`. -- `./experimental` -> explicit reference adapter exports from `src/experimental.ts`. - -**Bins:** -- `handshake` -> `bin/handshake` -> `dist/bin/handshake.mjs`; local operator/evidence CLI. -- `handshake-mcp` -> `bin/handshake-mcp` -> `dist/bin/handshake-mcp.mjs`; local stdio MCP proposal/evidence server. -- `handshake-protocol-kernel` -> `bin/handshake-mcp`; package-name execution alias for MCP hosts. - -## Protocol Product Surfaces +```bash +npm run build # tsc declarations + bun bundle all entrypoints +npm run dev # wrangler dev +npm run check:repo # build + typecheck + lint + format + test + pack:check + git diff --check +``` + +## Entry Points + +**HTTP (Cloudflare Worker):** +- `src/worker.ts` — default export `{ fetch: app.fetch }` from `createApp()`. + +**npm package root (`handshake-protocol-kernel`):** +- `src/index.ts` → `dist/index.mjs` — HTTP app factory, protocol public schemas, SDK clients (`ControlPlaneClient`, `GatewayClient`, `PolicyClient`, `EvidenceClient`), navigation metadata, transition error envelopes with FailureClass. **CLI:** -- Command manifest lives in `src/cli/command-manifest.ts`. -- Active commands include `schema`, `init`, `doctor`, `evidence aps-report`, `evidence contract-view`, `evidence receipt-timeline`, `cert verify`, `support bundle`, `install x402-payment`, `probes x402-payment`, `register x402-gateway-readiness`, `install health`, and `conformance x402-payment`. -- CLI output is evidence/readiness only. It does not evaluate policy, issue greenlights, perform gateway checks, use signers, mutate protected surfaces, export receipts as authority, or mint terminal certificates. +- `src/cli/main.ts` → `dist/bin/handshake.mjs` — launched via `bin/handshake` (Node shebang). +- Service operator bootstrap: `src/cli/service-operator/bootstrap.ts` (command `service bootstrap` in `src/cli/command-manifest.ts`). -**MCP:** -- MCP catalog lives in `src/mcp/catalog.ts`. -- The only proposal tool is `handshake.actions.x402_payment.propose`. -- Read-only resources use `handshake://metadata/*`, `handshake://challenges/*`, `handshake://evidence/*`, `handshake://health/*`, and `handshake://certificates/*` in `src/mcp/resources.ts`. -- MCP proposal handling in `src/mcp/x402-proposal.ts` can create runtime evidence, tool-call drafts, intent compilations, and proposed action contracts through a runtime client. It does not evaluate policy, greenlight, gateway-check, mutate, export receipts, mint certificates, or carry credential material. +**MCP stdio:** +- `src/mcp/stdio/entry.ts` → `dist/bin/handshake-mcp.mjs` — launched via `bin/handshake-mcp`. -**SDK:** -- Low-level `HandshakeClient` lives in `src/sdk/client.ts`. -- Role-scoped activation clients live under `src/sdk/surface-clients/`: `InstallClient`, `RuntimeClient`, `ControlPlaneClient`, `PolicyClient`, `GatewayClient`, and `EvidenceClient`. -- Use role-scoped clients for activation code because each class carries one custody role. Avoid teaching new activation paths with the multi-role `HandshakeClient` token map unless the test specifically needs route parity. +**Bundled subpath exports** (`scripts/build-package-bundles.mjs`): +- `./conformance`, `./adapter-sdk`, `./runtime`, `./sdk/role-clients`, `./cli`, `./mcp`, `./x402-protected-tool`, `./surfaces/a2a-negotiation-readback`, `./experimental`. + +**Canonical modules without current npm subpath bundles:** +- `src/hosted-admission/` — provider-neutral hosted admission contracts (`src/hosted-admission/index.ts`); HTTP shims re-export from `src/http/admission/hosted-*.ts`. Architecture test `test/architecture/manifest-coverage.test.ts` expects `./hosted-admission` in `package.json#exports`, but that subpath is **absent** from current `package.json` (and has no bundle row in `build-package-bundles.mjs`). +- `src/surfaces/service-workflow-admission/` — same export gap for `./surfaces/service-workflow-admission`. + +## Phase 04+05 structural additions + +**FailureClass taxonomy:** +- `src/protocol/foundation/failure-class/index.ts` — enum classes: `auth`, `hosted_admission`, `protected_action_refusal`, `proof_gap`, `replay_refusal`, `stale_admission`, `internal`. +- Wired into HTTP transition errors via `src/http/errors/transition-error-envelope.ts` (`TransitionFailureClassSchema`, `classifyFailureClassFromProtocolError`). + +**Integrator parity (formerly “Tier 1” transitions):** +- Transition IDs: `integratorParityTransitionIds` in `src/protocol/navigation/index.ts` (11 catalog/install/runtime/policy/gateway transitions). +- HTTP/SDK parity tests: `test/architecture/integrator-parity.test.ts`. +- Operator appendix: `docs/internal/integrator-parity-transitions.md`. + +**Service operator CLI lane:** +- Renamed from `src/cli/service/` → `src/cli/service-operator/` (`bootstrap.ts`, exported from `src/cli/index.ts`). +- Example recipe: `examples/service-operator-bootstrap/run.ts`. + +**HTTP mutation route manifest:** +- Frozen POST transition inventory: `src/http/mutation-route-manifest.ts` (parity with `transitionRouteDefinitions` in `src/http/routes/transition-route-registry.ts`). + +**x402 gateway-held custody (D-64):** +- `assertGatewayHeldSigningCommand()` in `src/adapters/x402-payment/wallet-gateway.ts` — enforces `credentialMaterialPosture: "gateway_held_redacted"` with gate-bound credential resolution evidence before signing. ## Platform Requirements **Development:** -- Install dependencies with `bun install --frozen-lockfile`; `.github/workflows/check.yml` uses that command. -- Main repo gate is `npm run check:repo`, which runs `npm run check:types`, `npm run lint`, `npm run format:check`, `npm run test`, `npm run pack:check`, and `git diff --check`. -- Focused gates are `npm run quality:architecture`, `npm run quality:claims`, and `npm run quality:storage`. -- Demo generation commands are `npm run demo:self-hosted`, `npm run demo:aps`, `npm run demo:adapter-sdk`, `npm run demo:x402-tool-profiles`, and `npm run demo:mcp-transcript`. +- Node.js `>=20` for installed CLI/MCP binaries. +- Bun `1.3.9` (or compatible) for `bun install`, `bun test`, and bundle build. +- Wrangler CLI for Worker local dev when exercising `src/http/` against D1/KV bindings. **Production:** -- HTTP service target is Cloudflare Workers through `src/worker.ts` and `wrangler.toml`. -- Durable reconstruction store is Cloudflare D1 through `src/storage/d1/index.ts` and `migrations/0001_protocol_kernel.sql`. -- KV is cache posture only through `src/storage/kv/index.ts`; it is not durable protocol truth. -- Public package consumers use Node ESM bundles under `dist/` and executable wrappers under `bin/`. -- Public npm availability, MCP Registry metadata, host profiles, and install health do not create authority. The gateway check remains the final enforcement point before consequence. +- Cloudflare Workers deployment with D1 (`DB`) for durable protocol state (`src/http/store/resolution.ts` → `D1ProtocolStore` in `src/storage/d1/index.ts`). +- Optional KV (`CACHE`) for isolation snapshot cache (`src/storage/kv/index.ts`); D1 remains source of truth per `migrations/0001_protocol_kernel.sql` header comment. +- npm registry publication of `handshake-protocol-kernel` at version `0.2.7` (package name in `package.json`; MCP name `io.github.CreasyBear/handshake-protocol-kernel` in `server.json`). + +**Distribution surfaces (non-authority):** +- npm package exports — curated subpaths in `package.json#exports` (root, `./conformance`, `./adapter-sdk`, `./runtime`, `./sdk/role-clients`, `./cli`, `./mcp`, `./x402-protected-tool`, `./surfaces/a2a-negotiation-readback`, `./experimental`). +- MCP Registry metadata — `server.json` declares stdio transport via npm package; **registry discoverability remains a proof gap** until registry acceptance/lookup is verified (`docs/internal/decisions.md` D-244). --- -*Stack analysis: 2026-05-25* +*Stack analysis: 2026-05-29* diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md index eefade3..cb2f09e 100644 --- a/.planning/codebase/STRUCTURE.md +++ b/.planning/codebase/STRUCTURE.md @@ -1,293 +1,319 @@ # Codebase Structure -**Analysis Date:** 2026-05-25 +**Analysis Date:** 2026-05-29 ## Directory Layout ```text -Handshake v0.0.2/ -├── src/ # Source-owned protocol, transport, adapters, clients, and surfaces -├── test/ # Unit, product, architecture, smoke, and integration tests -├── examples/ # Runnable demos and generated-output fixtures -├── scripts/ # Quality, packaging, docs, and architecture guard scripts -├── migrations/ # Cloudflare D1 schema for protocol kernel state -├── bin/ # Package CLI entry shims -├── docs/internal/ # Canonical product, protocol, and decision notes -├── .github/workflows/ # CI gates -├── .planning/codebase/ # GSD scratch codebase maps -├── package.json # Package scripts, exports, dependencies, and files surface -├── tsconfig.json # TypeScript project settings -├── wrangler.toml # Cloudflare Worker/D1 configuration -├── README.md # Current repo orientation and commands -├── QUALITY.md # TypeScript and naming quality rules -└── STRUCTURE.md # Tracked source, docs, and test ownership rules +handshake-protocol-kernel/ +├── AGENTS.md # Product invariants and doctrine +├── README.md # Repo orientation and commands +├── QUALITY.md # TypeScript quality rules +├── STRUCTURE.md # Canonical ownership map (repo root) +├── package.json # Exports, bins, scripts (v0.2.7) +├── bin/ +│ ├── handshake # CLI entry wrapper +│ └── handshake-mcp # MCP stdio entry wrapper +├── migrations/ # Canonical D1 schema +├── wrangler.toml # Worker bindings +├── server.json # MCP Registry metadata +├── src/ +│ ├── index.ts # Curated package exports +│ ├── experimental.ts # Reference adapter exports +│ ├── worker.ts # Cloudflare Worker entry +│ ├── protocol/ # Kernel and areas (authority) +│ ├── http/ # Hono app, mutation manifest, routes +│ ├── runtime/ # Ingress and proposal helpers +│ ├── adapters/ # Reference gateway fixtures +│ ├── adapter-sdk/ # Adapter authoring contracts +│ ├── conformance/ # Reference conformance probes +│ ├── storage/ # ProtocolStore implementations +│ ├── hosted-admission/ # Hosted caller evidence contracts +│ ├── sdk/ # HTTP client and role clients +│ ├── cli/ # Command manifest and handlers +│ │ └── service-operator/ # Service-operator bootstrap (Phase 05) +│ ├── mcp/ # MCP catalog, resources, stdio +│ ├── surfaces/ # Product readbacks and proof packets +│ ├── x402-protected-tool/ # Packaged x402 facade export +│ └── install/ # Install proposal compiler helpers +├── test/ # Mirrors src ownership (no loose root tests) +├── docs/internal/ # Compact canonical docs + integrator parity +├── examples/ # Reference rooms and workflows +└── scripts/ # Release and proof-packet builders ``` ## Directory Purposes -**`src/`:** -- Purpose: Source-owned implementation of the protocol kernel and product surfaces. -- Contains: Protocol areas, HTTP transport, storage adapters, runtime ingress, adapters, SDK role clients, CLI, MCP, surfaces, installation helpers, conformance exports, x402 protected-tool helper. -- Key files: `src/index.ts`, `src/worker.ts`, `src/protocol/kernel.ts`, `src/http/app.ts` - **`src/protocol/`:** -- Purpose: Protocol authority kernel, state-machine areas, store port, navigation, utilities, and evidence projections. -- Contains: `src/protocol/areas/*`, `src/protocol/store/port.ts`, `src/protocol/evidence-projections/*`, `src/protocol/navigation.ts`, `src/protocol/utils/*` -- Key files: `src/protocol/kernel.ts`, `src/protocol/LANE.md` - -**`src/protocol/areas/`:** -- Purpose: Source-owned protocol primitives grouped by area. -- Contains: Action contract, catalog envelope, credential custody, delegated authority, gateway gate, policy greenlight, receipts, recovery, isolation, terminal certificate, and related transition modules. -- Key files: `src/protocol/areas/action-contract/schemas.ts`, `src/protocol/areas/policy-greenlight/transitions.ts`, `src/protocol/areas/gateway-gate/transitions.ts` +- Purpose: Authority state machine, schemas, transitions, store port, navigation metadata, failure taxonomy +- Contains: `kernel.ts`, `areas/*`, `foundation/*` (including `failure-class/`), `events/*`, `public/*`, `evidence-projections/*`, `navigation/*` +- Key files: `src/protocol/kernel.ts`, `src/protocol/navigation/index.ts`, `src/protocol/store/port.ts`, `src/protocol/foundation/failure-class/index.ts` +- Lane doc: `src/protocol/LANE.md` — must not import HTTP, SDK, adapters, storage impls, surfaces **`src/http/`:** -- Purpose: HTTP entry, route metadata, admission, handlers, OpenAPI helpers, and HTTP-facing navigation. -- Contains: `src/http/admission`, `src/http/routes`, `src/http/handlers`, `src/http/errors`, `src/http/openapi`, `src/http/store` -- Key files: `src/http/app.ts`, `src/http/admission/index.ts`, `src/http/routes/transition-route-registry.ts`, `src/http/routes/evidence-read-route-registry.ts` - -**`src/storage/`:** -- Purpose: Concrete protocol store implementations and Cloudflare storage integration. -- Contains: D1 store, in-memory store, KV helpers, and storage lane docs. -- Key files: `src/storage/d1/index.ts`, `src/storage/memory/index.ts`, `src/storage/store.ts` +- Purpose: Transport only — routes, admission, read-only handlers, OpenAPI, dual-enforcement guards +- Contains: `app.ts`, `mutation-route-manifest.ts`, `routes/`, `handlers/`, `admission/` (including `transition-sequence-matrix.ts`), `errors/`, `openapi/` +- Key files: `src/http/app.ts`, `src/http/mutation-route-manifest.ts`, `src/http/routes/transition-route-registry.ts`, `src/http/routes/transition-invokers.ts` +- Lane doc: `src/http/LANE.md` — handlers are read-only; no protocol meaning **`src/runtime/`:** -- Purpose: Proposal-only runtime ingress for generated execution observations. -- Contains: Ingress handler, family registry, runtime family definitions, posture checks. -- Key files: `src/runtime/ingress/index.ts`, `src/runtime/ingress/registry.ts`, `src/runtime/ingress/families.ts` +- Purpose: Observer/compiler lane for generated execution and ingress dispatch +- Contains: `ingress/`, `codemode-multi-action/`, per-family folders (`x402-payment/` via adapters, `package-install/`, etc.) +- Key files: `src/runtime/ingress/index.ts`, `src/runtime/ingress/families.ts` +- Lane doc: `src/runtime/LANE.md` — no policy, greenlight, gateway check, or mutation **`src/adapters/`:** -- Purpose: Adapter implementations that connect verified gateway checks to real mutation surfaces. -- Contains: x402 payment adapter and package-install adapter. -- Key files: `src/adapters/x402-payment/wallet-gateway.ts`, `src/adapters/package-install/gateway.ts` +- Purpose: Reference gateways and activation profiles; mutation after verified gate; gateway-held custody +- Contains: `x402-payment/` (`wallet-gateway.ts`), `x402-wallet-gateway/`, `package-install/`, `repo-write/`, `auth-md/`, `http-profile/`, etc. +- Key files: `src/adapters/x402-payment/wallet-gateway.ts`, `src/adapters/x402-payment/protected-tool-facade/index.ts` +- Lane doc: `src/adapters/LANE.md` — mutation only after `VerifiedGatewayCheck` + +**`src/storage/`:** +- Purpose: Persist protocol records and stream commits +- Contains: `memory/`, `d1/`, `kv/`, `store.ts` re-exports +- Key files: `src/storage/d1/index.ts`, `src/storage/memory/index.ts` +- Lane doc: `src/storage/LANE.md` **`src/sdk/`:** -- Purpose: Role-scoped clients and SDK entry points for product consumers. -- Contains: Role clients and SDK lane docs. -- Key files: `src/sdk/role-clients.ts`, `src/sdk/LANE.md` +- Purpose: Typed HTTP ergonomics; integrator-parity role clients; failure-class remediation +- Contains: `client.ts`, `surface-clients/`, `transport-url.ts`, `repair.ts` +- Key files: `src/sdk/client.ts`, `src/sdk/surface-clients/index.ts`, `src/sdk/repair.ts` +- Lane doc: `src/sdk/LANE.md` **`src/cli/`:** -- Purpose: CLI command contracts and command dispatch surfaces. -- Contains: Command manifest, CLI entry implementation, readback commands. -- Key files: `src/cli/command-manifest.ts`, `src/cli/index.ts`, `src/cli/LANE.md` +- Purpose: Local operator commands, evidence views, service-operator bootstrap, x402 install/doctor/simulate +- Contains: `main.ts`, `command-manifest.ts`, `service-operator/`, grouped subfolders (`x402/`, `evidence/`, `host/`, etc.) +- Key files: `src/cli/main.ts`, `src/cli/command-manifest.ts`, `src/cli/service-operator/bootstrap.ts` +- Lane doc: `src/cli/LANE.md` — evidence/posture only; command id `service.bootstrap` (aliases: `service bootstrap`) **`src/mcp/`:** -- Purpose: MCP server surface for product integration. -- Contains: Server descriptors, route/tool wiring, MCP package surface. -- Key files: `src/mcp/server.ts`, `src/mcp/server.json`, `src/mcp/LANE.md` +- Purpose: MCP tools/resources; stdio process in `mcp/stdio/`; FailureClass on tool outcomes +- Key files: `src/mcp/stdio/server.ts`, `src/mcp/catalog.ts`, `src/mcp/x402-proposal.ts`, `src/mcp/output.ts` +- Lane doc: `src/mcp/LANE.md` **`src/surfaces/`:** -- Purpose: Non-authority review/readback surface models. -- Contains: Review renderer models and surface posture helpers. -- Key files: `src/surfaces/LANE.md` - -**`src/install/`:** -- Purpose: Installation, registry, and package setup helpers. -- Contains: Install-related package and server metadata helpers. -- Key files: `src/install/LANE.md` - -**`src/adapter-sdk/`:** -- Purpose: Public adapter SDK definitions that support third-party adapter packs without giving them protocol authority. -- Contains: Definition-only adapter pack contracts and helpers. -- Key files: `src/adapter-sdk/index.ts`, `src/adapter-sdk/LANE.md` +- Purpose: Non-authority manifests, service workflow projections, A2A readback, proof packets, product-completion gates +- Key files: `src/surfaces/boundary-manifest.ts`, `src/surfaces/proof-packets/index.ts`, `src/surfaces/proof-packets/product-completion.ts` +- Lane doc: `src/surfaces/LANE.md` -**`src/conformance/`:** -- Purpose: Conformance package surface for protocol/adapters compatibility checks. -- Contains: Conformance exports and fixtures. -- Key files: `src/conformance/index.ts`, `src/conformance/LANE.md` +**`src/hosted-admission/`:** +- Purpose: Provider-neutral hosted caller identity and verifier adapter shapes +- Key files: `src/hosted-admission/hosted-caller-identity.ts`, `src/hosted-admission/hosted-verifier-adapter.ts` +- Exported via `./hosted-admission` package subpath only +- Lane doc: `src/hosted-admission/LANE.md` **`src/x402-protected-tool/`:** -- Purpose: Narrow package surface for x402 protected-tool helpers. -- Contains: Tool helper exports and lane documentation. -- Key files: `src/x402-protected-tool/index.ts`, `src/x402-protected-tool/LANE.md` +- Purpose: Stable npm subpath for x402 protected-tool facade and host activation descriptors +- Re-exports from `src/adapters/x402-payment/` and `src/surfaces/` +- Lane doc: `src/x402-protected-tool/LANE.md` **`test/`:** -- Purpose: Verification suite for protocol invariants, architecture boundaries, product claims, examples, and integrations. -- Contains: `test/architecture`, `test/product`, `test/smoke`, `test/integration`, plus focused protocol and package tests. -- Key files: `test/architecture/import-posture.test.ts`, `test/architecture/package-surface.test.ts`, `test/architecture/surface-boundary-posture.test.ts` - -**`examples/`:** -- Purpose: Runnable demonstrations with checked source and ignored generated output. -- Contains: Example READMEs, `run.mjs` scripts, TypeScript helpers, and `output/.gitignore` files. -- Key files: `examples/x402-full-chain/run.mjs`, `examples/external-adapter-sdk/run.mjs`, `examples/x402-protected-tool/README.md` - -**`scripts/`:** -- Purpose: Repository quality, architecture, claims, package, docs, and example-output gates. -- Contains: Node scripts invoked from `package.json`. -- Key files: `scripts/check-architecture-docs.mjs`, `scripts/check-claims.mjs`, `scripts/check-package-surface.mjs`, `scripts/check-example-outputs.mjs` - -**`docs/internal/`:** -- Purpose: Tracked canonical product and architecture decisions. -- Contains: Decision log, protocol notes, protocol definition, protocol kernel architecture, and focused internal docs. -- Key files: `docs/internal/decisions.md`, `docs/internal/protocol-notes.md`, `docs/internal/protocol-definition.md`, `docs/internal/protocol-kernel-architecture.md` - -**`.planning/codebase/`:** -- Purpose: GSD scratch codebase maps for planner/executor agents. -- Contains: Generated architecture, structure, stack, testing, convention, concern, and integration maps. -- Key files: `.planning/codebase/ARCHITECTURE.md`, `.planning/codebase/STRUCTURE.md` +- Purpose: Guard architecture, protocol invariants, integration E2E, product readbacks, dual-enforcement +- Layout: One subdirectory per concern; no `test/*.test.ts` at root +- Key architecture tests: `test/architecture/http-handler-mutation-gating.test.ts`, `test/architecture/dual-enforcement-posture.test.ts`, `test/architecture/integrator-parity.test.ts`, `test/architecture/import-posture.test.ts` ## Key File Locations **Entry Points:** -- `src/worker.ts`: Cloudflare Worker fetch entry that delegates to the HTTP app. -- `src/http/app.ts`: Hono app factory and transport entry for transition/read routes. -- `src/index.ts`: Curated public root package exports. -- `src/experimental.ts`: Explicit experimental exports and reference fixtures. -- `bin/handshake.js`: Package CLI entry shim. +- `src/index.ts`: Public package surface (app factory, SDK, schemas, verifier helpers) +- `src/worker.ts`: Deployed Worker → `createApp()` +- `src/cli/main.ts`: `runCliCommand()` dispatch +- `src/mcp/stdio/server.ts`: `createHandshakeMcpStdioServer()` +- `bin/handshake`, `bin/handshake-mcp`: Thin Node launchers **Configuration:** -- `package.json`: Scripts, package exports, package files, dependency list. -- `tsconfig.json`: TypeScript compiler settings. -- `vitest.config.ts`: Test runner configuration. -- `wrangler.toml`: Cloudflare Worker and D1 binding configuration. -- `.github/workflows/check.yml`: CI quality gate. +- `package.json`: Version 0.2.7, exports, engine, test scripts +- `wrangler.toml`: Worker name, D1/KV bindings +- `migrations/`: D1 tables for protocol storage +- `server.json`: MCP registry discoverability metadata (proof gap until verified) **Core Logic:** -- `src/protocol/kernel.ts`: Protocol transition facade. -- `src/protocol/store/port.ts`: Store interface between protocol and persistence. -- `src/protocol/areas/action-contract/*`: Exact action contract records and transitions. -- `src/protocol/areas/policy-greenlight/*`: Policy decision and one-use greenlight records. -- `src/protocol/areas/gateway-gate/*`: Gateway enforcement transition and verified gateway artifacts. -- `src/protocol/areas/delegated-authority/*`: Principal-agent-runtime delegated authority references and status. -- `src/protocol/areas/credential-custody/*`: Gateway credential references and custody proof packets. -- `src/runtime/ingress/*`: Proposal-only runtime observation compiler. -- `src/adapters/x402-payment/wallet-gateway.ts`: Official x402 buyer-side signing gateway after verification. -- `src/adapters/package-install/gateway.ts`: Package-install gateway execution after verification. - -**Read Models and Projections:** -- `src/protocol/evidence-projections/projections.ts`: Redacted contract/timeline/readback projection helpers. -- `src/protocol/evidence-projections/assembly.ts`: Transaction envelope assembly from protocol records. -- `src/http/routes/evidence-read-route-registry.ts`: Evidence read route contracts, scopes, and role requirements. -- `src/http/handlers/evidence-read.ts`: Evidence projection HTTP handler. -- `src/http/handlers/internal-record-read.ts`: Raw/internal record read guardrails. - -**Admission and Routing:** -- `src/http/admission/index.ts`: Transition, evidence-read, hosted verifier, and raw/readiness admission checks. -- `src/http/routes/transition-route-registry.ts`: Transition route metadata and custody roles. -- `src/http/routes/transition-invokers.ts`: Route ID to kernel method mapping. - -**Persistence:** -- `src/storage/memory/index.ts`: In-memory store with conflict/idempotency semantics. -- `src/storage/d1/index.ts`: D1-backed store implementation. -- `src/storage/store.ts`: Store construction from environment. -- `migrations/0001_protocol_kernel.sql`: Durable D1 schema. +- `src/protocol/kernel.ts`: All transition methods +- `src/protocol/areas/gateway-gate/transitions.ts`: Gateway enforcement transition +- `src/protocol/areas/policy-greenlight/transitions.ts`: Policy / greenlight +- `src/protocol/areas/intent-compilation/candidate-decision.ts`: CandidateAction derivation +- `src/protocol/areas/action-contract/transitions.ts`: Contract proposal +- `src/protocol/foundation/failure-class/index.ts`: Cross-surface failure taxonomy +- `src/http/mutation-route-manifest.ts`: Frozen POST inventory + parity guard +- `src/http/admission/transition-sequence-matrix.ts`: Prerequisite route matrix +- `src/http/routes/transition-invokers.ts`: HTTP → kernel wiring +- `src/adapters/x402-payment/wallet-gateway.ts`: Gateway-held signing custody (D-64) **Testing:** -- `test/architecture/import-posture.test.ts`: Lane, import, authority, projection, storage, and signer boundary checks. -- `test/architecture/root-exports.test.ts`: Public root export restrictions. -- `test/architecture/package-surface.test.ts`: Packed package file and export restrictions. -- `test/architecture/surface-boundary-posture.test.ts`: Surface authority posture checks. -- `test/product/*`: Product behavior and example-output expectations. +- `test/protocol/`: Kernel and area unit tests +- `test/http/`: Route and admission tests +- `test/integration/`: D1/HTTP E2E (e.g. `x402-d1-http.test.ts`) +- `test/architecture/`: Import posture, CLI manifest, dual-enforcement, integrator parity, mutation gating +- `test/adapters/`: Gateway fixture and activation tests (including `x402-wallet-gateway.test.ts`) +- `test/product/`: A2A readback and hosted consumer scenarios +- `test/sdk/role-clients-walkthrough.test.ts`: Integrator parity client composition ## Naming Conventions **Files:** -- Protocol areas use lowercase kebab-case directories with explicit implementation files: `src/protocol/areas/gateway-gate/transitions.ts`, `src/protocol/areas/action-contract/schemas.ts`. -- Each first-level source lane has a `LANE.md` file: `src/protocol/LANE.md`, `src/http/LANE.md`, `src/runtime/LANE.md`. -- Tests use `*.test.ts` and live under a semantic test directory: `test/architecture/import-posture.test.ts`, `test/product/x402-demo-output.test.ts`. -- Example runners use `run.mjs`: `examples/external-adapter-sdk/run.mjs`, `examples/x402-full-chain/run.mjs`. -- Scripts use descriptive kebab-case `.mjs` names: `scripts/check-package-surface.mjs`. +- Area modules: `transitions.ts`, `schemas.ts`, `inputs.ts`, `guards.ts`, `index.ts` under `src/protocol/areas//` +- HTTP: `*-route-registry.ts`, `transition-invokers.ts`, `*-scope-resolvers.ts`, `mutation-route-manifest.ts` under `src/http/` +- Tests: `*.test.ts` colocated under `test//` matching `src//` +- Lane docs: `LANE.md` at first-level `src/*` folders (authority owner, allowed/forbidden imports) **Directories:** -- Protocol source directories are domain names, not stage labels: `src/protocol/areas/policy-greenlight`, `src/protocol/areas/gateway-gate`. -- Transport directories are responsibility names: `src/http/admission`, `src/http/routes`, `src/http/handlers`. -- Adapter directories name protected-action families: `src/adapters/x402-payment`, `src/adapters/package-install`. -- Test directories name verification class: `test/architecture`, `test/product`, `test/smoke`, `test/integration`. +- Protocol primitives: `src/protocol/areas//` +- Adapters by proof profile: `src/adapters//` +- CLI by command group: `src/cli//` (e.g. `x402/`, `service-operator/`, `host/`) +- Surfaces by product readback: `src/surfaces//` -**Symbols:** -- Public experimental exports must be named with `experimental*` or `Experimental*` from `src/experimental.ts`. -- Authority-bearing symbols should keep exact domain names such as `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheckAttempt`, `VerifiedGatewayCheck`, `DelegatedAuthorityRef`, and `GatewayCredentialRef`. -- Do not introduce broad names such as `Passport`, `Session`, `Approval`, or `Auth` as authority records unless they map to an existing exact protocol primitive. +**Types and IDs:** +- Digest fields: `sha256:` (see gateway and contract code) +- Version literals: `handshake...v1` style constants per module +- Action class wedge: `x402_payment.exact` in contracts and integration fixtures +- FailureClass evidence refs (MCP): `taxonomy:failureClass/` via `mcpFailureClassEvidenceRef` ## Where to Add New Code -**New Protocol Primitive:** -- Primary code: `src/protocol/areas//` -- Required files: `schemas.ts`, `inputs.ts` when needed, `transitions.ts`, `index.ts`, and focused helper modules. -- Kernel wiring: `src/protocol/kernel.ts` -- Store impact: `src/protocol/store/port.ts`, `src/storage/memory/index.ts`, `src/storage/d1/index.ts`, `migrations/0001_protocol_kernel.sql` if durable state changes. -- Tests: focused protocol tests plus `test/architecture/import-posture.test.ts` updates when import posture changes. - -**New Gateway-Enforced Action Family:** -- Primary code: existing or new protocol records under `src/protocol/areas/*`; gateway logic under `src/adapters//gateway.ts`. -- Runtime proposal support: `src/runtime/ingress/families.ts`, `src/runtime/ingress/registry.ts`, `src/runtime/ingress/index.ts` if the family can be detected from runtime observations. -- HTTP route support: `src/http/routes/transition-route-registry.ts`, `src/http/routes/transition-invokers.ts` if a new transition is needed. -- Tests: adapter tests, protocol gateway tests, product demo tests, and architecture boundary tests. - -**New Projection or Read Model:** -- Primary code: `src/protocol/evidence-projections/` -- HTTP route: `src/http/routes/evidence-read-route-registry.ts` -- Handler: `src/http/handlers/evidence-read.ts` or `src/http/handlers/internal-record-read.ts` -- Tests: projection tests and `test/architecture/import-posture.test.ts` to keep read models out of authority imports. - -**Passport/Admission/Service Gateway Simplification:** -- Passport readback should be added as a projection over `ParticipantIdentityBinding`, `OperatingEnvelope`, `ActionContract`, `DelegatedAuthorityRef`, `GatewayRegistryEntry`, and `GatewayCredentialRef`. -- Admission changes belong in `src/http/admission/index.ts` and route metadata under `src/http/routes/*`; they must not create greenlights or mutation authority. -- Service gateway language should map to `src/protocol/areas/catalog-envelope/schemas.ts`, `src/protocol/areas/credential-custody/*`, `src/protocol/areas/gateway-gate/*`, and adapter gateway files before adding new protocol state. -- Principal-agent link changes belong in `src/protocol/areas/catalog-envelope/schemas.ts`, `src/protocol/areas/action-contract/schemas.ts`, and `src/protocol/areas/delegated-authority/schemas.ts`. - -**New CLI Command:** -- Primary code: `src/cli/` -- Command contract: `src/cli/command-manifest.ts` -- Tests: CLI/product tests plus architecture checks if command claims authority. - -**New MCP Tool:** -- Primary code: `src/mcp/` -- Public package/server metadata: `src/mcp/server.json`, `package.json` exports if needed. -- Tests: MCP/package-surface tests and claim-boundary tests. - -**New SDK Client Capability:** -- Primary code: `src/sdk/role-clients.ts` -- Package export: `package.json` subpath export if public. -- Tests: SDK tests plus `test/architecture/root-exports.test.ts` and `test/architecture/package-surface.test.ts` when exports change. - -**New Example:** -- Primary code: `examples//` -- Output posture: generated outputs under `examples//output/` with only `.gitignore` tracked unless product tests require fixtures. -- Tests: `test/product/*` and `scripts/check-example-outputs.mjs` updates when generated output contracts matter. - -**Utilities:** -- Protocol-only utilities: `src/protocol/utils/` -- HTTP-only utilities: `src/http/` -- Script-only utilities: `scripts/` -- Do not place shared authority logic in examples, CLI, MCP, SDK, or surfaces. +**New protocol transition or record type:** +- Schemas/inputs: `src/protocol/areas//` (or extend existing area) +- Transition implementation: `src/protocol/areas//transitions.ts` +- Register on kernel: `src/protocol/kernel.ts` +- Navigation metadata (+ integrator-parity tag if applicable): `src/protocol/navigation/index.ts` +- Public aggregation: `src/protocol/public/schemas.ts` and `inputs.ts` +- Failure classification: extend `src/protocol/foundation/reason-codes.ts` if new reason codes +- HTTP route: `src/http/routes/transition-route-registry.ts` + invoker in `transition-invokers.ts` +- Mutation manifest row: `src/http/mutation-route-manifest.ts` (`routeFamilyById` + `requiresAdapterGatewayCheck: true`) +- Sequence matrix entry: `src/http/admission/transition-sequence-matrix.ts` +- Tests: `test/protocol/.test.ts`, update `test/protocol/transition-matrix.test.ts` if applicable + +**New HTTP evidence read route:** +- Handler logic: `src/http/handlers/evidence-read.ts` or dedicated handler (must stay on read-only allowlist) +- Registry: `src/http/routes/evidence-read-route-registry.ts` +- Projection source: `src/protocol/evidence-projections/` +- Tests: `test/http/`, update `test/architecture/http-handler-mutation-gating.test.ts` allowlist if new handler file + +**New runtime ingress family (generated execution):** +- Family config schema: `src/runtime/ingress/families.ts` and `schemas.ts` +- Adapter proposal config: `src/adapters//action-proposal.ts` +- Wire in `RuntimeIngressConfigSchema` in `src/runtime/ingress/index.ts` +- Tests: `test/runtime/` and integration under `test/integration/` + +**New reference gateway / adapter proof profile:** +- Implementation: `src/adapters//` +- Export `run*Gateway` runner; keep mutation behind post-`gatewayCheck` helpers +- Do not import from `src/protocol/areas` transitions into HTTP handlers +- Conformance (optional): `src/conformance//` +- Tests: `test/adapters/`, `test/integration/` +- If example runner mutates: add to `mutationExampleRunners` in `test/architecture/http-handler-mutation-gating.test.ts` +- Experimental export only if intentional: `src/experimental.ts` + +**New CLI command:** +- Handler: `src/cli//.ts` +- Manifest entry: `src/cli/command-manifest.ts` +- Dispatch branch: `src/cli/main.ts` +- Tests: `test/cli/cli-*.test.ts`, `test/architecture/cli-command-posture.test.ts` + +**New service-operator command:** +- Place under `src/cli/service-operator/` (not legacy host-only naming for service API lane) +- Follow `service.bootstrap` pattern in `src/cli/command-manifest.ts` +- Reference: `docs/internal/service-operator-runbook.md`, `docs/internal/golden-paths/service-operator-golden-path.md` + +**New MCP tool or resource:** +- Tool/resource definition: `src/mcp/catalog.ts`, `src/mcp/resources.ts` +- FailureClass wiring: `src/mcp/output.ts` via `classifyFailureClassFromReasonCodes` +- Stdio registration: `src/mcp/stdio/server.ts` +- Tests: `test/mcp/` + +**New SDK surface client:** +- Client module: `src/sdk/surface-clients/.ts` +- Export: `src/sdk/surface-clients/index.ts` +- Boundary row: `src/surfaces/boundary-manifest.ts` +- Integrator parity table (if operator TTHW): `docs/internal/integrator-parity-transitions.md` +- Tests: `test/sdk/`, `test/architecture/integrator-parity.test.ts` if parity transition + +**New product readback / proof packet:** +- Projection assembler: `src/surfaces//` +- Must not call kernel transitions that create greenlights or gateway checks +- Tests: `test/product/` or `test/architecture/proof-packets.test.ts` + +**New storage backend or index:** +- Implement `ProtocolStore` in `src/storage//` +- Resolve in `src/http/store/resolution.ts` +- Schema migration in `migrations/` if D1 +- Tests: `test/storage/` + +**New hosted admission field:** +- Types/adapters: `src/hosted-admission/` +- HTTP admission wiring: `src/http/admission/hosted-verifier-adapter.ts`, `hosted-caller-identity.ts` +- FailureClass: ensure `hosted_admission` / `stale_admission` classification in `src/protocol/foundation/failure-class/index.ts` +- Tests: `test/http/hosted-identity-evidence.test.ts` (or adjacent) ## Special Directories +**`.planning/`:** +- Purpose: GSD scratch (codebase maps, phase plans) — gitignored but force-addable for agent artifacts +- Generated: By planning agents +- Committed: Optional; not canonical over repo `STRUCTURE.md` / `docs/internal/` / tests + +**`docs/internal/`:** +- Purpose: Compact protocol and product decisions, operator runbooks, integrator parity +- Key: `docs/internal/decisions.md`, `docs/internal/integrator-parity-transitions.md`, `docs/internal/service-operator-runbook.md`, `docs/internal/host-operator-runbook.md` +- Committed: Yes — canonical with source and CI + +**`examples/`:** +- Purpose: Reference rooms (e.g. `examples/service-operator-bootstrap/`), x402 spend, external-adapter-sdk +- Committed: Yes — not imported by kernel at runtime; mutation runners guarded by architecture tests + +**`scripts/`:** +- Purpose: Release proof, publish handoff, product-completion checks (`scripts/check-product-completion.mjs`) +- Committed: Yes — invoked from `package.json` scripts + **`dist/`:** -- Purpose: Build output published by package scripts. -- Generated: Yes -- Committed: No +- Purpose: Built ESM output for npm +- Generated: Yes (`npm run build`) +- Committed: No (publish artifact) -**`examples/*/output/`:** -- Purpose: Generated demo packets such as JSON/Markdown readbacks. -- Generated: Yes -- Committed: Only `.gitignore` files are tracked unless a test deliberately adds a stable fixture. +## Test Placement Rules -**`.planning/`:** -- Purpose: GSD scratch plans and codebase maps. -- Generated: Yes -- Committed: Some codebase maps may be tracked, but they are not canonical product truth. +- Mirror `src/` lane under `test//` +- Architecture invariants: `test/architecture/` (import posture, exports, CLI manifest, dual-enforcement, mutation gating, integrator parity) +- End-to-end with D1: `test/integration/` +- Never add loose `test/foo.test.ts` at repository root -**`docs/internal/`:** -- Purpose: Durable product, protocol, and architecture canon. -- Generated: No -- Committed: Yes +## Dual-Enforcement Maintenance Checklist + +When adding service API surface area (Phase 04–05 carry-forward): + +1. Add POST transition to `src/http/routes/transition-route-registry.ts` + invoker +2. Mirror row in `src/http/mutation-route-manifest.ts` with `requiresAdapterGatewayCheck: true` +3. Add prerequisite entry to `src/http/admission/transition-sequence-matrix.ts` +4. Keep handlers read-only; mutation stays in adapters after `run*Gateway` +5. Update `docs/internal/service-operator-runbook.md` if operator-facing +6. Run `test/architecture/http-handler-mutation-gating.test.ts` and `test/architecture/dual-enforcement-posture.test.ts` + +## Package Subpath Guidance + +When exposing new public API, add an `exports` entry in `package.json` and a built file under `dist/`. Curate `src/index.ts` only for core kernel/HTTP/SDK surface. Keep adapter fixtures on `./experimental` or dedicated subpaths — not the default import. Integrator-parity clients export via `./sdk/role-clients`. + +## Folder Discipline (from repo `STRUCTURE.md`) + +- More than three TypeScript files in a folder → add `index.ts` public face +- No more than seven loose `.ts` files per folder (excluding `index.ts`) +- New protocol areas live under `src/protocol/areas/*`, not loose files under `src/protocol/` +- Each first-level `src/*` lane should maintain `LANE.md` with authority owner and forbidden imports +- Kernel must not depend on surfaces; surfaces create no authority — dependency flows inward toward `src/protocol/` + +## LANE.md Boundary Convention -**`migrations/`:** -- Purpose: Durable D1 schema for protocol storage. -- Generated: No -- Committed: Yes +Fifteen lane docs under `src/*/LANE.md` (and `src/protocol/areas/negotiation/LANE.md`) define: -**`.github/workflows/`:** -- Purpose: Repository CI quality gates. -- Generated: No -- Committed: Yes +| Field | Purpose | +|-------|---------| +| Authority owner | What this lane may decide or enforce | +| Current proof claim | Honest scope of what the lane proves | +| Allowed imports | Upstream dependencies permitted | +| Forbidden imports | Lanes that would create authority leakage | +| Guarding tests | Architecture tests that enforce the boundary | +| Public surface | What npm subpaths or bins expose | -**`.gstack/`, `.strategy/`, `.cursor/`:** -- Purpose: Local agent/tooling metadata if present. -- Generated: Yes -- Committed: No current tracked files detected. +Authority enforcement for protected mutation always terminates at `src/protocol/areas/gateway-gate/transitions.ts`; adapters execute only after that transition passes. --- -*Structure analysis: 2026-05-25* +*Structure analysis: 2026-05-29* diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md index 8e742f8..7f4476c 100644 --- a/.planning/codebase/TESTING.md +++ b/.planning/codebase/TESTING.md @@ -1,262 +1,330 @@ # Testing Patterns -**Analysis Date:** 2026-05-25 +**Analysis Date:** 2026-05-29 ## Test Framework **Runner:** -- Bun test through `bun test`. -- Package manager/runtime declared in `package.json`: `bun@1.3.9`, Node engine `>=20`. -- Config: no separate `bunfig.toml` or Vitest/Jest config detected. Test behavior is driven by `package.json`, TypeScript settings in `tsconfig.json`, and source/test imports. +- Bun built-in test (`bun:test`) — no Jest or Vitest config present. +- Config: implicit; `package.json` `"test": "bun test"`. +- TypeScript for tests uses root `tsconfig.json` (`include`: `src`, `test`). -**Assertion Library:** -- `bun:test` provides `describe`, `it`, and `expect`. -- Common matchers include `toBe`, `toEqual`, `toMatchObject`, `toContain`, `toHaveLength`, `toThrow`, `rejects.toThrow`, and Bun-specific matchers such as `toBeFunction()` and `toBeString()`. +**Assertion library:** +- Bun `expect` (Jest-compatible matchers: `toEqual`, `toMatchObject`, `toThrow`, `toContain`, `rejects`). + +**Run commands:** + +```bash +bun test # all tests +npm test # alias via package.json +npm run check:types # tsc --noEmit +npm run lint # eslint src test --max-warnings=0 +npm run format:check # prettier --check . +npm run check:repo # build + types + lint + format + test + pack:check + git diff --check +``` + +**Focused quality slices (`package.json`):** + +```bash +npm run quality:architecture # import/naming/surface/cli/mcp/conformance posture +npm run quality:storage # D1/http + kernel invariants + evidence projections +npm run quality:claims # active vocabulary + claim boundary +``` + +Local fast slice from `QUALITY.md`: + +```bash +npm run check:types +bun test +git diff --check +``` + +**Phase 04 service-agent gating scripts** (`scripts/check-service-agent-gating-phase.mjs`): + +```bash +npm run check:service-agent-gating-phase # operator tier — 10 tests +npm run check:service-agent-gating-phase:full # full tier — 15 tests (10 + 5) +``` + +| Tier | Flag | Count | Suite | +|------|------|-------|-------| +| operator | `--tier operator` | 10/10 | Operator product completion, dual enforcement, failure-class HTTP/SDK/MCP, bootstrap, golden path, proof-gap honesty, custody matrix, HTTP mutation gating | +| full | `--tier full` | 15/15 | Operator suite plus maintainer completion, integrator parity, HTTP profile canonicalization/orphan catalog, CLI agent-spine sequencer | + +Operator tier files (always run): + +1. `test/architecture/operator-product-completion-contract.test.ts` +2. `test/architecture/dual-enforcement-posture.test.ts` +3. `test/http/transition-error-failure-class.test.ts` +4. `test/product/service-operator-bootstrap.test.ts` +5. `test/integration/service-operator-golden-path.test.ts` +6. `test/architecture/proof-gap-honesty.test.ts` +7. `test/architecture/custody-matrix-parity.test.ts` +8. `test/architecture/http-handler-mutation-gating.test.ts` +9. `test/sdk/role-clients-failure-class.test.ts` +10. `test/mcp/mcp-failure-class-parity.test.ts` + +Full-tier additions: + +11. `test/architecture/maintainer-product-completion-contract.test.ts` +12. `test/architecture/integrator-parity.test.ts` +13. `test/adapters/http-profile-canonicalization.test.ts` +14. `test/adapters/http-profile-orphan-catalog.test.ts` +15. `test/cli/cli-agent-spine-sequencer.test.ts` + +Verified at HEAD `aef9478` (branch `phase-05-product-coherence`): both tiers pass. + +## Known Acceptable Residual Failures + +When running the full `bun test` suite locally, these structural-guard tests may fail for environmental or baseline reasons without blocking phase closeout: + +| Test file | Failing case(s) | Cause | Mitigation | +|-----------|-----------------|-------|------------| +| `test/architecture/naming-posture.test.ts` | `keeps workspace metadata junk out of active repo surfaces` | Local `.DS_Store` files under repo tree | Delete junk files or add to global gitignore; not a source defect | +| `test/architecture/naming-posture.test.ts` | `keeps deleted scratch documents out of the active tree` | Local `.agents/` or `skills-lock.json` present | Remove untracked scratch; `STRUCTURE.md` marks these as non-canon | +| `test/architecture/manifest-coverage.test.ts` | `maps each product surface export to a manifest surface with matching sourceRoots` | Pre-existing baseline: expects `./hosted-admission` and `./surfaces/service-workflow-admission` exports not yet in `package.json` | Track as manifest/export drift; other manifest-coverage cases pass | + +**Timeout note:** `test/architecture/release-repository-projection.test.ts` spawns `scripts/project-release-repository.js` (~1.6s isolated). It can time out when run inside the full parallel suite but passes in isolation: -**Run Commands:** ```bash -npm run test # Run all Bun tests -npm run test -- test/path.test.ts # Run one focused test file -npm run quality:claims # Claim-boundary language gate -npm run quality:architecture # Naming, imports, exports, surface posture, conformance gate -npm run quality:storage # Storage/kernel invariant slice -npm run check:repo # Full repo gate +bun test test/architecture/release-repository-projection.test.ts ``` ## Test File Organization **Location:** -- Tests are separate from source under `test/**`. -- Test support code lives under `test/support/**`. -- Root `test/*.test.ts` files are forbidden by `test/architecture/naming-posture.test.ts`. +- All tests live under `test/` in domain subfolders — never at `test/*.test.ts` root (enforced in `test/architecture/naming-posture.test.ts`). -**Naming:** -- Test files use `*.test.ts`. -- Test names describe the boundary or failure mode, not just the implementation path. Examples: `test/architecture/claim-boundary.test.ts`, `test/protocol/kernel-policy-gateway.test.ts`, `test/runtime/runtime-ingress.test.ts`, `test/adapters/x402-wallet-gateway.test.ts`. +**Directory layout:** -**Structure:** ```text test/ - architecture/ # claim, naming, import, export, package, surface, CLI, MCP gates - protocol/ # kernel state machine, canonicalization, policy, gateway, evidence, isolation - runtime/ # generated-execution proposal helpers and runtime ingress - adapters/ # reference gateway fixtures and adapter profiles - http/ # Hono/D1 route and store behavior - integration/ # D1/HTTP end-to-end protected action paths - mcp/ # proposal/evidence schema and resource contracts - cli/ # operator/evidence/local readiness command posture - product/ # demo/readback and acceptance packet contracts - conformance/ # adapter conformance checks - sdk/ # role-scoped clients - adapter-sdk/ # definition-only adapter authoring surface - support/ # fixtures, fakes, local harnesses, invariant helpers + architecture/ # repo structure, imports, naming, claims, package surface + protocol/ # kernel transitions, schemas, invariants, negotiation + http/ # Hono app, D1 HTTP harness, hosted identity + cli/ # CLI command envelopes and evidence views + mcp/ # MCP catalog, schema contract, stdio process + adapters/ # gateway fixtures, x402/auth-md activation probes + runtime/ # generated-execution proposal helpers + integration/ # end-to-end flows across HTTP + adapters + product/ # product-surface slices (A2A, demos, acceptance) + conformance/ # reference posture checks for adapters/x402 + sdk/ # HandshakeClient and role-scoped surface clients + storage/ # KV/isolation cache mechanics + adapter-sdk/ # public adapter SDK definitions + support/ # shared fixtures and harnesses (not test cases) ``` -There are 98 `*.test.ts` files under `test/**`. - -## Test Structure +**Naming:** +- Files: `-.test.ts` or `.test.ts`. +- One primary `describe` per guarded boundary; multiple `it` cases per invariant. -**Suite Organization:** -```typescript -import { describe, expect, it } from "bun:test"; -import { makeKernelFixture, registerFixtureObjects } from "../support/fixtures"; - -describe("runtime ingress adapter", () => { - it("observes supported dispatch and proposes a contract without policy or gateway authority", async () => { - const fixture = makeKernelFixture(); - await registerFixtureObjects(fixture); - - const result = await proposeRuntimeIngressActionContracts(/* ... */); - - expect(result.responsePosture).toMatchObject({ - authorityCreated: false, - greenlightCreated: false, - gatewayCheckPerformed: false, - mutationAttempted: false, - }); - expect(await recordCount(fixture.store, "greenlight")).toBe(0); - }); -}); -``` +## Architecture / Structural Guard Suites -**Patterns:** -- Build a fixture, register source-owned catalog/envelope/gateway objects, exercise one transition, then assert both returned posture and durable record counts. -- Use `makeKernelFixture()`, `registerFixtureObjects()`, `createGreenlitContract()`, `recordSafeBypassProbes()`, and `proposalInputForCompilation()` from `test/support/fixtures.ts` for kernel tests. -- Use local harnesses for integration boundaries: `createD1HttpHarness()` in `test/support/d1-http-harness.ts`, `createPackageManifestSurface()` in `test/support/package-install-flow.ts`, and `createRepoWriteSurface()` in `test/support/repo-write-flow.ts`. -- Assert negative space directly: no policy decision, no greenlight, no gateway check, no mutation attempt, no signer use, no raw credential material, no receipt export, no hosted/broad claims. +These tests act as repo posture enforcement — not unit tests of runtime behavior. They walk the filesystem, parse manifests, and compare against frozen allowlists. -## Mocking +### Claim and doctrine (`test/architecture/claim-boundary.test.ts`) -**Framework:** No dedicated mocking library is used. +- **`expectClaimMatrix`** — normalizes canonical doc text and asserts required phrases and forbidden patterns with exact phrasing. +- Required product/protocol language includes: `cleared protected-action event`, `protocol kernel`, `product surface`, `public npm availability does not create authority`, `MCP Registry discoverability remains a proof gap`, certificate-is-terminal-evidence-not-permission patterns. +- Validates root vs `./adapter-sdk` vs `./runtime` vs `./conformance` vs `./experimental` export separation (no authority symbols at root). +- Scans `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, `docs/internal/*`, lane manifests, and example READMEs. -**Patterns:** -```typescript -const store = new FaultInjectingProtocolStore(new InMemoryProtocolStore()); -store.hideListRecordsByTypeOnce("greenlight"); +Companion: `test/architecture/active-vocabulary.test.ts` (run via `quality:claims`). -const duplicate = await fixture.kernel.evaluatePolicy({ - actionContractId: fixture.contract.actionContractId, - envelopeId: fixture.envelope.envelopeId, -}); +### Package and export surface -expect(duplicate.decision.decisionReasonCode).toBe("idempotency_duplicate_authority"); -``` +| File | Guards | +|------|--------| +| `test/architecture/package-surface.test.ts` | `package.json` exports, bins, MCP name, no `./surfaces` barrel, publishable posture | +| `test/architecture/root-exports.test.ts` | Frozen sorted export list from `src/index.ts` | +| `test/architecture/manifest-coverage.test.ts` | Maps `package.json` exports and CLI handler files to `src/surfaces/boundary-manifest.ts` `sourceRoots` | +| `test/architecture/hosted-admission-reexport-only.test.ts` | Hosted admission subpath curation | -**What to Mock:** -- Use fakes at system boundaries, not inside the protocol state machine. -- Storage faults are modeled by `FaultInjectingProtocolStore` in `test/support/fault-injecting-protocol-store.ts`. -- D1 is modeled by a local Bun SQLite-backed `LocalD1Database` inside `test/support/d1-http-harness.ts`. -- Filesystem mutation surfaces are modeled by test surfaces such as `FilePackageManifestSurface` in `test/support/package-manifest-surface.ts` and repo-write helpers in `test/support/repo-write-surface.ts`. -- x402 signer behavior is modeled with tracked signing surfaces in `test/adapters/x402-wallet-gateway.test.ts`, while official signer imports stay constrained to `src/adapters/x402-payment/wallet-gateway.ts`. +### Naming and planning quarantine -**What NOT to Mock:** -- Do not mock `HandshakeKernel` transitions when asserting protocol authority behavior. Use the real kernel with `InMemoryProtocolStore`, `D1ProtocolStore`, or `FaultInjectingProtocolStore`. -- Do not mock away gateway checks in adapter tests. Conformance tests in `test/conformance/protected-mutation-adapter-conformance.test.ts` must prove adapters do not mutate without `VerifiedGatewayCheck`. -- Do not mock public surface manifests or package exports. Architecture tests import actual `src/**`, `package.json`, and `server.json`. +| File | Guards | +|------|--------| +| `test/architecture/naming-posture.test.ts` | Banned bucket segments, loose-file limits, `index.ts` public faces, Tier/stage label ban, `.DS_Store` junk, deleted scratch paths, overclaiming/vague protocol verbs, CI pinned to `npm run check:repo` | +| `test/architecture/planning-scratch-quarantine.test.ts` | D-62: macro-plan/concierge markers must not appear in scripts, README, `src/`, `test/`, `docs/` | +| `test/architecture/canonical-doc-forbidden-copy.test.ts` | Forbidden legacy doc paths in canon | -## Fixtures and Factories +### Import and lane posture -**Test Data:** -```typescript -export function makeKernelFixture() { - const store = new InMemoryProtocolStore(); - const kernel = new HandshakeKernel(store); - const createdAt = nowIso(); +| File | Guards | +|------|--------| +| `test/architecture/import-posture.test.ts` | LANE.md field completeness, transport off protocol internals, removed compatibility shims | +| `test/architecture/surface-boundary-posture.test.ts` | `boundary-manifest.ts` completeness, non-authority flags, forbidden authority routes | +| `test/architecture/cli-command-posture.test.ts` | CLI manifest alignment | +| `test/architecture/cli-non-authority-copy.test.ts` | CLI must not claim authority (D-60) | +| `test/architecture/mcp-surface-posture.test.ts` | MCP catalog posture | +| `test/architecture/negotiation-no-authority-surface.test.ts` | Negotiation area isolation from gateway/policy imports | - const tool: ToolCapability = { /* wrapped consequential tool */ }; - const actionType: ActionType = { /* package.install action type */ }; - const gateway: GatewayRegistryEntry = { /* customer gateway adapter */ }; - const envelope: OperatingEnvelope = { /* allowed action/resource bounds */ }; +### Authority boundary and bypass - return { store, kernel, tool, actionType, gateway, envelope }; -} -``` +| File | Guards | +|------|--------| +| `test/adapters/x402-bypass-probes.test.ts` | Hostile bypass probe executors; policy greenlight only after gateway-owned probes pass | +| `test/architecture/http-handler-mutation-gating.test.ts` | HTTP handlers cannot mutate without gating | +| `test/architecture/dual-enforcement-posture.test.ts` | Service golden path dual-enforcement language | +| `test/architecture/workflow-admission-boundary.test.ts` | Service workflow admission boundary | +| `test/architecture/x402-gateway-credential-custody.test.ts` | Gateway credential custody invariants | +| `test/architecture/gateway-invariant-*.test.ts` | Signer custody, params mismatch, replay | -**Location:** -- `test/support/fixtures.ts`: kernel fixtures, catalog registration, safe bypass probes, greenlit contracts. -- `test/support/kernel-invariant-helpers.ts`: kernel posture and out-of-band drift helpers. -- `test/support/d1-http-harness.ts`: Hono/D1 harness with role tokens and local SQLite D1 implementation. -- `test/support/fault-injecting-protocol-store.ts`: fault injection for commit conflicts, ambiguous commits, stale reads, hidden records, and posture drift. -- `test/support/package-install-flow.ts`, `test/support/repo-write-flow.ts`, `test/support/preview-deploy-flow.ts`, `test/support/auth-md-flow.ts`: adapter-specific flow builders. -- `test/support/codemode-multi-action-flow.ts`: generated-program/multi-action support. +### FailureClass taxonomy and parity -## Coverage +| File | Guards | +|------|--------| +| `test/protocol/failure-class-taxonomy.test.ts` | Reason-code → `FailureClass` mapping via `src/protocol/foundation/failure-class/index.ts` | +| `test/http/transition-error-failure-class.test.ts` | HTTP envelope `failureClass` alignment | +| `test/sdk/role-clients-failure-class.test.ts` | SDK client failureClass parity | +| `test/mcp/mcp-failure-class-parity.test.ts` | MCP binding reason codes vs HTTP classifier | -**Requirements:** Not enforced by a configured coverage threshold or package script. +### Integrator parity and product completion -**View Coverage:** -```bash -bun test --coverage # Available Bun coverage command, not wired into package scripts -``` +| File | Guards | +|------|--------| +| `test/architecture/integrator-parity.test.ts` | `integratorParityTransitionIds` tagged in navigation; HTTP route role/path parity | +| `test/architecture/operator-product-completion-contract.test.ts` | Golden path docs, runbooks, examples, required tests wired | +| `test/architecture/maintainer-product-completion-contract.test.ts` | Maintainer-tier test/doc closure | +| `test/architecture/product-completion-parity.test.ts` | Product completion gate parity | +| `test/architecture/proof-gap-honesty.test.ts` | Proof gaps not smoothed over in canon | -Coverage discipline is behavioral rather than percentage-based. New protocol work should add invariant tests for authority creation, refusal, replay, proof gap, projection redaction, isolation, and gateway-side enforcement. +### Release and distribution -## Test Types +| File | Guards | +|------|--------| +| `test/architecture/release-repository-projection.test.ts` | Release artifact projection (may timeout in full suite) | +| `test/architecture/package-release-proof.test.ts` | Release proof records | +| `test/architecture/npm-maintainer-posture.test.ts` | npm maintainer posture | +| `test/architecture/release-admin-gate.test.ts` | Release admin gate | -**Unit Tests:** -- Protocol and schema behavior: `test/protocol/canonical.test.ts`, `test/protocol/refusal-format.test.ts`, `test/protocol/reason-code-registry.test.ts`, `test/protocol/object-registry.test.ts`. -- Surface shape and package boundaries: `test/architecture/root-exports.test.ts`, `test/architecture/package-surface.test.ts`, `test/architecture/mcp-surface-posture.test.ts`. +Run the architecture slice: -**Integration Tests:** -- HTTP and D1-backed protocol paths: `test/http/d1-http.test.ts`, `test/integration/x402-d1-http.test.ts`, `test/integration/repo-write-d1-http.test.ts`. -- End-to-end adapter workflows: `test/integration/package-install-end-to-end.test.ts`, `test/integration/auth-md-protected-call.test.ts`, `test/integration/auth-md-receipt-reconstruction.test.ts`. +```bash +npm run quality:architecture +``` -**E2E Tests:** -- No browser E2E framework is used. -- Product/demo contract tests act as source-owned acceptance checks: `test/product/self-hosted-activation.test.ts`, `test/product/x402-protected-spend-demo-report.test.ts`, `test/product/external-adapter-sdk-demo.test.ts`, `test/product/x402-protected-tool-acceptance.test.ts`. +## Test Structure -## Common Patterns +**Suite organization:** -**Async Testing:** ```typescript -await expect( - proposeRuntimeIngressActionContracts(fixture.kernel, {}, input), -).rejects.toThrow("Runtime ingress package-install dispatch requires packageInstall config."); +import { describe, expect, it } from "bun:test"; +import { makeKernelFixture, createGreenlitContract } from "../support/fixtures"; + +describe("Handshake kernel invariants: operation lifecycle", () => { + it("keeps a passed gateway check pending until reconciliation records downstream finality", async () => { + const fixture = await createGreenlitContract(); + const result = await fixture.kernel.gatewayCheck({ /* exact binding */ }); + expect(result.gateAttempt.gateDecision).toBe("passed"); + expect(result.receipt.finalityStatus).toBe("pending"); + }); +}); ``` -Use async tests for kernel transitions, HTTP/D1 paths, filesystem surfaces, MCP process proof, CLI commands, and adapter gateways. +**Patterns:** +- No global `beforeEach` / `afterEach` hooks in most suites — tests construct fixtures inline or via async helpers. +- Architecture tests walk the filesystem with Node `fs` and aggregate violations into sorted arrays compared with `expect(violations).toEqual([])`. + +**Claim matrix helper (`test/architecture/claim-boundary.test.ts`):** -**Error Testing:** ```typescript -await expect( - fixture.kernel.putCatalogObject({ objectType: "greenlight", payload: fixture.greenlight }), -).rejects.toThrow("Direct writes are not allowed"); +function expectClaimMatrix(entries: ClaimMatrixEntry[]) { + for (const entry of entries) { + for (const source of entry.sources) { + const normalizedSource = normalizeRequiredClaim(source.text); + for (const phrase of entry.required ?? []) { + expect(normalizedSource, `${entry.label} must be stated in ${source.name}`).toContain( + normalizeRequiredClaim(phrase), + ); + } + } + } +} ``` -Prefer stable reason codes and posture fields over brittle message-only assertions. Message assertions are acceptable for explicit boundary text already covered by reason-code tests. +**Authority-boundary assertions (product/cli/mcp):** -**Refusal and proof-gap testing:** ```typescript -expect(result.outcome).toBe("gateway_check_refused"); -expect(result.gatewayCheck.gateAttempt.gateDecisionReasonCode).toBe("params_mismatch"); -expect(result.gatewayCheck.mutationAttempt).toBeNull(); -expect(surface.signatureCount()).toBe(0); +expect(output).toMatchObject({ + schemaVersion: "handshake.cli.v1", + authorityCreated: false, + gatewayCheckPerformed: false, + mutationAttempted: false, + reasonCodes: [], +}); +expect(JSON.stringify(output)).not.toContain("PAYMENT-SIGNATURE"); ``` -Use this shape when a generated action, observed parameter drift, stale posture, missing evidence, or replay must fail before signer use or mutation. +## Mocking -## Claim-Boundary Gates +**Framework:** None — no `mock`, `spyOn`, `vi.`, or Jest mocks detected under `test/`. -`npm run quality:claims` runs: +**Patterns:** +- Use real in-memory protocol store (`InMemoryProtocolStore` from `src/storage/memory`) via `makeKernelFixture()` in `test/support/fixtures.ts`. +- Use `FaultInjectingProtocolStore` in `test/support/fault-injecting-protocol-store.ts` for fault injection. +- HTTP integration uses `createD1HttpHarness()` in `test/support/d1-http-harness.ts`. +- CLI tests invoke `runCliCommand` from `src/cli/main.ts` with temp JSON fixture files. -```bash -npm run test -- test/architecture/active-vocabulary.test.ts test/architecture/claim-boundary.test.ts -``` +**What NOT to mock:** Protocol kernel transition semantics, Zod schema validation, canonicalization/digest functions under test. -Use this gate when simplifying product or kernel language in `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, `docs/internal/decisions.md`, `docs/internal/protocol-definition.md`, `docs/internal/protocol-kernel-architecture.md`, `docs/internal/protocol-layman.md`, `docs/internal/protocol-notes.md`, or `examples/x402-protected-spend/README.md`. +## Fixtures and Factories -The gate enforces: -- `cleared protected-action event`, `protocol kernel`, and `product surface` vocabulary. -- Category language: `protected actions for automated decision making`. -- Certificate boundary: terminal evidence, not permission. -- Distribution boundary: public npm and MCP Registry discoverability do not create authority. -- Production proof ledger and expansion admission language in `docs/internal/decisions.md`. -- Non-claims for hosted operation, provider custody, settlement/finality, broad x402 compatibility, aggregate spend, host-wide containment, and marketplace/certification. +**Kernel fixture (`test/support/fixtures.ts`):** `makeKernelFixture()`, `createGreenlitContract()`, `futureIso()`. -## Architecture and Naming Gates +**D1 HTTP harness (`test/support/d1-http-harness.ts`):** `createD1HttpHarness()` with in-memory SQLite + real `createApp()`. -`npm run quality:architecture` runs: +**Negotiation/A2A:** `test/support/negotiation-fixtures.ts`. -```bash -npm run test -- test/architecture/import-posture.test.ts test/architecture/naming-posture.test.ts test/architecture/package-surface.test.ts test/architecture/root-exports.test.ts test/architecture/surface-boundary-posture.test.ts test/architecture/cli-command-posture.test.ts test/architecture/mcp-surface-posture.test.ts test/conformance/protected-mutation-adapter-conformance.test.ts -``` +**Location for new fixtures:** `test/support/-fixtures.ts` or extend `fixtures.ts`. + +## Coverage -Use this gate for source moves, package export changes, CLI/MCP/SDK surface changes, adapter conformance changes, and naming simplification. +**Requirements:** No enforced coverage threshold; correctness is gated by `npm run check:repo` and architecture tests. -The gate enforces: -- No workspace junk or scratch canon in active repo surfaces. -- No bucket source path names. -- No internal planning-stage labels in repo-facing surfaces. -- No vague protocol mutation names or overclaiming function names. -- Public source lanes have `LANE.md` ownership manifests. -- Protocol, HTTP, runtime, storage, SDK, MCP, adapters, and surfaces keep their import boundaries. -- Surface outputs carry non-authority posture and forbid credential/raw record/payment material leakage. -- Package files exclude `src`, `test`, `examples`, scripts, `.planning`, `.agents`, and internal docs. -- Adapter conformance proves no mutation can occur without `VerifiedGatewayCheck`. +**Implicit coverage targets:** +- Every first-level `src/` lane lists **Guarding tests** in its `LANE.md`. +- Expansion of action families requires new tests naming execution shape, bypass posture, and proof-gap model (`QUALITY.md`). -## Projection-Vs-Authority Tests +## Test Types -Use these tests when changing readback, projection, CLI, MCP, SDK role clients, or support bundles: +**Unit tests (`test/protocol/`, parts of `test/adapters/`):** Direct `HandshakeKernel` invocation; store count assertions. -- `test/architecture/surface-boundary-posture.test.ts`: each surface has `authorityPosture`, route families, forbidden credentials, forbidden outputs, non-authority flags, and claim-boundary labels. -- `test/architecture/cli-command-posture.test.ts`: CLI commands stay evidence/local-readiness/conformance oriented and reject mutation-shaped command names. -- `test/architecture/mcp-surface-posture.test.ts`: MCP stays proposal/evidence only and cannot name executable authority or credential material. -- `test/protocol/evidence-projections.test.ts`: projections expose redacted evidence without creating authority. -- `test/protocol/representation-contract.test.ts`: Metadata, Challenge, Request, and EvidenceProjection shapes stay non-authority. -- `test/sdk/role-clients.test.ts`: role-scoped clients do not acquire all-role authority. +**Architecture / policy tests (`test/architecture/`):** Filesystem scans, manifest parity, claim matrices. -## Protocol Simplification Gate +**HTTP tests (`test/http/`):** `http.test.ts`, `d1-http.test.ts`, OpenAPI contract. -When simplifying confusing kernel language, test the simplification against three slices: +**CLI tests (`test/cli/`):** `runCliCommand` envelope shape and redaction. -```bash -npm run quality:claims -npm run quality:architecture -npm run test -- test/protocol/kernel-compilation-contract.test.ts test/protocol/kernel-policy-gateway.test.ts test/protocol/evidence-projections.test.ts test/runtime/runtime-ingress.test.ts -``` +**MCP tests (`test/mcp/`):** Catalog cardinality, schema rejection of authority-shaped fields. + +**Integration tests (`test/integration/`):** `x402-d1-http.test.ts`, `service-operator-golden-path.test.ts`, auth-md reconstruction. + +**Product tests (`test/product/`):** A2A ingress, service workflow admission, demo reports — always assert non-authority. + +**Conformance tests (`test/conformance/`):** Reference adapter posture. + +**Model-based invariants (`test/protocol/model-based-invariants.test.ts`):** Command scheduler over transition route IDs. + +## Where to Add Tests + +| Change type | Test location | Example guard file | +|-------------|---------------|-------------------| +| Protocol transition / invariant | `test/protocol/` | `kernel-operation-lifecycle.test.ts` | +| New `src/` lane or import rule | `test/architecture/` | `import-posture.test.ts`, `naming-posture.test.ts` | +| HTTP route or admission | `test/http/` | `http.test.ts`, `transition-error-failure-class.test.ts` | +| CLI command envelope | `test/cli/` | `cli-evidence.test.ts`, `cli-non-authority-copy.test.ts` | +| MCP tool/resource schema | `test/mcp/` | `mcp-schema-contract.test.ts`, `mcp-failure-class-parity.test.ts` | +| Adapter gateway / bypass | `test/adapters/` | `x402-bypass-probes.test.ts` | +| FailureClass mapping | `test/protocol/` + transport | `failure-class-taxonomy.test.ts` | +| End-to-end buyer flow | `test/integration/` or `test/product/` | `service-operator-golden-path.test.ts` | +| Public export or marketing claim | `test/architecture/` | `claim-boundary.test.ts`, `root-exports.test.ts` | +| Planning scratch promotion | `test/architecture/` | `planning-scratch-quarantine.test.ts` | +| Shared fixture / harness | `test/support/` | `fixtures.ts`, `d1-http-harness.ts` | -This is the minimum focused slice for language changes that touch proposal, evidence, action contracts, policy, gateway checks, and readback. Add adapter-specific tests such as `test/adapters/x402-wallet-gateway.test.ts` or `test/integration/x402-d1-http.test.ts` when the wording change affects x402 signer custody, per-call spend, PaymentPayload evidence, replay refusal, or downstream proof gaps. +Run the narrowest slice that covers your change before `npm run check:repo`. --- -*Testing analysis: 2026-05-25* +*Testing analysis: 2026-05-29* diff --git a/.planning/macro-plan/A2A_NEGOTIATION_META_META_GOAL.md b/.planning/macro-plan/A2A_NEGOTIATION_META_META_GOAL.md new file mode 100644 index 0000000..ec57a1d --- /dev/null +++ b/.planning/macro-plan/A2A_NEGOTIATION_META_META_GOAL.md @@ -0,0 +1,393 @@ +# A2A Negotiation Meta-Meta Goal + +Status: run-control goal +Purpose: drive GSD planning from architecture through implementation, +evaluation, and review/audit for agent-to-agent negotiated protected-action +events in Handshake. + +## Invariant At Stake + +Agent-to-agent agreement is not authority. + +Handshake may record, project, and audit negotiated obligations only if every +consequential obligation still becomes its own normal protected-action chain: + +```text +CandidateAction +-> exact ActionContract +-> PolicyDecision / one-use Greenlight or Refusal +-> GatewayCheck before consequence +-> Receipt / Refusal / ReplayRefusal / ProofGap / Isolation +-> optional AuthorityCertificate as terminal evidence only +``` + +No negotiation session, offer, counteroffer, acceptance, linked agreement, +marketplace listing, transcript, certificate, service admission, MCP proposal, +or rendered review surface may create permission, signer use, mutation +authority, settlement finality, cross-org trust, reputation, dispute resolution, +or reusable authorization. + +## Meta-Meta Goal + +Use GSD to plan the complete architecture, implementation, evaluation, and +review/audit path for A2A negotiation in Handshake. + +The output must let a future implementation agent build the first A2A +negotiation slice without inventing: + +- product category or launch claim; +- protocol object shape; +- transition and event lifecycle; +- authority boundary; +- policy hook; +- gateway proof obligation; +- cross-party evidence posture; +- x402 buyer/seller fixture; +- operator/readback surface; +- evaluation matrix; +- review/audit gates; +- stop conditions. + +The planning target is not "generic negotiation." The planning target is: + +```text +agent A and agent B negotiate one obligation; +the accepted obligation binds to one fresh protected-action contract; +each party clears only its own protected surface; +the terminal evidence can be reconstructed without treating agreement as authority. +``` + +## Product Frame + +Category: + +```text +Clearing layer for agent-negotiated protected-action events. +``` + +Primary product object: + +```text +LinkedAgreement +``` + +Economic object: + +```text +Cleared Work Unit +``` + +First proof fixture: + +```text +buyer-agent / seller-agent negotiation over one buyer-side x402_payment.exact +protected action. +``` + +First user: + +```text +agent builder or platform/security owner who wants agents to negotiate paid +work or paid API access without giving either agent ambient spend authority. +``` + +10-star moment: + +```text +The user sees that an accepted A2A offer did not authorize anything by itself; +Handshake bound one accepted obligation to one exact action contract, cleared or +refused it through policy/gateway, and produced receipt/refusal/proof-gap +evidence that both sides can inspect. +``` + +## Source Boundary + +Current source anchors: + +- `docs/internal/protocol-kernel-architecture.md` says bilateral ecosystem + operation may add negotiation and linked agreements, but each party's + obligation must still become its own normal `ActionContract`, policy decision, + greenlight, gateway check, and receipt/refusal/proof-gap chain. +- `docs/internal/protocol-layman.md` says the bilateral object is the agreement + while the enforcement object remains each side's action contract and gateway + check. +- `src/protocol/foundation/schema-core.ts` already exposes + `clearingEvidenceRefs.correlationRef`, `obligationRef`, and + `counterpartyRef`, which are the existing bridge from contracts to + negotiated obligations. +- `src/protocol/events/schemas.ts` owns durable event vocabulary. +- `src/protocol/areas/object-registry/` owns protocol object export and raw-read + posture. +- `src/protocol/kernel.ts` owns transition facade shape. +- `src/protocol/areas/policy-greenlight/sequence-dependencies.ts` owns existing + same-org action sequencing checks. + +Planning scratch, prior chat, memory, and market language are not source truth. +They may inform strategy, but implementation claims must be re-grounded in +current source and tests. + +## Required GSD Flow + +Run this as a GSD planning chain, not as a single chat answer: + +```text +gsd-plan-map +-> gsd-macro-plan +-> gsd-plan-phase +-> implementation slices +-> evaluation suite +-> review/audit chain +``` + +Use `--runtime multi` and `--authority-overlay` because the target involves +multi-agent execution, x402/payment, cross-party evidence, and protected-action +authority. + +The first normal-quality run must not be promoted unless it has durable +architecture, implementation, evaluation, and review artifacts. If subagent or +review-lens execution is unavailable, mark the run `DEGRADED` or +`DEGRADED_UNMAPPED`. + +## Required Skill Roles + +Use skill roles as production pressure, not ceremony: + +| Skill role | Required output | Blocking question | +| --- | --- | --- | +| `handshake-grounding` | source boundary and current non-proofs | Does current source support the claim? | +| `gsd-plan-map` | macro map with authority overlay | Is this the right macro move before implementation? | +| `gsd-macro-plan` | execution-ready macro plan package | Are slices, gates, and handoffs implementable? | +| `api-and-interface-design` | protocol/API/object contracts | Are interfaces hard to misuse and additive? | +| `plan-ceo-review` | market/opening verdict | Does A2A negotiation create market pull or distraction? | +| `plan-eng-review` | architecture and failure-mode review | Can the kernel extension preserve invariants? | +| `plan-devex-review` | first proof and adopter path | Can a builder reach the A2A proof quickly? | +| `plan-design-review` | readback/review surface critique | Can users see agreement vs authority clearly? | +| `plan-agent-review` | multi-agent operability review | Can agents propose without inheriting mutation authority? | +| `security-and-hardening` | cross-party, secret, tenancy, replay review | Do all dangerous paths fail closed? | +| `quality-contract` | acceptance and eval gates | Can bad A2A work fail objective tests? | +| `gsd-code-review` | implementation review | Did code preserve the authority boundary? | +| `gsd-secure-phase` | security review | Are credentials, signers, raw records, and tenancy safe? | +| `gsd-verify-work` | goal-backward completion audit | Does evidence prove the full goal, not a subset? | +| `thermo-nuclear-code-quality-review` | strict claim/maintainability audit | Are claims, names, and exports too broad? | + +## Architecture Deliverables + +The architecture plan must define all of the following before implementation: + +1. new non-authority protocol area: + +```text +src/protocol/areas/negotiation/ +``` + +2. additive records: + +```text +NegotiationSession +NegotiationOffer +NegotiationDecision +LinkedAgreement +AgreementObligationBinding +AgreementStatusTransition +``` + +3. additive events: + +```text +negotiation_session_opened +negotiation_offer_recorded +negotiation_decision_recorded +linked_agreement_recorded +agreement_obligation_bound +agreement_status_changed +``` + +4. object-registry posture: + +```text +exportPosture: transition_evidence +rawReadPosture: audit_read +``` + +5. kernel transition methods: + +```text +openNegotiationSession +recordNegotiationOffer +recordNegotiationDecision +recordLinkedAgreement +bindAgreementObligation +transitionAgreementStatus +``` + +6. policy hook: + +```text +if clearingEvidenceRefs.obligationRef is present, policy must be able to +require a current LinkedAgreement and a matching AgreementObligationBinding. +``` + +7. readback projections: + +```text +NegotiationTimelineProjection +LinkedAgreementProjection +AgreementObligationProjection +``` + +8. no-authority proof: + +```text +offer acceptance creates no PolicyDecision, Greenlight, GatewayCheck, signer +use, mutation, receipt, receipt export, certificate, settlement, or reusable +authorization. +``` + +## Implementation Slices + +The macro plan must split work into implementation slices with proof gates: + +### A2A-001 Source And Schema Foundation + +Create negotiation schemas, inputs, object registry entries, and event enum +additions. No policy or gateway behavior yet. + +Proof gate: records parse, reject malformed variants, and remain +`transition_evidence` only. + +### A2A-002 Transition Lifecycle + +Implement session, offer, decision, linked-agreement, obligation-binding, and +agreement-status transitions. + +Proof gate: acceptance and linked agreement creation do not create authority or +mutation records. + +### A2A-003 Obligation Binding To ActionContract + +Bind one accepted obligation to one existing `ActionContract` through +`clearingEvidenceRefs.obligationRef`, `counterpartyRef`, and digest checks. + +Proof gate: mismatched contract digest, parameters, party, status, expiry, or +counterparty refuses. + +### A2A-004 Policy Integration + +Add policy evaluation support for agreement-backed obligations. + +Proof gate: expired, withdrawn, disputed, superseded, or mismatched agreements +produce policy refusal, not best-effort continuation. + +### A2A-005 x402 Buyer/Seller Fixture + +Prove one buyer-agent/seller-agent negotiation over +`x402_payment.exact`. + +Proof gate: payment material remains behind `VerifiedGatewayCheck`; downstream +finality remains receipt/proof-gap evidence, not settlement. + +### A2A-006 Evidence Readback And Support Packet + +Add redacted negotiation/agreement readback and receipt timeline linkage. + +Proof gate: readback distinguishes accepted terms, bound obligations, action +contracts, policy, gateway, receipt/refusal/proof-gap, and non-claims. + +### A2A-007 Evaluation And Review Closeout + +Run product, protocol, security, agent, and claim audits. + +Proof gate: all P0/P1 findings are fixed, blocked, cut, or explicitly marked +accepted-risk before promotion. + +## Evaluation Suite + +The evaluation plan must include failing and passing cases: + +- offer acceptance does not create authority; +- accepted offer without obligation binding is not executable; +- obligation binding requires exact accepted terms digest; +- obligation binding requires exact action contract digest; +- party mismatch refuses; +- counterparty mismatch refuses; +- expired agreement refuses; +- withdrawn agreement refuses; +- disputed agreement refuses or proof-gaps according to policy; +- superseded offer cannot be accepted; +- stale transcript evidence refuses or proof-gaps; +- replayed greenlight still refuses; +- changed x402 parameters refuse; +- raw sibling payment path is detected/refused or recorded as proof gap; +- downstream x402 finality unknown records proof gap, not success; +- terminal certificate is evidence only; +- cross-org trust remains proof gap unless a separate trust model is proven; +- readback redacts raw terms, secrets, payment material, and signer material; +- receipt timeline can reconstruct agreement -> obligation -> contract -> + policy -> gateway -> terminal outcome. + +## Review And Audit Gates + +No implementation may be called complete until these reviews exist: + +1. CEO review: A2A negotiation opens market access without dragging Handshake + into owning the marketplace. +2. Engineering review: protocol extension is additive, typed, replay-safe, and + isolated from authority overclaim. +3. Security review: cross-party evidence, tenancy, secrets, signers, raw reads, + replay, stale terms, and disputed status fail closed. +4. DevEx review: builder can run the first A2A x402 proof without learning the + whole protocol. +5. Design review: UI/readback makes "agreement is not authority" visible. +6. Agent review: multi-agent runtime can propose and negotiate without raw + mutation tools. +7. Claim audit: docs and examples do not claim marketplace, settlement, + legal-contract, reputation, escrow, cross-org trust, provider custody, or + generic A2A support. +8. Verification audit: tests and generated outputs prove every acceptance gate. + +## Hard Stop Conditions + +Stop and report `BLOCKED` if: + +- the plan treats acceptance as permission; +- the plan lets one agreement authorize multiple mutations; +- the plan lets one party authorize the other party's gateway; +- the plan requires raw signer or payment material outside the gateway; +- the plan depends on cross-org trust before a trust model exists; +- the plan claims settlement, legal contract formation, reputation, dispute + resolution, escrow, marketplace certification, or provider custody; +- the plan cannot bind accepted terms to exact `ActionContract` digests; +- policy cannot refuse stale, expired, withdrawn, disputed, or mismatched + agreement state; +- readback cannot reconstruct the chain six months later; +- implementation requires broad root exports before package-surface gates; +- full review/audit gates are missing. + +## Success Definition + +This meta-meta goal is satisfied when GSD outputs a durable plan package that +contains: + +- source boundary; +- macro map; +- execution-ready macro plan; +- architecture contract; +- implementation slice plan; +- evaluation suite; +- review/audit matrix; +- fresh-agent handoff; +- concrete tasks; +- explicit proof gaps and non-claims; +- status that honestly reflects whether the work is ready for phase planning, + agent execution, or blocked. + +## Smallest Next Mechanism + +Create the GSD macro-map input packet for: + +```text +A2A negotiated protected-action events in Handshake +``` + +with runtime `multi`, authority overlay enabled, and first fixture +`buyer-agent / seller-agent x402_payment.exact`. diff --git a/.planning/macro-plan/AGENT-HANDOFF.md b/.planning/macro-plan/AGENT-HANDOFF.md new file mode 100644 index 0000000..3625bf7 --- /dev/null +++ b/.planning/macro-plan/AGENT-HANDOFF.md @@ -0,0 +1,176 @@ +# Agent Handoff + +## Objective + +Implement the architectural north-star correction: Handshake has one protocol +authority spine, and product vocabulary is projection/readback over that spine. +The goal is not another thin plan. It includes research, macro planning, +implementation, evaluation, sidecar review, full repo gates, and commits. + +## Source Boundary + +Canon lives in tracked repo docs/source/tests, not `.planning/`. The active +planning package for this run is +`.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/` and is +evidence for this execution only. Prior macro-plan runs are historical context, +not current closeout proof. + +## Runtime Profile + +Primary runtime is Codex in a workspace-write checkout with restricted network. +Use `rg` for discovery and `apply_patch` for edits. Multi-host posture remains +evidence-only; do not claim native containment for Codex, Claude Code, Hermes, +OpenClaw, MCP, browser, A2A, OpenAPI, auth.md, or x402. + +## Instruction Sources + +- `AGENTS.md` for doctrine and invariants. +- `QUALITY.md` and `STRUCTURE.md` for repo boundaries. +- `src/*/LANE.md` for lane-local ownership. +- `.planning/macro-plan/*` for execution plan and gates. + +## Context Bundle + +The live problem is not whether `src/surfaces` can exist. It can. The problem is +whether product vocabulary is described as a peer truth lane. Correct model: +projection/readback surfaces and role-scoped transition clients both sit under +one protocol authority spine. + +## Ignored Context + +Do not use older macro-plan validation or prior green tests as current-run +closeout evidence. Do not use `.planning/` labels in repo-facing source or +package exports. + +## Tool Contract + +Allowed: read/patch docs, source, tests, planning artifacts; run focused and +full repo gates; use sidecars for bounded audit only. Forbidden: protected +mutations outside user-authorized commands, broad network claims without +primary sources, and any authority claim not backed by source. + +## Protected-Action Boundary + +Projection context stops before authority. Every protected action still requires +`CandidateAction / ActionContract -> PolicyDecision -> one-use Greenlight or +Refusal -> GatewayCheck -> Receipt / Refusal / ReplayRefusal / ProofGap / +AuthorityCertificate`. + +## Read First + +1. `AGENTS.md` +2. `README.md` +3. `QUALITY.md` +4. `STRUCTURE.md` +5. `docs/internal/decisions.md` +6. `docs/internal/protocol-notes.md` +7. `docs/internal/service-workflow-story.md` +8. `.planning/macro-plan/MACRO-PLAN.md` +9. `.planning/macro-plan/EXECUTION-SLICES.md` +10. `.planning/macro-plan/RUNTIME-GATES.md` +11. `.planning/macro-plan/PROTECTED-ACTION-GATES.md` +12. `.planning/macro-plan/TASKS.jsonl` + +`.planning/` remains scratch. Do not turn planning labels into repo-facing +source or package surfaces. + +## North-Star Model + +```text +Projection/readback vocabulary + Passport / Admission / Handle / Clearance / Outcome / Certificate + over +One protected-action event spine + CandidateAction / ActionContract + -> PolicyDecision + -> one-use Greenlight or Refusal + -> GatewayCheck + -> Receipt / Refusal / ReplayRefusal / ProofGap / AuthorityCertificate +``` + +## Active Implementation Scope + +Allowed: + +- patch canonical docs to replace dual-lane mental model with projection over + one authority spine; +- add or update architecture tests for projection-only language; +- update `src/surfaces/LANE.md` to clarify that surfaces are implementation + boundaries for projection/readback, not behavior owners; +- run focused gates and full repo gates; +- commit coherent checkpoints. + +Forbidden: + +- add protocol primitives for Passport, Admission, Handle, Outcome, Badge, or + `ProtectedActionEvent`; +- widen root exports, CLI/MCP authority, SDK role powers, gateway adapters, or + hosted claims; +- treat receipts, certificates, support bundles, review screens, passports, or + workflow handles as future permission; +- claim hosted operation, provider custody, settlement/finality, marketplace + certification, cross-org trust, aggregate spend enforcement, host containment, + hosted org auth, or retention/search. + +## Subagent Topology + +At most five sidecars: + +- architecture/case-study mechanisms; +- vocabulary/projection language; +- protected-action lifecycle mapping; +- runtime/protected-action gates; +- evidence/review/closeout. + +Sidecars may write audit reports only. The chair owns final sequencing, status, +authority claims, and commits. + +## Evaluation Path + +```bash +/Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +npm run quality:claims +npm run quality:architecture +npm run test -- test/architecture/claim-boundary.test.ts test/architecture/workflow-admission-boundary.test.ts +npm run test -- test/runtime/runtime-ingress.test.ts test/product/service-workflow-admission.test.ts +npm run check:repo +git status --short --branch +``` + +## Stop Conditions + +Stop if: + +- product vocabulary becomes a peer authority lane; +- `ServiceWorkflowHandle` can satisfy policy, gateway, signer, mutation, + receipt, or certificate requirements; +- a case-study analogy is used as proof of Handshake capability; +- Tier 3/hosted pressure expands the kernel/package surface; +- full repo gate fails and no explicitly justified narrowed closeout exists. + +## Proof Gaps + +- No live provider custody, x402 settlement/finality, facilitator operation, or + seller middleware is proven. +- No hosted operation, hosted org auth, retention/search, marketplace trust, or + cross-org trust is proven. +- No native host containment is proven. +- No finished UI product experience is proven by this architecture correction. + +## Non-Claims + +This handoff does not authorize Tier 3, hosted operation, provider custody, +settlement, marketplace trust, cross-org trust, aggregate spend enforcement, +host containment, or product UX completion. + +## Current Next Step + +Patch canonical docs and `test/architecture/claim-boundary.test.ts` so the repo +requires projection-over-spine language and forbids product/protocol peer-lane +truth claims. + +## Next Agent Step + +Implement NPLAN-002 and NPLAN-003 first: canonical projection vocabulary plus +`src/surfaces/service-workflow-lifecycle-projections.ts` and its architecture +test. Do not begin hosted/Tier 3 work. diff --git a/.planning/macro-plan/DECISIONS.md b/.planning/macro-plan/DECISIONS.md new file mode 100644 index 0000000..25df196 --- /dev/null +++ b/.planning/macro-plan/DECISIONS.md @@ -0,0 +1,91 @@ +# Decisions + +## NPLAN-D001 - One Authority Spine + +- Status: accepted +- Decision: Handshake architecture is one protocol authority spine with + projection/readback vocabulary over it. +- Rationale: Product/protocol peer lanes create ambiguity about where authority + lives. +- Source: user correction; `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/input.md` +- Revisit trigger: only if a future source-owned transition changes the + authority spine. + +## NPLAN-D002 - Surfaces Are Implementation Boundaries + +- Status: accepted +- Decision: Keep `src/surfaces` and "surface" as implementation vocabulary, but + canonical docs must say surfaces expose projection/readback only and are not a + product truth lane. +- Rationale: Removing the folder would cause churn; correcting its meaning + addresses the real architectural risk. +- Source: `STRUCTURE.md`, `src/surfaces/LANE.md`, `test/architecture/surface-boundary-posture.test.ts` +- Revisit trigger: if package extraction needs a public projection subpath. + +## NPLAN-D002A - Projection Surfaces Versus Transition Clients + +- Status: accepted +- Decision: Canonical vocabulary must distinguish product projection/readback + surfaces from role-scoped protocol transition clients. +- Rationale: Some SDK/HTTP clients transport authority-bearing protocol + transitions, while product projection surfaces must remain non-authority. One + umbrella term hides that difference. +- Source: `runs/20260525T110908Z-architectural-north-star/audits/product-vocabulary-projection-audit.md` +- Revisit trigger: if the SDK/client taxonomy changes. + +## NPLAN-D003 - ProtectedActionEvent As Lifecycle Projection Concept + +- Status: accepted +- Decision: Use `ProtectedActionEvent` as a documentation/testing lifecycle + concept in this run, source-owned through a `src/surfaces` projection map, not + as a stored protocol object. +- Rationale: The current protocol already has navigation/lifecycle matrices; a + new primitive would risk duplicating authority state. +- Source: `src/protocol/navigation`, `src/protocol/areas/action-attempt-lifecycle`, `docs/internal/protocol-notes.md` +- Revisit trigger: if source proves the existing lifecycle cannot express a + required terminal event projection. + +## NPLAN-D003A - Runtime Composition Gaps Are Blocking + +- Status: accepted +- Decision: Mixed-family same-envelope and x402/auth.md non-composition gates + are P0 for closeout. +- Rationale: Projection-over-spine fails if one generated block can blur + multiple authority contexts into a single runtime spine or composite + credential/payment artifact. +- Source: `runs/20260525T110908Z-architectural-north-star/audits/runtime-protected-action-gates-audit.md` +- Revisit trigger: after focused runtime tests prove the gate. + +## NPLAN-D003B - Authority Surface Naming Must Be Replaced + +- Status: accepted +- Decision: `sdk.policy` and similar clients should be described as + role-scoped protocol transition clients, not authority surfaces. +- Rationale: The kernel/policy transition owns authority. SDK clients transport + a role-scoped call into that transition. +- Source: `runs/20260525T110908Z-architectural-north-star/audits/architecture-case-study-audit.md` +- Revisit trigger: if a future client truly owns an enforceable authority + transition outside the kernel, which should be treated as a new protocol + design. + +## NPLAN-D004 - Case Studies Become Mechanism Rules + +- Status: accepted +- Decision: Stripe, Kubernetes/OPA, Vault, GitHub, AWS IAM, SLSA/Sigstore, + Vercel, and Cloudflare are used as mechanism references only. +- Rationale: Borrowed analogy can overclaim enforcement. Mechanism rules can be + tested. +- Source: `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research.md` +- Revisit trigger: if a later implementation imports a concrete standard or + certification. + +## NPLAN-D005 - Badge Remains Unsafe Shorthand + +- Status: accepted +- Decision: Badge remains forbidden as schema/protocol/export/route authority + vocabulary. If used in UI later, it must mean a read-only state label derived + from evidence. +- Rationale: Badge reads as bearer authority under generated-agent behavior. +- Source: `.planning/macro-map/DECISIONS.md`, `docs/internal/service-workflow-story.md`, `src/mcp/LANE.md` +- Revisit trigger: if a UI-only state-label component is designed with explicit + non-authority copy and tests. diff --git a/.planning/macro-plan/EVIDENCE-PLAN.md b/.planning/macro-plan/EVIDENCE-PLAN.md new file mode 100644 index 0000000..6389f91 --- /dev/null +++ b/.planning/macro-plan/EVIDENCE-PLAN.md @@ -0,0 +1,138 @@ +# Evidence Plan + +## Invariant At Stake + +The closeout must prove the architectural correction, not just successful text +edits. Evidence must distinguish research, plan, implementation, test, review, +and residual proof gaps. + +## Evidence Artifacts + +| Artifact | Purpose | +| --- | --- | +| `runs/20260525T110908Z-architectural-north-star/input.md` | Immutable goal and source boundary | +| `runs/20260525T110908Z-architectural-north-star/research.md` | Primary-source case-study mechanisms | +| `runs/20260525T110908Z-architectural-north-star/source-snapshot.md` | Starting repo/source posture | +| `runs/20260525T110908Z-architectural-north-star/blocked-checks.md` | Preserved proof gaps and stop conditions | +| `runs/20260525T110908Z-architectural-north-star/audits/*.md` | Sidecar pressure reports | +| `runs/20260525T110908Z-architectural-north-star/validation.md` | Command and review closeout | + +## Current Evidence + +- Current run input, research, research-evidence, source snapshot, blocked + checks, and five sidecar audits exist. +- Macro-plan validator must be rerun after final plan edits. +- Source/docs/tests implementation evidence is not complete until focused gates + and `npm run check:repo` run after final changes. + +## Command Evidence + +Plan validation: + +```bash +/Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +``` + +Focused implementation gates: + +```bash +npm run quality:claims +npm run quality:architecture +npm run test -- test/architecture/claim-boundary.test.ts test/architecture/workflow-admission-boundary.test.ts +npm run test -- test/runtime/runtime-ingress.test.ts test/product/service-workflow-admission.test.ts +``` + +Closeout: + +```bash +npm run format:check +npm run check:repo +git status --short --branch +``` + +## Fixtures Or Examples + +- `examples/service-workflow-admission/latest.json` and `latest.md` must remain + service workflow readbacks, not authority artifacts. +- Product/architecture fixtures must assert Passport, Admission, Handle, + Clearance, Outcome, and Certificate as projections over existing lifecycle + entries or explicit pre-contract evidence context. +- Runtime fixtures must cover mixed-family envelope refusal and x402/auth.md + non-composition, not one composite authority object. + +## Readback And Redaction Checks + +- Readbacks may include correlation and reconstruction references, including + digest and presentation/admission/handle IDs, only when those IDs are marked + non-authority. +- Readbacks must not expose payment material, signer payloads, gateway-held + credentials, authority tokens, or live provider secrets. +- Redaction must preserve enough structure to reconstruct proposal, policy, + gateway check, receipt/refusal/proof gap, and terminal certificate posture + without turning evidence into reusable auth. + +## Runtime Proof Artifacts + +- Runtime proof must include generated execution shape, runtime posture, + protected action path, gateway authority holder, raw or sibling bypass + posture, and surviving receipt/refusal/proof-gap evidence. +- Mixed-family runtime proof must show a same-envelope pass or an explicit + refusal before one projected workflow readback is assembled. +- x402/auth.md runtime proof must show separate exact contracts or refusal, + never one composite credential-plus-payment authority artifact. + +## Evidence Not Yet Available + +- Post-implementation focused test outputs are not available until source/docs + edits land. +- Full `npm run check:repo` evidence is not available until after focused gates + pass. +- Hosted/Tier 3 proof remains unavailable by design in this run. +- Live provider custody, native host containment, registry acceptance, and + marketplace trust remain proof gaps. + +## Verification Commands + +Use the command matrix above. Record exact outputs in +`runs/20260525T110908Z-architectural-north-star/validation.md`. + +## Evidence Success Criteria + +- Sidecar findings are resolved or carried as explicit proof gaps. +- Tests require projection-over-spine language and non-authority service + workflow semantics. +- Full repo gate passes before final implementation closeout. +- Git commits separate macro-plan reset from implementation when possible. + +## Replay And Refusal Cases + +Evidence must include or preserve tests for replay refusal, policy/runtime +refusal, gateway refusal, stale handle/review refusal, mixed-family envelope +refusal, x402/auth.md non-composition refusal, and proof-gap readback. + +## Review Prompts + +- Does the diff preserve one authority spine? +- Does any product noun create authority or imply a second lane? +- Are sidecar P0 findings resolved in source/tests or recorded as proof gaps? +- Were focused gates and full repo gate run after final changes? + +## Browser Or Visual Evidence + +This correction is architecture/source owned, not a finished product UI slice. +Browser evidence is optional unless docs/demo pages or rendered service workflow +readbacks are changed. If visual/browser surfaces are touched, capture: + +- rendered service workflow readback showing projection language; +- absence of authority, trusted identity, reusable credential, or badge-style + permission wording; +- console and route errors for the changed route; +- a note that visual readback is evidence only and not an enforcement boundary. + +## Residual Proof Gaps To Preserve + +- No live provider custody or settlement finality. +- No hosted operation or hosted org auth. +- No marketplace/certification or cross-org trust. +- No native host containment. +- No finished product UI beyond source-owned docs/schema/demo/readback. diff --git a/.planning/macro-plan/EXECUTION-SLICES.md b/.planning/macro-plan/EXECUTION-SLICES.md new file mode 100644 index 0000000..81cfb83 --- /dev/null +++ b/.planning/macro-plan/EXECUTION-SLICES.md @@ -0,0 +1,328 @@ +# Execution Slices + +## Inputs + +- `.planning/macro-map/*` +- `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/*` +- canonical docs under repo root and `docs/internal/` +- `src/protocol`, `src/surfaces`, `src/runtime`, `src/sdk`, `src/cli`, `src/mcp` +- architecture, runtime, and product tests + +## Outputs + +- revised macro-plan package; +- canonical docs and source-owned projection map; +- architecture/runtime/product tests; +- validation, code-review, and git-checkpoint evidence. + +## Dependencies + +- N1 depends on N0 macro-plan reset. +- N2 depends on canonical projection vocabulary. +- N3 depends on projection map and canonical vocabulary. +- N4 depends on projection vocabulary guards. +- N5 depends on all implementation and focused gates. + +## Verification Commands Or Checks + +```bash +/Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +npm run quality:claims +npm run quality:architecture +npm run test -- test/architecture/claim-boundary.test.ts test/architecture/workflow-admission-boundary.test.ts +npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/product/service-workflow-admission.test.ts +npm run check:repo +``` + +## Rollback Or Abandonment Criteria + +- Roll back docs wording if claim-boundary tests show it weakens authority + boundaries. +- Abandon projection-map implementation if it requires a stored protocol object; + return to protocol design first. +- Abandon runtime closeout if mixed-family or x402/auth.md tests reveal + composite authority that cannot be fixed in scope. +- Do not close the goal if full repo gate fails without an explicit user-owned + narrowed closeout. + +## Agent Handoff Needs + +Fresh agents must read `AGENT-HANDOFF.md`, `RUNTIME-GATES.md`, +`PROTECTED-ACTION-GATES.md`, sidecar audit reports, and `TASKS.jsonl` before +editing. They must preserve dirty user state and avoid treating `.planning/` +as repo-facing canon. + +## Slice N0-00 - Research And Macro-Plan Reset + +### ID + +N0-00 + +### Invariant Or Risk + +A plan can launder a weak analogy into product architecture. Research must +become mechanism rules, not borrowed authority. + +### Objective + +Record primary-source case-study research, reset the macro-plan package around +projection-over-one-spine, and preserve proof gaps. + +### Source Evidence + +- `.planning/macro-map/MACRO-HANDOFF.md` +- `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research.md` +- `README.md` +- `STRUCTURE.md` +- `docs/internal/decisions.md` +- `src/surfaces/LANE.md` + +### Outputs + +- `runs/20260525T110908Z-architectural-north-star/input.md` +- `runs/20260525T110908Z-architectural-north-star/research.md` +- revised `.planning/macro-plan/*` + +### Stop Conditions + +- Any case study is used to claim Handshake has enforcement not proven in source. +- The plan preserves "product lane vs protocol lane" as a positive target. + +### Proof Gates + +- Macro-plan validator passes. +- Sidecar audits exist or missing sidecars are recorded. + +### Verification + +```bash +/Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +``` + +## Slice N1-01 - Canonical Projection Language + +### ID + +N1-01 + +### Invariant Or Risk + +Canonical docs currently use `product surface` and `protocol kernel` language +that is valid structurally but can be read as peer lanes of truth. + +### Objective + +Patch canonical docs to say product vocabulary is projection/readback over the +single protected-action event spine. + +### Candidate Paths + +- `README.md` +- `STRUCTURE.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/protocol-layman.md` +- `docs/internal/service-workflow-story.md` +- `src/surfaces/LANE.md` + +### Stop Conditions + +- Docs imply product vocabulary can create or reinterpret authority. +- Docs imply service workflow admission is policy/gateway admission. +- Docs imply certificate, receipt, outcome, or support bundle grants future + authority. + +### Proof Gates + +- Canon states exactly one authority spine. +- Canon states projection/readback surfaces are implementation boundaries only. +- Canon preserves public npm/MCP/hosted proof gaps. + +### Verification + +```bash +npm run quality:claims +npm run format:check +``` + +## Slice N2-01 - ProtectedActionEvent Projection Map + +### ID + +N2-01 + +### Invariant Or Risk + +Friendly nouns will drift unless they map to one source-owned lifecycle. + +### Objective + +Define `ProtectedActionEvent` as a documentation/testing lifecycle concept and +source-own the product projection vocabulary through a `src/surfaces` lifecycle +projection map. Map each product noun to lifecycle evidence without adding a +stored protocol object. + +### Candidate Paths + +- `docs/internal/protocol-notes.md` +- `docs/internal/service-workflow-story.md` +- `docs/internal/decisions.md` +- `src/surfaces/service-workflow-lifecycle-projections.ts` +- `src/surfaces/index.ts` +- `test/architecture/claim-boundary.test.ts` +- `test/architecture/service-workflow-lifecycle-projection.test.ts` + +### Stop Conditions + +- Implementation adds a new protocol primitive without a separate transition + proposal. +- `ProtectedActionEvent` becomes a package export, store record, or gateway + input in this slice. + +### Proof Gates + +- Projection map names source authority stage for each noun. +- Projection map names forbidden authority interpretation for each noun. +- Tests require the mapping in canonical docs. +- Tests validate lifecycle keys against `actionAttemptLifecycleEntry()`. + +### Verification + +```bash +npm run test -- test/architecture/claim-boundary.test.ts +``` + +## Slice N3-01 - Dual-Lane Drift Guards + +### ID + +N3-01 + +### Invariant Or Risk + +The phrase "product surface" can silently expand into a second lane of truth. + +### Objective + +Add claim-boundary tests that forbid product/protocol peer-lane language and +require projection-over-spine language. + +### Candidate Paths + +- `test/architecture/claim-boundary.test.ts` +- `test/architecture/workflow-admission-boundary.test.ts` + +### Stop Conditions + +- The tests are prose-only while source can still imply authority. +- The tests forbid legitimate implementation folder names such as + `src/surfaces` instead of forbidding peer truth claims. + +### Proof Gates + +- Tests require `projection/readback` language. +- Tests forbid "product lane", "protocol lane", "separate product truth", and + product vocabulary as authority. +- Existing workflow admission non-authority tests still pass. + +### Verification + +```bash +npm run test -- test/architecture/claim-boundary.test.ts test/architecture/workflow-admission-boundary.test.ts +npm run quality:architecture +``` + +## Slice N4-01 - Runtime And Protected-Action Regression + +### ID + +N4-01 + +### Invariant Or Risk + +Generated agents will treat simpler vocabulary as permission unless runtime and +protected-action gates stay fresh. + +### Objective + +Confirm or add regressions proving service workflow context only prepares +proposal context; each protected action still requires fresh exact clearance. +Add the sidecar-identified P0 gates for mixed-family same-envelope runtime +evidence and x402/auth.md non-composition. + +### Candidate Paths + +- `test/runtime/runtime-ingress.test.ts` +- `test/runtime/auth-md-candidate-compilation.test.ts` +- `test/product/service-workflow-admission.test.ts` +- `examples/service-workflow-admission/` +- `.planning/macro-plan/RUNTIME-GATES.md` +- `.planning/macro-plan/PROTECTED-ACTION-GATES.md` + +### Stop Conditions + +- A handle can be reused for loops/retries without a fresh action contract. +- Mixed-family runtime dispatch evidence can combine mismatched tenant, + organization, principal, agent, run, runtime adapter, operating envelope, + gateway registry, or authority-holder context into one runtime spine. +- x402/auth.md generated composition creates a composite authority artifact. +- x402/auth.md fixture output suggests composite authority. +- Payment/signature/credential material leaks into admission or handle records. + +### Proof Gates + +- Existing misuse tests pass. +- Mixed-family dispatch families must share one generated execution envelope or + refuse before runtime evidence is projected as one spine. +- x402 and auth.md composition must become separate candidates or refusal, never + a single composite authority contract. +- Any new projection fields have explicit non-authority semantics. + +### Verification + +```bash +npm run test -- test/runtime/runtime-ingress.test.ts test/product/service-workflow-admission.test.ts +``` + +## Slice N5-01 - Review, Evaluation, And Commit Closeout + +### ID + +N5-01 + +### Invariant Or Risk + +The branch can look clean while preserving a weak conceptual split. Review must +verify the goal, not just tests. + +### Objective + +Run sidecar review, macro validation, focused gates, full repo gate, record +evidence/proof gaps, and commit coherent checkpoints. + +### Candidate Paths + +- `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md` +- `.planning/macro-plan/REVIEW-GATES.md` +- `.planning/macro-plan/EVIDENCE-PLAN.md` +- git commit history + +### Stop Conditions + +- Sidecars identify a P0/P1 that cannot be resolved or recorded as a proof gap. +- `npm run check:repo` fails and no narrowed equivalent is justified. +- Working tree contains unrelated or unstaged goal changes at closeout. + +### Proof Gates + +- `npm run check:repo` passes. +- Macro-plan validator passes. +- Sidecar findings are resolved or recorded. +- Git status is clean after final commit. + +### Verification + +```bash +npm run check:repo +git status --short --branch +``` diff --git a/.planning/macro-plan/MACRO-PLAN.md b/.planning/macro-plan/MACRO-PLAN.md new file mode 100644 index 0000000..cf6ff20 --- /dev/null +++ b/.planning/macro-plan/MACRO-PLAN.md @@ -0,0 +1,294 @@ +# Macro Plan + +## Invariant At Stake + +Handshake must not split into product truth and protocol truth. Product +vocabulary may make service intake legible, but it must be a non-authority +projection/readback over one protected-action event spine. + +The single authority spine remains: + +```text +CandidateAction / ActionContract +-> PolicyDecision +-> one-use Greenlight or Refusal +-> GatewayCheck before mutation +-> Receipt / Refusal / ReplayRefusal / ProofGap / AuthorityCertificate +``` + +Passport, Admission, Handle, Clearance, Outcome, Certificate, Badge-like labels, +review screens, CLI output, MCP resources, SDK helpers, demos, and support +bundles can only project, request, or read this spine. They cannot create a peer +lane that authorizes, reinterprets, or bypasses it. + +## Source Boundary + +| Source | Role | Status | +| --- | --- | --- | +| `.planning/macro-map/MACRO-HANDOFF.md` | Passport / Admission / Badge macro map | Derived planning input, decision-gated but user-authorized for correction | +| `.planning/macro-map/*` | Lens maps, concerns, decisions, tasks | Derived planning evidence | +| `.planning/codebase/*` | Repo architecture, testing, integrations, concerns | Derived evidence; source-check before canon | +| `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/*` | Current input, research, snapshot, sidecar audits, validation | Current run evidence | +| `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md` | Doctrine, orientation, quality, structure | Canon | +| `docs/internal/decisions.md`, `protocol-notes.md`, `protocol-layman.md`, `service-workflow-story.md` | Product/protocol canon and plain translation | Canon | +| `src/protocol`, `src/surfaces`, `src/runtime`, `src/cli`, `src/mcp`, `examples/service-workflow-admission`, `test/*` | Source-owned behavior and proof gates | Mechanism truth | + +## Research Mechanisms + +Primary-source research is recorded in +`.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research.md`. +The imported mechanisms are: + +- Stripe PaymentIntents: one lifecycle object with explicit statuses and + idempotency, not multiple truth lanes. +- Kubernetes Admission / OPA: request-time chokepoints and rejection before + persistence or mutation. +- Vault: custody, leases, renewal, revocation, and audit; handles do not become + raw secret material. +- GitHub deployment environments: protection rules before execution proceeds. +- AWS IAM: default deny and explicit deny overriding convenience. +- SLSA / artifact attestations: provenance and certificates are terminal + evidence, not future permission. +- Vercel / Cloudflare: product copy names scope and method; verification is + repeated instead of assuming stale context remains valid. + +These are mechanisms only. They do not prove Handshake hosted operation, +provider custody, marketplace trust, or host containment. + +## Current Evidence + +- The existing protocol kernel already owns exact contracts, policy decisions, + one-use greenlights/refusals, gateway checks, receipts, refusals, proof gaps, + isolation, and terminal certificates. +- The existing service workflow admission schema already hard-codes + non-authority boundaries for admission and handle records. +- Sidecar audits found the right source shape but unsafe vocabulary pressure: + `product surface` is overloaded, `sdk.policy` is currently named as an + authority surface, product projection terms lack one source-owned lifecycle + map, and runtime composition needs same-envelope/non-composition gates. +- The current run has primary-source research, source snapshot, blocked checks, + and five sidecar audits under + `runs/20260525T110908Z-architectural-north-star/`. + +## Non-Proofs + +This plan does not prove live x402 provider custody, settlement/finality, +facilitator operation, seller middleware, marketplace trust, cross-org trust, +aggregate spend enforcement, hosted operation, hosted org auth, +retention/search, broad runtime containment, or user comprehension of the +projection vocabulary. + +## Selected Macro Move + +Replace "dual product/protocol lanes" with this architecture: + +```text +Projection vocabulary + Passport / ServiceWorkflowAdmission / ServiceWorkflowHandle / Clearance / Outcome + over +ProtectedActionEvent lifecycle + exact contract -> policy/refusal -> one-use greenlight -> gateway check -> terminal evidence + enforced by +Gateway-owned mutation adapters and protocol kernel transitions + reconstructed through +Receipts, refusals, proof gaps, isolation, terminal certificates, and support bundles +``` + +The repo may keep `src/surfaces` as an implementation folder, but canonical docs +must split three concepts: + +- product projection/readback surfaces: non-authority surfaces for service + workflow, evidence, reports, demos, and copy; +- role-scoped protocol transition clients: SDK/HTTP clients that transport a + specific protocol transition under custody and kernel/gateway authority; +- the protocol authority spine: the only place that creates policy decisions, + one-use greenlights/refusals, gateway checks, receipts, refusals, proof gaps, + isolation, and terminal certificates. + +None of these are peer product/protocol truth lanes. Product projection +surfaces never create authority. Role-scoped transition clients do not make +product nouns authoritative; they are transport into the protocol authority +spine. + +## Execution Thesis + +The correction succeeds by making projection subordinate to protocol authority +in both language and mechanism: + +1. Canonical docs name one protected-action event spine. +2. Source owns a service-workflow lifecycle projection map under `src/surfaces`. +3. Architecture tests require product vocabulary to remain projection/readback. +4. Runtime/protected-action tests prove mixed-family and x402/auth.md + composition cannot blur authority contexts. +5. Review and evidence gates distinguish planning proof from execution proof. + +## Ten-Star Success Criteria + +- Exactly one authority spine is named and enforced in docs, source, and tests. +- Product nouns are explicitly projection/readback nouns, never authority nouns. +- Canonical docs no longer imply product/protocol peer lanes. +- `ServiceWorkflowAdmission` and `ServiceWorkflowHandle` remain schema-level + non-authority records. +- A source-owned service workflow lifecycle projection map ties Passport, + Admission, Handle, Clearance, Outcome, and Certificate to existing lifecycle + entries or explicit pre-contract evidence context. +- Passport IDs remain correlation/reconstruction fields only. +- Badge remains forbidden as a schema/protocol/export noun; if it appears, it is + read-only state label language only. +- Case-study research is captured as mechanism rules with source URLs. +- Runtime misuse remains covered for loops, retries, stale handles, dynamic + tools, raw sibling bypass, stale review, replay, and proof gaps. +- Mixed-family runtime blocks either share one execution envelope or fail before + being projected as one runtime spine. +- x402/auth.md composition remains separate exact contracts or refusal; no + composite credential-plus-payment authority artifact is created. +- Hosted/Tier 3 remains blocked unless a separate hosted workspace or fresh + pre-hosted kernel task proves the missing gates. +- A fresh agent can resume from `AGENT-HANDOFF.md` without chat memory. + +## Execution Slices + +This package decomposes the correction into: + +```text +N0 - Research and macro-plan reset +N1 - Canonical projection-over-spine language +N2 - ProtectedActionEvent projection mapping +N3 - Architecture guards against dual-lane drift +N4 - Runtime/protected-action regression gates +N5 - Review, validation, full repo gate, and commit closeout +``` + +Each slice is detailed in `EXECUTION-SLICES.md` and assigned in `TASKS.jsonl`. + +## Non-Goals + +- Do not add a new protocol primitive for Passport, Admission, Handle, Outcome, + Certificate, Badge, or `ProtectedActionEvent` unless a separate source-owned + transition proposal proves a new enforceable state. +- Do not remove `src/surfaces`; correct its meaning instead. +- Do not widen package exports, CLI/MCP authority, SDK role powers, gateway + adapters, or hosted claims. +- Do not claim live provider custody, x402 settlement, facilitator operation, + seller middleware, marketplace certification, cross-org trust, aggregate spend + enforcement, native host containment, hosted org auth, or retention/search. +- Do not treat the case studies as evidence that Handshake already has their + enforcement properties. + +## Target State + +Canon says: + +```text +Product vocabulary is projection/readback over one protected-action event spine. +The protocol kernel remains the source-owned authority state machine. +Projection surfaces expose proposal, context, evidence, and readback only. +``` + +Source/tests prove: + +- The service workflow schema cannot create authority. +- Canonical docs must contain projection-over-spine wording. +- Canonical docs must not describe product/protocol as peer authority lanes. +- Product vocabulary cannot appear in protocol areas or root authority exports + as a shortcut. +- Runtime handles can assist proposal context only; each protected action still + creates a fresh exact contract and reaches a fresh policy/gateway boundary. + +## Decisions + +- Keep `src/surfaces` as a source-owned implementation boundary. +- Rename the mental model from `product surface vs protocol kernel` to + `projection/readback surface over protocol authority spine`. +- Use `ProtectedActionEvent` as a documentation/testing lifecycle concept + source-owned through a `src/surfaces` projection map. Do not create a stored + protocol object yet. +- Keep Passport as presentation evidence, Admission as service-side mapping, + Handle as context/readback reference, Clearance as fresh protected-action path, + and Outcome as terminal readback projection. +- Treat Badge as unsafe shorthand unless explicitly marked as a read-only state + label derived from evidence. + +## Risks And Proof Gaps + +- The word `surface` is entrenched in code. The mitigation is explicit docs and + tests saying surface means projection/readback implementation boundary. +- `Admission` remains overloaded with HTTP admission and service workflow + admission. The mitigation is explicit naming and tests that block policy/gate + implications. +- Product UX is not solved by this slice. The result is source-owned + architecture and proof language, not a finished app front door. +- Hosted/Tier 3 pressure remains a kernel-creep risk and stays blocked. + +## Blocking Concerns + +These are accepted-risk items for executing this correction plan only. They are +not accepted as product truth, hosted claims, or release-complete posture. Each +P0/P1 below is either assigned to an execution slice or preserved as a proof gap +until source/tests prove the mechanism. + +- P0: `product surface` remains overloaded until canonical docs split product + projection/readback surfaces from role-scoped protocol transition clients. +- P0: `sdk.policy` and similar clients must not be named authority surfaces; + they must be framed as custody-scoped transport into kernel transitions. +- P0: product projection terms need a source-owned lifecycle projection map or + docs remain the only guard. +- P0: mixed-family runtime blocks must prove one execution envelope or refuse. +- P0: x402/auth.md composition must not produce one composite authority object. +- P1: full product UX is still not implemented; this run corrects architecture + and source-owned projection semantics. + +## Verification Gates + +- Macro-plan validator: + `/Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan` +- Focused claim/architecture gates: + `npm run quality:claims` + `npm run quality:architecture` + `npm run test -- test/architecture/claim-boundary.test.ts test/architecture/workflow-admission-boundary.test.ts` +- Runtime/product regression where touched: + `npm run test -- test/runtime/runtime-ingress.test.ts test/product/service-workflow-admission.test.ts` +- Closeout: + `npm run format:check` + `npm run check:repo` + +## Runtime And Protected-Action Summary + +Runtime posture remains evidence-only. Codex, Claude Code, Hermes, OpenClaw, +MCP, browser, A2A, OpenAPI, auth.md, and x402 do not share one containment +model. Runtime ingress may record generated-execution evidence and propose +contracts only. + +Protected-action posture remains one event at a time. Projection vocabulary may +help prepare context, but every consequential action still requires a fresh +exact contract, policy/refusal, one-use greenlight when allowed, gateway check +before mutation, and terminal receipt/refusal/replay/proof-gap/certificate +evidence. x402/auth.md composition and mixed-family dispatches are blocking +runtime gates until focused tests prove separation or refusal. + +## Long-Running End Condition + +The run is complete only when research, macro plan, implementation, evaluation, +sidecar/review evidence, and git commits all support one conclusion: Handshake +has one protocol authority spine, and product vocabulary is projection/readback +over that spine. + +## Handoff To Phase Planning + +Detailed phase work starts from `EXECUTION-SLICES.md` and `TASKS.jsonl`, not +from chat memory. The first implementation slice is canonical docs plus +claim-boundary guards. The second implementation slice source-owns the service +workflow lifecycle projection map under `src/surfaces`. Runtime P0 gates follow +before closeout. Fresh agents must read `AGENT-HANDOFF.md`, +`RUNTIME-GATES.md`, `PROTECTED-ACTION-GATES.md`, and sidecar audits before +editing. + +## Smallest Next Mechanism + +Install a source-owned `Product Vocabulary Is Projection Only` guard in +canonical docs and `test/architecture/claim-boundary.test.ts`, then run the +focused claim/architecture gates before touching broader examples. + +## Plan Status + +`READY_FOR_AGENT_EXECUTION` diff --git a/.planning/macro-plan/PROTECTED-ACTION-GATES.md b/.planning/macro-plan/PROTECTED-ACTION-GATES.md new file mode 100644 index 0000000..4f2463c --- /dev/null +++ b/.planning/macro-plan/PROTECTED-ACTION-GATES.md @@ -0,0 +1,156 @@ +# Protected-Action Gates + +## Invariant At Stake + +Every consequential mutation must pass through the single protected-action +authority spine. Projection/readback vocabulary cannot become a shortcut around +candidate compilation, exact contract, policy, one-use greenlight/refusal, +gateway check, or terminal evidence. + +## Source Boundary + +Protected-action truth lives in `src/protocol`, `src/adapters`, gateway tests, +runtime tests, product tests, and canonical docs. This planning file defines +gates only; it does not create authority or gateway enforcement. + +## Authority Spine + +```text +runtime/projection context +-> CandidateAction +-> ActionContract +-> PolicyDecision +-> one-use Greenlight or Refusal +-> GatewayCheck before mutation +-> Receipt / Refusal / ReplayRefusal / ProofGap / AuthorityCertificate +``` + +## Protected-Action Triggers + +- any generated runtime dispatch that may mutate a protected surface; +- any x402 payment attempt; +- any auth.md-backed protected API call; +- any package/repo/preview/cloud/database/deploy mutation path; +- any retry, branch, loop, or sibling call that changes endpoint, payee, + resource, gateway, credential, delegated authority, body digest, or payment + requirement. + +## Candidate Actions + +Candidate actions are proposed commitments only. Passport, Admission, Handle, +Badge-like labels, Clearance wording, Outcome readback, and Certificate evidence +can provide context or references, but they cannot satisfy candidate creation or +contract proposal requirements. + +## Authority Boundary + +Authority begins only at exact policy greenlight and is usable only once after a +gateway verifies the same exact contract before mutation. Refusals, proof gaps, +isolation, stale posture, and explicit deny conditions dominate projection +convenience. + +## Gateway Or Enforcement Boundary + +The gateway check is the final pre-mutation enforcement point. SDK clients, +HTTP routes, CLI commands, MCP resources, demos, review screens, receipts, and +projection maps are not gateway enforcement. + +## Raw Sibling Or Bypass Posture + +Raw sibling package managers, x402 signers, auth.md credentials, browser tools, +direct HTTP/network calls, shell commands, cloud/deploy APIs, and database paths +must be prevented, isolated, or recorded as bypass/proof-gap evidence. Projection +vocabulary cannot claim containment over them. + +## Generated-Execution Stress Coverage + +Coverage must include loops, retries, branches, dynamic tool construction, +late-bound parameters, stale review/handle evidence, changed observed +parameters, raw sibling paths, replay, ambiguous commits, proof gaps, isolation, +mixed-family same-envelope checks, and x402/auth.md non-composition. + +## Evidence Readback Separation + +Receipts, refusals, replay refusals, proof gaps, authority certificates, +support bundles, release proof, and projection maps are readback/evidence. They +must distinguish gateway admission from downstream execution/finality and must +not become permission for future attempts. + +## Receipt Refusal Proof-Gap Evidence + +Every terminal projection must identify whether the source event is a receipt, +policy/gateway/runtime refusal, replay refusal, proof gap, isolation consequence, +or terminal certificate. Missing evidence stays a proof gap. + +## Projection Vocabulary Matrix + +| Product noun | Allowed use | Required protected-action gate | Forbidden meaning | +| --- | --- | --- | --- | +| Passport | Presented evidence package digest/reference | Fresh candidate and exact contract still required | identity, trust, permission, reusable auth | +| ServiceWorkflowAdmission | Service-side accepted/refused/stale/proof-gap mapping | No policy/gateway authority until fresh clearance | policy approval, gateway admission, receipt | +| ServiceWorkflowHandle | Correlation/readback context for later proposals | May only populate context refs on a fresh request | bearer token, retry permission, greenlight | +| Clearance | Fresh protected-action path | Must include policy/refusal and gateway check before mutation | workflow-level permission | +| Outcome | Terminal event projection | Must derive from receipt/refusal/replay/proof-gap/certificate evidence | downstream success or future authority | +| Certificate | Terminal verification evidence | Must be terminal and verifiable; never pre-action | permission, identity, settlement, hosted trust | +| Badge-like UI | Read-only state label derived from evidence | No schema/protocol/export route authority | executable grant or bearer credential | + +The source-owned projection map for these terms belongs under `src/surfaces` and +must validate any lifecycle keys against the existing action-attempt lifecycle. +It must not add a stored protocol object. + +## Field-Level Acceptance Matrix + +| Field/material | Allowed in projection | Authority posture | +| --- | --- | --- | +| `passportPackageDigest` | yes | correlation only | +| `passportPresentationId` | yes | presentation event only | +| `admissionId` | yes | service-side mapping only | +| `serviceWorkflowHandleId` | yes | readback/context only | +| `serviceWorkflowHandleDigest` | yes | context integrity only | +| `ActionContract` refs | context refs only | proposed commitment, not permission | +| `PolicyDecision` refs | readback after source record | protocol authority state only | +| `Greenlight` refs | never as projection input authority | one-use gateway-bound only | +| `GatewayCheck` refs | readback after source record | enforcement evidence only | +| raw credential/payment/signature material | no | gateway/custody only | + +## x402/auth.md Gates + +- x402 remains one buyer-side `x402_payment.exact` per-call path. +- PaymentPayload and `PAYMENT-SIGNATURE` remain behind a verified gateway check. +- auth.md evidence can support provenance/custody posture but cannot combine + with x402 into composite authority. +- A generated block containing both auth.md and x402 must produce separate fresh + exact contracts or a refusal/proof gap. It cannot produce one composite + credential-plus-payment authority artifact. +- External sandbox/live provider, settlement/finality, facilitator operation, + seller middleware, aggregate spend enforcement, and provider custody remain + proof gaps unless separately proven. + +## Hosted/Tier 3 Gate + +Service workflow projection clarity is not hosted-operation readiness. Hosted +operation, hosted org auth, retention/search, marketplace trust, cross-org +trust, or new kernel exports require a separate hosted workspace or fresh +pre-hosted kernel task. + +## Non-Claims + +These gates do not prove hosted operation, provider/customer custody, +settlement/finality, facilitator operation, seller middleware, marketplace +trust, cross-org trust, aggregate spend enforcement, native host containment, +or product UX completion. + +## Blocked Checks + +- live x402 custody and settlement; +- provider/customer gateway custody; +- hosted operation and hosted org auth; +- marketplace/certification and cross-org trust; +- broad runtime interception or raw sibling inventory; +- UI/product comprehension proof. + +## Stop Condition + +Stop if any projection noun is accepted as policy input authority, gateway +binding, signer/custody material, mutation command, receipt export, certificate +minting input, or reusable authorization. diff --git a/.planning/macro-plan/README.md b/.planning/macro-plan/README.md new file mode 100644 index 0000000..edc85f4 --- /dev/null +++ b/.planning/macro-plan/README.md @@ -0,0 +1,36 @@ +# Macro Plan Package + +Run: `20260525T110908Z-architectural-north-star` +Status: `READY_FOR_AGENT_EXECUTION` + +## Invariant + +Product vocabulary is projection/readback over one protected-action authority +spine. It is not a second lane of truth. + +## Package + +- `MACRO-PLAN.md` - chair-owned north-star plan and status. +- `EXECUTION-SLICES.md` - ordered implementation and verification slices. +- `TASKS.jsonl` - assignable next mechanisms. +- `AGENT-HANDOFF.md` - fresh-agent context. +- `RUNTIME-GATES.md` - generated-agent and host-runtime checks. +- `PROTECTED-ACTION-GATES.md` - authority, gateway, signer, and evidence gates. +- `EVIDENCE-PLAN.md` - proof collection and command matrix. +- `REVIEW-GATES.md` - sidecar and closeout review rules. +- `RISKS.md` - P0/P1 risks and proof gaps. +- `DECISIONS.md` - run decisions. + +## Current Run Evidence + +- `runs/20260525T110908Z-architectural-north-star/input.md` +- `runs/20260525T110908Z-architectural-north-star/research.md` +- `runs/20260525T110908Z-architectural-north-star/source-snapshot.md` +- `runs/20260525T110908Z-architectural-north-star/blocked-checks.md` +- `runs/20260525T110908Z-architectural-north-star/audits/*` +- `runs/20260525T110908Z-architectural-north-star/validation.md` + +## Smallest Next Mechanism + +Install canonical projection-over-spine language and a claim-boundary guard that +fails if product/protocol peer-lane language returns. diff --git a/.planning/macro-plan/REVIEW-GATES.md b/.planning/macro-plan/REVIEW-GATES.md new file mode 100644 index 0000000..7037854 --- /dev/null +++ b/.planning/macro-plan/REVIEW-GATES.md @@ -0,0 +1,129 @@ +# Review Gates + +## Invariant At Stake + +The chair owns final authority claims. Sidecars can pressure-test, but they +cannot promote a plan to ready or declare implementation complete. + +## Gate Summary + +The review system must reject three failure classes: + +- architectural drift back into dual product/protocol authority lanes; +- product vocabulary that becomes identity, permission, reusable auth, receipt + substitute, or gateway shortcut; +- evidence that proves planning effort but not source-owned mechanism. + +The plan can be promoted only when every gate below either passes with current +evidence or records a named proof gap that does not undermine the next slice. + +## Sidecar Review + +At most five sidecars: + +| Report | Scope | +| --- | --- | +| `architecture-case-study-audit.md` | Mechanism quality and case-study misuse | +| `product-vocabulary-projection-audit.md` | Product vocabulary and dual-lane language | +| `protected-action-lifecycle-audit.md` | Lifecycle/projection mapping | +| `runtime-protected-action-gates-audit.md` | Runtime misuse and protected-action gates | +| `evidence-review-gates-audit.md` | Evidence, validation, review, and commit closeout | + +The chair has accepted the sidecar reports as pressure inputs, not authority. +Resolved findings must appear in docs/source/tests. Unresolved findings remain +explicit proof gaps in `RISKS.md`, `blocked-checks.md`, or validation closeout. + +## CEO Gate + +Question: does this make the product smaller, harder, sharper, and easier to +adopt without broadening the wedge? + +Pass condition: the correction makes Handshake legible as protected-action +infrastructure for one cleared event lifecycle. It must not sell dashboards, +identity, agent trust, hosted clearing, marketplace certification, generic +observability, or approval theatre as the product. + +## Engineering Gate + +Question: can the mechanism be enforced and tested from source? + +Pass condition: there is one protocol authority spine, source-owned projection +mapping, focused tests for non-authority product nouns, and no widened package +exports, protocol primitives, gateway adapters, CLI/MCP authority, or hosted +claims. Any `sdk.policy`-like role client must be named as transition transport +under custody, not as a product authority surface. + +## Design Gate + +Question: does simplification hide protocol complexity without lying about +authority? + +Pass condition: Passport, Admission, Handle, Clearance, Outcome, and +Certificate can make the workflow understandable while their copy and schemas +explicitly say they do not create authority. Badge-like language is cut unless +it is a read-only state label derived from evidence. + +## DevEx Gate + +Question: can a builder integrate the narrow wedge without learning the entire +protocol internals? + +Pass condition: docs and demos teach proposal, evidence, readback, refusal, and +proof gap as product-facing concepts, while directing protected mutation through +the existing kernel/gateway state machine. No setup path asks a developer to +invent authority semantics. + +## Agent Gate + +Question: can a fresh agent resume without chat memory and without turning +planning into canon? + +Pass condition: `AGENT-HANDOFF.md`, `TASKS.jsonl`, and run-local evidence are +sufficient to start the next mechanism. `.planning/` remains derived evidence; +repo-facing truth lands only in canon docs, source, tests, and examples. + +## Runtime Gate + +Question: does generated execution remain bounded under loops, retries, +branches, sibling calls, stale handles, and dynamic tool pressure? + +Pass condition: runtime/protected-action tests prove same-envelope composition +or refusal, x402/auth.md non-composition, replay refusal, stale context +refusal, and proof-gap readback. Runtime handles may carry proposal context but +cannot authorize mutation. + +## Protected-Action Gate + +Question: is there still exactly one enforceable authority boundary? + +Pass condition: every consequential action reaches a fresh exact contract, +policy decision, one-use greenlight/refusal, gateway check, and terminal +receipt/refusal/proof gap/certificate posture. No product noun can skip, +cache, reuse, or summarize that boundary into authority. + +## Chair Review Checklist + +- Does the plan preserve one authority spine? +- Are product nouns projections/readbacks only? +- Do docs avoid product/protocol peer-lane claims? +- Do tests fail if peer-lane language returns? +- Does any source change widen package exports, protocol primitives, CLI/MCP + authority, SDK role powers, gateway adapters, or hosted claims? +- Are official case studies translated into mechanisms with URLs? +- Are residual proof gaps explicit? + +## Code Review Gate + +Before final closeout, inspect the diff for: + +- overbroad docs rewrites; +- repo-facing planning labels; +- new authority-shaped nouns; +- accidental package export churn; +- claim-boundary tests that merely bless prose without guarding source risk. + +## Promotion Rule + +`READY_FOR_AGENT_EXECUTION` means a bounded agent can execute the next slice. It +does not mean hosted/Tier 3 can start and does not mean the architecture is +complete until implementation and full gates pass. diff --git a/.planning/macro-plan/RISKS.md b/.planning/macro-plan/RISKS.md new file mode 100644 index 0000000..3aabac0 --- /dev/null +++ b/.planning/macro-plan/RISKS.md @@ -0,0 +1,62 @@ +# Risks + +## P0 - Dual-Lane Authority Drift + +Risk: `product surface` and `protocol kernel` become peer lanes of truth. + +Mitigation: canonical docs must say projection/readback over one authority +spine; claim-boundary tests must forbid product/protocol peer-lane claims. + +Stop condition: any product noun creates, grants, reinterprets, or bypasses +authority. + +## P0 - Handle Or Badge As Reusable Auth + +Risk: generated agents treat `ServiceWorkflowHandle` or badge-like UX as a +bearer token. + +Mitigation: schema false flags, workflow-admission tests, runtime misuse tests, +and forbidden vocabulary rules. + +Stop condition: a handle can satisfy policy, gateway, signer, mutation, receipt, +certificate, payment, or credential requirements. + +## P0 - Case-Study Overclaiming + +Risk: Stripe/Kubernetes/Vault/GitHub/AWS/SLSA/Vercel/Cloudflare analogies create +unearned authority claims. + +Mitigation: research is stored as mechanism rules only; source proof still wins. + +Stop condition: docs imply Handshake has hosted operation, provider custody, +settlement, host containment, or marketplace trust because another product has a +similar concept. + +## P1 - Surface Folder Name Confusion + +Risk: `src/surfaces` sounds like a product lane. + +Mitigation: keep the folder but clarify that it owns projection/readback +implementation boundaries only. + +Stop condition: surface code evaluates policy, issues greenlights, performs +gateway checks, mutates, exports receipts, mints certificates, or reads raw +protocol records. + +## P1 - ProtectedActionEvent Object Creep + +Risk: a useful lifecycle concept becomes a duplicated protocol primitive. + +Mitigation: keep it documentation/testing-only in this run and map to existing +protocol navigation/action-attempt lifecycle evidence. + +Stop condition: new stored event object, package export, gateway input, or +policy input is introduced without a separate transition proposal. + +## P1 - Tier 3 Kernel Creep + +Risk: hosted-product needs use the simplified vocabulary to widen kernel exports +or package surfaces. + +Mitigation: preserve hosted admission lock and route hosted operation to a +separate workspace or fresh pre-hosted kernel task. diff --git a/.planning/macro-plan/RUNTIME-GATES.md b/.planning/macro-plan/RUNTIME-GATES.md new file mode 100644 index 0000000..ad07fdf --- /dev/null +++ b/.planning/macro-plan/RUNTIME-GATES.md @@ -0,0 +1,105 @@ +# Runtime Gates + +## Invariant At Stake + +Generated agents will treat simple vocabulary as operational affordance unless +runtime gates prove otherwise. A projection/readback surface may help prepare a +proposal, but it cannot authorize a runtime dispatch. + +## Source Boundary + +Runtime gate truth lives in `src/runtime/ingress`, `test/runtime/*`, +`test/product/service-workflow-admission.test.ts`, `src/mcp/LANE.md`, +`src/cli/command-manifest.ts`, and protocol/gateway tests. Planning gates are +not runtime enforcement. + +## Runtime Targets + +| Target | Current posture | Required north-star gate | +| --- | --- | --- | +| Codex | Local profile and MCP/stdout evidence only | No host-wide containment claim; workflow handle is proposal context only | +| Claude Code | Managed/profile artifact evidence | No native containment claim | +| Hermes | Tool-packet/profile artifact evidence | No reusable handle authority | +| OpenClaw | Tool-packet/profile artifact evidence | No raw sibling mutation bypass claim | +| MCP | Proposal/evidence resources and stdio process proof | MCP cannot authorize, pay, execute, retry, recover, or certify | +| x402 | Buyer-side exact per-call local proof lane | Fresh exact action request for each payment; signer material stays behind gateway | +| auth.md | Provenance and credential-custody evidence | auth.md does not become composite authority with x402 | +| Browser / A2A / OpenAPI | Proof-gap contexts | No protected-action readiness without gateway-owned path | + +## Suitability Postures + +- Suitable for local source-owned proposal/evidence/readback tests. +- Suitable for Codex-local implementation with shell and repo gates. +- Not suitable for host-wide containment claims. +- Not suitable for hosted operation or live provider custody claims. + +## Instruction Sources + +- `AGENTS.md` +- `src/runtime/ingress/*` +- `src/mcp/LANE.md` +- `src/cli/command-manifest.ts` +- `docs/internal/decisions.md` +- `test/runtime/runtime-ingress.test.ts` +- `test/runtime/auth-md-candidate-compilation.test.ts` +- `test/product/service-workflow-admission.test.ts` + +## Tool Contract + +Runtime ingress may observe generated dispatches, record evidence, refuse unsafe +shapes, and propose candidates. It must not evaluate policy, issue greenlights, +perform gateway checks, use signers, mutate protected surfaces, export receipts, +mint certificates, or claim host containment. + +## Approval Or Permission Behavior + +Runtime evidence, service workflow handles, rendered reviews, and MCP/CLI/SDK +outputs are not approval or permission. Permission exists only when the protocol +spine records a policy greenlight and the gateway verifies it for one exact +mutation attempt. + +## Subagent Behavior + +Subagents may audit runtime gates or implement disjoint tests, but they may not +declare runtime protection, host containment, protected-action authority, or +final closeout. The chair reconciles findings. + +## Continuation State + +Runtime gates remain open until focused tests pass for mixed-family same-envelope +behavior, x402/auth.md non-composition, stale handle/review posture, and current +service workflow misuse cases. + +## Blocked Runtime Checks + +- Host-wide containment for Codex, Claude Code, Hermes, OpenClaw, MCP, browser, + A2A, OpenAPI. +- Live provider custody, settlement, facilitator operation, seller middleware. +- Broad raw sibling inventory for all browser, network, cloud, deploy, database, + and shell channels. + +## Required Runtime Misuse Coverage + +- mixed-family dispatch blocks must share one generated execution envelope + before they can be recorded as one runtime spine; +- loops and retries with the same handle; +- changed observed parameters across retries; +- dynamic tool construction; +- stale rendered review or stale admission context; +- raw sibling x402/auth.md/MCP/browser/network bypass; +- direct protected mutation attempt without fresh contract; +- replay after one-use greenlight consumption; +- proof-gap and isolation propagation. +- x402/auth.md generated composition as separate exact contracts or refusal, + never one composite authority artifact. + +## Pass Condition + +Runtime may carry projection context into proposal preparation only if the +resulting protected action still becomes one fresh exact action contract and +passes policy/gateway gates before mutation. + +## Stop Condition + +Stop if any runtime path treats Passport, Admission, Handle, Badge, Outcome, +Certificate, CLI output, MCP resource, or SDK helper as executable grant. diff --git a/.planning/macro-plan/TASKS.jsonl b/.planning/macro-plan/TASKS.jsonl new file mode 100644 index 0000000..0c79f30 --- /dev/null +++ b/.planning/macro-plan/TASKS.jsonl @@ -0,0 +1,6 @@ +{"id":"NPLAN-001","phase":"N0","slice":"N0-00","title":"Reset macro plan around projection-over-spine architecture","priority":"P0","owner":"chair","runtime":"codex","depends_on":[],"evidence":[".planning/macro-map/MACRO-HANDOFF.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/input.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/architecture-case-study-audit.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/evidence-review-gates-audit.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md"],"candidate_paths":[".planning/macro-plan/MACRO-PLAN.md",".planning/macro-plan/EXECUTION-SLICES.md",".planning/macro-plan/TASKS.jsonl"],"rationale":"The old surface framing can be misread as dual product/protocol truth lanes.","acceptance":["Macro-plan status follows from current evidence.","Official research becomes mechanism rules.","Plan contains execution slices, gates, risks, review gates, and evidence plan.","Sidecar findings are reflected as gates, tasks, risks, or proof gaps."],"non_goals":["Do not claim hosted operation or product UX completion."],"status":"completed","proof_gate":"Macro-plan validator passes.","next_mechanism":"Patch canonical docs to projection-over-spine language."} +{"id":"NPLAN-002","phase":"N1","slice":"N1-01","title":"Patch canonical docs to projection-over-spine language","priority":"P0","owner":"docs-implementer","runtime":"codex","depends_on":["NPLAN-001"],"evidence":["README.md","STRUCTURE.md","docs/internal/decisions.md","docs/internal/protocol-notes.md","docs/internal/service-workflow-story.md","src/surfaces/LANE.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/product-vocabulary-projection-audit.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md"],"candidate_paths":["README.md","STRUCTURE.md","docs/internal/decisions.md","docs/internal/protocol-notes.md","docs/internal/service-workflow-story.md","src/surfaces/LANE.md"],"rationale":"Product vocabulary must be projection/readback over the single authority spine, not a second lane.","acceptance":["Canon names exactly one authority spine.","Canon distinguishes product projection/readback surfaces from role-scoped protocol transition clients.","Canon defines projection/readback surfaces as implementation boundaries only.","Canon preserves non-authority posture for Passport, Admission, Handle, Outcome, Certificate, Badge-like labels, CLI, MCP, SDK, examples, receipts, and support bundles."],"non_goals":["Do not remove src/surfaces or rewrite protocol kernel docs wholesale."],"status":"completed","proof_gate":"quality:claims passes.","next_mechanism":"Define source-owned service workflow lifecycle projection map."} +{"id":"NPLAN-003","phase":"N2","slice":"N2-01","title":"Define source-owned service workflow lifecycle projection map","priority":"P0","owner":"architecture-docs-implementer","runtime":"codex","depends_on":["NPLAN-002"],"evidence":["docs/internal/protocol-notes.md","docs/internal/service-workflow-story.md","src/protocol/areas/action-attempt-lifecycle","src/protocol/navigation",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/protected-action-lifecycle-audit.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md"],"candidate_paths":["src/surfaces/service-workflow-lifecycle-projections/index.ts","src/surfaces/index.ts","docs/internal/protocol-notes.md","docs/internal/service-workflow-story.md","test/architecture/service-workflow-lifecycle-projection.test.ts","test/architecture/claim-boundary.test.ts"],"rationale":"Friendly nouns need a source-owned projection map to prevent drift while avoiding new protocol primitives.","acceptance":["Projection map lists product noun, source authority stage, allowed use, forbidden interpretation, and lifecycle keys or explicit pre-contract context.","Lifecycle keys validate against actionAttemptLifecycleEntry().","ProtectedActionEvent is documentation/testing concept only in this slice.","No new protocol primitive or root package export is added."],"non_goals":["Do not create a stored ProtectedActionEvent object."],"status":"completed","proof_gate":"projection-map and claim-boundary tests pass.","next_mechanism":"Add dual-lane drift guards."} +{"id":"NPLAN-004","phase":"N3","slice":"N3-01","title":"Add dual-lane drift guards","priority":"P0","owner":"architecture-test-implementer","runtime":"codex","depends_on":["NPLAN-003"],"evidence":["test/architecture/claim-boundary.test.ts","test/architecture/workflow-admission-boundary.test.ts","test/architecture/surface-boundary-posture.test.ts","test/architecture/service-workflow-lifecycle-projection.test.ts",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/product-vocabulary-projection-audit.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md"],"candidate_paths":["test/architecture/claim-boundary.test.ts","test/architecture/workflow-admission-boundary.test.ts","test/architecture/surface-boundary-posture.test.ts","test/architecture/service-workflow-lifecycle-projection.test.ts"],"rationale":"The repo needs a failing test if product/protocol peer-lane language returns.","acceptance":["Tests require projection-over-spine wording.","Tests forbid product/protocol peer-lane truth claims.","Tests guard Badge/Clearance/Outcome vocabulary drift.","Existing workflow admission boundary tests still pass."],"non_goals":["Do not forbid legitimate implementation folder names."],"status":"completed","proof_gate":"focused architecture tests pass.","next_mechanism":"Verify runtime and protected-action regressions."} +{"id":"NPLAN-005","phase":"N4","slice":"N4-01","title":"Verify runtime and protected-action regressions","priority":"P0","owner":"runtime-gate-owner","runtime":"codex","depends_on":["NPLAN-004"],"evidence":["test/runtime/runtime-ingress.test.ts","test/runtime/auth-md-candidate-compilation.test.ts","test/product/service-workflow-admission.test.ts",".planning/macro-plan/RUNTIME-GATES.md",".planning/macro-plan/PROTECTED-ACTION-GATES.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/runtime-protected-action-gates-audit.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md"],"candidate_paths":["test/runtime/runtime-ingress.test.ts","test/runtime/auth-md-candidate-compilation.test.ts","test/product/service-workflow-admission.test.ts","src/runtime/ingress/index.ts",".planning/macro-plan/RUNTIME-GATES.md",".planning/macro-plan/PROTECTED-ACTION-GATES.md"],"rationale":"Generated agents will treat simplified vocabulary as permission unless misuse gates stay explicit; sidecar found P0 mixed-family same-envelope and x402/auth.md non-composition gaps.","acceptance":["Runtime/product tests prove handles are proposal context only.","Mixed-family runtime dispatch blocks must share one execution envelope or refuse before being projected as one spine.","x402/auth.md remains separate exact contracts or refusal, never composite authority.","No signer/payment/credential material appears in admission or handle records."],"non_goals":["Do not certify host-wide containment."],"status":"completed","proof_gate":"runtime/product/auth-md focused tests pass or preserved as explicit proof gaps.","next_mechanism":"Evaluate review and commit closeout."} +{"id":"NPLAN-006","phase":"N5","slice":"N5-01","title":"Evaluate review and commit closeout","priority":"P0","owner":"chair","runtime":"codex","depends_on":["NPLAN-005"],"evidence":[".planning/macro-plan/REVIEW-GATES.md",".planning/macro-plan/EVIDENCE-PLAN.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/code-review.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/git-checkpoints.md"],"candidate_paths":[".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/code-review.md",".planning/macro-plan/runs/20260525T110908Z-architectural-north-star/git-checkpoints.md"],"rationale":"The goal is end-to-end only if research, plan, implementation, review, tests, and commits converge.","acceptance":["Sidecar findings are resolved or recorded.","Macro-plan validator passes after final plan edits.","Focused tests and full repo gate pass after final source/docs/tests changes.","Code review and git checkpoint records exist.","Git status is clean after final commit."],"non_goals":["Do not close the goal on planning alone."],"status":"completed","proof_gate":"check:repo and clean git status.","next_mechanism":"Commit implementation checkpoint, update git checkpoint record if needed, and close the goal."} diff --git a/.planning/macro-plan/a2a-negotiation/AGENT-HANDOFF.md b/.planning/macro-plan/a2a-negotiation/AGENT-HANDOFF.md new file mode 100644 index 0000000..56edb3e --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/AGENT-HANDOFF.md @@ -0,0 +1,80 @@ +# A2A Negotiation Agent Handoff + +Status: ready for detailed phase planning + +## Objective + +Create the detailed `A2A-001 Source And Schema Foundation` phase plan. + +Do not implement source code until the phase plan exists and passes review. + +## Required Reading + +1. `.planning/macro-plan/A2A_NEGOTIATION_META_META_GOAL.md` +2. `.planning/macro-plan/a2a-negotiation/MACRO-PLAN.md` +3. `.planning/macro-plan/a2a-negotiation/ARCHITECTURE.md` +4. `.planning/macro-plan/a2a-negotiation/EXECUTION-SLICES.md` +5. `.planning/macro-plan/a2a-negotiation/EVALUATION.md` +6. `.planning/macro-plan/a2a-negotiation/REVIEW-AUDIT.md` +7. `docs/internal/protocol-kernel-architecture.md` +8. `docs/internal/protocol-layman.md` +9. `src/protocol/foundation/schema-core.ts` +10. `src/protocol/events/schemas.ts` +11. `src/protocol/areas/object-registry/` +12. `src/protocol/kernel.ts` + +## Runtime Profile + +Runtime: Codex or equivalent coding agent. + +Protected-action overlay: mandatory. + +Write scope for phase planning: + +- `.planning/macro-plan/a2a-negotiation/` +- future phase directory chosen by the planner + +Do not edit protocol source during phase planning. + +## First Phase Target + +`A2A-001 Source And Schema Foundation` + +The phase plan must name exact source files, test files, export posture, and +stop conditions for the schema/object/event foundation. + +## Non-Negotiable Boundaries + +- acceptance is not permission; +- linked agreement is not bearer auth; +- obligation binding is not gateway approval; +- terminal certificate is evidence only; +- receipt is not settlement; +- no cross-org trust without a trust model; +- no root exports before package-surface gates; +- no raw terms, secrets, signer material, payment payload, or payment signature + in readback. + +## Stop Conditions + +Stop before implementation if: + +- the phase plan cannot prove no-authority acceptance; +- the phase plan requires broad package exports; +- the phase plan needs cross-org trust; +- x402 raw sibling path is used as success; +- policy hook cannot refuse stale/mismatched agreement state; +- tests cannot detect authority overclaim. + +## Expected Phase Plan Output + +The next agent should produce: + +- `PLAN.md`; +- `TASKS.jsonl`; +- `TEST_PLAN.md`; +- `PROTECTED_ACTION_GATES.md`; +- `REVIEW.md` or review gate plan; +- exact source/test file list; +- verification commands; +- residual proof gaps. diff --git a/.planning/macro-plan/a2a-negotiation/ARCHITECTURE.md b/.planning/macro-plan/a2a-negotiation/ARCHITECTURE.md new file mode 100644 index 0000000..e8dbc33 --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/ARCHITECTURE.md @@ -0,0 +1,239 @@ +# A2A Negotiation Architecture Contract + +Status: planned + +## Invariant + +Negotiation records coordinate obligations. They never issue authority. + +## New Protocol Area + +```text +src/protocol/areas/negotiation/ + schemas.ts + inputs.ts + transitions.ts + guards.ts + artifacts.ts + index.ts +``` + +## Record Contracts + +### NegotiationSession + +Purpose: bounded context for a negotiation between agents or services. + +Required fields: + +- `negotiationSessionId` +- `principalId` +- `initiatingAgentId` +- `partyRefs` +- `allowedActionTypeIds` +- `allowedResourceRefs` +- `sessionDigest` +- `transcriptEvidenceRefs` +- `expiresAt` +- `status` +- non-authority flags + +Non-authority: opening a session creates no agreement and no protected-action +authority. + +### NegotiationOffer + +Purpose: records offered terms and proposed obligations. + +Required fields: + +- `negotiationOfferId` +- `negotiationSessionId` +- `offeredByPartyRef` +- `respondsToOfferId` +- `termsDigest` +- `redactedTermsSummary` +- `proposedObligations` +- `offerDigest` +- `expiresAt` + +Non-authority: an offer is evidence only. + +### NegotiationDecision + +Purpose: records accept, reject, counter, or withdraw decisions over one offer. + +Required fields: + +- `negotiationDecisionId` +- `negotiationSessionId` +- `negotiationOfferId` +- `decidedByPartyRef` +- `decision` +- `decisionDigest` +- `attestationRef` + +Non-authority: acceptance creates no policy decision, greenlight, gateway check, +signer use, mutation, receipt, export, certificate, or reusable authorization. + +### LinkedAgreement + +Purpose: terminal agreement evidence for one accepted offer. + +Required fields: + +- `linkedAgreementId` +- `negotiationSessionId` +- `acceptedOfferId` +- `acceptedDecisionId` +- `acceptedTermsDigest` +- `partyRefs` +- `obligationRefs` +- `agreementDigest` +- `status` +- `expiresAt` + +Non-authority: a linked agreement cannot be used as a bearer token. + +### AgreementObligationBinding + +Purpose: binds one negotiated obligation to one exact `ActionContract`. + +Required fields: + +- `agreementObligationBindingId` +- `linkedAgreementId` +- `obligationRef` +- `responsiblePartyRef` +- `counterpartyRef` +- `actionContractId` +- `actionContractDigest` +- `expectedParamsDigest` +- `bindingDigest` +- `bindingStatus` + +Invariant: one binding points to one contract. One contract can clear at most +one gateway-checked mutation attempt through existing greenlight rules. + +### AgreementStatusTransition + +Purpose: records status changes such as active, withdrawn, expired, disputed, +superseded, or resolved. + +Required fields: + +- `agreementStatusTransitionId` +- `linkedAgreementId` +- `fromStatus` +- `toStatus` +- `reasonCode` +- `transitionDigest` +- `supersededByAgreementId` +- `effectiveAt` + +## Event Additions + +Add to `ContractStreamEventSchema`: + +```text +negotiation_session_opened +negotiation_offer_recorded +negotiation_decision_recorded +linked_agreement_recorded +agreement_obligation_bound +agreement_status_changed +``` + +Partitioning: use organization stream with `negotiation:` and +`agreement:` partition keys first. Do not add a new stream scope until a +query requirement proves it. + +## Object Registry + +All negotiation records: + +```text +exportPosture: "transition_evidence" +rawReadPosture: "audit_read" +``` + +Do not expose raw transcript text, raw terms, secrets, payment payloads, signer +material, or hidden counterparty metadata through raw reads. + +## Kernel Facade + +Add methods: + +```text +openNegotiationSession(input) +recordNegotiationOffer(input) +recordNegotiationDecision(input) +recordLinkedAgreement(input) +bindAgreementObligation(input) +transitionAgreementStatus(input) +``` + +Each transition must commit records with events through the existing recorder +and conflict semantics. + +## Policy Hook + +When `ActionContract.clearingEvidenceRefs.obligationRef` is present, policy can +require: + +- `LinkedAgreement` exists; +- agreement status is active; +- agreement is not expired; +- obligation exists in the accepted terms; +- `AgreementObligationBinding` matches the action contract; +- responsible party and counterparty match; +- contract digest and params digest match expected values; +- required evidence refs are present; +- no active isolation blocks the party, agreement, resource, gateway, or + credential ref. + +Policy refusal reason codes should be specific: + +- `agreement_missing` +- `agreement_not_active` +- `agreement_expired` +- `agreement_disputed` +- `agreement_withdrawn` +- `agreement_superseded` +- `obligation_missing` +- `obligation_binding_missing` +- `obligation_binding_digest_mismatch` +- `obligation_contract_digest_mismatch` +- `obligation_params_mismatch` +- `obligation_party_mismatch` +- `obligation_counterparty_mismatch` + +## Readback Projections + +Add redacted projections: + +```text +NegotiationTimelineProjection +LinkedAgreementProjection +AgreementObligationProjection +``` + +Required readback axes: + +- negotiation status; +- agreement status; +- obligation binding status; +- action contract status; +- policy status; +- gateway status; +- downstream outcome status; +- proof gaps; +- non-claims. + +## Cross-Org Boundary + +The first implementation is same-tenant/org local/reference unless a separate +trust model is admitted. + +Cross-org trust, remote JWKS, portable acceptance, settlement, and marketplace +certification remain proof gaps. diff --git a/.planning/macro-plan/a2a-negotiation/EVALUATION.md b/.planning/macro-plan/a2a-negotiation/EVALUATION.md new file mode 100644 index 0000000..dd8b8d3 --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/EVALUATION.md @@ -0,0 +1,90 @@ +# A2A Negotiation Evaluation Suite + +Status: planned + +## Evaluation Goal + +Bad A2A work must fail objective tests before it can become source truth. + +## Unit And Schema Evals + +- `NegotiationSession` rejects empty parties, unsupported action types, expired + sessions, and missing evidence refs. +- `NegotiationOffer` rejects missing terms digest and obligation refs. +- `NegotiationDecision` rejects acceptance by a non-party. +- `LinkedAgreement` rejects accepted terms digest mismatch. +- `AgreementObligationBinding` rejects missing action contract digest. +- `AgreementStatusTransition` rejects invalid status transitions. + +## Transition Evals + +- opening session emits `negotiation_session_opened`; +- recording offer emits `negotiation_offer_recorded`; +- recording acceptance emits `negotiation_decision_recorded`; +- linked agreement emits `linked_agreement_recorded`; +- binding emits `agreement_obligation_bound`; +- status transition emits `agreement_status_changed`; +- acceptance creates no `policy_decision`, `greenlight`, + `gateway_check_attempt`, `mutation_attempt`, `receipt`, + `receipt_export`, or `authority_certificate`. + +## Policy Evals + +- active exact agreement allows normal policy evaluation to continue; +- missing agreement refuses `agreement_missing`; +- expired agreement refuses `agreement_expired`; +- withdrawn agreement refuses `agreement_withdrawn`; +- disputed agreement refuses `agreement_disputed`; +- superseded agreement refuses `agreement_superseded`; +- missing obligation refuses `obligation_missing`; +- missing binding refuses `obligation_binding_missing`; +- digest mismatch refuses `obligation_contract_digest_mismatch`; +- params mismatch refuses `obligation_params_mismatch`; +- party mismatch refuses `obligation_party_mismatch`; +- counterparty mismatch refuses `obligation_counterparty_mismatch`; +- active isolation still refuses. + +## Gateway And x402 Evals + +- changed x402 amount refuses; +- changed target URL refuses; +- changed selected payment requirement refuses; +- replayed greenlight refuses; +- payment material appears only after verified gateway check; +- downstream finality unknown records proof gap; +- raw sibling payment path is refused, detected, or recorded as proof gap. + +## Readback Evals + +- readback shows negotiation status separately from policy status; +- readback shows gateway status separately from downstream outcome; +- support packet redacts raw terms, secrets, signer material, payment payload, + and payment signature; +- terminal certificate is shown as evidence only; +- proof gaps survive export/readback; +- six-month reconstruction can follow exact refs. + +## Product Evals + +- first fixture output includes JSON and Markdown; +- output names non-claims; +- output shows accepted offer created no authority; +- output shows bound obligation and exact action contract; +- output shows receipt/refusal/proof gap with reason codes; +- output does not claim settlement, marketplace, legal contract, reputation, + cross-org trust, or provider custody. + +## Suggested Commands + +Final command names are deferred to phase planning, but expected gates are: + +```bash +npm run test -- test/protocol/a2a-negotiation.test.ts +npm run test -- test/product/a2a-negotiated-x402.test.ts +npm run quality:claims +npm run quality:architecture +npm run check:repo +``` + +If broad repo gates fail from unrelated dirty work, the closeout must report the +exact blocker and preserve the focused A2A evidence. diff --git a/.planning/macro-plan/a2a-negotiation/EXECUTION-SLICES.md b/.planning/macro-plan/a2a-negotiation/EXECUTION-SLICES.md new file mode 100644 index 0000000..7a7a8ad --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/EXECUTION-SLICES.md @@ -0,0 +1,172 @@ +# A2A Negotiation Execution Slices + +Status: planned + +## A2A-001 Source And Schema Foundation + +Objective: create the non-authority schema foundation. + +Write scope: + +- `src/protocol/areas/negotiation/` +- `src/protocol/areas/object-registry/schemas.ts` +- `src/protocol/areas/object-registry/index.ts` +- `src/protocol/events/schemas.ts` +- focused schema tests + +Proof gates: + +- negotiation records parse and reject malformed variants; +- object registry entries are `transition_evidence` and `audit_read`; +- no policy, greenlight, gateway, mutation, receipt, or certificate records are + created; +- package root exports remain unchanged unless tests admit the surface. + +Stop conditions: + +- any schema field implies bearer authorization; +- raw transcript text becomes raw-readable; +- event names imply execution or settlement. + +## A2A-002 Transition Lifecycle + +Objective: implement session, offer, decision, linked agreement, obligation +binding, and status transitions. + +Write scope: + +- `src/protocol/areas/negotiation/transitions.ts` +- `src/protocol/areas/negotiation/guards.ts` +- `src/protocol/kernel.ts` +- transition route/SDK surfaces only if explicitly admitted +- focused transition tests + +Proof gates: + +- acceptance creates no authority records; +- linked agreement creation creates no authority records; +- status transitions are monotonic or explicitly superseding; +- duplicate acceptance and stale counteroffer paths refuse. + +Stop conditions: + +- acceptance directly calls policy or gateway; +- one linked agreement can bind multiple mutations without per-obligation + contracts; +- one party can authorize another party's gateway. + +## A2A-003 Obligation Binding To ActionContract + +Objective: bind one accepted obligation to one exact action contract. + +Write scope: + +- `src/protocol/areas/negotiation/` +- `src/protocol/areas/action-contract/` only if binding validation requires it +- tests for digest, party, counterparty, params, expiry, and status mismatch + +Proof gates: + +- `clearingEvidenceRefs.obligationRef` must match the binding; +- `counterpartyRef` must match the accepted counterparty; +- `actionContractDigest` and `paramsDigest` must match; +- mismatches refuse before policy greenlight. + +Stop conditions: + +- binding can mutate contract parameters; +- binding can be reused across different contracts; +- stale or withdrawn agreement can bind a fresh contract. + +## A2A-004 Policy Integration + +Objective: make policy aware of agreement-backed obligations. + +Write scope: + +- `src/protocol/areas/policy-greenlight/` +- reason-code registry +- policy tests + +Proof gates: + +- expired, withdrawn, disputed, superseded, missing, stale, or mismatched + agreement state produces policy refusal; +- active agreement with exact binding can proceed to normal greenlight rules; +- isolation still blocks policy and gateway. + +Stop conditions: + +- policy treats agreement as sufficient permission; +- refusal reason is generic or unauditable; +- gateway path can proceed without policy checking agreement state. + +## A2A-005 x402 Buyer/Seller Fixture + +Objective: prove first A2A negotiated protected-spend path. + +Write scope: + +- `examples/a2a-negotiated-x402/` +- product tests +- x402 adapter tests only as needed + +Proof gates: + +- buyer/seller accepted offer creates no authority; +- accepted obligation binds to `x402_payment.exact`; +- changed amount or endpoint refuses; +- replay refuses; +- signer/payment material appears only after `VerifiedGatewayCheck`; +- downstream finality unknown is proof gap, not success. + +Stop conditions: + +- fixture claims broad x402 compatibility; +- fixture claims hosted/provider/customer custody; +- fixture uses raw sibling payment path as success. + +## A2A-006 Evidence Readback And Support Packet + +Objective: make the chain inspectable without leaking raw terms or secrets. + +Write scope: + +- evidence projections; +- CLI/evidence readback only if admitted; +- example output `latest.json` and `latest.md`; +- product tests. + +Proof gates: + +- readback reconstructs agreement -> obligation -> contract -> policy -> + gateway -> receipt/refusal/proof-gap; +- readback distinguishes agreement status from authority status; +- raw terms, secrets, signer material, payment payload, and payment signature + are redacted or absent. + +Stop conditions: + +- support packet implies permission, recovery, or settlement; +- readback merges gateway check and downstream finality. + +## A2A-007 Review, Evaluation, And Closeout + +Objective: prove the implementation and claims. + +Required gates: + +- `npm run quality:claims`; +- `npm run quality:architecture`; +- focused protocol tests; +- focused product tests; +- package-surface tests; +- generated example outputs; +- final code review; +- security review; +- goal-backward verification. + +Promotion: + +- `READY_FOR_AGENT_EXECUTION` only after phase plans, source implementation, + tests, generated outputs, and reviews pass. diff --git a/.planning/macro-plan/a2a-negotiation/IMPLEMENTATION-EVAL-REVIEW.md b/.planning/macro-plan/a2a-negotiation/IMPLEMENTATION-EVAL-REVIEW.md new file mode 100644 index 0000000..b5c025a --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/IMPLEMENTATION-EVAL-REVIEW.md @@ -0,0 +1,109 @@ +# A2A Negotiation Implementation Eval Review + +Status: `PRODUCTION_READY_FOR_BOUNDED_LOCAL_REFERENCE_ROOM` +Score: `96/100` +Date: `2026-05-26` + +## Invariant At Stake + +Agent-to-agent agreement is evidence and policy input. It is not authority. + +The implementation is acceptable only if accepted negotiation evidence cannot +mint a policy decision, greenlight, gateway check, mutation attempt, receipt, or +certificate, and every consequential x402 payment remains bound to one exact +ActionContract plus one-use gateway enforcement. + +## Evaluation Verdict + +The bounded room is implemented end to end: + +```text +NegotiationSession +-> NegotiationOffer +-> NegotiationDecision +-> LinkedAgreement +-> AgreementObligationBinding +-> ActionContract +-> PolicyDecision / Greenlight or Refusal / ProofGap +-> GatewayCheck +-> x402 signer invocation only after verified gate +-> Receipt / ProofGap / ReplayRefusal +-> Support packet readback +``` + +## Coverage Matrix + +| Dimension | Result | Evidence | +| --- | --- | --- | +| Schema strictness | Covered | `test/protocol/negotiation-schemas.test.ts` | +| Object registry posture | Covered | `test/protocol/negotiation-object-registry.test.ts` | +| Recorded-only events | Covered | `test/protocol/negotiation-events.test.ts` | +| Negotiation transitions | Covered | `test/protocol/negotiation-transitions.test.ts` | +| Agreement creates no authority | Covered | `test/protocol/negotiation-transitions.test.ts`, `test/product/a2a-negotiated-x402-room.test.ts` | +| Obligation-to-contract exact binding | Covered | `src/protocol/areas/negotiation/transitions.ts`, `test/protocol/negotiation-policy.test.ts` | +| Policy refusal and proof-gap gates | Covered | `src/protocol/areas/negotiation/policy.ts`, `test/protocol/negotiation-policy.test.ts` | +| Scope drift rejection | Covered | `src/protocol/areas/negotiation/transitions.ts`, `src/protocol/areas/negotiation/policy.ts`, `test/protocol/negotiation-transitions.test.ts` | +| Session and offer expiry | Covered | `src/protocol/areas/negotiation/transitions.ts`, `src/protocol/areas/negotiation/policy.ts`, `test/protocol/negotiation-transitions.test.ts`, `test/protocol/negotiation-policy.test.ts` | +| Single-use obligation authority | Covered | Agreement-backed greenlights use an obligation-scoped idempotency ledger key; `test/protocol/negotiation-transitions.test.ts`, `test/protocol/negotiation-policy.test.ts` | +| Gateway remains final enforcement | Covered | `test/product/a2a-negotiated-x402-room.test.ts` | +| x402 signer material appears only post-gate | Covered | `test/product/a2a-negotiated-x402-room.test.ts` | +| Replay refusal | Covered | `test/product/a2a-negotiated-x402-room.test.ts` | +| Readback/support packet redaction | Covered | `src/surfaces/a2a-negotiation-support/index.ts`, `test/product/a2a-negotiated-x402-room.test.ts` | +| Generated fixture output | Covered | `examples/a2a-negotiated-x402-room/latest.json`, `examples/a2a-negotiated-x402-room/latest.md` | +| External A2A trust / legal contract / settlement | Explicit non-goal | Macro plan forbids these claims; source keeps refs imported evidence only | + +## Gates Run + +- `bun test test/protocol/negotiation-schemas.test.ts test/protocol/negotiation-object-registry.test.ts test/protocol/negotiation-events.test.ts test/architecture/negotiation-no-authority-surface.test.ts test/protocol/negotiation-transitions.test.ts test/protocol/negotiation-policy.test.ts test/product/a2a-negotiated-x402-room.test.ts` +- `bun examples/a2a-negotiated-x402-room/generate.ts` +- `npm run check:types` +- `npm run lint` +- `npm run quality:claims` +- `npm run quality:architecture` +- `npm run test` +- `npm run format:check` +- `npm run check:repo` after sidecar-review blocker fixes: 804 tests, 0 failures + +## Sidecar Review Findings Closed + +- Cross-scope negotiation evidence is refused before binding or policy. +- Expired negotiation sessions and offers are refused at transition time and + policy time. +- One linked agreement obligation cannot be rebound to multiple action + contracts, and agreement-backed greenlights reserve an obligation-scoped + idempotency ledger key. +- `x402_payment.exact` policy now applies by action class, not by optional + parameter presence. +- The support packet reports lifecycle assembly status instead of silently + collapsing errors into null lifecycle state. +- The A2A room now tests selected payment requirement drift and ships both JSON + and Markdown fixture output. + +## Residual Risks + +- The room is local/reference. It does not prove cross-org trust, identity + verification, marketplace operation, escrow, legal contract formation, + settlement finality, reputation, provider custody, or hosted production + custody. +- Negotiation transitions are kernel-only. No CLI, HTTP, MCP, SDK, or root + package surface is admitted for negotiation yet. +- The support packet is a readback projection over existing records. It is not a + review renderer and does not create authority. +- The single-use obligation ledger is proven through the existing policy + idempotency reservation path, not a new marketplace/settlement ledger. + +## Verdict + +Keep. + +This is a valid Tier 3 heat-up slice because it binds A2A negotiation evidence +into the existing protected-action spine without weakening the authority model. +The product claim must stay narrow: + +```text +Handshake records, binds, clears, refuses, and reconstructs one local/reference +agent-negotiated protected-action obligation. +``` + +The next mechanism is an admitted transport surface for recording negotiation +evidence, still without exposing greenlight or gateway authority. diff --git a/.planning/macro-plan/a2a-negotiation/MACRO-PLAN.md b/.planning/macro-plan/a2a-negotiation/MACRO-PLAN.md new file mode 100644 index 0000000..e079f73 --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/MACRO-PLAN.md @@ -0,0 +1,126 @@ +# A2A Negotiation Macro Plan + +Status: `READY_FOR_PHASE_PLANNING` +Run: `20260526T000830Z-a2a-negotiation-end2end` + +## Invariant At Stake + +Agent-to-agent agreement is not authority. + +Handshake may coordinate negotiated obligations only if every consequential +obligation is reduced to a fresh exact protected-action contract and then +cleared or refused through policy and gateway enforcement. + +## Product Claim Under Plan + +Allowed future claim after implementation and gates: + +```text +Handshake records, binds, clears, refuses, and reconstructs agent-negotiated +protected-action obligations. +``` + +Forbidden current claim: + +```text +Handshake supports A2A negotiation today. +``` + +Forbidden future overclaims: + +- marketplace operation; +- escrow; +- legal contract formation; +- settlement finality; +- reputation; +- dispute resolution; +- provider/customer custody; +- cross-org trust; +- generic A2A protocol support. + +## Selected Macro Move + +Create a non-authority `negotiation` protocol area: + +```text +NegotiationSession +-> NegotiationOffer +-> NegotiationDecision +-> LinkedAgreement +-> AgreementObligationBinding +-> AgreementStatusTransition +``` + +Then bind each accepted obligation to: + +```text +ActionContract.clearingEvidenceRefs.obligationRef +ActionContract.clearingEvidenceRefs.counterpartyRef +``` + +The binding feeds policy checks. It does not create authority. + +## First Proof + +Buyer-agent/seller-agent negotiation over one buyer-side +`x402_payment.exact` protected action. + +The proof must show: + +1. accepted offer creates no policy decision, greenlight, gateway check, signer + use, mutation, receipt, or certificate; +2. accepted obligation binds to one exact `ActionContract`; +3. policy can refuse mismatch, expiry, withdrawal, dispute, supersession, stale + evidence, changed params, and replay; +4. gateway still owns final enforcement before payment material; +5. receipt/readback separates agreement acceptance from downstream payment + finality. + +## Review Chain + +Inline lens sequence completed: + +```text +plan-ceo-review +-> plan-eng-review +-> plan-design-review +-> plan-devex-review +-> plan-agent-review +-> chair synthesis +-> validation audit +``` + +Review outputs: + +- `runs/20260526T000830Z-a2a-negotiation-end2end/raw/CEO.md` +- `runs/20260526T000830Z-a2a-negotiation-end2end/raw/ENGINEERING.md` +- `runs/20260526T000830Z-a2a-negotiation-end2end/raw/DESIGN.md` +- `runs/20260526T000830Z-a2a-negotiation-end2end/raw/DEVEX.md` +- `runs/20260526T000830Z-a2a-negotiation-end2end/raw/AGENT.md` + +## Key Decisions + +1. Use existing `clearingEvidenceRefs` as the contract bridge. +2. Add new records as `transition_evidence`, not `receipt_evidence` or + authority. +3. Keep public/root exports closed until package-surface tests admit them. +4. Keep first fixture local/reference and x402 buyer-side. +5. Do not solve cross-org trust in the first slice. +6. Treat marketplace and settlement language as explicit non-goals. +7. Make readback show agreement status, policy status, gateway status, and + downstream outcome as separate axes. + +## Blockers Before Implementation + +- A2A-001 phase plan must name exact source files and tests. +- Package export posture must be decided before public API exposure. +- Policy hook shape must be reviewed against existing policy transitions. +- Readback projection must prove redaction before support/export paths. +- Cross-org trust must remain a proof gap unless explicitly admitted later. + +## Final Status + +`READY_FOR_PHASE_PLANNING` + +The next valid step is a detailed phase plan for `A2A-001 Source And Schema +Foundation`. diff --git a/.planning/macro-plan/a2a-negotiation/README.md b/.planning/macro-plan/a2a-negotiation/README.md new file mode 100644 index 0000000..3f2ee1b --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/README.md @@ -0,0 +1,44 @@ +# A2A Negotiation Macro Plan Package + +Run: `20260526T000830Z-a2a-negotiation-end2end` +Status: `READY_FOR_PHASE_PLANNING` + +## Scope + +This package plans the architecture, implementation slices, evaluation suite, +and review/audit gates for agent-to-agent negotiated protected-action events in +Handshake. + +It is derived from: + +- `.planning/macro-plan/A2A_NEGOTIATION_META_META_GOAL.md` +- `runs/20260526T000830Z-a2a-negotiation-end2end/input.md` +- current source anchors listed in the run `source-snapshot.md` +- inline CEO, engineering, design, DevEx, and agent reviews + +## Macro Move + +Add a non-authority negotiation layer where agents can record offers, +decisions, linked agreements, and obligation bindings, while every +consequential obligation still clears through the normal protected-action +lifecycle. + +## Artifact Index + +- `MACRO-PLAN.md`: chair-owned plan, decisions, status, and proof boundaries. +- `ARCHITECTURE.md`: protocol/object/event/policy/readback architecture. +- `EXECUTION-SLICES.md`: ordered implementation slices and proof gates. +- `EVALUATION.md`: failing/passing eval suite and command targets. +- `REVIEW-AUDIT.md`: review, audit, claim, and promotion gates. +- `AGENT-HANDOFF.md`: fresh-agent execution context for detailed phase planning. +- `TASKS.jsonl`: assignable next mechanisms. +- `runs/20260526T000830Z-a2a-negotiation-end2end/`: source snapshot, raw lens + reviews, normalized findings, chair synthesis, validation. + +## Status Meaning + +`READY_FOR_PHASE_PLANNING` means a detailed `A2A-001` phase plan can be written. +It does not mean protocol code is implemented, tested, exported, or launchable. + +This package is not `READY_FOR_AGENT_EXECUTION` because no source implementation +or detailed phase plan has been verified yet. diff --git a/.planning/macro-plan/a2a-negotiation/REVIEW-AUDIT.md b/.planning/macro-plan/a2a-negotiation/REVIEW-AUDIT.md new file mode 100644 index 0000000..13493eb --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/REVIEW-AUDIT.md @@ -0,0 +1,88 @@ +# A2A Negotiation Review And Audit Gates + +Status: planned + +## Required Review Chain + +1. CEO review: + - market-opening value; + - first buyer; + - why Handshake should not own the marketplace; + - cleared work unit thesis. +2. Engineering review: + - schema and transition architecture; + - policy/gateway interaction; + - storage/event/replay behavior; + - package-surface risk. +3. Design review: + - agreement-vs-authority legibility; + - operator readback; + - redacted support packet; + - mobile/detail state. +4. DevEx review: + - time to first A2A proof; + - fixture path; + - errors and reason codes; + - public API/export posture. +5. Agent review: + - runtime profile; + - tool contract; + - write scopes; + - stop conditions; + - protected-action overlay. +6. Security review: + - tenancy; + - cross-party evidence; + - raw read posture; + - secret and signer material; + - replay and stale state. +7. Claim audit: + - docs, examples, README, CLI help, package exports; + - forbidden words and overclaims. +8. Verification audit: + - each requirement mapped to tests, generated outputs, or explicit proof gap. + +## Current Inline Reviews + +This macro package includes inline reviews under: + +```text +runs/20260526T000830Z-a2a-negotiation-end2end/raw/ +``` + +These satisfy phase-planning pressure. They do not replace post-implementation +code review, secure-phase review, or goal-backward verification. + +## P0 Audit Questions + +- Does any record create authority before `PolicyDecision` and `GatewayCheck`? +- Can one accepted offer authorize more than one mutation? +- Can one party authorize another party's gateway? +- Can an agent reach raw x402 payment material? +- Can stale, expired, withdrawn, disputed, or superseded agreement state clear? +- Can readback hide proof gaps? +- Can support/export leak raw terms or secrets? +- Can terminal certificate be mistaken for permission? +- Can public docs claim marketplace, settlement, or legal contract formation? + +## Promotion Gates + +Phase planning may begin when this package exists. + +Implementation may begin only after `A2A-001` has a detailed phase plan. + +Agent execution may begin only after: + +- exact file write scopes exist; +- focused tests are named; +- stop conditions are explicit; +- source branch/worktree state is classified; +- rollback/abandonment criteria exist. + +Launch claims may begin only after: + +- implementation is merged or otherwise source-owned; +- demo outputs are regenerated; +- claim and architecture gates pass; +- support/readback packet exists; +- non-claims are visible. diff --git a/.planning/macro-plan/a2a-negotiation/TASKS.jsonl b/.planning/macro-plan/a2a-negotiation/TASKS.jsonl new file mode 100644 index 0000000..e08d0db --- /dev/null +++ b/.planning/macro-plan/a2a-negotiation/TASKS.jsonl @@ -0,0 +1,6 @@ +{"id":"A2A-PLAN-001","status":"ready","title":"Write A2A-001 phase plan","objective":"Create a detailed source-and-schema foundation plan for the negotiation protocol area.","source":["A2A_NEGOTIATION_META_META_GOAL.md","a2a-negotiation/ARCHITECTURE.md","a2a-negotiation/EXECUTION-SLICES.md"],"acceptance":["exact source files named","test files named","no-authority acceptance gate included","package export posture decided or blocked"],"stop_conditions":["requires cross-org trust","requires raw signer/payment material","requires broad root exports before tests"]} +{"id":"A2A-PLAN-002","status":"ready","title":"Specify negotiation schema contracts","objective":"Define field-level contracts for NegotiationSession, NegotiationOffer, NegotiationDecision, LinkedAgreement, AgreementObligationBinding, and AgreementStatusTransition.","source":["a2a-negotiation/ARCHITECTURE.md"],"acceptance":["all schema fields typed","digests and statuses named","redaction posture named","malformed variants listed"],"stop_conditions":["schema implies bearer authority","raw transcript terms become audit-readable"]} +{"id":"A2A-PLAN-003","status":"ready","title":"Specify transition and event tests","objective":"Plan tests for negotiation transitions and contract stream events.","source":["a2a-negotiation/EVALUATION.md"],"acceptance":["event list mapped to tests","acceptance creates no authority test included","duplicate and stale decision tests included"],"stop_conditions":["tests only check happy path","events imply execution or settlement"]} +{"id":"A2A-PLAN-004","status":"ready","title":"Specify obligation binding and policy hook","objective":"Plan exact validation between accepted obligations, AgreementObligationBinding, and ActionContract clearingEvidenceRefs.","source":["a2a-negotiation/ARCHITECTURE.md","a2a-negotiation/EVALUATION.md"],"acceptance":["digest mismatch refusals named","party/counterparty mismatch refusals named","expired/withdrawn/disputed/superseded refusals named"],"stop_conditions":["policy can greenlight without agreement state check","binding mutates contract parameters"]} +{"id":"A2A-PLAN-005","status":"ready","title":"Specify x402 buyer-seller fixture","objective":"Plan the first buyer-agent/seller-agent x402_payment.exact fixture and generated outputs.","source":["a2a-negotiation/EXECUTION-SLICES.md","a2a-negotiation/EVALUATION.md"],"acceptance":["fixture path named","JSON and Markdown outputs planned","changed params and replay cases included","non-claims included"],"stop_conditions":["fixture claims broad x402 compatibility","fixture claims hosted/provider/customer custody","raw sibling payment path used as success"]} +{"id":"A2A-PLAN-006","status":"ready","title":"Specify readback and support packet","objective":"Plan redacted projections that reconstruct agreement to terminal protected-action outcome.","source":["a2a-negotiation/ARCHITECTURE.md","a2a-negotiation/REVIEW-AUDIT.md"],"acceptance":["NegotiationTimelineProjection named","LinkedAgreementProjection named","AgreementObligationProjection named","redaction gates named"],"stop_conditions":["readback merges gateway and downstream finality","support packet implies permission or recovery"]} diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/evidence.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/evidence.md new file mode 100644 index 0000000..1014183 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/evidence.md @@ -0,0 +1,342 @@ +## Audit Scope + +Focus: evidence plan, validation, proof gaps, and closeout commands for the Tier 1 / Tier 2 product-simplification macro-plan run. + +Verdict: fail for fresh-agent handoff as-is. The source boundary is strong enough for macro planning, and the macro-map validator passes, but the macro-plan package is not currently validated and cannot be treated as execution-ready evidence. The macro-plan validator fails, and the artifacts disagree about whether the user-owned noun/scope decision is resolved or still blocking. + +This audit does not select a macro move, synthesize the final plan, promote final status, or authorize implementation. + +## Source Boundary + +Authoritative source boundary for this audit: + +| Source | Role | Evidence Posture | +| --- | --- | --- | +| `AGENTS.md` user-provided instructions | Doctrine and invariant boundary | Governs this audit | +| `/Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` | Macro-plan workflow and success criteria | Required source | +| `/Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-plan-contract.md` | Required artifacts and sections | Required source | +| `/Users/joelchan/.codex/skills/gsd-macro-plan/references/output-quality-bar.md` | Quality bar beyond validator | Required source | +| `/Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py` | Structural validator behavior | Required source and executed command | +| `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md` | Run input, success criteria, anti-patterns, initial status | Required source | +| `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/source-snapshot.md` | Run-local source snapshot and non-proofs | Required source | +| `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md` | Run-local blocked checks | Additional run source | +| `.planning/macro-map/FACET-MAP.md` | Lens convergence and blocked checks | Required source | +| `.planning/macro-map/CONCERNS.md` | Open P0/P1 concerns | Required source | +| `.planning/codebase/TESTING.md` | Focused and repo verification gates | Required source | +| `README.md` | Current product/kernel orientation and command posture | Required source | +| `docs/internal/decisions.md` | Canon decisions, proof ledger, expansion gate | Required source | +| `docs/internal/protocol-notes.md` | Protocol primitive, evidence rules, proof lanes | Required source | +| `package.json` | Actual package scripts and command contract | Required source | +| `.planning/macro-plan/*.md`, `.planning/macro-plan/TASKS.jsonl` | Current macro-plan package under audit | Additional source needed to audit handoff | + +Non-sources: chat memory, future intent, sidecar expectations, and `.planning/` scratch not named above. `.planning/` is evidence for planning posture only; it is not repo-facing canon. + +## Files Read + +- `/Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-plan-contract.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/output-quality-bar.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/source-snapshot.md` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md` +- `.planning/macro-map/FACET-MAP.md` +- `.planning/macro-map/CONCERNS.md` +- `.planning/codebase/TESTING.md` +- `README.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` +- `package.json` +- `.planning/macro-plan/README.md` +- `.planning/macro-plan/MACRO-PLAN.md` +- `.planning/macro-plan/EXECUTION-SLICES.md` +- `.planning/macro-plan/AGENT-HANDOFF.md` +- `.planning/macro-plan/RUNTIME-GATES.md` +- `.planning/macro-plan/PROTECTED-ACTION-GATES.md` +- `.planning/macro-plan/EVIDENCE-PLAN.md` +- `.planning/macro-plan/REVIEW-GATES.md` +- `.planning/macro-plan/RISKS.md` +- `.planning/macro-plan/DECISIONS.md` +- `.planning/macro-plan/TASKS.jsonl` + +## Invariant At Stake + +Product simplification may hide protocol complexity from users, but it must not hide or weaken authority, gateway, evidence, refusal, proof-gap, isolation, or reconstruction boundaries. + +For evidence closeout, the specific invariant is: a fresh agent must be able to reconstruct what is proven, what is only planning posture, what is explicitly blocked, and which commands must pass before implementation. If the plan claims readiness while validation fails or artifacts disagree about blockers, this is not auditable. + +## Pass Conditions + +Artifact completeness checklist: + +| Artifact | Required Evidence Condition | Current Posture | +| --- | --- | --- | +| `README.md` | Scope, source map, sidecar review, status, artifact index | Present, but sidecar path references a different run ID than this assigned audit run | +| `MACRO-PLAN.md` | Exactly one status token, current evidence, non-proofs, verification gates, smallest next mechanism | Present, but validator fails because multiple status tokens appear | +| `EXECUTION-SLICES.md` | Slices with source evidence, stop conditions, proof gates, rollback/abandonment, handoff needs | Present; S0 decision gate conflicts with claimed ready posture | +| `AGENT-HANDOFF.md` | Fresh-agent objective, source boundary, runtime profile, tool contract, checkpoints, stop conditions, proof gaps | Present, but says the macro plan is blocked until noun-set acceptance | +| `RUNTIME-GATES.md` | Per-runtime posture, approval behavior, subagent behavior, continuation, blocked checks | Present; correctly proof-gaps multi-host containment | +| `PROTECTED-ACTION-GATES.md` | Candidate actions, authority boundary, gateway boundary, bypass posture, readback separation, proof gaps | Present; correctly treats admission/handle as non-candidate evidence | +| `EVIDENCE-PLAN.md` | Current evidence, commands, replay/refusal cases, review prompts, fixtures/examples, redaction, runtime artifacts, unavailable evidence | Present; needs stronger exact command plan and current validation result | +| `REVIEW-GATES.md` | CEO, engineering, design, DevEx, agent, runtime, protected-action pass/block gates | Present, but says the plan is blocked and no sidecar auditors ran | +| `RISKS.md` | Each risk has ID, severity, trigger, mitigation, owner, status | Present | +| `DECISIONS.md` | Each decision has ID, status, decision, rationale, source, revisit trigger | Present, but `MPLAN-D001` says blocked macro plan while README/MACRO-PLAN say ready for phase planning | +| `TASKS.jsonl` | Valid JSONL task records with evidence, acceptance, non-goals, proof gate, next mechanism | Present, but `MPLAN-001` is still open and later tasks are blocked | + +Validation pass conditions before handoff: + +1. `python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan` exits 0. +2. Status posture is consistent across `README.md`, `MACRO-PLAN.md`, `AGENT-HANDOFF.md`, `REVIEW-GATES.md`, `DECISIONS.md`, and `TASKS.jsonl`. +3. The plan either records the user decision as accepted and closes `MPLAN-001`, or keeps implementation blocked and avoids ready phrasing. +4. `EVIDENCE-PLAN.md` records the exact current validator output, not only a future command. +5. `REVIEW-GATES.md` records this and other sidecar audits before any readiness claim. +6. `blocked-checks.md` is updated or reconciled so it no longer says the macro-plan package has not been written or validated after the package exists. +7. Implementation entry is limited to phase planning unless a detailed phase plan names source files, focused tests, proof gaps, and rollback gates. + +Implementation-entry conditions: + +- Fresh agent may begin detailed phase planning only after macro-plan validation passes and status contradictions are reconciled. +- Fresh agent may begin source implementation only after a detailed phase plan exists for S1-S3 with source-opened target files, exact focused tests, and explicit non-authority acceptance criteria. +- Fresh agent must not implement fixture/demo work until S1-S4 guardrail gates exist or are explicitly blocked with proof gaps. +- Fresh agent must checkpoint with `git status --short` before edits and after each slice. The current checkpoint observed by this audit is clean on branch `main`; no commit was made. + +## Failures + +1. Structural validator failure. + +Current command result: + +```bash +python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +``` + +Current output: + +```text +ERROR: MACRO-PLAN.md must contain exactly one plan status +``` + +The immediate cause is that `MACRO-PLAN.md` contains more than one recognized status token. It includes `READY_FOR_PHASE_PLANNING` twice and also mentions `NEEDS_USER_DECISION`. + +2. Status contradiction across artifacts. + +- `README.md` and `MACRO-PLAN.md` say `READY_FOR_PHASE_PLANNING`. +- `AGENT-HANDOFF.md` says the macro plan is blocked until the user accepts the surface-first noun set. +- `REVIEW-GATES.md` says this macro plan is blocked because the macro map requires a user-owned noun/scope decision. +- `DECISIONS.md` says the accepted decision is to produce a blocked macro plan rather than an executable plan. +- `TASKS.jsonl` keeps `MPLAN-001` open and later tasks blocked. +- `blocked-checks.md` says the macro-plan package has not yet been written or validated, which is stale relative to the package now under audit. + +This is not a cosmetic inconsistency. A fresh agent could either start phase planning from `MACRO-PLAN.md` or stop at `AGENT-HANDOFF.md` and `REVIEW-GATES.md`. That means the handoff is not reconstructable. + +3. Evidence plan is command-shaped but not closeout-shaped. + +`EVIDENCE-PLAN.md` lists the right categories: current evidence, commands, replay/refusal cases, review prompts, fixtures/examples, readback/redaction checks, runtime proof artifacts, and unavailable evidence. It does not record the current macro-plan validator failure, the stale blocked-checks state, or the cross-artifact status conflict. + +4. Review gate state is not reconciled with this sidecar process. + +`REVIEW-GATES.md` says no sidecar auditors ran because normal macro planning is blocked. This audit exists and must be summarized by the chair before any status is promoted. This sidecar cannot promote status; it can only report that review evidence is currently incomplete. + +5. Handoff says "wait for user decision" while run input says the user explicitly authorized the full macro-plan pass. + +This may be resolvable by chair reconciliation, but as written it is a handoff hazard. If the user decision is accepted, the artifacts should record the decision and close or supersede S0. If not accepted, the ready status should be removed. + +## Proof Gaps + +Evidence gaps: + +- No current passing macro-plan validator output. +- No reconciliation record explaining whether the noun/scope decision is accepted, blocked, or superseded. +- No source schema for `ServiceWorkflowAdmission`. +- No source schema for `ServiceWorkflowHandle`. +- No negative tests proving admission/handle cannot create or satisfy `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheckAttempt`, `Receipt`, `AuthorityCertificate`, signer invocation, payment material, or mutation. +- No handle misuse tests for loops, retries, dynamic tool names, stale review surfaces, changed params, raw siblings, browser/network side channels, replay, or idempotency mismatch. +- No implemented readback artifact showing admission, handle, action request, clearance, receipt, refusal, and proof gap as separate states. +- No runtime proof artifacts for Claude Code, Hermes, OpenClaw, generic MCP, browser, A2A, or OpenAPI. +- No native host containment proof. +- No live external rail proof for ERC-8004, auth.md deployment corpus, live x402 provider custody, hosted custody, provider signer lifecycle, Agentic.Market listing, facilitator operation, settlement/finality, or MCP Registry lookup for this run. +- No evidence that public-facing docs or examples preserve `createsAuthority: false` for the proposed nouns because those docs/schemas do not exist yet. + +Non-proofs that must stay explicit: + +- Macro-map validation is not macro-plan validation. +- Passing the structural macro-plan validator would not prove source implementation, authority safety, runtime containment, or user comprehension. +- Codex-local or package-profile evidence does not prove other host containment. +- Admission/readback evidence does not prove policy, greenlight, gateway check, signer use, mutation, receipt export, or terminal certificate. +- Receipt evidence does not prove downstream business success or payment settlement. +- `.planning/codebase/*` routes implementation attention, but source files and tests must still be opened before edits. + +Validator risks: + +- The validator catches the current multiple-status failure, but its status scanner also treats negative mentions as status tokens. The chair should avoid writing status constants in explanatory prose inside `MACRO-PLAN.md`. +- The validator is structural. It does not detect cross-file contradictions like blocked handoff plus ready macro status. +- It does not verify that commands were run, that sidecar audits exist, that stale `blocked-checks.md` was reconciled, or that `TASKS.jsonl` statuses align with `MACRO-PLAN.md`. +- It does not prove the content-level quality bar: source-opened implementation paths, real negative tests, runtime proof artifacts, readback redaction, or refusal/replay fixtures. +- It can reject weak filler strings such as "run tests"; current artifacts mostly avoid that, but any repair should keep proof gates exact rather than generic. + +Replay/refusal cases that must remain in the plan and later fixtures: + +- consumed greenlight replay refuses before signer reuse; +- idempotency mismatch requires a new exact contract; +- stale metadata requires reload; +- changed observed parameters require recraft; +- raw sibling route requires stop, isolation, or proof gap; +- credential-ref or authority-ref isolation blocks policy/gateway; +- proof gap does not grant retry permission; +- handle presented as policy/gateway/signer/mutation input refuses; +- dynamic tool construction or late-bound endpoint/amount refuses or requires a new exact action contract. + +Readback/redaction gaps to close before implementation claims: + +- Admission readback must expose refs, digests, claim status, expiry, proof-gap reason, and non-authority flags only. +- It must not expose raw credentials, tokens, payment payloads, payment signatures, private keys, provider secrets, raw authorization headers, or signer material. +- Receipt readback must remain separate from admission readback. +- Runtime evidence, gateway-check evidence, mutation-attempt evidence, downstream observation, replay refusal, proof gap, and certificate must be separate in readback. + +## Required Changes + +1. Reconcile status before any handoff. + +Choose one evidence posture and make every artifact agree: + +- If the user decision is accepted: close or supersede `MPLAN-001`, update `AGENT-HANDOFF.md`, `REVIEW-GATES.md`, `DECISIONS.md`, and `blocked-checks.md`, and keep `READY_FOR_PHASE_PLANNING` only once in `MACRO-PLAN.md`. +- If the decision remains blocked: remove ready phrasing from `README.md` and `MACRO-PLAN.md`, keep tasks blocked, and set the plan posture to blocked without laundering it into phase planning. + +2. Fix structural validation. + +`MACRO-PLAN.md` must contain exactly one macro-plan status token. Avoid mentioning other status constants in prose. Then rerun: + +```bash +python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +``` + +3. Update evidence closeout. + +`EVIDENCE-PLAN.md` should record: + +- macro-map validator result; +- macro-plan validator result; +- current git branch and status; +- whether sidecar audits exist and where; +- exact commands that must pass before phase planning versus implementation; +- explicit skipped commands and why; +- stale or unavailable evidence. + +4. Reconcile run-local `blocked-checks.md`. + +It currently says the package has not yet been written or validated. That statement is stale now that the package exists and macro-plan validation has been attempted. It should be updated by the chair, not this sidecar. + +5. Make review prompts operational. + +Review prompts should become pass/block questions tied to artifacts and commands: + +- CEO: does the plan avoid a standalone Passport identity/trust/certification claim? +- Engineering: do source paths stay outside protocol authority and carry hard non-authority flags? +- Design/DevEx: can users distinguish admission, action request, clearance, receipt, refusal, and proof gap? +- Agent/runtime: can generated code misuse the handle in loops, retries, branches, dynamic tools, stale review, raw siblings, or browser/network side channels? +- Protected-action: can any field create or satisfy policy, greenlight, gateway check, signer use, mutation, receipt, or certificate? + +6. Add an exact verification command plan. + +Minimum planning closeout: + +```bash +python3 /Users/joelchan/.codex/skills/gsd-plan-map/scripts/validate_plan_map_output.py .planning/macro-map +python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +git status --short +``` + +Minimum first implementation-slice closeout after S1-S3 source changes: + +```bash +npm run quality:claims +npm run quality:architecture +npm run format:check +git diff --check +``` + +Protocol/readback implementation closeout when admission/handle schemas or projections exist: + +```bash +npm run test -- test/architecture/surface-boundary-posture.test.ts test/architecture/claim-boundary.test.ts test/architecture/naming-posture.test.ts +npm run test -- test/protocol/evidence-projections.test.ts test/protocol/representation-contract.test.ts test/runtime/runtime-ingress.test.ts +npm run quality:claims +npm run quality:architecture +``` + +Protected-action fixture closeout when x402/auth.md stitch work begins: + +```bash +npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts test/integration/auth-md-protected-call.test.ts test/integration/auth-md-receipt-reconstruction.test.ts +npm run test -- test/conformance/protected-mutation-adapter-conformance.test.ts +npm run check:repo +``` + +Full repo closeout before any claim that implementation is integrated: + +```bash +npm run check:repo +git status --short +``` + +Git checkpoint advice: + +- Do not commit from the audit sidecar. +- Before implementation starts, the chair or implementing agent should record `git status --short` and `git branch --show-current`. +- Create a checkpoint after macro-plan reconciliation and before source edits. +- After each slice, use `git status --short`, `git diff --stat`, and the slice-specific tests before proceeding. +- Do not mix macro-plan artifact repairs with source implementation in the same checkpoint. + +## Status Recommendation + +Do not promote final status from this sidecar. + +Evidence recommendation: block fresh-agent handoff until the macro-plan validator passes and the status contradictions are reconciled. After that, the package may be suitable for detailed phase planning, not source implementation. Source implementation should remain blocked until a detailed phase plan for the first slice names exact source paths, focused tests, proof gaps, rollback criteria, and non-authority acceptance conditions. + +Smallest next mechanism: reconcile the plan-status evidence by updating the macro-plan package so `MACRO-PLAN.md` has exactly one status token and every handoff/review/task artifact agrees on whether S0 is closed or still blocking, then rerun the macro-plan validator and record the result in `EVIDENCE-PLAN.md`. + +## Commands Or Tools Used + +Commands and tools used for this audit: + +```bash +rg -n "Tier 3 doctrine|x402 sandbox|tier1|Tier 1|macro-plan|protected-action|evidence|proof gap" /Users/joelchan/.codex/memories/MEMORY.md +sed -n '84,121p' /Users/joelchan/.codex/memories/MEMORY.md +sed -n '221,232p' /Users/joelchan/.codex/memories/MEMORY.md +sed -n '1,240p' /Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md +sed -n '1,260p' /Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-plan-contract.md +sed -n '1,260p' /Users/joelchan/.codex/skills/gsd-macro-plan/references/output-quality-bar.md +sed -n '1,520p' /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py +sed -n '1,260p' .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md +sed -n '1,320p' .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/source-snapshot.md +sed -n '1,240p' .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md +sed -n '1,340p' .planning/macro-map/FACET-MAP.md +sed -n '1,320p' .planning/macro-map/CONCERNS.md +sed -n '1,340p' .planning/codebase/TESTING.md +sed -n '1,360p' README.md +sed -n '1,360p' docs/internal/decisions.md +sed -n '1,720p' docs/internal/protocol-notes.md +sed -n '1,260p' package.json +rg --files .planning/macro-plan .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification +sed -n '1,420p' .planning/macro-plan/EXECUTION-SLICES.md +sed -n '1,360p' .planning/macro-plan/RUNTIME-GATES.md +sed -n '1,360p' .planning/macro-plan/PROTECTED-ACTION-GATES.md +sed -n '1,320p' .planning/macro-plan/RISKS.md +sed -n '1,260p' .planning/macro-plan/DECISIONS.md +sed -n '1,260p' .planning/macro-plan/README.md +sed -n '1,260p' .planning/macro-plan/TASKS.jsonl +python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +python3 /Users/joelchan/.codex/skills/gsd-plan-map/scripts/validate_plan_map_output.py .planning/macro-map +git status --short +git branch --show-current +rg -n "READY_FOR|NEEDS_|BLOCKED|CUT|DEGRADED" .planning/macro-plan/MACRO-PLAN.md .planning/macro-plan/README.md .planning/macro-plan/AGENT-HANDOFF.md .planning/macro-plan/REVIEW-GATES.md .planning/macro-plan/TASKS.jsonl .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md +``` + +Observed command results: + +- Macro-map validator: `Plan map output is valid.` +- Macro-plan validator: `ERROR: MACRO-PLAN.md must contain exactly one plan status` +- Git branch: `main` +- Git status before report write: clean + +Only this file was written by this sidecar audit. diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/product-devex-design.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/product-devex-design.md new file mode 100644 index 0000000..32e06dc --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/product-devex-design.md @@ -0,0 +1,212 @@ +## Audit Scope + +Focus: 10-star product design, DevEx, and adoption for Tier 1 / Tier 2 product simplification. + +Verdict: keep the simplification direction, but do not let it become executable macro-plan evidence until one source-owned product-surface readback contract, one first-use demo, and negative non-authority tests exist. "Simple" must mean the user sees fewer kernel nouns while the system preserves the exact boundary: + +```text +standing evidence +-> service admission/readback +-> non-authority workflow handle +-> fresh protected action request +-> exact policy decision +-> one-use greenlight or refusal +-> gateway check before mutation +-> receipt, refusal, replay refusal, proof gap, or terminal evidence +``` + +If Passport, Admission, Badge, Handle, Certificate, CLI, MCP, SDK, docs, or examples imply reusable permission, this is ambient authority wearing a badge. + +## Source Boundary + +Canonical repo truth wins over `.planning/` scratch. The current source boundary says: + +- `README.md`, `docs/internal/decisions.md`, and `docs/internal/protocol-notes.md` define Handshake as protected action infrastructure for automated decision making. +- Product surfaces are CLI, MCP, SDK, docs, demos, or service readback that expose proposal/evidence/readback without creating authority. +- The current first official wedge is one buyer-side `x402_payment.exact` per-call protected action. +- Public npm availability, MCP Registry metadata, host profiles, local demos, terminal certificates, and readback surfaces are evidence/distribution, not authority. +- `.planning/macro-map/*` and `.planning/codebase/*` are scratch/derived planning evidence, useful for this audit but not repo-facing canon. + +Memory was used only as context for known local Handshake boundary pitfalls. It is not source evidence for this audit. + +## Files Read + +- `/Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/output-quality-bar.md` +- `/Users/joelchan/.codex/memories/MEMORY.md` context only +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md` +- `.planning/macro-map/EXPERIENCE-MAP.md` +- `.planning/macro-map/views/DESIGN.md` +- `.planning/macro-map/views/DEVEX.md` +- `.planning/macro-map/views/CEO.md` +- `.planning/codebase/STACK.md` +- `.planning/codebase/STRUCTURE.md` +- `.planning/codebase/CONVENTIONS.md` +- `.planning/codebase/TESTING.md` +- `README.md` +- `docs/internal/protocol-layman.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` + +## Invariant At Stake + +Product simplification may hide protocol complexity from users, but it must not hide or weaken authority, gateway, evidence, refusal, proof-gap, isolation, or reconstruction boundaries. + +The product-design invariant: + +```text +Every user-facing shortcut must map to a visible non-authority surface or to a source-owned protocol transition. No friendly noun may smuggle permission. +``` + +The DevEx invariant: + +```text +The fastest developer path must teach the protected-action chain by doing one local proof, including a negative authority attempt, without making CLI/MCP/SDK/example artifacts look like enforcement. +``` + +## Pass Conditions + +### 10-Star Criteria Refinements + +- The first screen / first doc / first command teaches the story as "service accepts evidence into a bounded workflow, then every protected event still needs fresh clearance." +- Every surfaced object has explicit false posture fields, at minimum: `createsAuthority: false`, `createsGreenlight: false`, `performsGatewayCheck: false`, `permitsMutation: false`, plus existing repo posture fields where applicable. +- The five non-authority correlation fields are preserved and documented: `passportPackageDigest`, `passportPresentationId`, `admissionId`, `serviceWorkflowHandleId`, and `serviceWorkflowHandleDigest`. +- The first-use path includes a negative attempt where a handle alone fails to call a protected API, pay an x402 challenge, mutate a service, satisfy a gateway, export a receipt, or mint a certificate. +- SDK, CLI, MCP, docs, and examples converge on one packet shape. They must not each invent a parallel metaphor. +- Role-scoped SDK clients are taught before the lower-level `HandshakeClient`. +- MCP remains proposal/evidence/readback only. New MCP resources may expose admission/readback, but no MCP tool may imply it can admit, approve, pay, sign, gateway-check, or mutate. +- CLI commands remain evidence/readiness/readback only and must be listed in `src/cli/command-manifest.ts` with explicit non-goals before docs teach them. +- Example output is the source-owned teaching artifact: JSON plus Markdown, product-tested, with no hosted/provider/settlement/marketplace/certification overclaim. +- Tier 3 progression remains blocked until Tier 1 / Tier 2 simplification either has passing proof gates or records explicit proof gaps. + +### First-Use Path + +The macro plan should require this first-use path: + +1. Read a short story section in `docs/internal/protocol-layman.md` that avoids `OperatingEnvelope`, `DelegatedAuthorityRef`, and `ActionContract` until after the user understands the flow. +2. Run a local source-owned fixture that emits a `ServiceWorkflowAdmission` or `ServiceWorkflowAdmissionReport`. +3. Inspect a `ServiceWorkflowHandle` with all non-authority flags and the five correlation fields. +4. Try to use the handle as authority and observe a refusal/proof-gap/readback result before any signer, gateway check, mutation, receipt export, or certificate. +5. Create one fresh `x402_payment.exact` protected action request using the existing readiness ladder. +6. Clear or refuse it through the role-scoped runtime, policy, and gateway clients. +7. Inspect receipt/refusal/replay-refusal/proof-gap readback and, only after terminal evidence exists, optional certificate verification. + +The current `README.md` x402 ladder is useful, but it starts with installation mechanics. The simplified path should wrap that ladder in the product story instead of replacing the authority sequence. + +### Naming Decisions + +- Use `ServiceWorkflowAdmission` or `ServiceWorkflowAdmissionReport` for the surface that records accepted/refused/stale/proof-gap standing evidence. +- Use `ServiceWorkflowHandle` for the carried workflow context object. +- Keep `Badge` out of exported SDK, CLI, MCP, source path, test, and package-surface names. It can appear only as carefully bounded explanatory copy, if at all. +- `AgentPassportPackage` is acceptable as a presented evidence bundle name only if every use says it is not identity, trust, permission, spend approval, gateway acceptance, signer permission, mutation permission, receipt export, terminal certification, or reusable auth. +- Avoid `Admission` as a verb in commands or tools. `admit`, `approve`, `authorize`, `certify`, `trust`, `login`, `verifyAgent`, and `grant` are too authority-loaded unless backed by a source-owned transition with the same authority. +- Keep `AuthorityCertificate` visibly terminal: receipt/refusal/proof-gap/replay evidence only, not a pass or badge. + +## Failures + +- No source-owned `ServiceWorkflowAdmission`, `ServiceWorkflowAdmissionReport`, or `ServiceWorkflowHandle` schema exists in the required sources. +- No current demo starts with an evidence/passport package, emits admission/readback, proves handle-as-authority failure, and then continues into one `x402_payment.exact` clearance. +- No rendered review/readback artifact was available to inspect for copy, layout, state separation, or hidden authority leakage. +- No negative tests currently prove the proposed fields cannot create policy decisions, greenlights, gateway checks, signer use, mutations, receipts, exports, or certificates. +- `Badge` remains the most dangerous simplification noun. Developers will naturally treat it as reusable auth unless the API name is `ServiceWorkflowHandle` and the false posture fields are mandatory. +- The README first-use ladder is mechanically strong but product-cognitively inverted: it teaches install/x402 mechanics before the larger protected-action story. +- SDK/CLI/MCP/docs/examples are not yet converged around one product packet. Without convergence, simplification becomes more vocabulary, not less complexity. + +### UX Anti-Patterns + +- Showing a single "approved", "verified", "admitted", or "cleared" badge without separate rows for evidence recognition, action request, policy decision, gateway check, mutation attempt, receipt/refusal/proof gap, and downstream uncertainty. +- Letting the handle appear in UI near buttons that say pay, execute, sign, deploy, approve, retry, or repair. +- Treating refusal, proof gap, replay refusal, or support-bundle generation as retry permission. +- Using certificate visuals before terminal evidence exists. +- Rendering a human summary that is not structurally bound to the exact action contract. +- Teaching `HandshakeClient` first and only later explaining role custody. +- Hiding raw/sibling bypass posture from the first-use proof. +- Copying hand-written JSON into docs instead of generating schema-shaped samples from source-owned demos. + +## Proof Gaps + +- User comprehension is unproven. The macro map has strong reasoning, but no evidence that new developers will distinguish Passport/Admission/Handle from auth. +- Product-surface source placement is unresolved. The safe default is `src/surfaces` plus example/readback tests, not `src/protocol/areas`, unless a new authority transition is intentionally created. +- CLI command shape is unresolved. A new command may be useful only if it is readback/evidence posture and manifest-tested. +- MCP readback shape is unresolved. A read-only resource is safer than a new tool. +- SDK surface shape is unresolved. Role-scoped clients should expose or consume the readback shape without acquiring all-role authority. +- Adoption value is unproven until a clean installed-artifact or local repo first-use path can be run by a fresh developer without chat memory. +- No source-owned packet yet proves docs, SDK, CLI, MCP, and examples all describe the same object with the same non-authority fields. + +## Required Changes + +### Docs / SDK / CLI / MCP / Example Convergence Plan + +1. Define one source-owned surface packet: + +```text +ServiceWorkflowAdmissionReport + passportPackageDigest + passportPresentationId + admissionId + acceptedStandingEvidenceRefs + refusedStandingEvidenceRefs + staleStandingEvidenceRefs + proofGapEvidenceRefs + serviceWorkflowHandleId + serviceWorkflowHandleDigest + boundedAttemptScope + nextActionRequestTemplateRef + createsAuthority: false + createsGreenlight: false + performsGatewayCheck: false + permitsMutation: false +``` + +2. Place it in a product-surface/readback lane first, not in a protocol primitive lane, unless the chair explicitly scopes a new authority transition. +3. Add a local example such as `examples/service-workflow-admission/` that emits stable JSON and Markdown output and includes a handle-as-authority refusal. +4. Update `docs/internal/protocol-layman.md` to teach this story, then map it to the exact protocol chain. +5. Update `README.md` first-use language so the existing x402 ladder is the protected-event continuation, not the whole product story. +6. SDK: expose or consume the packet through role-scoped clients only. Do not teach the all-role root client as the first activation path. +7. CLI: either reuse existing evidence/readback commands or add only a manifest-declared readback command. It must have explicit non-goals and must not use mutation-shaped names. +8. MCP: expose admission/readback as read-only resources if needed. Keep `handshake.actions.x402_payment.propose` as proposal-only and do not add an authority-sounding admission tool. +9. Examples: make generated demo output the source of docs snippets where possible. +10. Tests: add or extend `quality:claims`, `quality:architecture`, `surface-boundary-posture`, CLI/MCP posture, role-client, and product demo tests to lock the convergence. + +### Adoption Gates + +- Gate 1: a fresh developer can run the local example and see accepted/refused/stale/proof-gap evidence plus non-authority handle fields without reading kernel internals first. +- Gate 2: the negative handle-as-authority path refuses before policy, greenlight, gateway check, signer use, mutation, receipt export, or certificate. +- Gate 3: the same packet fields appear in docs, SDK typing, CLI/MCP readback, and example output. +- Gate 4: role-scoped SDK client docs remain the first taught SDK path. +- Gate 5: `npm run quality:claims` passes after language changes. +- Gate 6: `npm run quality:architecture` passes after surface, command, export, and naming changes. +- Gate 7: focused product/demo tests pass for the generated output packet. +- Gate 8: package/public-surface checks pass if any export or package README changes. +- Gate 9: `npm run check:repo` passes before the macro plan treats the simplification as implementation-ready. + +## Status Recommendation + +Sidecar recommendation: design/DevEx/adoption gate is not passable yet. The direction is strong enough to plan, but not strong enough to execute without a source-owned packet, a first-use demo, convergence across surfaces, and negative non-authority tests. + +Do not use this focus as evidence for `READY_FOR_AGENT_EXECUTION`. This sidecar does not select the macro-plan status; the chair must reconcile this with other audits and validation. + +## Commands Or Tools Used + +- `rg -n` over `/Users/joelchan/.codex/memories/MEMORY.md` for relevant Handshake context. +- `wc -l` for required source sizing. +- `sed -n` for required source reads. +- `ls -la` to inspect the assigned audit directory. +- `test -e` to confirm the assigned report did not already exist. +- `git status --short -- ` to check the assigned write path. +- `apply_patch` to write this one report. + +## Smallest Next Mechanism + +Build the non-authority readback contract before changing public story or SDK ergonomics: + +```text +ServiceWorkflowAdmissionReport + ServiceWorkflowHandle +-> explicit false authority fields +-> handle-as-authority refusal fixture +-> one x402 protected-event continuation +-> JSON/Markdown example output +-> claim, architecture, CLI/MCP, SDK, and product tests +``` + +That is the smallest mechanism that can make the product feel simple without making the system basic or advisory. diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/protected-action.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/protected-action.md new file mode 100644 index 0000000..11c96e2 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/protected-action.md @@ -0,0 +1,144 @@ +## Audit Scope + +Verdict: accept the Passport / Admission / Handle ID model only as a non-authority product-surface or projection contract. Do not let it become a protocol primitive, gateway input, reusable workflow credential, signer permission, x402/auth.md clearance, receipt, or terminal certificate. + +Assigned focus: protected-action posture and authority boundaries for `passportPackageDigest`, `passportPresentationId`, `admissionId`, `serviceWorkflowHandleId`, and `serviceWorkflowHandleDigest`. + +Out of scope: selecting the macro move, synthesizing the final macro plan, promoting final plan status, editing source, running implementation gates, or proving runtime containment. + +## Source Boundary + +Canonical source truth for authority claims is `README.md`, `QUALITY.md`, `docs/internal/decisions.md`, and `docs/internal/protocol-notes.md`. These sources say product surfaces expose proposal/evidence/readback without creating authority; authority remains exact contract, policy decision, one-use greenlight, gateway check, and receipt/refusal/proof gap. + +Derived planning evidence is `.planning/macro-map/*` and `.planning/codebase/*`. It can pressure-test the plan, but it cannot promote Passport, Admission, Badge, or Handle fields into source truth. + +The run input explicitly requires all five ID fields to be correlation/reconstruction fields with `createsAuthority: false`. A read-only source search did not find those five field names in non-hidden source/docs; they are not source-owned implementation yet. + +Memory was used only for prior-boundary context and was not treated as authority. + +## Files Read + +- `/Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-protected-action-gates.md` +- `/Users/joelchan/.codex/memories/MEMORY.md` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md` +- `.planning/macro-map/PROTECTED-ACTION-MAP.md` +- `.planning/macro-map/views/AUTHORITY.md` +- `.planning/macro-map/views/RUNTIME.md` +- `.planning/macro-map/CONCERNS.md` +- `.planning/codebase/ARCHITECTURE.md` +- `.planning/codebase/CONCERNS.md` +- `.planning/codebase/INTEGRATIONS.md` +- `README.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` +- `QUALITY.md` + +## Invariant At Stake + +Passport, Admission, and Handle fields may help correlate a service workflow and reconstruct later protected-action evidence. They must not create permission, trust, policy, greenlight, gateway acceptance, signer access, payment material, mutation authority, receipt export, terminal certification, hosted operation, or reusable auth. + +Every protected event still needs a fresh `CandidateAction` or refusal, exact `ActionContract`, `PolicyDecision`, one-use `Greenlight` or `Refusal`, `GatewayCheckAttempt`, and terminal receipt/refusal/replay refusal/proof gap. If an admitted workflow or handle can execute without that chain, the compiler overreached the principal. + +## Pass Conditions + +### Field-Level Protected-Action Acceptance Matrix Additions + +| Field | Allowed Meaning | Required Flags | Forbidden Interpretation | Required Rejection | +| --- | --- | --- | --- | --- | +| `passportPackageDigest` | Content digest of the presented evidence bundle for reconstruction. | `createsAuthority: false`; `createsPolicyDecision: false`; `createsGreenlight: false`; `performsGatewayCheck: false`; `permitsMutation: false`; `containsSecretOrPaymentMaterial: false`. | Identity proof, trust proof, credential custody proof, policy input that bypasses fresh action evaluation. | Reject if used as `ActionContract` digest, delegated authority digest, credential-ref digest, gateway-readiness digest, or signer/payment material. | +| `passportPresentationId` | Unique per service intake or presentation event. | Same false authority flags. | Session token, bearer auth, reusable service admission, future-call permission. | Reject if reused to satisfy policy, gateway, SDK role-client auth, MCP tool auth, or OpenAPI security. | +| `admissionId` | Service-side workflow intake result reference: accepted, refused, or proof gap. | Same false authority flags plus `isProtectedActionClearance: false`. | `PolicyDecision`, `Greenlight`, gateway admission, route custody, mutation approval, receipt. | Reject if passed to policy/gateway APIs as sufficient evidence, or if an accepted admission skips `CandidateAction` creation/refusal. | +| `serviceWorkflowHandleId` | Carried workflow correlation reference for context and readback. | Same false authority flags plus `isReusableAuth: false`; `widensOperatingEnvelope: false`. | Badge, API key, capability token, x402 payment approval, auth.md credential, retry permission. | Reject if runtime, MCP, browser, shell, HTTP, x402, or auth.md code treats it as permission to call a protected surface. | +| `serviceWorkflowHandleDigest` | Digest of carried workflow handle context for drift detection and reconstruction. | Same false authority flags plus `isGatewayBinding: false`. | Contract digest, greenlight digest, gateway check digest, receipt digest, terminal certificate digest. | Reject if digest drift is smoothed over; require refusal or a new exact contract. | + +### Boundary Conditions + +- `CandidateAction`/refusal boundary: Admission may prepare context only. Each protected action must still create a fresh candidate or refusal with current assumptions, parameters, idempotency, delegated-authority status, credential posture, bypass posture, and evidence expectations. +- Gateway/enforcement boundary: Only the exact contract -> policy -> one-use greenlight -> gateway check chain may precede mutation. The five ID fields must never satisfy `VerifiedGatewayCheck`. +- Raw sibling bypass: Direct x402 payloads/signatures, bearer tokens, raw HTTP/MCP/browser/shell/package/network routes, dynamic tool names, changed parameters, stale metadata, and consumed greenlights must be refused or recorded as bypass/proof gap. If enforcement is not gateway-backed, This is advisory, not Handshake. +- x402 posture: current wedge stays one buyer-side `x402_payment.exact` per call. `PaymentPayload` and `PAYMENT-SIGNATURE` stay behind the wallet gateway after `VerifiedGatewayCheck`. +- auth.md posture: auth.md prose, PRM/AS metadata, registration, claims, scopes, revocation, and credentials are provenance/custody evidence only until a protected API call clears through exact contract, policy, one-use greenlight, gateway check, and post-gate credential resolution. +- Receipt/refusal/proof-gap separation: Admission/handle readback is not receipt evidence. Downstream finality unknown stays proof gap, not success. +- Tier 3 block: hosted operation, provider/customer gateway custody beyond local proof, marketplace/certification, cross-org trust, aggregate spend, seller/facilitator operation, and hosted mutation authority remain blocked until source evidence and gates prove them. + +### Non-Claims Required + +- Passport package does not prove identity authorization. +- Presentation ID does not prove principal understanding. +- Admission ID does not prove protected-action approval. +- Service workflow handle does not prove permission, settlement, signer access, credential access, gateway acceptance, or retry authority. +- Handle digest does not prove contract, greenlight, gateway, receipt, or certificate binding. +- MCP visibility, x402 capability, auth.md credential issuance, OpenAPI route shape, browser observation, host profile, or public npm/MCP Registry distribution does not create authority. + +## Failures + +- The macro map already records that no field-level acceptance matrix exists for `ServiceWorkflowAdmission`; this report supplies required additions, but source does not yet enforce them. +- No negative test proves `ServiceWorkflowHandle` cannot be passed into policy, gateway, runtime, SDK, MCP, x402, or auth.md APIs as permission. +- `Admission` is overloaded across route custody, hosted readiness, product admission packets, and receipt/export language. A standalone `Admission` object would blur route admission, workflow acceptance, policy decision, and gateway clearance. This is advisory, not Handshake. +- The five fields are not yet source-owned schema fields with hard false booleans; they currently live in planning intent. +- Raw sibling bypass posture is documented, but no Passport/Admission/Handle-specific probe proves generated code cannot route around the protected path. +- x402/auth.md composite execution remains an expansion candidate, not current execution authority. auth.md credential issuance plus x402 payment capability must not be marketed as a cleared composite call. +- Tier 3 hosted-operation language must remain blocked. The current sources explicitly leave hosted mutation authority, provider/customer gateway custody beyond local proof, settlement/finality, marketplace/certification, cross-org trust, aggregate spend enforcement, and host-wide containment as proof gaps or cut lines. + +## Proof Gaps + +- No source-owned `ServiceWorkflowAdmission` / `ServiceWorkflowHandle` schema was read. +- No source-owned matrix row proves all five fields have `createsAuthority: false`. +- No test gate was run for claim boundary, architecture boundary, protocol compilation, policy/gateway refusal, runtime ingress, x402, auth.md, or receipt projection. +- No host-specific smoke was run for browser, A2A, Claude Code, Hermes, OpenClaw, generic MCP, shell, package manager, or direct network bypass. +- No external x402 provider/facilitator finality, provider custody, settlement, or customer gateway custody proof exists in the audited sources. +- No provider-grade auth.md credential lifecycle or credential redaction fuzzing proof exists. +- No proof shows a handle cannot widen `OperatingEnvelope.allowedResources`, carry raw credential/payment material, or stand in for delegated authority. +- No receipt/export fixture proves admission readback cannot be mistaken for receipt, terminal certificate, downstream success, or retry permission. + +## Required Changes + +### Implementation Blockers + +- Block source implementation until the field-level acceptance matrix is source-owned and tested. +- Block docs, demos, SDK, CLI, MCP, and examples from saying Passport, Admission, Badge, or Handle creates authority. +- Block any kernel object, root export, protocol-area path, gateway-route name, or role-client method that makes the five fields look authority-bearing. +- Block x402/auth.md demo promotion until the non-authority surface is in place and the paid/credentialed call still routes through exact event clearance. +- Block Tier 3 progression until Tier 1/Tier 2 simplification has proof gates or explicit proof gaps recorded. + +### Negative Tests Required + +- Architecture/claim-boundary test: `Passport`, standalone `Admission`, `Badge`, `ServiceWorkflowAdmission`, and `ServiceWorkflowHandle` must not appear under `src/protocol/areas/*`, authority-bearing root exports, gateway execution paths, or policy/gateway route names unless a distinct enforceable transition is documented. +- Schema test: all five fields require `createsAuthority: false`; any `true`, omitted flag, raw secret, payment payload/signature, bearer token, signer ref, or resource-widening field fails. +- Policy/gateway test: `admissionId` and `serviceWorkflowHandleId` cannot satisfy `PolicyDecision`, `Greenlight`, `GatewayCheckAttempt`, `VerifiedGatewayCheck`, `Receipt`, or `AuthorityCertificate` inputs. +- Runtime stress test: loops, retries, branches, dynamic tool construction, stale review surfaces, late-bound parameters, and changed observed parameters produce refusal/new contract, not handle reuse. +- x402 test: handle/admission fields cannot create `PaymentPayload`, `PAYMENT-SIGNATURE`, signer invocation, live provider custody, or aggregate spend authority. +- auth.md test: handle/admission fields cannot resolve credentials, create Authorization headers, widen scopes, bypass revocation/isolation, or make `readyForCompositeExecution` true. +- Receipt/projection test: admission readback cannot be emitted as receipt, receipt export, terminal certificate, downstream success, or retry permission. +- Raw sibling bypass test: direct HTTP, MCP, browser, shell, package-manager, network, raw x402, and raw bearer paths remain prevented, refused, isolated, or proof-gapped per host posture. + +### Smallest Next Mechanism + +Add a source-owned product-surface contract outside `src/protocol/areas/*`: + +```text +ServiceWorkflowAdmission -> accepted | refused | proof_gap +ServiceWorkflowHandle -> correlation/readback context only +``` + +The schema must include the five ID fields, the hard false authority flags, host/runtime bypass posture refs, and redacted evidence refs. Pair it with the negative tests above before any product-language, SDK, CLI, MCP, demo, or Tier 3 work uses the model. + +## Status Recommendation + +Recommendation for this protected-action gate: `NEEDS_PROTECTED_ACTION_POSTURE`. + +Do not promote to `READY_FOR_AGENT_EXECUTION` on this focus until the field-level matrix, source-owned non-authority schema, and negative tests exist. Keep the move only as a non-authority product-surface simplification. The macro chair can still plan around it, but only with the blockers preserved as proof gates. + +## Commands Or Tools Used + +- `sed -n '1,220p' /Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` +- `sed -n '1,260p' /Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-protected-action-gates.md` +- `rg -n "Tier 3|Passport|Admission|Handle|passportPackageDigest|passportPresentationId|admissionId|serviceWorkflowHandleId|serviceWorkflowHandleDigest|protected action|x402|authority|createsAuthority|greenlight|gateway|CandidateAction|refusal|proof gap|bypass" /Users/joelchan/.codex/memories/MEMORY.md` +- `wc -l` on required source files and the target report path. +- `sed -n` on the required macro-plan input, macro-map, codebase, README, decisions, protocol-notes, and QUALITY files. +- `rg -n "passportPackageDigest|passportPresentationId|admissionId|serviceWorkflowHandleId|serviceWorkflowHandleDigest|ServiceWorkflowAdmission|ServiceWorkflowHandle|createsAuthority" . README.md QUALITY.md docs/internal/decisions.md docs/internal/protocol-notes.md` +- `rg -n "CandidateAction|Refusal|Greenlight|GatewayCheck|VerifiedGatewayCheck|PaymentPayload|PAYMENT-SIGNATURE|auth\\.md|x402_payment\\.exact|proof gap|bypass|host-wide containment|Tier 3|hosted" ...` +- `git status --short -- .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/protected-action.md` +- `ls -la .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits` +- `apply_patch` to add this report only. diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/review-gates.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/review-gates.md new file mode 100644 index 0000000..da8bc03 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/review-gates.md @@ -0,0 +1,199 @@ +## Audit Scope + +Focus: review-gates audit for T2-01 SDK/exports surface posture. + +Question under audit: whether `ServiceWorkflowAdmission` should be exported from +the package root or remain surface-only, how SDK role-client guidance should +describe it, and whether the current SDK/package posture creates authority drift. + +## Source Boundary + +Canonical source beats planning scratch. `.planning/` was used only for the +active macro-plan handoff and T2-01 acceptance criteria. + +Read boundary: + +- Canon/doctrine: `AGENTS.md`, `README.md`, `docs/internal/decisions.md`, + `docs/internal/protocol-notes.md`, `docs/internal/service-workflow-story.md`, + `docs/internal/protocol-layman.md`, `STRUCTURE.md`, `QUALITY.md`. +- Active plan: `.planning/macro-plan/AGENT-HANDOFF.md`, + `.planning/macro-plan/TASKS.jsonl`, + `.planning/macro-plan/EXECUTION-SLICES.md`. +- SDK/export source: `src/sdk/surface-clients/index.ts`, + `src/sdk/surface-clients/runtime-client.ts`, + `src/sdk/surface-clients/policy-client.ts`, + `src/sdk/surface-clients/gateway-client.ts`, + `src/sdk/surface-clients/evidence-client.ts`, `src/sdk/LANE.md`, + `src/index.ts`, `src/surfaces/index.ts`, + `src/surfaces/service-workflow-admission/index.ts`, `package.json`. +- Export/package tests: `test/architecture/root-exports.test.ts`, + `test/architecture/package-surface.test.ts`, + `test/architecture/workflow-admission-boundary.test.ts`, + `test/sdk/role-clients.test.ts`. +- Package scripts: `scripts/build-package-bundles.mjs`, + `scripts/check-package-surface.mjs`, + `scripts/check-published-entrypoints.mjs`. + +## Files Read + +- `AGENTS.md` +- `.planning/macro-plan/AGENT-HANDOFF.md` +- `.planning/macro-plan/TASKS.jsonl` +- `.planning/macro-plan/EXECUTION-SLICES.md` +- `.planning/macro-plan/MACRO-PLAN.md` +- `README.md` +- `STRUCTURE.md` +- `QUALITY.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/service-workflow-story.md` +- `docs/internal/protocol-layman.md` +- `src/sdk/LANE.md` +- `src/sdk/surface-clients/index.ts` +- `src/sdk/surface-clients/runtime-client.ts` +- `src/sdk/surface-clients/policy-client.ts` +- `src/sdk/surface-clients/gateway-client.ts` +- `src/sdk/surface-clients/evidence-client.ts` +- `src/index.ts` +- `src/surfaces/index.ts` +- `src/surfaces/service-workflow-admission/index.ts` +- `package.json` +- `test/architecture/root-exports.test.ts` +- `test/architecture/package-surface.test.ts` +- `test/architecture/workflow-admission-boundary.test.ts` +- `test/sdk/role-clients.test.ts` +- `scripts/build-package-bundles.mjs` +- `scripts/check-package-surface.mjs` +- `scripts/check-published-entrypoints.mjs` + +## Invariant At Stake + +SDK role clients can guide activation, proposal, policy evaluation, gateway +transport, and redacted readback, but they cannot infer authority from service +workflow evidence. `ServiceWorkflowAdmission` and `ServiceWorkflowHandle` are +non-authority product-surface records. They must not become root-level protocol +primitives, role-client permission inputs, policy substitutes, gateway passes, +receipt evidence, signer access, or reusable auth. + +## Pass Conditions + +- `ServiceWorkflowAdmission` stays off the package root. +- `ServiceWorkflowAdmission` is exposed only as a surface schema if a public + import path is intentionally added; it must not be exported through + `./sdk/role-clients`. +- Role-client docs state that admission/handle values are evidence/readback + context only. +- `RuntimeClient` may cite admission/handle context only while producing fresh + proposal records or compiler refusals. +- `PolicyClient.evaluatePolicy()` still requires an exact action contract input; + admission/handle is not policy. +- `GatewayClient.gatewayCheck()` still requires gateway check input bound to a + one-use greenlight; admission/handle is not a gateway pass. +- `EvidenceClient` readback must distinguish admission evidence from receipt + timeline, downstream finality, replay refusal, and proof gaps. +- Root/package/export tests remain curated and fail if root or role-client + exports widen accidentally. + +## Failures + +1. SDK role-client guidance is not explicit enough for T2-01 closeout. + `README.md` explains the first-use flow and says + `ServiceWorkflowAdmission` is not policy and `ServiceWorkflowHandle` is not + permission. `src/sdk/LANE.md` explains role-client custody boundaries. But + the role-client guidance never names `ServiceWorkflowAdmission` or + `ServiceWorkflowHandle`, so it does not tell developers where those records + may appear: context/evidence refs for fresh proposals and readback only, + never as policy input, greenlight, gateway input, receipt, credential, or + role token. + +2. The package surface has an unresolved `surfaces` export posture. Build and + package checks require `dist/surfaces/index.mjs` and + `dist/surfaces/index.d.ts`, and `src/surfaces/index.ts` exports + `service-workflow-admission`. `package.json` does not expose a + `./surfaces` subpath. That is safe against accidental public authority drift, + but ambiguous for T2-01: if the admission schema is meant to be public, the + public import path is missing; if it is source-internal only, the package + currently ships an unaddressable dist artifact. + +No current source failure shows `ServiceWorkflowAdmission` exported from root or +from `./sdk/role-clients`. + +## Proof Gaps + +- No import smoke exists for a public `handshake-protocol-kernel/surfaces` + subpath because that subpath does not exist. +- No role-client doc/test currently asserts the exact admission/handle wording: + context-only, fresh action contract required, admission readback is not receipt + evidence. +- `root-exports.test.ts` would catch a root export by exact export-list drift, + but it does not have a named regression assertion for + `ServiceWorkflowAdmission` / `ServiceWorkflowHandle`. +- T2-01 status in `TASKS.jsonl` remains `open`; this audit does not promote it. + +## Required Changes + +1. Do not export `ServiceWorkflowAdmission` from the package root. + + Root export would place a product-surface admission record beside + `ActionContractSchema`, `PolicyDecisionSchema`, `GreenlightSchema`, + `GatewayCheckInputSchema`, `ReceiptSchema`, `verifiedGatewayCheckFromResult`, + and `HandshakeClient`. That makes admission look like a protocol primitive or + authority-bearing input. It is review theatre risk in package form. + +2. Keep `ServiceWorkflowAdmission` surface-only. + + If a public type/schema import is required, add a deliberate + `handshake-protocol-kernel/surfaces` package subpath with tests that assert + non-authority exports and forbid `PolicyDecision`, `Greenlight`, + `GatewayCheck`, `ReceiptExport`, `PaymentPayload`, signer, mutation, and + certificate-minting names. Do not use `./sdk/role-clients` for these schemas; + that subpath should stay role-client constructors plus safe transport/error + types. + +3. Patch role-client guidance before closing T2-01. + + The docs should say: + + - `ServiceWorkflowAdmission` and `ServiceWorkflowHandle` are service + workflow context/readback records only. + - `RuntimeClient` may use their IDs/digests as declared assumptions, + evidence refs, or context while compiling/proposing a fresh exact action + contract. + - `PolicyClient.evaluatePolicy()` starts from exact contract input, not from + admission/handle. + - `GatewayClient.gatewayCheck()` starts from gateway-check input bound to a + one-use greenlight, not from admission/handle. + - `EvidenceClient` may read redacted evidence and receipt timelines, but an + admission readback is not receipt evidence or downstream success. + - No role client should retry protected work automatically because an + admission was accepted. + +4. Add named export-posture tests if a `./surfaces` subpath is introduced. + + Required assertions: root does not export `ServiceWorkflowAdmission*` or + `ServiceWorkflowHandle*`; role-clients do not export those schemas; the + surfaces subpath exports only non-authority surface schemas/constants/helpers. + +## Status Recommendation + +Conditional pass for current source posture; do not promote T2-01 to closed. + +Current source is safe on the central authority question: root does not export +`ServiceWorkflowAdmission`, role clients remain on an explicit non-root subpath, +and focused tests passed. The unresolved work is documentation and package +surface intent: either keep admission schema source-internal and stop implying a +public import, or add an explicit non-root `./surfaces` subpath with narrow +non-authority tests. Root export is the wrong move. + +## Commands Or Tools Used + +- `rg -n "T2-01|ServiceWorkflowAdmission|surface-clients|SDK|exports|macro-plan|audit" /Users/joelchan/.codex/memories/MEMORY.md` +- `sed -n '1,220p' /Users/joelchan/.codex/skills/handshake-grounding/SKILL.md` +- `pwd` +- `git status --short --branch` +- `sed -n` reads over the source boundary listed above +- `rg -n "ServiceWorkflowAdmission|ServiceWorkflowHandle|role-client|role client|surface client|surface-clients|sdk/role-clients|sdk/surface-clients|freshActionContractRequired|createsAuthority" . src test docs README.md package.json` +- `find .planning/macro-plan -maxdepth 4 -type d | sort` +- `find .planning/macro-plan/runs -maxdepth 3 -type f | sort` +- `nl -ba` reads for cited line anchors +- `npm run test -- test/architecture/root-exports.test.ts test/sdk/role-clients.test.ts test/architecture/package-surface.test.ts test/architecture/workflow-admission-boundary.test.ts` diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/runtime-agent.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/runtime-agent.md new file mode 100644 index 0000000..6e3a94d --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/runtime-agent.md @@ -0,0 +1,210 @@ +## Audit Scope + +Focus: runtime and generated-agent posture for the Tier 1 / Tier 2 product-simplification macro-plan run `20260525T095940Z-tier1-tier2-product-simplification`. + +Assigned sidecar focus: Codex, Claude Code, OpenClaw, Hermes, auth.md, x402, MCP, browser, A2A, OpenAPI, generated loops, retries, branches, dynamic tool names, stale review, raw sibling bypass, and handle misuse. + +Verdict: runtime-agent posture is not executable as a generic multi-host plan. The macro plan can proceed only as a runtime-gated planning package that preserves `NEEDS_RUNTIME_PROFILE` / `NEEDS_AGENT_REVIEW` blockers until the handle/admission surface has host-specific proof rows, generated-execution stop rules, raw sibling posture, and negative tests. This sidecar does not select the macro move and does not promote final status. + +## Source Boundary + +Canonical repo truth for runtime claims comes from `README.md`, `docs/internal/protocol-notes.md`, and source files under `src/`. `.planning/` files are scratch or derived evidence. They are valid for this macro-plan run but cannot become repo-facing authority without source and test promotion. + +The governing planning input says product simplification must not hide authority, gateway, evidence, refusal, proof-gap, isolation, or reconstruction boundaries. It also says Passport, Admission, Badge, Handle, Certificate, review surfaces, and IDs are evidence/correlation surfaces only unless a source-owned protocol transition proves otherwise. + +The runtime map explicitly names Codex, Claude Code, OpenClaw, Hermes, auth.md, x402, MCP, browser, A2A, and OpenAPI as distinct contexts. None can be collapsed into "agent admitted" or "host contained." + +Source confirms the same boundary: + +- Runtime ingress is proposal-only and records generated execution evidence, generated graph evidence, tool-call drafts, intent compilations, action contracts, or refusals. +- MCP is proposal/evidence transport only. +- x402 protected-tool profiles are readiness/profile artifacts only. +- auth.md is provenance plus gateway-custody evidence until exact protected API calls clear through policy and gateway. +- OpenAPI and HTTP admission describe route/caller custody only, not side-effect proof. +- Browser, A2A, shell, network, package-manager, and generic MCP interception remain proof gaps unless a specific gateway-owned protected path proves otherwise. + +## Files Read + +Required sources read: + +- `/Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-runtime-gates.md` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md` +- `.planning/macro-map/AGENT-RUNTIME-MAP.md` +- `.planning/macro-map/views/AGENT.md` +- `.planning/macro-map/views/RUNTIME.md` +- `.planning/codebase/ARCHITECTURE.md` +- `.planning/codebase/INTEGRATIONS.md` +- `.planning/codebase/TESTING.md` +- `docs/internal/protocol-notes.md` +- `README.md` +- `src/runtime/ingress/index.ts` +- `src/runtime/ingress/schemas.ts` +- `src/mcp/x402-proposal.ts` +- `src/x402-protected-tool/LANE.md` + +Additional source anchors read for runtime/auth/browser/OpenAPI/A2A posture: + +- `src/runtime/ingress/families.ts` +- `src/adapters/auth-md/action-proposal.ts` +- `src/adapters/auth-md/gateway.ts` +- `src/adapters/auth-md/bypass-probes.ts` +- `src/adapters/x402-payment/protected-tool-facade/index.ts` +- `src/adapters/x402-payment/protected-tool-profile/index.ts` +- `src/http/admission/index.ts` +- `src/http/openapi/index.ts` +- `src/mcp/LANE.md` +- `.planning/codebase/CONCERNS.md` +- `.planning/macro-map/MACRO-MAP.md` +- `.planning/macro-map/TASKS.jsonl` + +## Invariant At Stake + +No generated or automated consequential action may execute outside declared bounds. Runtime/tool/catalog/profile/admission evidence can help form candidate contracts, but it cannot become authority. + +Specific invariant: a Passport, Admission, Badge, or `ServiceWorkflowHandle` may carry context for an admitted workflow attempt, but it must not satisfy policy, create a greenlight, pass a gateway check, invoke a signer, create payment material, resolve credentials, execute a mutation, export a receipt, mint a certificate, or authorize retries. Every protected event still needs a fresh exact action contract, policy decision, one-use greenlight or refusal, gateway check, and receipt/refusal/proof gap. + +If a handle lets generated code call a protected tool, raw signer, browser tool, MCP sibling, OpenAPI route, A2A task, or auth.md/x402 path as permission, this is ambient authority wearing a badge. + +## Pass Conditions + +### Runtime Suitability Rows + +| Runtime or rail | Suitability for this macro plan | Pass condition | Non-claim that must survive | +| --- | --- | --- | --- | +| Codex local | Conditionally operable for source-owned local x402 profile evidence only | Name `AGENTS.md`, skill/MCP discovery, sandbox/approval/file-edit posture, non-interactive failure behavior, local profile target, and raw sibling probes | Not host-wide containment, user host mutation proof, policy, gateway, signer, or receipt proof | +| Claude Code | Profile required / proof-gapped | Name `CLAUDE.md`, skills/plugins, `.claude/agents`, managed MCP target, permissions, foreground/background subagent behavior, and fresh-context delegation prompt requirements | Not native host certification or unmanaged MCP containment | +| Hermes | Tool-packet profile required / proof-gapped | Name `hermes.tool-packet.json`, command/args/config digest, host tool digest, tool-list digest, unmanaged-tool-packet posture, and native-host non-claims | Not native host certification, gateway authority, or signer custody | +| OpenClaw | Tool-packet profile required / proof-gapped | Name `openclaw.tool-packet.json`, command/args/config digest, host tool digest, tool-list digest, unmanaged-tool-packet posture, and native-host non-claims | Not native host certification, gateway authority, or signer custody | +| Generic MCP | Proposal/evidence transport only | Keep MCP resources/tools as proposal/readback surfaces and require trusted runtime-side readiness/policy binding before contract proposal | Not enforcement, authorization, recovery authority, process supervision, broad MCP protection, or raw sibling containment | +| x402 | Narrow local/reference exact per-call path only | Bind official exact payment requirement, delegated spend ref, gateway readiness, policy version, selected requirement digest, idempotency, and `VerifiedGatewayCheck` before gateway-held signer use | Not principal spend authority, aggregate spend ledger, settlement, provider custody, hosted payment operation, broad x402 compatibility, or marketplace certification | +| auth.md | Provenance plus protected API-call proposal/gateway fixture only | Keep auth.md metadata, scopes, registration, and credential issuance as evidence; exact protected API call must clear through action contract, policy, greenlight, gateway check, and post-gate credential resolution | Not OAuth provider, identity provider, service gateway, WorkOS replacement, or protected-action approval | +| Browser | Evidence/probe surface only | Any browser-side mutation must be represented as its own protected path with raw sibling posture and gateway-owned mutation credential | Not controlled by MCP, OpenAPI, A2A, or host profile by default | +| A2A | Operation/task catalog evidence only | Treat task/agent/service shape as source evidence for a future candidate action, not as side-effect proof | Not gateway admission or protected-action clearance | +| OpenAPI | Route/catalog evidence only | Keep route security schemes as caller-custody/admission evidence; protected side effects still require exact contract and gateway check | Not runtime enforcement or proof that a side effect occurred | +| Runtime ingress | Proposal-only for known dispatch families | Preserve wrapped, raw sibling, and ambiguous dispatch distinctions; keep loops/retries/branches/dynamic construction/late-bound params in evidence and refusals | Not host-wide interception or sandbox containment | +| ServiceWorkflowHandle / Badge | Not executable authority | Carry only refs/digests, expiry, workflow bounds, non-authority flags, and requirement for fresh action request | Not reusable auth, permission, gateway acceptance, signer use, receipt, or retry permission | + +Weakest host posture controls executable status. Parity artifacts are not certification. + +### Generated-Execution Stress Gates + +The macro plan passes runtime-agent review only if it records these gates as stop conditions or negative tests: + +| Stress case | Required behavior | +| --- | --- | +| Loop over protected calls | Each iteration needs its own exact action request or explicit refusal; handle reuse must not create authority. | +| Retry after refusal/proof gap/replay | Stop or create a new exact contract according to reason code; never retry from handle/admission alone. | +| Branch-dependent action | Branch ref must be carried into generated execution evidence and candidate binding; stale summaries are not authority. | +| Dynamic tool name or endpoint construction | Refuse or mark ambiguous before contract proposal unless the exact tool/action/gateway binding is reconstructed. | +| Late-bound parameters | Refuse or recraft before policy/gateway; stale review cannot authorize changed params. | +| Stale rendered review | Require fresh contract/review binding; rendered review is evidence only. | +| Raw sibling route detected | Stop and record bypass posture/proof gap; do not smooth into success. | +| Browser/network side channel | Treat as raw sibling or unobserved region until host-specific proof exists. | +| Direct MCP/OpenAPI/A2A route | Treat as proposal/catalog evidence only unless exact gateway path is proven. | +| auth.md raw bearer or token replay | Refuse before compilation/gateway; raw credential material must not enter handle, evidence, or receipt. | +| x402 raw payment payload/signature | Refuse before signer use; `PaymentPayload` / `PAYMENT-SIGNATURE` must stay gateway-held after verified gate. | + +### Continuation And Handoff Requirements + +A future agent handoff must include: + +- source priority: canonical docs/source first, `.planning/` scratch second; +- exact allowed files and forbidden authority paths; +- runtime-specific suitability rows for Codex, Claude Code, Hermes, OpenClaw, generic MCP, browser, A2A, OpenAPI, auth.md, and x402; +- explicit non-authority flags for Passport, Admission, Badge, and `ServiceWorkflowHandle`; +- raw sibling inventory for x402 signer/payment, auth.md bearer/API, MCP sibling, browser, network, shell, package manager, repo write, deploy, and database mutation routes; +- stop conditions for stale metadata, stale policy, stale readiness, changed observed params, replay, proof gap, isolation, revocation, unknown gateway posture, raw sibling reachability, and unobserved generated-code regions; +- eval path a named runtime can run after compaction, restart, or handoff. + +## Failures + +P0: A macro plan that treats `ServiceWorkflowHandle`, Badge, MCP tool visibility, OpenAPI security schemes, A2A task shape, x402 capability, or auth.md credential issuance as permission fails the runtime invariant. This is advisory, not Handshake. + +P0: A macro plan that says "multi-host protected action" without separate Codex, Claude Code, Hermes, OpenClaw, generic MCP, browser, A2A, and OpenAPI rows overclaims. Host profiles are not containment. + +P0: A plan that allows a handle to skip a fresh action request for each protected event creates reusable ambient authority. The compiler overreached the principal. + +P1: Current source has strong proposal-only runtime ingress, but the new Passport/Admission/Badge/Handle surface does not yet have source-owned runtime misuse tests. The plan must add those gates before fixture or demo work. + +P1: Runtime ingress models loops, retries, branches, dynamic construction, late-bound params, raw siblings, and ambiguous dispatches, but it remains caller-observed evidence. It cannot prove every raw sibling path in a host was intercepted. + +P1: x402 protected-tool profiles can prepare runtime dispatch only after trusted readiness, but they remain profile/readiness artifacts. They do not perform policy, gateway check, signer use, mutation, receipt export, settlement, provider custody, native host certification, or host-wide containment. + +P1: auth.md protects useful provenance and credential-custody paths, but provider-grade credential custody and composite auth.md + x402 execution remain proof gaps. Do not plan a composite service-gateway proof before the surface gates exist. + +P1: Browser, A2A, and OpenAPI currently lack live protected-path probes in the read boundary. They must be treated as operation/catalog/evidence rails only. + +## Proof Gaps + +### Runtime-Specific Proof Gaps + +| Runtime or rail | Proof gap | Required proof before executable claim | +| --- | --- | --- | +| Codex | Local host-origin evidence does not prove host-wide containment or user host mutation control | Codex-local activation/readback plus named raw sibling probes for the exact handle workflow | +| Claude Code | Managed/profile parity artifact only | `.mcp.json` or managed MCP packet, permissions, fresh-context subagent handoff, unmanaged sibling posture, and smoke evidence | +| Hermes | Tool-packet artifact only | `hermes.tool-packet.json` packet, command/args/config/tool-list digests, native-host non-claims, and raw sibling posture | +| OpenClaw | Tool-packet artifact only | `openclaw.tool-packet.json` packet, command/args/config/tool-list digests, native-host non-claims, and raw sibling posture | +| Generic MCP | Tool discovery and proposal transport are not enforcement | External host transcript plus refusal/readback behavior, with sibling MCP path posture | +| Browser | No browser-side mutation interception proof | Browser-specific protected path or explicit proof gap for browser tool/network side effects | +| A2A | No task/agent side-effect proof | A2A operation-to-action-contract mapping plus gateway-owned mutation boundary | +| OpenAPI | Route shape and bearer schemes are not gateway admission | Operation catalog evidence plus proof that mutation routes require exact contract and gateway check | +| x402 | Local exact per-call proof is not live provider custody, settlement, aggregate spend, or broad compatibility | Live/provider-specific custody, facilitator/finality, and spend-ledger evidence before those claims | +| auth.md | Credential provenance is not protected-action approval, and redaction remains provider-format sensitive | Provider-specific credential fixtures/fuzzing and gateway custody proof before live custody claims | +| auth.md + x402 | Interlock packets are non-authority readiness/evidence surfaces | Composite exact contracts, policy, one-use greenlights, verified gateway checks, payment/credential evidence, receipt/refusal/proof-gap chain | +| Runtime ingress | Known-family proposal compiler, not host-wide telemetry/interception | Per-runtime host adapter proof that consequential mutation cannot bypass gateway, or explicit bypass proof gap | + +Additional proof gaps: + +- No current `ServiceWorkflowAdmission` / `ServiceWorkflowHandle` source schema exists in the required boundary. +- No dedicated negative tests prove the new handle cannot satisfy policy, greenlight, gateway check, receipt, certificate, signer, payment, credential resolution, or mutation paths. +- No workflow-specific raw sibling inventory exists for handle carriage. +- No live host smokes, browser/A2A probes, external MCP Registry lookup, live x402 provider check, or customer gateway custody check were run in this audit. + +## Required Changes + +1. Add a runtime-agent gate section to the macro plan before any executable status. It must include the runtime suitability rows above, weakest-host rule, and explicit non-claims. + +2. Add generated-execution stress gates for loops, retries, branches, dynamic tool names, late-bound params, stale review, changed observed params, unobserved regions, and replay. The expected behavior must be refusal, recraft, read evidence, stop, or proof gap, never permission from handle/admission. + +3. Define raw sibling bypass posture for the handle workflow. At minimum inventory x402 raw signer/payment payload, direct MCP x402 call, auth.md raw bearer/direct HTTP/browser/network/token replay, shell/package manager/repo/deploy/database mutation, browser-side tools, generic network clients, and unmanaged MCP/tool-packet siblings. + +4. Require a continuation/handoff packet. It must survive compaction/restart by naming canonical sources, scratch status, exact candidate files, runtime target, allowed/forbidden tool surfaces, stop conditions, and eval commands. + +5. Keep MCP, OpenAPI, and A2A as catalog/proposal/operation evidence. The plan must say they are not enforcement unless a source-owned gateway check path is present. + +6. Keep x402 per-call and auth.md protected API call separate until a later composite fixture has exact event clearance. The plan must not imply that auth.md credential issuance plus x402 payment capability creates a service-gateway authority event. + +7. Add negative tests or test-plan requirements that `ServiceWorkflowHandle` / Badge cannot create or satisfy `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheckAttempt`, `Receipt`, `AuthorityCertificate`, signer input, `PaymentPayload`, `PAYMENT-SIGNATURE`, raw credential material, OpenAPI security authority, hosted/provider custody, settlement, or widened envelope scope. + +### Smallest Next Mechanism + +Before fixture planning, write one runtime-agent gate packet for `ServiceWorkflowAdmission` / `ServiceWorkflowHandle` with: + +- hard non-authority booleans; +- per-host suitability rows; +- generated-execution stress gates; +- raw sibling bypass inventory; +- continuation/handoff requirements; +- required proof-gap labels; +- focused closeout gates: `npm run quality:claims`, `npm run quality:architecture`, `npm run test -- test/protocol/kernel-compilation-contract.test.ts test/protocol/kernel-policy-gateway.test.ts test/protocol/evidence-projections.test.ts test/runtime/runtime-ingress.test.ts`, plus x402/auth.md adapter tests if the wording touches payment, signer custody, credential custody, or downstream finality. + +## Status Recommendation + +Verdict: `NEEDS_RUNTIME_PROFILE` with `NEEDS_AGENT_REVIEW` pressure preserved. + +Do not mark the macro plan `READY_FOR_AGENT_EXECUTION` unless the chair reconciles this report into runtime gates, proof gaps, and tasks. A safe macro status can be phase-planning oriented only if it explicitly blocks executable runtime claims until the required changes above exist. + +This sidecar does not choose the macro move, does not synthesize the final plan, and does not promote final status. + +## Commands Or Tools Used + +- `rg -n` over `/Users/joelchan/.codex/memories/MEMORY.md` for relevant prior Handshake runtime/x402/macro-plan context. +- `wc -l` over required source files to size the read set. +- `sed -n` on all required sources listed in `Files Read`. +- `sed -n` on additional source anchors for runtime ingress families, auth.md, x402 protected-tool profile/facade, HTTP admission, OpenAPI, MCP lane, codebase concerns, macro map, and macro tasks. +- `rg -n` for runtime, host, raw sibling, browser, A2A, OpenAPI, auth.md, x402, loop, retry, branch, dynamic, and stale posture anchors. +- `rg --files` to locate auth.md, MCP, OpenAPI/admission, x402 protected-tool, and runtime ingress source files. +- `git status --short -- .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/runtime-agent.md` +- `ls -la .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits` +- `apply_patch` to create only this audit report. diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/slices.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/slices.md new file mode 100644 index 0000000..24e254c --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits/slices.md @@ -0,0 +1,182 @@ +## Audit Scope + +Verdict: fail closed for implementation until the macro plan contains a full long-running Tier 1/Tier 2 program, not a widened version of the earlier minimal slice. + +Focus: execution slices and full-program sequencing for Tier 1/Tier 2 product simplification before Tier 3 progression. This audit does not select the macro move, does not synthesize the final plan, and does not promote final status. It pressure-tests what the future chair-owned macro plan must contain before implementation begins. + +The user has explicitly rejected a minimal slice and asked to boil the lake before Tier 3. That changes the required planning breadth, but it does not erase the source blockers: non-authority product nouns, generated-agent handle misuse, host-profile overclaiming, naming drift, external rail proof gaps, and validation absence remain blocking gates. + +## Source Boundary + +Authoritative source boundary: + +- Canonical repo truth: `README.md`, `QUALITY.md`, `STRUCTURE.md`, `docs/internal/decisions.md`, `docs/internal/protocol-notes.md`. +- Macro-plan contract truth: `gsd-macro-plan/SKILL.md`, `macro-plan-contract.md`, `output-quality-bar.md`. +- Current run truth: `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md`, `source-snapshot.md`, `blocked-checks.md`. +- Derived planning evidence: `.planning/macro-map/*` and `.planning/codebase/*` files read below. These can guide planning, but tracked source, canonical docs, and tests win if facts disagree. +- Memory context was used only to avoid repeating prior drift mistakes: Tier 3 stays outside the kernel package, x402 remains narrow local/reference buyer-side proof, and prior green tests cannot be trusted after worktree drift. + +Boundary caveat: the input requires the future macro plan to read a larger source boundary than this sidecar was asked to read, including `FACET-MAP.md`, `EXPERIENCE-MAP.md`, `AGENT-RUNTIME-MAP.md`, `PROTECTED-ACTION-MAP.md`, `DECISIONS.md`, `TASKS.jsonl`, `views/*.md`, strategic run files, and protocol definition/architecture/layman docs. A future plan that does not reconcile that full boundary is not implementation-ready. + +## Files Read + +- `/Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-plan-contract.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/output-quality-bar.md` +- `/Users/joelchan/.codex/memories/MEMORY.md` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/source-snapshot.md` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md` +- `.planning/macro-map/MACRO-HANDOFF.md` +- `.planning/macro-map/MACRO-MAP.md` +- `.planning/macro-map/EXECUTION-MAP.md` +- `.planning/macro-map/MECHANISM-MAP.md` +- `.planning/macro-map/CONCERNS.md` +- `.planning/codebase/STRUCTURE.md` +- `.planning/codebase/TESTING.md` +- `README.md` +- `QUALITY.md` +- `STRUCTURE.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` + +## Invariant At Stake + +Product simplification can make Handshake legible, but it must not launder standing evidence, review language, workflow handles, or friendly IDs into authority. + +The invariant is: + +```text +Passport / Admission / Badge / Handle are evidence and context only. +Fresh exact protected-action clearance is the only path to authority. +``` + +Any macro plan that lets a passport, admission, badge, handle, certificate, review surface, CLI command, MCP resource, SDK type, demo output, or product ID satisfy policy, produce a greenlight, perform a gateway check, invoke a signer, create payment material, mutate, export a receipt, or mint terminal authority evidence violates the product kernel. + +## Pass Conditions + +The future macro plan passes this slices audit only if it contains all of the following: + +- A full source reconciliation phase that snapshots canonical docs, macro-map artifacts, codebase maps, blocked checks, missing artifacts, stale artifacts, and proof gaps before source edits. +- Execution slices with objective, source evidence, inputs, outputs, owner, dependencies, stop conditions, proof gates, verification commands, rollback or abandonment criteria, and agent handoff needs. +- A long-running sequence for Tier 1 and Tier 2, not only `docs/internal/service-workflow-story.md` plus a schema stub. +- Explicit P0/P1 preservation from `.planning/macro-map/CONCERNS.md` as implementation blockers unless accepted and bounded by the chair/user. +- A field-level matrix for `ServiceWorkflowAdmission` and `ServiceWorkflowHandle` proving every field is evidence, bounds, posture, refusal, proof gap, or correlation only. +- Negative tests proving handles cannot satisfy `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheckAttempt`, `Receipt`, `AuthorityCertificate`, signer invocation, payment material creation, or mutation. +- Generated-execution stress coverage for loops, retries, branches, dynamic tool construction, stale review surfaces, raw sibling paths, and agents passing handles as permission. +- Product surface convergence across docs, SDK, CLI, MCP, demos, examples, package exports, readback projections, and architecture tests without broadening authority. +- Protected-action gates for each touched action family, especially x402, that preserve exact candidate action, credential holder, gateway authority holder, raw sibling bypass posture, refusal/readback/proof-gap separation, and one-use greenlight semantics. +- Stop conditions that halt before Tier 3 if Tier 1/Tier 2 simplification lacks source-owned schema, negative tests, validation, sidecar reconciliation, and full repo gates. +- Rollback or abandonment criteria for authority drift, raw material leakage, protocol primitive creep, multi-host containment overclaim, external rail overclaim, or fixture/demo-first sequencing. +- An `AGENT-HANDOFF.md` sufficient for a fresh agent to resume without chat memory, including instruction sources, ignored context, tool contract, checkpoints, stop conditions, proof gaps, and next agent step. +- `TASKS.jsonl` lines that are assignable mechanisms with acceptance checks, not advice. +- Validation evidence from the macro-plan validator before any claim of execution readiness. + +## Failures + +Current blockers that the future macro plan must not smooth over: + +- P0: Passport, Admission, Badge, and `ServiceWorkflowHandle` can become ambient authority if they carry or imply policy, greenlight, gateway, signer, receipt, certificate, credential, payment, or mutation material. +- P0: Generated agents may pass a handle into tools as permission, especially inside loops, retries, dynamic tool calls, stale review flows, or branch-dependent execution. +- P1: Multi-host evidence is not native containment. Codex-local evidence is stronger than Claude Code, Hermes, OpenClaw, generic MCP, browser, A2A, or OpenAPI, and none can be generalized. +- P1: Passport/Admission/Badge names can leak into protocol areas, package exports, runtime dispatch, gateway paths, CLI/MCP commands, or demos. +- P1: Developer docs can become metaphor-only unless they include exact fields, forbidden interpretations, failure states, proof gates, and source-owned tests. +- P1: Free passport verification can blur into paid clearance unless the economic unit remains protected-event terminalization. +- The run's `blocked-checks.md` says no field-level acceptance matrix exists for `ServiceWorkflowAdmission` / `ServiceWorkflowHandle`. +- No negative test currently proves a handle cannot create or satisfy authority-bearing records or signer/payment/mutation behavior. +- No implemented schema or rendered readback artifact proves users see admission, handle, action request, clearance, receipt, refusal, and proof gap as separate states. +- No live external rail proof exists for x402 provider/facilitator behavior, auth.md deployment corpus, ERC-8004 standing, MCP Registry lookup, Agentic.Market listing, hosted custody, provider signer lifecycle, or settlement/finality. +- The macro-plan package has not yet been written or validated. + +Missing slices if the chair only follows the old minimal path: + +- Source-boundary reconciliation and stale-artifact classification slice. +- Product noun authority-boundary slice for Passport, Admission, Badge, Handle, Certificate, review surfaces, and IDs. +- Source-owned surface schema/projection slice for `ServiceWorkflowAdmission` and `ServiceWorkflowHandle`. +- Non-authority flag and negative-test slice. +- Naming/package/export guard slice. +- Runtime/generated-execution misuse slice. +- Protected-action field-level matrix slice. +- Evidence/readback/redaction slice. +- x402 current-wedge non-regression slice. +- Docs/SDK/CLI/MCP/demo/example convergence slice. +- Quality, package, and full-repo gate slice. +- Tier 3 stop-wall and handoff slice. +- Rollback, abandonment, and git-checkpoint slice. +- Fresh-agent handoff and continuation slice. + +## Proof Gaps + +- No full macro-plan package exists yet for this run, so there is no current `EXECUTION-SLICES.md`, `AGENT-HANDOFF.md`, `RUNTIME-GATES.md`, `PROTECTED-ACTION-GATES.md`, `EVIDENCE-PLAN.md`, `REVIEW-GATES.md`, `RISKS.md`, `DECISIONS.md`, or `TASKS.jsonl` to audit. +- No evidence shows the future plan has read the full source boundary required by the run input. +- No evidence shows the future plan has reconciled sidecar audits before chair synthesis. +- No evidence shows the future plan has stop conditions specific enough to halt implementation when a product noun becomes authority-bearing. +- No evidence shows rollback/abandonment criteria are attached to each slice rather than placed in a generic risk section. +- No evidence shows a fresh agent can execute the full long-running program without chat memory. +- No evidence shows Tier 3 remains blocked until Tier 1/Tier 2 proof gates pass or proof gaps are explicitly recorded. + +## Required Changes + +Required full-program phases: + +1. Source reconciliation and blocker preservation: classify canonical docs, scratch planning inputs, run-local files, missing full-boundary inputs, existing proof lanes, non-proofs, and open P0/P1 concerns. +2. Product boundary contract: define the noun set and forbidden interpretations so Passport/Admission/Badge/Handle remain evidence/context only. +3. Surface schema and readback design: specify `ServiceWorkflowAdmission` and `ServiceWorkflowHandle` as regenerated projection/readback objects with hard non-authority flags and no durable protocol authority state. +4. Architecture and claim-boundary tests: add naming, import, package, root-export, surface-posture, and claim tests before publicizing any simplified noun. +5. Runtime and generated-execution stress: prove handles fail as permission across runtime ingress, MCP, browser/A2A/OpenAPI posture, loops, retries, branches, stale reviews, and raw sibling bypass probes. +6. Protected-action matrix: map every field and transition from admission to fresh action request, exact contract, policy/refusal, one-use greenlight, gateway check, receipt/refusal/proof gap, replay refusal, and certificate. +7. Product surface convergence: align docs, SDK, CLI, MCP, demos, examples, package exports, and readback language without creating new authority or claiming hosted operation. +8. x402 and adjacent-lane non-regression: keep the first wedge as one buyer-side `x402_payment.exact` per-call protected action and preserve signer material behind `VerifiedGatewayCheck`. +9. Evidence and redaction: prove raw credentials, tokens, payment payloads, payment signatures, private keys, raw provider secrets, and raw internal records cannot leak through product surfaces. +10. Validation and handoff: run macro-plan validation, preserve sidecar findings, define git checkpoints, produce fresh-agent handoff, and only then enter implementation planning. +11. Tier 3 admission wall: explicitly block Tier 3/hosted progression until all Tier 1/Tier 2 source gates pass or named proof gaps are accepted as non-authority. + +Gates that block implementation: + +- Macro-plan package not written and validator not run. +- Sidecar audits not reconciled by the chair. +- Any P0 concern remains open without a concrete test-backed mechanism. +- Missing field-level protected-action matrix. +- Missing negative tests for handle-as-permission and noun-to-authority drift. +- Missing runtime stress coverage for generated code behavior. +- Missing source-owned placement decision for the schema/projection. +- Missing rollback/abandonment criteria per slice. +- Missing full-source-boundary readback. +- Any claim of native host containment, external provider custody, settlement/finality, marketplace/certification, hosted operation, or Tier 3 readiness from current local/profile evidence. + +What cannot be delegated: + +- Final sequencing of the full program. +- Final status recommendation. +- Authority boundary claims. +- Acceptance of P0/P1 risk. +- Decision that a product noun is safe to expose in source or package surfaces. +- Decision to admit a new protocol primitive. +- Decision to unblock Tier 3. +- Determination that a proof gap is acceptable product posture. +- Reconciliation of sidecar conflicts. + +Sidecars can report pressure findings. The chair must own the final sequence and cannot outsource authority claims. + +Smallest next mechanism: + +Write `EXECUTION-SLICES.md` first, not source code. The first slice must be source-boundary reconciliation with a table of canonical sources, scratch sources, missing inputs, P0/P1 blockers, pass gates, stop conditions, rollback/abandonment criteria, and handoff needs. The second slice must be the non-authority product-noun contract plus negative-test plan. No implementation slice should precede those two. + +## Status Recommendation + +Recommendation to chair: keep implementation blocked until the full macro-plan package exists, validates, and reconciles this slices audit with the other sidecar reports. + +Do not mark the future plan ready for agent execution from a minimal docs/schema/test path. The user asked for a full program; the only acceptable handoff is a long-running, source-backed Tier 1/Tier 2 sequence with proof gates, stop conditions, rollback/abandonment criteria, and fresh-agent handoff. + +Do not let Tier 3 move forward from product-language simplification alone. Without non-authority flags, negative tests, runtime misuse coverage, protected-action matrix, and evidence/readback separation, the simplification becomes review theatre and ambient authority risk. + +## Commands Or Tools Used + +- Used `gsd-macro-plan` skill instructions and references. +- `rg -n "Tier 3|Tier 1|Tier 2|macro-plan|x402|product simplification|20260525|Handshake v0\\.0\\.2" /Users/joelchan/.codex/memories/MEMORY.md` +- `wc -l` on required source files. +- `sed -n` on required source files and current run files. +- `find .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification -maxdepth 1 -type f -print` +- `ls -la .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits` +- `mkdir -p .planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/audits` +- `apply_patch` to add this report only. diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md new file mode 100644 index 0000000..80d22c2 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md @@ -0,0 +1,34 @@ +# Blocked Checks + +## Map Eligibility + +The current macro map was decision-gated, not `READY_FOR_MACRO_PLAN`. The user has now explicitly authorized a full macro-plan pass and implementation sequence, but the original blockers remain execution gates. + +## Runtime Proof + +- No live Codex, Claude Code, Hermes, OpenClaw, generic MCP, browser, A2A, or OpenAPI runtime smoke was run for this workflow handle. +- Existing host-profile evidence is posture/profile evidence, not native containment. + +## Protected-Action Proof + +- No field-level acceptance matrix exists yet for `ServiceWorkflowAdmission` / `ServiceWorkflowHandle`. +- No negative test currently proves the handle cannot create or satisfy `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheckAttempt`, `Receipt`, `AuthorityCertificate`, signer invocation, payment material, or mutation. + +## Product Proof + +- No implemented schema or rendered readback artifact proves users see admission, handle, action request, clearance, receipt, refusal, and proof gap as separate states. +- No user comprehension evidence proves `Badge` will not be read as bearer auth. + +## External Rail Proof + +- No live x402 provider/facilitator behavior, auth.md deployment corpus, ERC-8004 standing, MCP Registry lookup, Agentic.Market listing, hosted custody, provider signer lifecycle, or settlement/finality evidence was verified for this run. + +## Validation Status + +The macro-plan package has been written and the structural validator currently passes: + +```text +Macro plan output is valid. +``` + +This validates package structure, not source implementation. Protected-action fixture readiness, multi-host runtime claims, public-surface convergence, live external rails, hosted operation, and Tier 3 remain blocked until their source proof gates pass or explicit proof gaps are recorded. diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md new file mode 100644 index 0000000..fe53024 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/input.md @@ -0,0 +1,88 @@ +# Tier 1 / Tier 2 Product Simplification Macro-Plan Input + +## Invariant At Stake + +Product simplification may hide protocol complexity from users, but it must not hide or weaken authority, gateway, evidence, refusal, proof-gap, isolation, or reconstruction boundaries. + +Passport, Admission, Badge, Handle, Certificate, review surfaces, and user-facing IDs are evidence and correlation surfaces only unless a source-owned protocol transition proves otherwise. + +## User Objective + +Boil the lake. Produce a full, execution-ready Tier 1 and Tier 2 Handshake product-simplification macro plan before Tier 3 progression, grounded in `.planning/codebase`, `.planning/macro-map`, and canonical repo docs. Use `gsd-macro-plan` with sidecar reviews, define 10-star success criteria, long-running end conditions, anti-patterns, proof gates, assignable tasks, validation, git checkpoints, and then move into implementation. + +## Ten-Star Success Criteria + +- Users see a simple product flow, not protocol internals. +- The product never implies that a passport, certificate, review screen, or ID is authority. +- Tier 1 and Tier 2 each have crisp product surfaces, not internal architecture exposed as UX. +- Every surfaced object has explicit `createsAuthority: false` unless it is truly an enforceable gateway-bound authority artifact. +- Passport references are split cleanly: `passportPackageDigest`, `passportPresentationId`, `admissionId`, `serviceWorkflowHandleId`, `serviceWorkflowHandleDigest`. +- Every simplification preserves reconstructable evidence. +- Every action path still has a protected-action boundary and gateway enforcement posture. +- Docs, demos, SDK, CLI, MCP surfaces, and examples converge on the same simplified product model. +- The plan contains full execution slices, not advice. +- Tier 3 is blocked until Tier 1 and Tier 2 product simplification have proof gates satisfied or explicit proof gaps recorded. + +## Long-Running End Conditions + +The exercise ends only when the macro plan can hand a fresh agent the full Tier 1/Tier 2 simplification program with enough context to execute without chat memory, including source evidence, slices, gates, risks, task records, and validation output. + +Implementation begins only after the full macro-plan package is validated and sidecar findings are reconciled. + +## Anti-Patterns To Avoid + +- "Simple" meaning basic, toy, or under-modeled. +- Hiding authority boundaries behind friendly language. +- Treating passport/admission/workflow IDs as trust, identity, permission, or reusable auth. +- Letting UX summaries drift from exact contracts. +- Turning `.planning/` scratch into repo-facing canon. +- Broadening into Tier 3 before Tier 1/Tier 2 surfaces are sharp. +- Producing a minimal slice and calling it the plan. +- Claiming gateway enforcement where the source only proves advisory posture. +- Letting product polish outrun receipt, refusal, proof-gap, and isolation mechanics. + +## Chair Interpretation + +The prior macro-map handoff is `NEEDS_USER_DECISION`, not `READY_FOR_MACRO_PLAN`. The user decision to proceed is now explicit, but it does not erase the map blockers. This run must preserve those blockers as proof gates while broadening the plan from the smallest surface slice into the full Tier 1 / Tier 2 simplification program. + +## Required Source Boundary + +- `.planning/macro-map/MACRO-HANDOFF.md` +- `.planning/macro-map/MACRO-MAP.md` +- `.planning/macro-map/FACET-MAP.md` +- `.planning/macro-map/MECHANISM-MAP.md` +- `.planning/macro-map/EXECUTION-MAP.md` +- `.planning/macro-map/EXPERIENCE-MAP.md` +- `.planning/macro-map/AGENT-RUNTIME-MAP.md` +- `.planning/macro-map/PROTECTED-ACTION-MAP.md` +- `.planning/macro-map/CONCERNS.md` +- `.planning/macro-map/DECISIONS.md` +- `.planning/macro-map/TASKS.jsonl` +- `.planning/macro-map/views/*.md` +- `.planning/codebase/*.md` +- `README.md` +- `QUALITY.md` +- `STRUCTURE.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/protocol-definition.md` +- `docs/internal/protocol-kernel-architecture.md` +- `docs/internal/protocol-layman.md` + +## Non-Authority ID Model To Preserve + +The plan must define the following as correlation/reconstruction fields only: + +- `passportPackageDigest`: content-addressed digest of the presented evidence bundle. +- `passportPresentationId`: unique per service intake / presentation event. +- `admissionId`: service-side result after checking the passport. +- `serviceWorkflowHandleId`: carried workflow reference for context. +- `serviceWorkflowHandleDigest`: digest of the carried workflow reference. + +All five fields must have `createsAuthority: false`; none may prove identity, trust, spend approval, gateway acceptance, signer permission, mutation permission, receipt export, terminal certification, or reusable auth. + +## Initial Plan Status + +`READY_FOR_FULL_MACRO_PLAN_WITH_RECONCILED_BLOCKERS` + +This is not `READY_FOR_AGENT_EXECUTION` until the plan package, sidecar review, and validator pass. diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/source-snapshot.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/source-snapshot.md new file mode 100644 index 0000000..1d3c94c --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/source-snapshot.md @@ -0,0 +1,42 @@ +# Source Snapshot + +## Git State + +- Branch: `main` +- Upstream: `origin/main` +- Initial `git status --short`: clean + +## Canonical Product Truth + +- `README.md` says Handshake is protected action infrastructure for automated decision making and reduces one consequential automated action to an exact contract before mutation. +- `README.md` says product surfaces expose proposal/evidence without creating authority, and MCP is proposal/evidence only. +- `docs/internal/decisions.md` defines the current kernel chain as exact action contract -> policy decision -> one-use gateway-bound greenlight -> gateway check before mutation -> receipt/refusal/proof gap. +- `docs/internal/decisions.md` keeps hosted operation, provider custody, settlement/finality, marketplace/certification, cross-org trust, host-wide containment, aggregate spend, and broad x402 compatibility as proof gaps, outside claims, or cut lines. +- `docs/internal/protocol-notes.md` defines the primitive as reducing every consequential mutation attempt to an exact, inspectable, policy-evaluated, gateway-bound action contract before consequence. +- `QUALITY.md` and `STRUCTURE.md` require product surfaces to expose proposal/evidence/readback without becoming protocol authority. + +## Macro Map Truth + +- `.planning/macro-map/MACRO-HANDOFF.md` status is decision-gated and warns that Passport, Admission, Badge, and Handle are evidence/context only. +- `.planning/macro-map/MACRO-MAP.md` says the kernel authority chain should remain unchanged and the first mechanism belongs in product-surface admission/readback schema, not a new protocol primitive. +- `.planning/macro-map/CONCERNS.md` has open P0/P1 blockers for non-authority flags, handle misuse, multi-host overclaim, naming drift, metaphor-only docs, and free verifier versus paid clearance confusion. +- `.planning/macro-map/PROTECTED-ACTION-MAP.md` says the triggering consequence begins only when an admitted workflow tries to perform a protected action. +- `.planning/macro-map/AGENT-RUNTIME-MAP.md` says multi-host runtime claims must remain proof-gapped and host-specific. + +## Codebase Map Truth + +- `.planning/codebase/ARCHITECTURE.md` places authority in policy greenlight, gateway gate, verified gateway adapters, and replay-sensitive storage, not runtime ingress, HTTP admission, projections, CLI, MCP, SDK, or demos. +- `.planning/codebase/STRUCTURE.md` says Passport readback should be a projection over existing records, Admission changes belong in HTTP admission and route metadata only if needed, and service gateway language maps to existing gateway registry, credential custody, gateway gate, and adapter files. +- `.planning/codebase/CONCERNS.md` flags no current source-owned Passport primitive and warns that standalone Passport, Admission, ServiceGateway, or PrincipalAgentLink objects can duplicate existing authority-adjacent state. +- `.planning/codebase/TESTING.md` names the focused gates for simplification: `npm run quality:claims`, `npm run quality:architecture`, and focused protocol/runtime projection tests. + +## Source Boundary Status + +The source boundary is sufficient for full macro planning. The implementation phase must still source-open named files before edits and must not treat `.planning/` as canon. + +## Non-Proofs + +- No `ServiceWorkflowAdmission` or `ServiceWorkflowHandle` schema exists yet. +- No negative tests currently prove the new product nouns cannot create authority. +- No local demo connects an admitted workflow handle to one fresh x402 exact clearance. +- No live provider custody, settlement, hosted operation, native host containment, external registry acceptance, or marketplace trust is proven. diff --git a/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/validation.md b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/validation.md new file mode 100644 index 0000000..a623dd1 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/validation.md @@ -0,0 +1,135 @@ +# Validation + +## Macro-Plan Validator + +Command: + +```bash +python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +``` + +Observed output: + +```text +Macro plan output is valid. +``` + +## Status Reconciliation + +The plan is implementation-ready only for the first bounded Tier 1 story/schema/test slice. It is not a claim that protected-action fixtures, multi-host runtime posture, SDK/CLI/MCP convergence, live rails, hosted operation, or Tier 3 are ready. + +Sidecar audit recommendations were reconciled as gates: + +- protected-action posture -> field matrix, false authority flags, negative tests, no fixture until surface proof exists; +- runtime-agent posture -> host-specific rows, raw sibling posture, generated-execution stress gates, no containment claim; +- product/DevEx posture -> one source-owned packet, first-use demo later, convergence after schema/tests; +- evidence posture -> validator output and git state must be recorded before implementation; +- slices posture -> full long-running program captured before source edits. + +## Git State + +`.planning/` is ignored by `.gitignore`, so normal `git status --short` does not show these artifacts. If the user wants planning artifacts committed, they must be force-added deliberately. + +## Implementation Checkpoints + +T1-01 through T1-03 landed in source as the service workflow story, non-authority +admission/handle surface, and workflow-admission boundary tests. Verified gates: +focused workflow boundary test, `npm run quality:claims`, +`npm run quality:architecture`, `npm run format:check`, `git diff --check`, and +full `npm run check:repo`. + +T1-04 landed canonical-doc convergence for the simplified flow. Verified gates: +`npm run quality:claims`, `npm run quality:architecture`, +`npm run format:check`, and `git diff --check`. + +T2-01 landed active CLI, MCP, and SDK surface alignment only. It did not add +commands, MCP authority tools, SDK methods, package-root exports, policy, +gateway, signer, mutation, receipt export, or terminal certificate behavior. +Verified gates: + +```bash +npm run test -- test/architecture/cli-command-posture.test.ts test/architecture/mcp-surface-posture.test.ts test/cli/cli-evidence.test.ts +npm run test -- test/architecture/mcp-surface-posture.test.ts test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-resource-redaction.test.ts test/mcp/mcp-x402-proposal.test.ts test/architecture/workflow-admission-boundary.test.ts +npm run test -- test/architecture/root-exports.test.ts test/sdk/role-clients.test.ts test/architecture/package-surface.test.ts test/architecture/workflow-admission-boundary.test.ts +npm run check:types +npm run quality:architecture +npm run quality:claims +npm run format:check +git diff --check +``` + +Open next slice: MPLAN-007 / T2-02 local service workflow admission example. + +T2-02 landed a runnable local `service-workflow-admission` example that +validates one admission/handle packet, composes the existing x402 protected +spend demo as the separate fresh-clearance path, and writes JSON plus Markdown +readback. It did not introduce a new protocol primitive, gateway fixture, +policy evaluator, signer path, mutation runner, public root export, hosted +operation claim, provider custody claim, settlement claim, or handle-as- +permission behavior. Verified gates: + +```bash +npm run test -- test/product/service-workflow-admission.test.ts +npm run test -- test/product/service-workflow-admission.test.ts test/product/x402-protected-spend-demo-report.test.ts +npm run check:types +npm run quality:architecture +npm run quality:claims +npm run format:check +git diff --check +``` + +Open next slice: MPLAN-008 / T2-03 generated-agent and runtime misuse tests. + +T2-03 landed generated-agent and runtime misuse gates. The local service +workflow admission artifact now emits explicit non-authority misuse posture for +loop/retry handle reuse, changed parameters, dynamic tool construction, stale +rendered review, raw sibling x402 bypass, replay, and proof-gap cases. Runtime +ingress tests tie service workflow handle evidence to x402 stale/dynamic +refusal and loop/retry attempts while preserving fresh per-call action +contracts and no policy, greenlight, gateway check, signer, mutation, receipt, +or certificate records. Verified gates: + +```bash +npm run test -- test/product/service-workflow-admission.test.ts +npm run test -- test/runtime/runtime-ingress.test.ts +npm run check:types +npm run quality:architecture +npm run quality:claims +npm run format:check +``` + +Open next slice: MPLAN-009 / T2-04 protected-action fixture gate. + +T2-04 landed the protected-action fixture gate on the service workflow +admission example. The example now proves the workflow handle is +correlation-only context for one fresh `x402_payment.exact` path, records the +fresh ActionContract, PolicyDecision, Greenlight, GatewayCheck, and Receipt +refs separately from admission/readback, and verifies payment material appears +only as gateway evidence after verified gateway check. auth.md is explicitly +recorded as provenance/proof-gap posture only, not a composite credential plus +spend authority artifact. Verified gates: + +```bash +npm run test -- test/product/service-workflow-admission.test.ts +npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts +``` + +Open next slice: MPLAN-010 / T2-05 Tier 3 lock and final release gate. + +T2-05 landed the Tier 3 admission lock and final release gate in canonical +docs plus claim-boundary tests. The lock states that service workflow +simplification is not a hosted-operation go-ahead, Tier 3 may consume or extend +the surface only after Tier 1/Tier 2 proof or explicit proof-gap posture, and +hosted operation or kernel-export needs must route to a separate hosted +workspace or a new Tier 1/Tier 2 kernel task with fresh proof gates. Verified +gates: + +```bash +npm run test -- test/architecture/claim-boundary.test.ts +npm run check:repo +``` + +Final status: MPLAN-001 through MPLAN-010 are complete. Tier 1/Tier 2 product +simplification is implemented and repo-gated. Tier 3 remains locked behind a +separate hosted workspace or fresh Tier 1/Tier 2 kernel task if hosted needs +require kernel changes. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/architecture-case-study-audit.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/architecture-case-study-audit.md new file mode 100644 index 0000000..4ff56da --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/architecture-case-study-audit.md @@ -0,0 +1,211 @@ +## Audit Scope + +Assigned focus: slices. + +This audit covers the architectural north star for the correction run: one protocol authority spine with non-authority projection surfaces. It does not select the macro move, synthesize the final plan, or promote final status. The question under audit is whether current repo language and source shape support projection-over-one-authority-spine strongly enough to guide the macro plan. + +Report path: `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/architecture-case-study-audit.md`. + +## Source Boundary + +Repo-local evidence is from the current checkout only. `.planning/` was treated as scratch except for this assigned output path. Current git state observed: `main...origin/main [ahead 8]`. + +Official/primary case-study sources used: + +- Stripe PaymentIntents lifecycle and idempotency: `https://docs.stripe.com/payments/payment-intents`, `https://docs.stripe.com/api/idempotent_requests`. +- Kubernetes admission and OPA Gatekeeper: `https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/`, `https://open-policy-agent.github.io/gatekeeper/website/docs/customize-admission/`. +- HashiCorp Vault leases: `https://developer.hashicorp.com/vault/docs/concepts/lease`. +- GitHub deployment environments: `https://docs.github.com/en/actions/reference/workflows-and-actions/deployments-and-environments`. +- AWS IAM evaluation: `https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic_policy-eval-denyallow.html`. +- SLSA, in-toto, Sigstore/Rekor evidence: `https://slsa.dev/spec/v1.2-rc2/build-provenance`, `https://in-toto.io/docs/getting-started/`, `https://docs.sigstore.dev/logging/overview/`. +- Vercel and Cloudflare scope clarity: `https://vercel.com/docs/environment-variables`, `https://developers.cloudflare.com/fundamentals/api/reference/permissions/`. + +Browsing was available. No secondary sources were used for external facts. + +## Files Read + +- `AGENTS.md` +- `README.md` +- `STRUCTURE.md` +- `package.json` +- `docs/internal/decisions.md` +- `docs/internal/protocol-definition.md` +- `docs/internal/protocol-kernel-architecture.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/service-workflow-story.md` +- `src/protocol/LANE.md` +- `src/protocol/kernel.ts` +- `src/protocol/areas/policy-greenlight/transitions.ts` +- `src/protocol/areas/policy-greenlight/policy-record/index.ts` +- `src/protocol/areas/gateway-gate/transitions.ts` +- `src/protocol/areas/gateway-gate/artifacts.ts` +- `src/protocol/areas/gateway-gate/replay-refusal/index.ts` +- `src/protocol/areas/idempotency-ledger/entries.ts` +- `src/http/routes/transition-route-registry.ts` +- `src/http/routes/transition-invokers.ts` +- `src/sdk/LANE.md` +- `src/sdk/surface-clients/index.ts` +- `src/sdk/surface-clients/policy-client.ts` +- `src/sdk/surface-clients/gateway-client.ts` +- `src/surfaces/LANE.md` +- `src/surfaces/boundary-manifest.ts` +- `src/surfaces/outcome.ts` +- `src/surfaces/service-workflow-admission/index.ts` +- `test/architecture/surface-boundary-posture.test.ts` +- `test/architecture/claim-boundary.test.ts` +- `test/architecture/import-posture.test.ts` +- `test/architecture/package-surface.test.ts` +- `test/sdk/role-clients.test.ts` + +Searches also covered `src`, `test`, `docs/internal`, and the assigned run directory. + +## Invariant At Stake + +Every projection must remain a read/write view over one authority spine. A product-facing SDK, CLI, MCP tool, service-workflow handle, certificate view, launch gate, or hosted surface must not become a second place where policy, greenlight, gateway acceptance, credential custody, execution proof, or terminal trust is invented. + +If a projection can mint or imply authority independently of the protocol kernel state path and gateway check, it is advisory theatre with a nicer API. + +## Pass Conditions + +### What the case studies imply as mechanisms, not analogies + +- Stripe PaymentIntents imply a durable lifecycle object plus idempotency binding. A retry cannot silently become a second purchase; idempotency keys bind to parameters and parameter drift is an error. Handshake equivalent: `ActionContract` plus idempotency ledger must bind protected-surface, resource, key, and parameter digest before greenlight reuse or duplicate authority can happen. +- Kubernetes admission and Gatekeeper imply a chokepoint, not a dashboard. Every matching policy/binding/parameter combination must pass before admission. Gatekeeper's default fail-open posture is a warning: any macro slice that cannot prove fail-closed behavior for protected mutation is not an enforcement slice. +- Vault implies custody is lifecycle state: lease id, TTL, renewability, revocation, and audit trail. A `GatewayCredentialRef` without external custody, expiry, revocation, and rotation evidence is local/reference custody, not provider or customer custody. +- GitHub deployment environments imply protected material is withheld until the gate passes. Environment secrets are unavailable to a job until protection rules pass. Handshake equivalent: signer/payment material must stay behind `VerifiedGatewayCheck`, not behind a review screen or SDK convenience method. +- AWS IAM implies default deny plus explicit deny dominance. Handshake equivalent: refusal, isolation, stale custody, policy drift, replay, and proof-gap blockers must dominate projection convenience and future greenlights. +- SLSA, in-toto, and Sigstore imply evidence is useful only when it is digest-bound to a subject, builder/control-plane boundary, ordered layout/links, and append-only verification posture. Handshake equivalent: receipt/proof projections must carry record refs, digests, stream events, audit-chain posture, and proof gaps; a certificate is terminal evidence, not permission. +- Vercel and Cloudflare imply scope names must be operationally concrete: team/project/environment; zone/account/user permission groups. Handshake equivalent: every projection must name caller role, custody role, action family, gateway holder, protected surface, and non-claims. Distribution scope is not authority. + +Repo pass evidence: + +- The protocol definition already states one state path and authority rule: `docs/internal/protocol-definition.md:48-70`, `docs/internal/protocol-definition.md:88-104`. +- `HandshakeKernel` centralizes transition entrypoints over protocol areas rather than letting SDK/MCP/CLI own behavior: `src/protocol/kernel.ts:100-245`. +- Policy evaluation derives isolation, protected-path posture, idempotency, credential binding, delegated authority, and sequence state before decision/greenlight: `src/protocol/areas/policy-greenlight/transitions.ts:125-162`, `src/protocol/areas/policy-greenlight/transitions.ts:188-237`. +- Gateway check rereads contract, greenlight, policy decision, observed parameter digest, isolation, posture, custody bindings, sequence dependencies, and idempotency before mutation: `src/protocol/areas/gateway-gate/transitions.ts:87-103`, `src/protocol/areas/gateway-gate/transitions.ts:128-190`. +- Receipts distinguish gateway decision, greenlight consumption, mutation attempt, downstream status, proof gaps, and audit chain: `src/protocol/areas/gateway-gate/artifacts.ts:301-343`. +- Service workflow admission is explicitly non-authority and requires a fresh action contract: `src/surfaces/service-workflow-admission/index.ts:21-35`, `src/surfaces/service-workflow-admission/index.ts:95-111`. + +## Failures + +### Repo conflicts with projection-over-spine architecture + +1. The repo still frames the boundary as product/protocol vocabulary instead of one authority spine with projections. + + Evidence: `STRUCTURE.md:7-13`, `docs/internal/decisions.md:42-48`, `docs/internal/protocol-notes.md:13-40`, `docs/internal/protocol-kernel-architecture.md:35-40`, and `README.md:15-20`. + + The content usually says the right thing, but the architecture label is wrong for the target. The macro plan should not preserve a two-lane mental model where product surfaces and protocol are peers. Projections are subordinate views over the one authority spine. + +2. `sdk.policy` is modeled as an explicit authority surface. + + Evidence: `src/surfaces/boundary-manifest.ts:296-365` marks `sdk.policy` with `authorityPosture: "policy_authority"` and allows `policy_decision_write`. `test/architecture/surface-boundary-posture.test.ts:51-110` codifies `authoritySurfaces: ["sdk.policy"]` and asserts it is "policy authority". `src/sdk/LANE.md:110-115` calls `PolicyClient` the narrow policy-authority surface. + + This is the sharpest conflict. The implementation of `PolicyClient` is only a transport call to `/v0.2/policy-decisions` (`src/sdk/surface-clients/policy-client.ts:24-33`), and the HTTP invoker delegates to `kernel.evaluatePolicy` (`src/http/routes/transition-invokers.ts:49-53`). That is good source shape. The naming and tests are bad architecture: they teach that a projection surface owns authority. It should be modeled as a control-plane projection over a kernel transition, not as an authority surface. + +3. Surface route-family manifests are parallel authority maps, not visibly derived from the transition registry. + + Evidence: `src/surfaces/boundary-manifest.ts:90-105` defines per-surface allowed/forbidden route families; `src/http/routes/transition-route-registry.ts:80-120` and `src/http/routes/transition-route-registry.ts:251-300` define the actual transition routes and caller roles; `test/architecture/surface-boundary-posture.test.ts:74-123` checks the manifest internally but does not prove every allowed surface route is a projection over a specific kernel transition route. + + Mechanism risk: a future surface can become "allowed" in the manifest without proving the route maps to the kernel spine, caller role, scope resolver, and transition invoker. + +4. Gateway projection language is better than policy projection language, but still needs a macro gate. + + Evidence: `src/surfaces/boundary-manifest.ts:430-483` marks `sdk.gateway` as `transport_only` while allowing `gateway_check_write`; `src/sdk/surface-clients/gateway-client.ts:40-75` posts to gateway-custody routes; the actual route delegates to the kernel (`src/http/routes/transition-route-registry.ts:292-300`, `src/http/routes/transition-invokers.ts:49-53`). + + This is acceptable only if the macro plan keeps saying "gateway custody projection over the kernel gateway-check transition." If it drifts into "SDK gateway authority," the generated code escaped the contract boundary. + +5. Current docs contain correct non-claims, but they are scattered enough that projection-over-spine is not yet the obvious governing test. + + Evidence: `README.md:129-146`, `docs/internal/decisions.md:173-230`, `docs/internal/decisions.md:232-256`, and `docs/internal/protocol-notes.md:367-386` all carry cut lines. This is useful, but the macro plan needs a single gate that fails any slice whose projection wording exceeds the kernel/gateway evidence. + +## Proof Gaps + +- No current architecture test proves that every product projection route family is derived from `transitionRouteDefinitions` and `transitionInvokers`. +- No current architecture test forbids the concept of an "authority surface"; one test requires it for `sdk.policy`. +- No current architecture test enforces the target vocabulary: authority spine plus projection surfaces. +- Provider/customer gateway custody remains a proof gap beyond local/reference proof, already acknowledged in `docs/internal/decisions.md:196-205` and `docs/internal/decisions.md:340-343`. +- Hosted operation remains a proof gap until there is deployment boundary, custody, migration, secret-management, and receipt evidence, as acknowledged in `docs/internal/decisions.md:436-452`. +- External audit-log or transparency-log guarantees are not present. Local append-only protocol records and stream/audit-chain digests are not Sigstore/Rekor-style public transparency. + +## Required Changes + +### Required macro-plan slices/gates + +P0 slice: vocabulary correction. + +- Replace boundary language that treats "product" and "protocol" as peer lanes with "authority spine" and "projection surfaces". +- Gate: no positive architecture section may describe a product surface as creating authority. It may only expose, request, render, or transport spine-backed records. + +P0 slice: remove authority-surface modeling. + +- Recast `sdk.policy` from `policy_authority` to a control-plane projection over `kernel.evaluatePolicy`. +- Gate: `test/architecture/surface-boundary-posture.test.ts` must have no `authoritySurfaces` list. It should assert zero projection surfaces own authority, while allowing narrowly scoped transition projections to call authority-bearing routes only through the kernel route registry. + +P0 slice: route/projection derivation gate. + +- Tie every surface route family to `transitionRouteDefinitions`, caller role, scope resolver, and `transitionInvokers`. +- Gate: adding an allowed projection route without a kernel transition mapping fails architecture tests. + +P0 slice: chokepoint and bypass gate for every admitted action family. + +- Each action family must name the generated execution shape, exact protected path, final gateway enforcement point, raw/sibling bypass posture, failure-closed behavior, and proof-gap output. +- Gate: if mutation can occur without the gateway checking the exact one-use greenlight, stop the slice. This is advisory, not Handshake. + +P0 slice: custody lease/revocation gate. + +- Before any customer/provider custody claim, require evidence for credential holder, gateway holder, TTL/expiry, revocation, rotation, isolation, and post-gate credential-resolution evidence. +- Gate: local fixture custody cannot be promoted to provider/customer custody. + +P1 slice: evidence/provenance projection gate. + +- Every projection outcome must carry digest-bound refs to protocol records, stream events or audit-chain material, and proof-gap/refusal separation. +- Gate: terminal certificate, receipt, release proof, package provenance, or registry listing cannot be used as permission. + +P1 slice: distribution and scope gate. + +- Treat npm, MCP Registry, host profile, Vercel-like environment scope, and Cloudflare-like token scope as distribution or caller-scope facts only. +- Gate: listing/discoverability/installation cannot satisfy authority, custody, gateway, settlement, hosted trust, or cross-org trust. + +### P0/P1 risks and stop conditions + +P0 risk: macro plan preserves `policy_authority` as a surface posture. + +Stop condition: any plan slice says `PolicyClient`, SDK role clients, MCP, CLI, service workflow, or hosted surface owns policy authority rather than projecting a kernel transition. + +P0 risk: projection route drift. + +Stop condition: a surface manifest permits a route family that is not bound to `transitionRouteDefinitions`, caller custody, scope resolver, and a `HandshakeKernel` transition. + +P0 risk: custody claim outruns proof. + +Stop condition: provider/customer custody, signer lease, payment material, or revocation is claimed without external custody evidence and gateway-time reread. + +P0 risk: generated execution bypass. + +Stop condition: raw sibling, browser, shell, package manager, MCP sibling, direct signer, or hosted endpoint can mutate outside the exact contract -> policy -> one-use greenlight -> gateway check path. + +P1 risk: evidence inflation. + +Stop condition: receipt, certificate, provenance, package publication, registry lookup, or host invocation is described as permission, settlement, hosted trust, or cross-org trust. + +P1 risk: fail-open posture hidden as product convenience. + +Stop condition: outage, stale metadata, missing posture, ambiguous commit, or proof gap produces a retry or success path rather than refusal, isolation, replay refusal, or explicit proof gap. + +## Status Recommendation + +### Brutal verdict + +Keep the current source spine. Redesign the macro-plan language and surface boundary tests. + +The implementation is closer to the target than the vocabulary is: `PolicyClient` and `GatewayClient` are transport projections that call HTTP routes which delegate to `HandshakeKernel`. But the repo currently teaches one dangerous idea: an SDK projection can be an "authority surface." That is ambient authority wearing a planning label. + +Do not promote the architectural north star until the macro plan contains the P0 vocabulary, surface-model, and route/projection derivation slices above. The smallest next mechanism is an architecture gate that forbids authority-owned projection surfaces and proves every projection call maps back to the one kernel transition spine. + +## Commands Or Tools Used + +- Read repo files with `awk`, `find`, and `rg`. +- Checked dirty state with `git status --short --branch`. +- Used `web.search_query`, `web.open`, and `web.find` for official primary sources only. +- Created the assigned audit directory with `mkdir -p`. +- Wrote this single report with `apply_patch`. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/evidence-review-gates-audit.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/evidence-review-gates-audit.md new file mode 100644 index 0000000..fe7a817 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/evidence-review-gates-audit.md @@ -0,0 +1,234 @@ +# Evidence Review Gates Audit + +## Audit Scope + +Focus: evidence, review, and closeout gates for the architectural north-star macro-plan correction. + +This audit is bounded. It does not select the macro move, synthesize the final plan, promote final status, or convert protected-action proof gaps into authority. It identifies the evidence and gate structure that must exist before the correction can be treated as more than a thin plan. + +## Source Boundary + +The audit used the current checkout as source truth and treated `.planning/` as scratch planning evidence, not repo-facing canon. + +Primary source boundary: + +- Current doctrine and canonical truth: `AGENTS.md`, `docs/internal/decisions.md`, `QUALITY.md`. +- Current macro-map handoff: `.planning/macro-map/MACRO-HANDOFF.md`, `.planning/macro-map/CONCERNS.md`. +- Current macro-plan package: `.planning/macro-plan/*`. +- Prior macro-plan run evidence: `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/*`. +- Current command contract: `package.json` scripts. +- Current claim gate: `test/architecture/claim-boundary.test.ts`. +- Macro-plan skill contract: `gsd-macro-plan` `SKILL.md`, `macro-plan-contract.md`, `output-quality-bar.md`. + +The requested run directory did not exist before this audit report was written. That absence is a proof gap for the correction, not a blocker to writing this sidecar report. + +## Files Read + +- `AGENTS.md` +- `QUALITY.md` +- `package.json` +- `docs/internal/decisions.md` +- `test/architecture/claim-boundary.test.ts` +- `.planning/macro-map/MACRO-HANDOFF.md` +- `.planning/macro-map/CONCERNS.md` +- `.planning/macro-plan/README.md` +- `.planning/macro-plan/MACRO-PLAN.md` +- `.planning/macro-plan/EXECUTION-SLICES.md` +- `.planning/macro-plan/AGENT-HANDOFF.md` +- `.planning/macro-plan/RUNTIME-GATES.md` +- `.planning/macro-plan/PROTECTED-ACTION-GATES.md` +- `.planning/macro-plan/EVIDENCE-PLAN.md` +- `.planning/macro-plan/REVIEW-GATES.md` +- `.planning/macro-plan/RISKS.md` +- `.planning/macro-plan/DECISIONS.md` +- `.planning/macro-plan/TASKS.jsonl` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/validation.md` +- `.planning/macro-plan/runs/20260525T095940Z-tier1-tier2-product-simplification/blocked-checks.md` +- `.planning/macro-plan/runs/20260525T174005-passport-admission-full/audits/evidence.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-plan-contract.md` +- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/output-quality-bar.md` +- `/Users/joelchan/.codex/memories/MEMORY.md` lines 84-120 for prior x402 macro-plan drift lessons + +## Invariant At Stake + +The correction must not let planning evidence imitate execution evidence. + +A macro-plan can be structurally valid and still be thin. A prior run can have green tests and still be irrelevant after the checkout or plan boundary changes. A review table can exist and still be review theatre if it does not force sidecar disagreement, research evidence, test output, full repo gate, code review, and git checkpoints into the current run. + +For this correction, the invariant is: + +```text +Architectural north-star claims must be backed by current source evidence, +dated research evidence where external/current claims are made, current +macro-plan validation, current test output, full repo gate output, independent +review pressure, and reconstructable git checkpoints. +``` + +Anything less is advisory planning, not a Handshake-grade execution handoff. + +## Pass Conditions + +### Required Evidence Artifacts + +The current correction run must have its own evidence files under: + +```text +.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/ +``` + +Required run-local files: + +| Artifact | Required content | Stop condition if missing | +| --- | --- | --- | +| `input.md` | Exact correction objective, user constraints, run id, report paths, source boundary, and non-goals. | The chair cannot reconstruct why the correction exists. | +| `source-snapshot.md` | `git rev-parse HEAD`, `git status --short --untracked-files=all`, ignored `.planning/` posture, package scripts, canonical docs read, top-level macro-plan file list, and source/test paths touched or explicitly not touched. | Old evidence can be laundered into the current run. | +| `research-evidence.md` | Dated sources, URLs or local source paths, accessed date, extracted facts, disconfirming evidence, inference boundaries, and which macro-plan claim each fact supports. If no external/current claim remains, this file must say so explicitly and state why research is not needed. | Strategy or market claims become unsupported narrative. | +| `blocked-checks.md` | Open P0/P1 blockers, unavailable proof, non-proofs, external rails not verified, host/runtime proof gaps, and old-run evidence that is not transferable. | Proof gaps get smoothed over. | +| `validation.md` | Macro-plan validator command and output, status reconciliation, command matrix output, test output, full repo gate output, and what the validator does not prove. | Structural validation becomes semantic proof. | +| `code-review.md` | Findings-first review of the final diff, file/line references, missing tests, residual risk, and explicit statement if no source/docs/tests changed. | Review is replaced by plan authorship. | +| `git-checkpoints.md` | Checkpoint order, commit hashes, tested source commit, evidence-only commit if any, `git status` before/after, and whether `.planning/` files were force-added. | The chain cannot be reconstructed later. | +| `audits/*.md` | Bounded sidecar reports for slices, runtime, protected-action, and this evidence/review-gates audit, with chair reconciliation in `REVIEW-GATES.md`. | Sidecar pressure is not reconstructable. | + +Top-level macro-plan artifacts must also be current for this correction: + +- `.planning/macro-plan/EVIDENCE-PLAN.md` must point to the current run artifacts, not only the previous `095940Z` run. +- `.planning/macro-plan/REVIEW-GATES.md` must add current-run research, validation, repo gate, code review, and git checkpoint gates. +- `.planning/macro-plan/RISKS.md` must add P0/P1 risks for thin-plan laundering, stale research, missing code review, missing full repo gate, and ignored `.planning/` artifacts. +- `.planning/macro-plan/TASKS.jsonl` must include assignable current-run tasks with `status: "open"` until each proof file and gate output exists. + +### Review Gates And Sidecar Pressure Needed + +`REVIEW-GATES.md` must not only say sidecars exist. It must force pressure into the plan. + +Minimum required current-run gates: + +| Gate | Must include | Blocks promotion when | +| --- | --- | --- | +| Research Gate | Source table, date checked, claim supported, disconfirming facts, inference boundary. | External/current claims have no dated source evidence. | +| Macro-Plan Validation Gate | Validator command, observed output, artifact list, and semantic non-proof warning. | Validator was not run after final plan edits. | +| Source Boundary Gate | Canonical files, scratch files, stale/ignored artifacts, and source/test paths touched. | Current run inherits old run evidence without source snapshot. | +| Sidecar Reconciliation Gate | Each sidecar report, finding, chair disposition, artifact updated, residual blocker. | Sidecar findings are summarized but not converted into gates, risks, or tasks. | +| Code Review Gate | Findings-first review of final diff with file/line references or explicit no-source-change statement. | No independent final-diff review exists. | +| Focused Test Gate | Exact commands and outputs for affected claims. | Only generic "run tests" language exists. | +| Full Repo Gate | `npm run check:repo` output after final source/docs/tests changes. | Full gate not run or failed. | +| Git Checkpoint Gate | Commit hashes, force-add posture for `.planning/`, clean/known status, tested source commit. | Evidence cannot be tied to a committed state. | +| Protected-Action Non-Authority Gate | Explicit statement that research, review, plan, and checkpoint evidence do not create authority. | Any planning artifact is used as gateway, policy, signer, receipt, or hosted-operation proof. | + +Sidecar reports must be current-run reports. Prior `095940Z` and `174005` reports are patterns and historical evidence only; they do not satisfy this correction run. + +### Repo-Gate Command Matrix + +The correction closeout must record exact commands, timing, and observed output in `validation.md`. + +| Gate | Command | Required when | Evidence owner | +| --- | --- | --- | --- | +| Macro-plan structure | `python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan` | After final macro-plan edits. | `validation.md` | +| Claim boundary | `npm run quality:claims` | Any docs, claims, product language, README, or canonical text changes. | `validation.md` | +| Claim-boundary focused test | `npm run test -- test/architecture/claim-boundary.test.ts` | Any north-star/category/market/authority wording change. | `validation.md` | +| Architecture boundary | `npm run quality:architecture` | Any source, export, CLI, MCP, SDK, adapter, runtime, or surface posture change. | `validation.md` | +| TypeScript | `npm run check:types` | Any TypeScript source/test change. | `validation.md` | +| Runtime/generated-execution | `npm run test -- test/runtime/runtime-ingress.test.ts` | Any runtime, generated-agent, proposal, loop/retry, or stale-parameter claim. | `validation.md` | +| Product/example | `npm run test -- test/product/service-workflow-admission.test.ts` | Any service workflow/example/readback claim. | `validation.md` | +| x402 protected-action | `npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts` | Any x402/auth.md fixture, gateway, signer, payment material, or proof-gap claim. | `validation.md` | +| Demo output | `npm run demo:service-workflow-admission` and/or affected demo script | Any regenerated example packet. | `validation.md` plus generated artifact references | +| Formatting | `npm run format:check` | Any source/docs/test/example tracked change. | `validation.md` | +| Diff hygiene | `git diff --check` | Before every checkpoint. | `validation.md` | +| Full repo gate | `npm run check:repo` | Before closeout and before any final implementation claim. | `validation.md` | +| Git state | `git status --short --untracked-files=all` plus ignored `.planning/` check if planning artifacts are committed. | Before and after checkpoints. | `git-checkpoints.md` | + +`package.json` defines `check:repo` as build, typecheck, lint, formatting, tests, package checks, and `git diff --check`. Passing focused tests is not a substitute for the full gate. + +### What Must Be Committed And In What Checkpoints + +This sidecar does not commit. The final correction work must use explicit checkpoints: + +1. Planning/evidence checkpoint: current macro-plan artifacts, current run evidence files, and sidecar audits. Because `.planning/` is ignored by `.gitignore`, these files must be force-added deliberately if the user wants them committed. Do not let `git status` looking clean imply planning evidence is tracked. +2. Source/docs/tests checkpoint, if implementation changes exist: only the smallest source/docs/tests changes required by the correction, with focused test output recorded before commit. +3. Closeout checkpoint: `validation.md`, `code-review.md`, and `git-checkpoints.md` updated with final command output and reviewed state. If this is an evidence-only commit after `npm run check:repo`, it must record the exact source commit that the full repo gate tested. + +The checkpoint record must distinguish: + +- source commit tested by `npm run check:repo`; +- evidence-only commit containing run-local proof files; +- any untracked or ignored planning artifacts intentionally left out. + +### P0/P1 Risks And Stop Conditions + +| Severity | Risk | Stop condition | +| --- | --- | --- | +| P0 | Thin-plan laundering. | Current run lacks `research-evidence.md`, `validation.md`, `code-review.md`, or `git-checkpoints.md`. | +| P0 | Stale evidence inheritance. | Prior `095940Z` validation or tests are used as current-run closeout proof. | +| P0 | Review theatre. | `REVIEW-GATES.md` summarizes sidecars without chair disposition, artifact updates, blocker status, and residual proof gaps. | +| P0 | Repo-gate theatre. | Focused tests pass but `npm run check:repo` is absent, failed, or run before final source/docs/tests changes. | +| P0 | Git checkpoint gap. | `.planning/` evidence is ignored and no force-add/omission decision is recorded. | +| P0 | Protected-action overclaim. | Research, plan validation, demo output, or code review is treated as policy, gateway, signer, payment, receipt, hosted operation, or provider custody proof. | +| P1 | Research claim drift. | Current market/ecosystem claims lack dated sources and disconfirming evidence. | +| P1 | Structural validator overclaim. | Macro-plan validator output is recorded without saying it proves structure only. | +| P1 | Code review missing line-level findings. | Final review has summary language but no file/line references or explicit no-source-change statement. | +| P1 | TASKS drift. | `TASKS.jsonl` marks tasks complete before their evidence files and commands exist. | +| P1 | Command matrix drift. | `validation.md` names commands that no longer match `package.json` scripts. | + +## Failures + +- The requested current run directory did not exist before this audit report was created. +- The current top-level macro-plan package structurally validates, but it is tied to the older Tier 1/Tier 2 simplification package and prior `095940Z` evidence. That is not current-run proof for the architectural north-star correction. +- Existing `EVIDENCE-PLAN.md` and `TASKS.jsonl` describe completed work from the prior run. They cannot be reused as current correction closeout without a current source snapshot, current validation, and current review reconciliation. +- Existing `REVIEW-GATES.md` does not contain a current-run research gate, code review gate, full repo closeout gate, or git checkpoint gate. +- Existing `RISKS.md` does not explicitly track thin-plan laundering, stale research, old-run evidence inheritance, missing code review, missing full repo gate, or ignored `.planning/` checkpoint gaps. +- `.planning/` is ignored by `.gitignore` and `.prettierignore`. Normal `git status --short` can look clean while the entire evidence package is untracked and uncommitted. + +## Proof Gaps + +- No current-run `research-evidence.md` exists. +- No current-run `source-snapshot.md` exists. +- No current-run `validation.md` exists. +- No current-run `blocked-checks.md` exists. +- No current-run `code-review.md` exists. +- No current-run `git-checkpoints.md` exists. +- No current-run sidecar set, except this report, existed at the requested path before this audit. +- No current-run proof ties macro-plan status to current tests, current full repo gate, and current commit hashes. + +## Required Changes + +1. Create the missing current-run evidence files listed under Required Evidence Artifacts. +2. Update `EVIDENCE-PLAN.md` so the architectural north-star correction points to `20260525T110908Z-architectural-north-star` evidence, not only the older simplification run. +3. Update `REVIEW-GATES.md` with research, validation, code review, full repo, git checkpoint, and current sidecar reconciliation gates. +4. Update `RISKS.md` with P0/P1 risks for thin-plan laundering, stale evidence, research drift, review theatre, repo-gate theatre, code-review absence, and ignored `.planning/` artifacts. +5. Update `TASKS.jsonl` with current correction tasks. Required tasks must cover research evidence, source snapshot, macro-plan correction, validator run, sidecar reconciliation, focused tests, full repo gate, code review, and git checkpoints. Do not mark them complete until their evidence artifacts exist. +6. Record validation output after the final macro-plan edit, not before. +7. Run and record the full repo gate after final source/docs/tests changes if any implementation work happens. +8. Write a findings-first code review after the final diff. If the correction changes only planning artifacts, the review must say that explicitly and review the plan/evidence diff instead. +9. Record git checkpoints with commit hashes or explicitly state why no commit was made. If planning artifacts are expected in git, use a deliberate force-add decision because `.planning/` is ignored. + +## Status Recommendation + +Recommendation: `BLOCKED_FOR_EVIDENCE_AND_REVIEW_GATES` until the current run owns its research evidence, validation, sidecar reconciliation, tests, full repo gate, code review, and git checkpoint record. + +Do not promote the correction from older run evidence. Do not treat macro-plan validator success as semantic proof. Do not use a clean `git status` as proof that `.planning/` evidence is committed. + +Brutal verdict: without the required current-run evidence files and closeout gates, this becomes another thin plan with better headings. The smallest next mechanism is `source-snapshot.md` plus `research-evidence.md`; everything else should hang off that current-run boundary. + +## Commands Or Tools Used + +- Read macro-plan skill contract: + - `sed -n '1,240p' /Users/joelchan/.codex/skills/gsd-macro-plan/SKILL.md` + - `sed -n '1,220p' /Users/joelchan/.codex/skills/gsd-macro-plan/references/output-quality-bar.md` + - `sed -n '1,220p' /Users/joelchan/.codex/skills/gsd-macro-plan/references/macro-plan-contract.md` +- Discovered planning files: + - `rg --files .planning/macro-plan .planning/macro-map` + - `find .planning/macro-plan/runs/20260525T110908Z-architectural-north-star -maxdepth 3 -type f` +- Read required and adjacent sources with `sed`. +- Checked current validation: + - `python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan` +- Checked git state: + - `git status --short` + - `git status --short --untracked-files=all` + - `git check-ignore -v .planning/macro-plan/MACRO-PLAN.md .planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/evidence-review-gates-audit.md` +- Checked ignore posture: + - `rg -n "(^|/)\\.planning|planning" .gitignore .prettierignore .eslintignore` +- Memory quick pass: + - `rg -n "architectural north-star|macro-plan|x402|review gates|evidence" /Users/joelchan/.codex/memories/MEMORY.md` + - `nl -ba /Users/joelchan/.codex/memories/MEMORY.md | sed -n '84,124p'` +- Wrote this report only: + - `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/evidence-review-gates-audit.md` diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/product-vocabulary-projection-audit.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/product-vocabulary-projection-audit.md new file mode 100644 index 0000000..f9c8c84 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/product-vocabulary-projection-audit.md @@ -0,0 +1,198 @@ +## Audit Scope + +Assigned focus: product-vocabulary-projection-audit for the current Handshake gsd-macro-plan correction. + +This audit covers product vocabulary around `product surface`, `protocol kernel`, service workflow, `Passport`, `ServiceWorkflowAdmission`, `ServiceWorkflowHandle`, `Handle`, `Outcome`, `AuthorityCertificate`, `Certificate`, `Badge`, `Clearance`, product lane, and protocol lane. + +This report is a sidecar audit only. It does not select the macro move, synthesize the final plan, promote final status, or convert protected-action proof gaps into authority. + +## Source Boundary + +Canonical source boundary: + +- `README.md` +- `STRUCTURE.md` +- `QUALITY.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/protocol-layman.md` +- `docs/internal/protocol-definition.md` +- `docs/internal/protocol-kernel-architecture.md` +- `docs/internal/service-workflow-story.md` +- `src/protocol/LANE.md` +- `src/surfaces/LANE.md` +- `src/surfaces/boundary-manifest.ts` +- `src/surfaces/outcome.ts` +- `src/surfaces/service-workflow-admission/index.ts` +- `src/cli/LANE.md` +- `src/cli/command-manifest.ts` +- `src/cli/output.ts` +- `src/mcp/LANE.md` +- `src/mcp/catalog.ts` +- `src/mcp/output.ts` +- `src/sdk/LANE.md` +- architecture and product tests listed below. + +Derived planning source boundary: + +- `.planning/macro-plan/MACRO-PLAN.md` +- `.planning/macro-plan/DECISIONS.md` +- `.planning/macro-plan/EXECUTION-SLICES.md` +- `.planning/macro-plan/PROTECTED-ACTION-GATES.md` + +`.planning/` remains scratch. It can reveal current correction intent, but it is not repo-facing source truth. + +## Files Read + +- `README.md` +- `STRUCTURE.md` +- `QUALITY.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/protocol-layman.md` +- `docs/internal/protocol-definition.md` +- `docs/internal/protocol-kernel-architecture.md` +- `docs/internal/service-workflow-story.md` +- `src/protocol/LANE.md` +- `src/surfaces/LANE.md` +- `src/surfaces/boundary-manifest.ts` +- `src/surfaces/outcome.ts` +- `src/surfaces/service-workflow-admission/index.ts` +- `src/cli/LANE.md` +- `src/cli/command-manifest.ts` +- `src/cli/output.ts` +- `src/mcp/LANE.md` +- `src/mcp/catalog.ts` +- `src/mcp/output.ts` +- `src/sdk/LANE.md` +- `examples/service-workflow-admission/run.ts` +- `test/architecture/claim-boundary.test.ts` +- `test/architecture/self-hosted-activation-claim-boundary.test.ts` +- `test/architecture/workflow-admission-boundary.test.ts` +- `test/architecture/active-vocabulary.test.ts` +- `test/architecture/naming-posture.test.ts` +- `test/architecture/surface-boundary-posture.test.ts` +- `test/architecture/cli-command-posture.test.ts` +- `test/architecture/mcp-surface-posture.test.ts` +- `test/architecture/root-exports.test.ts` +- `test/product/service-workflow-admission.test.ts` +- `.planning/macro-plan/MACRO-PLAN.md` +- `.planning/macro-plan/DECISIONS.md` +- `.planning/macro-plan/EXECUTION-SLICES.md` +- `.planning/macro-plan/PROTECTED-ACTION-GATES.md` + +## Invariant At Stake + +Product nouns must be projections, readbacks, or correlation context only. They must not become a second protocol truth, reusable authority, credential posture, policy result, gateway pass, signer permission, receipt export, terminal certificate, retry grant, or widened operating envelope. + +Current vocabulary inventory: + +| Vocabulary | Current safe meaning | Boundary | +| --- | --- | --- | +| `protocol kernel` | Source-owned state machine and schema set for exact contracts, policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, isolation, and terminal certificates. | Canonical behavior source only. | +| `product surface` | Canon says CLI/MCP/SDK/docs/demo/service-facing readback exposing proposal/evidence/readback without creating authority. | Currently ambiguous because some SDK role clients are transition clients. | +| `src/surfaces` / product lane | Source-owned boundary manifests and non-authority outcomes for non-kernel product surfaces. | Must not evaluate policy, issue greenlights, perform gateway checks, mutate, mint certificates, export receipts, certify trust, host operation, or read raw records. | +| `src/protocol` / protocol lane | Protocol authority semantics and transition invariants. | Must not own product surface metaphors or service workflow projections. | +| `Passport` | Presented evidence package. | Not identity, trust, spend approval, signer access, permission, or reusable auth. | +| `ServiceWorkflowAdmission` / Admission | Service-side accepted/refused/stale/proof-gap mapping of presented evidence. | Not policy, greenlight, gateway check, receipt, certificate, or mutation permission. | +| `ServiceWorkflowHandle` / Handle | Correlation and readback context for later proposals. | Not badge, bearer token, tool permission, retry permission, x402 payment approval, auth.md credential, or gateway pass. | +| `Clearance` | Shorthand for one fresh protected-action chain. | Must not become a workflow-level permission or standalone artifact. | +| `Outcome` | Readback over receipt, refusal, replay refusal, proof gap, or terminal certificate after the event path. | Not downstream success or future permission. | +| `AuthorityCertificate` / Certificate | Terminal evidence after receipt/refusal/proof-gap/replay-refusal. | Not permission, identity, settlement, hosted trust, cross-org trust, or reusable auth. | +| `Badge` | Optional narrative anti-pattern/shorthand only. | Should not become schema, API, route, export, protocol object, or bearer-token metaphor. | + +## Pass Conditions + +- The phrase `product surface` cannot imply both non-authority readback and authority-bearing protocol transition clients. +- Product nouns are allowed only in docs/story, `src/surfaces/service-workflow-admission`, local readback/demo output, CLI/MCP/SDK explanatory lane text, and explicit negative tests. +- `Passport`, Admission, Handle, Badge, Clearance, Outcome, and Certificate cannot satisfy `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheck`, signer, credential, mutation, receipt, certificate mint, or operating-envelope requirements. +- `Badge` remains absent from source/API/export/route vocabulary except negative language. +- `Clearance` is always expanded to the exact protected-action chain before any authority claim. +- `Outcome` is always readback over terminal evidence and must distinguish gateway evidence from downstream business success. +- Architecture tests scan authority-bearing lanes, not only protocol areas and adapter/runtime roots. + +## Failures + +Confusing/unsafe language with file references: + +1. P0: `product surface` is overloaded. Canon says product surfaces are non-authority readbacks (`README.md:15-18`, `STRUCTURE.md:9-12`, `docs/internal/decisions.md:42-48`, `docs/internal/protocol-notes.md:13-22`), but `src/surfaces/boundary-manifest.ts:66-72` includes `policy_authority`, and `sdk.policy` may write policy decisions (`src/surfaces/boundary-manifest.ts:296-365`). `README.md:94-100` also teaches `PolicyClient.evaluatePolicy()` as a role-scoped client. That creates dual truth: "SDK product surface" can mean readback-only or policy-authority transport. + +2. P1: `Clearance` is too artifact-shaped unless always expanded. `README.md:22-37`, `docs/internal/service-workflow-story.md:10-25`, and `docs/internal/protocol-layman.md:37-55` are mostly safe, but the demo invariant says "fresh protected-action clearance carries authority" (`examples/service-workflow-admission/run.ts:91-97`). That phrasing can make `Clearance` sound like a reusable grant rather than shorthand for exact contract -> policy -> one-use greenlight/refusal -> gateway check. + +3. P1: `Badge` is still present as a narrative noun without an architecture guard that bans it from schema/API/export/route names. Current source use is bounded negative language (`docs/internal/service-workflow-story.md:23`, `docs/internal/service-workflow-story.md:94`, `docs/internal/protocol-layman.md:53-55`, `src/mcp/LANE.md:86-88`), but no current test scans for `Badge` as a future source/export/route noun. + +4. P1: Workflow-admission tests are strong at object shape but too narrow on placement. `test/architecture/workflow-admission-boundary.test.ts:17-35` scans exact service-workflow names out of `src/protocol/areas`, `src/adapters`, `src/runtime/ingress`, and `src/mcp`, but it does not scan `src/sdk/surface-clients/policy-client.ts`, `src/sdk/surface-clients/gateway-client.ts`, `src/http/routes`, `src/http/handlers`, `src/http/admission`, `src/protocol/public`, root exports, CLI commands, or package metadata for standalone `Passport`, `Admission`, `Badge`, `Handle`, `Clearance`, or `Outcome` drift. + +5. P1: `Outcome` is split across product story and reusable surface schema without an explicit vocabulary guard. `docs/internal/service-workflow-story.md:24-25` correctly defines Outcome as terminal readback, and `src/surfaces/outcome.ts:59-86` enforces non-authority flags. But there is no dedicated guard that product `Outcome` cannot be used as downstream success, retry permission, or a second terminal record apart from `Receipt`/`Refusal`/`ProofGap`/`AuthorityCertificate`. + +6. P1: `Certificate` is generally well bounded, but product copy must keep saying terminal evidence. The current claim-boundary test covers "certificate is terminal evidence, not permission" (`test/architecture/claim-boundary.test.ts:128-147`), and protocol notes are strict (`docs/internal/protocol-notes.md:388-416`). The residual risk is UX/product copy turning Certificate into Passport/Badge shorthand, explicitly forbidden in `docs/internal/service-workflow-story.md:94`. + +## Proof Gaps + +- No user-comprehension evidence proves that `Passport`, `Handle`, `Clearance`, or `Certificate` will not be interpreted as identity, permission, or reusable auth. +- No current guard proves `Badge` cannot enter future route names, exported symbols, package surfaces, or public examples. +- No current guard proves product projection nouns are excluded from authority-bearing SDK clients, HTTP transition routes, gateway clients, policy clients, or protocol public exports. +- No test currently enforces a taxonomy split between non-authority product projection/readback surfaces and role-scoped protocol transition clients. +- No tests were run in this audit; product demo tests can write generated outputs, so I inspected them read-only instead. + +## Required Changes + +Recommended canonical wording: + +- Replace broad `product surface` with two terms: + - `product projection surface`: CLI, MCP, SDK evidence/readback, docs, demos, and service-facing readbacks that expose proposal/evidence/readback without creating authority. + - `role-scoped protocol transition client`: SDK/HTTP client surface that transports a specific protocol transition under a custody role. It may call policy or gateway routes only when the protocol kernel/gateway path owns the authority. +- Keep `protocol kernel` as: "the source-owned state machine and schema set for exact contracts, policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, isolation, and terminal certificates." +- Define service workflow as: "`Passport -> ServiceWorkflowAdmission -> ServiceWorkflowHandle -> request one fresh protected-action clearance -> read terminal outcome` is a projection/readback story, not a protocol state path." +- Define `Passport`: "presented evidence package only; not identity, trust, approval, signer access, spend approval, permission, or reusable auth." +- Define `ServiceWorkflowAdmission`: "service-side evidence mapping only; not policy, greenlight, gateway check, receipt, certificate, or mutation permission." +- Define `ServiceWorkflowHandle`: "correlation/readback context only; not bearer token, badge, retry permission, payment approval, credential posture, gateway pass, or operating-envelope expansion." +- Define `Clearance`: "shorthand for one fresh `ActionContract -> PolicyDecision -> one-use Greenlight/Refusal -> GatewayCheck` path; not a record, token, reusable grant, workflow permission, or product object." +- Define `Outcome`: "readback over `Receipt`, `Refusal`, `ReplayRefusal`, `ProofGap`, or terminal `AuthorityCertificate`; not downstream business success or future permission." +- Define `AuthorityCertificate`: "terminal evidence only; never Passport, Badge, identity, settlement, hosted trust, cross-org trust, permission, or reusable auth." +- Define `Badge`: "do not use as an API/schema/route/export noun; if it remains in narrative copy, it must appear only as a forbidden interpretation of `ServiceWorkflowHandle`." + +Tests/guards to add or change: + +- Add a product-vocabulary projection guard under `test/architecture`, scanning repo-facing files for standalone `Passport`, `Admission`, `Badge`, `Handle`, `Clearance`, `Outcome`, and `Certificate` usage. Allow only approved files and require nearby negative boundary language. +- Extend `workflow-admission-boundary.test.ts` authority roots to include `src/sdk/surface-clients/policy-client.ts`, `src/sdk/surface-clients/gateway-client.ts`, `src/http/routes`, `src/http/handlers`, `src/http/admission`, `src/protocol/public`, `src/index.ts`, `src/experimental.ts`, `package.json`, and `server.json`. +- Add a guard that `Badge` cannot appear in TypeScript source except generated-negative-test strings, and cannot appear in exported symbols, command IDs, route names, schemas, package subpaths, or MCP tool/resource names. +- Add a guard that every use of `Clearance` in docs/examples is adjacent to `ActionContract`, `PolicyDecision`, `Greenlight`, and `GatewayCheck`, or else uses "request clearance" as a non-artifact action phrase. +- Add a guard that product `Outcome` cannot be paired with `downstreamSuccess`, `retry permission`, `future permission`, `business success`, or a new protocol object outside existing receipt/refusal/proof-gap/certificate objects. +- Update claim-boundary tests to require the new taxonomy: `product projection surface` is non-authority; `role-scoped protocol transition client` is a transport over protocol authority, not a product noun projection. +- Add root-export tests that `ServiceWorkflowAdmission`/`ServiceWorkflowHandle` stay off package root unless deliberately exposed through a projection-only subpath with explicit non-authority flags. If root export is intentional, the test must assert no policy/gateway/receipt/certificate/export material accompanies it. + +P0/P1 risks and stop conditions: + +- P0 stop: any plan or source change that says a product surface creates authority without naming the protocol transition and gateway boundary. +- P0 stop: `Passport`, Admission, Handle, Badge, Clearance, Outcome, or Certificate is accepted as sufficient input for policy, gateway, signer, mutation, receipt export, certificate mint, or operating-envelope expansion. +- P0 stop: role-scoped SDK policy/gateway authority is described as ordinary product surface authority rather than protocol transition transport. +- P1 stop: `Badge` appears in API/schema/export/route/package names. +- P1 stop: `Clearance` is used as a token/record/grant noun rather than a shorthand for the exact protected-action chain. +- P1 stop: readback copy collapses gateway check evidence and downstream business success. +- P1 stop: tests guard prose only while source exports or route names can still imply authority. + +Brutal verdict: + +Keep the service-workflow projection model. Cut the ambiguous umbrella use of `product surface`. Redesign the vocabulary taxonomy so product nouns are projections/readbacks only, while authority-bearing SDK/HTTP operations are called role-scoped protocol transition clients. Without that split, the repo can truthfully say "product surfaces create no authority" while also shipping `sdk.policy` as policy authority. That is a vocabulary bug with authority consequences. + +## Status Recommendation + +Recommend `NEEDS_REQUIRED_CHANGES` for product-vocabulary correction. + +Do not promote this macro-plan correction to final-ready until the taxonomy split and vocabulary guards are added. The source implementation is mostly disciplined, but the current wording still permits dual product/protocol truth at the SDK surface boundary. + +## Commands Or Tools Used + +- Read skills: `handshake-grounding`, `gsd-macro-plan`. +- `pwd` +- `git status --short --branch` +- `rg --files ...` +- `wc -l ...` +- `rg -n ...` +- `nl -ba ...` +- `find .planning/macro-plan/runs/20260525T110908Z-architectural-north-star ...` +- `ls -la .planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits` +- `apply_patch` to write this report only. + +No tests were executed. I preserved the read-only constraint except for this audit report. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/protected-action-lifecycle-audit.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/protected-action-lifecycle-audit.md new file mode 100644 index 0000000..16fe306 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/protected-action-lifecycle-audit.md @@ -0,0 +1,290 @@ +## Audit Scope + +Sidecar 3/5 audited the protected-action lifecycle focus for run `20260525T110908Z-architectural-north-star`. + +Question audited: whether the repo has a single protected-action event lifecycle/table that product projections can derive from, and how `Passport`, `Admission`, `Handle`, `Clearance`, `Outcome`, and `Certificate` can be defined as projections without becoming protocol primitives. + +This report is read-only analysis except for writing this file. It does not select a macro move, synthesize the final plan, promote final status, or edit source/docs/tests. + +## Source Boundary + +Canonical source boundary used: + +- Current checkout at `/Users/joelchan/Documents/Coding/App-Dev/live/Handshake v0.0.2`. +- `git status --short --branch` reported `## main...origin/main [ahead 8]`; no dirty tracked files were present before this audit file was written. +- `.planning/` is treated as scratch/derived planning output. The run directory did not exist before this report directory was created. +- Tracked source and docs are the evidence boundary; prior memory was used only as context to preserve Handshake/GSD constraints. + +## Files Read + +Required files read: + +- `src/protocol/navigation/index.ts` +- `src/protocol/areas/action-attempt-lifecycle/index.ts` +- `src/protocol/areas/action-attempt-lifecycle/types.ts` +- `src/protocol/areas/action-attempt-lifecycle/schemas.ts` +- `src/protocol/areas/action-attempt-lifecycle/matrix.ts` +- `src/protocol/public/transitions.ts` +- `docs/internal/protocol-definition.md` +- `docs/internal/protocol-kernel-architecture.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/service-workflow-story.md` +- `test/protocol/action-attempt-lifecycle.test.ts` +- `test/protocol/protocol-navigation.test.ts` + +Additional files read for projection and terminal-evidence boundary: + +- `docs/internal/decisions.md` +- `src/surfaces/service-workflow-admission/index.ts` +- `src/surfaces/outcome.ts` +- `src/surfaces/index.ts` +- `src/index.ts` +- `package.json` +- `test/product/service-workflow-admission.test.ts` +- `test/architecture/workflow-admission-boundary.test.ts` +- `test/architecture/root-exports.test.ts` +- `src/protocol/areas/operation-lifecycle/schemas.ts` +- `src/protocol/areas/operation-lifecycle/lifecycle.ts` +- `src/protocol/areas/operation-lifecycle/transitions.ts` +- `test/protocol/operation-lifecycle.test.ts` +- `src/protocol/events/chains.ts` +- `src/protocol/areas/receipt-export/schemas.ts` +- `src/protocol/areas/receipt-export/status.ts` +- `src/protocol/evidence-projections/schemas.ts` +- `src/protocol/evidence-projections/projections.ts` +- `src/protocol/areas/protected-action-representation/schemas.ts` +- `src/protocol/areas/protected-action-representation/projections.ts` +- `test/protocol/representation-contract.test.ts` +- `src/protocol/areas/authority-certificate/schemas.ts` +- `src/protocol/areas/authority-certificate/transitions.ts` + +## Invariant At Stake + +Product-facing nouns must derive from the source-owned protected-action lifecycle. They must not become parallel authority primitives. + +If `Passport`, `Admission`, `Handle`, `Clearance`, `Outcome`, or `Certificate` can be interpreted without the exact lifecycle path, product language can accidentally mint authority outside `ActionContract -> PolicyDecision -> one-use Greenlight -> GatewayCheck -> Receipt/Refusal/ProofGap`. + +## Pass Conditions + +- There is one source-owned transition/lifecycle spine for protected-action attempts. +- Product projection nouns point into that spine or into explicitly non-authority surface schemas. +- `Passport`, `Admission`, and `Handle` are evidence/readback/correlation only. +- `Clearance` means a fresh exact action path, not workflow permission. +- `Outcome` means terminal readback over receipt/refusal/replay/proof-gap/certificate evidence, not downstream business success. +- `Certificate` remains terminal evidence over existing terminal records, not identity, admission, permission, reusable auth, settlement, or hosted trust. +- Tests fail if a product projection term appears in authority-bearing protocol roots or if projection mapping drifts from lifecycle keys. + +## Existing Lifecycle Spine And Evidence + +The repo has a real source-owned lifecycle spine for protected-action attempts. + +1. `src/protocol/navigation/index.ts` owns the transition inventory. Each entry declares `transitionId`, `kernelMethod`, `phase`, `outcomeClasses`, `recordsWritten`, `eventsEmitted`, `authorityBoundary`, and `evidenceObligation` (`ProtocolNavigationEntry`, lines 96-105). The table covers catalog/setup, runtime evidence, compilation, contract, policy, review, gateway, operation lifecycle, isolation, receipt export, recovery, and authority certificate transitions (lines 107-431). + +2. `src/protocol/areas/action-attempt-lifecycle/schemas.ts` owns the derived lifecycle vocabulary: phase, state, authority effect, terminal outcome, and evidence obligation. The important boundary types are explicit: `authorityEffect` distinguishes `none`, `evidence_only`, `proposed_commitment`, `one_use_authority`, `gateway_admission`, `downstream_evidence`, and `future_authority_reduction` (lines 64-72). `terminalOutcome` distinguishes `open`, `contract`, `refusal`, `proof_gap`, `terminal_unknown`, `evidence_only`, `recovery`, `isolation`, `receipt`, `projection`, and `closed` (lines 75-87). + +3. `src/protocol/areas/action-attempt-lifecycle/matrix.ts` maps `ProtocolTransitionId:TransitionOutcomeClass` to lifecycle entries. It is derived over `protocolNavigation`, not a stored protocol object. The exact lookup and enumeration functions are source-owned (`actionAttemptLifecycleEntry`, `actionAttemptLifecycleEntries`, lines 606-622). The matrix correctly marks contract proposal as proposed commitment, policy greenlight as one-use authority, gateway check as gateway admission, receipt export/certificate export as projection, and recovery/isolation as non-mutating authority reduction/evidence (notably lines 333-377, 443-550). + +4. `test/protocol/action-attempt-lifecycle.test.ts` proves lifecycle coverage over every protocol navigation outcome exactly once (lines 13-22), proves the lifecycle is derived from evidence-chain transitions and not stored instances (lines 24-50), maps hostile generated-agent paths to refusal or proof-gap outcomes (lines 52-117), and keeps projections/recovery non-authoritative (lines 119-131). + +5. `test/protocol/protocol-navigation.test.ts` proves HTTP transition navigation derives from protocol transitions and route metadata (lines 10-65), keeps generated graph coverage and certificate minting kernel-only evidence (lines 67-79), validates declared protocol objects/events (lines 81-94), and keeps evidence reads diagnostic/read-only (lines 96-112). + +6. `src/protocol/public/transitions.ts` is a public guard narrative over the same state shape. It states compilation cannot mint authority, gateway check proceeds only from greenlight, receipt export packages existing evidence only, and recovery cannot reuse a greenlight or mutate gateway state (lines 22-115). This is useful documentation, but the stronger table is `protocolNavigation` plus `ActionAttemptLifecycle`. + +7. Downstream finality is separately source-owned in `src/protocol/areas/operation-lifecycle/lifecycle.ts`. `OPERATION_LIFECYCLE_MATRIX` maps `pending/succeeded/refused/failed/unknown` to reconciliation status, finality status, claim state, receipt downstream status, proof-gap reason, claim blocking, and isolation behavior (lines 18-78). `test/protocol/operation-lifecycle.test.ts` proves all downstream observation branches (lines 4-56). + +8. Reconstruction evidence has a source spine. `src/protocol/events/chains.ts` binds action lifecycle events by action contract, run, gateway, and resource (`actionLifecycleStreamRefs`, lines 58-67), and stream partitioning uses `action:` when available (lines 126-140). + +9. Docs reflect the lifecycle rule. `docs/internal/protocol-definition.md` defines the canonical path and primitive (lines 15-28, 88-104, 262-270). `docs/internal/protocol-kernel-architecture.md` states the gateway is the enforcement point and the store is reconstruction truth (lines 31-33), then gives the authority sequence diagram (lines 342-381). `docs/internal/protocol-notes.md` preserves compact product/protocol language and exact naming rules (lines 13-40, 452-456). + +## Missing Projection Mapping + +The source spine exists. The missing piece is a source-owned product projection mapping from service workflow words to lifecycle entries. + +Current partial coverage: + +- `docs/internal/service-workflow-story.md` defines the plain flow and correctly warns that `Passport`, `ServiceWorkflowAdmission`, `ServiceWorkflowHandle`, `Clearance`, and `Outcome` are not permission or downstream success (lines 7-25, 55-73, 88-98). +- `src/surfaces/service-workflow-admission/index.ts` source-owns `ServiceWorkflowAdmission` and `ServiceWorkflowHandle` as non-authority schemas. The boundary fields are hard literals: no authority, no policy decision, no greenlight, no gateway check, no mutation, no receipt export, no terminal certificate, no credential/payment material, no reusable auth, and fresh action contract required (lines 21-35, 39-53, 76-111). +- `test/architecture/workflow-admission-boundary.test.ts` rejects attempts to turn admission/handle into authority and keeps workflow nouns out of authority-bearing roots (`src/protocol/areas`, `src/adapters`, `src/runtime/ingress`, `src/mcp`) (lines 37-92). +- `test/product/service-workflow-admission.test.ts` proves the demo keeps admission/readback separate from fresh x402 clearance and excludes payment/auth authority material (lines 13-99, 101-228, 230-322). + +Gaps: + +1. There is no single source-owned `ServiceWorkflowProjectionMap` or equivalent table that maps `Passport`, `Admission`, `Handle`, `Clearance`, `Outcome`, and `Certificate` to `ActionAttemptLifecycle` keys, protocol object refs, and explicit non-authority flags. + +2. `Passport` is not source-owned as a projection schema. It appears as `passportPackageDigest` and `passportPresentationId` fields in admission/handle schemas, but there is no `PassportProjection` type that states it is a presented evidence package only, never identity/trust/permission/spend/signer access/reusable auth. + +3. `Admission` and `Handle` are source-owned as schemas, but not source-owned as lifecycle projections. They correctly avoid protocol authority roots, but no mapping ties them to pre-contract evidence/readback posture and says they cannot satisfy `compileIntent`, `proposeActionContract`, `evaluatePolicy`, or `gatewayCheck`. + +4. `Clearance` is prose only. The docs define it as a fresh exact protected-action path, but there is no source-owned projection that says clearance is a composite over existing lifecycle keys such as `proposeActionContract:recorded`, `evaluatePolicy:greenlight|refusal|review_required|proof_gap`, and `gatewayCheck:recorded|replay_refusal|proof_gap|conflict`. Without that table, the word can drift into workflow-level permission. + +5. `Outcome` is overloaded. `src/surfaces/outcome.ts` is a non-authority surface outcome helper for proposal/readiness/error shapes and explicitly prevents authority creation (lines 5-17, 59-86, 88-160), but it is not the terminal service-workflow Outcome described in `service-workflow-story.md` as receipt/refusal/replay/proof-gap/certificate. Terminal outcome derivation currently lives across `Receipt`, `ReceiptTimelineProjection`, `AgentTransactionEnvelopeProjection`, `OperationLifecycle`, `Refusal`, `ProofGap`, and `AuthorityCertificate` rather than a product-facing projection table. + +6. `Certificate` is source-owned as `AuthorityCertificate`, but not mapped into the service workflow vocabulary as a projection. `src/protocol/areas/authority-certificate/transitions.ts` only mints after receipt/refusal/proof-gap/replay terminal records (lines 149-176), and its schema binds terminal kind, artifacts, signatures, and verification policy (schemas lines 16-22, 24-40, 75-107). The product mapping should say `Certificate` means "optional terminal evidence projection over an Outcome", not "Passport", "Admission", or "Clearance". + +7. The current tests prevent misuse of admission/handle, but no test proves the entire product projection vocabulary is source-derived from `ActionAttemptLifecycle` and does not add protocol primitives. + +## Failures + +- Product projection mapping is not yet source-owned. The lifecycle table is source-owned; the product words are split across prose, admission schemas, demo outputs, and representation/outcome helpers. +- `Outcome` is not a single product projection over terminal event evidence. It is partly prose and partly unrelated non-authority surface outcome helper. +- `Clearance` has no source-owned projection contract. That is the most dangerous gap because it is the word closest to authority. +- `Passport` lacks a first-class projection schema. Digest fields exist, but the non-authority semantics are not pinned by a dedicated source map. + +## Proof Gaps + +- No current test asserts that `Passport`, `Admission`, `Handle`, `Clearance`, `Outcome`, and `Certificate` all resolve through one source-owned projection map. +- No current test asserts that `Clearance` maps only to a fresh exact contract/policy/gateway lifecycle chain and never to a reusable workflow handle. +- No current test asserts that terminal `Outcome` maps to receipt/refusal/replay/proof-gap/certificate evidence and not downstream business success. +- No current source constant links service workflow prose to `actionAttemptLifecycleEntry()` keys. +- No current docs pointer names the source file that owns the product projection map, because that file does not exist. + +## Required Changes + +1. Add one source-owned projection map under `src/surfaces`, not under `src/protocol/areas`. + + Suggested shape: + + ```ts + export const serviceWorkflowLifecycleProjectionMap = { + Passport: { + projectionKind: "passport", + protocolPrimitive: false, + createsAuthority: false, + lifecycleKeys: [], + sourceObjects: ["participant_identity_binding", "evidence_projection", "protected_path_health"], + boundary: "presented evidence package only", + }, + Admission: { + projectionKind: "service_workflow_admission", + protocolPrimitive: false, + createsAuthority: false, + lifecycleKeys: [], + sourceObjects: ["ServiceWorkflowAdmission"], + boundary: "service-side evidence/readback evaluation only", + }, + Handle: { + projectionKind: "service_workflow_handle", + protocolPrimitive: false, + createsAuthority: false, + lifecycleKeys: [], + sourceObjects: ["ServiceWorkflowHandle"], + boundary: "correlation and readback context only", + }, + Clearance: { + projectionKind: "clearance", + protocolPrimitive: false, + createsAuthority: "derived_from_policy_greenlight_only", + lifecycleKeys: [ + "proposeActionContract:recorded", + "evaluatePolicy:greenlight", + "gatewayCheck:recorded", + ], + refusalOrGapKeys: [ + "evaluatePolicy:refusal", + "evaluatePolicy:review_required", + "evaluatePolicy:proof_gap", + "gatewayCheck:replay_refusal", + "gatewayCheck:proof_gap", + "gatewayCheck:conflict", + ], + boundary: "fresh exact protected-action path for one event", + }, + Outcome: { + projectionKind: "outcome", + protocolPrimitive: false, + createsAuthority: false, + lifecycleKeys: [ + "gatewayCheck:recorded", + "gatewayCheck:replay_refusal", + "gatewayCheck:proof_gap", + "reconcileSurfaceOperation:recorded", + "reconcileSurfaceOperation:proof_gap", + ], + sourceObjects: ["receipt", "refusal", "proof_gap", "surface_operation_reconciliation"], + boundary: "terminal readback, not downstream business success or retry permission", + }, + Certificate: { + projectionKind: "certificate", + protocolPrimitive: false, + createsAuthority: false, + lifecycleKeys: ["createAuthorityCertificate:exported"], + sourceObjects: ["authority_certificate"], + boundary: "optional terminal evidence over one existing terminal event", + }, + } as const; + ``` + + The exact implementation should use existing `ActionAttemptLifecycleKey`/`actionAttemptLifecycleEntry()` so invalid lifecycle keys fail in tests. + +2. Keep the map in `src/surfaces` or a similarly explicit product-surface lane. Do not add `Passport`, `Admission`, `Handle`, `Clearance`, or `Outcome` to `src/protocol/areas` as protocol objects. + +3. Add schemas if needed for `PassportProjection`, `ClearanceProjection`, `TerminalOutcomeProjection`, and `CertificateProjection`, but make them projections over existing refs. All should carry the same kind of hard non-authority booleans used by `ServiceWorkflowAuthorityBoundarySchema`. + +4. Update docs to name the source-owned projection map: + + - `docs/internal/service-workflow-story.md`: replace prose-only mapping with "plain words derive from `serviceWorkflowLifecycleProjectionMap`". + - `docs/internal/protocol-notes.md`: keep naming rules and add that service workflow terms live under `src/surfaces` as projections. + - `docs/internal/protocol-definition.md`: keep protocol primitive names exact; mention product lifecycle projections are non-authority projections over the canonical state path. + +5. Add tests: + + - `test/architecture/service-workflow-lifecycle-projection.test.ts`: every product term maps to existing lifecycle keys or explicitly has no lifecycle key because it is pre-contract evidence; all entries set `protocolPrimitive: false`. + - Test `Clearance` includes `proposeActionContract`, `evaluatePolicy`, and `gatewayCheck` lifecycle keys, and refuses/review/proof-gap/replay branches are represented. + - Test `Outcome` includes terminal evidence refs and does not equate receipt to downstream business success. + - Test `Certificate` maps only to `createAuthorityCertificate:exported` and `authority_certificate` terminal evidence. + - Extend the existing workflow-admission boundary test so product terms remain absent from authority-bearing protocol roots. + +## Recommended Source/Docs/Test Changes + +Source: + +- Add `src/surfaces/service-workflow-lifecycle-projections.ts`. +- Export it from `src/surfaces/index.ts`; do not export it from the root unless product surface export policy explicitly allows it. +- Reuse `ServiceWorkflowAuthorityBoundarySchema` or factor a shared non-authority boundary schema for projection entries. + +Docs: + +- Make `docs/internal/service-workflow-story.md` a projection explanation over the source map, not a standalone vocabulary authority. +- Keep `docs/internal/protocol-definition.md` strict: the protocol object list must not gain Passport/Admission/Handle/Clearance/Outcome. +- Add one compact note in `docs/internal/protocol-notes.md` that product workflow terms are non-authority projections under `src/surfaces`. + +Tests: + +- Add projection-map coverage tests. +- Add a docs/source consistency test only if the repo already tolerates this style; otherwise keep the source map as the single tested authority and let docs point to it. +- Do not broaden tests into hosted trust, provider custody, live revocation, settlement, or marketplace claims. + +## Risks If Product Projection Mapping Is Not Source-Owned + +- `Clearance` becomes ambient authority wearing a badge: a workflow handle could be read as permission instead of correlation. +- `Passport` can swallow the product: identity/admission evidence starts posing as spend approval, signer access, or reusable auth. +- `Outcome` becomes evidence theatre: receipt, downstream finality, proof gap, and certificate get blurred into one success word. +- `Certificate` can be misused as a passport or badge if the product story does not derive it from terminal evidence only. +- Docs can drift faster than source. The current prose is good, but prose is not a mechanism. +- A future macro plan could create tasks around product names without touching the actual gateway-enforced lifecycle. + +## Status Recommendation + +Focus recommendation only: `NEEDS_REQUIRED_CHANGES` for the product projection mapping gate. + +The protocol lifecycle spine itself is present and source-owned. The product projection vocabulary is not yet source-owned as one derivation table. Do not promote any macro-plan status that depends on Passport/Admission/Handle/Clearance/Outcome/Certificate being a mechanically enforced projection layer until that source map and tests exist. + +## Brutal Verdict + +Keep the existing lifecycle spine. It is the right primitive. + +Cut any impulse to add Passport, Admission, Handle, Clearance, or Outcome as protocol primitives. That would create a second authority model. + +Narrow the product story into one source-owned projection table under `src/surfaces`. `Clearance` must be the fresh exact lifecycle chain. `Outcome` must be terminal readback. `Certificate` must be optional terminal evidence. `Passport`, `Admission`, and `Handle` must stay pre-contract evidence/correlation. + +Smallest next mechanism: add `serviceWorkflowLifecycleProjectionMap` under `src/surfaces` and test it against `ActionAttemptLifecycle`. + +## Commands Or Tools Used + +- Read skill guidance: `handshake-grounding`, `gsd-macro-plan`. +- Memory quick pass: searched `MEMORY.md` for Handshake macro-plan/protected-action context. +- Repo grounding: `pwd`, `git status --short --branch`. +- File discovery: `rg --files`, `find`. +- Source/doc/test reads: `awk` and `rg`. +- Report write: `mkdir -p` for the audit directory, then `apply_patch` to add this file. +- Tests were not run; this was a read-only audit of source/docs/tests, not a verification pass. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/runtime-protected-action-gates-audit.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/runtime-protected-action-gates-audit.md new file mode 100644 index 0000000..3e9a29f --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits/runtime-protected-action-gates-audit.md @@ -0,0 +1,244 @@ +# Runtime And Protected-Action Gates Audit + +## Audit Scope + +Sidecar 4/5 audit for runtime and protected-action gates in the +projection-over-spine macro-plan correction. + +Assigned focus only: generated-code misuse, loops/retries/branches, dynamic +tools, stale handles/review, raw sibling bypass, x402/auth.md composite +confusion, hosted/Tier 3 pressure, and gateway/signer/payment material +boundaries. + +This audit does not select the macro move, synthesize the final plan, promote a +final status, or authorize protected-action behavior. + +## Source Boundary + +Canonical boundary: + +- `AGENTS.md` doctrine supplied in the prompt. +- `docs/internal/decisions.md` for product/kernel/source truth. +- Source lane boundaries in `src/mcp/LANE.md`, `src/runtime/ingress/*`, and + `src/cli/command-manifest.ts`. + +Operational proof boundary: + +- `test/runtime/runtime-ingress.test.ts`. +- `test/runtime/auth-md-candidate-compilation.test.ts`. +- `test/product/service-workflow-admission.test.ts`. +- `test/architecture/workflow-admission-boundary.test.ts`. +- `examples/service-workflow-admission/*`. + +Planning boundary: + +- `.planning/macro-plan/RUNTIME-GATES.md`. +- `.planning/macro-plan/PROTECTED-ACTION-GATES.md`. +- `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/*`. + +`.planning/` is scratch. It is useful for gate pressure, not repo-facing canon. + +## Files Read + +- `test/runtime/runtime-ingress.test.ts` +- `test/runtime/auth-md-candidate-compilation.test.ts` +- `test/product/service-workflow-admission.test.ts` +- `test/architecture/workflow-admission-boundary.test.ts` +- `examples/service-workflow-admission/run.ts` +- `examples/service-workflow-admission/README.md` +- `src/runtime/ingress/index.ts` +- `src/runtime/ingress/schemas.ts` +- `src/runtime/ingress/families.ts` +- `src/runtime/ingress/registry.ts` +- `src/mcp/LANE.md` +- `src/cli/command-manifest.ts` +- `src/surfaces/service-workflow-admission/index.ts` +- `docs/internal/decisions.md` +- `.planning/macro-plan/MACRO-PLAN.md` +- `.planning/macro-plan/EXECUTION-SLICES.md` +- `.planning/macro-plan/AGENT-HANDOFF.md` +- `.planning/macro-plan/RUNTIME-GATES.md` +- `.planning/macro-plan/PROTECTED-ACTION-GATES.md` +- `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/input.md` +- `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/source-snapshot.md` +- `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/blocked-checks.md` +- `.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research.md` + +## Invariant At Stake + +Product vocabulary may project and read back one protected-action event spine. +It must not become a second authority lane. + +The runtime invariant is stricter: generated code may propose consequential +dispatches, but runtime ingress may create only proposal evidence and candidate +contracts. It must not create policy decisions, greenlights, gateway checks, +signer access, payment material, mutation attempts, receipts, certificates, or +host containment claims. + +The protected-action invariant remains: + +```text +CandidateAction / ActionContract +-> PolicyDecision +-> one-use Greenlight or Refusal +-> GatewayCheck before mutation +-> Receipt / Refusal / ReplayRefusal / ProofGap / AuthorityCertificate +``` + +## Pass Conditions + +- Runtime ingress remains proposal-only for package install, x402, and auth.md + dispatch families. +- Dynamic tool construction, late-bound parameters, ambiguous dispatches, + truncated graphs, unsupported provider posture, stale handles/reviews, and raw + sibling paths refuse before contract authority or stop as bypass evidence. +- Loops, retries, branches, and changed parameters produce distinct exact + candidate/action contracts with distinct sequence and idempotency evidence; + they do not create aggregate authority. +- `ServiceWorkflowAdmission` and `ServiceWorkflowHandle` remain correlation and + readback projections only. They cannot carry policy, greenlight, gateway, + signer, payment payload, credential, receipt, certificate, or mutation + material. +- x402 and auth.md remain separate protected-action rails. No fixture may merge + x402 spend authority and auth.md credential authority into one artifact. +- Payment material and `PAYMENT-SIGNATURE` remain behind `VerifiedGatewayCheck`. + Runtime, MCP, CLI, admission, handle, and review surfaces must not expose + signer helpers or raw payment material. +- Hosted/Tier 3 language remains locked behind separate hosted proof or a fresh + Tier 1/Tier 2 kernel task. Projection vocabulary must not expand package or + kernel authority. + +## Failures + +P0: mixed-family runtime ingress lacks an explicit same-envelope gate. The code +routes each dispatch through its family config, but `RuntimeExecution` and graph +issuer identity are derived from the first dispatch config in +`buildRuntimeIngressExecutionInput()` and `runtimeIngressGraphIssuerContext()`. +The mixed-family test covers package+x402 ordering, but not mismatched +tenant/org/principal/agent/run/runtimeAdapter/operatingEnvelope across configs. +Projection-over-spine closeout must either forbid mixed-family blocks at this +layer or prove all family configs share the same execution envelope before +runtime evidence is recorded. Otherwise a projection can make multiple authority +contexts look like one runtime spine. + +P0: x402/auth.md non-composition is asserted at the service workflow fixture, +but there is no mixed x402+auth.md runtime block test proving separate rails +under generated-code composition. Current auth.md runtime tests prove standalone +candidate/refusal posture; current x402 tests prove standalone and package+x402 +mixed posture. The correction needs a gate that prevents "credentialed paid API +call" from becoming composite authority unless each rail clears through its own +fresh exact contract, policy decision, one-use greenlight/refusal, gateway +check, and post-gate evidence. + +P1: stale review coverage is too dependent on dynamic/late-bound detection. The +runtime test for stale handle/review refuses because dynamic construction and +late-bound refs are present. Add a static-looking stale review digest/handle +digest mismatch case so a stale rendered review cannot pass merely because its +tool name and parameters are syntactically fixed. + +P1: branch coverage is too narrow for the protected-action gate. Runtime tests +cover branch detection and changed amount, but the planning gate asks for +branches that change endpoint, resource, payee, gateway, or credential refs. +Those changes are exactly where a projection can launder scope expansion. + +P1: "parallel proposals from one handle" remains under-proven. Tests cover +sequential retry/loop handle context, but not concurrent or sibling proposals +from the same handle. The required behavior is separate fresh contracts and no +aggregate spend or reusable handle authority. + +P1: raw sibling inventory is still not specific enough for the corrected +projection surface. Tests cover raw package install, raw x402 shell, direct MCP +x402, and raw auth.md MCP. Runtime gates still name browser, direct HTTP, +network, cloud, deploy, and database paths as bypass/proof-gap surfaces. The +closeout must not claim broad runtime protection until those are either named +as explicit proof gaps or covered by a source-owned raw sibling inventory. + +P1: runtime refusal readback is reason-code rich but `RuntimeIngressResponsePosture.refusalRefs` +is always empty. If projection-over-spine readback needs reconstructable refusal +evidence, the runtime outcome should either surface durable refusal refs or +explicitly state that refusal records are recoverable through the +`intentCompilationRefs` only. Without that, refusal evidence can become readback +theatre. + +## Proof Gaps + +- No tests were executed in this audit; this was a read-only source audit plus + report write. +- No host-native containment is proven for Codex, Claude Code, Hermes, OpenClaw, + MCP, browser, A2A, or OpenAPI. +- No live provider/customer custody, funded customer-gateway signer, settlement, + facilitator operation, seller middleware, marketplace trust, cross-org trust, + or aggregate spend ledger is proven. +- No hosted operation proof exists. Current hosted/Tier 3 posture is a lock, not + a go-ahead. +- Runtime ingress has strong local generated-code stress tests, but not a full + generated-code parser/interceptor proof for arbitrary browser, shell, network, + package manager, cloud, deploy, repo, or database tools. +- `auth.md + x402` remains an expansion candidate. It is not current composite + execution authority. + +## Required Changes + +1. Add a same-envelope runtime ingress gate before closeout. It must reject or + refuse mixed-family dispatch blocks whose configs disagree on tenant, + organization, principal, agent, run, runtime adapter, operating envelope, + gateway registry, or authority holder where those fields are intended to + share one generated execution spine. + +2. Add x402+auth.md composition tests. Minimum case: one generated block carries + an auth.md protected API call plus one x402 payment attempt. Expected result: + separate candidates or refusal; no shared credential/signer/payment material; + no composite action contract; no policy, greenlight, gateway, mutation, + receipt, or certificate from runtime ingress. + +3. Add stale review/handle mismatch tests that do not rely on dynamic tool + construction. The stale artifact itself must force a fresh action contract or + refusal. + +4. Add branch-scope tests for endpoint, payee, resource, gateway credential ref, + delegated authority ref, request body digest, and selected payment requirement + changes. Expected result: separate exact contracts or refusal; never aggregate + authority. + +5. Add parallel/sibling proposal tests from the same + `ServiceWorkflowHandle`. Expected result: every protected action still needs + a fresh exact contract and per-call greenlight/gateway chain. + +6. Refresh `.planning/macro-plan/RUNTIME-GATES.md` and + `.planning/macro-plan/PROTECTED-ACTION-GATES.md` for projection-over-spine + language. They should say product vocabulary is projection/readback over the + event spine, not a peer lane. Also reconcile stale blocked-check text against + existing architecture field-negative tests. + +7. Preserve and rerun closeout gates before any implementation claim: + `npm run quality:claims`, `npm run quality:architecture`, + `npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/product/service-workflow-admission.test.ts test/architecture/workflow-admission-boundary.test.ts`, + and `npm run check:repo`. + +## Status Recommendation + +Sidecar recommendation only: do not close runtime/protected-action gates as +passing until the P0 mixed-family same-envelope gate and x402/auth.md +non-composition test exist. + +Brutal verdict: keep projection-over-spine. The current runtime/protected-action +source is mostly disciplined and already refuses many generated-code misuse +shapes. The unsafe version is treating Admission/Handle/review output as a +second lifecycle or allowing mixed-family runtime evidence to blur authority +contexts. That must be blocked before closeout. + +## Commands Or Tools Used + +- Read `gsd-macro-plan` skill instructions. +- Memory quick pass through `/Users/joelchan/.codex/memories/MEMORY.md`. +- `pwd` +- `git status --short` +- `rg --files` +- `rg -n` +- `sed -n` +- `nl -ba` +- `find` +- `mkdir -p .planning/macro-plan/runs/20260525T110908Z-architectural-north-star/audits` +- `apply_patch` to create this report only. + +No tests were run. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/blocked-checks.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/blocked-checks.md new file mode 100644 index 0000000..d057f20 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/blocked-checks.md @@ -0,0 +1,30 @@ +# Blocked Checks + +## Not Blocked + +- The existing macro map is decision-gated but the user explicitly authorized a + new meta-goal and end-to-end run. +- The worktree was clean at start. +- The official research targets were reachable through primary docs. +- The implementation can be scoped to docs/source-boundary tests without + rewriting the protocol kernel. + +## Proof Gaps Preserved + +- No live x402 provider custody, settlement/finality, facilitator operation, or + seller middleware is proven. +- No native host containment is proven for Codex, Claude Code, Hermes, OpenClaw, + MCP, browser, A2A, or OpenAPI. +- No hosted operation, hosted org auth, retention/search, marketplace trust, or + cross-org trust is proven. +- No product UX beyond source-owned docs/schema/demo/readback is proven. + +## Stop Conditions + +- Stop if implementation needs a new protocol primitive for Passport, + Admission, Handle, Badge, Outcome, or Certificate. +- Stop if a product noun is accepted as authority by schema, docs, tests, CLI, + MCP, SDK, package exports, or examples. +- Stop if case-study analogies are used to claim enforcement that source does + not prove. +- Stop if hosted/Tier 3 language expands the kernel/package surface. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/code-review.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/code-review.md new file mode 100644 index 0000000..f9b4d79 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/code-review.md @@ -0,0 +1,52 @@ +# Code Review + +## Invariant At Stake + +Product vocabulary must remain projection/readback over the single protocol +authority spine. Passport, Admission, Handle, Clearance, Outcome, Certificate, +and badge-like language must not become identity, permission, reusable auth, +receipt substitutes, or gateway shortcuts. + +## Reviewed Diff + +- Canonical docs: `README.md`, `STRUCTURE.md`, + `docs/internal/decisions.md`, `docs/internal/protocol-notes.md`, + `docs/internal/service-workflow-story.md`, `src/surfaces/LANE.md`. +- Source: `src/surfaces/service-workflow-lifecycle-projections/index.ts`, + `src/surfaces/boundary-manifest.ts`, `src/runtime/ingress/index.ts`, + `src/surfaces/index.ts`. +- Tests: `test/architecture/service-workflow-lifecycle-projection.test.ts`, + `test/architecture/claim-boundary.test.ts`, + `test/architecture/surface-boundary-posture.test.ts`, + `test/runtime/runtime-ingress.test.ts`. + +## Findings + +No blocking review findings remain. + +Resolved sidecar findings: + +- Product/protocol dual-lane language is replaced with + projection/readback-over-spine language in canonical docs. +- `sdk.policy` is no longer named `policy_authority`; it is now + `policy_transition_transport`, a role-scoped transition client posture. +- Service workflow product nouns are source-owned in a projection map instead + of a new protocol primitive. +- Passport/admission/handle IDs are explicit non-authority correlation and + reconstruction fields. +- Badge is forbidden as a service workflow authority noun. +- Mixed-family runtime ingress now fails before runtime evidence when configs + do not share tenant, org, principal, agent, run, runtime adapter, operating + envelope, and gateway registry. +- x402 plus auth.md composition with separate envelopes refuses before runtime + evidence or action contracts, preserving separate exact contracts or refusal. + +## Residual Risks + +- This is not a UI completion slice. +- Hosted/Tier 3 remains blocked. +- Live provider custody, settlement, marketplace trust, retention/search, and + native host containment remain proof gaps. +- `authorityPosture` remains an existing field name in some product acceptance + matrices; this review only removed the unsafe positive `policy_authority` + posture from the surface boundary manifest. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/git-checkpoints.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/git-checkpoints.md new file mode 100644 index 0000000..74d1b03 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/git-checkpoints.md @@ -0,0 +1,23 @@ +# Git Checkpoints + +## Invariant At Stake + +Git history must separate planning reset from implementation and closeout +evidence so the architecture correction remains reconstructable. + +## Checkpoints + +| Commit | Purpose | +| --- | --- | +| `bdcec05` | Reset architecture macro plan around projection-over-spine north star. | +| `c8db729` | Implement projection map, docs, runtime same-envelope guard, tests, and validation evidence. | +| pending | Record closeout evidence after implementation commit. | + +## Working Tree Notes + +- `.DS_Store` generated workspace metadata was removed because the repo naming + posture gate treats it as active-surface junk. +- No destructive git reset or checkout was used. +- `.planning/macro-plan` run evidence was force-added because `.planning/` is + normally scratch, but this goal explicitly requires the macro-plan package and + review evidence to be committed. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/input.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/input.md new file mode 100644 index 0000000..1fdb09e --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/input.md @@ -0,0 +1,108 @@ +# Architectural North Star Macro Plan Input + +Run id: `20260525T110908Z-architectural-north-star` +Date: 2026-05-25 +Mode: `gsd-macro-plan` +Runtime posture: multi-host evidence only, no host-native containment claim +Protected-action posture: one authority spine, projection-only product vocabulary + +## User Request + +Re-run the macro-plan around the architectural north star. The previous position +created concern that Handshake now has dual product/protocol lanes. The new goal +is end to end: research, plan, implementation, evaluation, review, and commit. + +## Invariant At Stake + +Handshake must have one authority spine: + +```text +CandidateAction / ActionContract +-> PolicyDecision +-> one-use Greenlight or Refusal +-> GatewayCheck before mutation +-> Receipt / Refusal / ReplayRefusal / ProofGap / AuthorityCertificate +``` + +Product vocabulary may simplify readback and service intake, but it must remain +a projection over that spine. It must not become a peer lane of truth. + +## North Star + +```text +Product vocabulary = projection/readback over one protected-action event spine. +Protocol kernel = only source of authority state and gateway-enforced mutation. +Surfaces = implementation boundaries for projection and readback, not product +truth lanes. +``` + +## Research Targets + +Primary-source case studies to convert into mechanisms, not analogy: + +- Stripe PaymentIntents: lifecycle object, status model, idempotency, retries. +- Kubernetes Admission / OPA Gatekeeper: pre-write chokepoint, rejection, + validating/mutating separation, reconciliation for side effects. +- HashiCorp Vault: custody, leases, renewal, revocation, audit value. +- GitHub deployment environments: protection rules before jobs proceed. +- AWS IAM: default deny and explicit deny overriding allow. +- SLSA / GitHub artifact attestations / Sigstore family: provenance and + signed evidence as post-fact verification, not permission. +- Vercel Deployment Protection / Cloudflare Access: product scope/method clarity + and continuous verification language. + +## Source Boundary + +Canonical repo truth: + +- `AGENTS.md` +- `README.md` +- `QUALITY.md` +- `STRUCTURE.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-definition.md` +- `docs/internal/protocol-kernel-architecture.md` +- `docs/internal/protocol-layman.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/service-workflow-story.md` + +Derived planning input: + +- `.planning/macro-map/MACRO-HANDOFF.md` +- `.planning/macro-map/*` +- `.planning/codebase/*` +- prior `.planning/macro-plan/*` product-simplification package + +Operational proof: + +- `src/protocol/navigation` +- `src/protocol/areas/action-attempt-lifecycle` +- `src/surfaces` +- `src/runtime/ingress` +- `src/cli` +- `src/mcp` +- `examples/service-workflow-admission` +- `test/architecture/*` +- `test/runtime/runtime-ingress.test.ts` +- `test/product/service-workflow-admission.test.ts` + +## Cut Lines + +- No "product lane" and "protocol lane" as peer truth systems. +- No product surface may create, reinterpret, or bypass protocol authority. +- No Passport, Admission, Handle, Outcome, Certificate, Badge, or review screen + can be identity, permission, reusable auth, policy, greenlight, gateway + admission, mutation permission, receipt substitute, hosted trust, or terminal + settlement. +- No hosted/Tier 3 work may expand kernel/package exports because the projection + vocabulary is cleaner. + +## Desired Outputs + +- Revised macro-plan package with source boundary, official research, + execution slices, runtime gates, protected-action gates, evidence plan, + review gates, risks, decisions, task JSONL, validation, and sidecar audits. +- Source implementation that changes docs/source/tests from dual-lane language + to projection-over-spine language. +- Focused tests that fail if product vocabulary becomes a second authority lane. +- Full repo gate or explicitly justified equivalent before closeout. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research-evidence.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research-evidence.md new file mode 100644 index 0000000..17914b6 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research-evidence.md @@ -0,0 +1,37 @@ +# Research Evidence + +This file is the current-run evidence ledger requested by the evidence sidecar. +It expands `research.md` with claim-to-source boundaries. + +## Access Date + +2026-05-25 + +## Claims Supported + +| Macro-plan claim | Primary source | Evidence boundary | +| --- | --- | --- | +| Lifecycle clarity should be one object/spine, not multiple truth lanes. | Stripe PaymentIntents docs and lifecycle docs. | Supports status/idempotency design inspiration only; does not prove Handshake payments or Stripe parity. | +| Enforcement must happen at a chokepoint before mutation/persistence. | Kubernetes admission-control docs and OPA Kubernetes admission docs. | Supports gateway/admission design pattern only; does not make service workflow admission a Kubernetes-style admission controller. | +| Custody material must remain revocable/fresh and behind custody boundaries. | HashiCorp Vault lease docs. | Supports custody/freshness mechanism only; does not prove provider/customer custody in Handshake. | +| Deployment/protected execution gates are conditions before execution proceeds. | GitHub deployment environments docs. | Supports per-event protection gate framing only; does not turn approvals into mutation authority. | +| Deny/refusal/proof-gap blockers should dominate convenience. | AWS IAM policy evaluation docs. | Supports default/explicit deny discipline only; Handshake policy logic remains source-owned. | +| Attestations/provenance are verification evidence, not permission. | SLSA levels and GitHub artifact-attestation docs. | Supports receipt/certificate evidence framing only; does not claim public transparency log or SLSA compliance. | +| Product scope/method must be explicit and reverified. | Vercel Deployment Protection and Cloudflare ZTNA docs. | Supports product copy discipline only; does not turn Handshake into an access-control product. | + +## Disconfirming Boundaries + +- Stripe PaymentIntents can expose a client secret for client-side payment flow; + Handshake must not copy that pattern into Passport, Admission, Handle, or + Clearance. +- Kubernetes admission applies to API-server writes; Handshake service workflow + admission is evidence/readback mapping before protected-action clearance. +- Vault leases manage secrets; Handshake handles are not lease IDs or + credentials. +- GitHub deployment approval does not model generated-code inner mutations. +- AWS IAM is ambient principal authorization; Handshake requires exact per-event + contracts and one-use gateway-bound greenlights. +- SLSA/Sigstore/in-toto evidence verifies provenance; it does not authorize the + next action. +- Vercel/Cloudflare are access-control products; Handshake is execution-control + infrastructure. diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research.md new file mode 100644 index 0000000..1ac4a05 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/research.md @@ -0,0 +1,66 @@ +# Architectural Case Study Research + +## Invariant At Stake + +External products are useful only if they become mechanisms for Handshake's +single authority spine. They must not become borrowed analogy or permission +theatre. + +## Primary Sources Checked + +- Stripe PaymentIntents: + `https://docs.stripe.com/payments/payment-intents` and + `https://docs.stripe.com/payments/paymentintents/lifecycle` +- Kubernetes Admission Control: + `https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/` +- OPA for Kubernetes admission: + `https://www.openpolicyagent.org/docs/kubernetes` +- HashiCorp Vault leases: + `https://developer.hashicorp.com/vault/docs/concepts/lease` +- GitHub deployment environments: + `https://docs.github.com/en/actions/reference/workflows-and-actions/deployments-and-environments` +- AWS IAM policy evaluation: + `https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic_policy-eval-denyallow.html` +- SLSA security levels: + `https://slsa.dev/spec/v1.0/levels` +- GitHub artifact attestations: + `https://docs.github.com/en/actions/concepts/security/artifact-attestations` +- Vercel Deployment Protection: + `https://vercel.com/docs/deployment-protection` +- Cloudflare ZTNA access policies: + `https://developers.cloudflare.com/reference-architecture/design-guides/designing-ztna-access-policies/` + +## Mechanisms To Import + +| Source | Mechanism | Handshake translation | +| --- | --- | --- | +| Stripe PaymentIntents | One lifecycle object tracks a payment across status changes, retries, and idempotency. | Define one protected-action event spine and make friendly vocabulary projections of it. | +| Kubernetes Admission | Write requests hit admission before persistence; rejection halts the whole request. Side effects need reconciliation. | Gateway check remains the pre-consequence chokepoint; downstream uncertainty becomes receipt/proof-gap reconciliation. | +| OPA Gatekeeper | Policy is queried by the API server on create/update/delete, not by UI copy. | Policy is machine-evaluated against exact action contracts, not product summaries. | +| Vault | Dynamic secret leases force renewal/replacement and support revocation. | Handles and readiness are freshness-bound context, never reusable auth. Credential material stays behind custody/gateway. | +| GitHub environments | Deployment protection rules must pass before jobs referencing an environment proceed. | Protected-action clearance gates each consequential event before mutation. | +| AWS IAM | Default deny and explicit deny override allow. | Refusals, isolation, stale evidence, and bypass posture must dominate product convenience. | +| SLSA / artifact attestations | Provenance establishes build origin and process for verification. | Receipts/certificates are terminal evidence and reconstruction, not permission. | +| Vercel / Cloudflare | Clear protection scope/method; continuous verification avoids stale auth assumptions. | Product copy must name scope and method; every protected action rechecks fresh authority instead of trusting workflow admission. | + +## Anti-Mechanisms To Avoid + +- `client_secret`-style bearer material leaking into Passport, Admission, or + Handle. +- Kubernetes-style admission being misread as Handshake service admission. +- Vault lease IDs being treated as permission rather than management handles. +- Deployment approval becoming approval of all generated-code mutations. +- Attestation/certificate being treated as future authority. +- Access-control product language being substituted for execution-control + enforcement. + +## Architectural Conclusion + +Handshake should not have product/protocol lanes. It should have: + +```text +Projection/readback vocabulary +over one protected-action event lifecycle +over exact policy and gateway enforcement +over append-only evidence and recovery. +``` diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/source-snapshot.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/source-snapshot.md new file mode 100644 index 0000000..ebb4a27 --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/source-snapshot.md @@ -0,0 +1,39 @@ +# Source Snapshot + +## Git + +- Branch: `main` +- Starting status: clean, ahead of `origin/main` by 8 commits. + +## Canonical Boundary Observed + +- `STRUCTURE.md` says this repo is a TypeScript protocol kernel and defines + product surfaces as non-authority CLI/MCP/SDK/docs/demos/readbacks. +- `docs/internal/decisions.md` defines the shared product/protocol vocabulary + and makes `ServiceWorkflowAdmission` / `ServiceWorkflowHandle` non-authority + records. +- `docs/internal/protocol-notes.md` currently has a "Product And Protocol + Language" section that can be sharpened into projection-over-spine language. +- `docs/internal/service-workflow-story.md` currently says the story is a + product surface over the protocol kernel. This is directionally right but + should be recast as a projection/readback over one event spine. +- `src/surfaces/LANE.md` correctly blocks authority behavior, but the lane name + can still be mistaken for a peer product truth lane unless docs say surfaces + are implementation boundaries for projections. + +## Implementation Targets + +- `README.md` +- `STRUCTURE.md` +- `docs/internal/decisions.md` +- `docs/internal/protocol-notes.md` +- `docs/internal/service-workflow-story.md` +- `src/surfaces/LANE.md` +- `test/architecture/claim-boundary.test.ts` + +## Current Proof Gates + +- `npm run quality:claims` +- `npm run quality:architecture` +- `npm run test -- test/architecture/claim-boundary.test.ts test/architecture/workflow-admission-boundary.test.ts` +- `npm run check:repo` diff --git a/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md new file mode 100644 index 0000000..ac5716a --- /dev/null +++ b/.planning/macro-plan/runs/20260525T110908Z-architectural-north-star/validation.md @@ -0,0 +1,94 @@ +# Validation + +## Invariant At Stake + +Validation must prove the macro plan is structurally complete before the +implementation starts. It does not prove source implementation, runtime +enforcement, hosted operation, provider custody, or product UX completion. + +## Macro-Plan Validator + +Command: + +```bash +python3 /Users/joelchan/.codex/skills/gsd-macro-plan/scripts/validate_macro_plan_output.py .planning/macro-plan +``` + +Result: + +```text +Macro plan output is valid. +``` + +## Status + +- `NPLAN-001` is complete for planning structure and sidecar incorporation. +- `NPLAN-002` through `NPLAN-005` are implemented in source/docs/tests. +- `NPLAN-006` has full repo gate evidence and is ready for implementation + commit closeout. + +## Focused Implementation Gates + +Command: + +```bash +npm run test -- test/architecture/service-workflow-lifecycle-projection.test.ts test/architecture/surface-boundary-posture.test.ts test/architecture/claim-boundary.test.ts test/architecture/workflow-admission-boundary.test.ts +``` + +Result: + +```text +21 pass +0 fail +``` + +Command: + +```bash +npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/product/service-workflow-admission.test.ts +``` + +Result: + +```text +32 pass +0 fail +``` + +## Quality Gates + +Commands and results: + +```text +npm run quality:claims +4 pass, 0 fail + +npm run quality:architecture +68 pass, 0 fail + +npm run format:check +All matched files use Prettier code style. +``` + +Full repo gate: + +```bash +npm run check:repo +``` + +Result: + +```text +build, check:types, lint, format:check, test, pack:check, and git diff --check passed. +bun test: 621 pass, 0 fail. +pack:check: package surface, clean installed activation, release proof, and npm maintainer posture passed. +``` + +## Proof Gaps Preserved + +- Hosted/Tier 3 operation remains blocked pending separate hosted workspace or + fresh pre-hosted kernel task. +- Live provider custody, settlement finality, marketplace trust, cross-org + trust, retention/search, and native host containment are still non-proofs. +- x402/auth.md composition is covered as refusal for separate envelopes; no + composite credential-plus-payment authority artifact is created. diff --git a/.planning/macro-plan/runs/20260525T174005-passport-admission-full/audits/evidence.md b/.planning/macro-plan/runs/20260525T174005-passport-admission-full/audits/evidence.md new file mode 100644 index 0000000..822d76c --- /dev/null +++ b/.planning/macro-plan/runs/20260525T174005-passport-admission-full/audits/evidence.md @@ -0,0 +1,141 @@ +## Audit Scope + +Focus: evidence. + +Assigned slice: T2-01 MCP surfaces only. + +Question audited: whether the simplified service workflow can improve MCP descriptions/resources while preserving the invariant that MCP is proposal/evidence only and `ServiceWorkflowHandle` cannot become permission. + +No source, docs, or tests were edited. + +## Source Boundary + +Required sources read: + +- `AGENTS.md` +- `.planning/macro-plan/AGENT-HANDOFF.md` +- `.planning/macro-plan/TASKS.jsonl` +- `README.md` +- `src/mcp/catalog.ts` +- `src/mcp/resources.ts` +- `src/mcp/x402-proposal.ts` +- `src/mcp/output.ts` +- `test/architecture/mcp-surface-posture.test.ts` + +Additional read-only sources used to resolve the current boundary: + +- `src/surfaces/boundary-manifest.ts` +- `src/surfaces/service-workflow-admission/index.ts` +- `test/architecture/workflow-admission-boundary.test.ts` +- `test/mcp/mcp-schema-contract.test.ts` +- `test/mcp/mcp-resource-redaction.test.ts` +- `test/mcp/mcp-x402-proposal.test.ts` +- `package.json` +- `QUALITY.md` + +## Files Read + +- `AGENTS.md` +- `.planning/macro-plan/AGENT-HANDOFF.md` +- `.planning/macro-plan/TASKS.jsonl` +- `README.md` +- `src/mcp/catalog.ts` +- `src/mcp/resources.ts` +- `src/mcp/x402-proposal.ts` +- `src/mcp/output.ts` +- `src/surfaces/boundary-manifest.ts` +- `src/surfaces/service-workflow-admission/index.ts` +- `test/architecture/mcp-surface-posture.test.ts` +- `test/architecture/workflow-admission-boundary.test.ts` +- `test/mcp/mcp-schema-contract.test.ts` +- `test/mcp/mcp-resource-redaction.test.ts` +- `test/mcp/mcp-x402-proposal.test.ts` +- `package.json` +- `QUALITY.md` + +## Invariant At Stake + +MCP can expose proposal and evidence/readback. MCP must not evaluate policy, create a greenlight, perform a gateway check, invoke a signer, mutate, export a receipt, mint a terminal certificate, or let a service workflow handle function as permission. + +The dangerous failure is not current MCP mutation. The dangerous failure is adding the simplified service workflow in a way that makes `ServiceWorkflowHandle`, passport IDs, admission IDs, or handle digests look like clearance. + +## Pass Conditions + +- MCP keeps exactly proposal/evidence/readback posture. +- `handshake.actions.x402_payment.propose` remains one fresh x402 action-contract proposal, not policy or gateway authority. +- MCP resources remain read-only and set false non-authority flags. +- Service workflow alignment is descriptive or evidentiary only. +- Any service workflow reference, if later added, is correlation/readback context only and cannot satisfy `delegatedAuthorityBinding`, `operatingEnvelopeId`, `gatewayRegistryEntryId`, trusted readiness, policy version, idempotency authority, greenlight, gateway check, signer, payment material, mutation, receipt export, or certificate minting. +- Tests fail if MCP imports authority paths, names credential material, outputs authority fields, or accepts mutation-shaped proposal input. + +## Failures + +Current authority posture: no failure found. Focused MCP/workflow tests pass. + +Concrete T2-01 alignment gap: + +- `README.md` teaches `Show Passport -> ServiceWorkflowAdmission -> ServiceWorkflowHandle -> Request Clearance -> Read Outcome`, and states handle is correlation/readback only. +- `src/mcp/catalog.ts` exposes the one x402 proposal tool and read-only resource templates, but the tool description only says it proposes one exact x402 protected action and does not authorize or execute. It does not teach the service workflow model or the handle boundary. +- `src/mcp/resources.ts` metadata payload for `handshake://metadata/actions/{actionClass}` only returns action class, proposal tool, and non-authority flags. It does not expose the service workflow boundary or the "fresh action contract required" rule. +- `src/mcp/resources.ts` challenge payloads are generic `recraft_request` records. They do not distinguish stale service workflow evidence, handle-as-permission misuse, or fresh-clearance-required remediation. + +Planning/test conflict: + +- T2-01 asks to align MCP descriptions with the service workflow model. +- `test/architecture/workflow-admission-boundary.test.ts` currently treats `src/mcp` as a forbidden authority root for the service workflow nouns and IDs. That is good against handle-as-permission drift, but it also blocks naive MCP description/resource alignment if exact names are added to `src/mcp/catalog.ts` or `src/mcp/resources.ts`. +- Therefore T2-01 needs a narrow test rule, not a broad weakening: allow descriptive/read-only MCP metadata only if false non-authority flags and fresh-contract language are present; continue forbidding proposal input fields and authority-path use. + +## Proof Gaps + +- No MCP-specific test currently proves the simplified service workflow is visible to MCP users as proposal/evidence-only. Current tests prove MCP stays non-authority, not that it teaches the simplified flow. +- No MCP-specific negative test distinguishes safe service workflow metadata from unsafe handle-as-permission input. +- `McpX402PaymentProposalInputSchema` has `correlationRef`, but no typed service workflow context posture. That is safer than accepting a handle as permission, but it means any future handle correlation would be opaque unless bounded by explicit metadata/resource tests. +- No MCP resource family exists for read-only service workflow admission or handle readback. Adding one could help reconstruction, but only if it is read-only evidence and cannot be used as a bearer permission URI. + +## Required Changes + +For T2-01, keep the change descriptive and evidentiary: + +1. Update MCP tool/resource descriptions to say the tool proposes fresh clearance for one protected action after any service workflow context; it does not authorize, execute, or treat workflow handles as permission. +2. Prefer read-only metadata over handle-bearing proposal input. A safe direction is a metadata resource such as `handshake://metadata/service-workflow` or added fields in `handshake://metadata/actions/{actionClass}` that state: + - passport/admission/handle are evidence or context only; + - fresh action contract is required for every protected action; + - MCP creates no policy decision, greenlight, gateway check, mutation, receipt export, or certificate. +3. If actual service workflow readback resources are added, keep them under evidence/readback, include the service workflow non-authority boundary flags, and never return credential material, payment material, receipt exports, raw internal records, greenlights, gateway check inputs, or mutation commands. +4. Do not add MCP policy tools, gateway tools, signer tools, mutation tools, or service-workflow-handle permission tools. +5. Do not let `ServiceWorkflowHandle` populate `delegatedAuthorityBinding`, trusted readiness, policy version, gateway registry, operating envelope, idempotency authority, or proposal bounds. +6. Tighten tests by splitting "MCP may describe/read service workflow context" from "MCP may use service workflow context as authority." The latter must remain forbidden. + +## Status Recommendation + +Current MCP posture passes as proposal/evidence only. + +T2-01 should proceed only as a narrow descriptive/resource alignment. It should not add handle-bearing permission semantics or new authority-shaped MCP tools. + +Smallest acceptable move: make MCP catalog/metadata teach "service workflow context is not clearance; fresh action contract required" and add tests proving the wording/resource remains non-authority. + +## Commands Or Tools Used + +- `sed -n '1,220p' /Users/joelchan/.codex/skills/handshake-grounding/SKILL.md` +- `rg -n "T2-01|MCP|x402-proposal|mcp-surface|proposal/evidence|proposal evidence|x402" /Users/joelchan/.codex/memories/MEMORY.md` +- `pwd` +- `git status --short --branch` +- `nl -ba AGENTS.md | sed -n '1,260p'` +- `nl -ba .planning/macro-plan/AGENT-HANDOFF.md | sed -n '1,260p'` +- `nl -ba .planning/macro-plan/TASKS.jsonl | sed -n '1,220p'` +- `nl -ba README.md | sed -n '1,260p'` +- `nl -ba src/mcp/catalog.ts | sed -n '1,260p'` +- `nl -ba src/mcp/resources.ts | sed -n '1,320p'` +- `nl -ba src/mcp/x402-proposal.ts | sed -n '1,920p'` +- `nl -ba src/mcp/output.ts | sed -n '1,320p'` +- `nl -ba test/architecture/mcp-surface-posture.test.ts | sed -n '1,360p'` +- `rg --files src/mcp test/mcp test/architecture | sort` +- `nl -ba src/surfaces/boundary-manifest.ts | sed -n '586,660p'` +- `nl -ba src/surfaces/service-workflow-admission/index.ts | sed -n '1,180p'` +- `nl -ba test/mcp/mcp-schema-contract.test.ts | sed -n '1,260p'` +- `nl -ba test/mcp/mcp-resource-redaction.test.ts | sed -n '1,260p'` +- `nl -ba test/mcp/mcp-x402-proposal.test.ts | sed -n '1,760p'` +- `nl -ba test/architecture/workflow-admission-boundary.test.ts | sed -n '1,320p'` +- `nl -ba package.json | sed -n '84,112p'` +- `nl -ba QUALITY.md | sed -n '120,150p'` +- `npm run test -- test/architecture/mcp-surface-posture.test.ts test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-resource-redaction.test.ts test/mcp/mcp-x402-proposal.test.ts test/architecture/workflow-admission-boundary.test.ts` diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/audits/validation.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/audits/validation.md new file mode 100644 index 0000000..f4a6bb8 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/audits/validation.md @@ -0,0 +1,40 @@ +# A2A Negotiation Macro Plan Validation + +Run: `20260526T000830Z-a2a-negotiation-end2end` +Verdict: PASS_FOR_PHASE_PLANNING + +## Checked Requirements + +| Requirement | Evidence | Verdict | +| --- | --- | --- | +| CEO review exists | `raw/CEO.md` | PASS | +| Engineering review exists | `raw/ENGINEERING.md` | PASS | +| Design review exists | `raw/DESIGN.md` | PASS | +| DevEx review exists | `raw/DEVEX.md` | PASS | +| Agent review exists | `raw/AGENT.md` | PASS | +| Normalized findings exist | `normalized/*.jsonl` | PASS | +| Source boundary exists | `source-snapshot.md` | PASS | +| Chair synthesis exists | `chair-synthesis.md` | PASS | +| Architecture plan exists | `../../a2a-negotiation/ARCHITECTURE.md` | PASS | +| Implementation slices exist | `../../a2a-negotiation/EXECUTION-SLICES.md` | PASS | +| Evaluation suite exists | `../../a2a-negotiation/EVALUATION.md` | PASS | +| Review/audit matrix exists | `../../a2a-negotiation/REVIEW-AUDIT.md` | PASS | +| Agent handoff exists | `../../a2a-negotiation/AGENT-HANDOFF.md` | PASS | +| Task list exists | `../../a2a-negotiation/TASKS.jsonl` | PASS | +| Authority boundary preserved | all artifacts repeat agreement is not authority | PASS | + +## Non-Proofs + +- No protocol code has been implemented. +- No tests have been added or run for the future protocol extension. +- No independent subagent review artifacts were produced; lens reviews were run + inline in this thread. +- No cross-org trust model exists. +- No public package exports are approved. + +## Final Status + +`READY_FOR_PHASE_PLANNING` + +The package is sufficient to start detailed phase planning for A2A-001. It is +not sufficient to start autonomous source implementation without a phase plan. diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/chair-synthesis.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/chair-synthesis.md new file mode 100644 index 0000000..2a856d3 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/chair-synthesis.md @@ -0,0 +1,51 @@ +# Chair Synthesis: A2A Negotiation Macro Plan + +Run: `20260526T000830Z-a2a-negotiation-end2end` +Status: `READY_FOR_PHASE_PLANNING` + +## Convergence + +All five review lenses converge on the same macro move: + +```text +Add negotiated-obligation evidence and binding records, not negotiation +authority. +``` + +The first proof must be a buyer-agent/seller-agent +`x402_payment.exact` fixture. The agreement is a coordination/readback object. +The enforcement object remains the action contract and gateway check. + +## Accepted Decisions + +1. Add a new `negotiation` protocol area. +2. Add `LinkedAgreement` and `AgreementObligationBinding` as transition + evidence only. +3. Use existing `clearingEvidenceRefs.obligationRef` and `counterpartyRef` to + connect action contracts to negotiated obligations. +4. Keep first proof local/reference, not hosted/cross-org. +5. Require policy refusal for expired, withdrawn, disputed, superseded, stale, + or mismatched agreement state. +6. Defer cross-org trust, marketplace, escrow, reputation, settlement, + provider custody, and legal contract formation. + +## P0 Gates + +- agreement acceptance cannot create authority; +- one agreement cannot authorize multiple mutations; +- one party cannot authorize another party's gateway; +- policy must check agreement state before greenlight; +- gateway must still verify one-use greenlight before payment/signer material; +- readback must separate agreement status, policy status, gateway status, and + downstream finality; +- raw terms, secrets, signer material, and payment material must not leak in + readback or support packets. + +## Plan Status + +`READY_FOR_PHASE_PLANNING` + +Reason: this package contains source boundary, lens reviews, architecture +contract, execution slices, evaluation suite, audit gates, task list, and agent +handoff. It is not `READY_FOR_AGENT_EXECUTION` because implementation phase +plans and source edits have not yet been created or verified. diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/input.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/input.md new file mode 100644 index 0000000..489a881 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/input.md @@ -0,0 +1,76 @@ +# A2A Negotiation End-to-End Macro Plan Input + +Run: `20260526T000830Z-a2a-negotiation-end2end` +Source goal: `.planning/macro-plan/A2A_NEGOTIATION_META_META_GOAL.md` +Runtime posture: `multi` +Authority overlay: required +Planner posture: inline lens chain + +## User Objective + +Run the A2A Negotiation Meta-Meta Goal macro plan end to end: + +```text +full planceo review +-> plan-eng review +-> plan-design review +-> plan-devex review +-> plan-agent review +-> execution plan +-> review/audit +-> evaluation +-> commit +``` + +## Target Macro Move + +Plan agent-to-agent negotiated protected-action events in Handshake. + +The move is not generic negotiation. It is the smallest protocol/product layer +where two agents can negotiate an obligation, but accepted terms create no +authority until the obligation binds to a fresh protected-action contract and +clears the normal gateway-enforced lifecycle. + +## First Fixture + +```text +buyer-agent / seller-agent negotiation over one buyer-side x402_payment.exact +protected action +``` + +## Required Invariant + +Agent-to-agent agreement is not authority. + +Each consequential negotiated obligation must still clear through: + +```text +CandidateAction +-> exact ActionContract +-> PolicyDecision / one-use Greenlight or Refusal +-> GatewayCheck before consequence +-> Receipt / Refusal / ReplayRefusal / ProofGap / Isolation +``` + +## Source Boundary + +Canonical source anchors are listed in `source-snapshot.md`. + +This run may use memory and prior strategy only as context. Claims must be +grounded in current source files and the local planning artifact. + +## Review Lenses + +- CEO: market/opening verdict and scope discipline. +- Engineering: protocol architecture, state transitions, policy hook, tests. +- Design: readback workflow and agreement-vs-authority legibility. +- DevEx: first proof path and builder ergonomics. +- Agent: multi-agent runtime suitability and protected-action posture. + +## Promotion Rule + +This run can become `READY_FOR_PHASE_PLANNING` if it creates architecture, +execution slices, evals, review/audit gates, tasks, and a fresh-agent handoff. + +It must not claim `READY_FOR_AGENT_EXECUTION` unless implementation-ready phase +plans, source edits, tests, and independent verification are present. diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/AGENT.jsonl b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/AGENT.jsonl new file mode 100644 index 0000000..e43e63e --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/AGENT.jsonl @@ -0,0 +1,2 @@ +{"lens":"AGENT","severity":"P0","finding":"Agent may implement generic negotiation without protected-action clearing.","required_change":"Require slice handoffs with runtime profile, write scopes, tool contract, and stop conditions."} +{"lens":"AGENT","severity":"P1","finding":"Raw x402 payment path would escape the contract boundary.","required_change":"Fixture must prove signer/payment material stays behind VerifiedGatewayCheck."} diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/CEO.jsonl b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/CEO.jsonl new file mode 100644 index 0000000..7e5a990 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/CEO.jsonl @@ -0,0 +1,2 @@ +{"lens":"CEO","severity":"P0","finding":"Acceptance must not create authority.","required_change":"Keep LinkedAgreement non-authority and require fresh protected-action contracts for each obligation."} +{"lens":"CEO","severity":"P1","finding":"A2A negotiation can become marketplace sprawl.","required_change":"Keep first proof to buyer-agent/seller-agent x402_payment.exact and cut marketplace, escrow, reputation, and settlement claims."} diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/DESIGN.jsonl b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/DESIGN.jsonl new file mode 100644 index 0000000..e88de7c --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/DESIGN.jsonl @@ -0,0 +1,2 @@ +{"lens":"DESIGN","severity":"P0","finding":"Accepted offer can be mistaken for authorized action.","required_change":"Render agreement status separately from policy and gateway status."} +{"lens":"DESIGN","severity":"P1","finding":"Evidence can disappear behind summaries.","required_change":"Every obligation row must expose exact refs and terminal posture."} diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/DEVEX.jsonl b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/DEVEX.jsonl new file mode 100644 index 0000000..1807c51 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/DEVEX.jsonl @@ -0,0 +1,2 @@ +{"lens":"DEVEX","severity":"P0","finding":"Manual protocol assembly blocks first proof.","required_change":"Create a fixture runner for examples/a2a-negotiated-x402 before broad CLI/API work."} +{"lens":"DEVEX","severity":"P1","finding":"Hosted or cross-org dependencies would stall adoption.","required_change":"Keep first proof local/reference with explicit non-claims."} diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/ENGINEERING.jsonl b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/ENGINEERING.jsonl new file mode 100644 index 0000000..6bd046a --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/normalized/ENGINEERING.jsonl @@ -0,0 +1,2 @@ +{"lens":"ENGINEERING","severity":"P0","finding":"Cross-org dependencies exceed current same-org sequence dependency support.","required_change":"Treat cross-org trust as proof gap until a trust model exists."} +{"lens":"ENGINEERING","severity":"P0","finding":"Policy must validate agreement state before greenlight.","required_change":"Add agreement-backed obligation policy hook before any gateway path can clear."} diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/AGENT.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/AGENT.md new file mode 100644 index 0000000..85318c1 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/AGENT.md @@ -0,0 +1,68 @@ +# Agent Review: A2A Negotiation + +Status: PROFILE_REQUIRED_BEFORE_AGENT_EXECUTION +Runtime: multi +Protected-action overlay: required + +## Invariant At Stake + +Agents may negotiate, propose, and inspect evidence. They must not inherit raw +mutation, signer, payment, gateway, or cross-party authority from the +negotiation. + +## Execution Shape + +```text +buyer agent +-> receives seller offer +-> proposes acceptance evidence +-> Handshake records linked agreement +-> buyer agent proposes x402_payment.exact CandidateAction +-> Handshake binds obligation to ActionContract +-> policy/gateway decide consequence +``` + +Seller agent may present terms and read terminal evidence. It cannot authorize +buyer spend. Buyer agent cannot authorize seller-side mutation. + +## Agent Plan Contract + +The implementation plan must name: + +- runtime profile: Codex first, multi-host later; +- instruction sources: `AGENTS.md`, meta-meta goal, macro plan, source anchors; +- tool contract: read, propose, fixture-run, test only until gateway slice; +- write scopes: negotiation area, tests, examples, docs; +- stop conditions: authority overclaim, raw signer exposure, cross-org trust + dependency, unsupported broad export; +- evals: no-authority acceptance, binding mismatch, replay, proof gap; +- handoff: one fresh-agent packet per slice. + +## P0/P1 Findings + +P0: Without a runtime profile and fixture packet, a coding agent may implement +generic negotiation instead of protected-action clearing. + +P0: Any plan that asks the agent to call raw x402 payment paths outside a +gateway-protected wrapper must stop. + +P1: If the agent can dynamically construct action types or gateways from +negotiation text, policy must refuse until catalog-bound. + +P1: Parallel agents need disjoint write scopes because protocol schema, +object registry, kernel facade, tests, and examples are tightly coupled. + +## Suitability Matrix + +| Runtime | Posture | Reason | +| --- | --- | --- | +| Codex | `PROFILE_REQUIRED` | Can execute slices with file gates, but needs exact handoff. | +| MCP | `PROTECTED_ACTION_OVERLAY_REQUIRED` | Proposal/evidence only, no authority. | +| x402 | `PROTECTED_ACTION_OVERLAY_REQUIRED` | Payment material must stay behind gateway. | +| Multi-host | `BLOCKED_BY_TRUST_MODEL` | Cross-org trust and host parity are not proven. | + +## Agent Recommendation + +Proceed to phase planning, not autonomous implementation. First produce +`A2A-001` phase plan with source anchors, exact files, tests, and stop +conditions. diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/CEO.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/CEO.md new file mode 100644 index 0000000..f0ff707 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/CEO.md @@ -0,0 +1,76 @@ +# CEO Review: A2A Negotiation + +Status: PASS_FOR_PHASE_PLANNING +Mode: selective expansion with hard authority boundary + +## Invariant At Stake + +Handshake wins if it becomes the clearing layer for agent-negotiated work. It +loses if it becomes another marketplace or negotiation chatbot with proof +language attached. + +## Verdict + +Yes, pursue A2A negotiation, but only as negotiated-obligation clearing. + +The commercial object is not "conversation between agents." The commercial +object is a cleared work unit: accepted terms tied to exact protected-action +contracts and terminal evidence. + +## Market Thesis + +Agents will increasingly: + +- buy paid API calls; +- subcontract tasks; +- bid for work; +- deliver work claims; +- request evaluations; +- route payments; +- hand off protected actions across services. + +The market gap is not that agents cannot talk. They can. The gap is that +businesses cannot safely accept automated negotiated obligations without proof +that consequence was cleared inside bounds. + +## Scope Decision + +Keep: + +- `LinkedAgreement` as non-authority evidence. +- `AgreementObligationBinding` as the bridge to exact `ActionContract`s. +- first fixture: buyer-agent/seller-agent over `x402_payment.exact`. +- cleared work unit as economic language. + +Cut: + +- marketplace ownership; +- escrow/settlement; +- legal contract formation; +- generic A2A identity; +- reputation; +- cross-org trust; +- broad dispute resolution. + +## P0/P1 Findings + +P0: If agreement acceptance creates permission, the product becomes ambient +authority wearing a badge. + +P0: If Handshake claims A2A negotiation before the x402 fixture clears through +gateway evidence, the launch claim outruns enforcement. + +P1: If the first product surface leads with negotiation UI instead of terminal +evidence, users will misunderstand what Handshake controls. + +## Recommendation + +Proceed to architecture and phase planning with this product sentence: + +```text +Handshake lets services accept, refuse, and reconstruct agent-negotiated +protected-action obligations. +``` + +Do not promote to implementation until engineering proves exact obligation +binding, policy refusal, replay refusal, and redacted readback. diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/DESIGN.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/DESIGN.md new file mode 100644 index 0000000..680e504 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/DESIGN.md @@ -0,0 +1,90 @@ +# Design Review: A2A Negotiation + +Status: PASS_FOR_READBACK_SPEC + +## Invariant At Stake + +The interface must make agreement and authority visually distinct. If users see +"accepted" and infer "authorized," the design is review theatre. + +## Primary User Moment + +The user opens an A2A event and needs to answer: + +```text +What did the agents agree to, which obligations became exact contracts, what +cleared, what refused, and what remains a proof gap? +``` + +## Information Hierarchy + +1. Terminal posture: + - cleared; + - refused; + - proof gap; + - isolated; + - pending contract; + - pending gateway. +2. Agreement posture: + - offer; + - counter; + - accepted; + - withdrawn; + - expired; + - disputed; + - superseded. +3. Obligation bindings: + - obligation ID; + - responsible party; + - counterparty; + - action contract ref; + - digest match posture; + - policy posture; + - gateway posture. +4. Evidence timeline: + - negotiation events; + - action lifecycle; + - terminal receipt/refusal/proof gap. +5. Non-claims: + - acceptance is not permission; + - receipt is not settlement; + - certificate is terminal evidence only. + +## Required Screens Or Projections + +- A2A negotiation timeline. +- Linked agreement detail. +- Obligation binding table. +- Protected action evidence drawer. +- Redacted support packet preview. +- Failure-state readback for mismatch, expiry, dispute, replay, and proof gap. + +## P0/P1 Findings + +P0: Do not render "Accepted" as a success state unless the protected-action +outcome is separately visible. + +P0: Do not combine agreement status and gateway status into one badge. + +P1: Every obligation row needs exact refs. Hover-only evidence is not enough. + +P1: Empty states must explain whether no contract exists, no policy decision +exists, no gateway check exists, or readback is redacted. + +## Design Recommendation + +Use a two-column operational detail: + +```text +left: negotiation and obligation structure +right: protected-action lifecycle and terminal evidence +``` + +The top banner should answer: + +```text +Agreement accepted. Authority not created until each obligation clears. +``` + +The first x402 fixture should show "accepted offer" and "payment action +cleared/refused" as separate rows. diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/DEVEX.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/DEVEX.md new file mode 100644 index 0000000..e68fc77 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/DEVEX.md @@ -0,0 +1,63 @@ +# DevEx Review: A2A Negotiation + +Status: PASS_WITH_FIRST_PROOF_REQUIREMENT + +## Invariant At Stake + +Developers should not need to learn the full kernel to prove the first A2A +path, but the quickstart must not hide the authority boundary. + +## First Developer Job + +An agent builder wants to let a buyer agent accept a seller agent's paid API +offer without giving either agent raw spend authority. + +## First Proof Path + +```text +npm install handshake-protocol-kernel +-> run A2A x402 fixture +-> see accepted offer create no authority +-> bind obligation to x402_payment.exact ActionContract +-> see policy greenlight/refusal +-> see gateway pass/refuse before signer use +-> inspect receipt/refusal/proof-gap readback +``` + +## Required Developer Artifacts + +- one fixture JSON input; +- one fixture Markdown output; +- one support/readback packet; +- one CLI or test command that runs the fixture; +- one failure fixture for stale/changed params; +- one failure fixture for accepted offer without binding. + +## P0/P1 Findings + +P0: A developer must not be asked to assemble protocol records manually for the +first proof. Provide a fixture runner or helper facade. + +P0: Quickstart copy must say "proposal/evidence only" until policy/gateway +transitions are run. + +P1: If the first proof requires hosted operation, customer custody, registry +listing, or cross-org trust, adoption stalls. Keep it local/reference first. + +P1: Errors need reason codes, not prose-only failures. + +## DevEx Recommendation + +Add an example package path before broad API design: + +```text +examples/a2a-negotiated-x402/ + input/ + output/latest.json + output/latest.md + run.ts + README.md +``` + +Then add CLI only after the fixture proves stable. Do not expose public package +root helpers until package-surface tests prove the intended boundary. diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/ENGINEERING.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/ENGINEERING.md new file mode 100644 index 0000000..1d8777c --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/raw/ENGINEERING.md @@ -0,0 +1,98 @@ +# Engineering Review: A2A Negotiation + +Status: PASS_WITH_P0_GATES + +## Invariant At Stake + +The protocol extension must be additive and non-authority. Negotiation records +may coordinate obligations, but only `ActionContract`, policy, greenlight, +gateway, and receipt/refusal/proof-gap transitions control consequence. + +## Architecture Verdict + +Add a new protocol area: + +```text +src/protocol/areas/negotiation/ +``` + +Do not mutate `ActionContract` into a negotiation object. Use +`clearingEvidenceRefs.obligationRef` and `counterpartyRef` to connect the +contract to negotiated evidence. + +## Required Schemas + +- `NegotiationSession` +- `NegotiationOffer` +- `NegotiationDecision` +- `LinkedAgreement` +- `AgreementObligationBinding` +- `AgreementStatusTransition` + +Every schema must include tenant/org scope, digest fields, status fields, +expiry where relevant, evidence refs, non-secret summaries, and explicit +authority flags or non-authority posture. + +## Required Events + +- `negotiation_session_opened` +- `negotiation_offer_recorded` +- `negotiation_decision_recorded` +- `linked_agreement_recorded` +- `agreement_obligation_bound` +- `agreement_status_changed` + +## Required Transition Guards + +- one accepted offer per linked agreement; +- accepted offer digest must match linked agreement accepted terms digest; +- obligation binding must match action contract digest; +- responsible party must match principal/agent or accepted participant binding; +- counterparty must match `clearingEvidenceRefs.counterpartyRef`; +- expired, withdrawn, disputed, revoked, or superseded agreement cannot back a + greenlight; +- binding cannot broaden amount, resource, method, endpoint, credential, + gateway, or action type beyond accepted terms; +- agreement status changes must be monotonic or explicitly superseding. + +## P0/P1 Findings + +P0: Cross-org dependencies cannot reuse current same-org sequence dependency +logic. Treat cross-org trust as proof gap until a separate trust model exists. + +P0: A single agreement must not authorize multiple mutations. Each obligation +binding must reference one exact contract, and each greenlight remains one-use. + +P0: Policy must refuse stale or mismatched agreement state before greenlight. + +P1: Object-registry posture must be `transition_evidence` and `audit_read`. +Raw transcript text and secret terms should not be raw-readable. + +P1: Event projections must reconstruct the chain without reading internal-only +stream events directly. + +## Required Tests + +- schema parse/refuse tests; +- transition lifecycle tests; +- no-authority acceptance test; +- obligation binding digest mismatch tests; +- policy refusal tests for expired/withdrawn/disputed/superseded agreements; +- x402 changed parameter and replay refusal tests; +- evidence projection redaction tests; +- root export and package surface tests. + +## Engineering Recommendation + +Implement in seven slices: + +1. schemas and object registry; +2. transition lifecycle; +3. obligation binding; +4. policy hook; +5. x402 fixture; +6. readback projections; +7. audits and claim gates. + +Do not add package root exports until package-surface tests define the intended +public boundary. diff --git a/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/source-snapshot.md b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/source-snapshot.md new file mode 100644 index 0000000..febfd45 --- /dev/null +++ b/.planning/macro-plan/runs/20260526T000830Z-a2a-negotiation-end2end/source-snapshot.md @@ -0,0 +1,67 @@ +# A2A Negotiation Source Snapshot + +Run: `20260526T000830Z-a2a-negotiation-end2end` + +## Worktree Posture + +Branch: `codex/architectural-north-star-simplification` + +The worktree is already heavily dirty with unrelated tracked and untracked work +across `.planning/`, docs, examples, CLI, HTTP, protocol, runtime, storage, +surfaces, x402 protected-tool code, and tests. This run must not revert, +normalize, or stage unrelated edits. + +`.planning/` is ignored by `.gitignore`. New planning files under `.planning/` +must be force-added if the user wants them committed. + +## Canonical Current Anchors + +- `AGENTS.md`: governing invariant that rendered plans, generated code, and + agreement-like artifacts are not authority. +- `README.md`: product kernel, current x402 wedge, MCP proposal/evidence + boundary, package posture, and non-claims. +- `docs/internal/decisions.md`: current product kernel, proof ledger, + expansion admission, and launch-gate posture. +- `docs/internal/protocol-kernel-architecture.md`: protocol transition map, + extension boundary, and bilateral ecosystem note. +- `docs/internal/protocol-layman.md`: plain-language bilateral ecosystem + explanation. +- `src/protocol/foundation/schema-core.ts`: `clearingEvidenceRefs` already + includes `correlationRef`, `obligationRef`, and `counterpartyRef`. +- `src/protocol/events/schemas.ts`: source-owned contract event enum. +- `src/protocol/areas/object-registry/`: object export posture and raw-read + posture. +- `src/protocol/kernel.ts`: transition facade. +- `src/protocol/areas/action-contract/`: exact proposed commitment. +- `src/protocol/areas/policy-greenlight/`: policy decisions, greenlights, and + sequence dependency handling. +- `src/protocol/areas/gateway-gate/`: final enforcement before consequence. + +## Existing Source Truth For Bilateral Operation + +Current docs already permit future negotiation and linked agreements, with the +hard cut line that each party's obligation must still become its own normal +`ActionContract`, policy decision, greenlight, gateway check, and +receipt/refusal/proof-gap chain. + +The current protocol is not a marketplace, escrow system, settlement layer, +legal-contract system, reputation layer, dispute-resolution system, or generic +A2A protocol. + +## Current Non-Proofs + +- No implemented `negotiation` protocol area exists. +- No `LinkedAgreement` or `AgreementObligationBinding` schema exists. +- No negotiation event types exist in `ContractStreamEventSchema`. +- No policy hook validates agreement-backed obligations. +- No cross-org trust model exists. +- No A2A x402 fixture exists. +- No readback projection links agreement -> obligation -> contract -> policy + -> gateway -> terminal outcome. +- No launch claim may say Handshake supports A2A negotiation today. + +## Existing Useful Seam + +`clearingEvidenceRefs.obligationRef` and `counterpartyRef` are the right bridge +from a negotiated obligation to an `ActionContract`. The extension should use +that seam before adding new authority-bearing concepts. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-cli-mcp-publish-readiness/cli-mcp-publish-readiness-20260524T010000Z/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-cli-mcp-publish-readiness/cli-mcp-publish-readiness-20260524T010000Z/PLAN.md deleted file mode 100644 index 5dc4109..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-cli-mcp-publish-readiness/cli-mcp-publish-readiness-20260524T010000Z/PLAN.md +++ /dev/null @@ -1,69 +0,0 @@ -# CLI/MCP Publish Readiness Plan - -## Goal - -Bring the CLI and MCP Tier 2 surfaces to publishable package posture without reopening the Tier 1 kernel or implying that CLI/MCP authorize, gate, mutate, certify, settle, or host anything. - -## External Source Inputs - -- npm package metadata: `private: true` blocks publication, `bin` entries become PATH-installed executables, and package files must be verified through dry-run packaging. -- MCP Registry package rules: npm packages use `registryType: "npm"` in `server.json`, the official registry points to public npm artifacts, and `package.json#mcpName` must match `server.json#name`. -- MCP TypeScript SDK posture: stdio is the right local process transport for local MCP integrations, and the official client/server SDK can exercise tools/resources over stdio. -- MCP security posture: local MCP servers are local code execution surfaces, so the exact command must be inspectable and the server must avoid token passthrough, hosted auth claims, raw credential material, and ambient authority. - -## Success Criteria - -- `package.json` is publishable and no longer marked private. -- Node users import bundled ESM from `dist`; Bun local development can still use source through the `bun` export condition. -- `handshake` is a bundled Node CLI that emits the existing false-authority JSON envelope. -- `handshake-mcp` is a bundled Node stdio MCP server that exposes only the x402 proposal/evidence tool/resource surface. -- The package-name bin `handshake-protocol-kernel` points to the MCP server so npm/MCP package installation has a server-shaped default executable. -- `server.json` and `package.json#mcpName` are synchronized for MCP Registry publication. -- Package checks prove the npm dry-run includes source, generated types, bundled JS, bins, MCP metadata, and compact canon while excluding `.planning`, tests, scratch, old docs trees, and workspace junk. -- Published entrypoint checks spawn the actual package bins with Node and exercise CLI schema plus MCP stdio list/read/call through the official MCP client SDK. -- Claims remain explicit: CLI and MCP are evidence/proposal posture only, with no policy decision, greenlight, gateway check, mutation, receipt export, authority certificate minting, hosted operation, provider custody, settlement, broad MCP protection, or clearing-house posture. - -## Non-Goals - -- No hosted control plane. -- No hosted MCP server or process supervisor. -- No provider custody, wallet custody, signer export, payment settlement, facilitator operation, seller middleware, aggregate spend ledger, marketplace, certification, or cross-org trust. -- No new authority routes or Tier 1 schema changes. -- No CLI mutation command, gateway runner, receipt exporter, raw record dump, or certificate minter. -- No broad MCP/browser/shell/network/package-manager/cloud/repo interception claim. - -## Mechanism - -1. Package boundary - - Remove `private: true`. - - Add `license: "UNLICENSED"` until the owner chooses an open-source license. - - Add `bin` entries for `handshake`, `handshake-mcp`, and `handshake-protocol-kernel`. - - Add `./cli` and `./mcp` subpaths without exporting them from package root. - -2. Build boundary - - Keep declarations from `tsc`. - - Add `scripts/build-package-bundles.mjs` to bundle public imports and bins with `bun build --target=node --format=esm`. - - Keep thin Node shebang wrappers under `bin/`. - -3. MCP registry boundary - - Add `server.json` for `io.github.joelchan/handshake-protocol-kernel`. - - Keep server description negative about authority, gateway checks, mutations, receipt export, certificates, provider custody, hosted operation, and broad MCP protection. - -4. Verification boundary - - Extend package surface tests and dry-run checks. - - Add `scripts/check-published-entrypoints.mjs` to run `node bin/handshake schema` and connect to `node bin/handshake-mcp` using the official MCP client SDK. - - Keep architecture tests proving CLI/MCP stay off root and away from policy/gateway/signer/receipt/certificate authority. - -## Closeout Gates - -```bash -npm run test -- test/architecture/claim-boundary.test.ts test/architecture/package-surface.test.ts test/architecture/root-exports.test.ts -npm run pack:check -npm run quality:claims -npm run quality:architecture -npm run check:repo -``` - -## Residual External Action - -Actual publication still requires owner-held external credentials: npm login/publish and MCP Registry namespace authentication. Source publish-readiness means the artifact is shaped, tested, and claim-bounded for those actions; it does not mean the package was published during this goal. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-cli-mcp-publish-readiness/cli-mcp-publish-readiness-20260524T010000Z/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-cli-mcp-publish-readiness/cli-mcp-publish-readiness-20260524T010000Z/VALIDATION.md deleted file mode 100644 index 086d6a8..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-cli-mcp-publish-readiness/cli-mcp-publish-readiness-20260524T010000Z/VALIDATION.md +++ /dev/null @@ -1,72 +0,0 @@ -# CLI/MCP Publish Readiness Validation - -Status: closed source-owned implementation validation. - -## Scope - -This validation covers the publish-readiness goal for the Tier 2 CLI and MCP -surfaces only. It does not close hosted operation, provider custody, gateway -operation, receipt export, authority certificate minting, broad MCP protection, -SDK distribution, marketplace/certification, or cross-org trust. - -## External Inputs Applied - -- npm package metadata and bin behavior: package publication requires the package - not be private, package bins are installed as command executables, and the - package payload must be inspected by dry-run packaging. -- MCP Registry package metadata: `server.json` names the MCP server, - `package.json#mcpName` matches that server name, and the package entry points - to an npm stdio transport. -- MCP SDK and transport posture: the local MCP server is exercised by the - official MCP TypeScript client over stdio. -- MCP security posture: the server remains local code execution posture and - therefore exposes only proposal/evidence tools/resources, with no token, - credential, mutation, gateway, or hosted authority path. - -## Requirement-by-Requirement Audit - -| Requirement | Result | Evidence | -| --- | --- | --- | -| Publishable package metadata | Pass | `package.json` has no `private: true`, has package description/license/keywords/engines, and exposes only explicit package subpaths. | -| CLI package command | Pass | `bin/handshake` is a Node wrapper for bundled `dist/bin/handshake.mjs`; `node bin/handshake schema` is exercised by `scripts/check-published-entrypoints.mjs`. | -| MCP package command | Pass | `bin/handshake-mcp` and package-name bin `handshake-protocol-kernel` point to bundled MCP stdio server code. | -| MCP Registry metadata | Pass | `server.json#name`, `package.json#mcpName`, npm package identifier, version, and stdio transport are synchronized by tests and package-entrypoint check. | -| Root export boundary | Pass | CLI and MCP are available only through explicit `./cli` and `./mcp` package subpaths and stay off the package root. | -| Authority boundary | Pass | CLI/MCP command tests, claim tests, and posture tests forbid policy, greenlight, gateway check, mutation, receipt export, certificate minting, raw records, signer custody, and credential material. | -| Package payload | Pass | `npm run pack:check` confirms package dry-run includes bins, source, generated declarations, bundled JS, MCP metadata, README/QUALITY/STRUCTURE, and compact internal docs while excluding `.planning`, tests, scratch, and old docs trees. | -| Published entrypoint smoke | Pass | `scripts/check-published-entrypoints.mjs` spawns actual Node package bins, runs CLI schema, connects to MCP stdio through the official MCP client SDK, lists tools, reads metadata, calls the x402 proposal tool, and checks false-authority fields. | -| npm publish dry-run | Pass | `npm publish --dry-run --access public --cache /tmp/handshake-npm-cache` exits 0, includes 541 files, and reports the publish action as a dry run. | -| Demo evidence | Pass | `npm run demo:mcp-transcript` regenerates the source-owned MCP transcript; `npm run demo:self-hosted` passes `aps_x402_exact_path`, `cli_readbacks`, `mcp_reference_transcript`, and `mcp_stdio_process`. | - -## Gates Run - -```bash -npm run demo:mcp-transcript -npm run demo:self-hosted -npm run pack:check -npm publish --dry-run --access public --cache /tmp/handshake-npm-cache -npm run quality:claims -npm run quality:architecture -npm run check:repo -``` - -Observed closeout: - -- `npm run quality:claims`: 4 pass, 0 fail. -- `npm run quality:architecture`: 61 pass, 0 fail. -- `npm run check:repo`: 448 pass, 0 fail; package surface check passed with 541 files. -- `npm publish --dry-run --access public --cache /tmp/handshake-npm-cache`: dry-run publish of `handshake-protocol-kernel@0.2.4` succeeded with 541 files. - -## Publish Boundary - -The source artifact is publish-ready under the Tier 2 boundary. Actual external -publication still requires owner-held credentials for npm and MCP Registry -namespace authentication. That external account action is not performed by this -validation and does not create a Handshake authority claim. - -## Residual Product Boundary - -CLI/MCP are now publishable proposal/evidence surfaces. They are not execution -gates. The next product mechanism must remain adapter/runtime hardening or -operator adoption over this package boundary, not a claim that MCP or CLI -itself enforces protected mutations. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/ASSUMPTIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/ASSUMPTIONS.md deleted file mode 100644 index b4fe64b..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/ASSUMPTIONS.md +++ /dev/null @@ -1,17 +0,0 @@ -# Assumptions - -| ID | Assumption | Confidence | Evidence | Invalidation Trigger | -| --- | --- | --- | --- | --- | -| A1 | Tier 1 protocol/kernel primitives remain stable and should not be reopened for this concern-elimination work. | High | User constraint and raw perspectives agree that Tier 2 surfaces strengthen around the kernel. | A source task requires new protocol semantics rather than new adapter/runtime/MCP refusal behavior. | -| A2 | Runtime posture propagation is the nearest defect and must be fixed before registry extraction. | High | `RuntimeIngressObservedDispatchSchema` accepts posture fields while `x402PaymentAttemptForDispatch()` omits them. | A failing test shows another path creates authority before this bug can be exercised. | -| A3 | Runtime may record proposal/refusal evidence but must not issue policy, greenlights, gateway checks, mutations, receipts, receipt exports, signer evidence, or authority certificates. | High | `src/runtime/LANE.md` and user constraints. | Runtime lane contract is explicitly changed by the user and enforced in canon. | -| A4 | MCP can require explicit request-body and provider-environment posture fields instead of defaulting omitted fields to local safe posture. | Medium | Strict schema already rejects unknown fields and raw perspectives prefer explicit posture. | Existing external MCP callers must remain backwards compatible under a declared compatibility contract. If so, omission must still refuse or remain non-contractable. | -| A5 | Direct x402 adapter refusal reason codes are sufficient for runtime/MCP parity. | High | Existing `x402PaymentAttemptRefusalReasonCodes()` covers amount, official evidence, body posture, digest mismatch, and provider environment. | New source checks reveal missing reason codes for a posture case that can reach contract proposal. | -| A6 | Adding posture/ref to idempotency material is acceptable for new proposals and must not rewrite historical receipts. | High | Raw perspectives identify deterministic binding drift; old evidence remains reconstructable by stored records. | A package or replay contract requires stable legacy idempotency keys for active persisted records. | -| A7 | Local sandbox evidence is useful only as local/reference downstream fixture observation. | High | `sandbox-http.ts`, x402 demo, and perspectives all classify it as non-authority. | A separate seller/facilitator adapter with settlement proof is implemented and tested. | -| A8 | Session/day/review spend fields remain metadata until a reservation ledger exists. | High | `spendWindowEnforcementStatus: "not_enforced_local_metadata"` is present in source/tests and concerns. | A ledger phase introduces tenant/org/principal/agent/action/resource/window reservations with conflict and recovery evidence. | -| A9 | Signer custody remains local/reference or fixture-gateway evidence only. | High | Current wallet gateway uses injected signer after `VerifiedGatewayCheck`; no provider/vault lifecycle exists. | A real provider custody resolver with rotation, revocation, failure, and redaction tests lands. | -| A10 | Host-wide interception cannot be claimed from runtime/MCP evidence alone. | High | Runtime/MCP lanes are proposal/evidence only and no host-specific harness exists. | A concrete browser/shell/package/cloud/repo/MCP host harness with bypass probes is added. | -| A11 | Projection scale/redaction can be improved without claiming hosted audit/search. | Medium | Current store/projection boundaries can add scoped reads and redaction tests. | The implementation would require product or hosted architecture choices not in this macro. | -| A12 | Package/public readiness can be validated only through build, pack, and entrypoint smoke gates, not through dirty TypeScript source alone. | High | `pack:check` rebuilds and runs package surface scripts. | The repository removes bundled package artifacts and publishes directly from source under a new process. | -| A13 | `.planning/` must remain scratch even when it contains accurate concern maps. | High | User constraints and canon state `.planning/` is not repo-facing truth. | A user explicitly promotes a planning artifact into canonical docs after source validation. | diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/CONTEXT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/CONTEXT.md deleted file mode 100644 index 53b03af..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/CONTEXT.md +++ /dev/null @@ -1,89 +0,0 @@ -# Macro Context - -## Target - -Create an executable implementation plan that eliminates the current `.planning/codebase/CONCERNS.md` concern set through source mechanisms, tests, and gates, not documentation-only closure. - -## Run - -- Run id: `concerns-elimination-20260524T044836Z` -- Date: 2026-05-24 -- Role: CHAIR synthesis -- Output scope: `.planning/macro/*` and `.planning/macro/runs/concerns-elimination-20260524T044836Z/synthesis.md` - -## Invariant - -No consequential autonomous action executes outside declared bounds, and divergent behavior must be haltable, isolatable, and reconstructable. - -## Canon - -Canonical repo truth lives in: - -- `AGENTS.md` -- `README.md` -- `QUALITY.md` -- `STRUCTURE.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-notes.md` - -`.planning/` is scratch. It can identify concerns and implementation order, but it must not become a package surface, exported symbol, script name, CI name, public docs authority, or implementation namespace. - -## Input Packet - -The chair read: - -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/input.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/STRATEGY.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/ARCH.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/EXECUTION.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/RISK.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/ADOPTION.md` -- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/plan-contract.md` - -The chair also performed a narrow source check against `.planning/codebase/CONCERNS.md`, `package.json`, `src/runtime/ingress/index.ts`, `src/mcp/x402-proposal.ts`, `src/runtime/LANE.md`, `src/mcp/LANE.md`, `src/adapters/x402-payment/action-proposal.ts`, `src/adapters/x402-payment/sandbox-http.ts`, and `src/protocol/evidence-projections/projections.ts`. - -## Current Dirty Worktree From Input Packet - -These files were observed dirty before planning and are treated as current worktree state to validate, not as committed proof: - -- `README.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-notes.md` -- `examples/x402-protected-spend/README.md` -- `examples/x402-protected-spend/run.ts` -- `src/adapters/x402-payment/action-proposal.ts` -- `src/adapters/x402-payment/index.ts` -- `src/adapters/x402-payment/upstream-evidence.ts` -- `src/adapters/x402-payment/wallet-gateway.ts` -- `src/protocol/evidence-projections/projections.ts` -- `src/protocol/foundation/reason-codes.ts` -- `src/runtime/ingress/index.ts` -- `test/adapters/x402-payment-action-proposal.test.ts` -- `test/adapters/x402-wallet-gateway.test.ts` -- `test/product/x402-protected-spend-demo-report.test.ts` -- `src/adapters/x402-payment/sandbox-http.ts` - -## Source Observations - -- Runtime schema already accepts x402 body/provider posture fields, but `x402PaymentAttemptForDispatch()` does not forward `intendedRequestBodyPosture`, `providerEnvironmentPosture`, or `providerEnvironmentRef`. -- Direct x402 adapter parameters include body/provider posture, but idempotency material currently needs explicit posture/ref binding to prevent equivalence drift. -- MCP x402 proposal schema has `intendedRequestBodyDigest` but lacks explicit body posture and provider-environment posture/ref. -- MCP lane documentation forbids policy, gateway, signer, storage, receipt, all-role SDK, and certificate authority imports. -- Runtime lane documentation says runtime may observe and propose, but must not issue policy, greenlights, gateway checks, receipts, mutation attempts, provider enforcement, or production proof. -- Local x402 sandbox already has refusal reason codes for missing signature evidence, wrong header, non-reference environment, and ambiguous body posture, but it needs a stronger typed evidence boundary to prevent settlement/facilitator/custody overread. -- Projection redaction is pattern-based and must be hardened before hosted/provider claims. -- `package.json` already has `quality:claims`, `quality:architecture`, `quality:storage`, `pack:check`, `demo:aps`, `demo:mcp-transcript`, and `check:repo` gates. - -## Required Implementation Order - -1. Runtime posture propagation and pre-contract refusal. -2. MCP posture parity while staying proposal/evidence only. -3. Local sandbox signed-retry evidence boundary. -4. Runtime family registry/refactor hardening. -5. x402 future-surface, spend metadata, custody, and host-bypass guardrails. -6. Evidence projection scale/redaction mechanisms. -7. Package, `.planning`, demo, and closeout gates. - -No user-owned decision blocks starting this plan. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/DECISIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/DECISIONS.md deleted file mode 100644 index 0495b7a..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/DECISIONS.md +++ /dev/null @@ -1,46 +0,0 @@ -# Decisions - -## Accepted - -- D1: Runtime x402 posture propagation is first. The plan starts with failing runtime tests and a source patch to forward body/provider posture into the x402 attempt. -- D2: Runtime refusal must be pre-contract. Unsupported, omitted, external, live, or unknown x402 posture cannot produce an `ActionContract`. -- D3: Direct x402 idempotency material must include request-body posture, provider-environment posture, and provider-environment ref for new proposals. -- D4: MCP posture parity is second. MCP must carry or refuse the same posture boundary as the direct adapter/runtime path while staying proposal/evidence only. -- D5: MCP schema should require explicit posture fields. Missing posture is schema-invalid or structured pre-contract refusal, never silent local-reference defaulting. -- D6: Sandbox signed retry is local/reference downstream fixture evidence only. It is not settlement, facilitator operation, seller middleware, provider custody, gateway authority, or mutation proof. -- D7: Runtime family registry extraction waits until posture propagation tests pass. The refactor is a hardening phase, not the first fix. -- D8: Spend-window controls remain metadata in this macro. Guard the claim instead of building a partial ledger. -- D9: Custody, hosted verifier, host-wide interception, publication, and broad x402 surfaces are future cuts with tests and claim gates. -- D10: Package/public readiness requires `npm run pack:check`; dirty source and checked-in `dist/` are not proof by themselves. - -## Rejected - -- R1: Do not close concerns through docs-only or copy-only edits. -- R2: Do not make runtime/MCP import wallet gateway, signer, storage, policy, gateway, receipt, all-role SDK, or certificate authority code to achieve parity. -- R3: Do not add a runtime-side aggregate spend sum as a substitute for a real reservation ledger. -- R4: Do not use the sandbox signed retry as evidence of seller middleware, facilitator operation, settlement finality, provider custody, or live paid HTTP operation. -- R5: Do not broaden `x402_payment.exact` to `upto`, batch settlement, lifecycle hooks, signed offers, signed receipts, MCP auto-pay, or seller/facilitator surfaces. -- R6: Do not treat runtime/MCP bypass posture as broad host interception. -- R7: Do not claim npm/MCP Registry publication from source-owned package gates. - -## Deferred - -- F1: Aggregate spend reservation ledger with tenant/org/principal/agent/action/resource/window keys, conflicts, recovery, D1 persistence, and receipt evidence. -- F2: Provider/customer custody with vault resolver, rotation, revocation, gateway failure, and provider-specific redaction tests. -- F3: Hosted verifier with JWKS, revocation, cross-org trust, retention, and operational deployment proof. -- F4: Host-specific bypass interception for browser, shell, package manager, cloud API, repo, network, database, and sibling MCP tools. -- F5: Seller middleware, facilitator operation, settlement finality, and broader x402 action classes. -- F6: Actual npm and MCP Registry publication with owner-held credentials. -- F7: Dedicated support-bundle expansion beyond existing non-authority diagnostic surfaces. - -## User-Owned - -No user-owned decision blocks the implementation plan. - -Future user-owned choices: - -- Whether to fund the aggregate spend ledger. -- Which live custody provider or vault should be first. -- Which host/runtime deserves first real bypass-interception proof. -- Whether and when to publish to npm or MCP Registry with owner credentials. -- Whether to broaden x402 beyond exact buyer-side payment after the first wedge survives closeout. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/PLAN.md deleted file mode 100644 index a28d1f5..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/PLAN.md +++ /dev/null @@ -1,253 +0,0 @@ -# Plan - -## Goal - -Invariant at stake: no x402 proposal surface may create a cleaner contract than the protected path actually observed, and no evidence surface may imply authority, custody, settlement, hosted operation, broad interception, or aggregate spend enforcement that the gateway does not enforce. - -Eliminate the current codebase concerns by strengthening source mechanisms, regression tests, and closeout gates. The plan preserves the Tier 1 kernel as stable protocol meaning, strengthens Tier 2 surfaces around it, keeps runtime/MCP/CLI proposal or evidence only, and keeps x402 as the exact buyer-side first wedge unless future work is explicitly cut. - -## Non-Goals - -- Do not redesign Tier 1 protocol primitives, state machines, canonicalization, or receipt meaning. -- Do not move policy decisions, greenlights, gateway checks, mutation attempts, receipts, receipt export, signer custody, or authority certificate minting into runtime, MCP, CLI, demos, or review output. -- Do not implement an aggregate spend reservation ledger in this macro. -- Do not claim provider/customer custody, live provider operation, hosted verifier, JWKS/revocation, marketplace, certification, or clearing-house readiness. -- Do not claim seller middleware, facilitator operation, settlement finality, signed offers, signed receipts, `upto`, batch settlement, lifecycle hooks, or MCP auto-pay. -- Do not claim broad host interception across browser, shell, package manager, cloud API, network, database, repo, sibling MCP, or unwrapped tools. -- Do not treat `.planning/` as canon or close concerns through documentation-only edits. -- Do not claim npm or MCP Registry publication; package validation stops at source-owned build, pack, and entrypoint smoke gates. - -## Source Boundary - -Canonical repo truth remains `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, and `docs/internal/*`. `.planning/` is scratch and may guide implementation only when reconciled against source and tests. - -This plan was synthesized from: - -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/input.md` -- raw STRATEGY, ARCH, EXECUTION, RISK, and ADOPTION perspective outputs for the same run -- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/plan-contract.md` -- `.planning/codebase/CONCERNS.md` -- narrow source checks of the named runtime, MCP, x402 adapter, sandbox, projection, lane, package, and test files - -The dirty worktree listed in the input packet is current state, not validated closure and not something this plan assumes should be reverted. - -## Current State - -The nearest proven bug is runtime x402 posture loss. `RuntimeIngressObservedDispatchSchema` accepts `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef`, but `x402PaymentAttemptForDispatch()` forwards only `intendedRequestBodyDigest` and `selectedHeadersDigest`. `X402PaymentAttemptSchema` then defaults missing posture to `no_body` and `local_reference_sandbox`, which can turn observed unsupported, omitted, external, live, or unknown posture into a contractable local-reference attempt. - -The MCP x402 proposal schema currently lacks `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef`. `x402Parameters()` and `deriveMcpX402IdempotencyKey()` therefore cannot bind the same request/body/provider boundary as the direct adapter path. MCP is still proposal/evidence only, but its proposal shape can teach weaker semantics. - -The x402 sandbox is a local/reference fixture. It can emit official-shaped payment-required evidence and observe one signed retry after gateway-created signature evidence. Existing fields such as `authorityCreated: false` are necessary but not enough to prevent seller middleware, facilitator settlement, or payment-finality overread. - -Runtime ingress is still a monolithic cross-family module. That is a real maintainability risk, but refactoring it before the posture bug is fixed can preserve the bug behind a cleaner abstraction. - -Spend session/day/review controls are metadata only. Signer custody is local/reference or fixture-gateway evidence only. Runtime/MCP bypass evidence is scoped observed evidence only. Evidence projections and D1 reads are good local diagnostic proof, not hosted evidence-scale proof. Package surfaces are publishable only after build/pack gates. - -## Target State - -Runtime x402 dispatches either bind exact observed body/provider posture into the resulting candidate parameters and idempotency material or refuse before any action contract is proposed. Refusals preserve runtime/graph evidence where possible, but create no authority-bearing records. - -MCP x402 proposals require explicit request-body and provider-environment posture. Accepted MCP proposals bind the posture fields into parameters, non-secret summaries, tool-call drafts, compile-intent candidate material, and idempotency derivation. Unsupported, omitted, external, live, or unknown posture returns structured non-authority refusal or schema failure before runtime-client contract proposal. - -Sandbox challenge and signed-retry evidence carries an explicit local/reference downstream-fixture boundary. Signed retry evidence is post-gate observation only, with no seller middleware, facilitator operation, settlement finality, provider custody, or authority claim. - -Runtime family proposal code sits behind a source-owned family registry after the hotfix, so new families cannot silently drop refusal-critical fields. The registry remains proposal-only and cannot import or issue policy, greenlight, gateway, mutation, receipt, storage, signer, or certificate authority. - -Future surfaces are guarded by source-owned conformance, claim, package, and architecture tests. Ledger, live custody, hosted verifier, host-wide interception, seller/facilitator operation, registry publication, and broader x402 compatibility stay explicit cuts until separate phases implement them fully. - -## Assumptions - -- No user-owned decision blocks implementation of runtime posture propagation, MCP posture parity, sandbox evidence boundaries, registry hardening, and cut-line guards. -- The current dirty files are live worktree state to validate, not a baseline to revert. -- Existing Tier 1 primitives and reason-code registry can represent these refusals without introducing new kernel concepts. -- MCP schema strictness can require explicit posture fields; omitted posture is not silently normalized to safe local posture. -- Aggregate spend controls remain metadata until a real reservation ledger is designed and implemented. -- Provider/customer custody, hosted verifier, and host-wide interception cannot be validated from current source and must remain future cuts. - -## Decisions - -- Fix the runtime posture propagation defect first, before runtime registry extraction. -- Reuse direct adapter x402 refusal semantics for runtime and MCP parity; do not fork a weaker MCP-specific contract model. -- Require explicit MCP request-body and provider-environment posture fields. Missing posture is schema-invalid or structured pre-contract refusal, never silent local-reference defaulting. -- Add posture fields to x402 idempotency material so equivalent-looking contracts cannot hide different body/provider posture. -- Treat the local x402 sandbox as downstream local/reference fixture evidence only. -- Extract runtime ingress family adapters only after the posture hotfix is covered by tests. -- Keep spend windows, custody, hosted verifier, host interception, facilitator/seller middleware, and publication as cut/future items with guards, not partial implementation inside this macro. - -## Phases - -Phase 1: Runtime x402 posture propagation and refusal boundary. - -Implement failing tests first in `test/runtime/runtime-ingress.test.ts` and `test/adapters/x402-payment-action-proposal.test.ts`. Patch `src/runtime/ingress/index.ts` so `x402PaymentAttemptForDispatch()` forwards `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef`. Patch `src/adapters/x402-payment/action-proposal.ts` so direct x402 idempotency material includes request-body posture, provider-environment posture, and provider-environment ref. If runtime currently throws before recording refusal, add a narrow source-owned preflight/refusal helper so unsupported posture becomes `one_or_more_dispatches_refused` without an action contract. - -Acceptance: - -- Unsupported/omitted body posture and external/live/unknown provider posture refuse before action-contract proposal. -- Digest-bound local-reference posture binds posture, body digest, provider posture/ref, selected headers digest, and official evidence fields into candidate parameters. -- Refused runtime cases create no policy decision, greenlight, gateway check, mutation attempt, receipt, receipt export, or authority certificate. - -Phase 2: MCP x402 posture parity while staying proposal/evidence only. - -Patch `src/mcp/x402-proposal.ts` to require `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and nullable `providerEnvironmentRef`. Add MCP-local pre-contract refusal or schema failure for omitted, unsupported, external, live, and unknown posture before runtime-client proposal calls. Bind accepted posture fields into `x402Parameters()`, tool-call draft parameters, non-secret summaries, compile-intent candidate parameters, and `deriveMcpX402IdempotencyKey()`. Update MCP schema fixtures, reference transcript, stdio process smoke, and `scripts/check-published-entrypoints.mjs`. - -Acceptance: - -- MCP cannot propose a weaker x402 contract than the direct adapter/runtime path. -- MCP outputs retain `authorityCreated: false`, `greenlightCreated: false`, `gatewayCheckPerformed: false`, `mutationAttempted: false`, `receiptExportCreated: false`, and `authorityCertificateMinted: false`. -- MCP imports remain inside the lane boundary and do not pull adapter, wallet, signer, storage, policy, gateway, receipt, all-role SDK, or certificate authority code. - -Phase 3: Local sandbox evidence boundary. - -Patch `src/adapters/x402-payment/sandbox-http.ts`, `src/adapters/x402-payment/wallet-gateway.ts`, `src/protocol/evidence-projections/projections.ts`, and the x402 demo/report tests so challenge and signed-retry outputs carry an explicit evidence boundary: local/reference fixture scope, post-gate signed retry observation, not settlement finality, not seller middleware, not facilitator operation, not provider custody, and not authority. Keep signed retry recording gated on gateway-created signature evidence, local-reference provider posture, and non-ambiguous body posture. - -Acceptance: - -- Sandbox challenge and retry evidence cannot be serialized as settlement, seller middleware, facilitator operation, provider custody, or authority. -- Replay, missing signature evidence, wrong signature header, non-reference provider posture, and ambiguous body posture do not increment signed retry counts. -- Demo reports keep `x402_paid_http_call.exact` as buyer-readable proof-object language only, not an action catalog entry. - -Phase 4: Runtime ingress registry/refactor hardening. - -After Phase 1 passes, extract runtime family conversion into a source-owned registry under `src/runtime/ingress/` while preserving `proposeRuntimeIngressActionContracts()` behavior. The registry should own per-family dispatch coverage, config requirements, compile-input construction, preflight refusal reason codes, signing secret selection, grammar version, and raw-bypass reason codes. It must not own authority. - -Acceptance: - -- Package install, auth.md protected API call, and x402 runtime cases pass unchanged through the registry. -- Every supported dispatch kind maps to exactly one family adapter. -- Missing family config fails closed. -- Architecture tests forbid registry imports of policy, greenlight, gateway, storage implementation, mutation, receipt, signer, or certificate authority code. - -Phase 5: x402 cut-line guards for spend, custody, host bypass, and future surfaces. - -Patch conformance, install proposal, bypass probe, demo, and claim tests so unsupported x402 surfaces remain explicit source-owned cuts. Keep session/day/review bounds under `spendWindowEnforcementStatus: "not_enforced_local_metadata"`. Distinguish fixture gateway custody from provider/customer custody. Keep runtime/MCP bypass posture scoped and non-host-wide. - -Acceptance: - -- `upto`, batch settlement, lifecycle hooks, MCP auto-pay, signed offers, signed receipts, seller middleware, facilitator operation, aggregate spend ledger, live custody, hosted verifier, host-wide interception, and registry publication are classified as unsupported/future unless separate source mechanisms exist. -- Spend-window metadata never enters action-contract bounds as enforced aggregate control. -- Claims tests fail on broader x402 compatibility, custody, hosted, settlement, host-wide interception, or aggregate-spend enforcement language. - -Phase 6: Evidence projection scale and redaction mechanisms. - -Patch `src/protocol/store/port.ts`, memory/D1 storage, `migrations/0001_protocol_kernel.sql`, `src/protocol/evidence-projections/assembly.ts`, and `src/protocol/evidence-projections/projections.ts` only to the extent needed for source-owned scale/redaction concerns. Add contract/action/run-scoped store reads and batched stream-event range reads before any hosted evidence-scale claim. Strengthen projection redaction toward typed allowlists and deny-by-default handling for credential-shaped provider refs. - -Acceptance: - -- Projection assembly no longer depends on broad tenant/org scans for contract-scoped envelopes once hosted-scale language is allowed. -- D1 and memory store contracts remain equivalent. -- Provider-format fuzz tests prove raw signer refs, `PaymentPayload`, `PAYMENT-SIGNATURE`, bearer tokens, vault paths, secret refs, facilitator secrets, and auth.md credential material do not project. - -Phase 7: Package, `.planning`, demo, and closeout gates. - -Update package smoke fixtures and architecture guards after source behavior stabilizes. Keep `.planning/` out of package files, exports, scripts, CI names, README command sections, and canonical docs except as scratch-boundary language. Regenerate demo outputs only after source and tests pass. Run package and full-repo gates before calling concerns closed. - -Acceptance: - -- `npm run pack:check` proves build output, package files, and published entrypoint smoke match the final source schema. -- `npm run quality:claims` and `npm run quality:architecture` fail on claim broadening or lane-boundary drift. -- `npm run check:repo` passes on the worktree intended for closeout. - -## Task Graph - -```text -macro-001 -> macro-002 -> macro-003 -> macro-004 -macro-004 -> macro-005 -> macro-006 -> macro-007 -macro-004 -> macro-008 -> macro-009 -> macro-010 -macro-004 -> macro-011 -> macro-012 -> macro-013 -macro-004 -> macro-014 -> macro-015 -macro-010 -> macro-016 -> macro-017 -macro-007 -> macro-018 -macro-015 -> macro-019 -macro-013 -> macro-019 -macro-017 -> macro-019 -macro-018 -> macro-019 -``` - -Critical path: runtime posture failing tests, runtime propagation/refusal, direct idempotency binding, focused runtime gate, MCP schema/parity, MCP smoke/package fixture update, package/planning drift gate, full closeout. - -Parallel work after Phase 1 stabilizes: sandbox evidence boundary, x402 future-surface cut-line guards, evidence redaction/scale tests, and runtime registry test scaffolding. - -## Risks And Mitigations - -- P0: Runtime defaulting can create a weaker contract than observed. Mitigation: forward posture fields and refuse unsupported/live/unknown before action contract; gate with runtime and adapter tests. -- P0: MCP can teach weaker x402 semantics. Mitigation: strict posture schema, MCP preflight refusal, idempotency binding, stdio/package smoke updates, and MCP lane architecture tests. -- P0: Sandbox evidence can be overread as settlement or facilitator operation. Mitigation: explicit typed local/reference evidence boundary, projection labels, product tests, and claim gates. -- P0: Signer custody can leak into runtime/MCP/CLI or become a live custody claim. Mitigation: forbidden import/export tests, redaction tests, fixture-vs-live custody labels, and future custody cut. -- P1: Registry refactor can preserve the same posture bug. Mitigation: sequence refactor after focused runtime gate and require per-family parity tests. -- P1: Spend-window metadata can become fake aggregate enforcement. Mitigation: keep metadata label visible and fail claims until a real ledger exists. -- P1: Projection redaction can miss provider credential formats. Mitigation: typed allowlist direction plus fuzz fixtures. -- P1: Package artifacts can drift from dirty source. Mitigation: `pack:check` and published entrypoint smoke are closeout gates. -- P2: `.planning` scratch can become canon. Mitigation: package/architecture/claim guards and source-boundary language. - -## Validation Gates - -Focused runtime posture gate: - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/adapters/x402-payment-action-proposal.test.ts -npm run check:types -``` - -Focused MCP posture gate: - -```bash -npm run test -- test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/mcp/mcp-reference-transcript.test.ts test/mcp/mcp-stdio-process.test.ts test/architecture/mcp-surface-posture.test.ts -npm run check:types -``` - -Sandbox and x402 boundary gate: - -```bash -npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts test/product/x402-protected-spend-demo-report.test.ts test/architecture/claim-boundary.test.ts -npm run demo:aps -``` - -Runtime registry gate: - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/runtime/package-install-runtime.test.ts test/protocol/generated-execution-graph.test.ts -npm run quality:architecture -``` - -Evidence projection/storage gate: - -```bash -npm run test -- test/protocol/evidence-projections.test.ts test/http/d1-http.test.ts test/protocol/protocol-store-atomicity-contract.test.ts -npm run quality:storage -``` - -Claim, package, and full closeout gate: - -```bash -npm run demo:mcp-transcript -npm run quality:claims -npm run quality:architecture -npm run pack:check -npm run check:repo -``` - -## Cut Lines - -- Ledger: session/day/review spend control remains metadata until a D1-backed reservation ledger with conflict, recovery, and receipt semantics exists. -- Custody: local signer and fixture gateway proof do not prove provider custody, customer custody, vault rotation, revocation, resolver failure, or hosted signer operation. -- Hosted verifier: local terminal certificate verification does not prove hosted verifier, JWKS, revocation, cross-org trust, marketplace, certification, or clearing-house operation. -- Host interception: runtime/MCP bypass evidence does not prove browser, shell, package-manager, cloud API, network, database, repo, or sibling tool interception. -- x402 breadth: `x402_payment.exact` remains buyer-side exact per-call payment signature evidence; no `upto`, batch, lifecycle, seller, facilitator, settlement, signed offer, signed receipt, or MCP auto-pay support. -- Publication: package readiness is build/pack/entrypoint smoke only; real npm/MCP Registry publication requires external owner credentials. -- `.planning`: planning artifacts can guide work but cannot become package surface, exported names, public command names, CI names, canonical docs, or claim authority. - -## Rollback / Stop Conditions - -- Stop if runtime or MCP unsupported, omitted, external, live, or unknown posture reaches `action_contract_proposed`. -- Stop if runtime or MCP creates policy decision, greenlight, gateway check, mutation attempt, receipt, receipt export, signer evidence, or authority certificate. -- Stop if sandbox evidence serializes as seller middleware, facilitator operation, settlement finality, provider custody, or authority. -- Stop if `PaymentPayload`, `PAYMENT-SIGNATURE`, private keys, bearer tokens, vault paths, provider secrets, or raw signer refs leak into MCP, CLI, demo, package smoke, or projection output. -- Stop if aggregate session/day/review spend language appears as enforced without a real reservation ledger. -- Stop if registry extraction changes package/auth.md/x402 runtime behavior outside the intended family boundary. -- Stop if source changes weaken Tier 1 protocol/kernel semantics or move authority into runtime, MCP, CLI, demos, or review output. -- Stop if package smoke does not exercise the final MCP schema after posture fields are added. -- Stop if `.planning/` appears in package files or becomes repo-facing canon. - -## Smallest Next Action - -Add the failing runtime regression in `test/runtime/runtime-ingress.test.ts`: a wrapped x402 dispatch with `intendedRequestBodyPosture: "unsupported"`, `providerEnvironmentPosture: "live"`, and a live provider ref must return `one_or_more_dispatches_refused`, include `x402_request_body_posture_unsupported` and `x402_provider_environment_not_sandboxed`, and create no action contract or authority-bearing records. Then patch `x402PaymentAttemptForDispatch()` to forward posture fields and update x402 idempotency material. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/RISKS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/RISKS.md deleted file mode 100644 index 2d53592..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/RISKS.md +++ /dev/null @@ -1,35 +0,0 @@ -# Risks - -## P0 - -| ID | Risk | Failure Mode | Mitigation | Gate | -| --- | --- | --- | --- | --- | -| P0-R1 | Runtime x402 posture defaulting | Runtime observes unsupported/live posture but omits it before `X402PaymentAttemptSchema`, which defaults into contractable local posture. | Forward posture fields, bind idempotency, and refuse pre-contract. | `npm run test -- test/runtime/runtime-ingress.test.ts test/adapters/x402-payment-action-proposal.test.ts` | -| P0-R2 | MCP posture gap | MCP can submit/propose a weaker x402 candidate than the direct adapter would accept. | Add strict posture schema, pre-contract refusal, parameter/idempotency binding, and MCP smoke updates. | `npm run test -- test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/architecture/mcp-surface-posture.test.ts` | -| P0-R3 | Sandbox evidence overread | Local signed retry appears to prove seller middleware, facilitator settlement, payment finality, provider custody, or authority. | Add typed local/reference evidence boundary and projection/demo claim guards. | `npm run test -- test/adapters/x402-wallet-gateway.test.ts test/product/x402-protected-spend-demo-report.test.ts test/architecture/claim-boundary.test.ts` | -| P0-R4 | Signer custody leakage | Runtime/MCP/CLI/package output exposes signer material or implies provider/customer custody. | Forbidden imports/exports, redaction tests, fixture-vs-live custody labels. | `npm run test -- test/architecture/import-posture.test.ts test/adapters/x402-wallet-gateway.test.ts test/protocol/evidence-projections.test.ts` | -| P0-R5 | Authority moves into proposal surfaces | Runtime/MCP/CLI creates policy, greenlight, gateway, mutation, receipt, receipt export, signer, or certificate evidence. | Lane architecture tests and explicit non-authority flags. | `npm run quality:architecture` | - -## P1 - -| ID | Risk | Failure Mode | Mitigation | Gate | -| --- | --- | --- | --- | --- | -| P1-R1 | Registry refactor preserves bug | Family adapter abstraction repeats posture dropping across a cleaner boundary. | Refactor only after Phase 1 tests pass; add dispatch-kind coverage and parity tests. | `npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/runtime/package-install-runtime.test.ts` | -| P1-R2 | Spend metadata becomes fake budget enforcement | Session/day/review fields are read as enforced aggregate controls. | Keep `not_enforced_local_metadata` visible and fail broad claims until ledger exists. | `npm run test -- test/adapters/x402-install-proposal.test.ts test/architecture/claim-boundary.test.ts` | -| P1-R3 | Redaction misses provider credential formats | Pattern-based redaction misses raw provider/vault/signer material. | Move toward typed allowlists and add provider-format fuzz fixtures. | `npm run test -- test/protocol/evidence-projections.test.ts` | -| P1-R4 | D1/projection scale gets overclaimed | Tenant/org scans and per-offset reads are mistaken for hosted evidence readiness. | Add scoped reads/range reads before hosted audit/search claims. | `npm run quality:storage` | -| P1-R5 | Package drift | Source schema changes but `dist`, bin smoke, or package metadata lag. | Make `pack:check` and published-entrypoint smoke mandatory closeout. | `npm run pack:check` | -| P1-R6 | Future x402 surfaces sneak into first wedge | Unsupported variants are accepted as extensions of `x402_payment.exact`. | Conformance classifications and hostile upstream fixtures. | `npm run test -- test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts` | - -## P2 - -| ID | Risk | Failure Mode | Mitigation | Gate | -| --- | --- | --- | --- | --- | -| P2-R1 | `.planning` scratch becomes canon | Future agents revive stale plan claims from tracked planning maps. | Guard package/docs/scripts/exports against `.planning` authority. | `npm run quality:claims` and `npm run pack:check` | -| P2-R2 | False closeout | Concern marked done without source mechanism, regression test, and gate. | Closure rule: source diff plus focused test plus architecture/claim/package gate. | `npm run check:repo` | -| P2-R3 | Buyer-readable proof label becomes action-class claim | `x402_paid_http_call.exact` is treated as gateway-bound authority. | Keep label report-only until action catalog, compiler, policy, and gateway support it. | `npm run test -- test/product/x402-protected-spend-demo-report.test.ts test/architecture/claim-boundary.test.ts` | -| P2-R4 | Gateway failure evidence too coarse | Redacted diagnostics hide useful failure categories for operations. | Add redacted reason classes only after no-leakage tests. | `npm run test -- test/adapters/x402-wallet-gateway.test.ts test/protocol/evidence-projections.test.ts` | - -## Residual Risk - -Live provider custody, hosted verifier operation, host-wide interception, seller/facilitator settlement, aggregate spend enforcement, and public registry publication remain unvalidated because the mechanisms do not exist in the current source. The correct mitigation is explicit cut-line evidence, not partial claims. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/TASKS.jsonl b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/TASKS.jsonl deleted file mode 100644 index da8a2e3..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/TASKS.jsonl +++ /dev/null @@ -1,19 +0,0 @@ -{"id":"macro-001","priority":"P0","phase":"Phase 1","title":"Add failing runtime x402 posture regression tests","owner":"runtime implementer","rationale":"Runtime currently accepts posture fields but can default them away before x402 proposal; the failure must be visible before the fix.","depends_on":[],"acceptance":["test/runtime/runtime-ingress.test.ts covers unsupported body plus live provider posture returning one_or_more_dispatches_refused","refused runtime case includes x402_request_body_posture_unsupported and x402_provider_environment_not_sandboxed","refused runtime case creates no action_contract, policy_decision, greenlight, gateway_check_attempt, mutation_attempt, receipt, receipt_export, or authority_certificate","supported digest_bound local_reference_sandbox case asserts posture fields survive into candidate parameters"],"candidate_paths":["test/runtime/runtime-ingress.test.ts","test/adapters/x402-payment-action-proposal.test.ts"],"non_goals":["do not patch source before a failing regression exists","do not test hosted provider custody or aggregate spend enforcement"]} -{"id":"macro-002","priority":"P0","phase":"Phase 1","title":"Forward runtime x402 request and provider posture into adapter attempts","owner":"runtime implementer","rationale":"Observed dispatch posture must become exact adapter input or refuse before contract proposal; omission is compiler overreach.","depends_on":["macro-001"],"acceptance":["src/runtime/ingress/index.ts forwards intendedRequestBodyPosture, providerEnvironmentPosture, and providerEnvironmentRef in x402PaymentAttemptForDispatch","unsupported, omitted, external_sandbox, live, and unknown posture do not default to no_body or local_reference_sandbox","npm run test -- test/runtime/runtime-ingress.test.ts test/adapters/x402-payment-action-proposal.test.ts passes"],"candidate_paths":["src/runtime/ingress/index.ts","src/adapters/x402-payment/action-proposal.ts"],"non_goals":["do not extract runtime registry in this task","do not move authority into runtime"]} -{"id":"macro-003","priority":"P0","phase":"Phase 1","title":"Bind x402 posture into direct adapter idempotency material","owner":"x402 adapter implementer","rationale":"Two x402 attempts with different body or provider posture must not share idempotency semantics merely because amount and endpoint match.","depends_on":["macro-001"],"acceptance":["idempotency digest material includes intendedRequestBodyPosture, providerEnvironmentPosture, and providerEnvironmentRef for non-payment-identifier x402 proposals","tests prove idempotency changes when posture or provider ref changes","historical records are not rewritten or claimed equivalent"],"candidate_paths":["src/adapters/x402-payment/action-proposal.ts","test/adapters/x402-payment-action-proposal.test.ts"],"non_goals":["do not change stored historical receipts","do not add a new Tier 1 primitive"]} -{"id":"macro-004","priority":"P0","phase":"Phase 1","title":"Record runtime x402 refusal without authority-bearing records","owner":"runtime implementer","rationale":"A runtime posture refusal should preserve reconstructable proposal evidence without producing an action contract or downstream authority objects.","depends_on":["macro-002","macro-003"],"acceptance":["unsupported runtime x402 posture returns structured refusal outcome instead of unhandled throw","runtime/graph/tool-call evidence remains reconstructable where existing runtime semantics allow","tests assert no policy, greenlight, gateway, mutation, receipt, receipt_export, signer, or certificate records are created","npm run check:types passes"],"candidate_paths":["src/runtime/ingress/index.ts","src/adapters/x402-payment/action-proposal.ts","test/runtime/runtime-ingress.test.ts"],"non_goals":["do not treat refusal evidence as authorization","do not create action_contract for refused x402 attempts"]} -{"id":"macro-005","priority":"P0","phase":"Phase 2","title":"Add explicit MCP x402 body and provider posture schema fields","owner":"mcp implementer","rationale":"MCP cannot be posture-equivalent while its model-facing schema cannot express the direct adapter boundary.","depends_on":["macro-004"],"acceptance":["McpX402PaymentProposalInputSchema requires intendedRequestBodyPosture, providerEnvironmentPosture, and nullable providerEnvironmentRef","schema fixtures reject omitted posture unless an explicit compatibility refusal path is implemented","valid local_reference_sandbox inputs include posture fields","npm run test -- test/mcp/mcp-schema-contract.test.ts passes"],"candidate_paths":["src/mcp/x402-proposal.ts","test/mcp/mcp-schema-contract.test.ts","src/mcp/catalog.ts"],"non_goals":["do not default omitted MCP posture to local_reference_sandbox","do not expose signer or gateway authority through MCP"]} -{"id":"macro-006","priority":"P0","phase":"Phase 2","title":"Implement MCP x402 pre-contract refusal and posture binding","owner":"mcp implementer","rationale":"MCP should either bind the exact posture into a proposal or refuse before runtime-client contract proposal.","depends_on":["macro-005"],"acceptance":["MCP refuses or schema-fails omitted, unsupported, external_sandbox, live, and unknown posture before runtime-client proposeActionContract","accepted MCP proposals bind posture fields into x402Parameters, non-secret summary, tool-call draft, compile-intent candidate parameters, and deriveMcpX402IdempotencyKey","MCP result keeps non-authority flags for refusals and proposals","npm run test -- test/mcp/mcp-x402-proposal.test.ts test/architecture/mcp-surface-posture.test.ts passes"],"candidate_paths":["src/mcp/x402-proposal.ts","test/mcp/mcp-x402-proposal.test.ts","test/architecture/mcp-surface-posture.test.ts"],"non_goals":["do not import wallet gateway, policy, gateway, storage, receipt, all-role SDK, or certificate code","do not implement MCP auto-pay"]} -{"id":"macro-007","priority":"P0","phase":"Phase 2","title":"Update MCP transcript, stdio, and package smoke fixtures for posture schema","owner":"mcp/package implementer","rationale":"Public MCP/package evidence must exercise the same schema that source now enforces.","depends_on":["macro-006"],"acceptance":["MCP reference transcript includes local no_body success, digest_bound success, unsupported or omitted body refusal, and live or unknown provider refusal","stdio process smoke uses final MCP schema and leaks no PaymentPayload or PAYMENT-SIGNATURE","scripts/check-published-entrypoints.mjs reference MCP input includes posture fields","npm run test -- test/mcp/mcp-reference-transcript.test.ts test/mcp/mcp-stdio-process.test.ts passes"],"candidate_paths":["examples/mcp-reference-transcript/run.ts","test/mcp/mcp-reference-transcript.test.ts","test/mcp/mcp-stdio-process.test.ts","scripts/check-published-entrypoints.mjs"],"non_goals":["do not claim hosted MCP availability","do not claim sibling MCP interception"]} -{"id":"macro-008","priority":"P0","phase":"Phase 3","title":"Add explicit local/reference sandbox evidence-boundary object","owner":"x402 adapter implementer","rationale":"authorityCreated false is insufficient if signed retry evidence can still be read as settlement or middleware operation.","depends_on":["macro-004"],"acceptance":["sandbox challenge and signed retry outputs carry local_reference fixture scope and non-authority boundary fields","signed retry output explicitly says not settlement finality, not facilitator operation, not seller middleware, and not provider custody","TypeScript types make the boundary visible to demo/projection code"],"candidate_paths":["src/adapters/x402-payment/sandbox-http.ts","src/adapters/x402-payment/wallet-gateway.ts"],"non_goals":["do not implement seller middleware","do not implement facilitator settlement","do not claim live provider operation"]} -{"id":"macro-009","priority":"P0","phase":"Phase 3","title":"Test sandbox retry refusal boundaries and post-gate signing","owner":"x402 test implementer","rationale":"The local sandbox must only observe a signed retry after gateway-created signature evidence and exact local posture.","depends_on":["macro-008"],"acceptance":["missing signature evidence, wrong signature header, non-reference provider posture, ambiguous body posture, and replay do not increment signedRetryCount","official SDK PaymentPayload creation remains after VerifiedGatewayCheck","test output leaks no raw signer, PaymentPayload, or PAYMENT-SIGNATURE material","npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts passes"],"candidate_paths":["test/adapters/x402-wallet-gateway.test.ts","test/integration/x402-d1-http.test.ts","src/adapters/x402-payment/wallet-gateway.ts"],"non_goals":["do not expose payment signature authority to runtime, MCP, CLI, or demos","do not validate real provider custody"]} -{"id":"macro-010","priority":"P0","phase":"Phase 3","title":"Project and report sandbox signed retry as downstream fixture evidence only","owner":"projection/product implementer","rationale":"Adoption surfaces must not launder local retry observation into authority, settlement, custody, or action-catalog breadth.","depends_on":["macro-008","macro-009"],"acceptance":["evidence projections classify x402 local sandbox signed retry as local/reference downstream observation","demo report preserves x402_paid_http_call.exact as buyer-readable proof-object language only","claim tests fail if demo/docs imply settlement, seller middleware, facilitator operation, provider custody, or authority","npm run test -- test/protocol/evidence-projections.test.ts test/product/x402-protected-spend-demo-report.test.ts test/architecture/claim-boundary.test.ts passes"],"candidate_paths":["src/protocol/evidence-projections/projections.ts","examples/x402-protected-spend/run.ts","examples/x402-protected-spend/README.md","test/protocol/evidence-projections.test.ts","test/product/x402-protected-spend-demo-report.test.ts","test/architecture/claim-boundary.test.ts"],"non_goals":["do not create x402_paid_http_call.exact as an action catalog entry","do not claim payment finality"]} -{"id":"macro-011","priority":"P1","phase":"Phase 4","title":"Add runtime family registry coverage tests before extraction","owner":"runtime test implementer","rationale":"The registry is useful only if it prevents field loss and family drift instead of hiding it.","depends_on":["macro-004"],"acceptance":["tests define expected family coverage for package_install, x402_payment, and auth_md protected API dispatches","missing family config fails closed","mixed-family blocks retain existing grammar/version behavior","registry architecture tests forbid authority imports"],"candidate_paths":["test/runtime/runtime-ingress.test.ts","test/runtime/auth-md-candidate-compilation.test.ts","test/runtime/package-install-runtime.test.ts","test/architecture/import-posture.test.ts"],"non_goals":["do not alter public runtime API in the test-only step","do not add a new protected-action family"]} -{"id":"macro-012","priority":"P1","phase":"Phase 4","title":"Extract runtime ingress family adapters behind a proposal-only registry","owner":"runtime implementer","rationale":"Cross-family conversion in one module invites future refusal-field loss as more protected actions are added.","depends_on":["macro-011"],"acceptance":["runtime ingress exposes a family registry with dispatch coverage, config requirement, compile-input construction, preflight refusal, signing secret, grammar version, and raw-bypass hooks","proposeRuntimeIngressActionContracts public behavior remains stable","package install, auth.md, and x402 tests pass through the registry","registry code imports no policy, greenlight, gateway, storage implementation, mutation, receipt, signer, or certificate authority code"],"candidate_paths":["src/runtime/ingress/index.ts","src/runtime/ingress/registry.ts","src/runtime/ingress/families/x402-payment.ts","src/runtime/ingress/families/package-install.ts","src/runtime/ingress/families/auth-md-protected-api-call.ts"],"non_goals":["do not move family semantics into Tier 1 protocol","do not issue authority from runtime"]} -{"id":"macro-013","priority":"P1","phase":"Phase 4","title":"Close runtime registry architecture and regression gates","owner":"architecture reviewer","rationale":"Refactor closure requires proof that boundaries and existing families survived extraction.","depends_on":["macro-012"],"acceptance":["npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/runtime/package-install-runtime.test.ts test/protocol/generated-execution-graph.test.ts passes","npm run quality:architecture passes","no package export or lane doc claims runtime authority"],"candidate_paths":["test/architecture/import-posture.test.ts","test/architecture/naming-posture.test.ts","src/runtime/LANE.md"],"non_goals":["do not document registry as gateway enforcement","do not claim host-wide interception"]} -{"id":"macro-014","priority":"P1","phase":"Phase 5","title":"Pin unsupported x402 first-wedge surfaces in conformance tests","owner":"conformance implementer","rationale":"The first wedge must stay exact buyer-side x402_payment.exact unless broader surfaces have source, policy, and gateway support.","depends_on":["macro-004"],"acceptance":["conformance classifies upto, batch settlement, lifecycle hooks, MCP auto-pay, signed offers, signed receipts, seller middleware, facilitator operation, and settlement finality as unsupported or future","hostile upstream fixtures cover unknown extensions, multiple accepts, malformed assets, future versions, and non-exact schemes","npm run test -- test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts passes"],"candidate_paths":["src/adapters/x402-payment/conformance.ts","src/adapters/x402-payment/upstream-evidence.ts","test/conformance/x402-payment-conformance.test.ts","test/conformance/x402-upstream-exact-fixtures.test.ts"],"non_goals":["do not broaden x402_payment.exact","do not implement seller or facilitator adapters"]} -{"id":"macro-015","priority":"P1","phase":"Phase 5","title":"Guard spend metadata, custody labels, and scoped bypass posture","owner":"x402 boundary implementer","rationale":"Metadata-only spend fields, fixture custody, and observed bypass evidence are the easiest surfaces to overclaim.","depends_on":["macro-014"],"acceptance":["spend session/day/review controls remain outside enforced action-contract bounds and retain not_enforced_local_metadata","fixture gateway custody is distinguishable from live provider or customer custody","runtime/MCP bypass evidence remains scoped and non-host-wide","npm run test -- test/adapters/x402-install-proposal.test.ts test/adapters/x402-bypass-probes.test.ts test/architecture/claim-boundary.test.ts passes"],"candidate_paths":["src/adapters/x402-payment/install-proposal.ts","src/adapters/x402-payment/bypass-probes.ts","examples/x402-protected-spend/run.ts","test/adapters/x402-install-proposal.test.ts","test/adapters/x402-bypass-probes.test.ts","test/architecture/claim-boundary.test.ts"],"non_goals":["do not build aggregate spend ledger","do not claim provider custody","do not claim broad host interception"]} -{"id":"macro-016","priority":"P1","phase":"Phase 6","title":"Add projection scale and credential-redaction regression tests","owner":"storage/projection test implementer","rationale":"Hosted evidence and provider custody claims are invalid while projection reads and redaction remain local/denylist-shaped.","depends_on":["macro-010"],"acceptance":["tests cover high unrelated record volume for contract-scoped envelope assembly","tests cover long receipt timelines requiring batched range reads","redaction fuzz covers PaymentPayload, PAYMENT-SIGNATURE, raw signer refs, bearer tokens, vault paths, secret refs, facilitator secrets, and auth.md credential-looking refs","npm run test -- test/protocol/evidence-projections.test.ts test/http/d1-http.test.ts test/protocol/protocol-store-atomicity-contract.test.ts fails before source changes"],"candidate_paths":["test/protocol/evidence-projections.test.ts","test/http/d1-http.test.ts","test/protocol/protocol-store-atomicity-contract.test.ts"],"non_goals":["do not claim hosted audit/search from test scaffolding alone","do not expose raw records through projections"]} -{"id":"macro-017","priority":"P1","phase":"Phase 6","title":"Implement scoped store reads, D1 indexes, range reads, and projection redaction hardening","owner":"storage/projection implementer","rationale":"Projection evidence must be reconstructable and redacted under scale before hosted claims are even considered.","depends_on":["macro-016"],"acceptance":["ProtocolStore exposes contract/action/run-scoped reads needed by envelope assembly","memory and D1 implementations preserve store contract parity","D1 migration adds additive indexes or tables without changing canonical record digests","projection assembly uses scoped methods instead of broad tenant/org scans where scale claims are made","npm run quality:storage passes"],"candidate_paths":["src/protocol/store/port.ts","src/storage/memory/index.ts","src/storage/d1/index.ts","migrations/0001_protocol_kernel.sql","src/protocol/evidence-projections/assembly.ts","src/protocol/evidence-projections/projections.ts"],"non_goals":["do not change protocol record digests","do not implement hosted verifier or retention policy"]} -{"id":"macro-018","priority":"P1","phase":"Phase 7","title":"Update package smoke and planning-drift gates after MCP schema finalization","owner":"package/architecture implementer","rationale":"Package consumers execute built bins and packaged entrypoints, so source-only success is not publish readiness.","depends_on":["macro-007"],"acceptance":["scripts/check-published-entrypoints.mjs uses the final MCP posture schema","package surface checks exclude .planning, tests, workspace junk, raw credential material, PaymentPayload, and PAYMENT-SIGNATURE","architecture tests reject .planning as package/export/script/CI/canonical-doc authority","npm run pack:check passes"],"candidate_paths":["scripts/check-package-surface.mjs","scripts/check-published-entrypoints.mjs","test/architecture/package-surface.test.ts","test/architecture/active-vocabulary.test.ts","test/architecture/claim-boundary.test.ts","package.json"],"non_goals":["do not publish to npm or MCP Registry","do not treat .planning maps as canon"]} -{"id":"macro-019","priority":"P0","phase":"Phase 7","title":"Run final concern-elimination closeout gates","owner":"release captain","rationale":"The concerns are not eliminated until focused gates and full repo gates pass on the intended worktree.","depends_on":["macro-013","macro-015","macro-017","macro-018"],"acceptance":["npm run demo:aps passes and output preserves local/reference non-claims","npm run demo:mcp-transcript passes with posture parity cases","npm run quality:claims passes","npm run quality:architecture passes","npm run pack:check passes","npm run check:repo passes","closeout notes list remaining future cuts rather than claiming them complete"],"candidate_paths":["examples/x402-protected-spend/output/latest.json","examples/x402-protected-spend/output/latest.md","examples/mcp-reference-transcript/output/latest.json",".planning/macro/VALIDATION.md"],"non_goals":["do not commit from this planning task","do not mark ledger, custody, hosted verifier, host interception, seller/facilitator, or publication as complete"]} diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/VALIDATION.md deleted file mode 100644 index 0603b19..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/VALIDATION.md +++ /dev/null @@ -1,176 +0,0 @@ -# Validation - -## Closure Rule - -A concern is not closed unless it has: - -- a source-owned mechanism; -- a focused regression test or conformance test; -- a claim, architecture, storage, package, or full-repo gate that would catch future drift; -- no expansion of Tier 1 primitive meaning; -- no authority moved into runtime, MCP, CLI, demos, or review output. - -## Phase Gates - -### Phase 1: Runtime Posture - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/adapters/x402-payment-action-proposal.test.ts -npm run check:types -``` - -Proof obligations: - -- Runtime forwards `intendedRequestBodyPosture`, `intendedRequestBodyDigest`, `providerEnvironmentPosture`, and `providerEnvironmentRef`. -- Unsupported/omitted body and external/live/unknown provider posture refuse before action-contract proposal. -- Accepted local-reference/digest-bound posture appears in candidate parameters and idempotency material. -- Refused cases create no policy decision, greenlight, gateway check, mutation attempt, receipt, receipt export, or authority certificate. - -### Phase 2: MCP Posture - -```bash -npm run test -- test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/mcp/mcp-reference-transcript.test.ts test/mcp/mcp-stdio-process.test.ts test/architecture/mcp-surface-posture.test.ts -npm run check:types -``` - -Proof obligations: - -- MCP schema requires explicit request-body and provider-environment posture. -- MCP refuses or schema-fails omitted, unsupported, external, live, and unknown posture before runtime-client proposal. -- Accepted MCP proposals bind posture fields into parameters, non-secret summary, tool-call draft, compile-intent input, and idempotency digest. -- MCP outputs remain non-authority and leak no `PaymentPayload`, `PAYMENT-SIGNATURE`, signer, credential, receipt export, gateway, mutation, or certificate material. - -### Phase 3: Sandbox Boundary - -```bash -npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts test/protocol/evidence-projections.test.ts test/product/x402-protected-spend-demo-report.test.ts -npm run demo:aps -``` - -Proof obligations: - -- Challenge and signed-retry evidence carry local/reference fixture scope and `authorityCreated: false`. -- Signed retry is post-gate downstream observation only. -- Missing signature evidence, wrong signature header, non-reference provider posture, ambiguous body posture, and replay do not create another signed retry. -- Projections and demo output do not claim settlement finality, facilitator operation, seller middleware, provider custody, or authority. - -### Phase 4: Runtime Registry - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/runtime/package-install-runtime.test.ts test/protocol/generated-execution-graph.test.ts -npm run quality:architecture -``` - -Proof obligations: - -- Every dispatch kind has exactly one family adapter. -- Missing config fails closed. -- Existing package install, auth.md, and x402 runtime outputs remain behaviorally equivalent except for the intended posture fix. -- Registry code cannot import or issue authority-bearing transitions. - -### Phase 5: Future-Surface Guards - -```bash -npm run test -- test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts test/adapters/x402-install-proposal.test.ts test/adapters/x402-bypass-probes.test.ts test/architecture/claim-boundary.test.ts -npm run quality:claims -``` - -Proof obligations: - -- Unsupported x402 surfaces stay explicit future cuts. -- Spend session/day/review controls remain `not_enforced_local_metadata`. -- Fixture custody and scoped bypass evidence cannot be serialized as live custody or host-wide interception. -- README/docs/examples fail claims if they imply hosted, provider, broad host, aggregate spend, seller/facilitator, or settlement proof. - -### Phase 6: Projection Scale And Redaction - -```bash -npm run test -- test/protocol/evidence-projections.test.ts test/http/d1-http.test.ts test/protocol/protocol-store-atomicity-contract.test.ts -npm run quality:storage -``` - -Proof obligations: - -- Contract/action/run-scoped store reads and range reads preserve memory/D1 parity. -- Projection assembly does not rely on broad scans when making scale claims. -- Provider-format fuzz cases do not project raw signer refs, `PaymentPayload`, `PAYMENT-SIGNATURE`, bearer tokens, vault paths, secret refs, facilitator secrets, or auth.md credential material. - -### Phase 7: Package And Closeout - -```bash -npm run demo:mcp-transcript -npm run quality:claims -npm run quality:architecture -npm run pack:check -npm run check:repo -``` - -Proof obligations: - -- Package smoke uses the final MCP posture schema. -- `dist` and bin behavior match source after build. -- `.planning/`, tests, workspace junk, raw credentials, and scratch docs are excluded from package artifacts. -- Full repo check passes on the intended closeout worktree. - -## Commands Not Sufficient Alone - -- `npm run test` without focused posture cases does not prove runtime/MCP x402 parity. -- `npm run demo:aps` does not prove settlement, provider custody, hosted operation, or host interception. -- `npm run pack:check` does not prove publication. -- `npm run quality:claims` does not close a source concern without source tests. - -## Blocked / Future Checks - -- Live provider/customer custody checks are blocked until provider/vault custody code exists. -- Aggregate spend ledger checks are blocked until reservation ledger code exists. -- Hosted verifier, JWKS, revocation, and cross-org trust checks are blocked until hosted verifier code exists. -- Host-wide interception checks are blocked until a concrete host harness exists. -- Seller/facilitator/settlement checks are blocked until those adapters exist. -- Actual npm/MCP Registry publication checks are blocked on owner-held external credentials. - -## Closeout Result: 2026-05-24 - -Executed end-to-end against `macro-001` through `macro-019`. - -Closed source-owned concerns: - -- Runtime x402 posture is explicit in proposal input, candidate parameters, refusal evidence, and idempotency material. -- MCP x402 posture is explicit in schema, reference transcript, idempotency material, and package-entrypoint smoke input. -- Local/reference x402 sandbox retry evidence is labeled downstream fixture evidence only, with no authority, custody, settlement, seller, or facilitator claim. -- Runtime ingress family coverage is behind a proposal-only registry and guarded against authority imports. -- Unsupported x402 surfaces remain explicit future cuts, including settlement finality. -- Evidence projection assembly now uses contract-scoped reads plus store range reads instead of broad tenant/org scans. -- Memory and D1 stores preserve scoped-read and range-read parity, with D1 action-contract side refs and indexes. -- Projection redaction covers raw signer refs, `PaymentPayload`, `PAYMENT-SIGNATURE`, bearer tokens, vault/Infisical/1Password paths, secret refs, facilitator secrets, and auth.md credential-looking refs. -- Package and architecture gates exclude `.planning/`, tests, workspace junk, raw credential material, `PaymentPayload`, and `PAYMENT-SIGNATURE` from published surfaces. - -Closeout commands run: - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/adapters/x402-payment-action-proposal.test.ts -npm run test -- test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/architecture/mcp-surface-posture.test.ts test/mcp/mcp-reference-transcript.test.ts test/mcp/mcp-stdio-process.test.ts -npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts test/protocol/evidence-projections.test.ts test/product/x402-protected-spend-demo-report.test.ts test/architecture/claim-boundary.test.ts -npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/runtime/package-install-runtime.test.ts test/protocol/generated-execution-graph.test.ts test/architecture/import-posture.test.ts -npm run test -- test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts test/adapters/x402-install-proposal.test.ts test/adapters/x402-bypass-probes.test.ts test/architecture/claim-boundary.test.ts -npm run test -- test/protocol/evidence-projections.test.ts test/http/d1-http.test.ts test/protocol/protocol-store-atomicity-contract.test.ts -npm run demo:aps -npm run demo:mcp-transcript -npm run quality:storage -npm run quality:claims -npm run quality:architecture -npm run pack:check -npm run check:repo -``` - -Final closeout gate: - -- `npm run check:repo` passed with `471 pass, 0 fail`, package build/surface smoke green, and `git diff --check` green. - -Still future, not claimed: - -- live provider/customer custody; -- aggregate spend-window enforcement; -- hosted verifier/JWKS/revocation/cross-org trust; -- host-wide interception; -- seller middleware, facilitator operation, settlement finality; -- actual npm or MCP Registry publication. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/input.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/input.md deleted file mode 100644 index a7f2f10..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/input.md +++ /dev/null @@ -1,138 +0,0 @@ -# Concerns Elimination Macro Plan Input - -Run id: `concerns-elimination-20260524T044836Z` -Date: 2026-05-24 -Requested by: user - -## Target - -Create an executable GSD macro plan to eliminate the current `.planning/codebase/CONCERNS.md` concerns with technical implementation that strengthens Handshake rather than applying documentation-only or assertion-only band-aids. - -## Invariant - -No consequential autonomous action executes outside declared bounds, and divergent behavior must be haltable, isolatable, and reconstructable. - -## User Constraints - -- Plan for implementation, not vague strategy. -- Eliminate concerns by strengthening source mechanisms, tests, and gates. -- Do not weaken or reopen the Tier 1 protocol/kernel. -- Do not expand Tier 2 claims beyond installed, gateway-owned, exact protected paths. -- Keep CLI/MCP proposal/evidence only. -- Keep runtime ingress proposal-only. -- Keep x402 first wedge exact and buyer-side unless a concern explicitly requires a future cut line. -- Preserve existing dirty worktree changes as current state; do not plan by reverting them. -- No band-aids: each phase must include source-owned mechanism, tests, and validation gates. - -## Current Worktree State - -Dirty files observed before planning: - -```text -M README.md -M docs/internal/decisions.md -M docs/internal/protocol-notes.md -M examples/x402-protected-spend/README.md -M examples/x402-protected-spend/run.ts -M src/adapters/x402-payment/action-proposal.ts -M src/adapters/x402-payment/index.ts -M src/adapters/x402-payment/upstream-evidence.ts -M src/adapters/x402-payment/wallet-gateway.ts -M src/protocol/evidence-projections/projections.ts -M src/protocol/foundation/reason-codes.ts -M src/runtime/ingress/index.ts -M test/adapters/x402-payment-action-proposal.test.ts -M test/adapters/x402-wallet-gateway.test.ts -M test/product/x402-protected-spend-demo-report.test.ts -?? src/adapters/x402-payment/sandbox-http.ts -``` - -The map should treat these changes as current live worktree state for planning. The plan must not assume they are already validated or committed. - -## Required Source Packet - -First-pass planners may read: - -- `AGENTS.md` -- `README.md` -- `QUALITY.md` -- `STRUCTURE.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-notes.md` -- `.planning/codebase/CONCERNS.md` -- `.planning/codebase/ARCHITECTURE.md` -- `.planning/codebase/STRUCTURE.md` -- `.planning/codebase/TESTING.md` -- `.planning/codebase/INTEGRATIONS.md` -- `.planning/codebase/STACK.md` -- `.planning/codebase/CONVENTIONS.md` -- `src/runtime/ingress/index.ts` -- `src/runtime/LANE.md` -- `src/mcp/x402-proposal.ts` -- `src/mcp/LANE.md` -- `src/adapters/x402-payment/action-proposal.ts` -- `src/adapters/x402-payment/upstream-evidence.ts` -- `src/adapters/x402-payment/wallet-gateway.ts` -- `src/adapters/x402-payment/sandbox-http.ts` -- `src/adapters/x402-payment/install-proposal.ts` -- `src/adapters/x402-payment/conformance.ts` -- `src/adapters/x402-payment/bypass-probes.ts` -- `src/protocol/evidence-projections/projections.ts` -- `src/protocol/evidence-projections/assembly.ts` -- `src/protocol/store/port.ts` -- `src/storage/d1/index.ts` -- `migrations/0001_protocol_kernel.sql` -- `examples/x402-protected-spend/run.ts` -- `examples/x402-protected-spend/README.md` -- relevant tests under `test/runtime/`, `test/mcp/`, `test/adapters/`, `test/conformance/`, `test/protocol/`, `test/http/`, and `test/architecture/` -- `package.json` -- `scripts/check-package-surface.mjs` -- `scripts/check-published-entrypoints.mjs` - -First-pass planners must not read sibling raw outputs, normalized outputs, or `.planning/macro/PLAN.md`. - -## Concern Groups To Close - -1. Runtime x402 posture propagation: runtime ingress must not default away request-body or provider-environment posture. -2. MCP x402 posture parity: MCP proposals must carry/refuse the same body/environment posture that direct adapter/runtime paths enforce. -3. x402 sandbox/signed retry evidence boundary: local sandbox proof must be impossible to confuse with seller middleware, facilitator settlement, or authority. -4. Runtime ingress family hardcoding: cross-family proposal code needs a stronger source-owned family adapter/registry boundary. -5. x402 first-slice and future-surface guards: unsupported x402 surfaces must stay explicit, tested, and unclaimable. -6. Spend window metadata: aggregate spend/session/day/review controls remain metadata until a real reservation ledger exists. -7. Signer custody and provider custody: local signer proof must not become provider/customer custody claim. -8. Host/bypass posture: runtime/MCP bypass evidence is not broad host interception. -9. Evidence projection scale and redaction: projection assembly and credential redaction need stronger source mechanisms before hosted claims. -10. Publish/package drift: publish-ready package surfaces must stay tied to build/pack/published-entrypoint gates. -11. `.planning` scratch drift: derived maps must not become canon or bypass claim/vocabulary gates. - -## Required Output - -Write a coherent implementation macro plan to: - -- `.planning/macro/PLAN.md` -- `.planning/macro/CONTEXT.md` -- `.planning/macro/ASSUMPTIONS.md` -- `.planning/macro/DECISIONS.md` -- `.planning/macro/RISKS.md` -- `.planning/macro/VALIDATION.md` -- `.planning/macro/TASKS.jsonl` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/synthesis.md` - -Also write raw first-pass outputs under: - -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/STRATEGY.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/ARCH.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/EXECUTION.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/RISK.md` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/raw/ADOPTION.md` - -## Success Criteria - -- Plan has source mechanisms, not documentation-only fixes. -- Plan sequences nearest high-priority defects first: runtime posture propagation, MCP posture parity, and sandbox evidence boundaries. -- Plan explicitly cuts ledger, live custody, host-wide interception, hosted verifier, facilitator/seller middleware, and registry publication unless they are implemented as separate future phases. -- Every task has candidate paths, acceptance tests, and non-goals. -- Validation includes focused tests, architecture/claim gates, package gates, demo regeneration, and full repo check. -- The plan is ready to execute unless a user-owned decision is explicitly identified. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/ADOPTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/ADOPTION.md deleted file mode 100644 index 1bb845f..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/ADOPTION.md +++ /dev/null @@ -1,152 +0,0 @@ -# ADOPTION Perspective - -## Invariant At Stake - -First-use paths must teach the same authority boundary the kernel enforces: runtime, MCP, CLI, demos, support bundles, and docs may propose or display evidence only. They must not imply policy authority, signer custody, gateway checks, mutation execution, receipt export, hosted operation, provider custody, broad host interception, aggregate spend enforcement, or x402 settlement finality. - -## Adoption Path - -1. Fix the mechanism before updating the walkthroughs. - - Runtime x402 ingress must forward `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef` into the x402 attempt and action-contract parameters instead of defaulting them away. - - MCP x402 proposal input must expose the same request-body and provider-environment posture fields, bind them into parameters and idempotency derivation, and refuse unsupported/live/unknown posture as a structured non-authority outcome. - - Demo and docs changes should land only after the focused runtime/MCP tests fail without the source changes and pass with them. - -2. Make the first local success path a narrow activation sequence, not an authority shortcut. - - The first-use guide should preserve this order: `compileX402InstallProposal()` -> catalog/envelope registration -> hostile bypass probes -> `createProtectedPathPosture()` -> runtime proposal -> policy evaluation -> `runX402WalletGateway()` -> redacted evidence projection -> optional terminal certificate after receipt/refusal/proof-gap/replay. - - Add a source-owned activation helper or example-local sequencer only if it reduces ceremony without moving policy, greenlight, signer custody, gateway check, mutation, receipt export, or certificate minting into runtime/MCP/CLI. - - The helper output must include the same non-authority flags used by runtime/MCP/CLI outputs. - -3. Keep MCP and CLI as model/operator evidence surfaces. - - MCP should remain exactly one proposal tool plus read-only resources. It should never become `pay`, `approve`, `gatewayCheck`, `sign`, `receiptExport`, or `certMint`. - - CLI should remain schema/init/doctor/evidence/cert-verify/support/install-health/conformance posture. `support.bundle` can gather debug context, but it must not read raw internal records, spawn mutation commands, include credential material, or claim authority. - - Package docs should teach `handshake` as operator evidence/readiness CLI and `handshake-mcp` as local stdio proposal/evidence server. - -4. Treat demo outputs as adoption contracts. - - `examples/x402-protected-spend/output/latest.json` should keep named phases and include request-body posture, provider-environment posture/ref, gateway check vs downstream status, signed retry as local fixture evidence, replay refusal, non-claims, and missing proof objects. - - `examples/mcp-reference-transcript/output/latest.json` should include posture-parity cases: local no-body success, digest-bound success, omitted/unsupported body refusal, live/unknown/external provider-environment refusal, stale metadata, gateway offline, raw sibling input, replay refusal, and proof gap. - - The demo reports should show `x402_paid_http_call.exact` only as buyer-readable proof-object language, not as an action catalog entry until source, policy, runtime, and gateway all support that action class. - -5. Make packaging a first-use validation step. - - `npm run pack:check` must remain mandatory before publication or registry claims because package consumers use `dist/**` and `bin/**`, not dirty TypeScript source. - - `scripts/check-package-surface.mjs` and `scripts/check-published-entrypoints.mjs` should prove no `.planning/`, tests, workspace junk, raw credentials, `PaymentPayload`, or `PAYMENT-SIGNATURE` leaks into the package or MCP stdio smoke. - - The package docs must keep npm/MCP Registry publication as metadata readiness only until owner credentials actually publish the package and registry namespace. - -## First-Use Checklist - -1. Install and run the full local gate: - - `bun install --frozen-lockfile` - - `npm run check:repo` - -2. Generate the local x402 protected-spend evidence packet: - - `npm run demo:aps` - - Inspect `examples/x402-protected-spend/output/latest.md` and `latest.json` for phases `0_sandbox_payment_required_challenge` through `7_replay_refusal`. - - Confirm runtime records no policy/greenlight/gateway/mutation/receipt/certificate before policy, and the signer is invoked only after `VerifiedGatewayCheck`. - -3. Generate the MCP proposal/evidence transcript: - - `npm run demo:mcp-transcript` - - Confirm MCP outputs carry non-authority flags and posture-parity refusals without creating gateway or mutation records. - -4. Smoke the packaged surfaces: - - `npm run build` - - `node bin/handshake schema` - - `node bin/handshake-mcp` - - `npm run pack:check` - -5. Produce a sanitized support bundle once the bundle mechanism is strengthened: - - Include package version, `server.json`/`package.json#mcpName` sync, command manifest, non-authority flags, focused test results, demo output digests, install-health refs, MCP transcript case list, and redaction summary. - - Exclude raw protocol records, stream events, idempotency internals, raw signer refs, `PaymentPayload`, `PAYMENT-SIGNATURE`, private keys, registry credentials, Worker tokens, and `.planning/` scratch. - -## Missing Docs And Examples - -- README quickstart should separate three paths: local kernel proof, package/bin smoke, and MCP proposal/evidence transcript. It should not compress them into "install Handshake and pay safely." -- `examples/x402-protected-spend/README.md` needs a posture matrix: - - `no_body` with null digest: allowed for local/reference exact path. - - `digest_bound` with body digest: allowed only when bound through runtime/MCP and gateway parameters. - - `omitted` or `unsupported`: refusal before contract proposal. - - `local_reference_sandbox`: first-slice provider environment. - - `external_sandbox`, `live`, or `unknown`: refusal until a separate provider/firewall/custody mechanism exists. -- MCP reference transcript needs explicit request-posture and provider-posture examples, not only metadata/install/gateway/idempotency cases. -- CLI support bundle needs an example JSON fixture and a product test proving every field is diagnostic, redacted, and non-authority. -- Package docs need a short "dirty source is not packaged truth" note: `dist/**` is current only after `npm run build`/`pack:check`. -- Spend-window metadata needs one adoption-visible warning in README and demo output: session/day/review bounds are metadata until a reservation ledger exists. -- `.planning` scratch drift needs to stay out of package docs and package files; implementation plans can read `.planning/codebase/CONCERNS.md`, but users must learn canon from README, QUALITY, STRUCTURE, and `docs/internal/*`. - -## Success Metrics - -- A new developer can get from clean checkout to `examples/x402-protected-spend/output/latest.json` in one documented path without touching raw protocol records or all-role SDK clients. -- Runtime x402 posture parity has regression tests proving unsupported body posture and live/unknown/external provider environment refuse without an action contract. -- MCP x402 posture parity has schema, proposal, transcript, and package-entrypoint tests proving the same posture fields are either bound into the proposed contract or refused before authority-shaped output. -- Every first-use output includes `authorityCreated: false`, `greenlightCreated: false`, `gatewayCheckPerformed: false`, `mutationAttempted: false`, `credentialMaterialIncluded: false`, `receiptExportCreated: false`, and `authorityCertificateMinted: false` unless the output is a kernel/gateway evidence object that actually created that object. -- Demo and support outputs include non-claims and missing proof objects for hosted operation, provider custody, aggregate spend enforcement, broad host interception, payment settlement finality, and cross-org certificate trust. -- `npm run pack:check` proves package files and bundled entrypoints match the source boundary; no `.planning/`, tests, deleted doc trees, or workspace junk enter the package. -- `npm run quality:claims` fails if docs or examples teach false authority, broad x402 compatibility, provider custody, hosted operation, MCP auto-pay, facilitator/seller middleware, or spend-window enforcement. - -## Adoption Blockers And Fixes - -1. Runtime x402 posture defaults hide unsafe request/provider posture. - - Blocker: runtime dispatch schemas accept posture fields, but current x402 runtime tests do not prove those fields reach the direct adapter refusal boundary. - - Fix: update runtime x402 dispatch-to-attempt conversion to pass `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef`; add tests in `test/runtime/runtime-ingress.test.ts` for unsupported/omitted body and live/unknown/external provider environments producing no `action_contract`. - -2. MCP cannot express the same x402 request/provider posture as direct adapter/runtime paths. - - Blocker: `McpX402PaymentProposalInputSchema`, `x402Parameters()`, and `deriveMcpX402IdempotencyKey()` omit request-body posture and provider-environment posture/ref. - - Fix: add those fields, include them in parameter and idempotency binding, and add MCP proposal/transcript/package smoke cases proving refusal or exact binding. MCP should return structured non-authority outcomes with reason codes instead of letting models infer that missing posture defaults are safe. - -3. Local sandbox signed retry can be misread as seller middleware or settlement. - - Blocker: the sandbox emits official-shaped challenge/retry evidence and can look like real downstream x402 operation to first-time users. - - Fix: make local/reference boundary first-class in demo JSON, support bundle, conformance output, and claim tests. Preserve `authorityCreated: false`, `signedRetryIsAuthority: false`, `downstream fixture only`, and `not settlement finality` in every report. - -4. Activation ceremony is easy to skip. - - Blocker: first-use requires install compilation, record registration, probes, protected-path posture, runtime proposal, policy, gateway, projections, and optional certificate. Users will skip probes or push authority into runtime/MCP unless the sequence is one obvious path. - - Fix: add an activation sequencer or generated checklist that returns refs for each step and refuses to continue when probes/posture are missing. Keep mutation authority in gateway code only. - -5. Support bundles are valuable but dangerous. - - Blocker: a support bundle can become a raw audit dump or leak authority-shaped material. - - Fix: define a support-bundle schema with allowlisted fields only, add product tests for redaction/non-authority flags, and bind the command manifest so the bundle reads projections and generated artifacts, not raw records. - -6. Package readiness can drift from dirty source. - - Blocker: first-use docs mention publishable CLI/MCP surfaces while `dist/**` can lag changed source until build/pack checks run. - - Fix: keep `pack:check` in `check:repo`, add a package smoke section to README, and require demo/support output to report package version plus bundle smoke status as evidence, not publication proof. - -7. Spend-window language invites false adoption expectations. - - Blocker: per-session/day/review fields look like budget enforcement even though only per-call x402 amount is enforced. - - Fix: keep session/day/review values out of action-contract bounds and demo authority claims; report them as `not_enforced_local_metadata` until a reservation ledger exists. - -## Validation Gates - -- Runtime posture gate: - - `npm run test -- test/runtime/runtime-ingress.test.ts` - - Required additions: x402 unsupported/omitted body refusal, live/unknown/external provider-environment refusal, digest-bound binding, and no policy/greenlight/gateway/mutation records. - -- MCP posture gate: - - `npm run test -- test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/mcp/mcp-reference-transcript.test.ts test/mcp/mcp-stdio-process.test.ts` - - Required additions: posture fields in schema, idempotency changes when posture changes, structured refusal cases, and stdio smoke with no signer/payment material leakage. - -- x402 adapter/sandbox gate: - - `npm run test -- test/adapters/x402-payment-action-proposal.test.ts test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts` - - Required assertions: direct adapter and runtime/MCP surfaces agree on request/provider posture; sandbox signed retry stays local/reference and post-gate only. - -- Product/demo gate: - - `npm run demo:aps` - - `npm run demo:mcp-transcript` - - `npm run test -- test/product/x402-protected-spend-demo-report.test.ts test/product/self-hosted-activation.test.ts` - - Required assertions: demo reports include posture fields, non-claims, missing proof objects, support-bundle refs when implemented, and no all-role SDK adoption. - -- CLI/support/package gate: - - `npm run test -- test/architecture/cli-command-posture.test.ts test/architecture/mcp-surface-posture.test.ts test/architecture/package-surface.test.ts test/architecture/surface-boundary-posture.test.ts` - - `npm run pack:check` - - Required assertions: command manifest stays non-authority, support bundle is allowlisted/redacted, package files exclude scratch, and bundled bins run from `dist/**`. - -- Claim/canon gate: - - `npm run quality:claims` - - `npm run quality:architecture` - - Required assertions: no hosted/provider/broad-host/aggregate-spend/facilitator/seller/middleware/cross-org trust claims; `.planning` remains scratch and out of package surface. - -- Full closeout gate: - - `npm run check:repo` - -## Blocked Checks - -- Full validation was not run for this first-pass adoption perspective; implementation has not been changed yet. -- Actual npm publication and MCP Registry namespace publication cannot be validated from source because owner-held registry credentials are external. -- Live provider/customer custody, real vault rotation/revocation, live facilitator/seller middleware, hosted verifier/JWKS/revocation, broad browser/shell/network/MCP host interception, and aggregate spend reservation cannot be checked until those mechanisms exist. -- Sibling raw outputs, normalized outputs, and `.planning/macro/PLAN.md` were intentionally not read, so this perspective does not depend on other macro-planning drafts. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/ARCH.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/ARCH.md deleted file mode 100644 index 9a5e3bd..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/ARCH.md +++ /dev/null @@ -1,227 +0,0 @@ -# ARCH Perspective - -## Invariant at stake - -Tier 2 proposal and evidence surfaces must not default, omit, or relabel protected-action posture in a way that lets unsupported, live, ambiguous, or bypass-shaped x402 attempts become exact `x402_payment.exact` candidates. Tier 1 protocol meaning stays stable: `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheck`, `Receipt`, `Refusal`, `ProofGap`, and `IsolationState` do not move out of `src/protocol`. - -## Architecture implications - -1. Runtime x402 posture propagation is the first architecture defect to close. - - Current data flow is: - - ```text - RuntimeIngressObservedDispatchSchema - -> x402PaymentAttemptForDispatch() - -> X402PaymentAttemptSchema - -> buildX402PaymentCompileIntentInput() - -> IntentCompilationRecord.candidate.parameters - -> ActionContract.paramsDigest - -> X402WalletGateway observed parameters - ``` - - `src/runtime/ingress/index.ts` accepts `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef`, but `x402PaymentAttemptForDispatch()` drops them. `X402PaymentAttemptSchema` then defaults to `no_body` and `local_reference_sandbox`, which can turn an observed live, external, omitted, or unsupported posture into a cleaner proposal than the runtime actually observed. This is compiler overreach by omission. - - Source mechanism: forward the posture fields into the adapter attempt, include posture and provider-environment material in x402 idempotency/canonical parameter material, and add runtime tests proving `unsupported`, `omitted`, `external_sandbox`, `live`, and `unknown` refuse before `ActionContract` proposal where the direct adapter would refuse. - -2. MCP x402 posture parity must be closed without turning MCP into an adapter. - - `src/mcp/x402-proposal.ts` currently carries `intendedRequestBodyDigest` and selected headers, but not `intendedRequestBodyPosture`, `providerEnvironmentPosture`, or `providerEnvironmentRef`. Its `x402Parameters()` and `deriveMcpX402IdempotencyKey()` therefore cannot bind the same posture boundary as `src/adapters/x402-payment/action-proposal.ts`. - - MCP must remain proposal/evidence only. The `src/mcp/LANE.md` and `test/architecture/mcp-surface-posture.test.ts` forbid adapter imports, gateway imports, signer material, and authority-shaped code. Do not fix parity by importing wallet gateway or adapter execution code into MCP. - - Source mechanism: add strict MCP input fields and MCP-local pre-contract posture refusal logic, then test black-box parity against the direct adapter refusal outcomes. Forward accepted posture into tool-call drafts, candidate parameters, non-secret summaries, and the MCP idempotency digest. Output must still report `authorityCreated: false`, `greenlightCreated: false`, `gatewayCheckPerformed: false`, and `mutationAttempted: false`. - -3. The x402 sandbox needs a typed evidence boundary, not friendlier language. - - `src/adapters/x402-payment/sandbox-http.ts` is a local/reference 402 challenge and signed-retry fixture. Its retry is downstream observation after gateway-created signature evidence. It is not seller middleware, facilitator operation, settlement finality, signer custody, or authority. - - Source mechanism: make the local sandbox evidence boundary explicit in code and projections. The signed retry should carry or project a local/reference evidence role such as post-gate signed retry observation, a local provider-environment posture, and non-settlement finality. `authorityCreated: false` is necessary but not sufficient; product and projection tests must make it impossible to read the sandbox retry as facilitator settlement or provider custody. - -4. Runtime ingress family hardcoding should be refactored after the posture hotfix, not before it. - - `src/runtime/ingress/index.ts` is doing orchestration, schemas, family detection, graph-node classification, config selection, compile-input construction, signing-secret selection, and grammar-version selection for package install, x402 payment, and auth.md protected API calls. That increases cross-family drift risk, but the nearest defect is the x402 field drop. - - Source mechanism after the hotfix: introduce a runtime family adapter registry under `src/runtime/ingress/` that owns per-family conversion while the main ingress file owns only block orchestration. The adapter shape should be boring and narrow: - - ```text - familyId - dispatchKinds - requireConfig(config) - buildCompileIntentInput(...) - dispatchSpecificRefusalReasonCodes(...) - signingSecretForDispatch(...) - supportedGrammarVersion - ``` - - Keep the registry inside `src/runtime`; do not move family proposal semantics into `src/protocol`, and do not let runtime issue policy, greenlights, gateway checks, receipts, or mutations. - -5. Spend-window metadata must either stay metadata or become a real reservation ledger. - - `X402SpendBoundsSchema` has session/day/review fields, but the only enforced x402 bound is `maxAtomicAmountPerCall`. This must not be patched with a runtime-side sum or demo assertion. Aggregate spend enforcement would require a real source-owned reservation ledger with tenant/org/principal/agent/action/resource/window keys, reservation states, conflict semantics, recovery evidence, D1/memory implementations, and gateway/policy re-checks. - - For this concern-elimination plan, keep aggregate spend out of the first slice unless a full ledger phase is explicitly chosen. Strengthen the current boundary with source tests that keep `spendWindowEnforcementStatus: "not_enforced_local_metadata"` visible in install proposals, runtime/demo outputs, claim gates, and product reports. - -6. Signer custody and provider custody must remain separated. - - `src/adapters/x402-payment/wallet-gateway.ts` proves the official SDK signer is invoked only after `VerifiedGatewayCheck`, and install/conformance code can require gateway-held or fixture-gateway-held signer posture. That is still local/reference custody, not provider/customer custody or vault lifecycle proof. - - Source mechanism: keep custody status on install/conformance records, forbid raw signer, `PaymentPayload`, and `PAYMENT-SIGNATURE` through CLI/MCP/runtime projections, and require future provider custody to enter through `GatewayCredentialRef` and post-gate `CredentialResolutionEvidence`, not through x402 demo code. - -7. Host and bypass posture is evidence, not broad interception. - - Runtime ingress can refuse observed raw sibling dispatches and MCP can avoid direct payment authority. That does not prove broad browser, shell, package-manager, cloud, repo, or host interception. Do not promote synthetic bypass evidence into host-wide protection. - - Source mechanism: keep bypass posture in conformance and runtime graph evidence; add host-specific probe phases only when there is a concrete host harness. Until then, runtime/MCP outputs must keep saying proposal/evidence only. - -8. Evidence projection scale is a store-port boundary. - - `assembleAgentTransactionEnvelope()` currently scans many object types by tenant/org and filters in memory for one contract. That is acceptable for local foundation, but not for hosted audit/search claims. - - Source mechanism: add contract/action/run-scoped read methods to `ProtocolStore` and implement them in memory and D1 before any hosted evidence-scale claim. Candidate reads include policy decision by contract, latest greenlight by contract, gateway checks by contract, mutation attempts by contract, receipt by action contract, proof gaps by affected contract, refusals by contract, reconciliations by contract, credential-resolution evidence by contract, authority certificates by terminal contract, and recovery records by source contract. D1 needs compatible indexes or side tables; do not solve this in HTTP handlers. - -9. Redaction must move toward typed allowlists for live providers. - - `redactedProjectionRefs()` currently denies many credential-shaped strings by pattern. That is useful but not enough for unknown provider credential formats. Before hosted/provider claims, projection code needs typed evidence-ref allowlists per provider/action family or deny-by-default handling for credential namespaces. Continue to expose opaque refs and digests, not raw material. - -10. Package and planning drift are architecture gates. - - `package.json`, `scripts/check-package-surface.mjs`, and `scripts/check-published-entrypoints.mjs` already make package shape source-owned. Keep `.planning/` excluded from package files and keep `.planning` labels out of source paths, scripts, exports, CI names, and canonical docs. If scratch planning maps stay tracked, add guard tests around what can be promoted to canon rather than treating `.planning/codebase/*` as authority. - -## Boundaries that must not move - -- `src/protocol/areas/*` owns Tier 1 primitive meaning. Do not move x402 request posture, MCP schema convenience, sandbox labels, or runtime family dispatch into protocol primitives unless a real new protocol primitive is being introduced. -- `src/runtime/` may record runtime execution, generated graph evidence, tool-call drafts, intent compilations, action contracts, and refusals. It must not issue policy decisions, greenlights, gateway checks, receipts, authority certificates, or mutation attempts. -- `src/mcp/` may expose proposal/evidence transport only. It must not import adapters, wallet/signing code, storage, protocol kernel internals, gateway transitions, all-role SDK clients, or credential custody surfaces. -- `src/adapters/x402-payment/` owns local/reference x402 upstream evidence, install proposal, conformance, sandbox, and wallet gateway fixtures. It does not define protocol semantics and must not claim live provider custody, seller middleware, facilitator operation, settlement finality, or aggregate spend enforcement. -- `src/protocol/evidence-projections/` owns redacted diagnostic projections. HTTP, SDK, CLI, and MCP may route projections but must not become raw reconstruction or authority surfaces. -- `src/storage/*` owns persistence mechanics. KV remains cache posture only. D1/memory must preserve the same protocol-store contract. -- Canon remains `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, and `docs/internal/*`. `.planning/` is scratch. - -## Files/modules likely touched - -Nearest source fixes: - -- `src/runtime/ingress/index.ts`: forward x402 posture fields; add or prepare family adapter extraction. -- `test/runtime/runtime-ingress.test.ts`: x402 posture propagation/refusal tests; no-authority record-count assertions. -- `src/mcp/x402-proposal.ts`: add request-body and provider-environment posture fields, pre-contract refusal, parameter forwarding, idempotency binding. -- `test/mcp/mcp-schema-contract.test.ts`: schema fixture and catalog metadata update. -- `test/mcp/mcp-x402-proposal.test.ts`: live/unknown/external/omitted/unsupported posture refusal and idempotency/parity tests. -- `scripts/check-published-entrypoints.mjs`: reference MCP proposal input must include new posture fields if schema requires them. - -Sandbox/evidence boundary: - -- `src/adapters/x402-payment/sandbox-http.ts`: explicit local/reference evidence role and retry boundary. -- `src/adapters/x402-payment/wallet-gateway.ts`: ensure retry/sandbox evidence remains post-gate and non-settlement in returned evidence refs. -- `src/protocol/evidence-projections/projections.ts`: classify signed retry as local/reference evidence and settlement-finality-negative. -- `src/adapters/x402-payment/conformance.ts`: classify any new x402 evidence label without authority or settlement finality. -- `test/adapters/x402-wallet-gateway.test.ts`, `test/protocol/evidence-projections.test.ts`, `test/conformance/x402-payment-conformance.test.ts`, `test/product/x402-protected-spend-demo-report.test.ts`: boundary assertions. - -Runtime family boundary: - -- `src/runtime/ingress/index.ts` -- possible new files under `src/runtime/ingress/`, for example `registry.ts`, `families/x402-payment.ts`, `families/package-install.ts`, and `families/auth-md-protected-api-call.ts` -- `test/runtime/runtime-ingress.test.ts` -- `test/runtime/auth-md-candidate-compilation.test.ts` -- `test/architecture/import-posture.test.ts` and `test/architecture/naming-posture.test.ts` if folder shape changes - -Spend/custody/bypass claim guards: - -- `src/adapters/x402-payment/install-proposal.ts` -- `src/adapters/x402-payment/conformance.ts` -- `src/adapters/x402-payment/bypass-probes.ts` -- `examples/x402-protected-spend/run.ts` -- `examples/x402-protected-spend/README.md` -- `test/adapters/x402-install-proposal.test.ts` -- `test/adapters/x402-bypass-probes.test.ts` -- `test/architecture/claim-boundary.test.ts` -- `test/architecture/self-hosted-activation-claim-boundary.test.ts` - -Projection scale/redaction if included in the executable plan: - -- `src/protocol/store/port.ts` -- `src/storage/d1/index.ts` -- `src/storage/memory/index.ts` -- `migrations/0001_protocol_kernel.sql` -- `src/protocol/evidence-projections/assembly.ts` -- `src/protocol/evidence-projections/projections.ts` -- `test/protocol/evidence-projections.test.ts` -- `test/protocol/protocol-store-atomicity-contract.test.ts` -- `test/http/d1-http.test.ts` - -Package/planning gates: - -- `package.json` -- `scripts/check-package-surface.mjs` -- `scripts/check-published-entrypoints.mjs` -- `test/architecture/package-surface.test.ts` -- `test/architecture/claim-boundary.test.ts` -- `test/architecture/active-vocabulary.test.ts` - -## Compatibility/migration risks - -- MCP schema changes can break existing callers and packaged smoke fixtures. Prefer a metadata digest/catalog version bump and a backwards-compatible normalization path only when omission truly means legacy `no_body` plus `local_reference_sandbox`; explicit `omitted`, `unsupported`, `external_sandbox`, `live`, or `unknown` must refuse before contract proposal. -- Adding posture fields to idempotency material changes deterministic IDs for new proposals. Do not rewrite old receipts or claim historical equivalence. If needed, version the idempotency material label while keeping prior evidence reconstructable. -- Runtime family extraction can silently change graph-node classification, sequence dependencies, raw sibling refusal, or signing-secret selection. It should happen after the direct posture fix and be guarded by current runtime/auth-md/package-install tests. -- D1 scoped-read migration must be additive. Existing records remain in `protocol_records`; new indexes or side tables must not change canonical record digests. -- Projection redaction tightening can hide refs that current product tests expect. Update tests around roles, not raw strings: credential material stays hidden; opaque refs and digests stay visible where they are safe. -- `dist/` artifacts will drift until `npm run build` or `npm run pack:check` runs. Do not treat checked-in bundles as current proof after source changes. -- Dirty worktree files named in the input packet are current state, not something to revert. The plan must validate them or build on them. - -## Architecture validation gates - -Focused posture gates: - -```bash -npm run test -- test/adapters/x402-payment-action-proposal.test.ts test/runtime/runtime-ingress.test.ts -npm run test -- test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/mcp/mcp-reference-transcript.test.ts test/mcp/mcp-stdio-process.test.ts -``` - -Sandbox and x402 boundary gates: - -```bash -npm run test -- test/adapters/x402-wallet-gateway.test.ts test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts test/product/x402-protected-spend-demo-report.test.ts -npm run demo:aps -``` - -Runtime family/refactor gates: - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/runtime/package-install-runtime.test.ts test/protocol/generated-execution-graph.test.ts -npm run quality:architecture -``` - -Projection/storage gates if store-port work is included: - -```bash -npm run test -- test/protocol/evidence-projections.test.ts test/protocol/protocol-store-atomicity-contract.test.ts test/http/d1-http.test.ts -npm run quality:storage -``` - -Claim, package, and repo gates: - -```bash -npm run quality:claims -npm run pack:check -npm run check:repo -``` - -Required assertions inside the focused tests: - -- Runtime and MCP refused posture cases create no `policy_decision`, `greenlight`, `gateway_check_attempt`, `mutation_attempt`, `receipt`, or `authority_certificate` records. -- Runtime and MCP accepted local/reference cases bind `intendedRequestBodyPosture`, `intendedRequestBodyDigest`, `providerEnvironmentPosture`, `providerEnvironmentRef`, and selected headers into candidate parameters and params/idempotency material. -- Sandbox signed retry evidence is projected as local/reference downstream observation, not settlement finality, facilitator operation, seller middleware, provider custody, or authority. -- Spend session/day/review fields remain `not_enforced_local_metadata` unless a real reservation ledger is implemented. -- MCP and CLI package entrypoints still emit non-authority flags and leak neither `PaymentPayload` nor `PAYMENT-SIGNATURE`. - -## Blocked checks - -- Not run in this ARCH pass: all tests, demos, package checks, and `check:repo`. This role is assigned a planning output only and file edits outside this raw output are forbidden. -- Not inspected by instruction: sibling raw outputs, normalized outputs, and `.planning/macro/PLAN.md`. -- Live provider/customer custody validation is blocked by absent provider/vault gateway integration and must remain a future cut, not a current x402 claim. -- Broad host/browser/shell/package-manager/cloud/repo interception validation is blocked by absent host-specific harnesses and must remain a future cut. -- Actual npm publication and MCP Registry publication are blocked by external owner credentials; `pack:check` can prove package shape only. - -## Smallest next mechanism to build - -Forward x402 request-body and provider-environment posture through `x402PaymentAttemptForDispatch()`, bind it into x402 candidate/idempotency material, and add runtime refusal tests proving live/unknown/external/unsupported posture cannot produce an `ActionContract`. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/EXECUTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/EXECUTION.md deleted file mode 100644 index 1a1529a..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/EXECUTION.md +++ /dev/null @@ -1,211 +0,0 @@ -# EXECUTION Perspective - -## Phase Sequence - -Invariant at stake: exact x402 request/body/provider posture must survive runtime and MCP proposal surfaces without creating authority, and local evidence must not be confused with provider enforcement. - -1. **Runtime x402 posture propagation and recorded refusal** - - Source changes: - - `src/runtime/ingress/index.ts`: forward `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef` from `RuntimeIngressObservedDispatchSchema` into the x402 attempt. - - `src/adapters/x402-payment/action-proposal.ts`: expose a non-authority runtime refusal builder or split compile-input construction so runtime ingress can record a graph/tool-call/intent refusal instead of throwing when x402 posture is unsupported. - - `src/adapters/x402-payment/action-proposal.ts`: include body posture and provider-environment posture/ref in x402 idempotency material so the contract key is bound to the same semantics as the params digest. - - Tests: - - `test/runtime/runtime-ingress.test.ts`: add unsupported body/live provider dispatch cases that produce `one_or_more_dispatches_refused`, include `x402_request_body_posture_unsupported` and `x402_provider_environment_not_sandboxed`, create no action contract, and create no policy/greenlight/gateway/mutation/receipt records. - - `test/runtime/runtime-ingress.test.ts`: add supported digest-bound/local-reference case proving the resulting contract parameters preserve body posture, body digest, provider posture, and provider ref. - - `test/adapters/x402-payment-action-proposal.test.ts`: assert x402 idempotency changes when posture/ref changes where the attempt is contractable. - -2. **MCP x402 posture parity** - - Source changes: - - `src/mcp/x402-proposal.ts`: require explicit `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and nullable `providerEnvironmentRef` in `McpX402PaymentProposalInputSchema`. - - `src/mcp/x402-proposal.ts`: preflight MCP proposals through the same x402 refusal semantics as the direct adapter path before any runtime-client call. - - `src/mcp/x402-proposal.ts`: bind the posture fields into `x402Parameters()`, `deriveMcpX402IdempotencyKey()`, tool-call draft parameters, compile-intent candidate parameters, and any execution-block digest material. - - `scripts/check-published-entrypoints.mjs`: update the reference MCP proposal input so package smoke tests exercise the explicit posture schema. - - Tests: - - `test/mcp/mcp-schema-contract.test.ts`: require the new posture fields in `validProposalInput()` and reject omitted posture as invalid input. - - `test/mcp/mcp-x402-proposal.test.ts`: prove `unsupported`, `omitted`, `live`, `unknown`, and `external_sandbox` postures refuse before runtime calls, with non-authority structured outcomes. - - `test/mcp/mcp-x402-proposal.test.ts`: prove supported local/digest-bound posture reaches `compileIntent` with matching parameters and a posture-bound idempotency key. - - `test/mcp/mcp-stdio-process.test.ts` and package smoke path: keep stdio proposal/evidence only. - -3. **x402 local sandbox evidence boundary** - - Source changes: - - `src/adapters/x402-payment/sandbox-http.ts`: add an explicit local/reference evidence-boundary object to challenge and signed-retry outputs: local fixture scope, `authorityCreated: false`, `sellerMiddlewareOperated: false`, `facilitatorSettlementPerformed: false`, and `settlementFinality: "not_settlement_finality"`. - - `src/adapters/x402-payment/sandbox-http.ts`: keep signed retry recording gated on gateway-created signature evidence, local-reference provider posture, and non-ambiguous body posture. - - `src/protocol/evidence-projections/projections.ts`: keep signed retry labels as downstream fixture evidence and forbid facilitator settlement/finality labels for local sandbox refs. - - Tests: - - `test/adapters/x402-wallet-gateway.test.ts`: assert sandbox challenge and signed retry carry the evidence-boundary object and never carry settlement, middleware, or authority fields. - - `test/adapters/x402-wallet-gateway.test.ts`: add refusal cases for missing signature evidence, wrong signature header, non-reference provider posture, and ambiguous body posture with unchanged signed-retry count. - - `test/protocol/evidence-projections.test.ts`: prove `evidence:x402-local-sandbox-signed-retry:*` projects as downstream local fixture evidence, not facilitator settlement or finality. - - `test/product/x402-protected-spend-demo-report.test.ts`: pin buyer-readable report language to local/reference signed retry evidence only. - -4. **Runtime ingress family adapter registry** - - Source changes: - - `src/runtime/ingress/index.ts`: extract family-specific conversion behind a source-owned runtime ingress family registry while preserving the public `proposeRuntimeIngressActionContracts()` API. - - Candidate registry shape: `family`, `dispatchKind` coverage, `requiresConfig`, `buildCompileIntentInput`, `preflightRefusalReasonCodes`, `signingSecret`, `supportedGrammarVersion`, and `rawBypassReasonCodes`. - - Keep runtime ingress proposal-only: registry adapters must not import policy, greenlight, gateway, receipt, storage implementation, or mutation code. - - Tests: - - `test/runtime/runtime-ingress.test.ts`: existing package/x402/auth.md cases must pass through the registry unchanged. - - Add a registry coverage test under `test/runtime/` proving every dispatch kind has exactly one family adapter, missing family config fails closed, and mixed-family blocks retain `runtime-dispatch-mixed-0.1`. - - `test/architecture/import-posture.test.ts`: guard the registry against forbidden authority imports. - -5. **x402 future-surface, spend, custody, and host-bypass guards** - - Source changes: - - `src/adapters/x402-payment/conformance.ts`: keep unsupported x402 surfaces as source-owned cut lines and add explicit future-cut classifications for aggregate spend ledger, provider/customer custody, host-wide interception, facilitator/seller middleware, hosted verifier, and registry publication where they are not already represented. - - `src/adapters/x402-payment/install-proposal.ts`: keep session/day/review controls under `spendWindowEnforcementStatus: "not_enforced_local_metadata"` and prevent them from entering action-contract bounds until a reservation ledger exists. - - `src/adapters/x402-payment/bypass-probes.ts`: keep fixture gateway custody distinct from real gateway custody; host-bypass probes remain scoped evidence, not host-wide interception. - - Tests: - - `test/conformance/x402-payment-conformance.test.ts`: pin every unsupported/future surface to a refusal/cut-line reason code. - - `test/adapters/x402-install-proposal.test.ts`: assert spend-window metadata never appears in contract bounds and cannot be claimed as enforced. - - `test/adapters/x402-bypass-probes.test.ts`: distinguish fixture custody from live provider/customer custody and host-scoped bypass evidence from broad host interception. - - `test/architecture/claim-boundary.test.ts`: keep README/MCP/runtime/doc claims inside exact buyer-side local/reference proof. - -6. **Evidence projection scale and redaction mechanisms** - - Source changes: - - `src/protocol/store/port.ts`: add contract-scoped evidence lookup methods and batched stream-event range reads. - - `src/storage/d1/index.ts` and `migrations/0001_protocol_kernel.sql`: add the D1 indexes/tables needed for contract/action/run scoped projection assembly and receipt timeline range reads. - - `src/protocol/evidence-projections/assembly.ts`: replace broad tenant/org scans with contract-scoped store methods. - - `src/protocol/evidence-projections/projections.ts`: replace regex-only credential hiding with an allowlisted projection-ref policy plus deny patterns for known credential classes. - - Tests: - - `test/protocol/evidence-projections.test.ts`: add provider-format redaction fuzz cases for token, bearer, vault, infisical, raw signature, payment payload, facilitator secret, and auth.md credential refs. - - `test/http/d1-http.test.ts`: add D1 fixtures proving projection assembly uses scoped indexes and timeline range reads under high unrelated record volume. - - `test/protocol/protocol-store-atomicity-contract.test.ts`: pin memory/D1 parity for new store methods and conflict behavior. - -7. **Publish/package and `.planning` scratch drift gates** - - Source changes: - - `scripts/check-package-surface.mjs`: keep `.planning`, tests, local metadata, and generated scratch out of publish dry-run artifacts. - - `scripts/check-published-entrypoints.mjs`: keep CLI/MCP smoke outputs non-authority and synchronized with the new MCP posture schema. - - Architecture tests: add an active guard that `.planning` paths cannot appear in package exports, package files, package scripts, CI names, README command sections, or canonical docs except as scratch-boundary language. - - Tests: - - `test/architecture/package-surface.test.ts`: pin packable files and `check:repo` -> `pack:check`. - - `test/architecture/active-vocabulary.test.ts` and `test/architecture/claim-boundary.test.ts`: reject source/package/README claims that promote `.planning` maps to canon. - - `npm run pack:check`: mandatory before any publish-ready or registry-ready claim. - -## Task Graph - -```text -T1 runtime-failing-tests - -> T2 runtime-x402-preflight-refusal-builder - -> T3 runtime-forward-posture-fields - -> T4 runtime-idempotency-posture-binding - -> T5 runtime-focused-gate - -T6 mcp-schema-failing-tests - depends on T2 - -> T7 mcp-explicit-posture-schema - -> T8 mcp-preflight-refusal-and-binding - -> T9 mcp-stdio-and-package-smoke-update - -T10 sandbox-boundary-tests - -> T11 sandbox-boundary-source-object - -> T12 projection-signed-retry-label-guard - -> T13 product-demo-boundary-gate - -T14 runtime-registry-tests - depends on T5 - -> T15 runtime-family-registry-refactor - -> T16 runtime-registry-architecture-gate - -T17 x402-cutline-tests - -> T18 conformance-future-surface-cutlines - -> T19 spend-metadata-and-custody-guards - -T20 projection-scale-redaction-tests - -> T21 store-port-scoped-methods - -> T22 d1-index-and-range-read-implementation - -> T23 projection-assembly-refactor - -> T24 redaction-policy-hardening - -T25 package-planning-drift-tests - depends on T7 - -> T26 package-smoke-and-planning-guard-updates -``` - -## Dependency Map - -- Phase 1 blocks Phase 2 because MCP parity should reuse the same x402 posture refusal semantics rather than inventing a second refusal table. -- Phase 1 blocks Phase 4 because extracting the runtime registry before fixing x402 posture can preserve the bug behind cleaner structure. -- Phase 2 blocks package smoke updates because `scripts/check-published-entrypoints.mjs` must use the final MCP schema. -- Phase 3 can run after Phase 1 starts; it shares x402 posture vocabulary but does not depend on the MCP bridge. -- Phase 5 can run in parallel with Phase 3 once the direct/runtime posture semantics are stable. -- Phase 6 is independent of runtime/MCP behavior except for evidence labels; start after Phase 3 if signed-retry projection labels change. -- Phase 7 depends on Phase 2 for MCP smoke inputs and should close last so package gates reflect the final public surface. - -## Critical Path - -```text -T1 -> T2 -> T3 -> T4 -> T5 -> T6 -> T7 -> T8 -> T9 -> T25 -> T26 -> full validation -``` - -This is the critical path because runtime posture propagation is the known high-priority defect, MCP parity must not fork the semantics, and package/public smoke gates must reflect the final MCP input contract. - -## Parallelizable Work - -- Sandbox boundary work (`T10`-`T13`) can proceed while MCP parity is implemented, as long as it keeps the same posture enum values. -- x402 cut-line/conformance work (`T17`-`T19`) can proceed after the direct adapter refusal table is settled. -- Evidence projection scale/redaction work (`T20`-`T24`) can proceed independently, with one coordination point on signed-retry evidence labels from Phase 3. -- Package/planning drift tests (`T25`) can be drafted early, but the package smoke implementation (`T26`) must wait for MCP schema finalization. - -## First Executable Step - -Add a failing regression test to `test/runtime/runtime-ingress.test.ts`: - -- Create a `wrapped_x402_payment` dispatch with `intendedRequestBodyPosture: "unsupported"`, `providerEnvironmentPosture: "live"`, and `providerEnvironmentRef: "provider-environment:x402-live"`. -- Expect `proposeRuntimeIngressActionContracts()` to return `one_or_more_dispatches_refused`. -- Expect response and proposal reason codes to include `x402_request_body_posture_unsupported` and `x402_provider_environment_not_sandboxed`. -- Expect zero `action_contract`, `policy_decision`, `greenlight`, `gateway_check_attempt`, `mutation_attempt`, and `receipt` records. -- Expect runtime and generated graph evidence to be recorded, with the x402 dispatch node classified non-contractable instead of throwing. - -Only after that test fails for the right reason, patch `src/runtime/ingress/index.ts` and `src/adapters/x402-payment/action-proposal.ts`. - -## Validation Gates - -Focused gates after Phase 1: - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/adapters/x402-payment-action-proposal.test.ts -npm run check:types -``` - -Focused gates after Phase 2: - -```bash -npm run test -- test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/mcp/mcp-reference-transcript.test.ts test/mcp/mcp-stdio-process.test.ts -npm run check:types -``` - -Focused gates after Phase 3 and Phase 5: - -```bash -npm run test -- test/adapters/x402-wallet-gateway.test.ts test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts test/product/x402-protected-spend-demo-report.test.ts -npm run quality:claims -``` - -Focused gates after Phase 4: - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts -npm run quality:architecture -``` - -Focused gates after Phase 6: - -```bash -npm run test -- test/protocol/evidence-projections.test.ts test/http/d1-http.test.ts test/protocol/protocol-store-atomicity-contract.test.ts -npm run quality:storage -``` - -Final gates: - -```bash -npm run demo:aps -npm run quality:claims -npm run quality:architecture -npm run pack:check -npm run check:repo -``` - -## Blocked Checks - -- No user-owned product decision blocks execution; the current concern packet already cuts ledger, live custody, host-wide interception, hosted verifier, facilitator/seller middleware, and registry publication from this macro plan. -- External publication checks remain blocked on owner-held npm/MCP Registry credentials, so validation must stop at `npm run pack:check` and source-owned package smoke tests. -- Live provider/customer custody tests remain blocked until a real provider/vault custody integration is introduced; current work can only add fixture-vs-live cut-line tests. -- Broad host interception checks remain blocked until a specific host adapter/browser/shell/package-manager/cloud integration is in scope; current work can only preserve runtime/MCP bypass evidence as scoped, non-host-wide evidence. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/RISK.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/RISK.md deleted file mode 100644 index ef394b7..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/RISK.md +++ /dev/null @@ -1,75 +0,0 @@ -# RISK Perspective: Concerns Elimination - -## Invariant At Stake - -No consequential autonomous action executes outside declared bounds, and divergent behavior must be haltable, isolatable, and reconstructable. - -The current danger is false closure: runtime/MCP proposal surfaces can look aligned with the x402 adapter while dropping refusal-critical posture, sandbox evidence can be mistaken for seller/facilitator authority, and package/docs gates can make publish or hosted claims before source mechanisms exist. - -## P0 Risk Register - -| ID | Risk | Failure mode | Mitigation or cut line | Required validation gate | -| --- | --- | --- | --- | --- | -| P0-R1 | Runtime x402 posture defaulting creates weaker contracts than the direct adapter. | `RuntimeIngressObservedDispatchSchema` accepts `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef`, but `x402PaymentAttemptForDispatch()` currently omits them. Unsupported body posture or live/unknown provider posture can default to `no_body` and `local_reference_sandbox` before proposal. | Propagate the three fields into `X402PaymentAttempt`; add a shared x402 posture fixture/helper so runtime tests and adapter tests assert the same refusal codes. Cut line: runtime ingress cannot be described as an official x402 proposal path until unsupported/live/unknown dispatches refuse before contract proposal. | `npm run test -- test/runtime/runtime-ingress.test.ts test/adapters/x402-payment-action-proposal.test.ts`; assertions: no `intent_compilation`, `action_contract`, `greenlight`, or `gateway_check_attempt` on unsupported/live posture. | -| P0-R2 | MCP x402 proposal schema cannot express the same request/provider refusal boundary. | `McpX402PaymentProposalInputSchema`, `x402Parameters()`, and `deriveMcpX402IdempotencyKey()` omit request-body posture and provider-environment posture. A model-facing MCP proposal can produce a weaker candidate than the adapter would accept. | Add `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef` to the strict MCP schema; forward them into candidate parameters, tool-call drafts, non-secret summaries, and idempotency digest material; preflight refuse omitted/unsupported/live/unknown before runtime calls. Cut line: MCP stays proposal/evidence only and cannot be called "parity" until these fields are contract-bound. | `npm run test -- test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/architecture/mcp-surface-posture.test.ts`; pack smoke must update its reference proposal input. | -| P0-R3 | Local sandbox signed retry evidence is confused with seller middleware, facilitator settlement, or authority. | `createLocalX402PaidHttpSandbox()` emits official-shaped 402 challenge evidence and signed retry observation. Even with `authorityCreated: false`, product/demo text can launder it into payment finality or facilitator operation. | Keep sandbox evidence under explicit local/reference types and refs; keep `authorityCreated: false` on challenge and retry; classify signed retry as downstream fixture observation after `VerifiedGatewayCheck`, not policy, greenlight, gateway check, settlement, or signing authority. Cut line: no seller middleware, facilitator operation, settlement finality, or live paid HTTP claim without separate adapter and tests. | `npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts test/product/x402-protected-spend-demo-report.test.ts test/architecture/claim-boundary.test.ts`. | -| P0-R4 | Signer custody leaks into runtime/MCP/CLI or becomes a live provider custody claim. | `createOfficialExactX402SigningSurface()` uses an injected `ClientEvmSigner`; this proves gateway-side fixture/local signing after a passed gate, not provider vault lifecycle, customer custody, rotation, or revocation. | Keep signer factory out of adapter barrels and public root/runtime/MCP/CLI exports; enforce gateway-held or fixture-gateway-held signer posture in install/conformance; redact `PaymentPayload`, `PAYMENT-SIGNATURE`, raw private keys, and signer refs in projections and demos. Cut line: no live/provider/customer custody claim without provider-specific custody resolver, rotation/revocation tests, and gateway failure tests. | `npm run test -- test/architecture/import-posture.test.ts test/adapters/x402-wallet-gateway.test.ts test/adapters/x402-bypass-probes.test.ts test/protocol/evidence-projections.test.ts`. | -| P0-R5 | Runtime/MCP bypass evidence is overclaimed as host-wide interception. | Runtime ingress records observed/synthetic bypass-shaped evidence, and MCP rejects authority-shaped inputs. Neither proves browser, shell, package manager, cloud, network, repo, or sibling MCP interception in a real host. | Keep bypass posture as observed evidence only. Require host-specific bypass probes and installed gateway-owned credentials before claiming protection for any host. Cut line: broad MCP/runtime/browser/shell/network/package protection remains future work. | `npm run quality:claims`; `npm run test -- test/runtime/runtime-ingress.test.ts test/mcp/mcp-x402-proposal.test.ts test/architecture/mcp-surface-posture.test.ts`. | - -## P1 Risk Register - -| ID | Risk | Failure mode | Mitigation or cut line | Required validation gate | -| --- | --- | --- | --- | --- | -| P1-R1 | Runtime ingress family hardcoding causes cross-family refusal drift. | `src/runtime/ingress/index.ts` owns multiple family schemas, conversion functions, graph nodes, and dispatch classifiers. New families can miss refusal fields or inherit x402 defaults. | Introduce a source-owned family adapter/registry interface for dispatch schema, attempt conversion, graph node metadata, refusal preflight, and signing-secret lookup. Migrate one family at a time with no public claim expansion. Cut line: no new protected-action family through the monolithic switch after the registry exists. | `npm run test -- test/runtime/runtime-ingress.test.ts test/runtime/auth-md-candidate-compilation.test.ts test/runtime/package-install-runtime.test.ts`; `npm run quality:architecture`. | -| P1-R2 | Spend windows are metadata but get read as aggregate enforcement. | `X402SpendBoundsSchema` carries session/day/review fields with `spendWindowEnforcementStatus: "not_enforced_local_metadata"`; changed-amount retries can create separate per-call contracts. | Either implement a reservation ledger keyed by tenant/org/principal/agent/action/resource/window with conflict semantics and recovery evidence, or keep all aggregate spend copy/tests as non-claims. Cut line: no session/day/review enforcement claim until the ledger is source-owned and D1-backed. | Current cut-line gate: `npm run test -- test/runtime/runtime-ingress.test.ts test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts`. Future ledger gate must add D1 atomicity and conflict tests. | -| P1-R3 | Evidence redaction is denylist-shaped and can miss provider credential formats. | `redactedProjectionRefs()` filters raw-looking refs by regex. Unknown vault/provider formats can pass into contract/envelope projections. | Move live-provider projections toward allowlisted typed refs and digests; add provider-format fuzz fixtures for secret refs, payment signatures, bearer tokens, vault paths, and x402 payload terms. Cut line: no hosted audit/search or provider-custody evidence claim while redaction depends only on generic patterns. | `npm run test -- test/protocol/evidence-projections.test.ts test/http/http.test.ts test/integration/auth-md-receipt-reconstruction.test.ts`; add fuzz tests before any live-provider phase closes. | -| P1-R4 | D1/projection assembly does tenant/org scans and per-offset receipt reads. | `assembleAgentTransactionEnvelope()` calls broad `listRecordsByType()` for many object types, and receipt timeline reads load stream events one offset at a time. Hosted evidence reads will degrade or time out under real volume. | Add contract/action/run-scoped store methods, D1 indexes, and batched stream-event range reads. Keep current projections as local diagnostic reads until this lands. Cut line: no hosted audit/search, high-volume evidence, or customer dashboard claim. | `npm run quality:storage`; add scale fixtures around `assembleAgentTransactionEnvelope()` and receipt timeline reads before hosted claims. | -| P1-R5 | Publish/package drift ships stale bundles or stale MCP schema. | Dirty source can change runtime/MCP/x402 behavior while `dist/**`, bin smoke inputs, or package metadata lag behind. | Treat `npm run pack:check` as mandatory for publish readiness; update package entrypoint smoke inputs when MCP schema changes; fail if `.planning/`, tests, or scratch docs enter packed files. Cut line: no npm/MCP Registry/public install claim from source-only changes. | `npm run pack:check`; `node scripts/check-package-surface.mjs`; `node scripts/check-published-entrypoints.mjs`; `npm run check:repo`. | -| P1-R6 | x402 future surfaces sneak into `x402_payment.exact`. | `upto`, batch settlement, signed offers/receipts, lifecycle hooks, seller middleware, facilitator operation, and MCP auto-pay can be mistaken as extensions of the first wedge. | Keep `classifyX402FirstWedgeSurface()` as the source-owned cut line; add hostile/future upstream fixtures for unknown extensions, multiple accepts, non-exact schemes, malformed assets, and facilitator-shaped labels. Cut line: create new action classes only after policy/gateway/receipt support exists. | `npm run test -- test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts test/architecture/claim-boundary.test.ts`. | - -## P2 Risk Register - -| ID | Risk | Failure mode | Mitigation or cut line | Required validation gate | -| --- | --- | --- | --- | --- | -| P2-R1 | `.planning` scratch drift becomes repo canon. | Derived maps and macro outputs can be treated as source truth by future agents, reviving stale Tier 2 labels or overbroad claims. | Add/keep source-owned docs stating `.planning/` is scratch; ensure package surface excludes `.planning/`; do not create scripts, exports, CI names, or README sections from planning labels. Cut line: promote only source-backed decisions into `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, or `docs/internal/*`. | `npm run quality:claims`; `npm run pack:check`; add an architecture guard if README/package/scripts begin referencing `.planning` as canon. | -| P2-R2 | False completion through doc-only concern closure. | A plan can mark concerns closed after copy edits while source still defaults, overclaims, or leaks evidence. | Closure rule: every concern needs one source mechanism, one focused regression test, and one architecture/claim/package gate. Documentation can only follow source behavior. Cut line: if a concern has no source diff or test diff, it remains open. | Closeout must include focused tests plus `npm run quality:claims`, `npm run quality:architecture`, `npm run pack:check`, and `npm run check:repo`. | -| P2-R3 | Demo output normalizes non-authority proof-object language. | Buyer-readable `x402_paid_http_call.exact` can be mistaken as an action catalog entry, and report output can imply hosted/live provider behavior. | Keep buyer-readable names explicitly non-authority and backed by actual `x402_payment.exact` action-contract fields; product tests must assert local/reference labels, gateway holder, non-claims, and absent raw signer terms. Cut line: no new proof-object label until action catalog, compiler, policy, and gateway expose a matching action class. | `npm run demo:aps`; `npm run test -- test/product/x402-protected-spend-demo-report.test.ts test/architecture/claim-boundary.test.ts`. | -| P2-R4 | Gateway failure evidence remains too coarse for operations. | `runX402WalletGateway()` collapses signing failures to digest-only diagnostics, hiding selected-requirement drift versus SDK/signer/provider failure. | Add redacted failure reason codes without exposing signer material, `PaymentPayload`, or `PAYMENT-SIGNATURE`. Cut line: coarse failure classification is acceptable for local foundation, but not for hosted operations/support claims. | `npm run test -- test/adapters/x402-wallet-gateway.test.ts test/protocol/evidence-projections.test.ts`. | - -## Validation Gates - -Minimum implementation gate for this concerns-elimination plan: - -1. Focused P0 regression gate: - `npm run test -- test/runtime/runtime-ingress.test.ts test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-x402-proposal.test.ts test/adapters/x402-payment-action-proposal.test.ts test/adapters/x402-wallet-gateway.test.ts` -2. x402 future-surface and bypass gate: - `npm run test -- test/conformance/x402-payment-conformance.test.ts test/conformance/x402-upstream-exact-fixtures.test.ts test/adapters/x402-bypass-probes.test.ts` -3. Evidence/redaction/storage gate: - `npm run quality:storage` -4. Claim and architecture gate: - `npm run quality:claims && npm run quality:architecture` -5. Publish drift gate: - `npm run pack:check` -6. Final closeout gate: - `npm run check:repo` - -No concern is closed unless the focused gate and the final closeout gate both pass on the dirty worktree state being shipped. - -## Rollback And Stop Conditions - -- Stop if runtime or MCP unsupported/live/unknown posture still reaches `action_contract_proposed`. -- Stop if any runtime or MCP test creates `policy_decision`, `greenlight`, `gateway_check_attempt`, `mutation_attempt`, `receipt`, or `authority_certificate`. -- Stop if sandbox evidence introduces `authorityCreated: true`, settlement finality, seller middleware, facilitator operation, or live provider language. -- Stop if signer, `PaymentPayload`, raw private key, `PAYMENT-SIGNATURE`, bearer token, vault path, or provider secret material appears in MCP/CLI/demo/projection serialized output. -- Stop if aggregate spend/session/day/review language appears without a D1-backed reservation ledger. -- Stop if D1/projection changes rely on broader tenant/org scans for a hosted claim. -- Stop if package entrypoint smoke does not exercise the final MCP schema after posture fields are added. -- Stop if `.planning/` becomes a package file, public docs authority source, script name, CI name, exported symbol, or README claim source. -- Roll back claim text, not source guardrails, when source mechanisms pass but product copy overstates the installed boundary. -- Roll back implementation if it weakens Tier 1 protocol/kernel invariants or moves authority into runtime, MCP, CLI, demos, or review output. - -## Blocked Checks - -- No validation commands were run in this raw risk pass; this file is a planning artifact only. -- Sibling raw outputs, normalized outputs, and `.planning/macro/PLAN.md` were intentionally not read, so cross-perspective conflicts are unchecked here. -- Live provider custody, hosted verifier, npm publication, MCP Registry publication, facilitator/seller middleware, aggregate spend ledger, and host-wide interception cannot be validated from current source because those mechanisms are not implemented. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/STRATEGY.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/STRATEGY.md deleted file mode 100644 index 3161ca4..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/raw/STRATEGY.md +++ /dev/null @@ -1,112 +0,0 @@ -# STRATEGY - -## Invariant At Stake - -Runtime and MCP proposal surfaces must not make weaker x402 contracts than the direct adapter path, and the local buyer-side `x402_payment.exact` proof must not get broadened into ledger, custody, hosted, facilitator, seller, host-interception, or registry-publication claims. - -## Recommended Macro Shape - -1. Close the proposal correctness defects first. - - Fix runtime x402 posture propagation before any broader cleanup. `src/runtime/ingress/index.ts` already accepts `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef`; the builder must pass them into `X402PaymentAttempt` so direct adapter refusals survive runtime ingress. - - Add runtime tests proving unsupported/omitted request-body posture, missing digest for digest-bound bodies, no-body/body-digest mismatch, and live/unknown/external provider posture refuse before action-contract proposal, with zero policy, greenlight, gateway, mutation, receipt, or certificate records. - -2. Bring MCP to parity while keeping it proposal/evidence only. - - Add the same body and provider-environment posture fields to `McpX402PaymentProposalInputSchema`. - - Bind those fields into MCP x402 parameters and idempotency material. - - Refuse live/unknown/unsupported posture before runtime-client calls where possible; otherwise prove the runtime/direct adapter path refuses before contract proposal. - - Preserve `generatedExecutionGraphPosture: "not_exposed_by_role_scoped_runtime_surface"` and all non-authority flags. - -3. Harden the local x402 sandbox evidence boundary. - - Treat `src/adapters/x402-payment/sandbox-http.ts` as local/reference fixture evidence only. - - Keep challenge and signed retry outputs explicitly `authorityCreated: false`. - - Make signed retry evidence impossible to read as seller middleware, facilitator settlement, provider custody, or payment finality. - - Keep official SDK `PaymentPayload` and `PAYMENT-SIGNATURE` creation behind `VerifiedGatewayCheck` in the wallet gateway. - -4. Convert first-wedge cut lines into source-owned guards. - - Keep `x402_payment.exact` as one buyer-side, per-call, local/reference path. - - Unsupported x402 surfaces stay classified through conformance code and tests: `upto`, batch settlement, lifecycle hooks, MCP auto-pay, signed offers, signed receipts, seller middleware, and facilitator operation. - - Keep `x402_paid_http_call.exact` buyer-readable only until the action catalog, compiler, policy, and gateway expose it as a real action class. - - Spend-window session/day/review fields remain metadata. Do not build a partial ledger in this macro. - -5. Only then reduce runtime ingress family hardcoding. - - Introduce a source-owned proposal-family adapter or registry boundary for runtime ingress. - - The registry may normalize dispatch families into candidate proposal inputs; it must not issue policy decisions, greenlights, gateway checks, receipts, mutations, or authority certificates. - - This phase should prevent future family additions from silently dropping refusal-critical fields. - -6. Close evidence, package, and planning drift with gates. - - Evidence projection work should add real redaction and scale mechanisms only where needed: contract-scoped store reads, D1 indexes/range reads, and provider-format redaction fuzzing. Do not claim hosted audit/search from projection cleanup. - - Package drift closes through `pack:check`, package-surface checks, and published-entrypoint smoke tests after source changes. - - `.planning` drift closes through architecture gates that keep `.planning` scratch out of package files, public scripts, canonical docs, exported names, and claim/vocabulary authority. - -## What To Cut - -- Cut aggregate spend ledger implementation from this macro. Keep spend windows unclaimable metadata until a dedicated reservation ledger phase defines tenant/org/principal/agent/action/resource/time-window keys, reservation state, conflicts, recovery, and receipts. -- Cut live provider/customer custody. Local signer proof and fixture gateway custody do not prove provider vault custody, customer wallet custody, rotation, revocation, or resolver failure semantics. -- Cut seller middleware, facilitator operation, settlement finality, signed offers, signed receipts, `upto`, and batch settlement. -- Cut host-wide interception claims for MCP, browser, shell, package manager, cloud API, network, repo, database, and sibling tools. -- Cut hosted verifier, JWKS/revocation, cross-org trust, marketplace, certification, and clearing-house claims. -- Cut npm/MCP Registry publication claims. Source can prove package shape; owner-held registry credentials and real publication are outside this repo. -- Cut any plan step that moves policy, greenlight, gateway check, mutation, signer custody, receipt export, or certificate minting into CLI, MCP, or runtime ingress. - -## User-Owned Decisions - -No user-owned decision is required to start the concern-elimination macro. - -Future decisions that remain deliberately outside this macro: - -- Whether to fund a real aggregate spend reservation ledger. -- Which provider custody target should become the first live custody adapter. -- Which host/runtime deserves real bypass-interception proof first. -- Whether and when to publish to npm or the MCP Registry with owner credentials. - -## Six-Month Regret Scenario - -The bad outcome is a clean-looking x402 demo that quietly taught the market the wrong product: runtime or MCP accepted live/unknown provider posture, defaulted it into local sandbox semantics, and emitted action-contract proposals that the direct adapter would have refused. A pilot then retries multiple changed-amount payments under metadata-only session/day limits, reads local signed retry evidence as settlement, and assumes MCP/runtime protected the host. Six months later the receipt trail is internally consistent but strategically useless because it proves proposal ceremony, not gateway-enforced custody, ledger control, settlement, or host interception. - -The second regret is over-abstracting runtime ingress before fixing dropped fields. A family registry that preserves the same posture loss just makes the bug easier to repeat across auth.md, package install, repo write, and future adapters. - -## Smallest Strategically Valid First Move - -Patch `x402PaymentAttemptForDispatch()` in `src/runtime/ingress/index.ts` to forward: - -- `intendedRequestBodyPosture` -- `intendedRequestBodyDigest` -- `providerEnvironmentPosture` -- `providerEnvironmentRef` - -Then add focused regression tests in `test/runtime/runtime-ingress.test.ts` proving a wrapped x402 dispatch with unsupported request-body posture or live/unknown provider posture refuses before action-contract proposal and creates no authority-bearing records. - -That first move is strategically valid because it closes an actual proposal-boundary defect while preserving the Tier 1 kernel and keeping runtime proposal-only. - -## Validation Gates - -- Runtime posture propagation: - - `npm run test -- test/runtime/runtime-ingress.test.ts test/adapters/x402-payment-action-proposal.test.ts` - - Gate must prove runtime x402 parity with direct adapter refusal semantics. - -- MCP posture parity: - - `npm run test -- test/mcp/mcp-x402-proposal.test.ts test/architecture/mcp-surface-posture.test.ts` - - Gate must prove MCP remains proposal/evidence only and cannot create policy, greenlight, gateway check, mutation, receipt export, signer custody, or authority certificate evidence. - -- x402 sandbox and first-wedge cut lines: - - `npm run test -- test/adapters/x402-wallet-gateway.test.ts test/integration/x402-d1-http.test.ts test/product/x402-protected-spend-demo-report.test.ts` - - `npm run test -- test/conformance/x402-upstream-exact-fixtures.test.ts test/conformance/x402-payment-conformance.test.ts` - - Gate must preserve local/reference labels, `authorityCreated: false`, post-gate signing, unsupported-surface classification, replay refusal, and no settlement/facilitator/seller/custody claims. - -- Evidence projection and storage hardening: - - `npm run test -- test/protocol/evidence-projections.test.ts test/http/d1-http.test.ts test/protocol/protocol-store-atomicity-contract.test.ts` - - Gate must prove redaction and reconstruction behavior without hosted audit/search claims. - -- Claim, architecture, package, and full repo: - - `npm run quality:claims` - - `npm run quality:architecture` - - `npm run demo:aps` - - `npm run pack:check` - - `npm run check:repo` - - Gate must fail on claim broadening, source/package drift, stale package entrypoints, and dirty whitespace. - -## Blocked Checks - -- Did not read sibling raw outputs, normalized outputs, or `.planning/macro/PLAN.md` by instruction. -- Did not run validation commands; this STRATEGY pass is a raw first-pass planning artifact, not an implementation pass. -- Did not inspect files outside the input packet's allowed source set. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/synthesis.md b/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/synthesis.md deleted file mode 100644 index d96d18e..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-concerns-elimination/concerns-elimination-20260524T044836Z/synthesis.md +++ /dev/null @@ -1,58 +0,0 @@ -# Chair Synthesis - -## Invariant At Stake - -No x402 proposal surface may create a cleaner contract than the protected path actually observed, and no evidence surface may imply authority, custody, settlement, hosted operation, broad interception, or aggregate spend enforcement that the gateway does not enforce. - -## Synthesis - -The five perspectives converged on the same sequence. The immediate implementation work is not a registry refactor, package cleanup, or docs correction. The first defect is runtime posture loss: the runtime schema accepts `intendedRequestBodyPosture`, `providerEnvironmentPosture`, and `providerEnvironmentRef`, but `x402PaymentAttemptForDispatch()` drops them before the direct adapter boundary. That can turn unsupported or live posture into default local-reference posture. This is compiler overreach by omission. - -The second defect is MCP posture parity. MCP is proposal/evidence only, but its model-facing x402 proposal schema currently cannot express the same body/provider boundary as the direct adapter. MCP must either bind explicit posture into a proposed contract or refuse before proposal. It must not solve parity by importing adapter execution, wallet, signer, storage, policy, gateway, receipt, all-role SDK, or certificate authority code. - -The third defect is evidence interpretation. The local x402 sandbox is useful because it shows a post-gate signed retry can be observed in a local/reference fixture. It is dangerous if the resulting evidence reads like seller middleware, facilitator operation, settlement finality, provider custody, or authority. The fix is a typed local/reference evidence boundary plus projection/demo tests, not friendlier copy. - -Only after those nearest defects are covered should runtime ingress be extracted behind a family registry. The registry is a hardening step to prevent future field loss; if done first, it can preserve the current bug in a cleaner shape. - -The rest of the concern set is not implementation-by-half. Spend ledger, provider/customer custody, hosted verifier, host-wide interception, seller/facilitator operation, settlement, and public registry publication are explicit cuts. This macro should add source-owned guards that keep those surfaces unclaimable, not partial substitutes. - -## Chosen Phase Order - -1. Runtime x402 posture propagation and pre-contract refusal. -2. MCP x402 posture parity while staying proposal/evidence only. -3. Local sandbox evidence boundary. -4. Runtime ingress family registry/refactor hardening. -5. x402 future-surface, spend metadata, custody, and host-bypass guards. -6. Evidence projection scale and redaction mechanisms. -7. Package, `.planning`, demo, and closeout gates. - -## Reconciled Differences - -- Some raw outputs mention no `intent_compilation` record on posture refusal, while others allow a refused compile-intent record. The synthesis requires no action contract or authority-bearing records. If the existing protocol path records a refused intent compilation, it must be explicitly non-authority and reconstructable. -- Some raw outputs suggest backwards-compatible MCP normalization. The synthesis chooses strict explicit posture fields. If compatibility is later required, omitted posture must still fail closed as schema invalid or structured pre-contract refusal. -- Evidence projection scale is included after x402 boundary phases, but it remains a mechanism for local reconstruction and future readiness. It does not authorize hosted audit/search claims. - -## Outputs Written - -- `.planning/macro/PLAN.md` -- `.planning/macro/CONTEXT.md` -- `.planning/macro/ASSUMPTIONS.md` -- `.planning/macro/DECISIONS.md` -- `.planning/macro/RISKS.md` -- `.planning/macro/VALIDATION.md` -- `.planning/macro/TASKS.jsonl` -- `.planning/macro/runs/concerns-elimination-20260524T044836Z/synthesis.md` - -## Blocked Checks - -- No implementation validation commands were run; this chair task writes planning artifacts only. -- Live provider/customer custody remains blocked by absent provider/vault custody mechanism. -- Aggregate spend enforcement remains blocked by absent reservation ledger. -- Hosted verifier/JWKS/revocation/cross-org trust remains blocked by absent hosted verifier mechanism. -- Broad host/browser/shell/package/cloud/repo/MCP interception remains blocked by absent host-specific harnesses. -- Seller middleware, facilitator operation, settlement finality, signed offers, signed receipts, `upto`, and batch settlement remain blocked by absent action classes, policy, gateway, and receipt support. -- Actual npm/MCP Registry publication remains blocked by owner-held external credentials. - -## Smallest Next Mechanism - -Add the failing runtime x402 posture regression in `test/runtime/runtime-ingress.test.ts`, then patch `x402PaymentAttemptForDispatch()` to forward posture fields and update x402 idempotency material. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/AUDIT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/AUDIT.md deleted file mode 100644 index c20ad75..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/AUDIT.md +++ /dev/null @@ -1,111 +0,0 @@ -# Tier 2 Macro Closeout Audit - -Date: 2026-05-24 - -Status: passed for repo-owned source closeout; external owner-held publication -and production-hosted proofs remain explicit proof gaps. - -## Invariant At Stake - -No consequential automated action may be represented as protected unless it is -reduced to an exact action contract, evaluated by policy, bound to a one-use -greenlight, checked by a gateway before consequence, and reconstructable as a -receipt, refusal, proof gap, or terminal certificate. - -The seven macro plans are closed only at the source-owned scope proven by the -current repo. They do not claim production hosted readiness, provider custody, -actual npm publication, MCP Registry discoverability, settlement, payment -management, certification, package safety, or host-wide containment. - -## Scope - -Closed macro folders: - -- `claim-boundary-cleanup` -- `customer-owned-gateway-custody-proof` -- `terminal-verifier-trust-plane` -- `hosted-admission-redacted-evidence-plane` -- `concrete-adapter-pack-expansion` -- `host-specific-bypass-harnesses` -- `public-distribution-publication` - -Still active and not closed by this audit: - -- `.planning/macro/active/x402-product-evaluation-20260524` - -## Commit Mapping - -| Macro plan | Closeout commit(s) | Evidence summary | -| --- | --- | --- | -| Claim boundary cleanup | `286ea47` | Canonical docs and package metadata now frame Handshake as protected action infrastructure for automated decision making; claim guards reject engineering-agent-only and x402/payment overclaims. | -| Customer-owned gateway custody proof | `0d6cbcf` | `GatewayCustodyProofPacket`, `CredentialResolutionEvidence`, transition/navigation/object registry coverage, and redaction tests landed. | -| Terminal verifier trust plane | `b4c5229`, `3752733` | Issuer/key/status models, verifier key-set projection, JWKS projection, structured verification response, CLI parity, and hosted verifier read routes landed. | -| Hosted admission and redacted evidence plane | `5a257df`, `9718905` | Hosted verifier/read routes, deployment-mode admission config, tenant/read-role split, raw-read posture, and readiness projection landed. | -| Concrete adapter pack expansion | `15c2eee` | Package-install material adapter pack, evidence report, lifecycle-script posture, proof gaps, gateway observed-parameter validation, and conformance coverage landed. | -| Host-specific bypass harnesses | `7760654` | Local package-manager host fixture, raw sibling posture, freshness, proof-packet/report, and host-specific non-claims landed. | -| Public distribution and publication | `b3635c5` | `PackageReleaseProof`, release states, authority non-claims, package metadata guard, and release proof readiness check landed. | - -## Requirements Audit - -| Requirement | Status | Source evidence | Residual proof gap | -| --- | --- | --- | --- | -| Correct category boundary | Passed | `README.md`, `AGENTS.md`, `docs/internal/decisions.md`, `test/architecture/claim-boundary.test.ts`, `package.json` | None for repo wording. | -| x402 exact per-call remains first wedge | Passed | `README.md`, `docs/internal/protocol-notes.md`, `test/conformance/x402-payment-conformance.test.ts`, `test/conformance/x402-upstream-exact-fixtures.test.ts` | Broad x402 surfaces remain future cuts. | -| No payment-management, settlement, marketplace, or custody overclaim | Passed | `test/architecture/claim-boundary.test.ts`, `scripts/check-release-proof.mjs`, `src/surfaces/release-proof.ts` | Actual external payment/provider operations not implemented or claimed. | -| Custody proof packet binds gateway custody evidence | Passed | `src/protocol/areas/credential-custody/`, `test/protocol/credential-custody.test.ts`, `test/protocol/evidence-projections.test.ts` | Provider-specific/customer deployment proof remains external. | -| Credential resolution is post-gate evidence | Passed | `recordCredentialResolutionEvidence`, `test/protocol/credential-custody.test.ts`, adapter gateway tests | None for source path. | -| Terminal certificate verification is structured evidence | Passed | `src/protocol/areas/authority-certificate/`, `test/protocol/authority-certificate.test.ts`, `src/cli/certificate.ts` | Cross-org trust publication and live revocation operations remain future work. | -| Hosted admission is deny-by-default and tenant-scoped | Passed | `src/http/admission/hosted-admission-config.ts`, `src/http/admission/hosted-caller-identity.ts`, `test/http/http.test.ts` | Production deployment posture remains unproven. | -| Hosted reads are redacted and read-entitled | Passed | `src/http/handlers/evidence-read.ts`, `src/http/handlers/internal-record-read.ts`, `test/http/http.test.ts` | Compliance-grade audit/export program remains future work. | -| Package-install adapter pack proves one exact install attempt | Passed | `src/adapters/package-install/adapter-pack.ts`, `test/adapters/package-install-adapter-pack.test.ts`, `test/integration/package-install-end-to-end.test.ts` | Real external package safety/provenance certification is not claimed. | -| Lifecycle scripts blocked or proof-gapped | Passed | `src/adapters/package-install/adapter-pack.ts`, `src/adapters/package-install/gateway.ts`, adapter-pack and gateway tests | Separately contracted lifecycle script action not implemented. | -| Host-specific bypass harness is narrow | Passed | `src/adapters/package-install/host-harness.ts`, `src/adapters/protected-path-probes/host-fixture.ts`, `test/adapters/package-install-host-harness.test.ts` | Additional hosts and ongoing freshness automation remain future work. | -| Public release states are separated | Passed | `src/surfaces/release-proof.ts`, `test/architecture/package-release-proof.test.ts`, `scripts/check-release-proof.mjs` | Actual npm publish, clean install from public artifact, MCP Registry acceptance, and discoverability are external proof gaps. | - -## Integration Audit - -The implemented chain is internally coherent: - -```text -claim boundary --> custody proof packet --> terminal verifier structure --> hosted read/admission posture --> package-install adapter pack --> host-specific bypass harness --> release-state proof -``` - -No slice creates an alternate authority path. Runtime ingress, MCP, CLI, -hosted verifier/readiness, release proof, and package-install reports remain -proposal/evidence/read/metadata surfaces. The gateway check remains the -pre-consequence enforcement point. - -## Gate Evidence - -Final closeout commands run after the seven implementation commits: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -Observed result: - -- `quality:claims`: 4 pass, 0 fail. -- `quality:architecture`: 63 pass, 0 fail. -- `format:check`: passed. -- `check:repo`: 495 pass, 0 fail; package surface check passed with 563 files; - release proof readiness check passed; `git diff --check` passed. - -## Verdict - -Passed for repo-owned source closeout. The seven macro plans should no longer -live under `.planning/macro/active/`. - -Do not collapse the residual proof gaps into success language. Publication, -production hosted operation, provider custody, cross-org trust, package safety, -and host-wide containment remain unclaimed until future source and external -evidence prove them. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/GSD-REMAP.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/GSD-REMAP.md deleted file mode 100644 index 8bba70c..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/GSD-REMAP.md +++ /dev/null @@ -1,91 +0,0 @@ -# GSD Remap: Tier 2 Macro Closeout - -Date: 2026-05-24 - -## Mapper Runtime - -`gsd-sdk query init.map-codebase` reported that mapper agents were not -installed in this checkout. This remap was performed inline and written to the -existing `.planning/codebase/` scratch documents. - -## Remapped Documents - -Updated scratch maps: - -- `.planning/codebase/STACK.md` -- `.planning/codebase/ARCHITECTURE.md` -- `.planning/codebase/INTEGRATIONS.md` -- `.planning/codebase/STRUCTURE.md` -- `.planning/codebase/CONVENTIONS.md` -- `.planning/codebase/TESTING.md` -- `.planning/codebase/CONCERNS.md` - -Key correction: older map entries that described runtime/MCP x402 posture -propagation as current bugs are now stale. Current source includes the posture -fields in both runtime ingress and MCP proposal schema. - -## Current Source Map Delta - -New or materially expanded source areas: - -- `src/protocol/areas/credential-custody/`: gateway custody proof packets and - post-gate credential resolution evidence. -- `src/protocol/areas/authority-certificate/`: structured terminal verifier - response, issuer/key/status posture, verifier key-set projection, and JWKS - projection. -- `src/http/admission/`: hosted deployment-mode admission and caller identity - posture. -- `src/http/handlers/verifier.ts`: non-mutating hosted verifier routes. -- `src/http/handlers/hosted-readiness.ts`: hosted readiness reporting without - secret values or mutation authority. -- `src/adapters/package-install/adapter-pack.ts`: package-install material - adapter-pack evidence/report projection. -- `src/adapters/package-install/host-harness.ts` and - `src/adapters/protected-path-probes/host-fixture.ts`: named local host bypass - harness and proof-packet posture. -- `src/surfaces/release-proof.ts`: publication release-state proof and - non-authority boundary. -- `scripts/check-release-proof.mjs`: publication claim/readiness guard. - -## Active Planning State After Closeout - -Implemented bundle: - -- `.planning/macro/implemented/2026-05-24-tier2-macro-closeout/` - -Remaining active macro folder: - -- `.planning/macro/active/x402-product-evaluation-20260524` - -The remaining active folder was not one of the seven macro plans implemented in -this closeout and must not be archived by association. - -## Practical Next Map Queries - -Use this remap to route future work: - -- Custody or secret-boundary work: start in - `src/protocol/areas/credential-custody/` and - `test/protocol/credential-custody.test.ts`. -- Terminal verification work: start in - `src/protocol/areas/authority-certificate/`, `src/http/handlers/verifier.ts`, - and `test/protocol/authority-certificate.test.ts`. -- Hosted admission/read work: start in `src/http/admission/`, - `src/http/handlers/evidence-read.ts`, `src/http/handlers/internal-record-read.ts`, - `src/http/handlers/hosted-readiness.ts`, and `test/http/http.test.ts`. -- Package-install adapter work: start in - `src/adapters/package-install/adapter-pack.ts`, - `src/adapters/package-install/gateway.ts`, and - `test/adapters/package-install-adapter-pack.test.ts`. -- Host bypass work: start in `src/adapters/protected-path-probes/`, - `src/adapters/package-install/host-harness.ts`, and - `test/adapters/package-install-host-harness.test.ts`. -- Publication readiness work: start in `src/surfaces/release-proof.ts`, - `scripts/check-release-proof.mjs`, and - `test/architecture/package-release-proof.test.ts`. - -## Remap Verdict - -The current codebase map now matches the source-closed seven-plan stack. It -still treats `.planning/` as scratch and names external proof gaps instead of -turning them into product claims. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/REVIEW.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/REVIEW.md deleted file mode 100644 index a6c4750..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/REVIEW.md +++ /dev/null @@ -1,134 +0,0 @@ -# Tier 2 Macro Closeout Review - -Date: 2026-05-24 - -## Review Posture - -This is a source-closeout review of the seven macro implementation commits, not -a release approval for external npm/MCP publication or production hosted -operation. - -Reviewed axes: - -- correctness against the seven macro plans; -- authority-boundary preservation; -- security and redaction posture; -- architecture/import posture; -- test and gate credibility; -- residual proof gaps. - -## Findings - -No blocking findings were found in the closeout state. - -## Important Residual Risks - -### External publication remains a proof gap - -`PackageReleaseProof` correctly separates `ready_to_publish`, -`actually_published`, and `registry_discoverable`, but the repo has not -performed npm publish, post-publish clean install from the public artifact, MCP -Registry submission, or registry discoverability verification. This is not a -source bug; it is an external release-operator boundary. - -Required discipline: do not say "published" or "registry discoverable" until -the proof state advances with external evidence. - -### Hosted readiness is not production hosted operation - -Hosted admission, read-role separation, raw-read posture, and readiness reports -exist. They prove source-level local foundation behavior and configured posture, -not production operation, remote D1/KV proof, live revocation authority, abuse -control, or cross-org trust. - -Required discipline: keep "hosted" wording bound to admission/readiness and -evidence projections unless deployment evidence exists. - -### Package-install material evidence is not package safety - -The package-install adapter pack records material evidence, lifecycle-script -posture, proof gaps, exact contract binding, and gateway observed-parameter -validation. It does not prove package code is benign, replace npm audit, or -verify Bun provenance. - -Required discipline: preserve the report non-claims in future adapter pack -work. - -### Host-specific harness is not host-wide containment - -The host bypass harness proves one named local package-manager environment and -named raw sibling candidates at a freshness state. It does not prove generic -browser, shell, network, MCP, package-manager ecosystem, or runtime sandbox -containment. - -Required discipline: every new host claim needs its own manifest, probe list, -freshness, raw sibling posture, and proof-packet evidence. - -## Architecture Review - -The implementation preserves the core boundary: - -- Protocol primitives stay under `src/protocol/`. -- Runtime ingress remains observer/compiler/proposal posture. -- MCP remains proposal/evidence/read-only. -- CLI remains evidence/local readiness/readback. -- Hosted verifier/readiness routes are non-mutating. -- Release proof records publication evidence states, not authority. -- Adapter reports are reconstruction/evidence projections, not enforcement. - -The main architectural watch item is runtime ingress size. It is still the -largest cross-family conversion module. Current tests and the runtime registry -keep it proposal-only, so this is not a closeout blocker. The next family beyond -package install should trigger a narrow extraction before the module becomes a -god registry. - -## Security Review - -Redaction and custody posture improved: - -- Custody proof packets reject raw credential-looking material. -- Credential resolution evidence is post-gate. -- Evidence projections redact signer/payment/auth material. -- Hosted reads hide cross-tenant existence and gate raw records by posture. -- Verifier/JWKS projection exposes public key material only. - -Residual security boundaries are explicit: - -- no provider/customer custody proof from local fixtures; -- no live secret manager/vault provider integration; -- no production hosted trust or revocation distribution; -- no package safety guarantee; -- no host-wide bypass containment. - -## Test Review - -The final gate is credible because it includes: - -- full TypeScript checking; -- ESLint; -- Prettier; -- all Bun tests; -- package build and surface checks; -- published-entrypoint smoke checks; -- release proof readiness checks; -- whitespace diff check. - -Focused tests cover the new slices: - -- custody: `test/protocol/credential-custody.test.ts`; -- verifier: `test/protocol/authority-certificate.test.ts`, `test/http/http.test.ts`; -- hosted: `test/http/http.test.ts`, `test/sdk/role-clients.test.ts`; -- adapter pack: `test/adapters/package-install-adapter-pack.test.ts`; -- bypass harness: `test/adapters/package-install-host-harness.test.ts`; -- publication states: `test/architecture/package-release-proof.test.ts`; -- claims: `test/architecture/claim-boundary.test.ts`. - -## Review Verdict - -Keep. The seven-plan source stack is coherent, guarded, and narrow enough. - -Do not broaden it in closeout language. The next useful review is a -buyer-facing proof-path read: one concrete protected action from proposal to -contract, policy, one-use greenlight, gateway check, custody proof, receipt or -proof gap, terminal certificate, hosted redacted read, bypass posture, and -release metadata. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/VALIDATION.md deleted file mode 100644 index ceaeae4..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/VALIDATION.md +++ /dev/null @@ -1,63 +0,0 @@ -# Closeout Validation - -Date: 2026-05-24 - -## Commands - -Final gate commands from the implementation closeout: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -Planning closeout/remap must rerun at least: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -## Source-Closeout Results - -- `npm run quality:claims`: passed. -- `npm run quality:architecture`: passed. -- `npm run format:check`: passed. -- `npm run check:repo`: passed with 495 tests, 0 failures, package surface check - with 563 files, and release proof readiness check. - -## Planning-Closeout Rerun Results - -- `npm run format:check`: passed after the GSD remap/audit/review artifacts. -- `npm run quality:claims`: passed with 4 tests, 0 failures. -- `npm run quality:architecture`: passed with 63 tests, 0 failures. -- `npm run check:repo`: passed with 495 tests, 0 failures, package surface - check with 563 files, and release proof readiness check. -- `git diff --staged --check`: passed after force-adding ignored closeout - artifacts. - -## Closeout-Specific Checks - -- The seven implemented macro folders have moved under this implemented bundle. -- `.planning/macro/active/x402-product-evaluation-20260524` remains active. -- `.planning/codebase/CONCERNS.md` no longer lists closed runtime/MCP x402 - posture propagation issues as active bugs. -- The audit and review documents distinguish source-closed implementation from - external proof gaps. - -## Non-Claims Preserved - -- No actual npm publication claimed. -- No MCP Registry discoverability claimed. -- No production hosted operation claimed. -- No provider/customer custody claimed from local fixture evidence. -- No cross-org AuthorityCertificate trust claimed. -- No settlement, payment management, seller middleware, facilitator operation, - marketplace, or certification claimed. -- No package safety, npm audit replacement, Bun provenance verification, or - broad supply-chain security claimed. -- No host-wide containment or generic runtime/MCP/CLI enforcement claimed. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/ASSUMPTIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/ASSUMPTIONS.md deleted file mode 100644 index c970c4f..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/ASSUMPTIONS.md +++ /dev/null @@ -1,14 +0,0 @@ -# Assumptions - -| ID | Assumption | Confidence | Evidence | Invalidation Trigger | -| --- | --- | --- | --- | --- | -| A1 | The user correction is authoritative: Handshake is protected actions for automated decision making. | High | Immutable input packet and all raw perspectives converge. | User chooses a different category phrase before implementation. | -| A2 | Tier 1 protocol/kernel meaning is stable and must not change in this cleanup. | High | Input constraints and protocol definition already support protected action control. | A strengthened claim guard cannot pass without a protocol behavior change. That should stop the slice. | -| A3 | x402 exact per-call protected action is the current first wedge. | High | README, x402 walkthrough, product report test, and perspectives all point to the official buyer-side `x402_payment.exact` path. | Source evidence proves the x402 path is not the narrowest executable wedge. | -| A4 | Aggregate payment-budget management is intentionally outside current remit. | High | Input explicitly requires replacing spend-ledger-required wording with out-of-remit posture. | User asks to plan spend-budget management as a separate capability. | -| A5 | Engineering-agent workflows remain useful adoption context and threat model. | High | Current canon and examples are built around generated execution and engineering-agent mutation surfaces. | Implementation removes all engineering-agent references and loses first-use clarity. | -| A6 | `not_enforced_local_metadata` may remain only as local metadata. | Medium | Raw perspectives agree; current source uses local spend-window status language. | Search finds the marker used as a product-scope enforcement promise. | -| A7 | Current x402 proof is local/reference evidence, not live custody or hosted operation. | High | README, protocol definition, x402 walkthrough, and report tests state local/reference boundaries. | Future implementation adds real customer/provider gateway custody and verifies it. | -| A8 | Claim guards should use named high-authority surfaces, not unbounded regex sprawl. | High | Maintainability requirement and existing `claim-boundary.test.ts` structure. | Guard coverage cannot express the boundary without a broader source-owned vocabulary mechanism. | -| A9 | External verification is out of scope for this cleanup. | High | Input says do not browse by default and mark external claims out of scope. | A future implementation adds positive external x402, legal, registry, JWKS, npm, or Cloudflare claims. | -| A10 | `.planning/codebase/CONCERNS.md` is scratch risk evidence, not canon. | High | README and decisions canon say `.planning/` is scratch. | User explicitly promotes a planning artifact into repo canon. | diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/CONTEXT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/CONTEXT.md deleted file mode 100644 index a250009..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/CONTEXT.md +++ /dev/null @@ -1,89 +0,0 @@ -# Context - -## Target - -Plan critical-path item 0 from `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md`: Claim Boundary Cleanup. - -The cleanup must make eliminated items intentional product boundaries before new capability work. The user correction is controlling: Handshake is protected actions for automated decision making, not just engineering agents. x402 is the first wedge. - -## Source Packet - -Immutable packet: - -- `.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/input.md` - -Raw perspectives: - -- `raw/STRATEGY.md` -- `raw/ARCH.md` -- `raw/EXECUTION.md` -- `raw/RISK.md` -- `raw/ADOPTION.md` - -Contract: - -- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/plan-contract.md` - -Allowed source checks used during synthesis: - -- `AGENTS.md` -- `README.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` -- `test/architecture/claim-boundary.test.ts` -- `test/product/x402-protected-spend-demo-report.test.ts` -- `examples/x402-protected-spend/README.md` -- `examples/x402-protected-spend/run.ts` -- `examples/self-hosted-activation/README.md` -- `src/*/LANE.md` files named by the input packet -- `.planning/codebase/CONCERNS.md` as scratch risk evidence only - -No archive macro runs or external sources were read. - -## Current State - -Canonical docs and current README still contain category-level engineering-agent language. The protocol definition is safer: it already describes Handshake as a protocol kernel for protected action control and names the gateway as the pre-consequence enforcement point. - -x402 is already source-backed as the first narrow proof wedge. It is one buyer-side `x402_payment.exact` per-call path with local/reference sandbox evidence, gateway-held signer use after `VerifiedGatewayCheck`, replay refusal, and redacted report output. The repo also contains explicit non-claims for broad x402 compatibility, provider custody, hosted operation, facilitator/seller operation, settlement, marketplace/certification, and broad MCP/runtime control. - -The main contradiction is claim residue around aggregate spend. `README.md` still says session/day/review spend windows are metadata until a ledger exists, and the current product report test still expects `spend reservation ledger` in `missingProofObjects`. For this cleanup, that should become an explicit non-remit: aggregate payment-budget management is intentionally outside current scope. - -`test/architecture/claim-boundary.test.ts` already guards several claim surfaces, but it does not yet force the corrected category or prevent engineering-agent-only product definition. It should be strengthened, not replaced with a broad unstructured grep. - -## Relevant Canon - -Repo truth lives in: - -- `AGENTS.md` -- `README.md` -- `QUALITY.md` -- `STRUCTURE.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-layman.md` -- `docs/internal/protocol-notes.md` - -Operational behavior is guarded by: - -- `package.json` -- `.github/workflows/check.yml` -- `test/architecture/*` -- `src/*/LANE.md` - -`.planning/` is scratch. It can record this run and identify drift, but it must not become source, script, CI, package, or public API truth. - -## Synthesis Position - -The plan is a test-led claim cleanup: - -1. Inventory and phrase table. -2. Strengthen claim guards. -3. Rewrite canonical category language. -4. Clean x402 report/walkthrough wording. -5. Align lane manifests if needed. -6. Clean active scratch drift. -7. Run focused and full validation gates. - -No capability work is planned in this slice. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/DECISIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/DECISIONS.md deleted file mode 100644 index 09177d7..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/DECISIONS.md +++ /dev/null @@ -1,45 +0,0 @@ -# Decisions - -## Accepted - -- Use "protected actions for automated decision making" as the category phrase for this cleanup. -- Keep Tier 1 protocol meaning stable. The cleanup changes claims, examples, report wording, and tests, not protocol authority behavior. -- Treat engineering-agent workflows as adoption context and generated-execution stress case, not category boundary. -- Treat x402 as the first official buyer-side exact per-call protected-action wedge. -- Keep `x402_payment.exact` as the protected action class. Treat `x402_paid_http_call.exact` as buyer-readable report language only. -- Replace product-scope "spend reservation ledger required before claim" language with "aggregate payment-budget management intentionally out of current remit." -- Preserve customer-owned gateway custody as the future enforcement model while denying current provider/customer custody claims from local fixtures. -- Strengthen source-owned claim guards before or alongside prose changes. -- Use a small, named claim-surface list and grouped assertions. Avoid god files, regex sprawl, pass-through abstractions, and broad unstructured repo scans. - -## Rejected - -- Engineering agents as the product category. -- x402 as the protocol definition. -- Payment management, balances, aggregate spend windows, reservations, settlement, seller middleware, facilitator operation, or Handshake-held payment custody in this slice. -- Hosted operation, hosted trust, hosted verifier, live JWKS/revocation, marketplace/certification, clearing-house readiness, or cross-org certificate trust in this slice. -- Broad runtime, MCP, CLI, browser, shell, network, package-manager, cloud, repo, or database control claims. -- Treating runtime/MCP/CLI/SDK/review/report/certificate surfaces as authority surfaces. -- Implementing capability to make stale claims true. -- Promoting `.planning/` scratch into repo-facing source truth. - -## Deferred - -- Customer-owned gateway custody proof packets. -- Terminal verifier trust plane, JWKS/revocation, and portable verification. -- Hosted admission and redacted evidence plane. -- Additional protected-action packs beyond x402 exact per-call. -- Host-specific bypass harnesses for browser, shell, package manager, cloud, repo, database, or broad MCP/runtime surfaces. -- Public npm/MCP Registry publication proof and external package provenance claims. -- External x402 compatibility, legal, payment-regulatory, Cloudflare, or standards claims. -- Whether `test/architecture/active-vocabulary.test.ts` should join the cleanup. It was not in the chair's allowed source read, so implementation should verify it during inventory if needed. - -## User-Owned Decisions - -No P1 user-owned decision blocks execution of this cleanup plan. - -Potential future user decisions before capability expansion: - -- Which second protected-action pack follows x402 after claim cleanup. -- Whether the long-run clearing-house thesis should be captured in strategy docs outside this current repo. -- Whether active `.planning/codebase/CONCERNS.md` should be cleaned in the same implementation slice or left as stale scratch evidence with the active macro plan overriding it. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/PLAN.md deleted file mode 100644 index 27b3f03..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/PLAN.md +++ /dev/null @@ -1,354 +0,0 @@ -# Plan - -## Goal - -Create an executable implementation plan for claim-boundary cleanup before new capability work. - -The future implementation must make the eliminated items intentional product boundaries, not pending promises. It must correct the category boundary to protected actions for automated decision making, preserve Tier 1 protocol meaning, and keep x402 as the first official buyer-side exact per-call protected-action wedge. - -The invariant at stake: public repo language must not create authority that the gateway does not enforce. - -## Non-Goals - -- No Tier 1 protocol or schema redesign. -- No new authority, policy, gateway, greenlight, receipt, storage, or x402 signing behavior. -- No aggregate payment-budget management, spend reservation ledger, balances, settlement, seller middleware, facilitator operation, or payment-management product. -- No Handshake-held wallet, signer, provider, or customer custody claim. -- No hosted operation, hosted trust, hosted verifier, live JWKS/revocation, marketplace, certification, clearing-house readiness, or cross-org certificate trust claim. -- No broad runtime, MCP, CLI, browser, shell, network, package-manager, cloud, repo, or database control claim. -- No broad x402 compatibility claim. The current wedge is one official buyer-side `x402_payment.exact` per-call path. -- No public package, MCP Registry, Cloudflare, legal, or payment-regulatory claim unless a later slice explicitly performs external verification. - -## Source Boundary - -Used inputs: - -- `.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/input.md` -- Raw perspective outputs under `.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/` -- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/plan-contract.md` -- The allowed source files named in the input packet where needed to resolve conflicts. - -Not used: - -- No archived macro runs. -- No external browsing. -- No source files outside the allowed packet. - -Source priority for implementation: - -1. User correction in the immutable input packet. -2. Current canonical docs and tests. -3. Current `.planning` active run evidence. -4. Derived `.planning/codebase/*` maps as scratch risk context only. - -## Current State - -The protocol spine is already broader than the stale product language. `docs/internal/protocol-definition.md` defines protected action control: exact action contract, policy decision, one-use greenlight, gateway check before mutation, and receipt/refusal/proof-gap evidence. - -The category language is stale in high-authority docs. `AGENTS.md`, `README.md`, and `docs/internal/decisions.md` still define Handshake around engineering agents in places. That makes an adoption context look like the product boundary. - -x402 is the strongest current wedge but has claim residue. The repo already presents one official buyer-side exact per-call x402 path with gateway-held signing after `VerifiedGatewayCheck`, replay refusal, local/reference evidence, and non-claims. But `README.md`, `.planning/codebase/CONCERNS.md`, and `test/product/x402-protected-spend-demo-report.test.ts` still preserve "spend reservation ledger" / "metadata until a ledger exists" posture that can read as pending aggregate payment-budget management. - -Current guards exist but are not strict enough for the corrected category. `test/architecture/claim-boundary.test.ts` already checks runtime/MCP/conformance/x402 non-authority language and public entrypoint separation. `test/product/x402-protected-spend-demo-report.test.ts` already checks the local APS report boundary, redaction, role clients, replay refusal, and non-claims. These gates must be strengthened; they were not run during this planning-only synthesis. - -`.planning/` contains useful drift evidence but is not repo truth. `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` already says per-call x402 exact authorization is immediate posture and aggregate payment-budget management is not the product. `.planning/codebase/CONCERNS.md` still includes a derived spend-ledger fix path; implementation must treat that as stale risk evidence unless intentionally updated as scratch. - -## Target State - -Canonical repo truth reads as: - -```text -Handshake protects consequential actions from automated decision systems by reducing each protected action attempt to an exact, policy-evaluated, gateway-bound action contract before consequence. -``` - -The hierarchy is explicit: - -```text -category: protected actions for automated decision making -primitive: exact contract -> policy -> one-use greenlight -> gateway check -> receipt/refusal/proof gap -first wedge: one buyer-side x402_payment.exact per-call protected action -current adoption context: automated engineering/runtime workflows and generated execution -local proof boundary: local/reference only unless a customer-owned gateway owns the credential and checks the exact greenlight -``` - -Engineering-agent workflows remain useful as a generated-execution stress case and adoption context. They do not define the category. - -x402 remains one protected-action pack. It proves the spine; it does not define the protocol, broad payment management, settlement, seller/facilitator operation, provider/customer custody, marketplace/certification, or broad x402 compatibility. - -Aggregate payment-budget management is explicitly out of current remit. `not_enforced_local_metadata` may remain only when attached to local metadata and surrounded by wording that denies enforcement and budget-management claims. - -Claim guards fail if canon, examples, generated reports, or lane manifests imply broader authority than the source enforces. - -## Assumptions - -- The user correction is authoritative: Handshake is protected actions for automated decision making, not just engineering agents. -- Tier 1 protocol/kernel meaning is stable and must not be changed by this cleanup. -- x402 exact per-call protected action remains the first wedge unless future source evidence proves a narrower sequence is required. -- Existing current x402 proof is local/reference evidence, not live provider/customer custody or hosted operation. -- `.planning/` is scratch; active planning outputs may guide work but must not become repo-facing source paths, scripts, package names, or canonical docs. -- External standards, package publication, registry, legal, payment-regulatory, Cloudflare, JWKS, and live x402 compatibility claims are out of scope for this slice. - -## Decisions - -- Adopt "protected actions for automated decision making" as the category phrase for this cleanup. -- Keep engineering-agent language only where it is adoption context, generated-execution threat model, or a current local proof context. -- Treat x402 as the first official buyer-side exact per-call protected-action wedge. -- Keep `x402_payment.exact` as the protected action class. Keep `x402_paid_http_call.exact` as buyer-readable report language only unless a future source change adds a matching action catalog, compiler, policy, and gateway class. -- Replace product-scope "spend reservation ledger required before claim" language with "aggregate payment-budget management intentionally out of current remit." -- Keep customer-owned gateway custody as the future enforcement model, while stating that local x402 proof does not prove provider/customer custody today. -- Use source-owned claim guards over a small named surface set. Avoid broad random regex scans, god tests, pass-through abstractions, and spaghetti conditional exceptions. - -## Phases - -### Phase 0 - Claim Inventory And Phrase Table - -Build a small implementation inventory before edits. - -Classify each relevant phrase in `AGENTS.md`, `README.md`, `docs/internal/*`, x402 examples, the APS report generator, lane manifests, and active planning scratch as one of: - -- category claim; -- first wedge claim; -- current adoption context; -- local/reference evidence only; -- explicit non-claim or cut line; -- stale scratch evidence. - -Closeout evidence: an implementation note or PR description table. Do not add a new repo-facing canon file for the inventory. - -### Phase 1 - Test-First Claim Guards - -Strengthen guards before rewriting docs. - -Update `test/architecture/claim-boundary.test.ts` with a named surface map and grouped assertions: - -- category boundary assertions for canonical docs; -- x402 wedge assertions; -- payment-management non-claim assertions; -- runtime/MCP/CLI/SDK/lane non-authority assertions; -- custody, hosted, marketplace/certification, clearing-house, and cross-org trust non-claims. - -Update `test/product/x402-protected-spend-demo-report.test.ts` so the APS report no longer requires `spend reservation ledger` as a missing proof object. It should require aggregate payment-budget management to be absent from current authority or explicitly listed as out of current remit. - -Maintainability rule: use named surfaces and grouped helpers inside the test, or split into focused architecture tests if the file becomes a god file. Do not add repo-wide grep sprawl with opaque exceptions. - -Closeout evidence: focused tests initially fail on stale wording, then pass after phases 2-4. - -### Phase 2 - Canonical Category Rewrite - -Patch canonical docs after guards define the failure. - -Candidate paths: - -- `AGENTS.md` -- `README.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-layman.md` -- `docs/internal/protocol-notes.md` - -Required changes: - -- top-level category becomes protected actions for automated decision making; -- engineering-agent language moves to adoption context or generated-execution threat model; -- first wedge language becomes x402 exact per-call protected action; -- Tier 1 protocol object meanings remain unchanged; -- "No adapter family defines the protocol" remains visible; -- receipts, terminal certificates, and reports do not become permission, identity, settlement, certification, hosted trust, or downstream business success. - -Closeout evidence: category guard passes without protocol behavior changes. - -### Phase 3 - x402 Report And Walkthrough Cleanup - -Patch the first wedge without broadening it. - -Candidate paths: - -- `examples/x402-protected-spend/README.md` -- `examples/x402-protected-spend/run.ts` -- `examples/self-hosted-activation/README.md` -- `test/product/x402-protected-spend-demo-report.test.ts` - -Required changes: - -- scope the walkthrough to one buyer-side `x402_payment.exact` per-call protected action; -- label `x402_paid_http_call.exact` as buyer-readable report language only; -- replace product-scope spend-ledger wording with aggregate payment-budget management out of current remit; -- keep `not_enforced_local_metadata` only as local metadata; -- preserve signer invocation only after `VerifiedGatewayCheck`; -- preserve replay refusal before signer reuse; -- preserve local/reference downstream fixture wording; -- add or preserve support/debug payload redaction boundaries for payment-sensitive material. - -Closeout evidence: `npm run demo:aps` regenerates report output and the product report test passes. - -### Phase 4 - Lane And Surface Boundary Alignment - -Patch only lane wording that reintroduces stale category or authority drift. - -Candidate paths: - -- `src/runtime/LANE.md` -- `src/mcp/LANE.md` -- `src/cli/LANE.md` -- `src/sdk/LANE.md` -- `src/adapters/LANE.md` -- `src/conformance/LANE.md` - -Required posture: - -- runtime proposes and records evidence only; -- MCP proposes and displays evidence only; -- CLI reads/renders local evidence only; -- SDK role clients stay role-scoped for walkthroughs; -- adapters are protected-action packs and mutate only after verified gateway checks; -- conformance is reference posture, not certification or standards compliance. - -Closeout evidence: import posture, root exports, and claim-boundary tests stay green. - -### Phase 5 - Active Scratch Register Cleanup - -Patch active planning scratch only where it would mislead future agents. - -Candidate paths: - -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` -- `.planning/codebase/CONCERNS.md` only if the executor decides tracked scratch drift must be corrected in the same slice. - -Required posture: - -- category uses protected actions for automated decision making; -- x402 exact per-call remains the first wedge; -- aggregate payment-budget management is intentionally out of current remit; -- old spend-ledger fix advice is stale derived evidence unless rewritten. - -Closeout evidence: active scratch no longer contradicts canonical docs. Do not reference `.planning` from repo-facing source, package scripts, CI, README sections, or exported symbols. - -### Phase 6 - Validation And Closeout - -Run focused gates first, then full repo gate last. - -Required closeout ordering: - -1. `npm run quality:claims` -2. `npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts` -3. `npm run demo:aps` if `examples/x402-protected-spend/run.ts` changed -4. `npm run test -- test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts` if lane/package surfaces changed -5. `npm run quality:architecture` -6. `npm run format:check` -7. `npm run check:repo` - -Closeout evidence: command output plus a diff summary proving no protocol behavior changed. - -## Task Graph - -```text -macro-001 claim inventory - -> macro-002 architecture claim guards - -> macro-003 x402 report claim guards - -macro-002 architecture claim guards - -> macro-004 canonical category rewrite - -> macro-006 lane boundary alignment - -macro-003 x402 report claim guards - -> macro-005 x402 report and walkthrough cleanup - -macro-004 canonical category rewrite - -> macro-007 active scratch cleanup - -> macro-008 focused claim validation - -macro-005 x402 report and walkthrough cleanup - -> macro-008 focused claim validation - -> macro-009 APS demo validation - -macro-006 lane boundary alignment - -> macro-010 architecture posture validation - -macro-007 active scratch cleanup - -> macro-008 focused claim validation - -macro-008 focused claim validation -macro-009 APS demo validation -macro-010 architecture posture validation - -> macro-011 full repo closeout -``` - -Critical path: - -```text -inventory -> guard old failures -> canon rewrite -> x402 report cleanup -> active scratch cleanup -> focused gates -> check:repo -``` - -Parallelizable after inventory: - -- architecture claim guards and x402 report claim guards; -- canonical docs and lane manifest wording once phrase table is stable; -- x402 report cleanup independently of lane wording; -- active scratch cleanup after canonical phrasing is settled. - -## Risks And Mitigations - -- P0: Category boundary remains engineering-agent-only. Mitigation: positive category guard plus bounded-context allowance for engineering-agent examples. -- P0: x402 becomes payment management. Mitigation: explicit non-remit language and product report guard that rejects spend-ledger-as-promise wording. -- P0: Docs create authority without gateway enforcement. Mitigation: every protected claim must bind to exact contract, one-use greenlight, customer-owned gateway check before consequence, and receipt/refusal/proof-gap evidence. -- P0: Claim guards are too narrow or brittle. Mitigation: named source surfaces, grouped high-risk boundaries, required positive language plus forbidden overclaims; avoid whole-repo regex sprawl. -- P1: x402 becomes protocol definition. Mitigation: keep adapter/action-pack discipline and "No adapter family defines the protocol." -- P1: Customer-owned gateway custody gets erased while removing custody overclaims. Mitigation: use three states: local/reference fixture now, customer-owned gateway custody future enforcement model, Handshake-held custody out of remit. -- P1: Local sandbox evidence reads as seller/facilitator/settlement operation. Mitigation: report and tests keep local downstream fixture evidence separate from authority and downstream success. -- P1: Runtime/MCP/CLI surfaces launder authority. Mitigation: lane wording and import/export tests keep them proposal/evidence/read-only. -- P2: `.planning` scratch becomes canon again. Mitigation: support docs and plan state that scratch is coordination evidence only. -- P2: `x402_paid_http_call.exact` reads as an action catalog class. Mitigation: report test labels it buyer-readable only. - -## Validation Gates - -Existing source-present guards, not re-run during synthesis: - -- `test/architecture/claim-boundary.test.ts` currently checks public entrypoint separation and several runtime/MCP/x402 non-claims. -- `test/product/x402-protected-spend-demo-report.test.ts` currently executes the demo report and checks local/reference x402 authority boundaries, role clients, replay refusal, and redaction. - -Planned strengthened gates: - -- Category gate: canonical docs must state protected actions for automated decision making and must not define Handshake as engineering-agent-only. -- Adoption-context gate: engineering-agent references must be explicitly adoption context, generated-execution stress case, or current local proof context. -- x402 wedge gate: x402 is one official buyer-side exact per-call protected-action pack, not the protocol definition or broad x402 compatibility. -- Payment non-remit gate: aggregate payment-budget management is intentionally outside current remit; no spend ledger is required to make current per-call x402 claim honest. -- Local metadata gate: `not_enforced_local_metadata` appears only as local metadata and never as disabled enforcement. -- Surface authority gate: runtime, MCP, CLI, SDK, review, reports, and terminal certificates cannot create policy, greenlights, gateway checks, mutation authority, receipt export, signer authority, or certification trust. -- Redaction gate: docs and report do not ask users to share `PaymentPayload`, `PAYMENT-SIGNATURE`, private keys, signer refs, raw store records, role-token maps, gateway credentials, or raw payment material. -- Full closeout gate: `npm run check:repo` after focused gates. - -Performance and scale posture: - -- This slice should not affect runtime performance because it is docs, examples, and tests only. -- Claim guard scans should use a fixed, named set of high-authority files, not unbounded repo traversal. -- Demo regeneration is acceptable as a product proof gate; it must remain deterministic and local. - -## Cut Lines - -Stop or split into a separate capability plan if implementation requires: - -- protocol schema or state-machine changes; -- gateway, policy, greenlight, storage, receipt, x402 signing, or terminal certificate behavior changes; -- aggregate spend enforcement, spend windows, balance tracking, settlement, seller/facilitator roles, or payment management; -- new hosted routes, verifier operation, JWKS/revocation, org auth, retention, or audit search; -- package publication, registry publication, Cloudflare deployment, legal/payment/regulatory claims, or external x402 compatibility claims; -- new public exports, package scripts, source directories, MCP tools, CLI mutation commands, or SDK authority clients; -- broad runtime/MCP/browser/shell/network/package-manager protection claims without host-specific bypass harnesses. - -## Rollback / Stop Conditions - -Rollback should be mechanical: revert the docs, example, report, and test guard changes from the implementation slice. No migrations, package export changes, source behavior changes, or generated distribution dependency should be necessary. - -Stop immediately if: - -- a claim can be made true only by changing Tier 1 protocol meaning; -- a test failure suggests implementing a spend ledger instead of narrowing the claim; -- a local/reference fixture is being described as live provider/customer custody; -- a report or terminal certificate is treated as permission, identity, settlement, certification, or hosted trust; -- any positive external claim is added without explicit verification; -- broad runtime/MCP/CLI/browser/shell/network/package-manager control language appears outside an explicit non-claim. - -## Smallest Next Action - -Add the failing claim-boundary guard first: update `test/architecture/claim-boundary.test.ts` so canonical docs fail when they define Handshake as engineering-agent-only and fail when aggregate payment-budget management is treated as a pending spend-ledger promise instead of intentionally out of current remit. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/RISKS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/RISKS.md deleted file mode 100644 index 957b3aa..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/RISKS.md +++ /dev/null @@ -1,103 +0,0 @@ -# Risks - -## P0 - -### R1 - Category Boundary Remains Wrong - -Risk: Canon still defines Handshake as engineering-agent infrastructure. Future plans then treat one adoption context as the whole category. - -Mitigation: Add a positive category guard and rewrite canon to protected actions for automated decision making. Allow engineering-agent language only as adoption context, generated-execution stress case, or local proof context. - -Validation: `test/architecture/claim-boundary.test.ts` fails on engineering-agent-only product definitions. - -### R2 - x402 Becomes Payment Management - -Risk: Spend-ledger wording implies aggregate budget management is pending rather than out of remit. - -Mitigation: Replace product-scope ledger-required phrasing with aggregate payment-budget management intentionally out of current remit. Keep x402 per-call exact only. - -Validation: Product report test rejects `spend reservation ledger` as a current missing proof promise and requires explicit non-remit posture where aggregate spend is discussed. - -### R3 - Docs Create Authority Without Gateway Enforcement - -Risk: Broadened "protected" language claims control where no gateway owns the mutation credential and checks the exact greenlight. - -Mitigation: Bind every protected claim to exact contract, one-use greenlight, gateway check before consequence, and receipt/refusal/proof-gap evidence. - -Validation: Claim guards scan named canon and lane manifests for hosted, custody, broad runtime, and certification overclaims. - -### R4 - Guard Coverage Is Cosmetic - -Risk: Tests pin a few phrases but miss high-risk claim surfaces, or become brittle exact-copy tests that discourage accurate wording. - -Mitigation: Use a named surface map with grouped semantic assertions and forbidden overclaim patterns. Keep exact strings only for contract terms such as `x402_payment.exact`, `not_enforced_local_metadata`, `VerifiedGatewayCheck`, and "proposal/evidence only". - -Validation: Focused tests fail on known stale category and spend-ledger language before cleanup. - -## P1 - -### R5 - x402 Defines The Protocol - -Risk: Correcting engineering-agent drift overcorrects into payment-protocol positioning. - -Mitigation: Keep the hierarchy visible: category, primitive, first wedge, adoption context, local proof boundary. Preserve "No adapter family defines the protocol." - -Validation: Claim guard requires first-wedge wording and rejects broad x402 compatibility. - -### R6 - Customer-Owned Gateway Custody Gets Cut Too Far - -Risk: Removing custody overclaims also removes the future enforcement model. - -Mitigation: Use three states: local/reference fixture now, customer-owned gateway custody future enforcement model, Handshake-held custody out of remit. - -Validation: Docs keep current non-claim and future boundary in separate language. - -### R7 - Local Sandbox Evidence Reads As Seller/Facilitator/Settlement - -Risk: Local 402 challenge and signed retry evidence get mistaken for seller middleware, facilitator operation, or settlement finality. - -Mitigation: Keep local/reference downstream fixture labels and post-gateway observation wording. Maintain report booleans for settlement/facilitator/seller/provider custody false. - -Validation: `test/product/x402-protected-spend-demo-report.test.ts` continues asserting local sandbox non-claims. - -### R8 - Runtime/MCP/CLI Surfaces Launder Authority - -Risk: Automated-decision language makes proposal/evidence/read surfaces sound like control planes. - -Mitigation: Lane manifests must say these surfaces do not evaluate policy, issue greenlights, perform gateway checks, mutate, export receipts, invoke signers, or mint certificates. - -Validation: Claim-boundary, import-posture, and root-export tests stay green. - -### R9 - Redaction And Support Language Overclaims Privacy Or Audit Readiness - -Risk: Support/debug docs imply hosted audit, privacy, compliance, retention, or provider secret lifecycle proof. - -Mitigation: Add support payload allowlist and forbidden payment/credential field list if first-use docs are touched. - -Validation: Claim guards reject raw credential/payment material in public walkthroughs and report output. - -## P2 - -### R10 - `.planning` Scratch Becomes Canon Again - -Risk: Future agents load stale derived maps and override cleaned canon. - -Mitigation: This plan and support files classify `.planning` as scratch; future implementation may clean active scratch but must not reference it from repo-facing surfaces. - -Validation: No README, source, tests, scripts, exports, or CI names refer to `.planning` as product truth. - -### R11 - Buyer-Readable Report Label Becomes Action Class - -Risk: `x402_paid_http_call.exact` is mistaken for gateway-bound authority. - -Mitigation: Keep it explicitly buyer-readable and non-authority. The protected action remains `x402_payment.exact`. - -Validation: Product report or claim-boundary test asserts the distinction. - -### R12 - Rollback Is Not Mechanical - -Risk: A claim cleanup touches behavior, exports, or migrations and becomes hard to reverse. - -Mitigation: Limit diff to docs, examples, report strings, claim tests, and active scratch. Stop if behavior must change. - -Validation: Closeout diff contains no protocol/gateway/storage/export behavior change unless separately justified by a new plan. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/TASKS.jsonl b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/TASKS.jsonl deleted file mode 100644 index be7826d..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/TASKS.jsonl +++ /dev/null @@ -1,11 +0,0 @@ -{"id":"macro-001","priority":"P1","phase":"Phase 0","title":"Build claim inventory and phrase table","owner":"implementation lead","rationale":"The cleanup needs exact classification before edits so category, wedge, adoption context, local evidence, and non-claim language do not get blurred.","depends_on":[],"acceptance":["Each relevant claim surface is classified as category, first wedge, adoption context, local/reference evidence, explicit non-claim, or stale scratch evidence.","Inventory names every product-definition use of engineering-agent language and every spend-ledger or aggregate-spend phrase.","Inventory is recorded in the PR description or implementation note, not promoted as new repo canon."],"candidate_paths":["AGENTS.md","README.md","docs/internal/decisions.md","docs/internal/protocol-definition.md","docs/internal/protocol-kernel-architecture.md","docs/internal/protocol-layman.md","docs/internal/protocol-notes.md","examples/x402-protected-spend/README.md","examples/x402-protected-spend/run.ts","examples/self-hosted-activation/README.md","src/runtime/LANE.md","src/mcp/LANE.md","src/cli/LANE.md","src/sdk/LANE.md","src/adapters/LANE.md","src/conformance/LANE.md",".planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md",".planning/codebase/CONCERNS.md"],"non_goals":["No source behavior changes.","No new canonical inventory file.","No archive macro-run reads."]} -{"id":"macro-002","priority":"P1","phase":"Phase 1","title":"Strengthen architecture claim-boundary guards","owner":"test owner","rationale":"Source-owned tests must fail stale category and overclaim language before docs are rewritten.","depends_on":["macro-001"],"acceptance":["Claim guard requires protected actions for automated decision making in canonical product definitions.","Claim guard rejects engineering-agent-only category definitions while allowing engineering-agent adoption-context references.","Claim guard rejects broad x402 compatibility, payment management, settlement, seller/facilitator operation, hosted trust, marketplace/certification, clearing-house readiness, cross-org certificate trust, and broad runtime/MCP/CLI/browser/shell/network/package-manager control unless explicitly non-claims.","Guard uses a small named surface map and grouped assertions, not unbounded regex sprawl."],"candidate_paths":["test/architecture/claim-boundary.test.ts"],"non_goals":["No protocol behavior changes.","No broad repo-wide grep with opaque exceptions.","No new authority surfaces."]} -{"id":"macro-003","priority":"P1","phase":"Phase 1","title":"Strengthen x402 report claim guards","owner":"product proof owner","rationale":"The APS report is buyer-readable and must not imply aggregate payment-budget management or action classes the gateway does not expose.","depends_on":["macro-001"],"acceptance":["Product report test no longer requires spend reservation ledger as a missing proof object for current claims.","Test requires aggregate payment-budget management to be absent from current authority or explicitly out of current remit.","Test keeps not_enforced_local_metadata only as local metadata.","Test keeps x402_paid_http_call.exact classified as buyer-readable report language and x402_payment.exact as the protected action class."],"candidate_paths":["test/product/x402-protected-spend-demo-report.test.ts"],"non_goals":["No aggregate spend ledger implementation.","No new payment or settlement semantics.","No gateway or signer behavior changes."]} -{"id":"macro-004","priority":"P1","phase":"Phase 2","title":"Rewrite canonical category language","owner":"docs/canon owner","rationale":"Durable repo truth must reflect the corrected category while preserving Tier 1 protocol meaning.","depends_on":["macro-002"],"acceptance":["AGENTS.md, README.md, and docs/internal/decisions.md no longer define Handshake as engineering-agent-only.","Canonical docs describe Handshake as protected actions for automated decision making or protected action control.","Engineering-agent references are retained only as adoption context, generated-execution stress case, or current proof context.","No protocol object semantics, public exported symbols, scripts, or source paths are renamed."],"candidate_paths":["AGENTS.md","README.md","docs/internal/decisions.md","docs/internal/protocol-definition.md","docs/internal/protocol-kernel-architecture.md","docs/internal/protocol-layman.md","docs/internal/protocol-notes.md"],"non_goals":["No Tier 1 protocol rewrite.","No product marketing expansion.","No broad automated-decision governance claim."]} -{"id":"macro-005","priority":"P1","phase":"Phase 3","title":"Clean x402 walkthrough and report wording","owner":"example/product proof owner","rationale":"The first wedge must stay exact per-call x402 authorization without payment-management, custody, settlement, or broad compatibility implications.","depends_on":["macro-003"],"acceptance":["x402 walkthrough scopes the proof to one buyer-side x402_payment.exact per-call protected action.","examples/x402-protected-spend/run.ts emits out-of-current-remit aggregate payment-budget posture instead of spend-ledger-required wording.","not_enforced_local_metadata remains only where clearly local metadata.","Report and README preserve local/reference sandbox, gateway-held signer after VerifiedGatewayCheck, replay refusal, proof-gap, and non-claims.","Support/debug language does not request or expose raw payment or credential material."],"candidate_paths":["examples/x402-protected-spend/README.md","examples/x402-protected-spend/run.ts","examples/self-hosted-activation/README.md","test/product/x402-protected-spend-demo-report.test.ts"],"non_goals":["No signer custody change.","No x402 compatibility expansion.","No settlement, facilitator, seller, or hosted operation claim."]} -{"id":"macro-006","priority":"P2","phase":"Phase 4","title":"Align lane manifests with category and non-authority boundaries","owner":"source-boundary owner","rationale":"Lane manifests are local ownership contracts and must not launder proposal/evidence surfaces into authority surfaces.","depends_on":["macro-002","macro-004"],"acceptance":["Runtime lane says runtime proposes and records evidence only.","MCP lane says MCP proposes/displays evidence only and cannot authorize.","CLI and SDK lane wording does not imply signer, gateway, receipt-export, or certificate authority.","Adapter lane preserves protected-action-pack discipline and says no adapter family defines the protocol.","Conformance lane avoids marketplace, certification, or provider-enforcement claims."],"candidate_paths":["src/runtime/LANE.md","src/mcp/LANE.md","src/cli/LANE.md","src/sdk/LANE.md","src/adapters/LANE.md","src/conformance/LANE.md"],"non_goals":["No new MCP tools.","No new CLI commands.","No SDK authority client.","No package export changes."]} -{"id":"macro-007","priority":"P2","phase":"Phase 5","title":"Clean active planning scratch drift","owner":"planning hygiene owner","rationale":"Future agents may reload active scratch; it should not contradict the cleaned canon even though it is not repo truth.","depends_on":["macro-004","macro-005"],"acceptance":[".planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md uses protected actions for automated decision making and keeps x402 exact per-call as first wedge.","Spend-ledger language in active scratch is either removed or clearly marked stale/out of remit.","If .planning/codebase/CONCERNS.md is touched, it is updated as scratch risk evidence only and not promoted to canon."],"candidate_paths":[".planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md",".planning/codebase/CONCERNS.md"],"non_goals":["No archive cleanup.","No repo-facing references to .planning.","No planning taxonomy in source, scripts, CI, README sections, or exports."]} -{"id":"macro-008","priority":"P1","phase":"Phase 6","title":"Run focused claim validation","owner":"implementation lead","rationale":"The slice is not closed until claim guards prove stale category and payment-management wording cannot return.","depends_on":["macro-004","macro-005","macro-007"],"acceptance":["npm run quality:claims passes.","npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts passes.","Failures are fixed by narrowing claims, not by implementing out-of-scope capability."],"candidate_paths":["test/architecture/claim-boundary.test.ts","test/product/x402-protected-spend-demo-report.test.ts"],"non_goals":["No skipped claim tests.","No weakening forbidden-claim assertions to make prose pass."]} -{"id":"macro-009","priority":"P1","phase":"Phase 6","title":"Regenerate and verify APS report if report source changed","owner":"product proof owner","rationale":"The buyer-readable report is an observable contract and must match the narrowed claim boundary.","depends_on":["macro-005"],"acceptance":["npm run demo:aps passes when examples/x402-protected-spend/run.ts changes.","examples/x402-protected-spend/output/latest.md and latest.json preserve exact per-call x402 posture and local/reference non-claims.","Generated report contains no raw credential or payment material."],"candidate_paths":["examples/x402-protected-spend/run.ts","examples/x402-protected-spend/output/latest.md","examples/x402-protected-spend/output/latest.json"],"non_goals":["No hosted provider run.","No external x402 compatibility verification.","No settlement or payment finality proof."]} -{"id":"macro-010","priority":"P2","phase":"Phase 6","title":"Run architecture and package posture validation","owner":"source-boundary owner","rationale":"Claim cleanup must not move public entrypoints or lane authority boundaries.","depends_on":["macro-006"],"acceptance":["npm run test -- test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts passes if lane or package-facing wording changed.","npm run quality:architecture passes.","No new public exports, scripts, package subpaths, or source directories are introduced."],"candidate_paths":["test/architecture/import-posture.test.ts","test/architecture/root-exports.test.ts","src/runtime/LANE.md","src/mcp/LANE.md","src/cli/LANE.md","src/sdk/LANE.md","src/adapters/LANE.md","src/conformance/LANE.md"],"non_goals":["No export changes.","No package publication claim.","No generated dist or publish workflow work unless existing gates require it."]} -{"id":"macro-011","priority":"P1","phase":"Phase 6","title":"Run final format and repo closeout","owner":"implementation lead","rationale":"The future implementation slice should close with normal repo proof, not just focused claim tests.","depends_on":["macro-008","macro-009","macro-010"],"acceptance":["npm run format:check passes.","npm run check:repo passes.","Closeout summary names existing green evidence, changed guard surfaces, blocked external checks, and proof that Tier 1 behavior did not change."],"candidate_paths":["README.md","AGENTS.md","docs/internal/decisions.md","docs/internal/protocol-definition.md","docs/internal/protocol-kernel-architecture.md","docs/internal/protocol-layman.md","docs/internal/protocol-notes.md","test/architecture/claim-boundary.test.ts","test/product/x402-protected-spend-demo-report.test.ts"],"non_goals":["No staging or commit unless separately requested.","No external verification claims.","No capability expansion."]} diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/VALIDATION.md deleted file mode 100644 index 7171646..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/VALIDATION.md +++ /dev/null @@ -1,126 +0,0 @@ -# Validation - -## Existing Source-Present Checks - -These checks exist in the repo today but were not run during this planning-only synthesis: - -- `test/architecture/claim-boundary.test.ts` checks public entrypoint separation and several current runtime, MCP, conformance, and x402 non-claims. -- `test/product/x402-protected-spend-demo-report.test.ts` executes `examples/x402-protected-spend/run.ts` and checks local APS report boundaries, redaction, replay refusal, role clients, and non-claims. -- `test/architecture/import-posture.test.ts` and `test/architecture/root-exports.test.ts` guard package/lane import and export posture. - -## Planned Guard Additions - -### Category Boundary - -Proof obligation: - -- Canonical docs state protected actions for automated decision making. -- Canonical docs do not define Handshake as engineering-agent-only. -- Engineering-agent references are adoption context, generated-execution threat model, or current local proof context. - -Candidate gate: - -```bash -npm run test -- test/architecture/claim-boundary.test.ts -``` - -### x402 Wedge Boundary - -Proof obligation: - -- x402 is one official buyer-side `x402_payment.exact` per-call protected-action wedge. -- No adapter family defines the protocol. -- `x402_paid_http_call.exact` remains buyer-readable report language only. -- No broad x402 compatibility, `upto`, batch settlement, seller middleware, facilitator operation, or settlement finality claim. - -Candidate gates: - -```bash -npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts -npm run demo:aps -``` - -### Aggregate Payment-Budget Non-Remit - -Proof obligation: - -- Product-scope `spend reservation ledger required before claim` language is removed. -- Aggregate payment-budget management is intentionally out of current remit. -- `not_enforced_local_metadata` appears only as local metadata, not disabled enforcement or a roadmap promise. - -Candidate gate: - -```bash -npm run test -- test/product/x402-protected-spend-demo-report.test.ts -``` - -### Surface Non-Authority - -Proof obligation: - -- Runtime, MCP, CLI, SDK, review, report, and terminal certificate surfaces do not evaluate policy, issue greenlights, check gateways, mutate, export raw receipts, invoke signers, or mint authority. -- Lane manifests do not claim broad runtime, MCP, browser, shell, network, package-manager, cloud, repo, or database protection. - -Candidate gates: - -```bash -npm run test -- test/architecture/claim-boundary.test.ts -npm run test -- test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts -npm run quality:architecture -``` - -### Redaction And Support Payload Boundary - -Proof obligation: - -- Walkthroughs and support language do not request or expose `PaymentPayload`, `PAYMENT-SIGNATURE`, private keys, signer refs, raw store records, role-token maps, gateway credentials, or raw payment material. -- Shareable support/debug artifacts are redacted refs, reason codes, request IDs, local report sections, and local certificate verification results. - -Candidate gate: - -```bash -npm run quality:claims -``` - -## Required Closeout Commands - -Run focused gates first: - -```bash -npm run quality:claims -npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts -``` - -Run demo gate if `examples/x402-protected-spend/run.ts` changes: - -```bash -npm run demo:aps -``` - -Run architecture/package posture gates if lane manifests or public docs change: - -```bash -npm run test -- test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts -npm run quality:architecture -``` - -Run final formatting and repo gate: - -```bash -npm run format:check -npm run check:repo -``` - -If implementation touches runtime, MCP, or x402 proposal internals despite the cut line, add: - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/mcp/mcp-x402-proposal.test.ts test/adapters/x402-payment-action-proposal.test.ts -``` - -That should be exceptional. A need for those tests means the slice may be drifting from claim cleanup into capability work. - -## Blocked In This Synthesis - -- No tests were run; this chair task was planning-only. -- No external x402, npm, MCP Registry, JWKS, Cloudflare, legal, or payment-regulatory verification was performed. -- Package script definitions were not re-read from `package.json` because the run input provided the command contract and this chair stayed inside the allowed source boundary. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/input.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/input.md deleted file mode 100644 index f0bb016..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/input.md +++ /dev/null @@ -1,148 +0,0 @@ -# Macro Plan Input: Claim Boundary Cleanup - -Run ID: `claim-boundary-cleanup-20260524T065926Z` - -## Target - -Create a source-grounded macro plan for critical-path item 0 from `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md`: **Claim Boundary Cleanup**. - -Goal: remove ambiguity before adding new capability. The plan must define the implementation path for making eliminated items intentional product boundaries, not pending promises or roadmap-shaped claims. - -Important correction from the user: Handshake is **not specific to engineering agents**. Handshake is protected actions for automated decision making. The current first wedge is x402 protected actions, and engineering-agent workflows are an adoption context, not the category boundary. The plan must preserve modularity so the protocol can extend beyond the first wedge without turning any wedge into the protocol definition. - -## User Constraints - -- Use `$gsd-macro-plan` as a subagent-first workflow. -- This is planning only. Do not implement source changes under this run. -- Keep Tier 1 protocol/kernel meaning stable. -- Treat protected actions for automated decision making as the product category. -- Treat x402 as the first wedge unless source evidence proves a narrower implementation sequence is required. -- Do not make engineering agents the product boundary; treat them as one current adoption context. -- Do not weaken the Tier 2 x402 exact per-call wedge. -- Preserve customer-owned gateway custody as the future enforcement model. -- Do not turn Handshake into payment management, generic agent governance, hosted observability, settlement, marketplace, certification, or broad runtime control. -- Plans must be executable later: source-owned mechanisms, tests, claim guards, closeout gates, and cut lines. - -## Source Boundary - -Allowed source files for first-pass agents: - -- `AGENTS.md` -- `README.md` -- `QUALITY.md` -- `STRUCTURE.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-layman.md` -- `docs/internal/protocol-notes.md` -- `.planning/macro/README.md` -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` -- `.planning/codebase/ARCHITECTURE.md` -- `.planning/codebase/CONCERNS.md` -- `.planning/codebase/CONVENTIONS.md` -- `.planning/codebase/INTEGRATIONS.md` -- `.planning/codebase/STACK.md` -- `.planning/codebase/STRUCTURE.md` -- `.planning/codebase/TESTING.md` -- `test/architecture/claim-boundary.test.ts` -- `test/architecture/import-posture.test.ts` -- `test/architecture/root-exports.test.ts` -- `test/product/x402-protected-spend-demo-report.test.ts` -- `examples/x402-protected-spend/README.md` -- `examples/x402-protected-spend/run.ts` -- `examples/self-hosted-activation/README.md` -- `src/runtime/LANE.md` -- `src/mcp/LANE.md` -- `src/cli/LANE.md` -- `src/sdk/LANE.md` -- `src/adapters/LANE.md` -- `src/conformance/LANE.md` - -Forbidden files for first-pass agents: - -- sibling raw outputs under this run; -- normalized outputs under this run; -- the final `PLAN.md` for this run before chair synthesis; -- unrelated historical `.planning/macro/archive/**` files unless a specific current source file links to them; -- source files not listed above unless the agent first records why the listed source packet is insufficient. - -## Required Output Directory - -All artifacts for this item must stay under: - -```text -.planning/macro/active/claim-boundary-cleanup/ -``` - -First-pass outputs: - -```text -.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/STRATEGY.md -.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/ARCH.md -.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/EXECUTION.md -.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/RISK.md -.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/ADOPTION.md -``` - -Chair outputs: - -```text -.planning/macro/active/claim-boundary-cleanup/PLAN.md -.planning/macro/active/claim-boundary-cleanup/CONTEXT.md -.planning/macro/active/claim-boundary-cleanup/ASSUMPTIONS.md -.planning/macro/active/claim-boundary-cleanup/DECISIONS.md -.planning/macro/active/claim-boundary-cleanup/RISKS.md -.planning/macro/active/claim-boundary-cleanup/VALIDATION.md -.planning/macro/active/claim-boundary-cleanup/TASKS.jsonl -.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/synthesis.md -``` - -## Plan Requirements - -The chair plan must include: - -- goal; -- non-goals; -- source boundary; -- current state; -- target state; -- assumptions; -- decisions; -- phases; -- task graph; -- risks and mitigations; -- validation gates; -- cut lines; -- rollback / stop conditions; -- smallest next action. - -The plan must explicitly cover: - -- replacing "spend reservation ledger required before claim" wording with "aggregate payment-budget management intentionally out of current remit" where source evidence supports that cleanup; -- identifying source language that over-constrains Handshake to engineering agents and planning how to restate it as protected actions for automated decision making without overclaiming broad runtime control; -- keeping `not_enforced_local_metadata` only where clearly local metadata; -- adding or strengthening claim guards so docs/examples cannot imply payment management, settlement, seller/facilitator operation, hosted trust, broad x402 compatibility, broad runtime/MCP/CLI/browser/shell/network/package-manager control, marketplace/certification, clearing-house readiness, or cross-org certificate trust; -- preserving per-call x402 exact authorization as the current wedge; -- preserving modular adapter/action-pack discipline so x402 proves the spine but does not define it; -- preserving customer-owned gateway custody, terminal evidence, proposal/evidence surfaces, and one protected-action-pack-at-a-time discipline; -- identifying which checks are already green versus planned; -- identifying what must remain deferred or eliminated. - -## Success Criteria - -- The macro plan is executable as a future implementation slice without altering Tier 1 protocol meaning. -- The plan corrects category language toward protected actions for automated decision making while preserving source-backed boundaries. -- The plan narrows claim language and tests; it does not add authority, custody, payment management, settlement, or hosted operation. -- Each task names source/test/doc candidate paths and closeout evidence. -- `TASKS.jsonl` parses as JSONL. -- Validation gates are specific enough to fail overclaims. -- The plan names antipatterns and stop conditions. - -## External Verification - -This item is mostly repo-claim cleanup. Do not browse by default. If a perspective proposes npm, MCP Registry, JWKS, Cloudflare, x402, or legal/payment-regulatory language as part of this specific slice, it must explicitly mark that as out of scope or require external verification before implementation. - -## 10 Star Product Bar - -Claim cleanup is successful when a sophisticated buyer, maintainer, auditor, or future agent cannot misread local proof lanes as broad product authority or misread the first adoption context as the whole category. Handshake should read as smaller, sharper, and harder to fake: protected actions for automated decision making, proven first through x402 exact per-call authorization, with exact contract, one-use greenlight, gateway check, redacted evidence, proof gap, and terminal evidence only where the source actually enforces them. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/ADOPTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/ADOPTION.md deleted file mode 100644 index 1592ee0..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/ADOPTION.md +++ /dev/null @@ -1,207 +0,0 @@ -# ADOPTION First-Pass Plan: Claim Boundary Cleanup - -## Invariant at stake - -Adoption material must not turn a local proof lane into a product claim. A new user, maintainer, buyer, auditor, or future agent must understand that Handshake is protected actions for automated decision making, currently proven through a narrow x402 exact per-call protected-action wedge. Engineering-agent workflows are an adoption context, not the category boundary. - -If the docs teach "engineering agents" as the product category, the compiler overreaches the principal. If the x402 walkthrough teaches spend budgeting, settlement, hosted trust, seller/facilitator operation, or broad runtime control, the adoption surface is advisory theatre. - -## Source posture used - -Allowed packet read: `.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/input.md`. - -Allowed source files read for this pass included the canonical docs, current macro register, codebase maps, claim-boundary tests, x402 product report test, x402 walkthrough/readme, self-hosted activation readme, and source lane manifests named by the input packet. - -No sibling raw outputs, normalized outputs, or final `PLAN.md` were read. - -## Adoption path - -1. Establish the category vocabulary first. - - Candidate paths: `README.md`, `AGENTS.md`, `docs/internal/decisions.md`, `docs/internal/protocol-notes.md`, `docs/internal/protocol-layman.md`. - - Replace top-level "contracted execution infrastructure for engineering agents" posture with "protected actions for automated decision making" or "protocol kernel for protected action control" where the statement defines the product category. - - Preserve engineering-agent examples only where they are explicitly framed as the current adoption context or one generated-execution source. - - Do not change the Tier 1 primitive: exact action contract -> policy decision -> one-use greenlight -> gateway check -> receipt/refusal/proof gap. - -2. Make x402 the first wedge, not the protocol definition. - - Candidate paths: `README.md`, `docs/internal/decisions.md`, `docs/internal/protocol-definition.md`, `docs/internal/protocol-kernel-architecture.md`, `examples/x402-protected-spend/README.md`, `examples/x402-protected-spend/run.ts`. - - Teach the first-use path as one installed protected action pack: one official buyer-side `x402_payment.exact` per-call attempt. - - Keep `x402_paid_http_call.exact` as buyer-readable report language only unless the action catalog, compiler, policy, and gateway all expose that action class. - - Keep "No adapter family defines the protocol" visible near the first x402 walkthrough. - -3. Reframe aggregate spend as intentionally outside current remit. - - Candidate paths: `README.md`, `examples/x402-protected-spend/run.ts`, `test/architecture/claim-boundary.test.ts`, `test/product/x402-protected-spend-demo-report.test.ts`. - - Replace "spend reservation ledger required before claim" and "until a ledger exists" style language with "aggregate payment-budget management is intentionally out of current remit" where the source is describing product scope. - - Keep `not_enforced_local_metadata` only where it labels local metadata and cannot be read as a planned spend-window feature. - - The adoption message should be: Handshake authorizes one exact x402 protected action attempt; it does not manage budgets, reservations, or payment programs. - -4. Turn the first-use path into a claim-boundary walkthrough. - - Candidate paths: `README.md`, `examples/x402-protected-spend/README.md`, `examples/self-hosted-activation/README.md`. - - The first-use path should ask the user to run `npm run demo:aps`, inspect `examples/x402-protected-spend/output/latest.md`, and verify these boundaries: - - 402 challenge evidence exists before authority. - - Runtime proposal creates no policy, greenlight, gateway check, mutation, receipt, or certificate. - - Policy greenlights one exact contract. - - Gateway check precedes signing. - - Signed retry is downstream fixture evidence, not authority. - - Replay refuses before signer reuse. - - Proof gaps remain proof gaps. - - Terminal certificate is local pinned terminal evidence only. - -5. Keep support and debugging redacted from first use. - - Candidate paths: `README.md`, `src/sdk/LANE.md`, `examples/x402-protected-spend/README.md`. - - First-use docs should tell users to share only redacted report refs, reason codes, request identities, projection payloads, and local certificate verification results. - - They must not share `PaymentPayload`, `PAYMENT-SIGNATURE`, private keys, signer refs, raw store records, role-token maps, or gateway credentials. - -6. Preserve role-scoped activation ergonomics. - - Candidate paths: `README.md`, `examples/x402-protected-spend/run.ts`, `src/sdk/LANE.md`, `test/product/x402-protected-spend-demo-report.test.ts`. - - Keep first-slice activation on `RuntimeClient` and `EvidenceClient` from `handshake-protocol-kernel/sdk/role-clients`. - - Keep all-role `HandshakeClient` out of product walkthroughs because it teaches a mixed-custody shape. - -## First-use checklist - -For the future implementation slice, first-use docs should let a user complete this exact path: - -1. Read the top-level category: Handshake protects actions for automated decision making through installed gateway-checked paths. -2. Confirm the local setup command: `bun install --frozen-lockfile`. -3. Run the repo gate: `npm run check:repo`. -4. Run the x402 first wedge: `npm run demo:aps`. -5. Open `examples/x402-protected-spend/output/latest.md`. -6. Confirm the report shows the exact action class `x402_payment.exact`, not a generic payment manager. -7. Confirm the report's non-claims include no hosted operation, no provider/customer custody, no aggregate payment-budget management, no settlement finality, no seller/facilitator operation, no broad x402 compatibility, no broad MCP/CLI/browser/shell/network control, no cross-org certificate trust, no marketplace/certification, and no clearing-house readiness. -8. Confirm the gateway/signing section says signer invocation happens only after `VerifiedGatewayCheck`. -9. Confirm replay refusal does not reuse the signer. -10. Confirm support/debugging instructions use redacted refs and reason codes only. - -## Missing docs and examples - -- Missing category correction in top-level canonical language. - - Current issue: `README.md`, `AGENTS.md`, and `docs/internal/decisions.md` still contain category-level engineering-agent language. - - Fix: top-level category should become protected actions for automated decision making; engineering-agent execution remains a current adoption context and generated-execution source. - -- Missing wedge ladder. - - Fix: add a compact ladder in `README.md` and `docs/internal/decisions.md`: - - category: protected actions for automated decision making; - - protocol primitive: exact contract, policy, one-use greenlight, gateway check, receipt/refusal/proof gap; - - first wedge: x402 exact per-call protected action; - - current adoption context: automated engineering/runtime workflows; - - local proof boundary: local/reference only, no hosted/provider/cross-org claims. - -- Missing "how to read the APS report" guide. - - Fix: in `examples/x402-protected-spend/README.md`, explain each report section as adoption evidence: challenge before authority, proposal not permission, gateway check, signed retry evidence, replay refusal, proof gap, terminal certificate, non-claims. - -- Missing aggregate payment-budget cut-line language. - - Current issue: source/test language still treats "spend reservation ledger" as a missing proof object for future aggregate spend enforcement. - - Fix: replace with "aggregate payment-budget management intentionally out of current remit" in docs/report fields where the claim boundary is product scope rather than local metadata. - -- Missing support/debuggability playbook. - - Fix: add a short support section to the x402 walkthrough and/or README that says exactly which redacted artifacts can be shared and which credential/payment fields must never be requested. - -- Missing claim guard for engineering-agent category drift. - - Fix: strengthen `test/architecture/claim-boundary.test.ts` so top-level category statements cannot define Handshake as only engineering-agent infrastructure while still allowing engineering-agent workflows as example/adoption context. - -- Missing claim guard for report proof-object label. - - Fix: strengthen `test/product/x402-protected-spend-demo-report.test.ts` so `x402_paid_http_call.exact` remains classified as buyer-readable report language, not the action catalog class. - -## Success metrics - -- A buyer can state the product category after reading the first screen of `README.md`: protected actions for automated decision making, not generic agent governance and not only engineering agents. -- A developer can run `npm run demo:aps` and identify the exact contract, policy decision, gateway check, signed retry evidence, replay refusal, proof gap posture, and terminal evidence boundary without reading source internals. -- `npm run quality:claims` fails if canonical docs imply payment management, settlement, seller/facilitator operation, hosted trust, broad x402 compatibility, broad runtime/MCP/CLI/browser/shell/network/package-manager control, marketplace/certification, clearing-house readiness, or cross-org certificate trust. -- `test/product/x402-protected-spend-demo-report.test.ts` fails if the report describes aggregate payment-budget management as a near-term missing implementation rather than an intentional current non-remit. -- First-use examples import `RuntimeClient` and `EvidenceClient` from `handshake-protocol-kernel/sdk/role-clients` and do not import `HandshakeClient`. -- Search over canonical docs and walkthroughs finds engineering-agent language only as an adoption context, generated-execution example, or first-wedge operating environment, not as the protocol category. -- Search over x402 walkthrough/report output finds `not_enforced_local_metadata` only next to clearly local metadata, never as enforced spend control. - -## Adoption blockers and fixes - -| Blocker | Adoption failure | Fix | -| --- | --- | --- | -| Engineering-agent language defines the category | Buyers and future implementers think Handshake is a coding-agent tool, not protected actions for automated decision making | Rewrite category claims in canonical docs; add claim guard that allows engineering-agent examples only with context qualifiers | -| x402 first wedge reads like payment management | Users expect budgets, settlement, facilitator/seller roles, or provider custody | Make aggregate payment-budget management an explicit non-remit; keep per-call x402 exact as the only current spend authority | -| "Spend reservation ledger" reads like pending roadmap | Future work drifts into payment-program features just to satisfy an old claim | Replace product-scope occurrences with intentional non-remit language; leave ledger only as local metadata language if needed | -| Report proof object differs from action class | Users think `x402_paid_http_call.exact` is gateway-bound authority | Label it as buyer-readable only and guard action class remains `x402_payment.exact` | -| Self-hosted activation packet composes many surfaces | Users infer MCP/CLI/runtime are mutation or authority surfaces | Put proposal/evidence-only disclaimers directly next to activation commands and artifacts | -| Role-scoped SDK path is easy to bypass | Examples drift back to all-role client ergonomics | Keep product walkthroughs on role clients and assert the example source does not import `HandshakeClient` | -| Support path is underdocumented | Debugging requests may solicit payment signatures, raw records, or credentials | Add a support payload allowlist and forbidden field list to first-use docs | -| Package/registry/readiness language can overclaim availability | Users infer public distribution or endorsement from local metadata | Keep publication/registry claims deferred unless externally verified and owner-held credentials prove publication | - -## Assumptions - -- The user correction overrides stale category wording in current source: Handshake is protected actions for automated decision making. -- x402 remains the first wedge unless later source evidence proves a narrower implementation sequence. -- Tier 1 protocol/kernel meaning remains stable. -- This slice is claim cleanup only. It should not add custody, hosted operation, payment-budget management, settlement, provider integration, or runtime interception. -- Claim-boundary tests are the right enforcement surface for adoption language. -- `.planning/` remains scratch and must not become canonical repo truth. - -## Dependencies - -- Canonical docs: `README.md`, `AGENTS.md`, `docs/internal/decisions.md`, `docs/internal/protocol-definition.md`, `docs/internal/protocol-kernel-architecture.md`, `docs/internal/protocol-layman.md`, `docs/internal/protocol-notes.md`. -- Adoption examples: `examples/x402-protected-spend/README.md`, `examples/x402-protected-spend/run.ts`, `examples/self-hosted-activation/README.md`. -- Guard tests: `test/architecture/claim-boundary.test.ts`, `test/product/x402-protected-spend-demo-report.test.ts`. -- Lane boundaries: `src/runtime/LANE.md`, `src/mcp/LANE.md`, `src/sdk/LANE.md`, `src/adapters/LANE.md`, `src/conformance/LANE.md`. -- Validation commands named by allowed docs: `npm run quality:claims`, `npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts`, `npm run check:repo`. - -## Risks - -- Overcorrection risk: replacing engineering-agent category language with "automated decision making" could sound like broad governance unless every occurrence is tied back to installed protected paths. -- Wedge confusion risk: x402 can prove the spine without defining the protocol; docs must keep this hierarchy explicit. -- Payment-regulatory risk: "budget", "reservation", "settlement", "facilitator", "seller", and "clearing house" language can imply payment-management scope. Use non-claim language, not roadmap language. -- Support risk: a user debugging a failed local run may expose credential material unless the docs state a redacted support payload. -- MCP/CLI risk: local proposal/evidence surfaces can look like control surfaces if the first-use path puts them before the x402 authority chain. -- Claim-test brittleness risk: naive regex bans can block valid "engineering-agent adoption context" text. Guards should distinguish category statements from examples. -- External availability risk: publication, MCP Registry, JWKS, provider custody, and x402 legal/payment claims require external verification and are outside this cleanup slice. - -## Validation gates - -Planning gates for the future implementation slice: - -1. Category language gate. - - Search canonical docs and examples for category-level "engineering agents" wording. - - Pass only if engineering-agent references are context/examples, not product boundary. - -2. x402 wedge gate. - - `test/architecture/claim-boundary.test.ts` must keep "No adapter family defines the protocol" and one official buyer-side exact per-call boundary. - - It must reject broad x402 compatibility, facilitator/seller/settlement, hosted trust, and broad runtime claims. - -3. Aggregate payment-budget gate. - - `test/product/x402-protected-spend-demo-report.test.ts` must assert aggregate payment-budget management is outside current remit. - - It must not require a "spend reservation ledger" as a future claim prerequisite unless clearly labeled local metadata and not product scope. - -4. First-use output gate. - - `npm run demo:aps` must produce `examples/x402-protected-spend/output/latest.md` and `.json` with non-claims and missing-proof posture that cannot be read as authority. - -5. Role-client gate. - - Product walkthroughs must use `RuntimeClient` and `EvidenceClient` and must not import `HandshakeClient`. - -6. Support redaction gate. - - Docs must contain a support payload allowlist and forbidden credential/payment fields. - -7. Closeout gate. - - Run: - - `npm run quality:claims` - - `npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts` - - `npm run check:repo` - -## Cut lines - -- No hosted operation. -- No payment management. -- No aggregate payment-budget management. -- No settlement or downstream business-success claims. -- No facilitator operation. -- No seller middleware. -- No provider/customer custody claim from local fixtures. -- No broad x402 compatibility. -- No broad MCP, CLI, browser, shell, package-manager, network, cloud, repo, or database control. -- No marketplace, certification, clearing-house, or cross-org trust claim. -- No public package or MCP Registry availability claim without external verification and owner-held publication evidence. -- No review UI, approval, or rendered report as authority unless structurally bound to the exact action contract and enforced at gateway time. -- No mutation, signer access, receipt export, or certificate minting through SDK/MCP/CLI first-use surfaces. - -## Blocked checks - -- Did not run validation commands; this is a planning-only first-pass output. -- Did not verify `package.json` scripts directly because `package.json` was not in the allowed source boundary. Commands were taken from allowed docs. -- Did not externally verify x402, npm, MCP Registry, JWKS, Cloudflare, or legal/payment-regulatory language; the input packet says not to browse by default for this slice. -- Did not inspect source files outside the input packet allowlist, including implementation files referenced by allowed docs. -- Did not inspect sibling raw outputs, normalized outputs, or final `PLAN.md`. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/ARCH.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/ARCH.md deleted file mode 100644 index c0d296c..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/ARCH.md +++ /dev/null @@ -1,141 +0,0 @@ -# ARCH First Pass: Claim Boundary Cleanup - -## Invariant At Stake - -Handshake must not let category language become authority language. The architecture can support protected actions for automated decision making, with x402 as the first wedge, only if repo canon keeps the authority spine stable: - -```text -exact action contract --> policy decision --> one-use greenlight or refusal --> gateway check before mutation --> receipt, refusal, proof gap, or terminal evidence -``` - -If cleanup turns into broad runtime control, payment management, hosted trust, or a protocol rewrite, it weakens the boundary. If cleanup leaves "engineering agents" as the product boundary, the repo misstates the category and will keep producing wedge-shaped strategy errors. - -## Architecture Implications - -- This is a claim and guard migration, not a Tier 1 protocol migration. `docs/internal/protocol-definition.md` already defines the core as "protected action control" and should remain the authority rule source. -- Product category language should move from "contracted execution infrastructure for engineering agents" to protected actions for automated decision making. Engineering-agent workflows remain an adoption context and evidence source, not the protocol boundary. -- x402 should be presented as the current first protected-action wedge: one official buyer-side `x402_payment.exact` per-call path. It must not become the protocol definition. -- Existing protocol participant names such as `agentId`, `AgentTransactionEnvelopeProjection`, runtime evidence, and generated-execution graph should not be renamed in this slice. "Agent" remains a participant/evidence role where source objects already use it; it should stop being the top-level category claim. -- Spend-window language should stop implying a ledger is required before a future claim. Aggregate payment-budget management should be named as intentionally out of current remit. `not_enforced_local_metadata` can remain only when a local metadata field is explicitly non-enforcing. -- The cleanup should strengthen `test/architecture/claim-boundary.test.ts` and `test/product/x402-protected-spend-demo-report.test.ts`, not create new authority surfaces. -- `.planning/codebase/*` identifies current runtime/x402/MCP posture drift, but `.planning/` remains scratch. Durable corrections belong in compact canon docs and tests. - -## Boundaries That Must Not Move - -- `src/protocol/**` remains the only owner of protocol meaning. Do not move product-category text into protocol objects unless the schema truly changes. -- `src/runtime/**` remains proposal/evidence only. It may observe generated decisions and propose candidates; it must not evaluate policy, issue greenlights, gateway-check, receipt, mutate, or sign. -- `src/mcp/**` and `src/cli/**` remain proposal/evidence/operator surfaces only. No mutation, signer, gateway custody, receipt export, hosted operation, or cross-org trust path belongs there. -- `src/adapters/**` remains reference gateway/profile code. Mutation-capable adapters still run only after `VerifiedGatewayCheck`. -- `src/conformance/**` remains reference posture checks, not certification or standards compliance. -- Customer-owned gateway custody remains the future enforcement model. Do not add Handshake-held payment custody, signer custody, balances, settlement, seller middleware, or facilitator operation. -- x402 remains per-call exact authorization only. Do not add aggregate budget management to make old wording true. -- `AuthorityCertificate` remains terminal evidence. Do not claim permission, identity, settlement, marketplace certification, hosted verifier operation, or cross-org trust. - -## Likely Source/Test/Doc Paths - -### Canonical Docs To Update - -- `AGENTS.md`: replace category-level "contracted execution infrastructure for engineering agents" and "first wedge is engineering-agent actions" with protected actions for automated decision making; retain engineering-agent examples as current adoption context and generated-execution pressure case. -- `README.md`: update headline, system-design posture, and x402 demo language so the repo reads as a protected-action kernel with x402 as first wedge. -- `docs/internal/decisions.md`: update "Product Kernel", "Current Bought Product", and "Claims Boundary" so the durable decision is category-first, wedge-second. -- `docs/internal/protocol-definition.md`: likely only small wording cleanup. Preserve "protocol kernel for protected action control" and authority rule exactly. -- `docs/internal/protocol-kernel-architecture.md`: update architecture summary/local establishment wording only where it implies engineering agents define the protocol. -- `docs/internal/protocol-layman.md`: restate "agents will do real work through tools" as one common automated-decision actor, not the category limit. -- `docs/internal/protocol-notes.md`: update "Use case: reduce generated engineering-agent execution..." to protected-action attempts from automated decision systems, with generated engineering-agent execution as current pressure case. -- `examples/x402-protected-spend/README.md`: change scope from "generated engineering-agent execution evidence" to automated decision / generated execution evidence, with engineering-agent workflow as the local demo context if needed. -- `examples/self-hosted-activation/README.md`: likely keep non-claims; check for category drift during implementation. - -### Tests And Guards To Update - -- `test/architecture/claim-boundary.test.ts`: add guard that canon contains protected actions for automated decision making and does not define the product as engineering-agent-only. Also guard against payment management, settlement, seller/facilitator, hosted trust, broad x402 compatibility, broad runtime control, marketplace/certification, and cross-org certificate trust. -- `test/product/x402-protected-spend-demo-report.test.ts`: replace expectation that `missingProofObjects` contains "spend reservation ledger" with wording that marks aggregate payment-budget management out of remit or absent by design. Keep assertions for per-call exact authorization, local/reference sandbox, gateway-held signer, replay refusal, proof gap, and non-claims. -- `test/architecture/import-posture.test.ts`: likely no direct change unless doc cleanup touches lane manifest boundaries. Keep as validation gate. -- `test/architecture/root-exports.test.ts`: likely no direct change. Run to prove claim cleanup did not move public surfaces. - -### Source/Demo Paths Likely Touched By Claim Text - -- `examples/x402-protected-spend/run.ts`: update report strings such as "Premium context for one generated engineering-agent request", missing proof object label "spend reservation ledger", and final local-evidence disclaimer if needed. Do not alter authority flow. -- `src/runtime/LANE.md`, `src/mcp/LANE.md`, `src/cli/LANE.md`, `src/sdk/LANE.md`, `src/adapters/LANE.md`, `src/conformance/LANE.md`: only update category wording if a lane describes the product boundary. Keep lane-specific authority owner and forbidden imports stable. - -## Data And Control Flow To Preserve - -```text -automated decision / generated execution evidence --> runtime or MCP proposal surface --> intent compilation --> CandidateAction --> ActionContract --> PolicyDecision --> Greenlight --> GatewayCheck --> x402 wallet gateway creates signature evidence after verified gate --> local/reference signed retry evidence --> Receipt / Refusal / ProofGap / terminal certificate evidence -``` - -The first node can be generalized from "engineering agent" to automated decision making. The rest of the flow must not change in this slice. - -## Compatibility And Migration Risks - -- Category rename risk: a broad text replacement of "agent" would corrupt protocol participant semantics, exported schema names, and tests. The migration must distinguish product-category text from existing participant/evidence object names. -- Demo-contract risk: `examples/x402-protected-spend/run.ts` currently emits buyer-readable report fields consumed by `test/product/x402-protected-spend-demo-report.test.ts`; changing labels without updating assertions will break the product gate. -- Scratch-canon risk: `.planning/codebase/CONCERNS.md` still recommends adding a spend reservation ledger before claiming aggregate spend enforcement. The current run should override that as eliminated scope, but only in the active macro plan; do not promote scratch maps as canon. -- Wedge inversion risk: making x402 the product category would create the same architecture error as engineering-agent-only language. The protocol must remain adapter-pack modular. -- Surface drift risk: updating MCP/CLI/SDK docs for category clarity can accidentally imply those surfaces authorize or protect work. Claim guards must keep non-authority flags explicit. -- External verification risk: no external x402, MCP Registry, npm, JWKS, Cloudflare, or legal/payment claims should be added in this slice. Any such claim must be blocked until separately verified. - -## Architecture Validation Gates - -- `npm run quality:claims` -- `npm run quality:architecture` -- `npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts` -- `npm run test -- test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts` -- `npm run format:check` -- Final implementation closeout should run `npm run check:repo` if the slice touches docs, tests, or demo report generation. - -## Assumptions - -- The user correction is authoritative for this plan: protected actions for automated decision making is the category; engineering agents are an adoption context. -- Tier 1 protocol objects and source authority boundaries are stable and should not be renamed in this slice. -- x402 remains the first wedge because the current source packet proves the strongest local/reference path there. -- Aggregate x402 payment-budget management is eliminated from current remit, not deferred as a required future ledger for the current wedge. -- The macro plan will be implemented later; this first pass must not change source beyond this assigned raw output. - -## Dependencies - -- Canon docs must be updated before claim guards can be made strict without producing confusing failures. -- Demo report string changes in `examples/x402-protected-spend/run.ts` and assertion changes in `test/product/x402-protected-spend-demo-report.test.ts` should land together. -- Claim-boundary guards should drive the cleanup so future docs cannot reintroduce engineering-agent-only category language or payment-management claims. -- Architecture and root export tests provide regression proof that the cleanup did not move authority across package/lane boundaries. - -## Risks - -- Over-generalization: "automated decision making" can become generic agent governance if not tied back to protected actions, exact contracts, and gateway checks. -- Under-correction: leaving README/AGENTS/decisions as engineering-agent-first will keep future plans scoped to the wrong market and adoption model. -- Payment-regulatory drift: replacing "spend reservation ledger" poorly can still imply Handshake manages budgets, wallets, or settlement. Use "aggregate payment-budget management intentionally out of current remit" where applicable. -- x402 monopoly drift: x402 proof language can overfit the protocol to payments. Keep "adapter/action pack" and "one protected action pack at a time" discipline visible. -- Evidence theatre: buyer-readable report labels like `x402_paid_http_call.exact` must stay report labels, not action-catalog or gateway-bound authority types unless future source implements them. - -## Cut Lines - -- Do not implement a spend ledger, wallet custody, settlement, facilitator, seller middleware, or hosted verifier in this slice. -- Do not rename exported protocol schemas or root package surfaces to remove "agent" terminology. -- Do not add new public package exports, package scripts, CI names, or source folders. -- Do not modify `src/protocol/**` behavior unless a test proves a claim guard cannot be expressed without a source-owned predicate. -- Do not use `.planning/` files as active repo truth beyond this macro-planning run. -- Do not browse or add external standards claims for x402, MCP Registry, npm, JWKS, Cloudflare, or legal/payment posture. - -## Blocked Checks - -- Could not verify actual current test results because this first-pass role is planning-only and must not run implementation gates. -- Could not inspect unlisted implementation files such as `src/adapters/x402-payment/action-proposal.ts`, `src/adapters/x402-payment/install-proposal.ts`, `src/runtime/ingress/index.ts`, `src/mcp/x402-proposal.ts`, `src/surfaces/boundary-manifest.ts`, or `package.json`; path recommendations come from the allowed source packet and codebase maps. -- Could not confirm whether `not_enforced_local_metadata` appears outside the allowed packet; implementation should search the full repo during the execution slice. -- Could not confirm generated example outputs under `examples/*/output/`; implementation should regenerate affected demos before final claim gates if report text changes. - -## Smallest Next Mechanism To Build - -Strengthen `test/architecture/claim-boundary.test.ts` first so the repo fails when canonical docs define Handshake as engineering-agent-only or imply aggregate payment-budget management, then update canon/docs/demo strings until that guard passes without touching Tier 1 behavior. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/EXECUTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/EXECUTION.md deleted file mode 100644 index 0c3e8f1..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/EXECUTION.md +++ /dev/null @@ -1,423 +0,0 @@ -# EXECUTION First Pass: Claim Boundary Cleanup - -## Invariant at stake - -The implementation plan must prevent broad product language from becoming fake authority. Handshake should read as protected actions for automated decision making, proven first through one x402 exact per-call protected action wedge, without changing Tier 1 protocol meaning or implying payment management, hosted operation, provider custody, settlement, broad runtime control, or engineering agents as the category boundary. - -## Execution posture - -- Planning only. No implementation was performed in this pass. -- Source boundary honored: this pass used the immutable input packet and the allowed source files named there. -- `.planning/` is derived scratch. It can guide the cleanup plan, but durable repo truth must land in `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, and `docs/internal/*`. -- Tier 1 protocol/kernel meaning should remain stable. The work is claim, documentation, report, and guard cleanup unless a failing claim guard requires a narrow source-output adjustment. - -## Recommended phase sequence - -### Phase 0: Claim inventory and exact target language - -Purpose: create the edit map before touching source. - -Tasks: - -- Inventory current category claims across `AGENTS.md`, `README.md`, `docs/internal/decisions.md`, `docs/internal/protocol-definition.md`, `docs/internal/protocol-kernel-architecture.md`, `docs/internal/protocol-layman.md`, `docs/internal/protocol-notes.md`, `examples/x402-protected-spend/README.md`, `examples/x402-protected-spend/run.ts`, `examples/self-hosted-activation/README.md`, and lane manifests. -- Classify each claim as one of: - - category claim: protected actions for automated decision making; - - first wedge claim: x402 exact per-call protected action; - - current adoption context: engineering-agent workflows/generated execution; - - local/reference evidence only; - - explicit non-claim/cut line. -- Identify every "engineering agents" phrase that currently defines the product rather than describing an adoption context. -- Identify every "spend reservation ledger" or ledger-required-before-claim phrase and decide whether it is: - - authority idempotency ledger language that remains valid; - - aggregate payment-budget management language that should be cut as intentionally out of current remit; - - local metadata language that may keep `not_enforced_local_metadata`. - -Owner: implementation lead. - -Closeout evidence: claim inventory in the implementation PR description or support note, not a new repo-facing canon file. - -### Phase 1: Test-first claim guards - -Purpose: make overclaim failures mechanical before rewriting docs. - -Tasks: - -- Strengthen `test/architecture/claim-boundary.test.ts` to require: - - category wording does not define Handshake as engineering-agent-only; - - canonical docs state protected actions for automated decision making; - - engineering-agent/generated-execution wording is adoption context or runtime evidence context; - - x402 is the first wedge/action pack, not the protocol definition; - - current x402 enforcement is exact per-call only; - - aggregate payment-budget management is intentionally out of current remit; - - docs/examples do not imply payment management, settlement, seller middleware, facilitator operation, hosted trust, provider custody, marketplace/certification, broad runtime control, broad x402 compatibility, or cross-org certificate trust. -- Strengthen `test/product/x402-protected-spend-demo-report.test.ts` to require: - - the buyer-readable report no longer lists "spend reservation ledger" as a missing proof object required before an aggregate spend claim; - - aggregate payment-budget management appears as a non-claim or out-of-remit boundary; - - `not_enforced_local_metadata` is only represented as local metadata, not a deferred promise; - - `x402_paid_http_call.exact` stays a buyer-readable label and not an action catalog authority type; - - x402 report language names automated decision/protected action context without erasing generated execution evidence. -- If the implementation inventory confirms active vocabulary tests scan these surfaces, update `test/architecture/active-vocabulary.test.ts` as a follow-up candidate. This file was not opened in this first-pass source boundary. - -Owner: test owner. - -Dependency: Phase 0 inventory. - -Closeout evidence: initial failing focused test slice, then green after source/doc cleanup. - -### Phase 2: Canonical category rewrite - -Purpose: align durable repo truth to the user correction without expanding authority. - -Tasks: - -- Update `AGENTS.md` category doctrine: - - from "contracted execution infrastructure for engineering agents"; - - to protected actions for automated decision making; - - keep generated engineering-agent execution as the current adoption context and threat model. -- Update `README.md` first screen and system design posture: - - describe this checkout as a TypeScript protocol kernel for protected action control; - - state x402 exact per-call protected action as the current first wedge; - - remove engineering-agent phrasing where it defines category; - - keep runtime/generated execution language where it describes evidence inputs. -- Update `docs/internal/decisions.md`: - - Product Kernel: category becomes protected actions for automated decision making; - - first credible wedge becomes x402 exact per-call protected actions; - - "engineering-agent actions" becomes adoption context / current workflow context; - - first bought product remains narrow only if framed as one automated decision workflow around one protected action, not category. -- Update `docs/internal/protocol-definition.md`, `docs/internal/protocol-kernel-architecture.md`, `docs/internal/protocol-layman.md`, and `docs/internal/protocol-notes.md` only where needed: - - preserve the primitive and authority rule; - - avoid changing protocol object semantics; - - shift use-case phrasing from "generated engineering-agent execution" to "automated decision/runtime generated execution" where it is category-defining; - - keep examples that are explicitly generated execution or coding-agent adoption examples. - -Owner: docs/canon owner. - -Dependencies: Phase 1 claim guard draft. - -Closeout evidence: claim-boundary tests prove the category language cannot regress. - -### Phase 3: x402 protected-action report cleanup - -Purpose: keep the first wedge strong while cutting payment-management implication. - -Tasks: - -- Update `examples/x402-protected-spend/README.md`: - - scope becomes one official buyer-side `x402_payment.exact` protected action attempt from automated/generated execution evidence; - - retain "generated engineering-agent" only as one demo context if needed; - - keep cut lines for no provider custody, no aggregate x402 spend windows, no facilitator/seller/settlement, no broad x402 compatibility. -- Update `examples/x402-protected-spend/run.ts` report fields: - - replace `missingProofObjects` entry `spend reservation ledger` with an out-of-remit/non-claim object such as `aggregate payment-budget management`; - - make `requiredBeforeClaim` stop implying a planned ledger is required for current claim cleanup; - - keep `spendWindowEnforcementStatus: "not_enforced_local_metadata"` only where it describes local metadata; - - keep idempotency wording as authority idempotency only, not payment settlement. -- Update `examples/self-hosted-activation/README.md` if needed: - - self-hosted packet remains local reference evidence; - - no hosted operation, provider/customer custody, cross-org trust, aggregate spend-window enforcement, clearing-house readiness, or broad host protection. - -Owner: example/product proof owner. - -Dependencies: Phase 1 product report assertions. - -Closeout evidence: `test/product/x402-protected-spend-demo-report.test.ts` and `npm run demo:aps` pass. - -### Phase 4: Lane and surface boundary alignment - -Purpose: keep package/lane manifests from reintroducing the old category or surface authority. - -Tasks: - -- Update `src/runtime/LANE.md`: - - runtime proposal evidence supports automated/generated execution; it does not define the category or issue authority. -- Update `src/mcp/LANE.md`, `src/cli/LANE.md`, and `src/sdk/LANE.md` only if current wording implies broad runtime/MCP/CLI control or category ownership. -- Update `src/adapters/LANE.md`: - - adapter proof lanes are protected-action packs; - - x402 is the first wedge/action pack; - - no adapter family defines the protocol. -- Update `src/conformance/LANE.md`: - - conformance verifies narrow adapter/protected-action posture, not certification or provider enforcement. - -Owner: source-boundary owner. - -Dependencies: Phase 2 and Phase 3 wording decisions. - -Closeout evidence: `test/architecture/import-posture.test.ts`, `test/architecture/root-exports.test.ts`, and `test/architecture/claim-boundary.test.ts` pass. - -### Phase 5: Scratch planning register cleanup - -Purpose: stop active planning scratch from teaching future agents the wrong boundary. - -Tasks: - -- Update `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md`: - - vision/category becomes protected actions for automated decision making; - - x402 exact per-call protected action remains first wedge; - - engineering-agent workflows become adoption context, not category; - - Step 0 cleanup says aggregate payment-budget management is intentionally outside current remit, not a missing spend ledger promise. -- Treat `.planning/codebase/CONCERNS.md` as derived scratch. If implementation touches it, revise the "Spend Window Metadata" fix approach from "add a spend reservation ledger before claiming aggregate spend" to "do not claim aggregate payment-budget management in the current remit; keep local metadata only." Do not promote this scratch text to canon. - -Owner: planning hygiene owner. - -Dependencies: Phase 2 canonical wording. - -Closeout evidence: active macro scratch no longer contradicts canon. - -### Phase 6: Validation and closeout - -Purpose: prove the cleanup did not alter authority behavior or package posture. - -Tasks: - -- Run focused claim gates first. -- Run architecture/import/export gates if lane manifests, exports, or package-facing wording changed. -- Run demo/report gate after example report changes. -- Run full repo gate before declaring the slice executable/closed. -- Record any blocked checks with exact command and reason. - -Owner: implementation lead. - -Dependencies: Phases 1-5. - -Closeout evidence: command outputs and no source behavior changes beyond claim/report surfaces unless explicitly justified by test failure. - -## Task graph - -```text -T0 claim_inventory - -> T1 architecture_claim_guard - -> T2 product_report_claim_guard - -T1 architecture_claim_guard - -> T3 canonical_category_rewrite - -> T5 lane_manifest_alignment - -T2 product_report_claim_guard - -> T4 x402_report_cleanup - -T3 canonical_category_rewrite - -> T6 scratch_register_cleanup - -> T8 validation_quality_claims - -T4 x402_report_cleanup - -> T8 validation_quality_claims - -> T9 validation_demo_aps - -T5 lane_manifest_alignment - -> T7 import_export_validation - -T6 scratch_register_cleanup - -> T8 validation_quality_claims - -T7 import_export_validation - -> T10 full_repo_gate - -T8 validation_quality_claims - -> T10 full_repo_gate - -T9 validation_demo_aps - -> T10 full_repo_gate -``` - -Task IDs: - -- T0: build claim inventory and target phrase table. -- T1: strengthen `test/architecture/claim-boundary.test.ts`. -- T2: strengthen `test/product/x402-protected-spend-demo-report.test.ts`. -- T3: rewrite canonical docs. -- T4: rewrite x402 report/example language and report fields. -- T5: align lane manifests. -- T6: align active scratch register. -- T7: run import/export architecture validation. -- T8: run focused claim validation. -- T9: run APS demo/report validation. -- T10: run full repo validation. - -## Dependency map - -| Work item | Depends on | Blocks | -| --- | --- | --- | -| Claim inventory | none | all rewrite tasks | -| Architecture claim guard | claim inventory | canonical docs, lane manifests, scratch cleanup | -| Product report claim guard | claim inventory | x402 report cleanup | -| Canonical category rewrite | architecture guard | scratch cleanup, quality claims | -| x402 report cleanup | product report guard | demo/report validation | -| Lane manifest alignment | architecture guard and canonical phrasing | import/export validation | -| Scratch register cleanup | canonical category rewrite | final closeout | -| Focused validation | docs/examples/tests complete | full repo gate | -| Full repo gate | focused gates green | execution readiness | - -## Critical path - -```text -claim inventory --> claim-boundary tests fail for old category/spend wording --> canonical docs rewrite --> x402 report cleanup --> active scratch register cleanup --> focused claim/product gates --> full repo gate -``` - -The critical path is claim-test-led because this slice is primarily about preventing future overclaims. Editing docs first without a failing guard risks reintroducing the same ambiguity. - -## What can run in parallel - -After T0: - -- T1 and T2 can run in parallel. - -After T1: - -- T3 canonical docs and T5 lane manifests can run in parallel if they share a phrase table. - -After T2: - -- T4 x402 report cleanup can run independently of canonical doc edits. - -After T3: - -- T6 scratch register cleanup can run in parallel with T4/T5 as long as it mirrors canonical wording and does not invent new claims. - -Validation can be staged in parallel only after relevant files settle: - -- `test/architecture/claim-boundary.test.ts` and `test/product/x402-protected-spend-demo-report.test.ts` can run as focused slices. -- Import/export checks can run separately if lane/package surfaces change. -- `npm run check:repo` should remain last. - -## First executable step - -Add failing claim guards before source rewrites: - -```bash -npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts -``` - -Expected initial failure targets: - -- Canonical docs still define Handshake as engineering-agent infrastructure in places. -- Product/demo report still treats `spend reservation ledger` as a missing proof object rather than treating aggregate payment-budget management as intentionally out of remit. - -## Source/test/doc candidate paths - -### Canonical docs - -- `AGENTS.md` -- `README.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-layman.md` -- `docs/internal/protocol-notes.md` - -### Examples and reports - -- `examples/x402-protected-spend/README.md` -- `examples/x402-protected-spend/run.ts` -- `examples/self-hosted-activation/README.md` - -### Architecture/product tests - -- `test/architecture/claim-boundary.test.ts` -- `test/product/x402-protected-spend-demo-report.test.ts` -- `test/architecture/import-posture.test.ts` -- `test/architecture/root-exports.test.ts` -- `test/architecture/active-vocabulary.test.ts` as a candidate if implementation inventory confirms it scans the relevant terms. It was not opened in this first-pass source boundary. - -### Lane manifests - -- `src/runtime/LANE.md` -- `src/mcp/LANE.md` -- `src/cli/LANE.md` -- `src/sdk/LANE.md` -- `src/adapters/LANE.md` -- `src/conformance/LANE.md` - -### Source candidates only if claim guards require output adjustment - -These were named by allowed codebase maps but not opened directly in this first pass: - -- `src/adapters/x402-payment/install-proposal.ts` -- `src/adapters/x402-payment/action-proposal.ts` -- `src/runtime/ingress/index.ts` -- `src/mcp/x402-proposal.ts` -- `src/surfaces/boundary-manifest.ts` - -Use these only for narrow metadata/output posture fixes. Do not change protocol semantics or add aggregate spend enforcement in this slice. - -### Planning scratch - -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` -- `.planning/codebase/CONCERNS.md` only if the implementation owner decides tracked scratch drift must be corrected. Do not treat it as canon. - -## Validation gates - -Focused gates: - -```bash -npm run quality:claims -npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts -npm run demo:aps -``` - -Architecture/package posture gates: - -```bash -npm run test -- test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts -npm run quality:architecture -``` - -Closeout gates: - -```bash -npm run format:check -npm run check:repo -``` - -If a source-output adjustment touches runtime/MCP/x402 proposal posture, add: - -```bash -npm run test -- test/runtime/runtime-ingress.test.ts test/mcp/mcp-x402-proposal.test.ts test/adapters/x402-payment-action-proposal.test.ts -``` - -## Cut lines - -- Do not change Tier 1 protocol object semantics, authority rule, gateway check semantics, greenlight consumption, idempotency behavior, or receipt/proof-gap semantics. -- Do not implement a spend reservation ledger. -- Do not describe aggregate payment-budget management as a pending near-term promise. -- Do not weaken the x402 exact per-call wedge. -- Do not make x402 the protocol definition. -- Do not make engineering agents the product category boundary. -- Do not add seller middleware, facilitator operation, settlement finality, balances, wallet custody, or payment-management claims. -- Do not add hosted operation, hosted dashboard claims, hosted verifier claims, JWKS/revocation claims, customer/provider custody claims, or cross-org trust claims. -- Do not add broad MCP/CLI/browser/shell/network/package-manager/runtime control claims. -- Do not expose CLI/MCP/runtime policy, greenlight, gateway, mutation, receipt-export, signer, or certificate-minting authority. -- Do not create new package exports, scripts, source directories, or public surfaces for this slice unless a claim guard proves the existing surface is misleading. -- Do not edit sibling raw outputs, normalized outputs, or final `PLAN.md` under this run. - -## Assumptions - -- The user correction is authoritative: Handshake category is protected actions for automated decision making. -- x402 exact per-call protected action is the first wedge for current implementation/product proof. -- Engineering-agent workflows remain important adoption context and threat model, but not the product boundary. -- Current Tier 1 protocol primitives already support the corrected category; the cleanup should not require schema or state-machine changes. -- `not_enforced_local_metadata` can remain when attached to local metadata and explicitly denied as enforcement. -- The current APS report can change wording/report fields without changing the protected action execution path. -- Validation command names are taken from allowed repo docs and codebase testing maps; package script definitions were not independently opened in this first pass. - -## Risks - -- Category over-broadening risk: "automated decision making" can sound like generic governance. Mitigation: always bind the category to protected actions and gateway-enforced consequence. -- Wedge collapse risk: making x402 the first wedge can accidentally make x402 the protocol. Mitigation: keep "adapter/action pack" language and repeat "No adapter family defines the protocol." -- Payment-management drift: ledger wording can make aggregate budgets look like an unfinished feature. Mitigation: move aggregate payment-budget management to explicit out-of-remit/non-claim language. -- Local metadata ambiguity: `not_enforced_local_metadata` can look like disabled enforcement. Mitigation: tests must require it to appear only as metadata and never as claim support. -- Test overfitting risk: exact string assertions can pass while nearby text overclaims. Mitigation: pair required phrases with forbidden regexes and scan all relevant docs/examples/lanes. -- Scratch drift risk: `.planning/codebase/CONCERNS.md` still says "add spend reservation ledger" as a fix approach. Mitigation: either update tracked scratch or record it as stale derived evidence in the final plan. -- Product proof drift: `x402_paid_http_call.exact` buyer-readable label can be mistaken for action catalog authority. Mitigation: product test must keep it explicitly non-authority until source action catalog, compiler, policy, and gateway expose it. -- Hidden implementation creep: touching `run.ts` may tempt changing x402 behavior. Mitigation: product report edits should not change gateway signing, policy, replay, receipt, or proof-gap behavior. - -## Blocked checks - -- Tests were not run in this first-pass planning role. -- External verification was not performed. The input says not to browse by default, and this slice should not add npm, MCP Registry, JWKS, Cloudflare, x402, legal, or payment-regulatory claims. -- Source files outside the allowed first-pass packet were not opened, including implementation internals named by codebase maps. Candidate source paths above need implementation-time verification before edits. -- Sibling raw outputs, normalized outputs, and the final `PLAN.md` for this run were not read. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/RISK.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/RISK.md deleted file mode 100644 index 51b416c..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/RISK.md +++ /dev/null @@ -1,417 +0,0 @@ -# RISK First Pass: Claim Boundary Cleanup - -## Invariant At Stake - -Claim cleanup must not silently change authority. The slice is safe only if it -narrows product language toward protected actions for automated decision making, -keeps x402 as the first protected-action wedge, preserves per-call exact -authorization, and refuses to create new claims about custody, settlement, -hosted operation, broad runtime control, or payment-budget management. - -## Scope Boundary - -This is a planning artifact for a future implementation slice. The future slice -should be docs, examples, and claim guards only unless the chair finds a -source-owned guard that must move with the wording. It must not alter Tier 1 -protocol semantics, gateway authority, policy evaluation, greenlight behavior, -receipt semantics, storage, x402 signing behavior, or adapter execution. - -Source packet evidence used: - -- `README.md` still opens with "contracted execution infrastructure for - engineering agents" and later frames the use case as generated - engineering-agent execution. -- `AGENTS.md` and `docs/internal/decisions.md` still describe the product - kernel or first credible domain in engineering-agent terms. -- `docs/internal/protocol-definition.md` gives the safer canonical primitive: - protected action control, exact action contract, policy decision, one-use - greenlight, gateway check, and receipt/refusal/proof gap. -- `docs/internal/protocol-kernel-architecture.md` and - `docs/internal/protocol-notes.md` already separate runtime evidence from - gateway enforcement and make x402 per-call only. -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` explicitly says aggregate - x402 spend-window enforcement should be eliminated from the near-term remit. -- `.planning/codebase/CONCERNS.md` still contains a derived "Fix approach" that - adds a spend reservation ledger before claiming aggregate spend enforcement; - that conflicts with the run input's correction and must be treated as scratch - risk evidence, not canon. - -## P0 Risk Register - -### P0.1 Category Boundary Remains Wrong - -Risk: If the cleanup leaves the top-level claim as "engineering agents", -Handshake remains scoped to one adoption context instead of the product category: -protected actions for automated decision making. That creates strategy and -architecture drift: future planners may make runtime/agent governance the -product boundary and treat non-engineering protected actions as out-of-scope. - -Mitigation: Update canonical product language in `README.md`, `AGENTS.md`, -`docs/internal/decisions.md`, `docs/internal/protocol-notes.md`, and any example -scope text to say protected actions for automated decision making. Keep -engineering agents only as a current adoption context or generated-execution -risk pattern. Preserve the primitive wording from -`docs/internal/protocol-definition.md`. - -Cut line: Stop the slice if a task claims Handshake provides generic automated -decision governance, generic agent safety, broad runtime control, or category -coverage beyond installed protected paths. - -Validation gate: Claim guard must fail if active canon says "Handshake is -contracted execution infrastructure for engineering agents" as the product -definition. It may allow phrases that explicitly mark engineering agents as a -current adoption context. - -### P0.2 x402 Becomes Payment Management - -Risk: Current sources contain both correct per-call x402 language and residue -that points toward a "spend reservation ledger" as a missing proof object. If -the cleanup keeps that phrasing, the repo still implies aggregate payment-budget -management is pending rather than intentionally outside the current remit. - -Mitigation: Replace "spend reservation ledger required before claim" style -phrasing with "aggregate payment-budget management intentionally out of current -remit". Keep `not_enforced_local_metadata` only where it labels local metadata, -not deferred enforcement. Keep the x402 wedge as one official buyer-side -`x402_payment.exact` per-call path. - -Cut line: No task may add a budget ledger, session/day/review enforcement, -spend reporting, balance tracking, settlement state, seller middleware, or -facilitator operation as part of claim cleanup. - -Validation gate: `test/architecture/claim-boundary.test.ts` and -`test/product/x402-protected-spend-demo-report.test.ts` should fail on -"spend reservation ledger" in active claim surfaces and should require the -intentional-out-of-remit wording where aggregate spend is discussed. - -### P0.3 Docs Create Authority Without Gateway Enforcement - -Risk: Claim cleanup can accidentally polish language into "safe", "trusted", -"controlled", or "protected" claims for paths where no customer-owned gateway -owns the mutation credential and checks the exact greenlight before mutation. -That is advisory, not Handshake. - -Mitigation: Every broadened product phrase must be paired with the installed -path rule: exact contract, one-use greenlight, customer-owned gateway check -before consequence, receipt/refusal/proof gap, and isolation/bypass evidence -where applicable. - -Cut line: Stop if a claim says Handshake protects a path without naming the -gateway enforcement boundary or if it treats runtime, MCP, CLI, SDK, review, -catalog, certificate, or receipt surfaces as authority. - -Validation gate: Claim tests must scan canonical docs and lane manifests for -hosted operation, provider custody, broad MCP/runtime/browser/shell/network -control, marketplace/certification, clearing-house readiness, and certificate -trust language unless paired with explicit non-claims. - -### P0.4 Claim Guards Are Too Narrow - -Risk: Existing `claim-boundary.test.ts` pins important README, x402 walkthrough, -runtime, adapter, conformance, and MCP language, but the source packet shows -category-risk language in `AGENTS.md`, `docs/internal/decisions.md`, -`docs/internal/protocol-notes.md`, and `examples/x402-protected-spend/run.ts`. -A prose cleanup without expanded guards will drift back. - -Mitigation: Expand guard coverage to active canon and generated report source: -`AGENTS.md`, `README.md`, `docs/internal/decisions.md`, -`docs/internal/protocol-definition.md`, -`docs/internal/protocol-kernel-architecture.md`, -`docs/internal/protocol-layman.md`, `docs/internal/protocol-notes.md`, -`examples/x402-protected-spend/README.md`, -`examples/x402-protected-spend/run.ts`, `examples/self-hosted-activation/README.md`, -and the lane manifests that carry public posture claims. - -Cut line: Do not close the future implementation slice if changed wording is -not guarded by tests. Unguarded prose cleanup is reversible but not durable. - -Validation gate: `npm run quality:claims` plus the focused claim/product test -slice must fail on the old category boundary, payment-management implication, -and broad x402/runtime/hosted/custody claims. - -## P1 Risk Register - -### P1.1 x402 First Wedge Turns Into Protocol Definition - -Risk: The user correction says x402 is the first wedge, not the protocol. If -the plan overcorrects from "engineering agents" into "x402 protected spend", -Handshake becomes a payment protocol instead of a protected-action authority -spine. - -Mitigation: Say the protocol category is protected actions for automated -decision making. Say x402 is the first protected-action pack because it exercises -exact per-call authorization, gateway signer custody, replay refusal, redacted -evidence, and proof gaps. Keep "No adapter family defines the protocol." - -Cut line: Stop if `x402_payment.exact` is described as the general action model, -the protocol definition, broad x402 compatibility, or a settlement/payment -product. - -Validation gate: Claim tests should require "No adapter family defines the -protocol" or equivalent language near first-wedge status. - -### P1.2 Customer-Owned Gateway Custody Gets Cut Too Far - -Risk: Removing provider/customer custody claims can accidentally remove the -future enforcement model. The source needs to say customer-owned gateway custody -is the intended enforcement posture without claiming it is already proven. - -Mitigation: Use three states consistently: local/reference gateway fixture is -proven now; customer-owned gateway custody is future required enforcement model; -Handshake-held payment custody is out of remit. - -Cut line: Do not claim provider/customer custody is landed. Do not remove -customer-owned gateway custody from the future enforcement architecture. - -Validation gate: Canonical docs must include both a current non-claim -("not provider/customer custody") and a future boundary ("customer-owned gateway -custody before live custody claims"). - -### P1.3 Local Sandbox Evidence Gets Read As Seller Or Facilitator Operation - -Risk: The x402 walkthrough and report include local/reference 402 challenge and -signed retry evidence. A buyer can misread that as seller middleware, -facilitator operation, settlement finality, or live provider operation. - -Mitigation: Keep the sandbox labeled as local/reference downstream fixture -evidence. Keep `authorityCreated: false` before policy. Keep signed retry as -post-gateway observation, not authority or settlement. - -Cut line: No claim may say seller middleware, facilitator operation, settlement -finality, payment finality, live provider operation, or merchant fulfillment -unless a future adapter and external verification exist. - -Validation gate: Product report tests should continue checking -`settlementFinalityClaimed: false`, `facilitatorOperationClaimed: false`, -`sellerMiddlewareClaimed: false`, `providerCustodyClaimed: false`, and local -sandbox posture. - -### P1.4 Runtime/MCP/CLI Surfaces Launder Authority - -Risk: Changing category language toward automated decision making can make MCP, -CLI, runtime, SDK, or review surfaces sound like generalized control planes. The -allowed sources repeatedly state these are proposal/evidence/read surfaces only. - -Mitigation: Keep each surface's role explicit: runtime proposes, MCP proposes -and displays evidence, CLI renders local evidence, SDK sends requests and parses -responses. None evaluates policy, creates greenlights, performs gateway checks, -mutates, exports raw receipts, mints authority certificates, or holds signer -material. - -Cut line: No new public route, package subpath, CLI command, MCP tool, or SDK -client should be planned for this slice. Any such work is capability expansion, -not claim cleanup. - -Validation gate: Existing import/root export/surface posture tests should remain -green, and claim guards should fail if these surfaces are described as -authority, execution, custody, or broad host protection. - -### P1.5 Redaction And Privacy Claims Overreach - -Risk: Docs can imply privacy-grade redaction or hosted audit readiness while the -source only proves redacted local projections and known pattern coverage. The -codebase concerns note that unknown provider credential formats need fuzzing -before live provider claims. - -Mitigation: Say redacted evidence projections are local/source-owned and -diagnostic. Avoid privacy, compliance, audit-search, retention, hosted reader -authorization, or provider secret lifecycle claims. - -Cut line: Stop if the plan claims SOC/compliance readiness, hosted audit search, -production privacy posture, retention policy, or provider-grade secret lifecycle -proof. - -Validation gate: Claim tests should forbid raw credential terms in examples and -ensure redacted evidence is not described as hosted compliance evidence. - -### P1.6 External x402 Facts Drift - -Risk: The example source names x402 docs and package versions. This planning -slice is not supposed to browse. If the future implementation changes x402 -compatibility, legal/payment-regulatory language, package version claims, or -facilitator semantics without external verification, it can create false claims. - -Mitigation: Treat external x402 references as existing source basis only. Do not -change external compatibility claims or regulatory/payment language except to -narrow them. Require external verification for any positive new external claim. - -Cut line: No new npm, MCP Registry, JWKS, Cloudflare, x402 compatibility, -payment-regulatory, settlement, facilitator, or custody claim in this slice. - -Validation gate: Chair plan should mark external verification as blocked/out of -scope unless a later implementation explicitly requests it. - -## P2 Risk Register - -### P2.1 Tests Overfit Exact Prose - -Risk: Current claim tests rely on exact phrases. Strengthening guards only with -more literal strings can make future truthful wording changes painful and can -encourage cargo-cult phrasing. - -Mitigation: Use a mix of required semantic phrases and forbidden regex patterns. -Pin high-risk exact phrases only where they are contractual, such as -`not_enforced_local_metadata`, `x402_payment.exact`, `maxUses: 1`, and -"proposal/evidence only". - -Cut line: Do not make tests require every sentence of product copy. - -Validation gate: Tests should fail on old overclaims and forbidden broadened -claims while allowing equivalent narrower wording. - -### P2.2 `.planning/` Scratch Becomes Canon Again - -Risk: The input packet intentionally reads `.planning` files, but repo canon says -`.planning/` is scratch. Derived maps include stale or conflicting improvement -paths. Future agents may reload those maps and override cleaned canon. - -Mitigation: The chair plan should explicitly classify `.planning` inputs as run -evidence and risk context, not source of repo truth. Any durable claim must land -in canonical docs and tests. - -Cut line: Do not promote `.planning/codebase/*` wording into repo-facing docs -without revalidating against active source and tests. - -Validation gate: Support docs should record this assumption, and future -implementation should not reference `.planning` paths from README, source, tests, -scripts, package exports, or CI names. - -### P2.3 Example Report Label Remains Ambiguous - -Risk: `x402_paid_http_call.exact` is a buyer-readable report proof-object label, -while the actual action class is `x402_payment.exact`. Without guard language, -readers can treat the label as an action catalog type or gateway authority class. - -Mitigation: Keep the label explicitly buyer-readable and non-authority until an -action catalog, compiler, policy, and gateway expose that exact action class. - -Cut line: Do not add `x402_paid_http_call.exact` as source action class or -public protocol type in this slice. - -Validation gate: Product report or claim-boundary tests should assert the label -is non-authority language and the protected action remains `x402_payment.exact`. - -### P2.4 Rollback Is Easy But Not Named - -Risk: Claim cleanup is mostly reversible docs/tests work, but without explicit -stop conditions a future implementation can keep pushing after tests reveal -category conflicts. - -Mitigation: Make rollback mechanical: revert docs/examples/test guard changes -from the slice; no migrations, package API changes, data rewrites, or generated -dist dependency should be necessary. - -Cut line: If the future slice needs a migration, route change, storage change, -new package export, or gateway behavior change to make the claims true, stop and -open a separate capability plan. - -Validation gate: Closeout diff should contain only canonical docs, examples, -claim tests, and possibly source-owned guard scripts. No protocol behavior diff. - -## Validation Gates - -Required future closeout gates: - -1. `npm run quality:claims` -2. `npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts` -3. `npm run quality:architecture` -4. `npm run format:check` -5. `npm run check:repo` - -Additional focused checks the chair should consider: - -- A grep-style guard that fails on product-definition uses of "engineering - agents" outside explicit adoption-context language. -- A guard that fails on "spend reservation ledger" in active claim surfaces. -- A guard that fails on "x402 compatible", "payment management", "settlement", - "seller middleware", "facilitator operation", "hosted trust", - "cross-org certificate trust", "marketplace", "certification", - "clearing-house", and broad MCP/runtime/browser/shell/network/package-manager - control claims unless explicitly listed as non-claims. -- Regenerate or execute the APS report path only if the implementation changes - `examples/x402-protected-spend/run.ts`; then verify the report still has local - non-claims and no raw credential material. - -## Rollback And Stop Conditions - -Rollback plan: - -- Revert the docs/example/test changes from the claim cleanup slice. -- Do not run migrations. -- Do not change package exports or public APIs. -- Do not change x402 gateway behavior, signer custody, policy, greenlight, - receipt, storage, or adapter semantics. - -Stop conditions: - -- Any task requires changing Tier 1 protocol meaning. -- Any task adds aggregate spend enforcement, budget reservation, payment - management, settlement, balances, seller/facilitator operation, or hosted - payment custody. -- Any task changes gateway, policy, greenlight, receipt, storage, or x402 signing - behavior to make wording true. -- Any task claims broad runtime/MCP/CLI/browser/shell/network/package-manager - protection without a host-specific bypass harness. -- Any task requires external legal/payment-regulatory/x402/JWKS/npm/MCP Registry - claims without external verification. -- Any claim change is not backed by a source-owned guard. - -## Assumptions - -- The input packet correction is authoritative for this run: Handshake is - protected actions for automated decision making; engineering agents are an - adoption context; x402 is the first wedge. -- Tier 1 protocol/kernel semantics are stable and must not be changed by this - plan. -- x402 remains exact per-call buyer-side authorization only in the current - wedge. -- `not_enforced_local_metadata` may remain only as local metadata and must not - imply planned budget enforcement. -- Customer-owned gateway custody remains the future enforcement model, but it is - not currently proven by the local x402 walkthrough. -- `.planning/` files are scratch coordination. They can reveal drift, but they - do not override canonical docs and tests. - -## Dependencies - -- Canonical docs: `AGENTS.md`, `README.md`, `docs/internal/decisions.md`, - `docs/internal/protocol-definition.md`, - `docs/internal/protocol-kernel-architecture.md`, - `docs/internal/protocol-layman.md`, `docs/internal/protocol-notes.md`. -- Claim tests: `test/architecture/claim-boundary.test.ts`, - `test/product/x402-protected-spend-demo-report.test.ts`, and any existing - active-vocabulary guard if the chair includes it. -- Lane manifests: `src/runtime/LANE.md`, `src/mcp/LANE.md`, `src/cli/LANE.md`, - `src/sdk/LANE.md`, `src/adapters/LANE.md`, `src/conformance/LANE.md`. -- Example claim surfaces: `examples/x402-protected-spend/README.md`, - `examples/x402-protected-spend/run.ts`, - `examples/self-hosted-activation/README.md`. -- Existing command contract: `npm run quality:claims`, focused Bun tests, - `npm run quality:architecture`, `npm run format:check`, and - `npm run check:repo`. - -## Antipatterns To Reject - -- Clean proof surface -> first market. -- x402 wedge -> x402 defines Handshake. -- Engineering-agent adoption context -> product category. -- Local/reference fixture -> provider/customer custody. -- Per-call authorization -> aggregate payment-budget management. -- Signed retry evidence -> settlement finality. -- Terminal certificate -> permission, identity, certification, or cross-org - trust. -- MCP/CLI/runtime/SDK proposal or evidence surface -> authority surface. -- Receipt -> downstream business success. -- Claim cleanup -> behavior change. -- `.planning` register -> canonical source truth. - -## Blocked Checks - -- Did not run tests; first-pass planner was asked to read and plan only. -- Did not browse external x402, npm, MCP Registry, JWKS, Cloudflare, or - legal/payment-regulatory sources; the input packet said not to browse by - default and this slice should not make new external claims. -- Did not read source files outside the immutable input packet and the allowed - file list named inside it. -- Did not inspect sibling raw outputs, normalized outputs, or the final plan for - this run. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/STRATEGY.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/STRATEGY.md deleted file mode 100644 index e3a7938..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/raw/STRATEGY.md +++ /dev/null @@ -1,121 +0,0 @@ -# STRATEGY First Pass: Claim Boundary Cleanup - -## Invariant at stake - -Handshake must not let a first wedge, adoption context, demo report, or missing proof object become a product claim. The current strategic invariant is: Handshake is protected actions for automated decision making; x402 exact per-call authorization is the first wedge; engineering agents are one adoption context. - -## Findings - -- The source packet still contains legacy category language. `AGENTS.md`, `README.md`, `docs/internal/decisions.md`, and `docs/internal/protocol-notes.md` describe Handshake as contracted execution infrastructure for engineering agents or generated engineering-agent execution. That is too narrow after the user correction. -- The protocol primitive is already broader than engineering agents. `docs/internal/protocol-definition.md` defines a protocol kernel for protected action control and describes exact `ActionContract`, `PolicyDecision`, one-use `Greenlight`, pre-mutation `GatewayCheck`, and terminal `Receipt` / `Refusal` / `ProofGap` evidence. That is the stable Tier 1 anchor. -- x402 is already the best first wedge in the current source packet. `README.md`, `examples/x402-protected-spend/README.md`, and `test/product/x402-protected-spend-demo-report.test.ts` show one buyer-side `x402_payment.exact` per-call path with gateway-held signing after verified gate, replay refusal, redacted evidence, and local/reference non-claims. -- The strategic risk is not that x402 is too narrow. The risk is that x402 becomes the protocol definition, payment management, settlement, broad x402 compatibility, or a clearing-house claim. -- Existing claim guards are meaningful but incomplete for the corrected category. `test/architecture/claim-boundary.test.ts` guards public entrypoint boundaries, local runtime ingress language, MCP proposal/evidence posture, and several x402 non-claims. It does not yet force the category rewrite away from engineering-agent-only language. -- The "spend reservation ledger" phrase is strategically wrong if treated as a missing requirement before product truth. Aggregate payment-budget management should be marked intentionally out of current remit. Per-call x402 exact authorization must remain in scope. -- `not_enforced_local_metadata` appears in the x402 demo source as spend-window status. That can stay only if the surrounding report treats session/day/review spend windows as local metadata and not as a deferred enforcement promise. -- Package install, repo write, and preview deploy are useful protocol regression/reference lanes, not wedge replacements for this cleanup. Treating package install as the first wedge would reintroduce the old engineering-agent category bias. - -## Recommended macro shape - -1. Re-anchor category language. - - Rewrite canonical product statements from "engineering agents" to "protected actions for automated decision making" where they define Handshake. - - Keep engineering agents as a current adoption context, generated-execution stress case, or local proof lane. - - Do not change Tier 1 protocol object meaning. - -2. Re-state x402 as first protected-action pack. - - Preserve `x402_payment.exact` as one official buyer-side per-call path. - - Keep package install as regression/parity, not first wedge. - - Preserve "No adapter family defines the protocol." - -3. Convert eliminated items into explicit non-goals. - - Replace "spend reservation ledger required before claim" posture with "aggregate payment-budget management intentionally out of current remit." - - Keep settlement, seller middleware, facilitator operation, broad x402 compatibility, payment custody, clearing-house readiness, marketplace/certification, hosted trust, and broad runtime control as cut lines. - -4. Strengthen claim guards. - - Extend `test/architecture/claim-boundary.test.ts` and `test/product/x402-protected-spend-demo-report.test.ts` so the corrected category and x402 non-claims fail if they drift. - - Add explicit forbidden patterns for engineering-agent-only category language in canonical product definitions while allowing bounded adoption-context references. - -5. Close with source-owned verification only. - - Required future gates: `npm run quality:claims`, targeted claim-boundary and x402 report tests, and then broader repo gate if the implementation touches canonical docs or demo output. - - No external verification is needed unless the implementation adds new x402, payment-regulatory, JWKS, MCP Registry, npm, Cloudflare, or legal claims. - -## What to cut - -- Cut engineering agents as the product category. -- Cut "agent auth", "generic agent governance", "runtime control", "hosted observability", and "dashboard over logs" framing. -- Cut any implication that x402 exact per-call proof means aggregate payment-budget management. -- Cut `spend reservation ledger` as a required missing proof object for the current wedge; replace it with an intentional out-of-remit boundary. -- Cut payment management, settlement finality, Handshake-held wallets, seller middleware, facilitator operation, signed-offer flows, batch settlement, `upto` authorization, and clearing-house readiness. -- Cut broad x402 compatibility. The current wedge is official buyer-side `exact` only. -- Cut hosted operation, live provider/customer custody, cross-org certificate trust, live JWKS/revocation, marketplace certification, and provider custody claims from this slice. -- Cut broad MCP/CLI/browser/shell/network/package-manager protection claims. MCP and CLI remain proposal/evidence surfaces. -- Cut any plan that adds capability before the claim boundary is cleaned. - -## What must be decided before execution - -- Exact canonical category phrase: use the user's phrase, "protected actions for automated decision making," unless the chair records a stronger source-backed wording. -- Whether `AGENTS.md` doctrine is in scope for the implementation slice. Strategically it should be, because it currently defines the old category. -- Allowed references to engineering agents: they should remain only as adoption context, generated-execution stress case, or current local proof context. -- Whether the demo report should remove `spend reservation ledger` entirely from `missingProofObjects` or move it to an explicit `outOfRemit` / `nonClaims` field. The strategic preference is explicit out-of-remit, not hidden deletion. -- Whether "APS" remains a buyer-readable label for the x402 report. If kept, it must resolve to x402 exact protected spend and not imply a broader payment product. - -## Six-month regret scenario - -Six months from now, the damaging failure is that the repo reads cleaner but still sells the wrong thing. Buyers see "engineering agents" and treat Handshake as a coding-agent niche. x402 readers see `spend reservation ledger` and assume payment-budget management is on the roadmap. Internal builders then implement hosted dashboards, verifier routes, or package-manager lanes to satisfy implied claims instead of hardening one customer-owned gateway path. The protocol survives in code but the product category drifts into advisory governance and payment theatre. - -## Smallest strategically valid first move - -Patch the canonical claim boundary, not the product surface: update the canonical docs and claim tests so the source must say "protected actions for automated decision making," must say x402 exact per-call authorization is the first wedge, and must fail if it implies aggregate spend management, hosted trust, broad runtime control, or engineering-agent-only category scope. - -## Assumptions - -- Tier 1 protocol meaning is stable and must not be redefined in this macro plan. -- x402 remains the first wedge unless an execution planner finds a source-level blocker. -- The implementation slice is allowed to edit the listed canonical docs, examples, and tests. -- `.planning/` remains scratch; only promoted plan outputs under the active macro directory are durable for this run. -- Existing x402 local/reference proof is sufficient for claim cleanup; external x402 verification is not part of this slice. - -## Dependencies - -- Canonical docs: `AGENTS.md`, `README.md`, `docs/internal/decisions.md`, `docs/internal/protocol-definition.md`, `docs/internal/protocol-kernel-architecture.md`, `docs/internal/protocol-layman.md`, `docs/internal/protocol-notes.md`. -- Claim guard tests: `test/architecture/claim-boundary.test.ts`, `test/product/x402-protected-spend-demo-report.test.ts`. -- Demo source/report wording: `examples/x402-protected-spend/README.md`, `examples/x402-protected-spend/run.ts`, `examples/self-hosted-activation/README.md`. -- Lane manifests that preserve non-authority posture: `src/runtime/LANE.md`, `src/mcp/LANE.md`, `src/cli/LANE.md`, `src/sdk/LANE.md`, `src/adapters/LANE.md`, `src/conformance/LANE.md`. -- Closeout commands named by the input: `npm run quality:claims` and targeted claim/x402 tests. - -## Risks - -- Overcorrection risk: replacing every "engineering agent" phrase would erase the useful current adoption context and generated-code threat model. -- Wedge collapse risk: making x402 the category would turn Handshake into payment infrastructure. -- Scope creep risk: adding hosted, custody, verifier, marketplace, or registry work would violate the claim-cleanup purpose. -- Test theatre risk: banning words without requiring positive category language could produce sterile docs that still fail to explain the product. -- Demo-report drift risk: `missingProofObjects` can imply "pending promise" even when the intended boundary is "not our remit." -- Adoption confusion risk: if engineering-agent examples disappear entirely, the first buyer path loses the concrete stress case that explains why protected actions are needed. - -## Validation gates - -- Positive category gate: canonical product definitions contain protected actions for automated decision making or equivalent chair-approved wording. -- Bounded adoption-context gate: engineering agents appear only as adoption context, generated-execution stress case, or current proof lane, not as the product boundary. -- x402 wedge gate: docs/examples keep one official buyer-side `x402_payment.exact` per-call path as first wedge and reject broad x402 compatibility. -- Non-goal gate: docs/examples/tests reject payment management, aggregate spend enforcement, settlement, seller/facilitator operation, Handshake-held custody, marketplace/certification, clearing-house readiness, hosted trust, and broad runtime control. -- Metadata gate: `not_enforced_local_metadata` remains only where clearly local metadata, not a deferred enforcement claim. -- Authority spine gate: exact contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap, and terminal evidence distinctions stay unchanged. -- Closeout gate: future executor runs `npm run quality:claims` and `npm run test -- test/architecture/claim-boundary.test.ts test/product/x402-protected-spend-demo-report.test.ts`. - -## Cut lines - -- No new protocol primitives. -- No new hosted surfaces. -- No new payment, settlement, seller, facilitator, or ledger implementation. -- No new MCP/CLI mutation capability. -- No package publication, registry publication, JWKS, revocation, or Cloudflare deployment work. -- No external legal/payment-regulatory claims. -- No new adapter pack beyond preserving x402 exact and existing regression/reference lanes. -- No claim that local/reference proof equals live provider/customer custody. - -## Blocked checks - -- Did not run tests or commands; this first-pass role is planning-only and wrote only the assigned raw strategy artifact. -- Did not browse or externally verify x402, npm, MCP Registry, JWKS, Cloudflare, or payment/legal claims; external verification is out of scope unless future execution adds such claims. -- Did not inspect sibling raw outputs, normalized outputs, or the final `PLAN.md`. -- Did not read source files outside the immutable packet's allowed source list. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/synthesis.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/synthesis.md deleted file mode 100644 index f9e8fc5..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/synthesis.md +++ /dev/null @@ -1,96 +0,0 @@ -# Chair Synthesis - -## Invariant At Stake - -Claim cleanup must not silently create authority. The repo must say protected actions for automated decision making, preserve exact contract -> policy -> one-use greenlight -> gateway check -> receipt/refusal/proof gap, and keep x402 as the first buyer-side exact per-call protected-action wedge. - -## Inputs Read - -- Immutable input packet for `claim-boundary-cleanup-20260524T065926Z`. -- Raw perspective outputs: Strategy, Architecture, Execution, Risk, Adoption. -- Macro plan contract. -- Selected allowed source files to verify current claim/test surfaces. -- Lightweight memory lookup for prior repo-specific x402/Tier discipline. - -No archive macro runs, sibling normalized outputs, or external sources were read. - -## Synthesis - -The perspectives converged on one sequence: - -1. Inventory claims and produce a phrase table. -2. Add or strengthen failing claim guards. -3. Rewrite canonical category language. -4. Clean x402 report and walkthrough wording. -5. Align lane manifests only where they drift. -6. Clean active scratch drift. -7. Run focused claim gates and full repo gate. - -The plan is test-led because prose cleanup alone would be reversible. The durable mechanism is a small, named claim-boundary guard surface covering canonical docs, x402 examples/report output, and lane manifests. - -## Conflicts Resolved - -### Engineering Agents - -Decision: engineering agents are not the product category. They remain as adoption context, generated-execution threat model, and current local proof context. - -Reason: the protocol primitive already supports protected action control, and the user correction is explicit. - -### x402 - -Decision: x402 is the first official buyer-side exact per-call protected-action wedge, not the protocol definition. - -Reason: the source packet proves the x402 path as the strongest current wedge, but broad payment, compatibility, settlement, seller/facilitator, hosted, and marketplace claims are out of scope. - -### Spend Reservation Ledger - -Decision: product-scope spend-ledger-required language should be replaced with aggregate payment-budget management intentionally out of current remit. - -Reason: treating the ledger as missing proof makes payment-budget management look like a pending promise. The current claim is exact per-call authorization only. - -### `.planning` Evidence - -Decision: active `.planning` files can be cleaned as scratch drift but must not become canon. - -Reason: README and decisions docs define `.planning/` as scratch. Durable claims must land in canonical docs and tests. - -### Claim Guards - -Decision: strengthen existing guard surfaces rather than build a new broad vocabulary subsystem. - -Reason: the slice should avoid god files, regex sprawl, pass-through abstractions, and capability expansion. A fixed surface map with grouped assertions is enough for this cleanup. - -## Architecture And Control Flow Preserved - -```text -automated decision / generated execution evidence --> runtime or MCP proposal/evidence surface --> intent compilation --> CandidateAction --> ActionContract --> PolicyDecision --> one-use Greenlight --> GatewayCheck before mutation --> x402 wallet gateway signer use after VerifiedGatewayCheck --> Receipt / Refusal / ProofGap / terminal local evidence -``` - -Only the first node is generalized from engineering-agent-only language to automated decision making. The authority path remains unchanged. - -## Blocked Checks - -- No tests were run; this chair task was planning-only. -- No `npm run quality:claims`, focused tests, demo, or `check:repo` gate was executed. -- No external x402, npm, MCP Registry, JWKS, Cloudflare, legal, or payment-regulatory verification was performed. -- No source implementation files outside the allowed packet were opened. - -## Output Files Written - -- `.planning/macro/active/claim-boundary-cleanup/PLAN.md` -- `.planning/macro/active/claim-boundary-cleanup/CONTEXT.md` -- `.planning/macro/active/claim-boundary-cleanup/ASSUMPTIONS.md` -- `.planning/macro/active/claim-boundary-cleanup/DECISIONS.md` -- `.planning/macro/active/claim-boundary-cleanup/RISKS.md` -- `.planning/macro/active/claim-boundary-cleanup/VALIDATION.md` -- `.planning/macro/active/claim-boundary-cleanup/TASKS.jsonl` -- `.planning/macro/active/claim-boundary-cleanup/runs/claim-boundary-cleanup-20260524T065926Z/synthesis.md` diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/ASSUMPTIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/ASSUMPTIONS.md deleted file mode 100644 index 3a8d5c0..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/ASSUMPTIONS.md +++ /dev/null @@ -1,39 +0,0 @@ -# Assumptions - -## Product Assumptions - -- Handshake is protected actions for automated decision making, not engineering-agent-only. -- x402 exact per-call protected action is the first wedge, not the protocol center. -- Package-manager material attestation is the right first adapter expansion because it preserves exactness while moving beyond payment-centered interpretation. -- The buyer-readable value is gating automated dependency actions on exact material evidence, policy, and gateway-bound authority. -- The product must not claim package safety, npm audit replacement, Bun provenance verification, broad supply-chain security, hosted operation, payment management, or broad runtime/MCP/CLI enforcement. - -## Source Assumptions - -- `ProtectedActionAdapterPackSchema` exists and is the right basis for the adapter manifest activation boundary. -- The schema already includes pack id/version, action family, protected surface, parameter schema ref, endpoint evidence schema ref, install compiler ref, policy rule pack ref, gateway observed parameter validator ref, receipt evidence mapper ref, bypass probe kinds, and hostile fixture refs. -- A generic install proposal exists and can be made package-install-specific without broadening authority. -- Package install runtime compiler and gateway tests exist. -- Preview deploy runtime/gateway lanes exist but should remain second. -- Repo write runtime/gateway lanes exist but should remain third. -- Runtime ingress contains cross-family hardcoding risk and must not become a god registry. -- CLI and MCP are proposal/evidence/read-only surfaces. - -## External Assumptions - -- npm provenance and signatures can verify source/build/publisher posture and registry/tarball integrity. -- `npm audit signatures` verifies registry signatures and provenance attestations after `npm install` when used with a supported npm CLI. -- Trusted publishing and provenance depend on external package account, repository, and workflow configuration. -- npm provenance/signature evidence does not prove package code is benign. -- Bun lockfile evidence is local material/reconstruction evidence, not npm provenance verification. - -## Security Assumptions - -- Lifecycle scripts are consequential code execution. -- Lifecycle scripts must default blocked unless separately contracted. -- Raw sibling package-manager invocation is a bypass condition. -- Missing material evidence must be recorded as a proof gap. -- A buyer report is not enforcement. -- Runtime trace is not an action contract. -- Proposal is not permission. -- Evidence preview is not gateway acceptance. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/CONTEXT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/CONTEXT.md deleted file mode 100644 index b653f6b..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/CONTEXT.md +++ /dev/null @@ -1,34 +0,0 @@ -# Context - -Handshake is protected actions for automated decision making. The next macro item is concrete adapter pack expansion. - -The expansion must not collapse into an engineering-agent-only narrative, payment management, hosted operations, or broad runtime enforcement. x402 remains the first exact per-call protected action wedge, but it is not the protocol center. - -The promoted first adapter pack is package-manager material attestation/package-install. This pack is the best first expansion because it breaks payment-centered interpretation while staying exact: one automated dependency action, one proposed contract, one policy decision, one gateway-bound mutation attempt, one reconstructable receipt. - -The key architectural constraint is that the adapter pack manifest is the activation boundary. Runtime ingress may select compilers, but must not authorize. CLI and MCP may expose proposal, inventory, evidence, and read-only surfaces, but must not be treated as enforcement. - -The package-install pack must prove that the Tier 1 spine generalizes: - -- exact protected action contract; -- atomic policy decision; -- one-use greenlight; -- gateway observed-parameter validation; -- material evidence mapping; -- hostile fixtures; -- bypass posture; -- receipt/refusal/proof-gap reconstruction. - -The product claim is narrow: - -Handshake gates automated dependency actions on exact material evidence, policy, and gateway-bound authority. - -The forbidden claim is broad supply-chain safety. npm provenance/signatures can help verify source/build/publisher posture and registry/tarball integrity. They do not prove package code is benign. Bun lockfile evidence supports local reconstruction and drift detection, not npm provenance verification. - -Expansion order: - -1. package-manager material attestation/package-install; -2. preview deploy; -3. repo write. - -Smallest next mechanism: package-install conformance for one npm install attempt. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/DECISIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/DECISIONS.md deleted file mode 100644 index 4855b12..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/DECISIONS.md +++ /dev/null @@ -1,71 +0,0 @@ -# Decisions - -## D1: Promote Package-Manager Material Attestation First - -Package-manager material attestation/package-install is the first concrete adapter pack expansion. - -Reason: it breaks the payment-centered narrative while keeping the protected action exact, observable, and gateway-bound. - -## D2: Keep x402 As Wedge, Not Center - -x402 remains the first exact per-call protected action wedge. It must not become the center of the protocol or the explanation of all protected actions. - -Reason: Handshake is the control layer for protected actions in automated decision making, not a payment-management system. - -## D3: Expansion Order - -Adapter pack expansion order is: - -1. package install; -2. preview deploy; -3. repo write. - -Reason: package install has enough existing compiler/gateway surface to prove the adapter spine without immediately inheriting deploy or repo-write scope. - -## D4: Manifest Contract Is Activation Boundary - -The adapter pack manifest is the activation boundary. - -Reason: a pack is promotable only when its schemas, compiler, policy rule pack, gateway validator, receipt mapper, bypass probes, and hostile fixtures are declared together. - -## D5: Runtime Ingress Selects, It Does Not Authorize - -Runtime ingress may route to compilers by action family. It must not become the authority holder. - -Reason: authorization belongs to exact contract policy and gateway-bound greenlight enforcement. - -## D6: Use Small Typed Registries - -Use small typed registries for compilers, policy packs, gateway validators, receipt mappers, bypass probes, and hostile fixtures. Do not create one god registry. - -Reason: one central registry invites cross-family shortcut authority and ambient coupling. - -## D7: Gateway Validator Enforces Exact Binding - -The package-install gateway observed-parameter validator is the pre-consequence enforcement point. - -Reason: policy decision without gateway enforcement is advisory, not Handshake. - -## D8: Receipts Record Evidence And Proof Gaps - -The receipt mapper records material evidence, gateway check, execution result, reconstruction material, and proof gaps. - -Reason: missing evidence must survive as missing evidence. It must not be converted into confidence language. - -## D9: Lifecycle Scripts Default Blocked - -Lifecycle scripts are blocked by default unless separately contracted. - -Reason: install scripts are consequential code execution and cannot hide under package-install authority. - -## D10: Bypass Posture Blocks Promotion - -Raw sibling bypass must be detected, isolated, or treated as a stop condition. - -Reason: if generated code can call an unwrapped consequential package-manager tool, the generated code escaped the contract boundary. - -## D11: Reports Must Bind To Exact Contract - -Buyer-readable reports must reference exact contract and receipt evidence. They must not summarize authority in loose prose. - -Reason: otherwise the report becomes review theatre. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/PLAN.md deleted file mode 100644 index 47f9146..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/PLAN.md +++ /dev/null @@ -1,306 +0,0 @@ -# GSD Macro Plan: Concrete Adapter Pack Expansion - -## Goal - -Invariant at stake: adapter pack expansion must prove that protected actions for automated decision making generalize without turning x402, runtime ingress, CLI, MCP, or reports into shortcut authority. - -Build the first concrete adapter pack expansion around package-manager material attestation for one exact package install attempt. The pack must show that Handshake can take an automated dependency action, reduce it to an exact protected action contract, require material evidence, enforce gateway-bound authority, and leave a reconstructable receipt with explicit proof gaps. - -The first wedge is x402 exact per-call protected action. It is not the protocol center. The package-manager adapter pack must preserve the Tier 1 spine while proving that exact per-call authorization can apply to non-payment protected actions. - -## Non-Goals - -- No payment management. -- No hosted operation claim. -- No broad runtime, MCP, or CLI enforcement claim. -- No supply-chain safety claim. -- No npm audit replacement claim. -- No Bun provenance verification claim. -- No claim that provenance, signatures, lockfiles, or attestations prove package code is benign. -- No package install execution outside an exact gateway-bound greenlight. -- No expansion into preview deploy or repo write until the package-install conformance slice closes. -- No god registry that centralizes every family, compiler, policy, validator, mapper, and bypass probe behind ambient runtime ingress authority. - -## Source Boundary - -Canonical source boundaries for this macro plan: - -- `ProtectedActionAdapterPackSchema` is the adapter contract boundary. -- Runtime ingress may select the relevant compiler for an action family. -- Runtime ingress must not authorize protected action execution. -- CLI and MCP may expose proposal, evidence, inventory, or read-only surfaces. -- CLI and MCP must not be described as enforcement points unless a gateway-bound mutation path actually enforces the exact greenlight. -- Gateway observed-parameter validation is the pre-consequence enforcement boundary. -- Receipt evidence mapping is post-decision and post-gateway evidence, not proof that downstream business outcome succeeded. - -The expansion order is: - -1. Package-manager material attestation / package-install adapter pack. -2. Preview deploy adapter pack. -3. Repo write adapter pack. - -## Current State - -Known source state: - -- `ProtectedActionAdapterPackSchema` exists and includes: - - pack id/version; - - action family; - - protected surface; - - parameter schema ref; - - endpoint evidence schema ref; - - install compiler ref; - - policy rule pack ref; - - gateway observed parameter validator ref; - - receipt evidence mapper ref; - - bypass probe kinds; - - hostile fixture refs. -- A generic install proposal exists. -- Package install runtime compiler and gateway tests exist. -- Preview deploy runtime and gateway lanes exist. -- Repo write runtime and gateway lanes exist. -- Runtime ingress has cross-family hardcoding risk and must not become a god registry. -- CLI and MCP are proposal/evidence/read-only surfaces. -- Bun lockfile evidence is available as local material/reconstruction evidence, not npm provenance verification. - -External evidence boundary: - -- npm provenance and signatures can verify source/build/publisher posture and registry/tarball integrity. -- `npm audit signatures` verifies registry signatures and provenance attestations after `npm install` with a supported npm CLI. -- Trusted publishing and provenance depend on external package account, repository, and workflow configuration. -- None of this proves benign package code. - -## Target State - -A concrete package-manager adapter pack exists as the first promoted expansion pack. - -It proves: - -- the manifest is the activation boundary; -- package install is represented as an exact protected action contract; -- runtime ingress selects the package-install compiler but does not authorize execution; -- policy evaluates exact package-manager material evidence requirements; -- gateway observed-parameter validation enforces the exact binding before mutation; -- receipt mapping records: - - proposed action; - - authority binding; - - exact contract; - - material evidence; - - gateway check; - - execution outcome; - - proof gaps; - - reconstruction material; - - bypass posture. -- lifecycle scripts are blocked by default unless separately contracted. -- raw sibling bypass is detected or blocks expansion. -- hostile fixtures prove the pack fails closed under drift, laundering, and bypass attempts. - -The buyer-readable product claim becomes: - -Handshake gates automated dependency actions on exact material evidence, policy, and gateway-bound authority. - -## Assumptions - -- The existing `ProtectedActionAdapterPackSchema` is close enough to freeze as the pack activation boundary, with only narrow additions allowed for conformance. -- The generic install proposal can be canonicalized into a package-install action contract without inventing broad package-manager authority. -- Existing package install runtime compiler and gateway tests can be extended into conformance fixtures. -- npm provenance/signature evidence is optional or gap-recorded when unavailable, not silently treated as satisfied. -- Bun lockfile evidence is useful for reconstruction and drift detection, not provenance verification. -- Lifecycle scripts are consequential execution and require separate contracting. -- Raw package-manager invocation outside the gateway is a bypass condition, not an unsupported happy path. -- Preview deploy and repo write can wait until package-install conformance demonstrates the adapter pattern. - -## Decisions - -1. Promote package-manager material attestation/package-install first. -2. Treat preview deploy as second. -3. Treat repo write as third. -4. Keep x402 as the first exact per-call protected action wedge, not the protocol center. -5. Treat the adapter manifest as the activation boundary. -6. Use small typed registries per concern instead of one god registry. -7. Runtime ingress selects compilers only; it does not authorize. -8. Gateway observed-parameter validator enforces exact binding. -9. Receipt evidence mapper records evidence and proof gaps; it does not certify benign code. -10. Block lifecycle scripts by default unless separately contracted. -11. Treat raw sibling bypass as a stop condition for expansion. -12. Require hostile fixtures before declaring the adapter pack promotable. - -## Phases - -Phase 1: Freeze Adapter Contract - -- Confirm `ProtectedActionAdapterPackSchema` expresses the activation boundary. -- Separate pack identity, action family, protected surface, compiler, policy, gateway validator, evidence mapper, bypass probes, and hostile fixtures. -- Prevent runtime ingress from becoming the authorization registry. -- Define conformance requirements for a promoted adapter pack. - -Phase 2: Canonical Package Install Proposal - -- Canonicalize the generic install proposal into a package-install protected action contract. -- Bind package name, version/range resolution, registry, package manager, lockfile posture, lifecycle script posture, material evidence requirements, and idempotency expectations. -- Preserve uncertainty markers when resolution or evidence cannot be proven before install. - -Phase 3: Gateway Observed-Parameter Validator - -- Implement package-install observed-parameter validation as the enforcement boundary. -- Reject drift between canonical contract and observed install parameters. -- Reject reusable greenlights. -- Reject lifecycle scripts unless separately contracted. -- Reject raw sibling bypass or mark expansion blocked when detection is not available. - -Phase 4: Material Attestation Mapper - -- Map npm provenance/signature evidence, registry/tarball integrity, lockfile material, package manager version, and proof gaps into receipt evidence. -- Keep npm evidence claims narrow. -- Treat Bun lockfile evidence as reconstruction material, not provenance verification. -- Record absent or unverifiable evidence as proof gaps. - -Phase 5: Custody And Bypass Probes - -- Add hostile fixtures for provenance laundering, lockfile drift, lifecycle script execution, registry substitution, tarball mismatch, raw sibling bypass, stale policy, and credential custody ambiguity. -- Expansion cannot pass if bypass posture is unobserved or advisory only. - -Phase 6: Buyer-Readable Report - -- Produce a report format with sections: - - action; - - authority; - - exact contract; - - evidence; - - outcome; - - proof gaps; - - reconstruction. -- Ensure the report does not imply package safety, hosted operation, or broad supply-chain security. - -Phase 7: Conformance And Export - -- Define adapter pack conformance export for the package-install slice. -- Produce a minimal conformance fixture for one npm install attempt. -- Export receipts and reports that reconstruct the chain without relying on chat transcript or runtime trace. - -## Task Graph - -```mermaid -flowchart TD - A["Freeze adapter contract"] --> B["Canonical package-install proposal"] - B --> C["Gateway observed-parameter validator"] - B --> D["Material attestation mapper"] - C --> E["Custody and bypass probes"] - D --> E - E --> F["Buyer-readable report"] - F --> G["Conformance/export"] - G --> H["Promote preview deploy second"] - G --> I["Promote repo write third"] -``` - -Critical path: - -1. Freeze adapter contract. -2. Canonicalize one npm install attempt. -3. Enforce observed-parameter validation. -4. Map material evidence and proof gaps. -5. Pass hostile fixtures. -6. Export receipt/report. - -## Risks And Mitigations - -- Shortcut authority: Runtime ingress, CLI, MCP, or report surfaces may be mistaken for enforcement. - - Mitigation: declare gateway observed-parameter validation as the only pre-consequence enforcement boundary. - -- Provenance laundering: npm provenance may be presented as package safety. - - Mitigation: receipt language must say provenance/signatures verify source/build/publisher posture and integrity, not benign code. - -- Lifecycle script consequence: install scripts can execute code during dependency install. - - Mitigation: lifecycle scripts default blocked unless separately contracted. - -- Lockfile drift: observed install may differ from contract or prior material state. - - Mitigation: gateway validator rejects drift or records proof gap before consequence where rejection is impossible. - -- Raw sibling bypass: generated code may call package-manager tools outside the protected gateway. - - Mitigation: bypass probe required; absence of detection blocks expansion. - -- Runtime/MCP/CLI overclaim: proposal and evidence surfaces may be marketed as enforcement. - - Mitigation: all docs and reports must separate proposal, policy, gateway check, and receipt. - -- Credential custody ambiguity: package registry tokens, CI identities, or local credentials may perform mutation outside the contract. - - Mitigation: adapter pack must name custody boundary and proof gaps. - -- Report theatre: buyer-readable report may summarize rather than bind to exact contract and receipt. - - Mitigation: report must reference exact contract id/hash and receipt evidence ids. - -## Validation Gates - -Gate 1: Adapter Contract Freeze - -- `ProtectedActionAdapterPackSchema` acts as activation boundary. -- No cross-family god registry is introduced. -- Runtime ingress remains compiler selection only. - -Gate 2: Package Install Contract - -- One npm install attempt can be represented as an exact protected action contract. -- Contract includes material evidence expectations and lifecycle script posture. -- Contract does not imply permission. - -Gate 3: Gateway Enforcement - -- Gateway validator rejects observed parameter drift. -- Greenlight is one-use and exact. -- Lifecycle scripts are blocked unless separately contracted. - -Gate 4: Evidence Mapping - -- npm signatures/provenance are recorded only within their real evidentiary scope. -- Bun lockfile evidence is recorded as local reconstruction material only. -- Missing evidence becomes a proof gap. - -Gate 5: Hostile Fixtures - -- Fixtures cover provenance laundering, lockfile drift, lifecycle scripts, registry substitution, tarball mismatch, raw sibling bypass, stale policy, and credential custody ambiguity. -- Any advisory-only bypass posture fails the gate. - -Gate 6: Report And Export - -- Report distinguishes action, authority, exact contract, evidence, outcome, proof gaps, and reconstruction. -- Export reconstructs the chain without trusting the runtime transcript. - -## Cut Lines - -Cut immediately: - -- Any broad supply-chain security claim. -- Any claim that npm provenance proves package safety. -- Any Bun provenance claim. -- Any payment-management framing. -- Any hosted-operation framing. -- Any MCP/CLI/runtime enforcement claim not backed by gateway enforcement. -- Any registry design that turns runtime ingress into authorization. -- Any report section that summarizes authority without exact contract binding. -- Any lifecycle-script allowance without a separate contract. - -Defer: - -- Preview deploy adapter pack. -- Repo write adapter pack. -- Cross-runtime enforcement claims. -- Hosted control plane packaging. -- Buyer dashboard polish. -- Broad adapter marketplace language. - -## Rollback / Stop Conditions - -Stop expansion if: - -- Runtime ingress becomes the authority holder. -- A greenlight can authorize more than one install attempt. -- Gateway observed-parameter validation cannot reject drift. -- Lifecycle scripts can execute under package-install authority without separate contracting. -- Raw sibling package-manager invocation cannot be detected, isolated, or treated as a blocking bypass. -- Receipt cannot distinguish gateway check from downstream install result. -- npm provenance/signature evidence is represented as benign-code proof. -- The report cannot reconstruct exact contract, authority, evidence, outcome, and proof gaps. -- The implementation requires broad CLI/MCP/runtime enforcement claims to sound useful. - -## Smallest Next Action - -Define the package-install conformance fixture for one npm install attempt: exact contract fields, expected npm material evidence, lifecycle script default-block posture, gateway observed parameters, receipt evidence mapping, and hostile drift cases. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/RISKS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/RISKS.md deleted file mode 100644 index 7e97d52..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/RISKS.md +++ /dev/null @@ -1,16 +0,0 @@ -# Risks - -| ID | Risk | Failure Mode | Mitigation | Stop Condition | -| --- | --- | --- | --- | --- | -| R1 | Shortcut authority | Runtime ingress, CLI, MCP, or reports are treated as authorization. | State that only gateway observed-parameter validation enforces before consequence. | Any docs or implementation path claims ingress/CLI/MCP enforcement without gateway binding. | -| R2 | God registry | Cross-family hardcoding becomes one ambient authority registry. | Use small typed registries by concern. | Runtime ingress owns policy, gateway validation, or receipt mapping authority. | -| R3 | Provenance laundering | npm provenance/signatures are described as package safety. | Limit claim to source/build/publisher posture and registry/tarball integrity. | Report claims benign code, safe package, or supply-chain security. | -| R4 | npm audit replacement claim | Adapter sounds like a vulnerability or audit replacement. | Say material attestation complements policy; it is not vulnerability detection. | Product copy claims audit replacement. | -| R5 | Bun provenance confusion | Bun lockfile is treated as npm provenance verification. | Treat Bun lockfile as local reconstruction and drift evidence only. | Receipt says Bun verified npm provenance. | -| R6 | Lifecycle script escape | Package install runs consequential code under install authority. | Block lifecycle scripts by default unless separately contracted. | Lifecycle scripts execute without a separate exact contract. | -| R7 | Lockfile drift | Observed install differs from canonical contract or expected material. | Gateway validator rejects drift or records proof gap before consequence where rejection is impossible. | Drift is accepted silently. | -| R8 | Raw sibling bypass | Generated code invokes package manager outside the gateway. | Require bypass probes and block promotion if bypass posture is advisory only. | Bypass cannot be detected, isolated, or treated as blocking. | -| R9 | Credential custody ambiguity | Registry credentials or CI identity mutate outside declared authority. | Receipt and manifest name custody boundary and proof gaps. | Credential source cannot be reconstructed. | -| R10 | Report theatre | Buyer report summarizes action without exact binding. | Report must include action, authority, exact contract, evidence, outcome, proof gaps, reconstruction. | Report cannot tie back to contract id/hash and receipt evidence. | -| R11 | Stale policy | Gateway check uses a decision made against stale policy or stale contract. | Gateway validator checks exact greenlight binding, one-use state, and policy/contract identity. | Reused or stale greenlight can pass. | -| R12 | Expansion overreach | Preview deploy or repo write borrows package-install authority pattern without hostile fixtures. | Keep expansion order gated by conformance. | Second/third pack starts before package-install conformance closes. | diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/TASKS.jsonl b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/TASKS.jsonl deleted file mode 100644 index e5713de..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/TASKS.jsonl +++ /dev/null @@ -1,12 +0,0 @@ -{"id":"CAP-001","priority":"P0","phase":"freeze-adapter-contract","title":"Freeze adapter pack manifest as activation boundary","owner":"architecture","rationale":"Adapter expansion is unsafe unless the manifest declares the exact compiler, policy, gateway validator, receipt mapper, bypass probes, and hostile fixtures required for activation.","depends_on":[],"acceptance":["ProtectedActionAdapterPackSchema is treated as the promoted pack boundary","manifest references remain typed and concern-specific","runtime ingress is not the authority holder"],"candidate_paths":["src/protocol","src/runtime","docs/internal/protocol-notes.md","docs/internal/decisions.md"],"non_goals":["implementation of preview deploy pack","implementation of repo write pack","god registry design"]} -{"id":"CAP-002","priority":"P0","phase":"freeze-adapter-contract","title":"Split adapter registries by concern","owner":"architecture","rationale":"A single registry would invite cross-family shortcut authority and turn runtime ingress into ambient authorization.","depends_on":["CAP-001"],"acceptance":["compiler registry is separate from policy registry","gateway validator registry is separate from receipt mapper registry","bypass probes and hostile fixtures are not hidden behind runtime ingress"],"candidate_paths":["src/runtime","src/policy","src/gateway","src/receipts"],"non_goals":["central control-plane registry","runtime enforcement claim","hosted registry service"]} -{"id":"CAP-003","priority":"P0","phase":"canonical-package-install","title":"Canonicalize one npm install protected action contract","owner":"protocol","rationale":"The smallest proof is one exact npm install attempt reduced from proposal to inspectable contract without granting broad package-manager authority.","depends_on":["CAP-001"],"acceptance":["contract binds package identity, version or resolution posture, registry, package manager, lifecycle-script posture, material evidence expectations, and idempotency key","contract is a proposal, not permission","uncertainty is preserved as uncertainty markers"],"candidate_paths":["src/protocol","src/adapters/package-install","tests"],"non_goals":["package safety scoring","vulnerability audit replacement","general dependency management"]} -{"id":"CAP-004","priority":"P0","phase":"gateway-validator","title":"Implement gateway observed-parameter validator for package install","owner":"gateway","rationale":"Policy without observed-parameter gateway enforcement is advisory, not Handshake.","depends_on":["CAP-003"],"acceptance":["validator rejects drift between contract and observed install parameters","validator enforces exact one-use greenlight binding","validator blocks lifecycle scripts unless separately contracted"],"candidate_paths":["src/gateway","src/adapters/package-install","tests/gateway"],"non_goals":["CLI enforcement","MCP enforcement","runtime trace enforcement"]} -{"id":"CAP-005","priority":"P0","phase":"material-attestation","title":"Map npm signatures and provenance into receipt evidence","owner":"receipts","rationale":"Material evidence must be recorded in its real evidentiary scope without laundering it into package safety.","depends_on":["CAP-003"],"acceptance":["receipt records npm registry signature/provenance status when available","receipt states proof gaps when evidence is absent or unsupported","receipt does not claim benign code or broad supply-chain security"],"candidate_paths":["src/receipts","src/adapters/package-install","docs/internal/protocol-notes.md"],"non_goals":["npm audit replacement","malware detection","package reputation scoring"]} -{"id":"CAP-006","priority":"P1","phase":"material-attestation","title":"Record Bun lockfile as reconstruction evidence only","owner":"receipts","rationale":"Bun lockfile material can help reconstruction and drift analysis, but it is not npm provenance verification.","depends_on":["CAP-005"],"acceptance":["Bun lockfile evidence is labeled as local material or reconstruction evidence","receipt never claims Bun verified npm provenance","lockfile drift produces rejection or proof gap"],"candidate_paths":["src/receipts","src/adapters/package-install","tests/fixtures"],"non_goals":["Bun provenance support","package safety claim","cross-package-manager equivalence claim"]} -{"id":"CAP-007","priority":"P0","phase":"custody-bypass-probes","title":"Add lifecycle-script hostile fixture","owner":"security","rationale":"Lifecycle scripts are consequential code execution and cannot hide inside package-install authority.","depends_on":["CAP-004"],"acceptance":["fixture attempts install with lifecycle script execution","default behavior blocks or refuses without separate contract","receipt records refusal or proof gap accurately"],"candidate_paths":["tests/fixtures/hostile","tests/gateway","src/adapters/package-install"],"non_goals":["supporting lifecycle scripts by default","script sandbox claim","supply-chain safety claim"]} -{"id":"CAP-008","priority":"P0","phase":"custody-bypass-probes","title":"Add raw sibling package-manager bypass fixture","owner":"security","rationale":"If generated code can call an unwrapped package-manager mutation path, the generated code escaped the contract boundary.","depends_on":["CAP-004"],"acceptance":["fixture exercises raw sibling install attempt","system detects, isolates, or marks expansion blocked","docs state advisory-only bypass posture is not promotable"],"candidate_paths":["tests/fixtures/hostile","src/runtime","src/gateway","docs/internal/decisions.md"],"non_goals":["broad host sandbox guarantee","MCP enforcement claim","CLI enforcement claim"]} -{"id":"CAP-009","priority":"P1","phase":"custody-bypass-probes","title":"Add material drift and provenance laundering fixtures","owner":"quality","rationale":"The pack must fail closed when evidence changes, disappears, or is misrepresented.","depends_on":["CAP-005","CAP-006"],"acceptance":["fixtures cover missing provenance, invalid signature, tarball mismatch, registry substitution, and lockfile drift","receipt records proof gaps without confidence language","gateway rejects pre-consequence drift where observable"],"candidate_paths":["tests/fixtures/hostile","tests/receipts","src/adapters/package-install"],"non_goals":["malware judgment","dependency update recommendation","registry trust scoring"]} -{"id":"CAP-010","priority":"P1","phase":"buyer-report","title":"Define buyer-readable protected dependency action report","owner":"product","rationale":"Adoption needs a readable artifact, but the report must bind to exact contract and receipt evidence or it becomes review theatre.","depends_on":["CAP-005","CAP-008","CAP-009"],"acceptance":["report sections are action, authority, exact contract, evidence, outcome, proof gaps, reconstruction","report references exact contract and receipt evidence ids","report excludes package safety and broad supply-chain claims"],"candidate_paths":["docs/internal","src/receipts","src/reports"],"non_goals":["dashboard polish","hosted operations claim","compliance certification"]} -{"id":"CAP-011","priority":"P0","phase":"conformance-export","title":"Create package-install conformance export for one npm install attempt","owner":"quality","rationale":"The first expansion is only real if the whole chain reconstructs from contract to receipt for one concrete attempt.","depends_on":["CAP-004","CAP-005","CAP-008","CAP-010"],"acceptance":["export includes proposal, exact contract, policy decision, gateway check, execution outcome, evidence, proof gaps, and reconstruction material","chain reconstructs without runtime transcript","closeout commands pass"],"candidate_paths":["tests/conformance","docs/internal","src/adapters/package-install"],"non_goals":["preview deploy conformance","repo write conformance","adapter marketplace"]} -{"id":"CAP-012","priority":"P2","phase":"next-pack-readiness","title":"Define promotion checklist for preview deploy and repo write","owner":"architecture","rationale":"Second and third packs must inherit the spine, not shortcut around package-install proof.","depends_on":["CAP-011"],"acceptance":["checklist requires manifest, compiler, policy, gateway validator, receipt mapper, bypass probes, and hostile fixtures","preview deploy remains second and repo write remains third","checklist blocks broad runtime/MCP/CLI enforcement claims"],"candidate_paths":["docs/internal/decisions.md","docs/internal/protocol-notes.md","tests/conformance"],"non_goals":["implementing preview deploy","implementing repo write","broadening protected actions beyond the validated spine"]} diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/VALIDATION.md deleted file mode 100644 index b23bc67..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/VALIDATION.md +++ /dev/null @@ -1,65 +0,0 @@ -# Validation - -## Validation Matrix - -| Gate | Required Evidence | Passing Condition | Failure Means | -| --- | --- | --- | --- | -| Adapter contract freeze | Adapter pack manifest fields and references | Manifest is the activation boundary and no god registry is introduced | Expansion is structurally unsafe | -| Runtime ingress boundary | Runtime ingress routing behavior | Ingress selects compiler only and does not authorize | Shortcut authority | -| Package-install contract | Canonical package-install proposal | One npm install attempt is exact, inspectable, and policy-evaluable | Vague intent laundered into fake precision | -| Policy decision | Policy rule pack result | Decision is greenlight, refusal, review, halt, or quarantine against exact contract | Advisory policy | -| Gateway observed-parameter validation | Observed install parameters | Gateway rejects drift and enforces one-use exact binding | This is advisory, not Handshake | -| Lifecycle script posture | Contract and observed install flags | Lifecycle scripts blocked unless separately contracted | Hidden consequential execution | -| npm material evidence | Signature/provenance/tarball/registry evidence | Evidence recorded within real scope, with proof gaps when absent | Provenance laundering | -| Bun lockfile evidence | Lockfile material and reconstruction notes | Lockfile recorded as local reconstruction/drift evidence only | False provenance claim | -| Receipt mapping | Receipt/refusal/proof-gap output | Receipt distinguishes proposal, policy, gateway check, execution result, proof gaps | Evidence theatre | -| Bypass probes | Hostile fixtures | Raw sibling bypass is detected, isolated, or blocks promotion | Generated code escaped the contract boundary | -| Buyer report | Report artifact | Report sections bind to exact contract and receipt evidence | Review theatre | -| Export conformance | Exported fixture and receipt | Chain reconstructs without runtime transcript | This is not auditable | - -## Hostile Fixture Requirements - -Required hostile fixtures: - -- provenance laundering; -- missing provenance; -- invalid npm registry signature; -- tarball integrity mismatch; -- registry substitution; -- lockfile drift; -- lifecycle script attempt; -- raw sibling package-manager invocation; -- stale policy decision; -- reusable greenlight attempt; -- credential custody ambiguity; -- report/contract mismatch. - -## Closeout Commands - -Run closeout only after implementation work exists. This macro plan itself is planning-only. - -Expected closeout command set: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -Focused closeout must also include the existing package-install runtime/gateway test target once its exact project script name is confirmed. - -## Closeout Evidence - -Closeout requires: - -- package-install conformance fixture for one npm install attempt; -- contract canonicalization evidence; -- gateway observed-parameter validation evidence; -- npm material evidence receipt mapping; -- Bun lockfile reconstruction evidence, if Bun material is present; -- explicit proof-gap case; -- lifecycle-script blocked case; -- raw sibling bypass case; -- buyer-readable report bound to exact contract and receipt ids; -- no product claims beyond protected dependency-action gating. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/input.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/input.md deleted file mode 100644 index 1a22cdc..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/input.md +++ /dev/null @@ -1,107 +0,0 @@ -# GSD Macro Input: Concrete Adapter Pack Expansion - -Run id: `concrete-adapter-pack-expansion-20260524T082400Z` -Date: 2026-05-24 - -## Hard Frame - -Handshake is protected actions for automated decision making, not an engineering-agent-only product. - -x402 exact per-call protected spend is the first wedge. It must remain one adapter proof pack, not the protocol center and not a payment-management product. - -Concrete adapter pack expansion must prove the Tier 1 spine generalizes: - -```text -exact action contract --> policy decision --> one-use gateway-bound greenlight/refusal --> customer-owned gateway check before mutation --> receipt/refusal/proof gap --> redacted reconstruction -``` - -No new adapter may invent shortcut authority because the mutation seems simpler than x402. - -## Current Source State - -Existing source already contains: - -- `ProtectedActionAdapterPackSchema` in `src/install/protected-action-adapter-pack/index.ts` with pack id/version, action family, protected surface kind, parameter schema ref, endpoint evidence schema ref, install compiler ref, policy rule pack ref, gateway observed parameter validator ref, receipt mapper ref, bypass probe kinds, and hostile fixture refs. -- Generic install proposals in `src/install/install-proposal/index.ts`. -- x402 install proposal and gateway signer path. -- Package install runtime proposal compiler in `src/runtime/package-install/action-proposal.ts`. -- Package install gateway in `src/adapters/package-install/gateway.ts`. -- Preview deploy runtime proposal compiler in `src/runtime/preview-deploy/action-proposal.ts`. -- Preview deploy gateway in `src/adapters/preview-deploy/gateway.ts`. -- Repo write runtime proposal compiler in `src/runtime/repo-write/action-proposal.ts`. -- Repo write gateway in `src/adapters/repo-write/gateway.ts`. -- Tests for package-install gateway, package-install runtime, package-install end-to-end, preview-deploy gateway, repo-write gateway, repo-write D1/HTTP, and support flows. - -Current `.planning/codebase/CONCERNS.md` says: - -- Runtime ingress is a 1,014-line cross-family module hardcoding package install, x402 payment, and auth.md dispatches. -- Each new protected-action family increases risk of missed refusal fields, cross-family parameter drift, and accidental authority language in the public runtime subpath. -- New family conversion should move behind source-owned family adapters or registry. -- Runtime ingress creates proposal evidence only: no policy decisions, greenlights, gateway checks, mutation attempts, receipts, or authority certificates. -- Package install is currently a regression lane until external package-manager material attestation is source-owned and tested. -- Broad runtime/host interception is not proven. - -Current `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` recommends first candidates: - -1. package-manager material attestation, because package install already exists as a regression lane; -2. preview deploy, because it is a common automated/generative execution mutation with visible downstream consequence; -3. repo write with protected branch or release consequence, because it exercises generated-code inspection and gateway path binding. - -Mechanisms required per adapter: - -- install proposal compiler; -- action type and gateway registry entry; -- exact parameter canonicalization; -- gateway observed-parameter validator; -- custody/bypass probes; -- receipt/proof-gap mapper; -- conformance fixture; -- buyer-readable report. - -## External Source Constraints - -For package-manager material attestation: - -- npm provenance lets consumers verify where/how a package was published and validate authorized publisher posture; `npm audit signatures` verifies registry signatures and provenance attestations when dependencies were installed with npm CLI support. -- npm provenance is not proof of benign code; it is a verifiable link to source/build instructions and transparency log evidence. -- npm registry signatures bind package name, version, and tarball integrity. -- Trusted publishing can automatically generate provenance when public packages are published via supported OIDC workflows, but account/repository/workflow correctness remains external configuration. -- Bun creates a `bun.lock` lockfile and recommends committing it; Bun lock evidence is local material evidence, not npm provenance verification by itself. - -Source links used: - -- https://docs.npmjs.com/viewing-package-provenance/ -- https://docs.npmjs.com/about-registry-signatures/ -- https://docs.npmjs.com/generating-provenance-statements/ -- https://docs.npmjs.com/trusted-publishers/ -- https://bun.com/docs/pm/lockfile - -## Planning Question - -Create a macro plan for concrete adapter pack expansion. Decide the first adapter pack to promote, the sequencing for preview deploy and repo write, and the mechanism that keeps adapter packs modular without weakening Tier 1 or making x402 the protocol. - -The likely answer should be: promote package-manager material attestation first, because package install already has runtime/gateway/regression lanes and external provenance standards can be bound as evidence. But challenge that if another candidate is materially stronger. - -## Required Output Properties - -The plan must include: - -- selected first adapter pack and why; -- explicit non-goals and cut lines; -- adapter pack manifest contract; -- parameter canonicalization and observed-parameter validation; -- material/provenance evidence posture; -- gateway custody and bypass probes; -- conformance fixtures; -- runtime/MCP/CLI exposure boundary; -- buyer-readable proof report; -- validation gates and closeout commands; -- architecture/import posture and no-god-registry constraints; -- success criteria and 10-star product bar. - -Do not implement source changes in this run. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/ADOPTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/ADOPTION.md deleted file mode 100644 index 3c72138..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/ADOPTION.md +++ /dev/null @@ -1,142 +0,0 @@ -# ADOPTION Perspective - -## Invariant At Stake - -Mutation authority stays in the gateway. The adapter pack may propose, explain, diagnose, and report, but it must not make CLI/MCP/runtime surfaces feel like enforcement. - -## Recommended First Adapter Pack - -Make the first concrete expansion a Package Install Adapter Pack. - -Do not promote preview deploy and repo write alongside it yet. Package install is narrow enough to prove modularity, evidence capture, lockfile grounding, registry identity checks, replay/idempotency posture, and gateway-bound mutation without implying Handshake controls the whole runtime. - -x402 exact remains the first protected-action wedge. Package install becomes the first buyer-legible adapter proof that the same control primitive generalizes. - -## Operator/Developer Adoption Path - -1. Read-only inventory. - Detect package manager, workspace root, lockfile, package manifests, registry config, and install command posture. - Output what Handshake can observe, not what it can enforce. - -2. Proposal mode. - Agent/runtime/CLI/MCP can propose `package.install` candidates. - Candidate includes package spec, manager, workspace, expected manifest targets, expected lockfile effect, lifecycle-script posture, registry source, and required gateway. - -3. Evidence preview. - Show npm provenance/signature/material identity evidence where available. - Show Bun lockfile as local material evidence. - Say explicitly: provenance/signatures support identity/source/build posture, not package safety. - -4. Gateway-bound greenlight. - Policy evaluates the exact canonical package-install contract. - Gateway verifies one-use greenlight before running the install. - No CLI or MCP command can mutate without the gateway check. - -5. Receipt/report. - Record proposal, canonical contract, policy decision, gateway check, execution result, lockfile/package manifest delta, evidence sources, and proof gaps. - -## Command And Report Affordances - -Developer-facing commands should feel boring and composable: - -```bash -handshake adapters list -handshake adapters inspect package-install -handshake package-install scan -handshake package-install propose bun add zod@3.25.0 -handshake package-install report --latest -handshake package-install diagnose --receipt -``` - -Gateway mutation must be visibly separate: - -```bash -handshake gateway execute -``` - -Avoid commands like: - -```bash -handshake install zod -handshake approve install -handshake run agent safely -``` - -Those blur proposal, approval, and enforcement. - -## Buyer-Readable Proof Report Shape - -A useful report should fit on one page first, with expandable evidence. - -Sections: - -1. Action. - Install package `zod@3.25.0` in workspace `apps/web` using `bun`. - -2. Authority. - Principal, runtime, policy version, greenlight id, gateway id. - State clearly whether the gateway enforced before mutation. - -3. Exact Contract. - Canonical action type, package name/version/range, registry, package manager, workspace, expected manifest/lockfile targets, idempotency key, one-use greenlight binding. - -4. Evidence. - npm provenance/signature status if available, registry metadata captured, Bun lockfile before/after material delta, package manifest delta, lifecycle scripts detected or absent. - -5. Outcome. - Executed, refused, quarantined, halted, or proof gap. - Downstream install success is not the same as package safety. - -6. Proof Gaps. - Missing provenance, unverified signature, registry metadata unavailable, lockfile changed outside expected package closure, lifecycle script posture uncertain. - -7. Reconstruction. - Receipt id, contract hash, greenlight hash, gateway-check record, evidence artifact ids. - -## Error Model - -Errors should name the violated boundary, not just the failed command. - -Examples: - -- `CONTRACT_REQUIRED`: runtime attempted a package mutation without a canonical package-install contract. -- `GREENLIGHT_MISSING`: gateway received a mutation request without an exact one-use greenlight. -- `GREENLIGHT_SCOPE_MISMATCH`: greenlight was for a different package, workspace, manager, registry, or lockfile target. -- `GREENLIGHT_ALREADY_USED`: replayed authority attempt. -- `LOCKFILE_DELTA_UNEXPECTED`: install changed more than the declared dependency closure. -- `PROVENANCE_UNAVAILABLE`: evidence gap, not failure unless policy requires it. -- `LIFECYCLE_SCRIPT_REQUIRES_REVIEW`: package install includes script execution posture that policy will not auto-greenlight. -- `READ_ONLY_SURFACE`: CLI/MCP can propose or report, but cannot mutate. - -## Diagnostics And Anti-Frustration Details - -- Always show the exact field that prevented greenlight. -- Provide a copyable corrected proposal command. -- Distinguish policy refused from gateway could not verify. -- Distinguish package identity evidence missing from package unsafe. -- Show lockfile delta in human terms, not only hash terms. -- Explain why a reused greenlight failed. -- Let teams run read-only scan/report commands without gateway setup. -- Provide fixture/demo mode using known package installs, but label it non-production evidence. -- Keep preview deploy and repo write visible as available lanes, not default promoted adapters. - -## 10-Star Product Bar - -The first adapter pack is excellent when a skeptical engineering lead can say: - -- I can add this to one repo without migrating my runtime. -- I understand exactly which package install was contracted. -- I can see where authority was enforced. -- I can prove CLI/MCP did not hold mutation authority. -- I can reconstruct the action six months later. -- I can explain provenance/signatures without pretending they prove safety. -- I can see lockfile evidence as local material proof. -- I can diagnose refusal without reading source code. -- I can pilot this on package installs before trusting broader protected actions. -- I do not feel sold a universal agent-control platform. - -## Brutal Verdict - -Keep package install as the first adapter pack. Cut simultaneous promotion of preview deploy and repo write. Narrow CLI/MCP to proposal, evidence, diagnostics, and read-only reporting. Buyer trust comes from exact gateway-bound mutation evidence, not from claiming runtime control. - -Smallest next mechanism to build: a package-install proof report schema that binds canonical contract, policy decision, gateway check, lockfile delta, npm provenance/signature evidence, and explicit proof gaps. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/ARCH.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/ARCH.md deleted file mode 100644 index 7cbb6cf..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/ARCH.md +++ /dev/null @@ -1,228 +0,0 @@ -# ARCHITECTURE Perspective - -## Invariant At Stake - -Adapter expansion must not create shortcut authority. Every adapter can only describe how to compile, canonicalize, validate, map evidence, probe bypass, and test hostile cases for a protected action family. It must never mint permission, widen a greenlight, or treat external provenance as proof of safety. - -## Architectural Plan - -### 1. Adapter-Pack Manifest Contract - -`ProtectedActionAdapterPackSchema` should become the only accepted manifest shape for adapter expansion. - -Each adapter pack should declare: - -- `adapterPackId`: stable, namespaced, versioned identifier. -- `actionFamily`: package install, preview deploy, repo write, etc. -- `supportedRuntimes`: runtime proposal surfaces only, not authority holders. -- `installCompilerRef`: turns runtime intent into proposed contracts. -- `policyPackRef`: family-specific policy rules and refusal reasons. -- `gatewayObservedParameterValidatorRef`: validates actual gateway-side parameters. -- `receiptMapperRef`: maps proposal, policy, gateway, execution, proof-gap, and bypass evidence. -- `bypassProbeRefs`: detects raw or sibling mutation paths. -- `hostileFixtureRefs`: conformance fixtures for overreach, stale policy, replay, parameter drift, and hidden mutation. -- `materialEvidenceFields`: family-specific evidence that may help reconstruction. -- `provenanceEvidenceFields`: attestations such as npm provenance/signatures or Bun lockfile facts. -- `redactionPolicyRef`: field-level reconstruction rules. - -The manifest is not executable authority. It is a signed or hash-addressed declaration of which family-specific components Handshake is allowed to load for proposal and evidence handling. - -### 2. Source Ownership - -Keep adapter ownership split by control primitive, not by runtime. - -Recommended ownership shape: - -- Protocol-owned schemas: canonical action contract, adapter-pack manifest, evidence envelopes, refusal/proof-gap enums. -- Family-owned adapter packs: package install, preview deploy, repo write. -- Runtime-owned proposal compilers: Codex, MCP, CLI, browser, CI, etc. -- Gateway-owned validators: observed parameter validation and greenlight binding. -- Receipt-owned mappers: durable evidence shape and redaction posture. -- Test-owned conformance suites: hostile fixtures and bypass probes. - -Do not let runtime ingress own adapter-family logic. Runtime ingress should select a proposal compiler by declared runtime and action family, then hand the candidate into canonical protocol flow. Cross-family hardcoding in ingress is architectural debt because it makes runtime adapters quietly become policy routers. - -### 3. Registry Shape - -Use small registries with typed refs, not one global registry. - -Required registries: - -- `AdapterPackRegistry`: resolves manifest refs by adapter pack id and version. -- `ActionCatalogRegistry`: maps known consequential action families to schemas. -- `CompilerRegistry`: maps runtime plus action family to proposal compiler. -- `PolicyPackRegistry`: maps action family plus policy version to evaluator. -- `GatewayValidatorRegistry`: maps action family plus gateway id to observed-parameter validator. -- `ReceiptMapperRegistry`: maps action family to evidence mapper. -- `FixtureRegistry`: maps adapter pack to conformance and hostile fixtures. - -Registry lookup must be deterministic and version-pinned. No runtime-selected dynamic imports from model output. No fallback to generic adapter for protected mutations unless the result is refusal or proof gap. - -### 4. Parameter Canonicalization - -Canonicalization is the contract boundary. - -Each adapter pack must define a deterministic canonical parameter shape: - -- normalized package manager command, package names, versions, registry, lockfile intent; -- normalized preview deploy target, project, branch, environment, provider, commit; -- normalized repo write path set, operation type, diff hash, branch, external consequence marker. - -Canonicalization must reject ambiguity. It should not best-guess package aliases, deploy targets, branch names, environment names, or write scopes. - -Canonical output should include: - -- `canonicalActionHash`; -- `protectedSurfaceId`; -- `idempotencyKey`; -- `sequencingDependencies`; -- `materialParameters`; -- `uncertaintyMarkers`; -- `redactionHints`. - -The compiler may produce candidates. The canonicalizer decides whether the candidate is exact enough to evaluate. If not, refusal or review, not permission. - -### 5. Observed-Parameter Validation - -Gateway observed-parameter validation is the adapter's most important expansion point. - -At mutation time, the gateway must compare: - -- canonical contract parameters; -- one-use greenlight binding; -- actual observed gateway parameters; -- policy version; -- adapter pack version; -- gateway registry version; -- isolation state. - -Mismatch means refusal or proof gap, not degraded execution. - -Validation must catch: - -- package manager changed package/version/registry/flags; -- Bun/npm lockfile drift after approval; -- preview deploy target changed branch/environment/provider/project; -- repo write touched paths outside approved diff; -- runtime retried with mutated parameters; -- sibling/raw tool path bypassed the adapter; -- stale review surface approved an older contract. - -A greenlight is valid for exactly one observed mutation attempt. - -### 6. Material And Provenance Evidence Posture - -Material evidence helps reconstruction. It is not authority. - -For package managers, evidence fields may include: - -- npm provenance attestation presence; -- npm signature verification result; -- registry URL; -- resolved package tarball integrity; -- lockfile digest; -- Bun lockfile digest; -- package manager version; -- install command digest; -- dependency graph delta. - -These fields prove what was attempted or observed. They do not prove the code is benign. Treating provenance as safety proof is evidence theatre. - -For preview deploys: - -- provider; -- project; -- environment; -- commit SHA; -- build config digest; -- deployment URL; -- provider request id; -- gateway decision id. - -For repo writes: - -- path allowlist; -- diff hash; -- commit hash if committed; -- working tree state; -- external consequence marker; -- bypass probe result. - -Receipts must distinguish proposal, policy decision, gateway check, execution result, downstream uncertainty, refusal, and proof gap. - -### 7. Conformance Fixtures - -Every adapter pack must ship hostile fixtures before it is accepted. - -Minimum fixture families: - -- overbroad vague intent compiled into excessive scope; -- generated code loop retries after refusal; -- greenlight replay attempt; -- stale policy version at gateway check; -- stale rendered review artifact; -- parameter drift between proposal and gateway; -- hidden secondary mutation; -- raw tool bypass; -- sibling adapter bypass; -- missing material evidence; -- missing provenance evidence; -- provenance present but malicious or unknown package behavior; -- receipt mapper unable to distinguish gateway check from execution result. - -The fixture suite should prove the adapter preserves the global Handshake chain: - -```text -proposal -> canonical contract -> policy -> greenlight/refusal -> gateway check -> receipt/proof gap -> redacted reconstruction -``` - -### 8. Import / Export Posture - -Adapter packs may be imported as declarative manifests plus versioned implementation refs. Import must validate schema, version, fixture coverage, and registry compatibility before activation. - -Export should produce reconstruction bundles: - -- adapter pack manifest digest; -- action contract; -- policy decision; -- gateway check record; -- observed parameters; -- evidence fields; -- redaction map; -- proof gaps; -- bypass probe results. - -Exports must not leak secrets, tokens, raw environment values, or full unredacted lockfile content unless explicitly allowed by redaction policy. CLI and MCP exports remain proposal/evidence only. - -### 9. No-God-Registry Constraints - -Do not build a universal adapter registry that can decide everything. - -Hard constraints: - -- Registry resolves refs; it does not interpret policy. -- Runtime ingress selects compilers; it does not authorize. -- Adapter pack declares family behavior; it does not bypass canonical protocol schemas. -- Policy pack evaluates exact contracts; it does not execute. -- Gateway validator enforces exact binding; it does not infer intent. -- Receipt mapper records evidence; it does not smooth gaps. -- CLI/MCP propose and report evidence; they do not mint greenlights. - -A god registry will become ambient authority with better metadata. Keep registries narrow, typed, version-pinned, and hostile-fixture-gated. - -## Expansion Sequence - -1. Promote adapter-pack manifest contract as the required activation boundary. -2. Split runtime ingress from action-family selection so compilers are looked up by runtime plus action family. -3. Define canonical parameter contracts for package install, preview deploy, and repo write. -4. Add gateway observed-parameter validators for those three families. -5. Attach material/provenance evidence fields without treating them as safety proof. -6. Require hostile fixture suites before any adapter pack is considered conformant. -7. Add redacted reconstruction export for one complete package-install receipt. -8. Only then add more adapter families. - -## Brutal Verdict - -Keep the adapter-pack expansion, but narrow its authority. The adapter pack is not a plugin permission model. It is a constrained evidence-and-contract module that must pass through the same Handshake primitive every time. - -Smallest next mechanism to build: a versioned adapter-pack activation gate that validates manifest refs, fixture coverage, canonical parameter schema, and gateway observed-parameter validator presence before the pack can be used. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/EXECUTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/EXECUTION.md deleted file mode 100644 index 1d4b607..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/EXECUTION.md +++ /dev/null @@ -1,186 +0,0 @@ -# EXECUTION Perspective - -## Invariant At Stake - -A concrete adapter may expand Tier 1 only if it preserves exact contract binding: candidate action -> deterministic canonicalization -> policy decision -> one-use gateway check -> receipt/refusal/proof-gap. Anything that adds provenance, reports, or runtime tests without gateway-observed enforcement is advisory, not Handshake. - -## First Adapter Selection - -Select package install adapter first. - -Reason: it already has runtime compiler and gateway test lanes, and the missing piece is sharply bounded: promote material attestation without pretending it proves package safety. That makes it the smallest credible adapter-pack expansion while protecting Tier 1. - -Do not select preview deploy or repo write first. They are more operationally valuable, but their blast radius includes environment drift, downstream platform state, filesystem semantics, and rollback ambiguity. Package install gives the adapter pack a cleaner first conformance surface. - -## Phase 0: Freeze The Adapter Contract - -Tasks: - -1. Define the package-install adapter pack boundary. -2. Confirm action type name, protected surface, gateway registry ownership, and receipt event names. -3. State explicitly that npm signatures/provenance are material evidence, not benignness proof. -4. State Bun lockfile evidence as local material evidence only. -5. Add no new Tier 1 claims unless a gateway check observes and validates the same canonical parameters. - -Validation gate: - -- The adapter pack must be expressible as one action type with one protected mutation path. -- No report or receipt may imply package safety from provenance alone. - -Stop condition: - -- If the existing package install action contract cannot carry install target, package manager, registry source, lockfile/material evidence fields, and idempotency key without widening Tier 1 primitives, stop and redesign the contract shape first. - -## Phase 1: Canonical Package Install Proposal - -Tasks: - -1. Compile package-install proposals into exact candidate actions. -2. Canonicalize package manager, package names, versions/ranges, registry URL, workspace path, lockfile path, install mode, and expected material evidence. -3. Reject dynamic package names, implicit registries, hidden postinstall scope, or unresolved workspace targets as refusal/review candidates. -4. Preserve generated code/spec references as proposal evidence, not permission. - -Validation gate: - -- Golden fixture proves semantically equivalent install proposals produce identical canonical contracts. -- Ambiguous versions, registry aliases, and workspace-relative path drift produce refusal/review outcomes. - -Stop condition: - -- If the compiler converts vague intent like "make tests pass" into package install authority without explicit candidate evidence, stop. The compiler overreached the principal. - -## Phase 2: Gateway Observed Parameter Validator - -Tasks: - -1. Add gateway registry entry for package install. -2. Validate observed gateway parameters against the exact greenlit canonical contract. -3. Enforce one-use greenlight binding. -4. Verify package manager, package spec, registry, workspace path, and idempotency key at the mutation boundary. -5. Record mismatch as refusal or bypass/proof-gap evidence, not a soft warning. - -Validation gate: - -- Gateway tests prove mismatch on package name, version, registry, workspace, or package manager blocks execution. -- Replay of a used greenlight fails. -- Raw/sibling install path is detected or recorded as bypass posture where possible. - -Stop condition: - -- If install can proceed through an unwrapped package-manager path while claiming Handshake enforcement, stop. The generated code escaped the contract boundary. - -## Phase 3: Material Attestation Mapper - -Tasks: - -1. Capture npm provenance/signature verification result when npm is the package manager. -2. Capture `npm audit signatures` result as registry-signature/provenance evidence after install where applicable. -3. Capture Bun lockfile deltas as local material evidence only. -4. Map unavailable, unsupported, failed, or skipped attestation to structured proof gaps. -5. Keep attestation separate from gateway check and downstream install result. - -Validation gate: - -- npm provenance/signature success is recorded as material attestation evidence, not safety approval. -- unsupported package manager or missing registry support records proof gap. -- failed attestation does not get smoothed into generic install failure. - -Stop condition: - -- If receipt language implies "verified package is safe," stop. Provenance does not prove benignness. - -## Phase 4: Custody And Bypass Probes - -Tasks: - -1. Probe whether install occurred through the Handshake-wrapped gateway. -2. Probe for lockfile/package manifest changes that do not match the greenlit contract. -3. Distinguish gateway-observed install, raw install suspicion, postinstall uncertainty, and unsupported custody evidence. -4. Record bypass/proof-gap evidence even when install appears successful. - -Validation gate: - -- Fixture proves manifest or lockfile mutation without matching gateway receipt is recorded as bypass/proof gap. -- Fixture proves install success without material attestation does not erase the proof gap. - -Stop condition: - -- If custody cannot distinguish gateway check from downstream install result, stop. This is evidence theatre. - -## Phase 5: Buyer-Readable Adapter Report - -Tasks: - -1. Generate a compact report for one package install attempt. -2. Include candidate contract, policy result, gateway check, observed install result, material attestation, bypass posture, and proof gaps. -3. Avoid internal planning-stage labels. -4. Make the report reconstructable from receipts, not from runtime logs alone. - -Validation gate: - -- Report can be regenerated from stored evidence. -- Report does not claim benignness, supply-chain safety, or org-wide enforcement beyond the observed attempt. - -Stop condition: - -- If the report is manually assembled from runtime trace instead of receipt evidence, stop. This is not auditable. - -## Phase 6: Conformance And Export Surface - -Tasks: - -1. Add package-install adapter conformance fixture. -2. Add architecture/export tests for action type, gateway registry entry, receipt/proof-gap mapper, and report generator. -3. Add runtime/MCP proposal tests only if this adapter is exposed through runtime/MCP proposal surfaces. -4. Keep preview deploy and repo write untouched except for shared adapter-pack interfaces required by this slice. - -Validation gate: - -- Architecture/export tests prove the adapter pack is wired through declared registries, not ad hoc imports. -- Conformance fixture proves proposal -> canonical contract -> gateway validation -> receipt/report reconstruction. - -## Closeout Commands - -Run only after implementation: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -Add focused tests if present: - -```bash -npm test -- package-install -npm test -- adapter -npm test -- gateway -``` - -## Rollback Conditions - -Rollback or stop the slice if: - -1. Tier 1 wording expands from enforced package install attempts to general supply-chain safety. -2. A greenlight can authorize more than one install attempt. -3. Gateway validation does not compare observed parameters to the canonical contract. -4. Provenance/signature evidence is treated as authorization. -5. Receipts collapse gateway check, install result, and attestation into one vague success event. -6. Raw or sibling package-manager bypass is invisible or unrecorded. -7. The adapter requires preview deploy or repo write changes to look complete. - -## Smallest Implementation Slice - -Build only this: - -Package install adapter conformance slice for one npm install attempt: - -1. Action catalog entry. -2. Deterministic canonical package-install contract. -3. Gateway registry entry with observed parameter validator. -4. One-use greenlight enforcement test. -5. Receipt mapper that separates gateway check, install result, npm signature/provenance evidence, and proof gaps. -6. One buyer-readable report generated from the receipt. - -Smallest next mechanism to build: the package-install gateway observed-parameter validator bound to the canonical contract. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/RISK.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/RISK.md deleted file mode 100644 index 8bd5def..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/RISK.md +++ /dev/null @@ -1,104 +0,0 @@ -# RISK Perspective - -## Invariant At Stake - -A new adapter pack must not convert protected actions into polite wrappers. Every package install, preview deploy, and repo write still needs an exact action contract, one-use greenlight, gateway-side check, receipt/refusal/proof-gap evidence, and bypass posture. If the adapter merely proposes or reports, it is advisory, not Handshake. - -## Risk Stance - -First adapter pack should be narrow: package-install, preview-deploy, and repo-write only. - -Do not center x402. Do not claim broad host interception. Do not claim CLI/MCP enforcement unless the gateway actually blocks mutation. CLI/MCP can emit proposals and evidence, but they are not authority holders unless paired with a blocking gateway. - -## Threat Model - -Protected actions: - -- Install or update dependencies. -- Trigger preview deploys. -- Write repo files with consequential downstream effects. -- Invoke CLI/MCP tools that may mutate through sibling paths. -- Use credentials needed by package managers, deploy systems, repos, or cloud APIs. - -Trust boundaries: - -- Agent runtime to Handshake proposal boundary. -- Handshake policy to gateway enforcement boundary. -- Gateway to external system mutation boundary. -- Package manager to registry/provenance/lockfile boundary. -- CLI/MCP adapter to raw host tools boundary. -- Receipt evidence to downstream business-success claims. - -Primary adversary is generated code with loops, retries, stale plans, dynamic tool names, lifecycle script execution, env access, credential leakage, and vague intent compiled into excessive scope. - -## Premortem - -| Risk | Failure Mode | Required Mechanism | -| --- | --- | --- | -| Shortcut authority | Adapter pack treats approved install/deploy/write as reusable permission. | One exact contract per mutation attempt; greenlight nonce bound to adapter, target, args, policy version, idempotency key, and expiry. | -| Supply-chain evidence laundering | npm provenance/signature is shown as proof the package is safe. | Receipt must distinguish registry provenance verified from benign code proven. | -| Package-manager side effects | Install runs lifecycle scripts, postinstall downloads, binary builds, env reads, or transitive mutations. | Package-install contract must declare lifecycle posture: blocked, sandboxed, or explicitly allowed with evidence. | -| Lifecycle scripts | Generated code only installs a package but install executes arbitrary package code. | Default should be ignore-scripts unless lifecycle scripts are separately contracted. | -| Lockfile drift | Lockfile changes differ from proposed dependency delta, or Bun lockfile is treated as npm provenance. | Canonical lockfile diff must be receipted; Bun lockfile proof cannot stand in for npm registry provenance. | -| Raw sibling bypass | Agent calls npm, bun, git, deploy CLI, or MCP raw path outside the adapter. | Explicit bypass tests; isolation state set on detected raw sibling mutation. | -| Runtime/MCP overclaim | CLI/MCP emits proposals/evidence but product claims enforcement. | Label CLI/MCP as proposal/evidence only until paired with a blocking gateway. | -| Credential custody | Adapter holds broad tokens and becomes ambient authority. | Gateway-owned scoped credentials; per-action credential reference; no runtime-held deploy/package/repo mutation secrets. | -| Report theatre | Adapter generates a clean report without proving gateway check or downstream result. | Receipts must separate proposal, policy decision, gateway check, attempted mutation, external response, and proof gap. | -| Import posture | Imported adapter lessons, package attestations, or external claims become canon without enforcement proof. | Imports are advisory notes unless backed by local contract/gateway/receipt fixtures. | - -## Hard Validation Gates - -1. Contract gate. - Each adapter action must canonicalize to a deterministic contract with protected surface, exact target, args, idempotency key, policy version, credential ref, expected evidence, and bypass posture. - -2. One-use greenlight gate. - A greenlight must fail on replay, mutation drift, expired policy, changed args, changed target, changed credential ref, or second use. - -3. Gateway enforcement gate. - Mutation must be impossible without the gateway check. If the raw tool can still mutate the same surface from the same runtime path, the adapter is not enforcement. - -4. Package-install evidence gate. - Package install receipts must separately record registry metadata, signature/provenance status, lockfile delta, lifecycle-script posture, package-manager version, and proof gaps. - -5. Lifecycle gate. - Lifecycle scripts default blocked. Allowing them requires a separate exact contract and evidence record. - -6. Bypass gate. - Tests must attempt raw npm/bun, raw deploy CLI, raw git write, and MCP sibling mutation. Any successful uncontracted mutation sets isolation state and blocks expansion. - -7. Runtime ingress gate. - Runtime family hardcoding must be removed or explicitly bounded. Adapter pack cannot assume one runtime family maps to authority semantics. - -8. Credential gate. - Runtime cannot possess broad mutation credentials. Gateway must hold or broker scoped credentials, and receipts must identify which credential reference was used. - -9. Receipt gate. - Receipts must reconstruct proposal, policy decision, gateway check, external attempt, result, refusal, proof gap, and bypass detection independently of chat logs. - -10. Claim gate. - README/docs/product language must not claim host-wide interception, MCP enforcement, package safety, or x402-centered authority unless implemented and tested. - -## Stop Conditions - -Stop adapter expansion if any of these are true: - -- A greenlight can authorize more than one mutation. -- A raw sibling path can mutate the protected surface. -- CLI/MCP is described as enforcement while only producing proposals or evidence. -- Package install evidence treats provenance, signatures, or lockfiles as proof of benign code. -- Lifecycle scripts can run without a separate contracted decision. -- Runtime ingress logic depends on hardcoded runtime families for authority. -- Gateway check and downstream execution are collapsed into one receipt field. -- Credentials are available to the agent runtime instead of the gateway boundary. -- Docs claim broad host interception before bypass tests prove it. -- x402 becomes the center of the protocol story instead of a protected-spend adapter case. - -## Brutal Verdict - -Keep the adapter pack only if it is framed as three concrete protected-action adapters with blocking gateway checks and hostile bypass tests. - -Cut any marketable language that says adapter support, MCP enforcement, safe installs, or runtime protection without exact gateway blocking. - -Narrow package install hardest. It is the riskiest because package managers execute code, mutate lockfiles, resolve transitive graphs, and produce evidence that is easy to launder into false confidence. - -Smallest next mechanism to build: a package-install contract fixture that records lifecycle posture, registry provenance status, lockfile delta, credential ref, one-use greenlight, gateway check, and explicit proof gaps. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/STRATEGY.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/STRATEGY.md deleted file mode 100644 index 0f65721..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/raw/STRATEGY.md +++ /dev/null @@ -1,111 +0,0 @@ -# STRATEGY Perspective - -## Invariant At Stake - -A protected action must reduce an automated decision into an exact, gateway-checkable contract with reconstructable evidence. The next adapter pack must prove Handshake is not payments, not deploy approvals, not agent auth, and not a hosted workflow product. - -## Choice - -Promote package-manager material attestation first. - -Not package install approval. That is too weak and too engineering-agent-coded. Promote the adapter as material attestation for automated dependency decisions. - -This is the cleanest next proof that the Tier 1 spine generalizes from x402 exact per-call to non-payment protected actions: - -- exact action contract; -- one-use greenlight; -- gateway check before consequence; -- refusal/proof-gap path; -- reconstructable material evidence; -- narrow adapter-owned semantics. - -Preview deploy is useful, but it pulls the product toward hosted operations. Repo write is foundational, but it is too broad and likely to become an intent/compiler swamp before the adapter spine is proven. - -## Strategic Sequencing - -1. Package-manager material attestation. - First promoted adapter pack. Use it to prove Handshake can gate an automated decision based on material evidence rather than payment state. - -2. Preview deploy. - Second. Use it to prove the same spine controls externally visible hosted consequences, but only after the adapter-pack boundary is already clean. - -3. Repo write. - Third. Use it when the compiler/canonicalizer boundary is stronger. Repo write touches too many protected surfaces and will otherwise blur action contract, diff intent, branch policy, CI side effects, and downstream deploy consequence. - -## Product Claim Boundary - -Say: - -> Handshake can gate automated dependency actions on exact package material evidence, policy, and gateway-bound execution authority. - -Do not say: - -- Handshake proves package code is safe. -- Handshake replaces npm audit. -- Handshake guarantees dependency security. -- Handshake verifies Bun provenance. -- Handshake knows whether a package is benign. -- Handshake is package-manager auth. -- Handshake broadly secures software supply chains. - -The exact claim is narrower and stronger: - -> For a declared package-manager action, Handshake records the proposed package mutation, evaluates required material evidence, greenlights or refuses one exact attempt, checks that greenlight at the gateway, and records the resulting evidence or proof gap. - -## 10-Star Bar - -The promoted adapter pack is not 10-star unless it has all of this: - -1. Adapter-owned contract schema. - Package name, version/range, resolved version, registry, package manager, lockfile posture, install command shape, workspace path, expected mutation class, and idempotency key are first-class fields. - -2. Canonicalization before policy. - The same proposed install/update must canonicalize deterministically. No policy decision over raw command strings. - -3. Material evidence model. - npm provenance/signature evidence is represented separately from local lockfile evidence. Bun lockfiles can support local reconstruction, but cannot masquerade as npm provenance verification. - -4. Explicit non-benign-code boundary. - The adapter must state that signatures/provenance/tarball integrity are material posture, not proof of harmless code. - -5. Gateway-side check. - The install path must verify the exact greenlight before mutation. If the runtime compiler proposes but raw install can bypass, that bypass must be recorded or blocked. - -6. Refusal as product output. - Missing signature, unsupported registry, unverifiable package manager, stale lockfile, unresolved package, or mismatched tarball must produce structured refusal or proof gap. - -7. Evidence receipt separation. - Receipt must distinguish proposal, policy decision, gateway check, install execution, signature/provenance verification, lockfile delta, and downstream audit uncertainty. - -8. No god registry. - Runtime ingress must not absorb package-manager semantics. The adapter pack owns package-manager canonicalization and evidence interpretation behind a narrow interface. - -9. Regression lane converted into source-owned adapter. - Existing package install fixtures/tests stop being only regression coverage. They become canonical adapter examples with named doctrine. - -10. Cross-manager honesty. - npm gets provenance/signature verification where supported. Bun gets local lockfile/material evidence only unless an actual provenance verification mechanism is wired. No fake parity. - -## Cut Lines - -Cut package install as permission. The product is not "agent asked to install lodash and user approved." That is approval theatre unless the gateway binds the exact resolved artifact and attempt. - -Cut broad supply-chain security. Handshake does not decide benignness. It controls whether an automated dependency mutation may proceed under declared material evidence requirements. - -Cut Bun provenance claims unless wired to a real verification mechanism. Bun lockfiles are useful reconstruction evidence, not npm provenance attestation. - -Cut runtime-ingress centralization. Runtime ingress should normalize proposal intake and route to adapter packs. It must not become the global registry for every protected action family. - -Cut MCP/CLI as authority surfaces. MCP/CLI can propose, inspect, and emit evidence. They do not become the authority holder unless the gateway check is actually enforced there. - -Cut preview deploy as first generalization proof. It is compelling, but it reinforces hosted operation control. Use it after package-manager attestation proves the spine works on material evidence. - -Cut repo write as first generalization proof. It is too large. Without stronger compiler boundaries, repo write will collapse into vague intent, diff review, branch policy, CI consequence, and deploy adjacency. - -## Brutal Verdict - -Promote package-manager material attestation first. - -It is the smallest adapter pack that breaks the payment-center narrative while preserving exact per-action discipline. It forces Handshake to say what evidence proves, what it does not prove, and where gateway authority actually lives. - -Smallest next mechanism to build: a source-owned package-manager material attestation adapter contract with npm signature/provenance evidence, Bun lockfile-only evidence, structured refusal/proof-gap receipts, and one gateway fixture proving exact greenlight binding before install. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/synthesis.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/synthesis.md deleted file mode 100644 index 1d7e51e..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/concrete-adapter-pack-expansion/runs/concrete-adapter-pack-expansion-20260524T082400Z/synthesis.md +++ /dev/null @@ -1,127 +0,0 @@ -# Chair Synthesis: Concrete Adapter Pack Expansion - -## Invariant At Stake - -No consequential automated action executes outside declared bounds, and divergent behavior must be haltable, isolatable, and reconstructable. - -For this macro item, the dangerous failure is expansion theatre: claiming Handshake generalizes beyond x402 while silently replacing exact gateway-bound authority with runtime ingress, CLI/MCP surfaces, reports, npm evidence, or package-manager conventions. - -## Perspective Reconciliation - -### Strategy - -Strategy is right to promote package-manager material attestation first. - -It breaks the payment-centered narrative without broadening into vague platform claims. The claim is narrow and defensible: Handshake gates automated dependency actions on exact material evidence, policy, and gateway-bound authority. - -The strategy boundary is equally important. Do not say package safety. Do not say npm audit replacement. Do not say Bun provenance. Do not say broad supply-chain security. Do not say hosted operation. Do not say MCP/CLI/runtime enforcement. - -### Architecture - -Architecture is right that the manifest contract is the activation boundary. - -The adapter pack is not a folder of helpers. It is a declared activation unit: schemas, compiler, policy rule pack, gateway observed-parameter validator, receipt evidence mapper, bypass probes, hostile fixtures. - -The runtime ingress concern is real. If runtime ingress grows into one cross-family registry that knows every compiler, policy, validator, mapper, and bypass probe, it becomes ambient authority by architecture. Use small typed registries. Runtime ingress selects compilers. It does not authorize. - -### Execution - -Execution is right on phase order: - -1. freeze adapter contract; -2. canonical package install proposal; -3. gateway observed-parameter validator; -4. material attestation mapper; -5. custody/bypass probes; -6. buyer-readable report; -7. conformance/export. - -The smallest useful slice is package-install conformance for one npm install attempt. Anything broader invites unearned claims. - -### Risk - -Risk is right to treat lifecycle scripts, lockfile drift, raw sibling bypass, provenance laundering, credential custody, and report theatre as first-class blockers. - -Lifecycle scripts are the sharp edge. An install that runs scripts is not merely installing material. It is executing code. Default block unless separately contracted. - -Raw sibling bypass is the second sharp edge. If generated code can call `npm`, `bun`, `pnpm`, or another package-manager mutation path outside the gateway, the generated code escaped the contract boundary. Advisory detection is not enough for promotion. - -### Adoption - -Adoption is right that the operator path must be concrete: - -1. scan/inventory; -2. propose; -3. evidence preview; -4. gateway-bound greenlight; -5. receipt/report. - -The commands and UI must not blur proposal, approval, and enforcement. The report must have stable sections: action, authority, exact contract, evidence, outcome, proof gaps, reconstruction. - -The report is useful only if it binds to the exact contract and receipt evidence. Otherwise this is review theatre. - -## 10-Star Bar - -A 10-star version of this macro plan proves the Tier 1 spine outside payments with one exact dependency action. - -It must demonstrate: - -- exact package-install contract; -- policy decision against that exact contract; -- one-use greenlight; -- gateway observed-parameter enforcement; -- lifecycle script default block; -- npm material evidence mapped within true scope; -- Bun lockfile evidence scoped to reconstruction; -- raw sibling bypass detected or promotion blocked; -- hostile fixtures that fail closed; -- receipt that distinguishes proposal, policy, gateway check, downstream install result, and proof gaps; -- buyer-readable report that does not overclaim. - -The 10-star bar is not a beautiful adapter story. It is one reconstructable protected action that cannot be confused with payment management, package safety, supply-chain security, hosted operations, or runtime enforcement. - -## Antipatterns - -### Antipattern: Clean Proof Surface Becomes First Market - -A clean package-install proof surface is not automatically the first market. It is a demo candidate and adapter spine proof. Market merit still requires urgent, budgeted, frequent, expensive pain and a distribution path. - -### Antipattern: npm Evidence Becomes Safety Claim - -npm provenance/signatures help verify source/build/publisher posture and registry/tarball integrity. They do not prove benign code. Calling this package safety is provenance laundering. - -### Antipattern: Bun Lockfile Becomes Provenance - -Bun lockfile material supports local reconstruction and drift evidence. It is not npm provenance verification. - -### Antipattern: Runtime Ingress Becomes Authority - -Runtime ingress selecting a compiler is acceptable. Runtime ingress authorizing a mutation is shortcut authority. - -### Antipattern: CLI/MCP Enforcement Language - -CLI and MCP may propose, display, inventory, and export evidence. Unless they are the gateway-bound mutation path, they are not enforcement. - -### Antipattern: Report Theatre - -A buyer-readable report that summarizes authority without binding to exact contract and receipt evidence is review theatre. - -### Antipattern: Lifecycle Scripts Hidden Under Install - -Lifecycle scripts are consequential execution. They require separate contracting or default blocking. - -### Antipattern: Bypass As Documentation - -Documenting that raw package-manager bypass exists is not enough. Detect it, isolate it, or block promotion. - -## Final Verdict - -Keep and narrow. - -Promote package-manager material attestation/package-install first. It is the right adapter pack because it proves Handshake is about exact protected actions, not payments, while staying small enough to enforce. - -Cut every broad claim around supply-chain security, package safety, hosted operations, payment management, and runtime/MCP/CLI enforcement. - -Do not start preview deploy or repo write promotion until package-install conformance closes for one npm install attempt with hostile fixtures and reconstructable receipt evidence. - -Smallest next mechanism to build: package-install conformance for one npm install attempt, including exact contract, npm material evidence expectations, lifecycle-script default block, gateway observed parameters, receipt mapping, and hostile drift/bypass cases. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/ASSUMPTIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/ASSUMPTIONS.md deleted file mode 100644 index d36a022..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/ASSUMPTIONS.md +++ /dev/null @@ -1,16 +0,0 @@ -# Assumptions - -| ID | Assumption | Confidence | Evidence | Invalidation Trigger | -| --- | --- | --- | --- | --- | -| A1 | Tier 1 protocol meaning must stay stable: exact contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap, isolation. | High | User constraints and all raw perspectives. | Implementation requires a custody-specific greenlight, approval, or permission object. | -| A2 | Customer-owned gateway custody means the customer/provider gateway owns or resolves the mutation credential; Handshake does not hold it. | High | Input constraints and product canon in raw outputs. | Any source change stores signer material, wallets, bearer tokens, payment credentials, balances, or settlement state in Handshake. | -| A3 | x402 is the first wedge but must not define generic custody proof semantics. | High | User constraints and strategy/execution raw outputs. | Protocol packet fields become x402/payment-specific instead of provider-neutral. | -| A4 | A new packet is needed because extending only existing fields leaves buyer-readable custody proof scattered. | Medium-High | ARCH, STRATEGY, EXECUTION, and ADOPTION raw outputs converge. | Source map shows an existing source-owned object can carry the full chain without overloading semantics. | -| A5 | The packet can be added under credential custody as evidence without creating a second authority plane. | Medium | Existing credential-custody and protected-path primitives appear to own the right boundary. | Object registry, kernel, or public schema ownership prevents additive packet wiring without broad redesign. | -| A6 | Custody proof should be required first for credential-backed protected paths, not every `gateway_checked` path. | High | Strategy raw output warns global requirement could drift Tier 1 meaning. | Implementation proves all gateway-checked paths already have credential backing and can migrate safely. | -| A7 | Fixture/local custody can support regression tests but cannot support provider/customer custody claims. | High | Input constraints and all raw perspectives. | Any docs, examples, or projections describe `fixture_gateway_held` as customer/provider custody. | -| A8 | Credential resolution evidence remains post-gate and cannot become install proof or permission. | High | ARCH, RISK, and ADOPTION raw outputs. | Implementation records credential resolution before a passed gateway check or uses it to authorize policy. | -| A9 | Redacted projections should be allowlist-style for custody fields because provider formats are not verified. | Medium-High | RISK and ADOPTION raw outputs identify pattern-only redaction risk. | Official provider verification and fuzz tests prove safe provider-specific field rendering. | -| A10 | Provider-neutral schema planning can proceed without browsing. | High | Input packet explicitly says do not browse by default. | A named provider/vault/KMS/wallet implementation becomes necessary for the first slice. | -| A11 | Companion files outside the packet may affect object registration, public inputs, projection schemas, and storage. | High | ARCH and EXECUTION raw outputs list unverified source paths. | Phase 0 inspection shows no companion changes are required. | -| A12 | Claim-boundary cleanup remains in force and must be extended, not bypassed. | High | Input references active claim-boundary cleanup and raw outputs rely on claim guards. | Claim tests are stale or do not cover custody proof language. | diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/CONTEXT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/CONTEXT.md deleted file mode 100644 index 9e195ea..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/CONTEXT.md +++ /dev/null @@ -1,67 +0,0 @@ -# Context - -## Target - -Create a source-grounded macro plan for customer-owned gateway custody proof, the critical-path item that proves a protected action path is real because the mutation credential lives behind a customer/provider gateway that enforces the exact greenlight before consequence. - -The intended mechanism is: - -```text -gateway install evidence --> credential ref binding --> protected-path posture --> custody/bypass probe packet --> gateway check binds exact contract --> redacted custody projection -``` - -## Source Packet - -Read inputs: - -- `.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/input.md` -- raw perspective outputs under `.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/` -- `/Users/joelchan/.codex/skills/gsd-macro-plan/references/plan-contract.md` - -The raw outputs independently converged on the same core decision: add a source-owned custody proof packet, but keep it subordinate to existing credential ref, protected-path posture, bypass probe, policy, gateway check, credential resolution, and projection primitives. - -## Current State Summary - -Existing source, as summarized by the raw agents, already has: - -- opaque gateway credential references. -- post-gate credential resolution evidence. -- current protected-path posture with probe coverage and source authority. -- policy-time and gateway-time posture/credential binding checks. -- one-use greenlight and gateway check semantics. -- x402 local/reference signing after `VerifiedGatewayCheck`. -- auth.md lifecycle, revocation, redaction, and post-gate credential resolution patterns. -- redacted projection infrastructure and claim-boundary tests. - -Missing: - -- one typed, source-owned, digest-bound custody packet tying install evidence, credential ref, posture, bypass probes, drift status, redaction status, and claim level. -- policy/gateway refusal rules that require that packet for credential-backed protected paths. -- redacted custody projection that a buyer can inspect without raw record reads or secret exposure. -- claim guards preventing fixture custody from becoming provider/customer custody language. - -## Relevant Canon - -- Handshake is protected actions for automated decision making, not just engineering agents. -- x402 is the first wedge, not the protocol. -- customer-owned gateway custody is the enforcement model. -- Tier 1 protocol meaning remains exact contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap, and isolation. -- `.planning/` is scratch. Durable claims must be source/test/canonical-doc backed before becoming repo-facing truth. - -## Implementation Source Boundary To Verify Later - -The plan cannot be executed until implementation verifies companion ownership for: - -- protocol public schemas and inputs. -- object registry and source-owned object type wiring. -- kernel facade and public exports. -- evidence projection schemas. -- store/memory/D1 persistence and migrations. -- test fixtures and adapter export surfaces. - -Provider-specific vault/KMS/wallet/x402 provider details remain blocked until official source verification. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/DECISIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/DECISIONS.md deleted file mode 100644 index b0ea8b6..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/DECISIONS.md +++ /dev/null @@ -1,87 +0,0 @@ -# Decisions - -## Accepted - -### D1 - Add A Custody Proof Packet As Evidence - -Add `GatewayCustodyProofPacket` or the final source-owned equivalent under `src/protocol/areas/credential-custody/`. - -Justification: existing primitives are necessary but scattered. A buyer-readable customer-owned custody claim needs a digest-bound object that references install evidence, credential ref, protected-path posture, bypass probes, resolver/lease/provider posture, drift status, redaction status, and claim level. - -Boundary: the packet creates no permission. It cannot replace policy, greenlight, gateway check, mutation evidence, credential resolution evidence, or downstream reconciliation. - -### D2 - Extend Existing Authority Bindings - -Extend `GatewayCredentialRef`, `ProtectedPathPosture`, bypass probe inputs, policy input, gateway check evidence, and projections only as needed to bind the packet id/digest and drift status. - -Justification: a new custody authority plane would violate Tier 1 protocol meaning. The gateway check remains the enforcement point before consequence. - -### D3 - Require Packet First For Credential-Backed Protected Paths - -Require custody packet binding first for credential-backed protected paths such as x402 signer custody. Do not make custody proof mandatory for every `gateway_checked` path in this slice. - -Justification: this avoids changing Tier 1 protocol meaning while proving the stronger enforcement story where mutation credential custody is the issue. - -### D4 - x402 Uses The Generic Packet - -x402 install/proposal/gateway paths should bind signer custody through generic `GatewayCredentialRef` plus custody packet digest. - -Justification: x402 is the first wedge but not the protocol. Payment-specific signer fields must not become generic protocol semantics. - -### D5 - Fixture Custody Is Local-Only Evidence - -Introduce or preserve an explicit claim level such as `local_fixture`, `customer_gateway_evidence`, `provider_gateway_evidence`, and `proof_gap`. - -Justification: local fixture keys can test mechanics but cannot prove live customer/provider custody. - -### D6 - Projection Is Redacted And Reconstruction-Oriented - -The buyer-facing artifact is a redacted custody projection over refs/digests/statuses, not raw packet browsing. - -Justification: custody proof must be auditable without exposing signer material, secret paths, payment payloads, bearer tokens, or mutation credentials. - -## Rejected - -### R1 - Only Add More Fields To Existing Records - -Rejected because it leaves custody proof distributed across credential refs, posture, probes, resolution evidence, and projections. That makes customer-owned custody too easy to overclaim and hard to reconstruct. - -### R2 - Add A New Custody Permission Or Greenlight - -Rejected because it creates a second authority plane. The packet is evidence, not permission. - -### R3 - Make x402 Payment Management The Slice - -Rejected because the product primitive is protected-action custody proof. Balances, settlement, payment management, seller/facilitator operation, and aggregate spend ledgers are outside scope. - -### R4 - Claim Live Provider Custody From Fixtures - -Rejected because fixture custody is local/reference evidence only. Live provider/customer custody requires source-owned packet behavior, negative tests, redacted projections, and later official source verification for provider-specific implementation. - -### R5 - Move Enforcement Into Runtime, MCP, CLI, Or SDK Convenience - -Rejected because runtime-facing surfaces can propose and read evidence but cannot own policy decisions, greenlights, gateway checks, credential resolution, receipts, or mutation authority. - -## Deferred - -### F1 - Exact Public Object Registration Pattern - -Deferred until Phase 0 verifies object registry, public schemas, kernel facade, projection schemas, storage, and fixture ownership. - -### F2 - Exact Gateway Check Artifact Shape - -Deferred until schema ownership is verified. Preferred shape is explicit packet refs/digests seen on gateway evidence. Fallback is only acceptable if posture digest deterministically includes packet digest and drift state, with tests proving it. - -### F3 - Provider-Specific Custody Implementations - -Deferred until official source verification for named vault, KMS, wallet, x402 provider, JWKS, Cloudflare, legal, or payment-regulatory details. - -### F4 - Activation Helper Or Buyer Quickstart - -Deferred until the packet, policy/gateway binding, x402 integration, and projection exist. A helper may sequence transitions but cannot move authority into runtime/MCP/SDK. - -## User-Owned - -No P1 user-owned decision blocks the next implementation slice. The plan chooses the packet approach. - -User or maintainer decision may be needed later if Phase 0 reveals a wider public API/storage migration blast radius than expected. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/PLAN.md deleted file mode 100644 index 9f8ac5c..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/PLAN.md +++ /dev/null @@ -1,441 +0,0 @@ -# Plan - -## Goal - -Invariant at stake: a protected action is real only when the mutation credential remains behind a customer/provider gateway boundary, an exact one-use greenlight is checked immediately before consequence, unsafe or drifted custody refuses before mutation, and the surviving evidence is redacted but reconstructable. - -Create an implementation plan for customer-owned gateway custody proof as a source-owned mechanism for protected actions for automated decision making. x402 is the first wedge because paid HTTP makes credential custody concrete, but x402 must not define the protocol. Tier 1 protocol meaning stays stable: exact action contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap, and isolation state remain the authority spine. - -The 10-star bar is this: a buyer can see that the automated decision system never received the mutation credential, the customer/provider gateway held or resolved the credential, the exact greenlight was checked immediately before mutation, drift/stale/unsafe custody refused before consequence, and the surviving packet is redacted but reconstructable. - -## Non-Goals - -- No Handshake-held wallets, private keys, bearer tokens, payment credentials, balances, settlement state, or payment-management state. -- No provider/customer custody claim from fixture keys, local sandbox signers, conformance fixtures, or `fixture_gateway_held` posture. -- No live provider custody, named vault/KMS/wallet architecture, JWKS behavior, x402 provider behavior, legal, or payment-regulatory claim until official source verification happens in a later implementation pass. -- No broad x402 compatibility, marketplace, certification, clearing-house readiness, facilitator operation, seller middleware, signed offers, signed receipts, aggregate spend ledgers, or payment settlement. -- No broad runtime, MCP, browser, shell, package-manager, cloud, repo, database, or network control claim. -- No new authority plane. A custody proof packet cannot create permission, mint greenlights, replace policy evaluation, replace the gateway check, or prove downstream business success. -- No raw custody packet read API that exposes secret-bearing provider coordinates, signer material, `PaymentPayload`, `PAYMENT-SIGNATURE`, bearer tokens, mutation credentials, payment payloads, authorization headers, claim tokens, JWTs, PII, or provider secret paths. -- No planning-stage labels from `.planning/` promoted into source paths, package scripts, CI names, exports, or canonical docs. - -## Source Boundary - -This plan was synthesized from the immutable packet at `.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/input.md`, the five raw perspective outputs under the same run, and the macro plan contract. - -Allowed source paths named in the packet define the evidence boundary for this planning pass. The plan relies on the raw agents' source-grounded findings, especially around: - -- `GatewayCredentialRef`, `CredentialResolutionEvidence`, and credential-custody transitions. -- `ProtectedPathPosture`, source-authority posture, and bypass probe digests. -- policy and gateway transitions that already re-check posture and credential bindings. -- x402 install, wallet-gateway, bypass-probe, and conformance posture. -- auth.md gateway, revocation, bypass, and serialization-redaction learnings. -- evidence projection and claim-boundary tests. - -Companion implementation files outside the first-pass packet must be verified before coding, including protocol public aggregation, object registry, kernel facade, projection schemas, fixtures, storage, and migrations. This plan is executable only after that source map is checked. - -## Current State - -Current source appears to have the authority spine needed for the slice: - -- `GatewayCredentialRef` provides an opaque, provider-neutral credential reference and rejects raw credential-looking material. -- `CredentialResolutionEvidence` is post-gate evidence. It binds exact contract, greenlight, gate attempt, credential ref digest, resolver metadata, request digest, redaction status, and result class after a passed gateway check. -- `ProtectedPathPosture` models current runtime/gateway/action/resource posture, including gateway-checked state, credential custody status, raw sibling status, bypass probe refs/digests, source authority, expiry, and posture digest. -- policy evaluation and gateway check both consult current protected-path posture and gateway credential bindings before authority proceeds. -- gateway artifacts distinguish gateway check from mutation attempt and downstream outcome. -- redacted projections already expose contract, transaction, receipt, install-health, idempotency, and credential evidence without raw credential material. -- x402 proves one local/reference buyer-side `x402_payment.exact` path where signing happens after `VerifiedGatewayCheck`. -- auth.md provides the strongest pattern for credential refs, lifecycle drift/revocation, post-gate credential resolution, isolation, and redaction. - -The gap is not vocabulary. The gap is that custody proof is scattered across install evidence, credential refs, protected-path posture, bypass probes, policy input, gateway checks, credential resolution evidence, and projections. Without a source-owned packet or equivalent digest spine, customer-owned gateway custody can be overclaimed from fixture posture, adapter metadata, or a review projection. - -## Target State - -Add a narrow source-owned `GatewayCustodyProofPacket` under the credential-custody authority spine. It is evidence, not authority. - -The mechanism is: - -```text -gateway install evidence --> GatewayCredentialRef id/digest --> protected-path posture id/digest --> custody/bypass probe packet refs/digests --> custody proof packet id/digest --> action contract credential binding --> policy input and greenlight binding --> gateway-time revalidation before mutation --> post-gate CredentialResolutionEvidence --> redacted custody projection -``` - -The packet binds existing primitives instead of replacing them. Existing `GatewayCredentialRef`, `CredentialResolutionEvidence`, `ProtectedPathPosture`, policy checks, gateway checks, bypass probes, and projections should be extended to consume or expose the packet where necessary. Do not add a new custody approval, custody greenlight, wallet authorization, hosted trust certificate, or payment-custody object. - -The packet posture is provider-neutral and redaction-first. Candidate fields: - -- `gatewayCustodyProofPacketId` -- `gatewayCustodyProofPacketDigest` -- `gatewayCredentialRefId` -- `gatewayCredentialRefDigest` -- `protectedPathPostureId` -- `protectedPathPostureDigest` -- `gatewayInstallEvidenceRefs` -- `gatewayInstallEvidenceDigests` -- `bypassProbeIds` -- `bypassProbeDigests` -- `gatewayId` -- `gatewayRegistryEntryId` -- `protectedSurfaceKind` -- `actionClasses` -- `resourceRefs` -- `custodyProviderClass` -- `custodyProviderRegistryRef` -- `custodyProviderRegistryDigest` -- `opaqueKeyHandleRef` -- `opaqueKeyHandleDigest` -- `credentialKind` -- `credentialCustodyStatus` -- `custodyClaimLevel`: `local_fixture | customer_gateway_evidence | provider_gateway_evidence | proof_gap` -- `resolverRef` -- `resolverVersion` -- `resolverDigest` -- `leaseRef` -- `leaseVersion` -- `leaseIssuedAt` -- `leaseExpiresAt` -- `attestationRefs` -- `attestationDigests` -- `redactedAuditRefs` -- `redactedAuditDigest` -- `custodyDriftStatus`: `current | stale | provider_drift | resolver_drift | unsafe_custody | proof_gap` -- `resolverDriftStatus` -- `redactionStatus` -- `externalVerificationStatus`: `not_required | required_before_live_claim | verified_by_official_source` -- `redactionProfileRef` -- `secretMaterialIncluded: false` -- `recordedAt` -- `expiresAt` - -The packet must reject raw credentials, raw signer refs, raw vault/KMS/provider secret paths, bearer tokens, `PaymentPayload`, `PAYMENT-SIGNATURE`, private keys, mutation credentials, payment payloads, and access-token-looking values. Projection should expose refs, digests, statuses, and omitted fields only. - -## Assumptions - -- Tier 1 protocol meaning remains stable and is not redefined by custody proof. -- Customer-owned gateway custody means the customer/provider gateway owns or resolves the mutation credential; Handshake does not hold or manage the credential. -- x402 remains the first protected-action pack, not the protocol definition. -- The packet can be added as an evidence object under credential custody without introducing hosted operation. -- Custody proof is required first for credential-backed protected paths, including x402 signer custody. It should not become a global requirement for every `gateway_checked` path in this slice. -- Fixture/local/reference custody can support regression proof only and must project as `local_fixture`, not customer/provider custody. -- Named provider, vault, KMS, wallet, x402 provider, JWKS, Cloudflare, npm, MCP Registry, legal, or payment-regulatory details require official source verification before implementation. -- Object registry, public schema, projection schema, storage, migration, fixture, and package-export impacts are not fully verified in this planning pass and must be checked before source edits. - -## Decisions - -1. Add a custody proof packet, but keep it subordinate to existing primitives. - - Choice: add `GatewayCustodyProofPacket` as a typed evidence packet under `src/protocol/areas/credential-custody/`. - - Reason: extending only `GatewayCredentialRef`, `CredentialResolutionEvidence`, `ProtectedPathPosture`, and bypass probes leaves the custody story scattered. A buyer-readable claim needs one digest-bound packet that ties install evidence, credential ref, posture, probes, drift, redaction, and later gate/resolution evidence together. - - Boundary: the packet does not authorize mutation. Policy and gateway checks remain the enforcement points. - -2. Extend existing bindings instead of creating a new authority lane. - - `GatewayCredentialRef` remains the opaque credential handle. - - `ProtectedPathPosture` remains current, probe-backed posture. - - bypass probes remain hostile-path evidence. - - `CredentialResolutionEvidence` remains post-gate use/resolution evidence. - - policy and gateway checks must consume packet id/digest and drift state for custody-backed paths. - -3. Require custody proof first for credential-backed protected paths. - - x402 signer custody is the first target. - - Do not silently require custody proof for all `gateway_checked` paths until the first credential-backed path proves the mechanism. - -4. Treat x402 as a proof pack, not payment infrastructure. - - x402 maps signer custody into generic credential refs and custody proof packets. - - x402 remains one buyer-side exact paid HTTP action per call. - - No Handshake-held wallet, balance, settlement, facilitator, seller middleware, aggregate spend, or broad compatibility claim. - -5. Import auth.md learnings only as custody/ref lifecycle patterns. - - Reuse credential-ref binding, lifecycle drift, revocation/isolation, post-gate resolution, and redaction patterns. - - Do not turn Handshake into an auth provider, OAuth server, identity provider, or generic API gateway. - -6. Redacted projection is the adoption artifact. - - The buyer should read a custody projection that links packet, contract, policy/greenlight, gateway check, credential resolution, mutation/refusal/proof-gap refs, and omitted fields. - - Raw packet access is not the buyer-facing proof path. - -## Phases - -### Phase 0 - Source Map Verification - -Before implementation, inspect companion files outside the first-pass packet that likely own public aggregation, object registration, storage, fixture, and projection schema wiring. Confirm the exact edit set and update this plan if source ownership differs. - -Candidate paths to verify: - -- `src/protocol/kernel.ts` -- `src/protocol/areas/credential-custody/index.ts` -- `src/protocol/areas/credential-custody/types.ts` -- `src/protocol/areas/object-registry/*` -- `src/protocol/public/schemas.ts` -- `src/protocol/public/inputs.ts` -- `src/protocol/evidence-projections/schemas.ts` -- `src/storage/d1/*` -- `src/storage/memory/*` -- `test/support/fixtures.ts` -- `test/support/auth-md-flow.ts` -- adapter index/export files - -Exit criteria: exact source/test/doc edit map is confirmed before coding. - -### Phase 1 - Test-First Custody Packet Failures - -Add failing tests before implementation. The first tests should prove: - -- custody packet schema rejects raw credential and secret-looking fields. -- custody packet digest changes when credential ref, protected-path posture, bypass probes, resolver version, lease/version, attestation digest, redacted audit digest, drift status, redaction status, or expiry changes. -- policy refuses a credential-backed action that has valid credential ref and protected-path posture but no valid custody packet binding. -- gateway refuses when custody packet/posture/credential ref drifts after greenlight and before mutation. -- projections expose refs/digests/status only and omit secret-bearing material. -- fixtures cannot satisfy customer/provider custody claims. - -Exit criteria: focused tests fail for missing source-owned packet behavior, not unrelated fixture setup. - -### Phase 2 - Source-Owned Packet Schema And Transition - -Add `GatewayCustodyProofPacket` schema/input/transition under credential custody. Implement `recordGatewayCustodyProofPacket(input)` or the local equivalent. - -The transition must: - -- load the credential ref by id/digest. -- load current protected-path posture by id or exact scope. -- verify tenant/org/gateway/protected surface/action/resource agreement. -- verify posture is fresh, `gateway_checked`, and accepted-source probe-backed. -- verify required bypass probes are present and passed. -- verify credential custody can satisfy gateway-checked posture. -- canonicalize the packet digest after loaded refs are known. -- commit packet record and event through the source-owned object/store pattern. -- never retrieve, store, or project secret material. -- never create permission, greenlight, mutation proof, wallet custody, settlement, or payment state. - -Exit criteria: packet schema and transition tests pass with deterministic digest behavior and redaction failure handling. - -### Phase 3 - Bind Packet Into Contract, Policy, And Gateway Evaluation - -Extend the existing gateway credential binding path with custody packet id/digest and required drift/redaction status fields. Do not create a parallel policy evaluator. - -Policy must refuse before greenlight when: - -- packet is missing. -- packet digest mismatches the credential ref, posture, or binding. -- packet is stale or expired. -- credential ref is stale, isolated, scope-mismatched, or provider-drifted. -- provider registry digest, resolver version, lease/version, posture digest, or probe digest drifted. -- custody status is unsafe, agent-exposed, fixture-only for customer/provider claim, or proof gap. -- source authority is weak. -- required bypass probes are missing or failed. -- redaction failed. - -Gateway check must re-run the same current-state custody checks immediately before mutation and record what it saw. Prefer explicit `custodyProofPacketIdSeen`, `custodyProofPacketDigestSeen`, and `custodyDriftStatusSeen` fields on gateway evidence if schema ownership supports it. If not, prove that posture digest deterministically includes packet digest and drift status. - -Exit criteria: policy and gateway negative tests refuse before mutation and do not record downstream success as custody proof. - -### Phase 4 - x402 First Wedge Integration - -Make x402 use the generic custody primitives. - -Implementation direction: - -- x402 install proposal derives or references a `GatewayCredentialRef` for signer/payment credential custody. -- x402 action proposal binds the credential ref and custody packet digest on the candidate/contract path. -- wallet gateway continues to require `VerifiedGatewayCheck` before signing. -- wallet gateway records redacted `CredentialResolutionEvidence` after a passed gate and binds it to exact contract, greenlight, gate attempt, credential ref, and custody packet. -- x402 bypass/conformance tests distinguish local fixture custody from customer/provider custody. -- fixture custody projects as `local_fixture` and cannot satisfy live customer/provider custody claim guards. - -Exit criteria: x402 cannot call the signer on missing/stale/drifted/unsafe packet, raw sibling posture, replay, params mismatch, or gateway policy drift; x402 still does not introduce payment custody or payment management. - -### Phase 5 - auth.md Parity Pattern - -Use auth.md as a reference protected API profile for lifecycle and redaction semantics. - -Implementation direction: - -- bind auth.md credential refs to the same custody packet shape when custody proof is required. -- preserve revocation/lifecycle isolation. -- ensure metadata/provider digest drift blocks policy/gateway checks before credential resolution and downstream service calls. -- keep auth.md identity/claim/revocation evidence as provenance, not auth-provider authority. - -Exit criteria: auth.md drift, revocation, token replay, raw bearer passthrough, unsafe retry, and redaction failure still quarantine/refuse before credential use. - -### Phase 6 - Redacted Custody Projection - -Add a redacted projection that assembles the packet chain for buyers without exposing raw custody material. - -Projection fields should include: - -- custody proof packet ref/digest. -- credential ref/digest. -- protected-path posture ref/digest. -- action contract ref/digest. -- policy decision/greenlight ref/digest. -- gateway check ref/digest. -- credential resolution evidence refs. -- mutation/refusal/proof-gap/downstream reconciliation refs. -- custody provider class, provider registry digest, opaque key handle digest, resolver version, lease version/freshness, attestation digests, redacted audit digest. -- custody claim level, drift status, redaction status, external verification status, omitted fields, and reason codes. - -Projection must omit secret paths, signer material, raw key handles, bearer tokens, `PaymentPayload`, `PAYMENT-SIGNATURE`, mutation credentials, payment payloads, raw authorization headers, claim tokens, JWTs, PII, and provider secret coordinates. - -Exit criteria: projection tests prove the packet distinguishes gateway check, credential resolution, mutation/downstream outcome, refusal, and proof gap. - -### Phase 7 - Claim Guards And Canonical Docs - -Update canonical docs only after source/tests prove the packet. Keep docs compact and source-owned. - -Candidate docs: - -- `README.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-layman.md` -- `docs/internal/protocol-notes.md` - -Claim guards must fail if docs/examples imply: - -- live provider/customer custody from fixture keys. -- Handshake-held wallet, payment credential, balance, settlement, payment management, seller/facilitator, marketplace, certification, or clearing-house operation. -- x402 as the protocol instead of the first protected-action pack. -- hosted trust or broad runtime/MCP/browser/shell interception. -- provider-specific vault/KMS/wallet correctness without official source verification. - -Exit criteria: claim-boundary and architecture tests pass before public/docs language changes are considered complete. - -### Phase 8 - Closeout - -Close only when focused protocol, adapter, projection, redaction, architecture, claim, and full repo gates pass. Planned evidence must be separated from existing evidence throughout closeout. - -## Task Graph - -```text -custody-000 - -> custody-010 - -> custody-020 - -> custody-030 - -> custody-040 - -> custody-050 - -> custody-060 - -> custody-070 - -> custody-080 - -> custody-090 -``` - -- `custody-000`: verify source map and exact edit ownership. -- `custody-010`: add failing protocol, gateway, projection, and claim tests. -- `custody-020`: add packet schema/input/canonicalization. -- `custody-030`: add packet record transition and source-owned persistence/event wiring. -- `custody-040`: bind packet into contract/policy/gateway checks. -- `custody-050`: integrate x402 signer custody with generic credential ref and packet. -- `custody-060`: apply auth.md parity for lifecycle/isolation/redaction. -- `custody-070`: add redacted custody projection. -- `custody-080`: update canonical docs and claim guards after source/tests. -- `custody-090`: run closeout gates and record evidence. - -Do not start adapter implementation before packet schema and binding semantics are stable. Otherwise x402 and auth.md will grow adapter-specific custody stories and the protocol primitive will rot. - -## Risks And Mitigations - -- P0: packet theatre. A packet emitted only as projection text is advisory, not Handshake. Mitigation: policy and gateway must require packet id/digest for custody-backed paths. -- P0: stale custody admitted after greenlight. Mitigation: gateway re-reads current credential ref, posture, packet, isolation, resolver/lease/provider registry status, and policy drift immediately before mutation. -- P0: agent-exposed signer path remains reachable. Mitigation: required bypass probes and raw sibling posture must fail closed before `gateway_checked` posture can satisfy policy. -- P0: redacted projection leaks secrets. Mitigation: allowlisted projection fields, denylist/fuzz tests, and `redaction_failed` refusal/proof gap instead of best-effort serialization. -- P0: payment custody/regulatory drift. Mitigation: explicit non-goals plus claim guards. -- P1: packet overfits x402. Mitigation: provider-neutral fields only; x402 maps into the generic packet. -- P1: fixture laundering. Mitigation: `custodyClaimLevel` and claim guards distinguish `local_fixture` from customer/provider evidence. -- P1: provider registry or resolver drift is weakly detected. Mitigation: require digests/versions/lease fields for custody-backed paths; absent digest becomes proof gap or unsafe posture. -- P1: runtime/MCP proposal surfaces imply enforcement. Mitigation: runtime/MCP/CLI/SDK remain proposal/evidence/read surfaces only. -- P2: operational ceremony blocks adoption. Mitigation: activation helpers may sequence source-owned transitions later, but cannot move authority out of policy/gateway. -- P2: storage/projection blast radius hidden. Mitigation: Phase 0 source map verification before source edits. - -## Validation Gates - -Focused future gates: - -```bash -npm run test -- test/protocol/credential-custody.test.ts test/protocol/kernel-policy-gateway.test.ts -npm run test -- test/protocol/evidence-projections.test.ts -npm run test -- test/adapters/x402-wallet-gateway.test.ts test/adapters/x402-bypass-probes.test.ts -npm run test -- test/conformance/x402-payment-conformance.test.ts -npm run test -- test/adapters/auth-md-gateway-pressure.test.ts test/adapters/auth-md-serialization-redaction.test.ts -npm run test -- test/architecture/claim-boundary.test.ts test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -Add new focused test files only if existing ownership cannot carry the cases, for example: - -- `test/protocol/customer-owned-gateway-custody-proof.test.ts` -- `test/adapters/x402-install-proposal.test.ts` -- `test/adapters/x402-payment-action-proposal.test.ts` - -Required behavioral evidence: - -- missing custody packet refuses before greenlight for custody-backed paths. -- stale packet/ref/posture refuses before greenlight and at gateway time. -- packet drift after greenlight refuses before mutation and records no downstream success. -- agent-exposed signer refuses during install/proposal/posture/policy/gateway paths. -- raw sibling signer/payment path prevents `gateway_checked` posture from satisfying policy. -- gateway check sees the exact packet/ref/posture digest expected by policy. -- credential resolution evidence is recorded only after a passed gateway check. -- replay cannot reuse a greenlight for another credential resolution or mutation. -- redacted projection omits secret material and distinguishes gateway check, credential resolution, mutation/downstream outcome, refusal, and proof gap. -- fixture custody cannot project or document as live customer/provider custody. - -## Cut Lines - -Cut from this slice: - -- Handshake-held payment custody, signer custody, balances, settlement, or payment management. -- provider-specific vault/KMS/wallet implementations before official source verification. -- live provider/customer custody claim from fixture keys. -- broad x402 compatibility, facilitator operation, seller middleware, marketplace, certification, clearing-house readiness, or settlement finality. -- aggregate x402 spend-window enforcement until a real ledger exists. -- broad runtime/MCP/browser/shell/network/package-manager/database/cloud interception. -- all-role SDK, CLI, MCP, or runtime mutation commands. -- raw custody record reads as buyer proof. -- dashboard/review UX unless it renders exact packet refs and cannot authorize anything. - -Antipatterns: - -- `custodyProof: true` without packet digest and policy/gateway enforcement. -- wallet gateway profile metadata treated as customer-owned custody proof. -- rendered review screen that says "gateway owned" without exact packet/contract/greenlight/gateway binding. This is review theatre. -- receipt that cannot distinguish gateway check from credential resolution and downstream result. This is evidence theatre. -- recording signer use before gateway check. -- one greenlight per workflow. This is ambient authority wearing a badge. -- fixture custody described as provider/customer custody. -- regex-only redaction for live provider custody. -- docs claiming live custody before packet, negative tests, and redacted projections exist. - -## Rollback / Stop Conditions - -Stop implementation if: - -- packet id/digest is not consumed by both policy and gateway checks for custody-backed paths. -- gateway cannot refuse before signer/credential use. -- implementation requires one greenlight to authorize multiple credential resolutions or mutations. -- fixture/local signer custody is the only evidence behind a customer/provider custody claim. -- redaction tests find raw signer, token, payment payload, secret path, bearer credential, mutation credential, or PII in projections. -- provider-specific vault/KMS/wallet behavior is required but official docs have not been verified. -- runtime/MCP/SDK convenience code starts issuing policy decisions, greenlights, gateway checks, receipts, mutation attempts, or credential-resolution records. -- aggregate spend, settlement, facilitator, seller middleware, balance, or payment-management language appears. -- public aggregation, object registry, storage, or projection schema ownership is unclear after Phase 0. - -Rollback should quarantine or remove the new packet/projection/claim surface while preserving existing `GatewayCredentialRef`, `CredentialResolutionEvidence`, `ProtectedPathPosture`, policy, gateway, and projection behavior. Partial schema without enforcement must be labeled advisory or removed. Do not leave a decorative packet in source. - -## Smallest Next Action - -Inspect Phase 0 companion files, then add the first failing tests in `test/protocol/credential-custody.test.ts` and `test/protocol/kernel-policy-gateway.test.ts` for: - -1. `GatewayCustodyProofPacket` schema redaction and deterministic digest binding. -2. packet binding to `GatewayCredentialRef`, `ProtectedPathPosture`, and bypass probe digests. -3. policy refusal when an otherwise valid custody-backed action lacks the packet binding. - -Do not touch x402 until those failures prove the protocol shape. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/RISKS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/RISKS.md deleted file mode 100644 index a770167..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/RISKS.md +++ /dev/null @@ -1,43 +0,0 @@ -# Risks - -## P0 - -| Risk | Failure Mode | Mitigation | -| --- | --- | --- | -| Packet theatre | A packet is emitted as projection/install text but policy and gateway do not require it before credential use. | Bind packet id/digest into credential-backed contract/policy/gateway checks; cut custody claims if enforcement is absent. | -| Stale custody after greenlight | Credential ref, resolver version, lease, provider registry, posture, or packet drifts after policy but before mutation. | Gateway re-reads current credential ref, posture, packet, isolation, resolver/lease/provider state, and policy drift before mutation. | -| Agent-exposed signer path | x402/auth-style adapters leave direct SDK signer, private key env, raw signature header, bearer passthrough, MCP/browser/network sibling, or retry loop outside the gateway. | Required bypass probes and raw sibling posture must fail closed before `gateway_checked` posture can satisfy policy. | -| Redaction leak | Projection exposes private keys, bearer tokens, provider secret paths, `PaymentPayload`, `PAYMENT-SIGNATURE`, mutation credentials, payment payloads, authorization headers, claim tokens, JWTs, or PII. | Allowlisted projection fields, denylist/fuzz tests, redaction-failure refusal/proof gap. | -| Payment custody drift | Work introduces Handshake-held wallets, balances, payment credentials, settlement, facilitator/seller operation, or payment management. | Non-goals, claim guards, and x402 limited to one buyer-side exact protected action per call. | - -## P1 - -| Risk | Failure Mode | Mitigation | -| --- | --- | --- | -| x402 overfit | Protocol fields become wallet/payment/x402-specific. | Keep packet provider-neutral; x402 maps into generic refs/digests/statuses. | -| Fixture laundering | `fixture_gateway_held` passes local tests and later docs imply provider/customer custody. | Add `custodyClaimLevel`; claim guards reject provider/customer custody from fixtures. | -| Weak drift detection | Null provider registry or resolver digests allow stale custody to pass. | Custody-backed paths require digest/version/lease presence or become `proof_gap`/unsafe. | -| Resolver failure misclassified | Credential resolution failure becomes downstream uncertainty after mutation. | Resolver failure must refuse before protected mutation; no mutation attempt on pre-gate custody failure. | -| auth.md scope creep | Credential/ref lifecycle lessons turn into auth-provider/OAuth claims. | Import lifecycle isolation/redaction only; cut identity-provider claims. | -| Review laundering | UI says "gateway owned" while contract/packet is stale or weaker. | Review/projection must bind exact contract digest, policy input/greenlight, packet digest, and uncertainty/reason codes. | -| Runtime/MCP authority drift | Proposal surfaces imply enforcement or gain signer/gateway authority. | Runtime/MCP/CLI/SDK remain proposal/evidence/read only; import/surface tests enforce this. | - -## P2 - -| Risk | Failure Mode | Mitigation | -| --- | --- | --- | -| Duplicate state | Packet duplicates credential ref, protected-path posture, and resolution evidence without ownership clarity. | Packet owns aggregation/digest binding only; existing primitives keep their meanings. | -| Hidden storage blast radius | New object needs registry, public schema, D1/memory store, migrations, or indexes not planned. | Phase 0 source map verification before coding. | -| Adoption ceremony | Integrators must manually assemble install evidence, refs, probes, posture, policy, gateway, resolution, and projection. | Add activation helper later, but helper only sequences source-owned transitions. | -| `.planning` becomes canon | Scratch terms leak into source exports, package scripts, CI, or README claims. | Canonical docs change only after source/tests; no planning labels in public source. | - -## Antipatterns - -- `custodyProof: true` without packet digest and policy/gateway checks. -- wallet profile metadata treated as customer-owned custody proof. -- recording credential resolution before a passed gateway check. -- one greenlight authorizing multiple mutations. -- fixture custody described as live provider/customer custody. -- provider-specific fields such as `vaultPath`, `secretPath`, `walletPrivateKey`, `PaymentPayload`, or `PAYMENT-SIGNATURE` in protocol records or projections. -- regex-only redaction for live provider custody. -- docs claiming hosted trust, marketplace readiness, clearing-house readiness, or broad runtime control. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/TASKS.jsonl b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/TASKS.jsonl deleted file mode 100644 index d6623f9..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/TASKS.jsonl +++ /dev/null @@ -1,10 +0,0 @@ -{"id":"custody-000","priority":"P0","phase":"Phase 0","title":"Verify implementation source map for custody packet ownership","owner":"executor","rationale":"The raw planning packet did not include all public aggregation, object registry, storage, fixture, and projection schema owners needed for safe implementation.","depends_on":[],"acceptance":["Companion source owners are inspected before edits","Exact source/test/doc edit map is recorded","Plan is revised or blocked if object registration or storage ownership contradicts the packet approach"],"candidate_paths":["src/protocol/kernel.ts","src/protocol/areas/credential-custody/index.ts","src/protocol/areas/credential-custody/types.ts","src/protocol/areas/object-registry","src/protocol/public/schemas.ts","src/protocol/public/inputs.ts","src/protocol/evidence-projections/schemas.ts","src/storage/d1","src/storage/memory","test/support/fixtures.ts","test/support/auth-md-flow.ts"],"non_goals":["Do not implement source changes during source map verification","Do not browse provider docs in this task"]} -{"id":"custody-010","priority":"P0","phase":"Phase 1","title":"Add failing custody packet and refusal tests","owner":"test-owner","rationale":"The packet must be enforced by tests before source implementation or it can become decorative evidence.","depends_on":["custody-000"],"acceptance":["Tests fail for missing GatewayCustodyProofPacket behavior","Tests cover redaction rejection, digest binding, missing packet refusal, stale/drift refusal, and fixture claim guard","Failures are specific to missing custody proof behavior"],"candidate_paths":["test/protocol/credential-custody.test.ts","test/protocol/kernel-policy-gateway.test.ts","test/protocol/evidence-projections.test.ts","test/architecture/claim-boundary.test.ts"],"non_goals":["Do not update docs to claim custody before source behavior exists","Do not make fixture custody satisfy provider/customer custody"]} -{"id":"custody-020","priority":"P0","phase":"Phase 2","title":"Define GatewayCustodyProofPacket schema and input","owner":"protocol-owner","rationale":"Customer-owned custody needs one provider-neutral, redaction-first packet that binds existing custody primitives by digest without creating authority.","depends_on":["custody-010"],"acceptance":["Packet schema includes credential ref digest, posture digest, bypass probe digests, provider registry digest, resolver version, lease/version, attestation digests, redacted audit digest, drift status, claim level, redaction status, and external verification status","Schema rejects raw credentials, secret paths, signer material, PaymentPayload, PAYMENT-SIGNATURE, bearer tokens, mutation credentials, and access-token-looking values","Digest changes when any authority-relevant packet field changes"],"candidate_paths":["src/protocol/areas/credential-custody/schemas.ts","src/protocol/areas/credential-custody/inputs.ts","test/protocol/credential-custody.test.ts"],"non_goals":["Do not add x402-specific payment fields to the generic packet","Do not store or resolve secrets"]} -{"id":"custody-030","priority":"P0","phase":"Phase 2","title":"Implement source-owned packet transition and record wiring","owner":"protocol-owner","rationale":"The packet must be source-owned evidence recorded from loaded refs/posture/probes, not caller-supplied prose.","depends_on":["custody-020"],"acceptance":["Transition loads and verifies GatewayCredentialRef and ProtectedPathPosture scope agreement","Transition requires fresh gateway_checked posture and accepted-source bypass probe coverage","Transition records packet and event through the source-owned object/store pattern","Transition never retrieves or stores secret material"],"candidate_paths":["src/protocol/areas/credential-custody/transitions.ts","src/protocol/areas/credential-custody/custody-posture.ts","src/protocol/areas/object-registry","src/protocol/public/schemas.ts","src/protocol/public/inputs.ts","src/storage/memory","src/storage/d1"],"non_goals":["Do not create a custody approval or custody greenlight","Do not add hosted provider operation"]} -{"id":"custody-040","priority":"P0","phase":"Phase 3","title":"Bind custody packet into contract, policy, and gateway checks","owner":"protocol-owner","rationale":"Custody proof is Handshake only if policy and gateway refuse missing, stale, drifted, unsafe, or redaction-failed packet state before mutation.","depends_on":["custody-030"],"acceptance":["Credential-backed actions bind custody packet id/digest with the credential ref","Policy refuses missing packet, digest mismatch, stale packet, provider drift, resolver drift, unsafe custody, weak source authority, failed probes, raw sibling, isolation, and redaction failure","Gateway revalidates current packet/ref/posture before mutation and records packet refs/digests seen or equivalent tested posture digest binding","No mutation attempt or downstream success is recorded for pre-mutation custody refusal"],"candidate_paths":["src/protocol/areas/policy-greenlight/transitions.ts","src/protocol/areas/gateway-gate/schemas.ts","src/protocol/areas/gateway-gate/artifacts.ts","src/protocol/areas/gateway-gate/transitions.ts","src/protocol/areas/credential-custody/transitions.ts","test/protocol/kernel-policy-gateway.test.ts"],"non_goals":["Do not create a parallel policy evaluator","Do not allow one greenlight to authorize multiple mutations"]} -{"id":"custody-050","priority":"P1","phase":"Phase 4","title":"Integrate x402 signer custody through generic credential refs and packet binding","owner":"x402-adapter-owner","rationale":"x402 is the first wedge, but it must prove the generic custody primitive instead of becoming payment infrastructure.","depends_on":["custody-040"],"acceptance":["x402 install/proposal binds signer custody through GatewayCredentialRef plus custody packet digest","Signer is called only after VerifiedGatewayCheck and valid packet/ref/posture state","Redacted CredentialResolutionEvidence is recorded after the passed gate","Fixture custody projects as local_fixture and cannot satisfy customer/provider custody claims","No wallet custody, balances, settlement, facilitator, seller middleware, aggregate spend, or payment-management state is added"],"candidate_paths":["src/adapters/x402-payment/install-proposal.ts","src/adapters/x402-payment/action-proposal.ts","src/adapters/x402-payment/wallet-gateway.ts","src/adapters/x402-payment/bypass-probes.ts","src/adapters/x402-payment/conformance.ts","test/adapters/x402-wallet-gateway.test.ts","test/adapters/x402-bypass-probes.test.ts","test/conformance/x402-payment-conformance.test.ts"],"non_goals":["Do not broaden x402 compatibility","Do not claim live provider custody from fixtures"]} -{"id":"custody-060","priority":"P1","phase":"Phase 5","title":"Apply auth.md lifecycle, isolation, and redaction parity","owner":"auth-adapter-owner","rationale":"auth.md has the right pattern for credential refs, revocation drift, post-gate resolution, and redaction without turning Handshake into an auth provider.","depends_on":["custody-040"],"acceptance":["auth.md custody-backed calls can bind the same packet shape when required","Revocation, metadata drift, stale ref, scope drift, resolver failure, token replay, raw bearer passthrough, unsafe retry, and redaction failure refuse before downstream call","CredentialResolutionEvidence remains post-gate only"],"candidate_paths":["src/adapters/auth-md/profiles.ts","src/adapters/auth-md/gateway.ts","src/adapters/auth-md/revocation.ts","src/adapters/auth-md/bypass-probes.ts","test/adapters/auth-md-gateway-pressure.test.ts","test/adapters/auth-md-serialization-redaction.test.ts"],"non_goals":["Do not add OAuth, identity-provider, auth-provider, or generic API gateway claims","Do not expose bearer material or raw credentials"]} -{"id":"custody-070","priority":"P1","phase":"Phase 6","title":"Add redacted custody projection","owner":"projection-owner","rationale":"Adoption depends on a buyer-readable packet that reconstructs custody by digest without exposing credential material.","depends_on":["custody-040"],"acceptance":["Projection exposes custody packet, credential ref, posture, contract, greenlight, gateway check, credential resolution, mutation/refusal/proof-gap refs and digests","Projection includes claim level, drift status, redaction status, external verification status, omitted fields, and reason codes","Projection omits secret paths, signer material, raw key handles, PaymentPayload, PAYMENT-SIGNATURE, bearer tokens, mutation credentials, payment payloads, authorization headers, claim tokens, JWTs, PII, and provider secret coordinates"],"candidate_paths":["src/protocol/evidence-projections/projections.ts","src/protocol/evidence-projections/assembly.ts","src/protocol/evidence-projections/schemas.ts","test/protocol/evidence-projections.test.ts"],"non_goals":["Do not expose raw packet browsing as buyer proof","Do not smooth redaction failure into success"]} -{"id":"custody-080","priority":"P1","phase":"Phase 7","title":"Update canonical docs and claim guards after source proof exists","owner":"docs-and-architecture-owner","rationale":"Product language must not exceed enforcement. Docs can change only after packet, negative tests, and projection behavior exist.","depends_on":["custody-050","custody-060","custody-070"],"acceptance":["Canonical docs describe customer-owned gateway custody as protected-action custody proof, not payment custody or x402 protocol meaning","Claim guards reject provider/customer custody from fixtures, Handshake-held payment custody, hosted trust, broad x402 compatibility, marketplace/certification/clearing-house readiness, and broad runtime control","Provider-specific vault/KMS/wallet details are marked as requiring official source verification before implementation"],"candidate_paths":["README.md","docs/internal/decisions.md","docs/internal/protocol-definition.md","docs/internal/protocol-kernel-architecture.md","docs/internal/protocol-layman.md","docs/internal/protocol-notes.md","test/architecture/claim-boundary.test.ts","test/architecture/import-posture.test.ts","test/architecture/root-exports.test.ts"],"non_goals":["Do not promote .planning labels into source or package scripts","Do not write provider setup docs from repo source alone"]} -{"id":"custody-090","priority":"P0","phase":"Phase 8","title":"Run focused and full closeout gates","owner":"executor","rationale":"The slice is complete only when enforcement, redaction, claims, and repo quality gates pass together.","depends_on":["custody-080"],"acceptance":["Focused protocol, projection, x402, auth.md, and architecture tests pass","quality:claims and quality:architecture pass","format/check/type/lint/test/pack/check:repo closeout passes or blockers are recorded with exact evidence","Closeout distinguishes existing evidence from planned evidence"],"candidate_paths":["test/protocol/credential-custody.test.ts","test/protocol/kernel-policy-gateway.test.ts","test/protocol/evidence-projections.test.ts","test/adapters/x402-wallet-gateway.test.ts","test/adapters/x402-bypass-probes.test.ts","test/conformance/x402-payment-conformance.test.ts","test/adapters/auth-md-gateway-pressure.test.ts","test/adapters/auth-md-serialization-redaction.test.ts","test/architecture/claim-boundary.test.ts","test/architecture/import-posture.test.ts","test/architecture/root-exports.test.ts"],"non_goals":["Do not stage or commit from the planning run","Do not claim completion if provider-specific verification remains required for live custody"]} diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/VALIDATION.md deleted file mode 100644 index 4320f28..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/VALIDATION.md +++ /dev/null @@ -1,104 +0,0 @@ -# Validation - -## Proof Obligations - -- Customer/provider gateway custody is evidenced by source-owned packet refs/digests, not prose. -- The packet is required by policy and gateway checks for custody-backed protected paths. -- Exact contract, policy decision, greenlight, gateway check, credential resolution, mutation/refusal/proof-gap, and downstream reconciliation remain distinct. -- Redaction failure refuses or records proof gap; it never serializes raw custody material. -- Fixture custody cannot satisfy provider/customer custody claims. -- Provider-specific custody details are blocked until official source verification. - -## Focused Tests - -### Protocol - -- `test/protocol/credential-custody.test.ts` - - packet schema rejects raw private keys, bearer tokens, `PaymentPayload`, `PAYMENT-SIGNATURE`, provider secret paths, raw signer refs, mutation credentials, payment payloads, and access-token-looking fields. - - packet digest changes with credential ref digest, protected-path posture digest, bypass probe digests, provider registry digest, resolver version, lease/version, attestation digest, redacted audit digest, drift status, redaction status, and expiry. - - packet cannot bind mismatched tenant/org/gateway/action/resource scope. - - fixture custody projects as `local_fixture` and cannot satisfy customer/provider claim level. - -- `test/protocol/kernel-policy-gateway.test.ts` - - policy refuses missing packet, digest mismatch, stale packet, stale credential ref, provider drift, resolver drift, unsafe custody, weak source authority, failed probe, raw sibling present, active isolation, and redaction failure. - - gateway refuses the same conditions after greenlight and before mutation. - - replay cannot reuse a greenlight for another credential resolution or mutation. - - gateway evidence records packet refs/digests seen or proves posture digest includes packet digest and drift state. - -- `test/protocol/evidence-projections.test.ts` - - custody projection includes refs/digests/status/reason codes only. - - projection distinguishes gateway check, credential resolution, mutation attempt, downstream reconciliation, refusal, and proof gap. - - projection omits secret paths, signer material, raw key handles, `PaymentPayload`, `PAYMENT-SIGNATURE`, bearer tokens, payment payloads, mutation credentials, authorization headers, claim tokens, JWTs, PII, and provider secret coordinates. - -### x402 - -- `test/adapters/x402-wallet-gateway.test.ts` - - signer call count is zero on missing/stale/drifted/unsafe packet, raw sibling posture, replay, params mismatch, policy drift, or failed gateway check. - - signer use occurs only after `VerifiedGatewayCheck`. - - redacted credential resolution evidence is recorded after a passed gate and bound to exact contract, greenlight, gateway check, credential ref, and packet. - -- `test/adapters/x402-bypass-probes.test.ts` - - direct signer SDK, raw payment signature header, paid fetch/axios, MCP direct payment, token passthrough, wrapper drift, and failure-open posture fail closed. - -- `test/conformance/x402-payment-conformance.test.ts` - - x402 remains one buyer-side exact protected action per call. - - no balance, settlement, facilitator, seller middleware, broad compatibility, or payment-management claim is introduced. - -Add `test/adapters/x402-install-proposal.test.ts` and `test/adapters/x402-payment-action-proposal.test.ts` if existing test ownership cannot cover install/proposal binding. - -### auth.md - -- `test/adapters/auth-md-gateway-pressure.test.ts` - - revocation, metadata drift, stale credential ref, scope drift, resolver failure, raw bearer passthrough, token replay, direct HTTP/browser/network/MCP path, and unsafe retry refuse before downstream service call. - -- `test/adapters/auth-md-serialization-redaction.test.ts` - - auth-derived custody evidence never exposes bearer material, claims, tokens, raw credentials, or secret paths. - -### Architecture And Claims - -- `test/architecture/claim-boundary.test.ts` - - provider/customer custody claims fail when sourced from fixture keys. - - Handshake-held wallet/payment credential/balance/settlement/payment-management language fails. - - x402-as-protocol, broad compatibility, seller/facilitator, marketplace, certification, clearing-house, hosted trust, and broad runtime-control claims fail. - -- `test/architecture/import-posture.test.ts` - - runtime/MCP/CLI/SDK/projection surfaces cannot import or issue policy, greenlight, gateway check, receipt, credential resolution, signer, wallet, or raw custody internals. - -- `test/architecture/root-exports.test.ts` - - root exports do not expose secret resolution, signer, wallet, raw custody internals, or provider-specific secret coordinates. - -## Closeout Commands - -Focused: - -```bash -npm run test -- test/protocol/credential-custody.test.ts test/protocol/kernel-policy-gateway.test.ts -npm run test -- test/protocol/evidence-projections.test.ts -npm run test -- test/adapters/x402-wallet-gateway.test.ts test/adapters/x402-bypass-probes.test.ts -npm run test -- test/conformance/x402-payment-conformance.test.ts -npm run test -- test/adapters/auth-md-gateway-pressure.test.ts test/adapters/auth-md-serialization-redaction.test.ts -npm run test -- test/architecture/claim-boundary.test.ts test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts -npm run quality:claims -npm run quality:architecture -``` - -Full: - -```bash -npm run check:types -npm run lint -npm run format:check -npm run test -npm run pack:check -git diff --check -npm run check:repo -``` - -## End Criteria - -- Packet schema, canonicalization, transition, policy binding, gateway binding, x402 integration, auth.md parity, and projection tests pass. -- x402 signer cannot execute unless a valid packet/ref/posture/greenlight/gateway check chain exists. -- Credential resolution evidence is post-gate only. -- Redacted projection is reconstructable by digest and contains no secret-bearing material. -- Claim guards prevent overclaiming fixture custody, provider custody, payment custody, hosted trust, broad x402 compatibility, marketplace/certification, clearing-house readiness, or broad runtime control. -- Provider-specific details remain marked as requiring official source verification unless that verification has been performed in a later pass. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/input.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/input.md deleted file mode 100644 index b7b839d..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/input.md +++ /dev/null @@ -1,178 +0,0 @@ -# Macro Plan Input: Customer-Owned Gateway Custody Proof - -Run ID: `customer-owned-gateway-custody-proof-20260524T071623Z` - -## Target - -Create a source-grounded macro plan for critical-path item 1 from `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md`: **Customer-Owned Gateway Custody Proof**. - -Goal: define the implementation path for proving a protected path is real because the mutation credential lives behind a customer/provider gateway that enforces the exact greenlight before consequence. - -The desired mechanism from the active register: - -```text -gateway install evidence --> credential ref binding --> protected-path posture --> custody/bypass probe packet --> gateway check binds exact contract --> redacted custody projection -``` - -## User Constraints - -- Use `$gsd-macro-plan` as a subagent-first workflow. -- This is planning only. Do not implement source changes under this run. -- Handshake is protected actions for automated decision making, not just engineering agents. -- x402 is the first wedge, but x402 must not define the protocol. -- Keep Tier 1 protocol/kernel meaning stable. -- Preserve customer-owned gateway custody as the enforcement model. -- Do not introduce Handshake-held wallets, payment credentials, balances, settlement state, or payment management. -- Do not claim live provider/customer custody until a source-owned custody proof packet, negative tests, and redacted projections exist. -- Do not add provider-specific vault/KMS architecture without marking official-doc/source verification as required before implementation. - -## Source Boundary - -Allowed source files for first-pass agents: - -- `AGENTS.md` -- `README.md` -- `QUALITY.md` -- `STRUCTURE.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-layman.md` -- `docs/internal/protocol-notes.md` -- `.planning/macro/README.md` -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` -- `.planning/macro/active/claim-boundary-cleanup/PLAN.md` -- `.planning/codebase/ARCHITECTURE.md` -- `.planning/codebase/CONCERNS.md` -- `.planning/codebase/CONVENTIONS.md` -- `.planning/codebase/INTEGRATIONS.md` -- `.planning/codebase/STACK.md` -- `.planning/codebase/STRUCTURE.md` -- `.planning/codebase/TESTING.md` -- `src/protocol/areas/credential-custody/schemas.ts` -- `src/protocol/areas/credential-custody/inputs.ts` -- `src/protocol/areas/credential-custody/custody-posture.ts` -- `src/protocol/areas/credential-custody/transitions.ts` -- `src/protocol/areas/protected-path-posture/schemas.ts` -- `src/protocol/areas/protected-path-posture/inputs.ts` -- `src/protocol/areas/protected-path-posture/transitions.ts` -- `src/protocol/areas/gateway-gate/schemas.ts` -- `src/protocol/areas/gateway-gate/inputs.ts` -- `src/protocol/areas/gateway-gate/artifacts.ts` -- `src/protocol/areas/gateway-gate/transitions.ts` -- `src/protocol/areas/policy-greenlight/transitions.ts` -- `src/protocol/evidence-projections/projections.ts` -- `src/protocol/evidence-projections/assembly.ts` -- `src/adapters/x402-payment/install-proposal.ts` -- `src/adapters/x402-payment/wallet-gateway.ts` -- `src/adapters/x402-payment/bypass-probes.ts` -- `src/adapters/x402-payment/conformance.ts` -- `src/adapters/auth-md/profiles.ts` -- `src/adapters/auth-md/gateway.ts` -- `src/adapters/auth-md/revocation.ts` -- `src/adapters/auth-md/bypass-probes.ts` -- `src/adapters/protected-path-probes` -- `test/protocol/credential-custody.test.ts` -- `test/protocol/evidence-projections.test.ts` -- `test/protocol/kernel-policy-gateway.test.ts` -- `test/adapters/x402-wallet-gateway.test.ts` -- `test/adapters/x402-bypass-probes.test.ts` -- `test/adapters/auth-md-gateway-pressure.test.ts` -- `test/adapters/auth-md-serialization-redaction.test.ts` -- `test/conformance/x402-payment-conformance.test.ts` -- `test/architecture/claim-boundary.test.ts` -- `test/architecture/import-posture.test.ts` -- `test/architecture/root-exports.test.ts` - -Forbidden files for first-pass agents: - -- sibling raw outputs under this run; -- normalized outputs under this run; -- the final `PLAN.md` for this run before chair synthesis; -- unrelated historical `.planning/macro/archive/**` files unless a specific current source file links to them; -- source files not listed above unless the agent first records why the listed source packet is insufficient. - -## Required Output Directory - -All artifacts for this item must stay under: - -```text -.planning/macro/active/customer-owned-gateway-custody-proof/ -``` - -First-pass outputs: - -```text -.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/STRATEGY.md -.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/ARCH.md -.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/EXECUTION.md -.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/RISK.md -.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/ADOPTION.md -``` - -Chair outputs: - -```text -.planning/macro/active/customer-owned-gateway-custody-proof/PLAN.md -.planning/macro/active/customer-owned-gateway-custody-proof/CONTEXT.md -.planning/macro/active/customer-owned-gateway-custody-proof/ASSUMPTIONS.md -.planning/macro/active/customer-owned-gateway-custody-proof/DECISIONS.md -.planning/macro/active/customer-owned-gateway-custody-proof/RISKS.md -.planning/macro/active/customer-owned-gateway-custody-proof/VALIDATION.md -.planning/macro/active/customer-owned-gateway-custody-proof/TASKS.jsonl -.planning/macro/active/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/synthesis.md -``` - -## Plan Requirements - -The chair plan must include: - -- goal; -- non-goals; -- source boundary; -- current state; -- target state; -- assumptions; -- decisions; -- phases; -- task graph; -- risks and mitigations; -- validation gates; -- cut lines; -- rollback / stop conditions; -- smallest next action. - -The plan must explicitly cover: - -- whether to extend existing `GatewayCredentialRef`, `CredentialResolutionEvidence`, `ProtectedPathPosture`, and bypass probe primitives or add a new proof packet primitive; -- custody proof packet schema shape and digest binding; -- binding custody proof to protected-path posture, action contract, policy/greenlight, gateway check, and redacted projections; -- provider-neutral fields for custody provider, key handle, lease/version, attestation refs, resolver version, redacted audit refs, and drift status; -- negative tests for agent-exposed signer, stale credential ref, provider drift, resolver failure, missing custody packet, unsafe custody status, redaction failure, and raw sibling path; -- how x402 uses the custody proof without broadening into payment management or provider custody claims; -- how auth.md learnings around credential refs, revocation, and redaction inform this mechanism without turning Handshake into an auth provider; -- projection redaction rules that never expose secret paths, signer material, payment payloads, bearer tokens, or mutation credentials; -- claim guards preventing provider/customer custody claims from fixture keys; -- external verification that must happen later for any named vault/KMS/provider custody implementation. - -## Success Criteria - -- The macro plan is executable as a future implementation slice without altering Tier 1 protocol meaning. -- The plan strengthens the enforcement story for protected actions while preserving customer-owned custody and avoiding Handshake-held payment custody. -- Each task names source/test/doc candidate paths and closeout evidence. -- `TASKS.jsonl` parses as JSONL. -- Validation gates are specific enough to fail stale custody, drift, redaction, and unsafe signer exposure. -- The plan names antipatterns and stop conditions. - -## External Verification - -Do not browse by default for this planning pass. If a perspective proposes a named vault, KMS, wallet provider, x402 provider, JWKS, Cloudflare, npm, MCP Registry, legal, or payment-regulatory detail, it must mark that detail as requiring official source verification before implementation. Provider-neutral schema planning may proceed from repo source only. - -## 10 Star Product Bar - -Custody proof is successful when a buyer can see that the automated decision system never received the mutation credential, the customer-owned gateway had the credential, the exact greenlight was checked immediately before mutation, drift/stale/unsafe custody refuses before consequence, and the surviving evidence is redacted but reconstructable. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/ADOPTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/ADOPTION.md deleted file mode 100644 index 8e8eb70..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/ADOPTION.md +++ /dev/null @@ -1,196 +0,0 @@ -# ADOPTION First Pass: Customer-Owned Gateway Custody Proof - -## Invariant At Stake - -A buyer must not be asked to trust a "gateway-protected" claim unless the first-use evidence shows: - -- the automated decision system never received the mutation credential; -- the customer/provider gateway held or resolved the credential behind its boundary; -- the exact one-use greenlight was checked immediately before mutation; -- stale, drifted, unsafe, missing, or bypassable custody refused before consequence; -- the surviving packet is redacted but reconstructable. - -If the buyer has to infer custody from scattered internal records, this is not adoption-ready. It may be source-true for a maintainer and still unreadable to an operator. - -## Source Posture For Adoption - -Current source already has adoption-relevant building blocks: - -- `GatewayCredentialRef` records opaque gateway-side custody without raw credential material. -- `CredentialResolutionEvidence` can be recorded only after a passed `GatewayCheckAttempt` and binds the exact contract, greenlight, gate attempt, credential ref digest, resolver metadata, request digest, redaction status, and result class. -- `ProtectedPathPosture` requires `gateway_checked` posture to be fresh, scope-bound, probe-backed, and backed by gateway/hosted-monitor-strength source authority. -- Policy and gateway evaluation both consult protected-path posture and credential-ref binding before authority proceeds. -- `GatewayCheckAttempt`, `MutationAttempt`, `Receipt`, `Refusal`, and `ProofGap` already distinguish gateway admission from downstream outcome. -- Redacted projections expose contract, agent transaction envelope, receipt timeline, idempotency recovery, and install health without raw signer, payment payload, bearer token, or provider secret-path material. -- x402 proves one local/reference buyer-side `x402_payment.exact` path with gateway signing only after `VerifiedGatewayCheck`. -- auth.md proves useful lifecycle lessons: credential refs, metadata/revocation drift, gateway-time credential resolution, isolation, and redaction without making Handshake an auth provider. - -Current source does not yet give the buyer one custody proof packet that ties install evidence, credential ref, posture/probes, exact contract, policy/greenlight, gateway check, credential resolution, and redacted projection into a single first-use artifact. That is the adoption blocker this plan must remove. - -## Adoption Path - -1. **Buyer chooses one protected path.** - Start with one tenant/org, one principal, one runtime, one action class, one gateway, and one resource. For the first wedge, use one buyer-side `x402_payment.exact` per-call path. Do not teach x402 as the protocol and do not teach aggregate payment-budget management. - -2. **Customer/operator installs the gateway boundary.** - The operator declares the gateway authority holder, protected surface, resource namespace, accepted action classes, policy version, enforcement mode, credential custody status, and resolver version. The mutation credential remains behind the customer/provider gateway. Handshake receives only opaque refs, digests, and redacted audit refs. - -3. **Developer compiles install records.** - The install path produces tool capability, action type, gateway registry entry, and operating envelope records. It must also produce or reference the future custody proof packet. Install refusal must be normal when the signer/credential is agent-exposed, bounds are wildcarded, resources are outside envelope, or provider evidence is incomplete. - -4. **Gateway records credential ref binding.** - Register `GatewayCredentialRef` with provider-neutral fields: custody provider class, credential kind, key/credential handle ref, provider registry ref/digest, resolver ref/version, lease or expiry, evidence expectation refs, redaction profile, and explicit `secretMaterialIncluded: false`. The contract later binds the ref ID and digest. - -5. **Gateway or hosted monitor runs hostile probes.** - Required probe kinds: credential custody, raw sibling blocking, MCP direct-call blocking, token passthrough blocking, wrapper drift, and failure-closed behavior. A `gateway_checked` posture should not be accepted from weak fixture-only or caller-reported evidence. If source authority is too weak, adoption should show a refusal, not a yellow success. - -6. **Protected-path posture is recorded.** - Create a fresh `ProtectedPathPosture` scoped to runtime, gateway, action class, resource, and protected surface. It must carry `postureState: "gateway_checked"`, safe credential custody, raw sibling absent/blocked, probe IDs, probe digests, and expiry. - -7. **Runtime proposes, but does not authorize.** - Runtime/MCP/CLI may help the developer propose the exact action. They must not hold signer material, evaluate policy, create greenlights, run gateway checks, mutate, export receipts, or mint certificates. - -8. **Policy refuses or greenlights from current custody state.** - Policy input must include the contract digest, protected-path posture digest/freshness, gateway credential ref binding, isolation snapshot, and idempotency state. Missing, stale, unsafe, drifted, or isolated custody refuses before any greenlight. - -9. **Gateway checks immediately before consequence.** - The gateway verifies the exact contract/greenlight/params/idempotency/posture/policy drift/credential binding. If passed, adapter mutation-side code receives `VerifiedGatewayCheck`. If not passed, no credential resolution and no mutation-side call occur. - -10. **Gateway records post-gate custody evidence.** - Credential resolution evidence is recorded only after a passed gate and must state whether the credential was resolved, used, refused, blocked by isolation, or became a proof gap. Redaction failure is a refusal/proof-gap path, not a best-effort warning. - -11. **Buyer reads one redacted custody proof packet.** - The packet should answer, without exposing secrets: who owned the gateway, what credential ref was expected, what probes passed, what exact contract was greenlit, what the gateway saw, whether the credential was resolved/used after the gate, what downstream evidence exists, and what proof gaps or refusals remain. - -## First-Use Checklist - -- Pick one action class: first wedge should be `x402_payment.exact`. -- Name the protected resource exactly: endpoint URL, network, payee, token, amount, request posture, selected payment requirement digest, and idempotency material. -- Name the customer/operator gateway authority holder and gateway ID. -- Verify the mutation credential is not available to the agent/runtime, MCP tool, browser path, shell path, environment, sibling wrapper, or direct SDK client. -- Register the gateway registry entry with enforcement mode, policy version, credential custody status, and authority holder. -- Register an opaque `GatewayCredentialRef`; reject any raw private key, bearer token, `PaymentPayload`, `PAYMENT-SIGNATURE`, provider secret path, or access-token-looking value. -- Run all required hostile probes and keep the probe evidence refs redacted. -- Record `ProtectedPathPosture` only after all required probes pass from an accepted source authority. -- Compile one runtime proposal and one exact `ActionContract`; ensure the contract binds the gateway credential ref digest. -- Evaluate policy and confirm either a one-use greenlight or a durable refusal. -- Run the gateway check with gateway-observed parameters, not runtime-trusted parameters. -- Confirm a replay of the same greenlight refuses before mutation. -- Record `CredentialResolutionEvidence` only after the passed gate. -- Read the redacted custody proof packet and verify it does not expose secret paths, signer material, payment payloads, bearer tokens, mutation credentials, raw authorization headers, claim tokens, JWTs, or PII. -- Run negative-path checks for agent-exposed signer, stale credential ref, provider drift, resolver failure, missing custody packet, unsafe custody status, redaction failure, raw sibling path, and weak source authority. - -## Missing Docs And Examples - -- A buyer/operator "customer-owned gateway custody proof" quickstart is missing. Candidate future path: `examples/customer-owned-gateway-custody-proof/README.md`. It should teach the one-path install, probes, posture, proposal, policy, gateway check, resolution evidence, replay refusal, and redacted packet readback. -- A machine-readable example packet is missing. Candidate future path: `examples/customer-owned-gateway-custody-proof/output/latest.json`. It should include refs/digests, not raw records or secrets. -- A buyer-readable Markdown packet is missing. Candidate future path: `examples/customer-owned-gateway-custody-proof/output/latest.md`. It should be readable by a security/operator buyer without knowing protocol internals. -- `README.md` should eventually expose the smallest custody proof command or walkthrough only after the packet exists. Do not add a hosted/provider custody claim. -- `docs/internal/protocol-definition.md` and `docs/internal/protocol-kernel-architecture.md` should eventually name the custody proof packet or explicitly say it is a redacted projection over existing records. Do not change Tier 1 object meaning. -- `docs/internal/protocol-layman.md` needs the operator explanation: "the gateway had the credential; the agent did not; this exact pass was checked before use." -- x402 walkthrough docs need a custody-proof subsection that keeps local/reference fixture status visible and refuses provider/customer custody claims from fixture keys. -- Support/debug docs are missing for reason-code-to-fix mapping: `gateway_credential_ref_missing`, `gateway_credential_ref_stale`, `gateway_credential_ref_provider_drift`, `gateway_credential_ref_unsafe_custody`, `protected_path_probe_failed`, `protected_path_source_authority_weak`, `protected_path_raw_sibling_tool_present`, `gateway_policy_drift`, `params_mismatch`, `already_consumed`, `redaction_failed`, and downstream proof-gap reasons. -- Provider-specific vault/KMS/wallet setup docs must not be written from repo source alone. They require official source verification before implementation. - -## Success Metrics - -- A developer can produce the first local/reference custody proof packet from a clean checkout with one documented command or short checklist. -- A buyer can answer five questions from the packet without reading source: Did the agent receive the credential? Who held it? What exact contract was greenlit? Did the gateway check it before mutation? What evidence is missing or redacted? -- Every unsafe custody path produces a named refusal or proof gap before mutation. -- Negative tests cover all required custody failure classes and assert zero credential resolution and zero mutation when pre-gate evidence fails. -- Redacted packet serialization contains no raw credential material under current x402/auth.md secret patterns. -- Support can map every custody failure reason code to an operator action. -- Claim guards fail if docs/examples imply live provider custody, Handshake-held wallets/payment credentials, hosted operation, settlement, aggregate spend enforcement, generic MCP/runtime protection, or broad x402 compatibility. -- The first-use path does not require all-role SDK clients, raw protocol record reads, or direct adapter internals. - -## Adoption Blockers And Fixes - -| Blocker | Why it blocks adoption | Fix | -| --- | --- | --- | -| Custody evidence is scattered across refs, posture, probes, gate, resolution, receipt, and projections. | Buyers cannot verify custody without protocol expertise. | Add a redacted custody proof packet or projection that assembles the chain and exposes digest-bound refs. | -| The packet primitive is not source-owned yet. | Docs would have to describe an implied artifact. That becomes evidence theatre. | Define packet schema or projection contract before buyer docs. | -| Gateway setup ceremony is long. | Integrators may skip probes/posture or move authority into runtime/MCP for convenience. | Build an activation helper that sequences existing calls while keeping policy, greenlight, gateway check, signer/custody, and mutation authority out of runtime/MCP. | -| x402 local fixture can be mistaken for live custody. | Fixture keys and local sandbox evidence do not prove provider/customer custody. | Keep fixture/local/reference status in packet and claim guards; require official provider verification before live custody docs. | -| Provider-neutral custody fields are incomplete for buyer language. | A buyer needs key handle, lease/version, attestation refs, resolver version, audit refs, and drift status in one place. | Add these to the packet, reusing `GatewayCredentialRef` where possible and adding packet-level fields only where the existing ref is not enough. | -| Source-authority expectations can confuse implementers. | `gateway_checked` posture is accepted only from gateway/hosted-monitor-strength evidence; weaker fixture/caller evidence must refuse. | Document accepted source authorities and add tests that weak source authority refuses with a readable reason. | -| Runtime/MCP x402 posture parity gaps exist in the codebase map. | Proposal surfaces can teach weaker request-body/provider-environment semantics than the direct adapter path. | Use direct adapter/runtime-client path for first custody proof, then add runtime/MCP parity before exposing MCP as the first-use path. | -| Redaction is partly pattern-based. | Unknown provider credential formats can leak or force overbroad omission. | Prefer allowlisted packet fields and add provider-format fuzz tests before live provider custody. | -| Existing demos prove local/reference x402, not customer-owned custody. | The buyer may see "wallet gateway" and infer real customer/provider control. | Add explicit packet fields for `fixture_only`, `local_reference`, `customer_gateway_adapter`, or `provider_gateway` posture and fail claims from fixture-only packets. | -| Support/debug output is not organized around operator fixes. | A refusal is good protocol behavior but bad adoption if the operator cannot repair install state. | Add reason-code remediation table and packet-level `nextOperatorAction` labels. | - -## Assumptions - -- Tier 1 protocol meaning remains stable: exact contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof-gap, and isolation semantics do not change. -- Customer-owned gateway custody can be implemented as an additive packet/projection over existing primitives unless architecture proves a new protocol object is necessary. -- x402 remains the first wedge, but the custody mechanism must stay provider-neutral. -- Handshake does not hold wallets, signers, payment credentials, balances, settlement state, or payment-management state. -- Live provider/customer custody claims are blocked until source-owned packet, negative tests, redacted projections, and official provider verification exist. -- `.planning/` remains scratch and should not become repo-facing canon. - -## Dependencies - -- Existing protocol primitives: `GatewayCredentialRef`, `CredentialResolutionEvidence`, `ProtectedPathPosture`, `BypassProbe`, `ActionContract`, `PolicyDecision`, `Greenlight`, `GatewayCheckAttempt`, `Receipt`, `Refusal`, `ProofGap`, and `IsolationState`. -- Existing x402 adapter path: install proposal, action proposal, wallet gateway, hostile bypass probes, and conformance posture. -- Existing auth.md lessons: credential ref binding, metadata/revocation drift, post-gate credential resolution, lifecycle isolation, and redaction. -- Evidence projection assembly and redaction rules. -- Claim-boundary tests preventing fixture/local evidence from becoming provider/customer custody claims. -- Future official-source verification for any named vault, KMS, wallet provider, x402 provider, Cloudflare, JWKS, npm, MCP Registry, legal, or payment-regulatory details. - -## Risks - -- **Review theatre:** A pretty custody packet that is not structurally bound to the exact contract, policy input, greenlight, gateway check, and credential ref digest. -- **Evidence theatre:** A packet that cannot distinguish gateway check, credential resolution, mutation attempt, downstream response, refusal, and proof gap. -- **Fixture laundering:** Local fixture signer custody gets presented as customer/provider custody. -- **Runtime authority drift:** Activation convenience moves signer custody or gateway checks into runtime, MCP, CLI, or SDK surfaces. -- **Provider lock-in:** A provider-specific KMS/vault model leaks into protocol fields before official verification. -- **Redaction failure:** Unknown credential formats evade current string/pattern redaction. -- **Stale acceptance:** A custody proof packet remains accepted after provider registry digest, resolver version, lease, posture, or policy drift. -- **Support opacity:** Refusals are correct but not operator-actionable, causing teams to bypass the gateway. -- **x402 overreach:** The first wedge drifts into settlement, seller/facilitator operation, signed offers/receipts, aggregate spend windows, or broad compatibility. - -## Validation Gates - -- Schema/canonicalization tests for the custody proof packet or projection digest. -- Policy tests refusing missing packet, stale packet, unsafe custody, provider drift, resolver failure, weak source authority, failed probes, and active credential-ref isolation. -- Gateway tests refusing params drift, gateway policy drift, stale credential ref, missing credential ref, unsafe custody, replay, and raw sibling path before credential resolution or mutation. -- Adapter tests proving x402 signing receives only `VerifiedGatewayCheck`, and signing count remains zero on refusal/replay/drift. -- Redaction tests serializing the full packet and asserting absence of private keys, `PAYMENT-SIGNATURE`, `PaymentPayload`, bearer tokens, provider secret paths, raw authorization material, claim tokens, JWTs, and PII. -- Projection tests showing the packet distinguishes gateway admission from downstream outcome and proof gap. -- Claim-boundary tests preventing provider/customer custody claims from fixture keys and preventing Handshake-held wallet/payment-management language. -- Docs/example tests for the buyer-readable packet, including refusal and proof-gap paths, not only success. -- Focused future gates: `npm run quality:claims`, custody/projection protocol tests, x402 adapter/probe tests, auth.md redaction/gateway pressure tests, and architecture import/root export tests if public surfaces change. -- Full future closeout: `npm run check:repo`. - -## Cut Lines - -- No Handshake-held wallets, private keys, bearer tokens, payment credentials, balances, settlement state, or payment management. -- No provider-specific vault/KMS/wallet architecture without official source verification. -- No live provider/customer custody claim from local fixtures, local sandbox, conformance fixtures, or fixture keys. -- No aggregate x402 spend-window enforcement until a real ledger exists. -- No seller middleware, facilitator operation, settlement finality, signed offers, signed receipts, batch settlement, `upto`, or MCP auto-pay in this slice. -- No broad runtime, MCP, browser, shell, package-manager, cloud, repo, database, or network interception claim. -- No raw protocol record reads as the buyer-facing proof path. -- No all-role SDK or CLI/MCP mutation command in first-use docs. -- No greenlight reuse or multi-mutation authority. -- No "installed" or "protected" label unless current probe-backed posture and custody packet are present. - -## Antipatterns - -- "The gateway is trusted" without a gate attempt, credential ref digest, and probe-backed posture. -- "Approved plan" as a substitute for exact contract binding. -- "The signer is in a vault" with no resolver version, provider registry digest, lease/freshness, and post-gate resolution evidence. -- "Local fixture gateway-held" described as provider custody. -- "MCP payment tool" that can produce payment payloads or signatures. -- "Support mode" that exposes raw records, secret paths, signer refs, `PaymentPayload`, or bearer material. -- "One greenlight per workflow" instead of one greenlight per exact mutation attempt. -- "Downstream succeeded" inferred from a gateway check or receipt without reconciliation evidence. -- "Unknown" smoothed into success instead of a `ProofGap`. -- Docs that teach x402 as the protocol rather than the first protected-action pack. - -## Blocked Checks - -- No external official documentation was verified in this first pass. Any named provider, vault, KMS, x402 provider, Cloudflare, JWKS, npm, MCP Registry, legal, or payment-regulatory detail remains blocked on official source verification before implementation. -- Sibling raw outputs, normalized outputs, and the final plan for this run were not read, by instruction. -- No source, test, docs, package, or prior planning artifact was modified. -- No tests were run because this is a planning-only first-pass artifact with a hard write boundary. -- Unlisted example files were not inspected; missing docs/examples above are candidate future paths, not verified current contents. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/ARCH.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/ARCH.md deleted file mode 100644 index f8fc292..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/ARCH.md +++ /dev/null @@ -1,400 +0,0 @@ -# ARCH First-Pass Plan: Customer-Owned Gateway Custody Proof - -## Invariant at stake - -A protected path is real only when the mutation credential lives behind a customer or provider gateway, the exact one-use greenlight is checked immediately before consequence, stale or unsafe custody refuses before mutation, and the surviving evidence is redacted but reconstructable. - -If this work only adds a report, install label, fixture signer posture, or projection text, this is advisory, not Handshake. - -## Architecture implications - -The current source already has the authority spine needed for this slice: - -- `GatewayCredentialRef` is provider-neutral, opaque, digest-bound, scoped to tenant/org/gateway/action/resource, and rejects raw credential-looking material. -- `CredentialResolutionEvidence` is post-gate evidence only. It binds exact `ActionContract`, `Greenlight`, `GatewayCheckAttempt`, optional `MutationAttempt`, credential ref digest, resolver metadata, request digest, redaction status, and result class. -- `ProtectedPathPosture` is current-state evidence for runtime/gateway/action/resource. It already carries posture state, credential custody status, raw sibling status, bypass probe IDs/digests, source authority, expiry, and a posture digest. -- Policy evaluation and gateway check both re-read current protected-path posture and gateway credential bindings before greenlighting or admitting mutation. -- Gateway check records the contract digest, greenlight digest, params digest, protected-path posture seen, drift status, refusal/proof-gap/admission, and one-use greenlight consumption. -- Evidence projections already expose redacted contract evidence, agent transaction envelopes, credential refs/resolution evidence refs, receipt timelines, idempotency recovery, and protected-path install health. - -The missing architecture object is not another permission path. The gap is a source-owned custody proof packet that turns "gateway owns or controls the mutation credential" from a field assertion into digest-bound install evidence that can be: - -```text -gateway install evidence --> credential ref binding --> protected-path posture --> custody/bypass probe packet --> exact contract / policy input / greenlight / gateway check --> redacted custody projection -``` - -Without that packet, `GatewayCredentialRef.custodyStatus`, gateway registry custody status, and `ProtectedPathPosture.credentialCustodyStatus` are still too easy to treat as caller-reported posture. The current tests already reject weak posture source authority and fixture-only x402 custody, but there is no first-class custody packet digest tying install evidence, credential ref, posture, probes, resolver version, and redacted audit refs together. - -## Extend vs new primitive recommendation - -Add a new custody proof packet record inside the existing credential-custody/protected-path authority spine. Do not create a parallel authority primitive. - -Recommended shape: - -- Add a `GatewayCustodyProofPacket` or `CustomerGatewayCustodyProofPacket` schema and transition under `src/protocol/areas/credential-custody/`. -- Bind that packet into `GatewayCredentialRef` and `ProtectedPathPosture` by ID and digest. -- Include the packet digest in policy input and gateway-time revalidation through the existing protected-path posture and credential-ref checks. -- Extend redacted evidence projections to expose custody proof refs/digests/status, never raw provider paths or signer material. -- Keep `CredentialResolutionEvidence` post-gate. It must not become pre-gate install proof. - -Why not only extend existing fields: - -- Overloading `GatewayCredentialRef.evidenceExpectationRefs` leaves custody proof as loose refs with no typed drift semantics. -- Overloading `ProtectedPathPosture.evidenceRefs` lets a posture claim look current without proving which gateway install and credential ref it depended on. -- Overloading bypass probes alone proves hostile-path posture, not the customer-owned custody chain from gateway install to credential ref to resolver/version to redacted audit refs. - -Why not add a new top-level authority primitive: - -- The protocol primitive is still one exact contract, one policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap. -- Custody proof is evidence that a required protected path may be considered gateway-owned. It does not authorize mutation. -- Any new "custody approval", "custody greenlight", "wallet authorization", or "provider trust decision" would create a second permission plane. - -Brutal verdict: add a new proof packet record, but keep it subordinate to `GatewayCredentialRef`, `ProtectedPathPosture`, policy evaluation, and gateway check. - -## Proposed custody proof packet boundary - -The packet should be provider-neutral and redaction-first. - -Candidate fields: - -- `custodyProofPacketId` -- `custodyProofPacketDigest` -- `gatewayInstallEvidenceRef` -- `gatewayInstallEvidenceDigest` -- `gatewayCredentialRefId` -- `gatewayCredentialRefDigest` -- `gatewayId` -- `gatewayRegistryEntryId` -- `protectedSurfaceKind` -- `actionClasses` -- `resourceRefs` -- `custodyProviderClass` -- `custodyProviderRegistryRef` -- `custodyProviderRegistryDigest` -- `opaqueKeyHandleRef` -- `opaqueKeyHandleDigest` -- `credentialKind` -- `credentialCustodyStatus` -- `resolverRef` -- `resolverVersion` -- `leaseRef` -- `leaseVersion` -- `leaseIssuedAt` -- `leaseExpiresAt` -- `attestationRefs` -- `attestationDigests` -- `redactedAuditRefs` -- `redactedAuditDigest` -- `driftStatus`: `current | stale | provider_drift | resolver_drift | unsafe_custody | proof_gap` -- `bypassProbeIds` -- `bypassProbeDigests` -- `redactionProfileRef` -- `secretMaterialIncluded: false` -- `recordedAt` -- `expiresAt` - -The packet must reject raw credential material and provider secret paths in the same spirit as `GatewayCredentialRefSchema` and auth.md/x402 projection redaction. For live providers, use opaque handles and digests, not `vault://team/prod/secret`, private key refs, `PAYMENT-SIGNATURE`, `PaymentPayload`, bearer tokens, API keys, raw signer refs, or path-like secret coordinates. - -## Data and control flow - -### Install and proof recording - -```text -adapter install proposal --> gateway registry entry --> gateway credential ref --> custody proof packet --> bypass probes --> protected-path posture -``` - -The install path should compile or record the credential ref and proof packet before any `gateway_checked` posture can be accepted. For x402, this means the wallet/signer boundary becomes a gateway credential ref plus custody proof packet, not only `walletGatewayProfile.signerRef` on the gateway registry entry. - -For auth.md, the existing pattern is the model to copy: raw credential intake is adapter-local, registration/revocation evidence is redacted and digest-bound, and the protocol sees an opaque `GatewayCredentialRef`. - -### Policy - -Policy already includes: - -- protected-path posture input; -- gateway credential binding input; -- isolation state; -- sequence dependency state; -- idempotency state. - -The plan should extend policy input so custody proof is included through: - -- `GatewayCredentialRef` proof packet refs/digests; and/or -- `ProtectedPathPosture` proof packet refs/digests. - -Policy must refuse before greenlight when: - -- custody proof packet is missing; -- packet digest does not match the credential ref or posture binding; -- packet is stale or expired; -- packet drift status is unsafe; -- packet source authority is weak or fixture-only when a live/customer-owned claim is being made; -- redaction status is failed; -- credential ref is stale, provider-drifted, scope-mismatched, or isolated. - -### Gateway check - -Gateway check should keep its current role: exact final admission before mutation. - -The gateway check should re-read current custody packet state indirectly through current protected-path posture and credential binding, or directly if the implementation adds custody-proof lookup. It must refuse before mutation when the proof packet seen at policy time no longer matches current gateway custody state. - -The resulting `GatewayCheckAttempt` should either: - -- add `custodyProofPacketIdSeen`, `custodyProofPacketDigestSeen`, and `custodyProofDriftStatusSeen`; or -- keep the gateway record unchanged only if `protectedPathPostureDigestSeen` deterministically includes the custody proof packet digest and tests prove that drift changes the posture digest. - -The first option is more auditable. The second is smaller but risks hiding the custody proof inside a posture digest. - -### Resolution and mutation - -Credential resolution remains after a passed gateway check. The packet proves custody posture before authority; `CredentialResolutionEvidence` proves gateway-side credential resolution/use after authority admission. - -For x402: - -```text -verified gateway check --> gateway-held signing surface creates PaymentPayload / PAYMENT-SIGNATURE evidence --> redacted signature/payload digests recorded as evidence refs --> downstream sandbox/provider response becomes reconciliation or proof gap -``` - -Do not add Handshake-held wallets, balances, signer APIs, payment settlement state, facilitator operation, seller middleware, or aggregate spend state. - -### Projection - -Evidence projection should add a redacted custody projection rather than raw proof packet browsing. - -Candidate projection fields: - -- `custodyProofPacketRef` -- `custodyProofPacketDigest` -- `gatewayCredentialRef` -- `gatewayCredentialRefDigest` -- `gatewayId` -- `protectedSurfaceKind` -- `actionClasses` -- `resourceRefs` -- `custodyProviderClass` -- `custodyProviderRegistryDigest` -- `opaqueKeyHandleDigest` -- `resolverRef` -- `resolverVersion` -- `leaseVersion` -- `attestationDigests` -- `redactedAuditDigest` -- `driftStatus` -- `expiresAt` -- `redactionProfileRef` -- `omittedFields` - -This projection should be available to contract/agent transaction/install-health evidence without exposing secret paths, signer material, payment payloads, bearer tokens, mutation credentials, provider secret URIs, or raw audit payloads. - -## Boundaries that must not move - -- `src/protocol/areas/*` owns protocol meaning. Adapters can produce evidence and execute after `VerifiedGatewayCheck`; they must not define custody proof semantics alone. -- `src/runtime`, `src/mcp`, `src/cli`, and SDK role clients remain proposal/evidence/read surfaces. They must not record custody proof, resolve credentials, issue policy decisions, mint greenlights, run gateway checks, export receipts, or mutate. -- Gateway check remains the enforcement boundary before consequence. Custody proof cannot replace the exact contract or one-use greenlight. -- `GatewayCredentialRef` stays opaque and non-secret. No protocol API should retrieve secrets or expose provider secret paths. -- `CredentialResolutionEvidence` stays post-gate. It must not become permission or install proof. -- `ProtectedPathPosture` stays current and probe-backed. A caller-reported or fixture posture cannot satisfy customer-owned custody. -- x402 remains one buyer-side `x402_payment.exact` per-call protected action pack. It must not become payment management, wallet custody, balance tracking, facilitator operation, seller middleware, settlement, or broad x402 compatibility. -- auth.md learnings apply to credential refs, lifecycle isolation, redaction, and revocation evidence. They must not turn Handshake into an auth provider. -- `.planning/` remains scratch. Any durable doctrine belongs in compact canonical docs only after implementation proves it. - -## Likely source paths - -Protocol: - -- `src/protocol/areas/credential-custody/schemas.ts` -- `src/protocol/areas/credential-custody/inputs.ts` -- `src/protocol/areas/credential-custody/transitions.ts` -- `src/protocol/areas/credential-custody/custody-posture.ts` -- `src/protocol/areas/protected-path-posture/schemas.ts` -- `src/protocol/areas/protected-path-posture/inputs.ts` -- `src/protocol/areas/protected-path-posture/transitions.ts` -- `src/protocol/areas/policy-greenlight/transitions.ts` -- `src/protocol/areas/gateway-gate/schemas.ts` -- `src/protocol/areas/gateway-gate/artifacts.ts` -- `src/protocol/areas/gateway-gate/transitions.ts` -- `src/protocol/evidence-projections/projections.ts` -- `src/protocol/evidence-projections/assembly.ts` - -Adapter and probe surfaces: - -- `src/adapters/x402-payment/install-proposal.ts` -- `src/adapters/x402-payment/wallet-gateway.ts` -- `src/adapters/x402-payment/bypass-probes.ts` -- `src/adapters/x402-payment/conformance.ts` -- `src/adapters/auth-md/profiles.ts` -- `src/adapters/auth-md/gateway.ts` -- `src/adapters/auth-md/revocation.ts` -- `src/adapters/auth-md/bypass-probes.ts` -- `src/adapters/protected-path-probes/index.ts` -- `src/adapters/protected-path-probes/executor.ts` - -Likely additional implementation paths to verify before execution: - -- `src/protocol/areas/object-registry/*` -- `src/protocol/public/inputs.ts` -- `src/protocol/public/schemas.ts` -- `src/protocol/kernel.ts` -- `src/protocol/store/port.ts` -- `src/storage/d1/*` -- `src/storage/memory/*` -- `src/http/routes/*` -- `src/http/handlers/evidence-read.ts` -- `src/sdk/surface-clients/evidence-client.ts` -- `src/mcp/resources.ts` -- `src/cli/projection-evidence.ts` - -Docs: - -- `README.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-notes.md` -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` -- `.planning/macro/active/customer-owned-gateway-custody-proof/PLAN.md` after chair synthesis only - -Tests: - -- `test/protocol/credential-custody.test.ts` -- `test/protocol/evidence-projections.test.ts` -- `test/protocol/kernel-policy-gateway.test.ts` -- new or extended `test/protocol/customer-owned-gateway-custody-proof.test.ts` -- `test/adapters/x402-wallet-gateway.test.ts` -- `test/adapters/x402-bypass-probes.test.ts` -- `test/adapters/auth-md-gateway-pressure.test.ts` -- `test/adapters/auth-md-serialization-redaction.test.ts` -- `test/conformance/x402-payment-conformance.test.ts` -- `test/architecture/claim-boundary.test.ts` -- `test/architecture/import-posture.test.ts` -- `test/architecture/root-exports.test.ts` - -## Compatibility and migration risks - -- Adding required fields directly to `GatewayCredentialRef` or `ProtectedPathPosture` will break existing fixtures and stored records. Prefer additive nullable/default fields first, then tighten required status only for action contracts that require `gateway_checked` and custody proof. -- If custody proof affects `paramsDigest`, `policyInputDigest`, `postureDigest`, or contract digest, existing tests that assert exact duplicate/refusal behavior may need fixture updates. That is acceptable only if the digest change reflects real authority input. -- Existing x402 install proposals store signer posture on `walletGatewayProfile` and gateway registry metadata. Migrating x402 to protocol-level credential refs may require install compiler output changes beyond the allowed source packet. -- Current projection redaction is pattern-based with known gaps for unknown provider formats. Live provider custody claims need allowlisted projection fields and provider-format fuzz tests before they are credible. -- `CredentialResolutionEvidence` requires an existing passed gateway check. If implementation tries to use it for install custody, it will invert the state machine. -- Store/object registry/public aggregation paths were not in the allowed packet. A new protocol object type will likely require updates there before tests compile. -- D1 migration/index requirements are unknown from this packet. If custody proof needs first-class lookup by credential ref, gateway, tenant/org, or contract, storage indexes may be needed. -- Existing `sourceAuthorityCanSatisfyGatewayChecked` accepts `gateway_probe` and `hosted_monitor`. A custody proof packet must not backdoor `conformance_fixture` or `operator_attestation` into live customer-owned custody. -- x402 fixture tests currently distinguish `fixture_gateway_held` from real gateway-held posture. Preserve that distinction or claim guards will regress. - -## Architecture validation gates - -Protocol/schema gates: - -- Custody proof packet schema rejects raw private keys, bearer tokens, API keys, `PaymentPayload`, `PAYMENT-SIGNATURE`, raw signer refs, secret URIs, and provider secret paths. -- Custody proof packet digest changes when gateway install evidence, credential ref digest, resolver version, lease/version, attestation digest, redacted audit digest, or drift status changes. -- `GatewayCredentialRef` binds to the custody proof packet by ID/digest or refuses when a required proof packet is missing. -- `ProtectedPathPosture` digest includes custody proof packet ID/digest and all required bypass probe digests. -- Policy refuses missing custody packet, stale packet, provider drift, resolver drift, unsafe custody status, weak source authority, and redaction failure before greenlight. -- Gateway check refuses when custody proof or protected-path posture drifts after greenlight and before mutation. - -Adapter gates: - -- x402 install refuses `agent_exposed` signer custody and fixture-only posture for customer-owned custody claims. -- x402 gateway never calls the signer on params mismatch, replay, stale custody proof, missing custody proof, unsafe custody proof, provider drift, or raw sibling posture. -- x402 official SDK PaymentPayload / `PAYMENT-SIGNATURE` evidence remains post-gate, redacted, and local/reference unless official provider/customer custody verification is added later. -- auth.md gateway continues to record credential resolution after passed gate only and quarantines credential refs on revocation/lifecycle drift. - -Projection/redaction gates: - -- Contract/evidence projections expose custody proof refs and digests, not raw proof payloads or secret coordinates. -- Agent transaction envelope distinguishes gateway check evidence, custody proof evidence, credential resolution evidence, mutation evidence, downstream reconciliation, refusal, and proof gap. -- Redaction failure produces refusal or proof gap; it never serializes raw custody material. - -Architecture/claim gates: - -- Claim guards reject live provider/customer custody claims from fixture keys. -- Claim guards keep x402 as per-call exact protected action, not payment management or provider custody. -- Import posture keeps custody proof protocol meaning out of adapters, runtime, MCP, CLI, SDK, and projections. -- Root exports do not expose secret resolution, signer, wallet, or raw custody internals. - -Closeout command candidates: - -- `npm run test -- test/protocol/credential-custody.test.ts test/protocol/kernel-policy-gateway.test.ts test/protocol/evidence-projections.test.ts` -- `npm run test -- test/adapters/x402-wallet-gateway.test.ts test/adapters/x402-bypass-probes.test.ts test/adapters/auth-md-gateway-pressure.test.ts test/adapters/auth-md-serialization-redaction.test.ts` -- `npm run test -- test/conformance/x402-payment-conformance.test.ts` -- `npm run test -- test/architecture/claim-boundary.test.ts test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts` -- `npm run quality:claims` -- `npm run quality:architecture` -- `npm run check:repo` - -## Assumptions - -- Tier 1 protocol meaning remains stable: exact contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap. -- Customer-owned gateway custody is the enforcement model. Handshake does not hold wallets, signer credentials, balances, settlement state, or payment credentials. -- x402 is the first proof pack, not the protocol definition. -- Provider-neutral schema planning can proceed from repo source. Named vault/KMS/wallet/provider behavior requires official source verification before implementation. -- A custody proof packet can be added without requiring hosted operation. -- Existing object registry/store/public aggregation can accept a new object type, but this was not verified because those files were outside the packet. - -## Dependencies - -- Claim-boundary cleanup must land first or in parallel only if this plan keeps its non-claim language intact. -- The implementation needs a source-owned object-type route for custody proof packet records. -- Policy and gateway checks depend on current store lookup for credential refs, protected-path posture, isolation, and potentially custody proof packet records. -- x402 adapter changes depend on the install compiler being able to emit or sequence gateway credential refs and custody proof packets. -- Redacted projections depend on schema additions in evidence projection types not included in this packet. -- Provider-specific custody implementation depends on later official documentation/source verification for any named vault, KMS, wallet provider, x402 provider, JWKS, Cloudflare, or regulatory claim. - -## Risks - -- The proof packet becomes a decorative certificate. Mitigation: policy and gateway refuse when the packet is missing, stale, drifted, unsafe, or not bound to the exact credential ref/posture. -- The packet duplicates `GatewayCredentialRef` without adding enforcement. Mitigation: keep the credential ref as the opaque handle and make the packet prove install/custody/drift state for that handle. -- x402 signer fixture gets relabeled as customer-owned custody. Mitigation: claim guards and x402 bypass tests must distinguish `fixture_gateway_held` from customer/provider custody. -- Provider secret paths leak through "opaque" fields. Mitigation: safe-string schema, allowlisted projection fields, serialized redaction tests, and redaction-failure refusal/proof gap. -- Gateway check only records protected-path posture digest, hiding custody proof drift. Mitigation: either add custody proof seen fields to `GatewayCheckAttempt` or test that posture digest changes deterministically include proof packet drift. -- Runtime/MCP/CLI adoption pressure moves custody setup into model-facing surfaces. Mitigation: keep runtime/MCP/CLI as proposal/evidence/read only and enforce with import/surface tests. -- New schema required fields break older local demos before migration. Mitigation: additive fields first, then enforce only when `requiredProtectedPathState` is `gateway_checked` for custody-requiring action classes. -- External provider docs are inferred instead of verified. Mitigation: mark all named provider details as blocked until official verification. - -## Cut lines - -Cut from this slice: - -- Handshake-held wallet, signer, token, bearer credential, payment credential, balance, settlement, or payment-management state. -- Aggregate x402 session/day/review spend enforcement. -- Facilitator operation, seller middleware, settlement finality, or broad x402 compatibility. -- Hosted operation, production RBAC, tenant audit/search, live JWKS, revocation service, marketplace, certification, or clearing-house claims. -- Broad MCP/browser/shell/network/package-manager interception. -- Provider-specific vault/KMS/wallet architecture before official source verification. -- Any runtime, MCP, CLI, SDK, or review-renderer authority path. -- Raw proof packet read APIs that expose internal custody payloads. - -Split if the implementation needs: - -- D1 migration and hosted evidence indexing beyond local proof storage. -- New provider SDK integration. -- New public package exports. -- A provider-specific gateway adapter. -- Hosted admission or verifier trust plane work. - -## Blocked checks - -- Did not read sibling raw outputs, normalized outputs, or the final `PLAN.md` for this run by instruction. -- Did not read files outside the immutable packet's allowed source list. -- Did not inspect `src/protocol/areas/object-registry/*`, `src/protocol/public/*`, `src/protocol/kernel.ts`, `src/protocol/store/port.ts`, `src/storage/*`, `src/http/*`, `package.json`, or migrations because they were not in the allowed packet. Those paths must be verified before implementation. -- Did not inspect `src/protocol/areas/action-contract/*` directly because it was not in the allowed packet. Contract binding recommendations are inferred from canonical docs, projection code, and policy/gateway transition use. -- Did not inspect projection schema definitions because only projection assembly/logic files were allowed. Projection field additions must verify schema owners before execution. -- Did not run tests. This was a planning-only first pass constrained to reading the packet and allowed source files. -- Did not browse official provider, vault, KMS, wallet, x402, Cloudflare, JWKS, npm, MCP Registry, legal, or payment-regulatory sources. Any named provider custody implementation must be officially verified later. - -## Smallest next mechanism to build - -Define the custody proof packet schema under `src/protocol/areas/credential-custody/`, add one failing protocol test that refuses policy greenlight when `requiredProtectedPathState: "gateway_checked"` has a credential ref and posture but no custody proof packet digest, then bind that digest into protected-path posture before touching x402. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/EXECUTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/EXECUTION.md deleted file mode 100644 index 03a7ed5..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/EXECUTION.md +++ /dev/null @@ -1,522 +0,0 @@ -# Execution First Pass: Customer-Owned Gateway Custody Proof - -## Invariant at stake - -A protected path is real only when the mutation credential is behind a customer/provider gateway, the exact one-use greenlight is checked immediately before consequence, stale or unsafe custody refuses before mutation, and the surviving evidence is redacted but reconstructable. - -Current source already has strong pieces: - -- `GatewayCredentialRef` and `CredentialResolutionEvidence` in `src/protocol/areas/credential-custody/*`. -- Probe-backed `ProtectedPathPosture` in `src/protocol/areas/protected-path-posture/*`. -- Policy and gateway re-checks for protected-path posture and gateway credential bindings in `src/protocol/areas/policy-greenlight/transitions.ts` and `src/protocol/areas/gateway-gate/transitions.ts`. -- x402 wallet gateway signing only after `VerifiedGatewayCheck` in `src/adapters/x402-payment/wallet-gateway.ts`. -- auth.md reference gateway recording `CredentialResolutionEvidence` after a passed gate and before downstream service execution in `src/adapters/auth-md/gateway.ts`. - -The execution gap is not "add a gateway check." The gap is a source-owned custody proof packet that binds install evidence, credential refs, protected-path posture, custody/bypass probes, policy/gateway evaluation, and redacted projections into one digest-bearing evidence object. Without that packet, x402 signer custody can remain profile metadata plus adapter evidence, which is too easy to overclaim as customer-owned gateway custody. - -## Recommended phase sequence - -### Phase 0 - Implementation source map verification - -Before any code change, the executor must inspect companion files not included in this first-pass source packet but required for a real implementation: - -- `src/protocol/kernel.ts` -- `src/protocol/areas/credential-custody/index.ts` -- `src/protocol/areas/credential-custody/types.ts` -- `src/protocol/areas/object-registry/*` -- `src/protocol/public/schemas.ts` -- `src/protocol/public/inputs.ts` -- `src/protocol/evidence-projections/schemas.ts` -- `test/support/fixtures.ts` -- `test/support/auth-md-flow.ts` -- x402/auth.md adapter index/export files - -Closeout: confirm exact edit set before touching source. If these files show a different public aggregation pattern than expected, update the plan before implementation. - -### Phase 1 - Test-first custody packet failures - -Add failing tests before adding implementation. - -Primary tests: - -- `test/protocol/credential-custody.test.ts` - - rejects raw credential material in custody proof packet fields; - - creates a custody proof packet only when it binds a stored `GatewayCredentialRef` and a current `ProtectedPathPosture`; - - proves the packet digest includes credential ref digest, protected-path posture digest, bypass probe digests, provider-neutral key handle/lease/resolver/attestation refs, drift status, and expiry; - - refuses stale credential ref, provider drift, resolver failure, unsafe custody, missing packet, digest mismatch, redaction failure, and agent-exposed signer. -- `test/protocol/kernel-policy-gateway.test.ts` - - policy refuses when a contract requiring gateway custody lacks a valid custody proof packet; - - policy greenlights only when current posture, credential ref, and packet all agree; - - gateway refuses if the packet drifts or expires after greenlight but before gateway check; - - gateway does not consume the greenlight when custody refusal happens before mutation. -- `test/protocol/evidence-projections.test.ts` - - transaction envelope and contract projection expose custody packet refs/digests/status only; - - projections omit key handles that look like secret paths, signer material, payment payloads, bearer tokens, provider secret paths, and mutation credentials. - -Adapter tests: - -- `test/adapters/x402-install-proposal.test.ts` - - x402 install emits a gateway credential ref intent and custody packet expectation, not a Handshake-held wallet. - - fixture custody remains explicitly local/reference and cannot become live provider/customer custody. -- `test/adapters/x402-payment-action-proposal.test.ts` - - x402 candidate binds the signer credential ref and custody proof packet digest. - - x402 proposal refuses when signer custody is agent-exposed or packet binding is missing. -- `test/adapters/x402-wallet-gateway.test.ts` - - no signer call when custody packet is missing/stale/drifted/unsafe; - - signer call still happens only after `VerifiedGatewayCheck`; - - credential resolution/use evidence is recorded as redacted custody evidence for the exact contract and gate. -- `test/adapters/auth-md-gateway-pressure.test.ts` - - preserve auth.md drift/revocation behavior while adding packet binding. - -Architecture/claim tests: - -- `test/architecture/claim-boundary.test.ts` - - docs cannot claim provider/customer custody from fixture keys; - - docs cannot claim Handshake-held wallets, balances, settlement, payment management, or live provider custody. - -### Phase 2 - Add the protocol custody proof packet primitive - -Recommendation: add a narrow packet object under `src/protocol/areas/credential-custody/`, not a new authority lane. - -Do not replace `GatewayCredentialRef`, `CredentialResolutionEvidence`, or `ProtectedPathPosture`. Add a packet that binds them. - -Candidate object name: - -```text -GatewayCustodyProofPacket -``` - -Minimum schema shape: - -```text -gatewayCustodyProofPacketId -gatewayCustodyProofPacketDigest -gatewayCredentialRefId -gatewayCredentialRefDigest -protectedPathPostureId -protectedPathPostureDigest -bypassProbeIds -bypassProbeDigests -gatewayInstallEvidenceRefs -custodyProviderClass -custodyProviderRef -custodyProviderDigest -keyHandleRef -keyHandleDigest -leaseRef -leaseVersion -leaseExpiresAt -resolverRef -resolverVersion -resolverDigest -attestationRefs -attestationDigests -redactedAuditRefs -custodyStatus -custodyDriftStatus -resolverDriftStatus -redactionStatus -externalVerificationStatus -redactionProfileRef -secretMaterialIncluded: false -issuedAt -expiresAt -``` - -Field rules: - -- `custodyProviderClass`, `custodyProviderRef`, `keyHandleRef`, `leaseRef`, `resolverRef`, `attestationRefs`, and `redactedAuditRefs` are opaque refs, not provider-specific vault/KMS APIs. -- The schema must reject raw credential material and obvious secret paths using the same posture as existing credential custody redaction. -- `externalVerificationStatus` should allow provider-neutral local planning without implying official provider verification. Any named vault/KMS/wallet/provider implementation remains blocked until official source verification. -- `fixture_gateway_held` can support local/reference evidence only; it must not project as live customer/provider custody. - -Transition: - -```text -recordGatewayCustodyProofPacket(input) -``` - -Transition checks: - -- loads the credential ref by ID; -- loads current protected-path posture by ID or scope; -- verifies tenant/org/gateway/protected surface/action/resource agreement; -- verifies posture is fresh, `gateway_checked`, and probe-backed; -- verifies required bypass probe kinds are present and passed; -- verifies credential custody can satisfy gateway-checked posture; -- canonicalizes packet digest after all loaded refs are known; -- commits packet record and event; -- never retrieves or stores secret material; -- never creates permission, greenlight, mutation proof, wallet custody, settlement, or payment state. - -### Phase 3 - Bind the packet into contract, policy, and gateway evaluation - -Extend the existing `GatewayCredentialBinding` path instead of creating a parallel policy path. - -Candidate binding additions: - -```text -custodyProofPacketId -custodyProofPacketDigest -requiredCustodyDriftStatus -requiredResolverDriftStatus -``` - -Policy/gateway execution changes: - -- `evaluateGatewayCredentialBindings()` loads both the credential ref and packet. -- Policy input includes credential ref posture plus packet posture, freshness, drift, redaction status, and packet digest. -- Policy refuses before greenlight for missing packet, digest mismatch, stale packet, packet/ref scope mismatch, unsafe custody status, provider drift, resolver drift, weak posture, failed probes, or redaction failure. -- Gateway re-runs the same evaluation immediately before mutation and refuses without consuming the greenlight when custody drift blocks pre-mutation admission. -- Gateway check artifacts should record packet refs/digests seen, either directly on `GatewayCheckAttempt` if schema ownership supports it or through evidence refs on receipt/projection if the schema change is too wide. - -Do not change the Tier 1 authority rule. The packet strengthens evidence required for `gateway_checked` custody. It does not authorize mutation by itself. - -### Phase 4 - Make x402 use credential-ref custody proof - -x402 is the critical adapter because current install/profile code carries signer posture in `X402WalletGatewayProfile` and gateway registry metadata, while the candidate contract currently uses `secretRefs: {}` and does not bind a generic `GatewayCredentialRef`. - -Implementation direction: - -- `src/adapters/x402-payment/install-proposal.ts` - - derive a provider-neutral gateway credential ref for the wallet signer/payment credential; - - keep signer refs opaque and redacted; - - mark fixture custody as fixture/local only; - - add packet expectation refs to install output and human summary without claiming live provider custody; - - preserve per-call x402 exact scope and no aggregate payment-budget management. -- `src/adapters/x402-payment/action-proposal.ts` - - add credential ref and custody packet binding to the candidate `gatewayCredentialRefs`; - - include packet digest in candidate/contract digest path through the existing binding; - - refuse if x402 attempt cannot bind a valid packet for the installed gateway. -- `src/adapters/x402-payment/wallet-gateway.ts` - - continue calling `gatewayCheck()` before signer invocation; - - after `VerifiedGatewayCheck`, record redacted credential resolution/use evidence for the signer credential ref and custody packet; - - do not call the official signer when packet/ref/posture/gateway check refuses; - - do not expose `PaymentPayload`, `PAYMENT-SIGNATURE`, private keys, payment credentials, or provider secret paths in packet, resolution evidence, reconciliation evidence, or projections. -- `src/adapters/x402-payment/bypass-probes.ts` and `src/adapters/x402-payment/conformance.ts` - - keep hostile probe posture as packet inputs; - - distinguish `gateway_held` from `fixture_gateway_held`; - - require external verification before any named live provider custody implementation. - -x402 must remain the first wedge, not the protocol definition. The implementation must not add balances, settlement state, payment management, facilitator operation, seller middleware, or Handshake-held wallet concepts. - -### Phase 5 - Apply auth.md learnings without turning Handshake into auth - -auth.md already has the right execution posture: - -- gateway check first; -- no downstream execution if gate/ref/metadata/scope drift refuses; -- `CredentialResolutionEvidence` after passed gate; -- revocation/lifecycle evidence maps to credential-ref isolation; -- redaction assertions block bearer material. - -Implementation direction: - -- bind auth.md protected API call candidates to the same custody proof packet shape; -- keep auth.md discovery, registration, claim, identity, and revocation as provenance/evidence only; -- packet drift or revocation-driven isolation must block both policy and gateway checks; -- do not introduce auth provider, OAuth server, WorkOS alternative, or generic API gateway claims. - -### Phase 6 - Redacted custody projections - -Add a buyer-readable custody projection without exposing secret-bearing material. - -Candidate projection fields: - -```text -custodyProofPacketRef -custodyProofPacketDigest -gatewayCredentialRef -gatewayCredentialRefDigest -protectedPathPostureRef -protectedPathPostureDigest -custodyProviderClass -custodyProviderRef -keyHandleDigest -leaseVersion -leaseFreshness -resolverVersion -custodyDriftStatus -resolverDriftStatus -redactedAuditRefs -attestationRefs -externalVerificationStatus -secretMaterialIncluded: false -redactionProfileRef -omittedFields -``` - -Candidate source paths: - -- `src/protocol/evidence-projections/projections.ts` -- `src/protocol/evidence-projections/assembly.ts` -- `src/protocol/evidence-projections/schemas.ts` (not read in this first pass; implementation must verify) - -Projection tests must assert absence of: - -- secret paths; -- signer material; -- raw private keys; -- `PaymentPayload`; -- `PAYMENT-SIGNATURE`; -- bearer tokens; -- mutation credentials; -- provider-specific secret locator strings. - -### Phase 7 - Canon and claim guards - -Docs should change only after source/tests define the packet. - -Candidate docs: - -- `README.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-notes.md` -- `docs/internal/protocol-layman.md` -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` only as scratch alignment - -Required wording: - -- protected path is installed only when a gateway owns or controls the mutation credential, custody packet evidence is current, the exact greenlight is checked before mutation, and drift/unsafe custody refuses; -- fixture custody is local/reference only; -- x402 uses the custody proof as one protected-action pack and does not define the protocol; -- Handshake does not hold wallets, payment credentials, balances, settlement state, payment management, provider custody, or auth-provider custody; -- named vault/KMS/provider custody implementations require official source verification before implementation. - -## Task graph - -| Task | Owner lane | Depends on | Candidate paths | Closeout evidence | -| --- | --- | --- | --- | --- | -| T0 source map verification | Executor | input packet | kernel, object registry, public aggregators, projection schemas, fixtures | confirmed exact edit map | -| T1 failing protocol tests | Protocol tests | T0 | `test/protocol/credential-custody.test.ts`, `test/protocol/kernel-policy-gateway.test.ts` | focused tests fail for missing packet | -| T2 packet schema/input | Protocol | T1 | `src/protocol/areas/credential-custody/schemas.ts`, `inputs.ts` | schema rejects secret material and unsafe field shape | -| T3 packet transition/registry | Protocol | T2 | `src/protocol/areas/credential-custody/transitions.ts`, companion public/kernel/object-registry files | packet record/event commits and binds ref/posture/probes | -| T4 policy/gateway binding | Protocol | T3 | `credential-custody/transitions.ts`, `policy-greenlight/transitions.ts`, `gateway-gate/transitions.ts`, `gateway-gate/artifacts.ts` | policy/gateway refuse missing/stale/drifted/unsafe packet | -| T5 x402 install/proposal/gateway | Adapter | T4 | `src/adapters/x402-payment/install-proposal.ts`, `action-proposal.ts`, `wallet-gateway.ts`, `bypass-probes.ts`, `conformance.ts` | no signer call without valid packet; no wallet/payment-management claim | -| T6 auth.md parity | Adapter | T4 | `src/adapters/auth-md/gateway.ts`, `profiles.ts`, `revocation.ts`, `bypass-probes.ts` | packet drift/revocation blocks credential resolution and downstream call | -| T7 projections | Protocol projections | T4 | `src/protocol/evidence-projections/projections.ts`, `assembly.ts`, schemas companion | redacted custody projection includes refs/digests/status only | -| T8 docs and claim guards | Docs/architecture tests | T5, T7 | canonical docs, `test/architecture/claim-boundary.test.ts` | fixture/live custody and payment-management claims fail if reintroduced | -| T9 closeout gates | Executor | T1-T8 | package scripts | focused gates and `npm run check:repo` pass | - -## Dependency map - -```text -T0 - -> T1 - -> T2 - -> T3 - -> T4 - -> T5 - -> T6 - -> T7 - -> T8 - -> T9 -``` - -Hard dependency: x402/auth.md adapter work should not begin until the packet schema and binding semantics are stable. Otherwise each adapter will invent its own custody proof shape and the protocol will lose the customer-owned gateway custody primitive. - -## Critical path - -```text -failing protocol tests --> packet schema/input --> packet transition and digest --> extend GatewayCredentialBinding evaluation --> x402 binds signer credential ref and packet --> gateway refuses stale/drifted/unsafe packet before signer --> projection redacts custody evidence --> claim guards prevent fixture/live custody overclaim --> focused tests and check:repo -``` - -The riskiest segment is `GatewayCredentialBinding` extension. It sits in candidate/contract digest, policy input, and gateway evaluation. If it is added as optional metadata instead of required evidence for gateway-custody actions, the packet becomes advisory. - -## What can run in parallel - -After T2 field names are stable: - -- Protocol projection tests and architecture claim guards can be drafted in parallel. -- x402 and auth.md adapter test cases can be drafted in parallel, as long as they use the same packet binding shape. -- Docs wording can be prepared in parallel but should not land before source/tests prove packet behavior. -- Redaction fuzz cases can be added in parallel with adapter integration. - -Do not parallelize by giving x402 a local custody shape and auth.md a separate shape. That creates two adapter-specific evidence stories and no protocol primitive. - -## First executable step - -Implementation turn first step: - -```text -Inspect required companion files from Phase 0, then add the first failing tests in -test/protocol/credential-custody.test.ts for: -1. GatewayCustodyProofPacket schema redaction. -2. Packet digest binding to GatewayCredentialRef + ProtectedPathPosture + bypass probe digests. -3. Policy refusal when an otherwise valid contract lacks the packet binding. -``` - -Only after those tests fail for the expected reason should source implementation begin. - -## Source/test/doc candidate paths - -Protocol source candidates: - -- `src/protocol/areas/credential-custody/schemas.ts` -- `src/protocol/areas/credential-custody/inputs.ts` -- `src/protocol/areas/credential-custody/custody-posture.ts` -- `src/protocol/areas/credential-custody/transitions.ts` -- `src/protocol/areas/protected-path-posture/schemas.ts` -- `src/protocol/areas/protected-path-posture/inputs.ts` -- `src/protocol/areas/protected-path-posture/transitions.ts` -- `src/protocol/areas/policy-greenlight/transitions.ts` -- `src/protocol/areas/gateway-gate/schemas.ts` -- `src/protocol/areas/gateway-gate/inputs.ts` -- `src/protocol/areas/gateway-gate/artifacts.ts` -- `src/protocol/areas/gateway-gate/transitions.ts` -- `src/protocol/evidence-projections/projections.ts` -- `src/protocol/evidence-projections/assembly.ts` - -Likely implementation companion paths not read in this first pass: - -- `src/protocol/kernel.ts` -- `src/protocol/areas/credential-custody/index.ts` -- `src/protocol/areas/credential-custody/types.ts` -- `src/protocol/areas/object-registry/*` -- `src/protocol/public/schemas.ts` -- `src/protocol/public/inputs.ts` -- `src/protocol/evidence-projections/schemas.ts` -- `src/storage/d1/*` and migrations if the new object needs durable indexed storage -- `test/support/fixtures.ts` -- `test/support/auth-md-flow.ts` - -Adapter source candidates: - -- `src/adapters/x402-payment/install-proposal.ts` -- `src/adapters/x402-payment/action-proposal.ts` -- `src/adapters/x402-payment/wallet-gateway.ts` -- `src/adapters/x402-payment/bypass-probes.ts` -- `src/adapters/x402-payment/conformance.ts` -- `src/adapters/auth-md/profiles.ts` -- `src/adapters/auth-md/gateway.ts` -- `src/adapters/auth-md/revocation.ts` -- `src/adapters/auth-md/bypass-probes.ts` -- `src/adapters/protected-path-probes/index.ts` -- `src/adapters/protected-path-probes/executor.ts` - -Test candidates: - -- `test/protocol/credential-custody.test.ts` -- `test/protocol/evidence-projections.test.ts` -- `test/protocol/kernel-policy-gateway.test.ts` -- `test/adapters/x402-install-proposal.test.ts` -- `test/adapters/x402-payment-action-proposal.test.ts` -- `test/adapters/x402-wallet-gateway.test.ts` -- `test/adapters/x402-bypass-probes.test.ts` -- `test/conformance/x402-payment-conformance.test.ts` -- `test/adapters/auth-md-gateway-pressure.test.ts` -- `test/adapters/auth-md-serialization-redaction.test.ts` -- `test/architecture/claim-boundary.test.ts` -- `test/architecture/import-posture.test.ts` -- `test/architecture/root-exports.test.ts` - -Doc candidates: - -- `README.md` -- `QUALITY.md` -- `STRUCTURE.md` only if source ownership changes -- `docs/internal/decisions.md` -- `docs/internal/protocol-definition.md` -- `docs/internal/protocol-kernel-architecture.md` -- `docs/internal/protocol-layman.md` -- `docs/internal/protocol-notes.md` -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` only as scratch alignment - -## Validation gates - -Focused gates: - -```bash -npm run test -- test/protocol/credential-custody.test.ts test/protocol/kernel-policy-gateway.test.ts -npm run test -- test/protocol/evidence-projections.test.ts -npm run test -- test/adapters/x402-install-proposal.test.ts test/adapters/x402-payment-action-proposal.test.ts test/adapters/x402-wallet-gateway.test.ts test/adapters/x402-bypass-probes.test.ts -npm run test -- test/conformance/x402-payment-conformance.test.ts -npm run test -- test/adapters/auth-md-gateway-pressure.test.ts test/adapters/auth-md-serialization-redaction.test.ts -npm run quality:claims -npm run quality:architecture -``` - -Full closeout: - -```bash -npm run check:types -npm run lint -npm run format:check -npm run test -npm run pack:check -git diff --check -npm run check:repo -``` - -Required behavioral evidence: - -- Missing custody packet refuses before greenlight. -- Stale custody packet refuses before greenlight and before gateway mutation. -- Packet drift after greenlight refuses at gateway and does not call signer/downstream surface. -- Agent-exposed signer refuses during install/proposal/posture/policy path. -- Raw sibling bypass posture fails protected path posture and prevents greenlight. -- Credential resolution evidence is recorded only after a passed gateway check. -- Redacted projections never expose signer material, payment payloads, bearer tokens, mutation credentials, or provider secret paths. -- Fixture custody cannot project as live provider/customer custody. - -## Cut lines - -Keep out of this implementation slice: - -- Handshake-held wallets or payment credentials. -- Balance tracking, settlement, payment management, facilitator operation, seller middleware, spend-window ledger enforcement, or aggregate payment budgets. -- Live provider/customer custody claims from fixture keys. -- Provider-specific vault/KMS architecture unless official source verification is performed in a later implementation pass. -- Hosted operation, hosted verifier, live JWKS/revocation, cross-org trust, marketplace, certification, or clearing-house claims. -- Broad MCP/browser/shell/network/package-manager interception claims. -- New dashboard/review UX unless it renders exact packet refs and cannot authorize anything. -- A second adapter-specific custody proof shape. - -## Assumptions - -- The implementation may add a new credential-custody protocol object without changing Tier 1 authority semantics. -- Existing `GatewayCredentialRef` remains the opaque credential reference; the packet binds install/posture/probe evidence around it. -- Existing policy and gateway evaluation should remain the enforcement points. -- x402 must migrate from signer-profile metadata toward generic credential-ref/packet binding for custody claims. -- auth.md remains a reference protected API call profile and should inform lifecycle/isolation/redaction patterns only. -- `.planning/` is scratch and should not become source/package/public API naming. - -## Risks - -- Optional packet risk: if packet binding is optional on candidates, x402 can keep running on signer metadata while docs claim custody proof. This is advisory, not Handshake. -- Digest drift risk: if packet digest is not included in candidate/contract/policy/gateway inputs, a stale packet can be swapped after review. -- Gateway consumption risk: if custody refusal consumes the greenlight, safe retry/recovery semantics get muddied. Pre-mutation custody refusal should not become mutation evidence. -- Fixture overclaim risk: `fixture_gateway_held` can pass local tests but must not support live provider/customer custody language. -- Redaction pattern risk: current redaction relies partly on pattern detection. Unknown provider refs can evade it. Prefer allowlisted projection fields and digest-only provider material. -- x402 scope creep risk: custody proof can invite wallet/payment-management fields. Keep the packet provider-neutral and action-bound. -- Migration blast radius: public schemas, object registry, kernel facade, storage, and projections may all need updates. Do not hide those changes inside adapter-only work. - -## Antipatterns - -- Adding `custodyProof: true` to install output without a protocol object and digest. -- Treating wallet gateway profile metadata as customer-owned custody proof. -- Recording credential resolution evidence before a passed gateway check. -- Letting x402 call the signer after a failed packet/ref/posture check. -- Storing provider secret paths, raw signer refs, payment payloads, bearer tokens, or private keys in packet fields. -- Creating x402-specific custody proof that auth.md cannot reuse. -- Calling fixture custody "provider custody" or "customer custody." -- Using docs to claim live custody before source-owned packet, negative tests, and redacted projections exist. -- Browsing or adding named provider architecture during implementation without official source verification. - -## Blocked checks - -- Did not read sibling raw outputs, normalized outputs, or final `PLAN.md` for this run. -- Did not browse or verify any named vault/KMS/wallet/x402/provider documentation; any provider-specific custody implementation remains blocked on official source verification. -- Did not inspect companion implementation files outside the input packet, including kernel facade, object registry, public aggregators, projection schemas, storage migrations, and fixture helpers. -- Did not run tests because this is a planning-only first pass and source was not modified. -- Did not verify whether D1 storage needs a migration/index for the new packet object; implementation must check object registry/store behavior before coding. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/RISK.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/RISK.md deleted file mode 100644 index ae0fc8e..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/RISK.md +++ /dev/null @@ -1,142 +0,0 @@ -# RISK First Pass: Customer-Owned Gateway Custody Proof - -## Invariant At Stake - -A path is protected only when the customer/provider gateway owns the mutation credential, the exact one-use greenlight is checked immediately before consequence, unsafe or drifted custody refuses before mutation, and surviving evidence is redacted but reconstructable. Anything weaker is advisory, not Handshake. - -## Current Risk Read - -The current source already has useful enforcement primitives: `GatewayCredentialRef`, `CredentialResolutionEvidence`, `ProtectedPathPosture`, required bypass probe coverage, policy-time and gateway-time posture checks, one-use greenlight replay refusal, gateway policy drift refusal, credential-ref isolation, and redacted evidence projections. - -The risk is not "can the repo name custody." The risk is that a custody proof packet becomes claim material without becoming a policy and gateway constraint. If the packet is just projection text, install metadata, or adapter evidence not bound into the exact contract, greenlight, gateway check, and receipt chain, it will overstate customer-owned custody. - -## Recommended Risk Shape - -Extend existing primitives first, and add a distinct custody proof packet only if the existing `GatewayCredentialRef` plus `CredentialResolutionEvidence` shape cannot carry install evidence, provider-neutral resolver/lease/drift fields, and redacted projection requirements without overloading their meaning. - -Minimum safe chain: - -```text -gateway install evidence --> gateway credential ref binding --> protected-path posture with required gateway-owned bypass probes --> custody proof packet digest --> action contract and policy input include the packet/ref digest --> gateway check re-reads packet/ref/posture before mutation --> credential resolution evidence records post-gate use only --> redacted custody projection exposes refs/digests/status, never secret material -``` - -Cut line: do not claim live customer/provider custody until source-owned packet schema, policy/gateway refusals, negative tests, redacted projection tests, and claim guards all exist. - -## P0 Risk Register - -| Risk | Failure Mode | Mitigation Or Cut Line | -| --- | --- | --- | -| P0: Custody proof becomes receipt/projection theatre | The packet is emitted after the fact or rendered in projections, but policy and gateway do not require it before signer/credential use. | The custody packet/ref digest must be included in contract canonicalization, policy input digest, greenlight binding, gateway check evaluation, and receipt/projection evidence refs. If any of those bindings are not implemented, cut custody claims to "advisory evidence only." | -| P0: Gateway check does not verify current custody immediately before mutation | A greenlight issued against fresh custody is used after credential ref, provider registry, resolver version, lease, or protected-path posture drifts. | Gateway check must re-read current `GatewayCredentialRef`, protected-path posture, isolation state, gateway registry policy version, and custody packet drift status. Missing, stale, unsafe, drifted, or isolated custody refuses with no `MutationAttempt`. | -| P0: Agent-exposed signer path remains reachable | x402 or auth-style adapters have a direct SDK signer, private key env, raw signature header, bearer passthrough, MCP/browser/network sibling, or retry loop available outside the gateway. | Required bypass probe kinds must pass from `gateway_probe` or stronger source authority before `gateway_checked` posture. Raw sibling status `present` or `unknown` must refuse. Synthetic/conformance-only probes must not establish live custody. | -| P0: Redacted custody projection leaks secrets | Projection evidence refs or provider refs expose `PaymentPayload`, `PAYMENT-SIGNATURE`, private key paths, vault secret paths, bearer tokens, auth.md credentials, PII, or payment-sensitive payloads. | Use typed redaction schemas plus denylist/fuzz tests. Prefer allowlisted projection ref prefixes for live providers. `redaction_failed` must become refusal or proof gap, not an emitted projection. | -| P0: Payment custody / regulatory claim drift | The plan accidentally introduces Handshake-held wallets, balances, signer custody, settlement state, payment management, or facilitator/seller operation. | Explicit non-goal in plan and claim guards. x402 remains one buyer-side exact per-call protected action. No Handshake-held payment credential, no spend ledger claim, no settlement/facilitator/customer custody claim without later official-source verification and source-owned implementation. | - -## P1 Risk Register - -| Risk | Failure Mode | Mitigation Or Cut Line | -| --- | --- | --- | -| P1: Custody proof overfits x402 | Schema names payment payloads, wallet providers, or x402-specific surfaces and pollutes protocol meaning. | Keep provider-neutral fields: custody provider class, key/credential handle ref, lease/version, resolver ref/version, provider registry ref/digest, attestation refs, redacted audit refs, drift status, redaction profile. x402 maps into the packet as an adapter profile only. | -| P1: Fixture custody is mistaken for customer-owned custody | Local fixture keys and `fixture_gateway_held` posture pass tests and docs later imply provider/customer custody. | Claim guards must distinguish `fixture_gateway_held` from customer/provider gateway custody. Projection should expose fixture/reference posture as local evidence only. Live-custody language stays blocked until non-fixture provider/customer gateway evidence exists. | -| P1: Provider registry digest comparison is too permissive | Current binding only refuses digest mismatch when both binding and stored ref have non-null digests; a null digest path can allow weak drift detection. | For custody proof packets, require digest presence when provider registry or resolver posture matters. If digest is absent, status must be `proof_gap` or `unsafe`, not `gateway_checked`. | -| P1: Lease/version semantics are underspecified | A custody ref has `issuedAt`/`expiresAt`, but no explicit provider lease, resolver lease, rotation epoch, or attestation freshness semantics. | Packet should carry `custodyLeaseRef`, `custodyLeaseVersion`, `resolverVersion`, `attestationRefs`, `observedAt`, `expiresAt`, and `driftStatus`. Stale/unknown lease refuses before greenlight and gateway check. | -| P1: Resolver failure becomes downstream uncertainty | Gateway cannot resolve a credential, but the system records a proof gap after a mutation attempt or treats failure as pending downstream status. | Resolver failure must happen before protected mutation. It should produce gateway refusal or credential-resolution refusal evidence with `mutationAttempted: false`, unless there is explicit evidence the mutation already started. | -| P1: Auth.md lifecycle learning is imported as identity-provider scope | Revocation, claim, JWT, or metadata evidence turns Handshake into an auth provider or OAuth server. | Import only the custody/ref lifecycle pattern: credential-ref isolation, metadata/provider digest drift, redacted revocation evidence, and future policy/gateway blocking. Cut identity-provider claims. | -| P1: Projection redaction remains pattern-only | Unknown provider credential formats bypass regex redaction. | Add provider-format fuzz tests and allowlist projected custody fields. Unknown provider refs should project as opaque digest/status, not raw URI/path, until provider docs are verified. | -| P1: Review artifact laundering | A review surface displays "gateway owned" while the underlying contract/custody packet has weaker or stale status. | Review renderer must bind to exact contract digest, policy input digest, custody proof digest, and rendered uncertainty digest. Missing binding is review theatre. | -| P1: Runtime/MCP proposal surfaces imply enforcement | MCP/runtime proposals include custody metadata and users infer mutation protection, even though those surfaces cannot gate signer use. | Runtime/MCP can propose and read evidence only. They must not create custody proof packets, policy decisions, greenlights, gateway checks, receipts, or credential resolution evidence. | - -## P2 Risk Register - -| Risk | Failure Mode | Mitigation Or Cut Line | -| --- | --- | --- | -| P2: New primitive creates duplicate custody state | A new packet duplicates `GatewayCredentialRef`, `CredentialResolutionEvidence`, and `ProtectedPathPosture` without clear ownership. | Decide ownership up front. Either extend existing records or define a packet that references them by digest and owns only install/custody proof aggregation. No parallel secret or permission model. | -| P2: Plan expands into hosted/provider architecture | Custody proof planning drifts into Cloudflare, KMS, wallet provider, JWKS, registry, legal, or payment-regulatory implementation details. | Mark all named provider/KMS/wallet/legal/payment details as requiring official-source verification before implementation. Provider-neutral schema can proceed now. | -| P2: Operational ceremony blocks adoption | Integrators must manually sequence install evidence, credential ref, probes, posture, policy, gateway, credential resolution, and projections. | Future implementation can add activation helpers, but helpers must only sequence existing source-owned transitions. They must not move authority into runtime/MCP/SDK convenience layers. | -| P2: Evidence assembly scale is ignored | Projection assembly and receipt timelines can become broad tenant/org scans under hosted volume. | Keep this slice local/kernel. Hosted audit/search claims require scoped indexes, pagination, and retention policy in a later plan. | -| P2: `.planning` scratch becomes canon | Active planning language gets promoted into README/tests/exports without source validation. | Chair plan should treat `.planning` as scratch and name canonical source/test/doc paths for each implementation task. No planning-stage labels in source, scripts, package exports, or CI names. | - -## Validation Gates - -Implementation must be blocked until these gates exist and pass: - -- Schema/canonicalization: custody proof packet or extended custody records have deterministic digest tests, reject raw credential material, require provider-neutral lease/version/drift fields, and preserve Tier 1 protocol meaning. -- Policy gate: missing packet/ref, stale packet/ref, unsafe custody status, provider registry drift, resolver/version drift, weak source authority, missing probe coverage, failed probe, raw sibling present, and active credential-ref isolation all refuse before greenlight. -- Gateway gate: the same stale/drift/unsafe/missing cases refuse at gateway time after a greenlight and produce no mutation attempt or signer call. -- Adapter negative tests: x402 agent-exposed signer, raw private key env, direct official SDK signing, paid fetch/axios, raw payment signature header, sibling x402 wrapper, MCP direct payment, token passthrough, wrapper drift, failure-open posture, and live/unknown provider posture fail closed. -- Auth.md regression tests: revocation, metadata drift, downstream 401, stale credential ref, scope drift, raw bearer passthrough, direct HTTP/browser/network/MCP path, token replay, unsafe retry loop, and redaction failure quarantine/refuse before credential use. -- Projection tests: redacted custody projection includes refs/digests/status/reason codes and omits secret paths, signer material, `PaymentPayload`, `PAYMENT-SIGNATURE`, bearer tokens, raw provider credentials, payment payloads, and PII. -- Claim guards: docs/examples/tests fail if fixture keys imply customer/provider custody, if x402 becomes payment management, if Handshake-held wallets/balances/settlement appear, or if provider-specific custody is claimed without official-source verification. -- Closeout gates: focused protocol/adapter/projection/claim tests first, then `npm run quality:claims`, `npm run quality:architecture`, `npm run format:check`, and `npm run check:repo`. - -Candidate focused test paths: - -- `test/protocol/credential-custody.test.ts` -- `test/protocol/evidence-projections.test.ts` -- `test/protocol/kernel-policy-gateway.test.ts` -- `test/adapters/x402-wallet-gateway.test.ts` -- `test/adapters/x402-bypass-probes.test.ts` -- `test/adapters/auth-md-gateway-pressure.test.ts` -- `test/adapters/auth-md-serialization-redaction.test.ts` -- `test/conformance/x402-payment-conformance.test.ts` -- `test/architecture/claim-boundary.test.ts` -- `test/architecture/import-posture.test.ts` -- `test/architecture/root-exports.test.ts` - -## Rollback And Stop Conditions - -Stop the implementation slice if: - -- custody proof is not consumed by both policy and gateway checks; -- the gateway cannot refuse before signer/credential use; -- one greenlight can be reused for multiple custody resolutions or mutations; -- fixture/local signer custody is the only evidence behind a customer/provider custody claim; -- redaction tests find any raw signer, token, payment payload, secret path, bearer credential, or PII in projections; -- provider-specific vault/KMS/wallet behavior is needed but official docs have not been verified; -- runtime/MCP/SDK convenience code starts issuing policy, greenlight, gateway, receipt, mutation, or credential-resolution records; -- aggregate spend, settlement, facilitator, seller middleware, balance, or payment-management language appears in the slice. - -Rollback should remove or quarantine the new custody packet/projection/claim surface and keep existing `GatewayCredentialRef`, `CredentialResolutionEvidence`, `ProtectedPathPosture`, policy, gateway, and projection behavior unchanged. If partial schema lands without enforcement, it must be marked advisory or removed. - -## Assumptions - -- Customer-owned gateway custody remains the enforcement model. -- Handshake does not hold wallets, payment credentials, balances, settlement state, or payment-management authority. -- x402 remains the first wedge but does not define protocol primitives. -- Tier 1 protocol meaning remains stable: exact contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap, isolation. -- Existing credential custody and protected-path posture primitives are reusable unless implementation proves a source-level schema conflict. -- Provider-neutral custody schema planning can proceed without browsing; named provider/KMS/wallet/legal/payment details cannot. - -## Dependencies - -- Current `GatewayCredentialRef` and `CredentialResolutionEvidence` schemas and transition checks. -- Current protected-path posture evaluator, required bypass probe kinds, and source-authority rules. -- Current policy and gateway checks that evaluate protected-path posture, credential refs, idempotency, isolation, gateway policy drift, params digest, and sequence dependencies. -- x402 install proposal, wallet gateway, hostile bypass probes, and conformance posture. -- auth.md credential intake, lifecycle isolation, protected API gateway, bypass probes, and serialization redaction patterns. -- Evidence projection assembly and redaction behavior for contract views, agent transaction envelopes, receipt timelines, idempotency recovery, and protected-path health. - -## Antipatterns - -- "Custody proof" as a receipt label without pre-mutation enforcement. -- A rendered review screen that says "customer gateway holds credential" without binding to the exact custody proof digest. -- A provider-specific field named `vaultPath`, `secretPath`, `walletPrivateKey`, `PaymentPayload`, or `PAYMENT-SIGNATURE` in protocol records or projections. -- `fixture_gateway_held` presented as customer/provider custody. -- A helper that gives runtime/MCP/SDK code access to signer, credential resolver, gateway check, or credential-resolution writes. -- Treating spend session/day/review bounds as enforced before a ledger exists. -- Collapsing credential resolution failure into downstream unknown after mutation. -- Regex-only redaction for live provider custody. - -## Blocked Checks - -- No external official-provider, vault/KMS, wallet, x402, JWKS, legal, or payment-regulatory verification was performed; the input packet explicitly said not to browse by default. -- I did not read source files outside the immutable packet's allowed source boundary. In particular, exact `ActionContract` schema internals, action-proposal internals, HTTP handlers, D1 storage, runtime ingress, MCP proposal code, and product example generators were not read unless included indirectly in allowed tests/docs. -- I did not run tests; this is a planning-only first-pass risk artifact. -- I did not read sibling raw outputs, normalized outputs, or the final run `PLAN.md`. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/STRATEGY.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/STRATEGY.md deleted file mode 100644 index b6e69c8..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/raw/STRATEGY.md +++ /dev/null @@ -1,338 +0,0 @@ -# STRATEGY: Customer-Owned Gateway Custody Proof - -## Invariant at stake - -A protected path is real only when the mutation credential stays behind the gateway boundary, the exact one-use greenlight is checked immediately before consequence, unsafe drift refuses before mutation, and the surviving evidence can reconstruct that chain without exposing credential material. - -If the source cannot show that chain as one digest-bound custody story, any customer-owned gateway claim is theatre. - -## Findings - -1. The strategic goal is not "better x402." The goal is a reusable custody proof for protected actions for automated decision making. x402 is the first wedge because paid HTTP makes credential custody concrete, but x402 must remain a proof profile, not the protocol definition. - -2. The existing kernel already has most control pieces: - - `GatewayCredentialRef` stores opaque gateway-side credential custody metadata without raw material. - - `CredentialResolutionEvidence` is recorded only after a passed `GatewayCheckAttempt`. - - `ProtectedPathPosture` requires current `gateway_checked` state, gateway/host source authority, raw sibling status, and required bypass probe coverage. - - policy and gateway transitions both re-check protected-path posture and credential ref bindings. - - evidence projections expose redacted transaction, contract, receipt, install-health, and credential refs. - -3. The gap is not enforcement vocabulary. The gap is a source-owned custody proof packet or equivalent projection spine that binds install evidence, credential ref, protected-path posture, bypass probes, exact contract, greenlight, gateway check, and redacted custody evidence into one reconstructable object. Today the ingredients exist but the buyer-readable custody claim is assembled from scattered records. - -4. x402 currently proves "sign only after `VerifiedGatewayCheck`" but does not yet prove customer-owned gateway custody. The x402 install path has `walletGatewayProfile.signerRef` and `signerCustodyStatus`, and the gateway creates payment signature evidence after the gate. It does not yet bind x402 signer custody through `GatewayCredentialRef` on the action contract or record x402 signer use as `CredentialResolutionEvidence`. - -5. Fixture/local custody must stay visibly below customer-owned custody. `fixture_gateway_held` can support local regression proof. It must not satisfy a public "customer-owned gateway custody established" claim. The proof packet/projection needs an explicit claim level so local fixture keys cannot launder into provider/customer custody. - -6. auth.md gives the correct pattern: opaque credential refs, lifecycle drift/revocation mapped into isolation or quarantine, post-gate credential-resolution evidence, and redacted projections split by evidence type. Reuse that pattern. Do not turn Handshake into an auth provider, OAuth server, wallet provider, vault provider, or payment custodian. - -7. The 10-star product shape is a custody receipt a buyer can read: - - the automated decision system proposed an exact action; - - the agent/runtime never received signer or mutation credential material; - - the customer/provider gateway held or resolved the credential; - - stale, drifted, missing, unsafe, raw sibling, or redaction-failed custody refused before consequence; - - the gateway checked the exact greenlight immediately before signer use; - - the resulting evidence is redacted but reconstructable by digest refs. - -## Recommended macro shape - -### 0. Claim boundary lock - -Start by freezing the claim: - -```text -customer-owned gateway custody proof = source-owned evidence that a protected path's mutation credential is held or resolved by the gateway boundary and used only after an exact gateway check. -``` - -This slice must not claim: - -- Handshake-held wallet custody; -- payment balances, settlement, or payment management; -- live provider custody; -- broad x402 compatibility; -- hosted operation; -- provider-specific vault/KMS correctness. - -Closeout should include claim guards before product docs or demos can say "customer-owned custody" from fixture keys. - -### 1. Add a narrow custody proof packet, not a new authority path - -Recommended primitive: add a `GatewayCustodyProofPacket` or similarly named protocol object as evidence, not authority. - -Its job is to bind existing primitives, not replace them: - -```text -gateway install evidence digest --> GatewayCredentialRef id/digest --> provider registry ref/digest --> resolver ref/version --> lease/version or custody generation --> attestation refs / redacted audit refs --> protected path posture id/digest --> bypass probe ids/digests --> drift status --> custody proof digest -``` - -It must not contain: - -- signer material; -- `PaymentPayload`; -- `PAYMENT-SIGNATURE`; -- bearer tokens; -- provider secret paths; -- raw vault/KMS addresses; -- payment settlement or balance state. - -Strategic reason to add a packet: extending only `GatewayCredentialRef`, `ProtectedPathPosture`, and `CredentialResolutionEvidence` leaves the proof scattered. A buyer-facing custody claim needs one digest-bound packet that can be projected and tested as an artifact. - -Boundary: this packet is evidence. It creates no permission, no greenlight, no gateway check, no mutation proof, no downstream success, and no provider custody claim by itself. - -### 2. Bind x402 to the generic custody primitives - -x402 should become the first use of the custody proof without becoming payment management. - -Minimum strategic path: - -1. x402 install proposal registers or references a `GatewayCredentialRef` for the signer boundary. -2. x402 runtime/action proposal includes that credential ref binding in the `CandidateAction` and resulting `ActionContract`. -3. x402 policy/gateway checks inherit the existing credential-ref and protected-path refusal behavior. -4. x402 wallet gateway records post-gate signer use as `CredentialResolutionEvidence` before or alongside payment-signature reconciliation. -5. x402 redacted projection surfaces the custody proof packet and credential-resolution refs without exposing signature payloads. - -This keeps x402 as: - -```text -one buyer-side exact paid HTTP action --> one gateway-held signer boundary --> one policy decision --> one gateway check --> one redacted signer-use proof or proof gap -``` - -It must not add: - -- Handshake-held wallets; -- account balances; -- spend-window ledgers; -- facilitator operation; -- seller middleware; -- settlement finality; -- provider custody claims from local fixtures. - -### 3. Make protected-path posture consume custody packet evidence - -The current protected-path posture already requires current gateway probes and raw sibling blocking. The plan should decide whether customer-owned custody proof is: - -- required only for adapter packs that declare a gateway credential binding; or -- required for every `requiredProtectedPathState: "gateway_checked"` path. - -Strategy recommendation: require it first only for credential-backed paths, including x402 signer custody. Do not silently change Tier 1 meaning for every protected action. After x402 proves the mechanism, promote the requirement to other custody-backed adapter packs. - -### 4. Add a redacted custody projection - -The product proof should be a projection, not raw record access. - -Recommended projection shape: - -```text -custodyProofRef -custodyProofDigest -claimLevel: local_fixture | customer_gateway_evidence | provider_gateway_evidence | proof_gap -gatewayCredentialRef -gatewayCredentialRefDigest -protectedPathPostureRef -protectedPathPostureDigest -bypassProbeCoverage -credentialResolutionEvidenceRefs -gatewayCheckRef -greenlightRef -actionContractRef -driftStatus -redactionStatus -omittedFields -proofGapRefs -refusalReasonCodes -``` - -The projection should answer the buyer question directly: "Did the automated system ever receive the mutation credential?" The safe answer is not prose. It is the absence of exposed material plus evidence that signer use happened only after a verified gate. - -### 5. Preserve source-owned negative proof - -The plan must make the negative tests the product, not an afterthought. The first execution slice should fail closed on: - -- agent-exposed signer; -- missing custody packet; -- stale credential ref; -- provider registry drift; -- resolver version drift; -- resolver failure; -- unsafe custody status; -- protected-path posture stale or not gateway checked; -- required bypass probe missing or failed; -- raw sibling signer/payment path present; -- redaction failure; -- replayed greenlight; -- fixture custody trying to claim customer-owned/provider custody. - -## What to cut - -- Cut Handshake-held wallets, signing keys, payment credentials, balances, settlement, facilitator state, or spend management. -- Cut provider-specific vault/KMS architecture from this macro plan unless every named provider detail is marked "requires official source verification before implementation." -- Cut any public claim that local `fixture_gateway_held` proves customer-owned or provider custody. -- Cut a "custody dashboard" unless it is a redacted projection over exact records. A UI without digest binding is review theatre. -- Cut generic "secure custody" language. Use exact custody statuses, refs, digests, drift status, and refusal codes. -- Cut a new payment abstraction. The reusable thing is protected-action custody proof, not x402 payment infrastructure. -- Cut broad x402 compatibility. Keep `x402_payment.exact` as the first buyer-side per-call path. -- Cut aggregate spend windows. Session/day/review bounds remain metadata until a ledger exists. - -## What must be decided before execution - -1. Primitive name and object type: choose whether the evidence object is `GatewayCustodyProofPacket`, `CredentialCustodyProofPacket`, or a narrowly named projection-only packet. Do not let the name imply authority. - -2. Requirement scope: decide whether custody proof packet is required for all `gateway_checked` protected paths or only for paths with `GatewayCredentialRef` bindings. Strategy recommendation: credential-backed paths first. - -3. Fixture semantics: decide the exact claim level for `fixture_gateway_held`. Strategy recommendation: fixture can pass local regression posture but must project `claimLevel: "local_fixture"` and fail any customer/provider custody claim guard. - -4. x402 migration shape: decide whether `X402WalletGatewayProfile.signerRef` remains as adapter-local install metadata or becomes a `GatewayCredentialRef`-backed field. Strategy recommendation: preserve adapter metadata if useful, but the action contract must carry a generic `GatewayCredentialRef` binding before customer-owned custody proof can be claimed. - -5. Post-gate signer evidence: decide whether x402 wallet gateway must record `CredentialResolutionEvidence` before the payment signature evidence or after the signature is created. Strategy recommendation: record a redacted credential-use evidence object after a passed gate and before projecting the downstream reconciliation as custody proof. - -6. Projection surface: decide whether custody projection is part of the existing agent transaction envelope or a separate `projectGatewayCustodyProof` read. Strategy recommendation: create a separate projection and link it from the transaction envelope to avoid making every transaction projection custody-heavy. - -7. External verification boundary: decide which future provider/vault/wallet details require official docs. For this macro, every named provider implementation detail is blocked until official source verification. - -## Six-month regret scenario - -Six months from now, the failure mode is not "we did not support enough x402 providers." The failure mode is that Handshake shipped a clean demo where the agent did not see a signer, then called that customer-owned custody while the actual source only proved a local fixture signer behind a reference adapter. - -That regret creates three wounds: - -1. Customers treat Handshake as a payment custodian or wallet manager when it is neither. -2. Future adapter teams copy x402-specific signer fields instead of generic custody refs, making every protected action pack invent its own credential story. -3. Receipts cannot prove whether a mutation credential was gateway-held, provider-held, fixture-held, stale, drifted, or simply redacted away. - -The antidote is a narrow proof packet with explicit claim levels and negative tests that make fixture custody unable to masquerade as customer-owned custody. - -## Smallest strategically valid first move - -The smallest valid first move is not a provider integration. It is a source-owned x402 custody proof skeleton: - -```text -GatewayCredentialRef-bound x402 signer --> custody proof packet digest --> x402 ActionContract includes credential binding --> policy refuses missing/stale/unsafe/drifted custody --> gateway refuses drift before signing --> x402 gateway records redacted CredentialResolutionEvidence after VerifiedGatewayCheck --> custody projection shows local_fixture vs customer_gateway_evidence explicitly -``` - -This first move is strategically valid because it proves the reusable Handshake primitive without broadening x402, holding money, or pretending provider custody is done. - -## Assumptions - -- The current Tier 1 protocol spine remains stable: exact contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap. -- x402 remains the first wedge and does not define the protocol. -- `.planning/` is scratch; tracked canon and source/tests control implementation truth. -- Customer-owned gateway custody means the customer/provider gateway owns or controls the mutation credential, not Handshake. -- Provider-neutral schema planning can proceed from repo source; named provider/vault/KMS details require later official source verification. -- The current local x402 signing path is useful as a proof harness, but it does not establish live provider/customer custody. - -## Dependencies - -- Claim-boundary cleanup must remain in force so new docs/tests cannot reintroduce payment-management or provider-custody claims. -- Existing `GatewayCredentialRef`, `CredentialResolutionEvidence`, `ProtectedPathPosture`, bypass probe, policy, and gateway transitions are the implementation base. -- x402 install/action/gateway paths must accept generic credential bindings rather than keeping signer custody as adapter-local metadata only. -- Evidence projections must either add a custody projection or link to one from the agent transaction envelope. -- Claim-boundary tests must be extended before public/demo wording changes. -- Official provider/vault/wallet documentation is a future dependency only if execution chooses a named provider implementation. - -## Risks - -1. Proof packet theatre: a new packet that only repeats claims without binding exact refs/digests is worse than no packet. - -2. Tier 1 drift: making custody proof globally required for all `gateway_checked` paths in one slice can change protocol meaning. Keep the first requirement scoped to credential-backed paths. - -3. x402 capture: payment-specific fields can leak into generic protocol objects. Keep payment payload and signature evidence adapter-owned and redacted. - -4. Fixture laundering: local fixture custody can accidentally become customer-owned custody language. Add claim-level fields and guards. - -5. Redaction failure: unknown provider credential formats can bypass pattern-based redaction. Prefer allowlisted projection fields and fuzz redaction with credential-looking refs. - -6. Adoption drag: requiring every integrator to hand-assemble install evidence, credential ref, probes, posture, contract, policy, gate, and projection is too much ceremony. The macro should plan activation helpers later, but not move authority into runtime or MCP. - -7. Provider drift blind spot: without lease/version and resolver-version binding, a stale proof packet can keep passing after gateway credential rotation. - -8. Gateway bypass optimism: runtime/MCP evidence can observe bypass-shaped calls, but cannot prove all host paths are blocked. The proof should be honest about installed protected paths only. - -## Validation gates - -Planning should require future execution to close with focused gates before full repo gates: - -1. Protocol schema/canonicalization tests for the custody proof packet: - - digest changes when credential ref, provider registry digest, resolver version, lease/version, posture digest, probe digest, or drift status changes; - - raw credential-looking fields are rejected or excluded. - -2. Policy/gateway negative tests: - - missing custody packet refuses; - - stale credential ref refuses; - - provider registry drift refuses; - - resolver drift/refusal refuses; - - unsafe custody status refuses; - - protected-path posture stale or not gateway checked refuses; - - raw sibling path present refuses; - - replay refuses before signer reuse. - -3. x402 adapter tests: - - x402 install compiles a signer `GatewayCredentialRef` binding; - - x402 action contract carries credential ref binding; - - signer use occurs only after `VerifiedGatewayCheck`; - - x402 gateway records redacted `CredentialResolutionEvidence`; - - fixture custody projects as local fixture, not customer/provider custody. - -4. Projection/redaction tests: - - custody projection omits signer material, `PaymentPayload`, `PAYMENT-SIGNATURE`, bearer tokens, provider secret paths, and mutation credentials; - - projection distinguishes gateway check, credential resolution, downstream reconciliation, and proof gap. - -5. Claim guards: - - canonical docs and demo outputs cannot claim live provider/customer custody from fixture keys; - - x402 wording stays per-call exact buyer-side protected action; - - no Handshake-held wallet/payment-custody/payment-management language appears. - -6. Closeout command candidates for the future implementation: - - `npm run quality:claims` - - `npm run test -- test/protocol/credential-custody.test.ts test/protocol/evidence-projections.test.ts test/protocol/kernel-policy-gateway.test.ts` - - `npm run test -- test/adapters/x402-wallet-gateway.test.ts test/adapters/x402-bypass-probes.test.ts test/conformance/x402-payment-conformance.test.ts` - - `npm run test -- test/architecture/claim-boundary.test.ts test/architecture/import-posture.test.ts test/architecture/root-exports.test.ts` - - `npm run format:check` - - `npm run check:repo` - -## Cut lines - -- No mutation credential may cross into runtime, MCP, CLI, SDK, or model-facing surfaces. -- No greenlight may authorize more than one exact gateway-checked mutation attempt. -- No custody proof packet may create permission. -- No receipt or projection may claim downstream payment success without downstream evidence. -- No fixture key may satisfy customer/provider custody claims. -- No provider/vault/KMS claim may ship without official source verification and provider-specific negative tests. -- No broad x402 compatibility, facilitator operation, settlement finality, seller middleware, or spend-window enforcement in this slice. -- No raw record route or generic projection may expose credential material or secret-bearing refs. - -## Antipatterns - -- "Custody status: safe" without credential ref digest, resolver version, lease/version, posture digest, probe digest, and drift status. -- Adding a wallet provider abstraction before the generic custody proof works. -- Treating `signerRef` strings as proof of custody. -- Recording signer use before the gateway check. -- Recording signer use after the gateway check but failing to bind it to the exact contract, greenlight, and gate attempt. -- Hiding redaction failure as success. -- Letting x402 provider-environment fields default away live/unknown posture. -- Using dashboard copy to imply protection where the gateway cannot block mutation. -- Using MCP proposal evidence as if it proves host-wide bypass prevention. - -## Blocked checks - -- Did not browse or verify official provider, vault, KMS, wallet, x402 provider, legal, or payment-regulatory details. The input packet said not to browse by default; any named provider architecture remains blocked on official source verification before implementation. -- Did not read sibling raw outputs, normalized outputs, or the final plan for this run. -- Did not run tests because this is a planning-only first-pass artifact. -- Did not inspect source files outside the immutable input packet and allowed source boundary. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/synthesis.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/synthesis.md deleted file mode 100644 index 2d3f7b2..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/customer-owned-gateway-custody-proof/runs/customer-owned-gateway-custody-proof-20260524T071623Z/synthesis.md +++ /dev/null @@ -1,54 +0,0 @@ -# Chair Synthesis - -## Invariant At Stake - -A protected action is real only when the mutation credential remains behind a customer/provider gateway boundary, the exact one-use greenlight is checked immediately before consequence, unsafe or drifted custody refuses before mutation, and the surviving evidence is redacted but reconstructable. - -## Synthesis Decision - -The final plan chooses a new source-owned `GatewayCustodyProofPacket` as evidence, not authority. - -This is not a new permission primitive. The packet is subordinate to existing `GatewayCredentialRef`, `ProtectedPathPosture`, bypass probes, policy evaluation, gateway check, `CredentialResolutionEvidence`, and redacted projections. - -Reasoning: - -- Extending only existing fields keeps the custody story scattered and too easy to overclaim. -- A new top-level authority primitive would violate Tier 1 protocol meaning. -- A packet under credential custody can bind install evidence, credential ref, posture, probes, drift, redaction, and claim level while policy and gateway remain the enforcement points. - -## Perspective Reconciliation - -- Strategy emphasized that Handshake is protected actions for automated decision making, x402 is the first wedge, and fixture custody must not become customer/provider custody. -- Architecture emphasized that existing primitives are strong, but a source-owned packet is needed to make custody proof digest-bound and reconstructable. -- Execution emphasized test-first sequencing and warned that x402/auth.md adapter work must wait until packet binding semantics are stable. -- Risk emphasized that a packet not consumed by policy and gateway is advisory, not Handshake. -- Adoption emphasized the buyer-readable projection: the buyer should not infer custody from scattered protocol records. - -The plan therefore sequences source map verification, failing tests, packet schema/transition, policy/gateway binding, x402 integration, auth.md parity, redacted projection, claim guards, and closeout gates. - -## Preserved Boundaries - -- Handshake does not hold wallets, private keys, bearer tokens, payment credentials, balances, settlement state, or payment-management state. -- x402 remains one buyer-side exact protected action per call and does not define the protocol. -- customer-owned gateway custody remains the enforcement model. -- Tier 1 meaning remains exact contract, policy decision, one-use greenlight, gateway check, receipt/refusal/proof gap, and isolation. -- Provider-specific vault/KMS/wallet/x402 provider details require later official source verification before implementation. -- Fixture/local/reference custody is regression evidence only and cannot support live customer/provider custody claims. - -## Blocked Checks - -- Did not inspect companion implementation files outside the allowed planning packet, including protocol public aggregation, object registry, kernel facade, projection schemas, storage/migrations, fixtures, or adapter exports. -- Did not browse official provider, vault, KMS, wallet, x402 provider, JWKS, Cloudflare, npm, MCP Registry, legal, or payment-regulatory sources. -- Did not run tests because this was a planning-only synthesis with a hard write boundary. -- Did not read archive macro runs. -- Did not stage or commit. - -## Output Files - -- `.planning/macro/active/customer-owned-gateway-custody-proof/PLAN.md` -- `.planning/macro/active/customer-owned-gateway-custody-proof/CONTEXT.md` -- `.planning/macro/active/customer-owned-gateway-custody-proof/ASSUMPTIONS.md` -- `.planning/macro/active/customer-owned-gateway-custody-proof/DECISIONS.md` -- `.planning/macro/active/customer-owned-gateway-custody-proof/RISKS.md` -- `.planning/macro/active/customer-owned-gateway-custody-proof/VALIDATION.md` -- `.planning/macro/active/customer-owned-gateway-custody-proof/TASKS.jsonl` diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/ASSUMPTIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/ASSUMPTIONS.md deleted file mode 100644 index 2f2cd25..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/ASSUMPTIONS.md +++ /dev/null @@ -1,35 +0,0 @@ -# Assumptions: Host-Specific Bypass Harnesses - -## Hard Assumptions - -- Handshake is protected actions for automated decision making, not engineering-agent-only infrastructure. -- x402 exact per-call is the first proof wedge, not the protocol center. -- A host harness proves only named configured installed path behavior against named bypass routes at a recorded freshness state. -- No host harness can claim host-wide containment. -- No fixture can manufacture establishment custody or gateway-checked posture. -- CLI and MCP surfaces do not enforce unless paired with blocking gateway checks. - -## Technical Assumptions - -- `runBypassProbeExecutors` and `BypassProbeExecutor` are reusable for host harness probe execution. -- Existing x402 hostile bypass probe executors are a useful calibration pattern. -- Package-install conformance can supply the first protected action fixture boundary. -- Host tool identity can be represented with host id, resolved path, digest, adapter version, registry entry, and freshness timestamp. -- Wrapper drift and stale tool metadata are common enough to be first-class refusal states. -- Raw sibling paths can be named in a fixture manifest. -- Redacted evidence can preserve enforcement distinctions without leaking secrets. - -## Product Assumptions - -- The first useful adoption surface is CLI reporting. -- Operators need explicit non-claims more than broad safety language. -- Exit states are more valuable than prose confidence. -- Dashboard work should wait until the proof packet and posture derivation are stable. - -## Unknowns - -- Exact package-install host names and paths for the first fixture. -- Final shape of package-install adapter expansion. -- Whether current claim guard scripts already cover all host-wide overclaims. -- Whether existing conformance fixtures expose enough metadata for host digest and wrapper integrity checks. -- How much redaction should happen in source evidence versus projection. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/CONTEXT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/CONTEXT.md deleted file mode 100644 index f81966c..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/CONTEXT.md +++ /dev/null @@ -1,105 +0,0 @@ -# Context: Host-Specific Bypass Harnesses - -## Invariant - -Handshake controls protected actions for automated decision making. It is not engineering-agent-only. A host harness is valid only when it binds a protected action attempt to a named configured installed path and records whether named bypass routes were refused, detected, proof-gapped, or left advisory-only. - -## Why This Macro Exists - -Handshake already has bypass probe executor machinery and x402 hostile bypass probe precedent. That is not enough to claim host protection. - -The missing mechanism is host-specific evidence: - -- which host was tested -- which installed path was configured -- which protected action was attempted -- which wrapper was expected -- which raw sibling routes were reachable -- which registry entry bound the gateway -- which freshness state applied -- which evidence survived redaction -- which claims are explicitly not made - -## Product Boundary - -Handshake is protected actions for automated decision making. - -Engineering-agent actions are still an important wedge, but the product category is broader. The host harness must avoid language that narrows Handshake into engineering-agent-only infrastructure. - -x402 exact per-call remains the first proof wedge because it demonstrates exact action contract, policy, gateway check, refusal, and bypass evidence. It is not the protocol center. - -## First Host Choice - -Choose package-manager local host first, after package-install conformance is stable. - -Reason: - -- package installs are consequential protected actions -- local host paths have visible wrapper and raw sibling distinctions -- package manager bypasses are concrete enough to test -- the adoption path is understandable to engineering organizations -- the evidence boundary can stay narrow - -x402 hostile bypass probes should be used second as calibration for hostile probe discipline. - -MCP host harnesses are deferred until the package-install host contract is boring. MCP and CLI are proposal, evidence, and read surfaces unless paired with blocking gateway enforcement. - -## Evidence Shape - -The required evidence object is `BypassProofPacket`. - -It must include: - -- manifest reference -- host identity -- environment identity -- adapter identity and version -- registry entry -- policy identity -- protected action type -- protected path -- wrapper identity and resolved path -- raw sibling candidates -- tool list digest -- freshness timestamp -- probe results -- wrapper integrity result -- gateway binding result -- gateway check result -- downstream execution result -- refusal evidence -- bypass evidence -- proof gaps -- redacted projection -- non-claims - -Redaction must not erase the distinction between gateway check, downstream execution, refusal, bypass, and proof gap. - -## Adoption Surface - -CLI report comes first. - -Target command shape: - -- `handshake harness init --host codex --protected-path package-install` -- `handshake harness check --host codex --protected-path package-install` -- `handshake harness probe --host codex --protected-path package-install` -- `handshake harness report --host codex --protected-path package-install` -- `handshake harness doctor --host codex --protected-path package-install` - -The CLI must report status and non-claims. Dashboard rendering is deferred until the evidence object is stable. - -## Product Bar - -A 10-star version does not say "safe." - -It says: - -- ready for this host fixture -- advisory only for these routes -- stale for this digest -- drifted at this wrapper -- unbound at this gateway -- raw sibling mutation possible at this named path -- proof gap for this missing evidence -- not tested for browser, shell, network, MCP, platform, or ecosystem coverage diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/DECISIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/DECISIONS.md deleted file mode 100644 index b174c52..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/DECISIONS.md +++ /dev/null @@ -1,98 +0,0 @@ -# Decisions: Host-Specific Bypass Harnesses - -## D01: First Host Harness Is Package-Manager Local Host - -Use package-manager local host first after package-install conformance. - -Reason: package installs are concrete protected actions with obvious wrapper and raw sibling bypass risks. - -Rejected alternatives: - -- x402 first as host center: rejected because x402 is calibration and proof wedge, not protocol center. -- MCP host first: rejected because MCP surface posture is still proposal/evidence/read unless blocking gateway enforcement is paired. -- generic host harness first: rejected because it invites host-wide claims. - -## D02: Define HostFixtureManifest v1 Before Probe Expansion - -The manifest must bind: - -- host identity -- environment identity -- protected action type -- protected path -- adapter identity and version -- wrapper identity -- wrapper configured path -- wrapper resolved path -- raw sibling candidates -- registry entry -- policy identity -- freshness timestamp -- tool list digest -- expected posture -- redaction policy -- non-claims - -Missing required fields fail closed. - -## D03: Define BypassProofPacket As Durable Evidence - -The packet must preserve: - -- probe execution inputs -- probe execution outputs -- wrapper integrity -- gateway binding -- freshness decisions -- protected-path posture -- gateway check result -- downstream execution result -- refusal evidence -- bypass evidence -- proof gaps -- redacted projection -- non-claims - -The packet is not a marketing artifact. It is reconstruction evidence. - -## D04: Stale Metadata Refuses Or Proof-Gaps - -Stale tool list digest, changed host tool digest, stale probe freshness, missing registry binding, wrapper drift, or unknown raw sibling posture cannot produce `READY`. - -Allowed outcomes are refusal, proof gap, or advisory-only posture. - -## D05: Protected-Path Posture Is Fixture-Specific - -Posture attaches to one host fixture at one freshness state. - -It does not attach to: - -- the whole host -- all tools in the host -- the package manager ecosystem -- MCP generally -- shell/browser/network paths -- x402 generally -- engineering agents generally - -## D06: CLI Report First, Dashboard Later - -CLI is the first adoption surface because it can show exact status, evidence, and non-claims without creating review theatre. - -Dashboard comes after proof packet stability. - -## D07: Exit States Are Product Surface - -Required exit states: - -- `READY` -- `ADVISORY_ONLY` -- `WRAPPER_MISSING` -- `WRAPPER_DRIFTED` -- `GATEWAY_UNBOUND` -- `RAW_SIBLING_MUTATION_POSSIBLE` -- `STALE_PROBE` -- `HOST_TOOL_DIGEST_CHANGED` -- `PROOF_GAP` - -These states are not internal details. They are the control vocabulary. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/PLAN.md deleted file mode 100644 index d46d126..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/PLAN.md +++ /dev/null @@ -1,326 +0,0 @@ -# GSD Macro Plan: Host-Specific Bypass Harnesses - -## Goal - -Invariant at stake: a protected action for automated decision making must not execute through an uncontracted host path while Handshake claims gateway-checked control. - -Build the first host-specific bypass harness for one configured installed host path, beginning with package-manager local host after package-install conformance is boring. The harness must prove only this narrow claim: - -In environment E, host H, adapter A, policy P, action T, Handshake resisted named bypass routes B and recorded evidence R at freshness state F. - -The harness must not claim host-wide containment, platform safety, package-manager safety, MCP safety, browser/shell/network protection, or x402 ecosystem coverage. - -x402 exact per-call remains the first proof wedge and calibration surface. It is not the protocol center. Handshake is protected actions for automated decision making, not engineering-agent-only infrastructure. - -## Non-Goals - -- No generic host sandbox. -- No host-wide safety claim. -- No MCP-wide or CLI-wide enforcement claim. -- No browser, shell, network, package-manager ecosystem, or platform containment claim. -- No claim that a host harness proves all sibling tools are blocked. -- No claim that x402 coverage implies broader payment ecosystem coverage. -- No dashboard-first delivery. -- No implementation in this macro step. -- No use of fixture evidence to manufacture establishment custody, gateway ownership, or host-wide control. - -## Source Boundary - -Current source named by the input packet: - -- `src/adapters/protected-path-probes/executor.ts` - - already contains `runBypassProbeExecutors` - - already contains `BypassProbeExecutor` -- conformance fixture support already has `fixtureGatewayCheckedBypassProbeExecutors` -- `src/adapters/x402-payment/bypass-probes.ts` - - already contains hostile x402 bypass probe executors -- existing x402 tests already prove: - - policy greenlights only after gateway-owned hostile probes pass - - raw x402 bypass paths cause policy refusal - - official SDK side channels are raw sibling bypass evidence - - direct payment, token passthrough, wrapper drift, and failure-open probes are distinct - - conformance fixture probes cannot manufacture gateway-checked posture - - fixture wallet custody is not establishment custody evidence -- auth.md bypass probes and MCP surface posture tests exist, but MCP and CLI are proposal, evidence, and read surfaces unless paired with blocking gateway enforcement. - -Canonical planning boundary: - -- This macro plan is scratch under `.planning/`. -- Repo-facing durable truth must only move into canonical docs or source after implementation validates it. -- No planning label from this macro may become an exported product claim. - -## Current State - -Handshake already has reusable bypass probe executor machinery and x402 hostile probe examples. That proves the shape of gateway-owned hostile probing, but not a host-specific harness for an installed configured host path. - -The current evidence posture is narrower than many tempting claims: - -- x402 evidence proves exact per-call bypass behavior for named payment paths. -- conformance fixture probes prove fixture behavior only. -- MCP and CLI surfaces can report, propose, or show evidence, but they do not enforce unless a gateway blocks mutation. -- existing probe results do not prove host-wide containment. -- existing probe results do not prove sibling package-manager, browser, shell, network, MCP, or SDK safety. - -The missing layer is a host fixture contract that binds a configured host, protected path, wrapped tool identity, raw sibling routes, freshness, wrapper integrity, expected posture, evidence redaction, and non-claims. - -## Target State - -A package-manager local host harness exists behind a strict fixture manifest. - -The first acceptable report states: - -- host identity -- environment identity -- adapter identity and version -- protected action type -- protected path -- configured wrapper path -- resolved wrapper path -- raw sibling candidates -- tool list digest -- registry entry -- policy identity -- freshness timestamp -- probe classes -- wrapper integrity result -- gateway binding result -- one-use greenlight result -- raw sibling refusal, detection, proof gap, or stop condition -- protected-path posture -- redacted bypass proof packet -- explicit non-claims - -The product bar is 10-star only if the report makes the boundary impossible to misunderstand: - -- it names exactly what was protected -- it names exactly what was probed -- it names exactly what was not probed -- it refuses stale metadata -- it refuses wrapper drift -- it distinguishes gateway check from downstream execution -- it records proof gaps instead of smoothing uncertainty -- it treats raw sibling reachability as evidence, not as a hidden detail -- it never lets redaction erase enforcement distinctions -- it exits advisory-only when the gateway cannot block consequence - -## Assumptions - -- Package-install conformance is the prerequisite first host boundary because package installation is a concrete protected action with visible raw sibling paths. -- x402 hostile probes are calibration examples, not the center of the protocol. -- A host harness can only speak about a named configured installed path and named bypass routes at a recorded freshness state. -- Host tool identity and resolved path can drift between runs. -- Tool catalogs can become stale. -- Raw sibling tools may remain reachable. -- Wrapper integrity can drift independently from policy logic. -- CLI and MCP reports are evidence surfaces unless paired with blocking gateway enforcement. -- Redaction is necessary, but redaction must preserve gateway, downstream, refusal, bypass, and proof-gap distinctions. - -## Decisions - -1. Choose package-manager local host first. - - Rationale: package install is a protected action with direct raw sibling risk and clear local host fixture boundaries. - - Constraint: start only after package-install conformance is stable enough to avoid fixture laundering. - -2. Use x402 hostile probes second as calibration. - - Rationale: x402 already has hostile bypass executor shape and exact per-call discipline. - - Constraint: do not recenter the protocol around x402. - -3. Define `HostFixtureManifest` v1 before adding more probes. - - Required bindings: host, environment, adapter, action type, protected path, wrapper path, raw sibling paths, registry entry, freshness, redaction, expected posture, non-claims. - -4. Define `BypassProofPacket` as the durable evidence object. - - Required sections: probes, wrapper integrity, freshness decisions, protected-path posture, raw sibling results, redacted projection, proof gaps, non-claims. - -5. Treat stale metadata as refusal or proof gap. - - Stale tool list digest, changed host tool digest, wrapper drift, stale probe results, or missing registry binding cannot produce gateway-checked posture. - -6. Keep protected-path posture fixture-specific. - - Posture is derived for one fixture, one host, one adapter, one action type, one freshness state. - - It is never host-wide. - -7. Put CLI report first. - - Dashboard can render later. - - First commands are conceptual product targets: `handshake harness init`, `check`, `probe`, `report`, and `doctor`. - -8. Keep MCP and CLI as separate host boundaries. - - They may show proposal and evidence posture. - - They are not enforcement unless paired with blocking gateway checks. - -## Phases - -Phase 0: Scope Lock And Precondition - -- Confirm package-install conformance is the first host harness target. -- Confirm x402 hostile probes remain calibration only. -- Write claim guards before new product claims can land. -- Stop if the plan drifts into host-wide protection. - -Phase 1: Host Fixture Contract - -- Define `HostFixtureManifest` v1. -- Bind host identity, protected action path, wrapper identity, raw sibling candidates, registry entry, adapter version, policy identity, freshness timestamp, expected posture, redaction policy, and non-claims. -- Add fixture validation that fails closed on missing or stale bindings. - -Phase 2: Wrapped Path Success - -- Prove a wrapped package-install path can receive one exact greenlight. -- Bind greenlight to one action contract and one gateway check. -- Record downstream execution separately from gateway acceptance. -- Stop if a greenlight can authorize multiple mutations. - -Phase 3: Raw Sibling Probes - -- Add raw sibling probes for package-manager bypass paths. -- Record each raw sibling as refusal, detection, proof gap, or stop condition. -- Stop if raw sibling mutation succeeds without refusal, proof gap, or quarantine evidence. - -Phase 4: Wrapper Integrity And Freshness - -- Detect wrapper missing, wrapper drift, gateway unbound, host tool digest changed, and stale probe results. -- Refuse or proof-gap stale metadata. -- Do not allow stale success to produce gateway-checked posture. - -Phase 5: Bypass Proof Packet And Redacted Projection - -- Emit `BypassProofPacket`. -- Emit redacted projection for CLI reports. -- Preserve distinctions between gateway check, downstream result, refusal, bypass evidence, and proof gap. - -Phase 6: Protected-Path Posture Updates - -- Derive fixture-specific protected-path posture from manifest plus proof packet. -- Supported exit states: - - `READY` - - `ADVISORY_ONLY` - - `WRAPPER_MISSING` - - `WRAPPER_DRIFTED` - - `GATEWAY_UNBOUND` - - `RAW_SIBLING_MUTATION_POSSIBLE` - - `STALE_PROBE` - - `HOST_TOOL_DIGEST_CHANGED` - - `PROOF_GAP` - -Phase 7: CLI Report And Claim Guard Closeout - -- CLI report shows protected path, tool list digest, wrapper integrity, gateway binding, probe freshness, raw sibling attempts, evidence, and non-claims. -- Dashboard remains deferred. -- Claim guards reject host-wide, platform-wide, MCP-wide, package-manager-wide, x402-ecosystem-wide, or engineering-agent-only framing. - -## Task Graph - -- T01 locks the scope and precondition. -- T02 defines `HostFixtureManifest` v1. -- T03 defines package-install fixture data. -- T04 proves wrapped path success with one-use greenlight. -- T05 adds raw sibling probes. -- T06 adds wrapper integrity checks. -- T07 adds freshness refusal and proof-gap behavior. -- T08 defines `BypassProofPacket`. -- T09 derives protected-path posture. -- T10 adds CLI report shape. -- T11 adds claim guards and closeout validation. - -No later task may claim posture without T02, T06, T07, and T08. - -## Risks And Mitigations - -- Stale tool list: - - Mitigation: bind tool list digest and freshness timestamp; stale digest becomes refusal or proof gap. - -- Wrapper drift: - - Mitigation: bind resolved path and wrapper digest; drift exits `WRAPPER_DRIFTED`. - -- Raw sibling reachability: - - Mitigation: enumerate named siblings in manifest; mutation-capable sibling exits `RAW_SIBLING_MUTATION_POSSIBLE`. - -- MCP or CLI overclaim: - - Mitigation: claim guard text says proposal/evidence/read surface unless blocking gateway enforcement exists. - -- Weak `sourceAuthority` fixtures: - - Mitigation: fixture source authority cannot stand in for establishment custody or host-wide posture. - -- Token passthrough: - - Mitigation: keep token passthrough as a distinct bypass class, not a generic wrapper failure. - -- Fixture laundering: - - Mitigation: conformance fixtures cannot manufacture gateway-checked posture. - -- Redaction leakage: - - Mitigation: redaction policy must hide sensitive values while preserving enforcement distinctions. - -- Evidence projection flattening: - - Mitigation: CLI report must keep gateway check, downstream execution, refusal, bypass, and proof gap separate. - -## Validation Gates - -Precondition gates: - -- package-install conformance passes before host harness posture can be claimed. -- x402 hostile bypass tests remain passing as calibration. -- existing bypass probe executor tests remain passing. - -Implementation closeout commands, once code exists: - -- `npm run quality:claims` -- `npm run quality:architecture` -- `npm run format:check` -- `npm run check:repo` - -Focused validation targets to add or run when available: - -- host fixture manifest schema tests -- wrapped package-install path one-use greenlight test -- raw sibling refusal or proof-gap tests -- wrapper missing and wrapper drift tests -- stale tool digest and stale probe tests -- bypass proof packet redaction tests -- protected-path posture derivation tests -- CLI report non-claim tests - -Report validation must show: - -- protected path -- tool list digest -- wrapper integrity -- gateway binding -- probe freshness -- raw sibling attempts -- evidence -- non-claims - -## Cut Lines - -Cut any claim that says or implies: - -- Handshake protects the whole host. -- Handshake protects all package-manager operations. -- Handshake protects MCP tools generally. -- Handshake protects browser, shell, or network paths. -- Handshake proves platform-wide containment. -- x402 coverage proves payment ecosystem coverage. -- Host harnesses prove engineering-agent safety generally. -- Fixture evidence proves establishment custody. -- A report is enforcement. -- A CLI or MCP surface is blocking without a gateway. -- A wrapped path success covers raw siblings. -- A redacted report can omit proof gaps. - -## Rollback / Stop Conditions - -Stop immediately if: - -- raw sibling mutation succeeds without refusal, quarantine, or proof-gap evidence -- gateway check and downstream execution are collapsed into one receipt field -- stale metadata still produces `READY` -- wrapper drift still produces gateway-checked posture -- one greenlight can authorize more than one mutation attempt -- fixture probes manufacture gateway-checked posture -- redacted projection hides bypass/proof-gap distinction -- CLI or MCP report claims enforcement without blocking gateway checks -- package-install harness expands into host-wide claims - -Rollback posture to `ADVISORY_ONLY` or `PROOF_GAP` when evidence is incomplete. - -## Smallest Next Action - -Write the `HostFixtureManifest` v1 contract for the package-manager local host harness, including non-claims and freshness refusal rules, before adding any new probe implementation. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/RISKS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/RISKS.md deleted file mode 100644 index 1628e9e..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/RISKS.md +++ /dev/null @@ -1,67 +0,0 @@ -# Risks: Host-Specific Bypass Harnesses - -## R01: Host-Wide Overclaim - -Failure mode: a fixture-level result is described as host protection. - -Mitigation: claim guards must reject host-wide, platform-wide, package-manager-wide, MCP-wide, browser/shell/network, and ecosystem-wide claims. - -Stop condition: any report says or implies host-wide containment. - -## R02: Stale Tool List - -Failure mode: a previously valid wrapper or raw sibling list changes, but old probe results still produce `READY`. - -Mitigation: bind tool list digest and freshness timestamp. Digest change exits `HOST_TOOL_DIGEST_CHANGED` or `STALE_PROBE`. - -## R03: Wrapper Drift - -Failure mode: the configured wrapper path changes or no longer binds to the gateway. - -Mitigation: compare configured path, resolved path, wrapper digest, and registry binding. Drift exits `WRAPPER_DRIFTED` or `GATEWAY_UNBOUND`. - -## R04: Raw Sibling Mutation - -Failure mode: package install succeeds through an unwrapped sibling path while Handshake reports protected posture. - -Mitigation: raw sibling probes are required. Mutation-capable sibling exits `RAW_SIBLING_MUTATION_POSSIBLE` and blocks `READY`. - -Stop condition: raw sibling mutation succeeds without refusal, quarantine, or proof-gap evidence. - -## R05: Gateway/Downstream Evidence Collapse - -Failure mode: receipt cannot distinguish gateway check from downstream execution. - -Mitigation: `BypassProofPacket` has separate gateway check and downstream result fields. - -Stop condition: evidence projection flattens these fields. - -## R06: MCP/CLI Enforcement Overclaim - -Failure mode: report or proposal surfaces are treated as enforcement. - -Mitigation: MCP and CLI are proposal/evidence/read surfaces unless paired with blocking gateway checks. - -## R07: Weak Source Authority - -Failure mode: fixture `sourceAuthority` is treated as establishment custody or real gateway ownership. - -Mitigation: fixture authority remains fixture-only and cannot produce establishment custody evidence. - -## R08: Token Passthrough - -Failure mode: a token or payment proof is passed around the wrapper, creating false gateway posture. - -Mitigation: token passthrough remains a distinct bypass class and must be recorded separately. - -## R09: Fixture Laundering - -Failure mode: conformance fixture probes are used to manufacture gateway-checked host posture. - -Mitigation: conformance fixture evidence can satisfy schema behavior only, not host posture. - -## R10: Redaction Erases Control Meaning - -Failure mode: redacted report hides the difference between refusal, bypass, downstream uncertainty, and proof gap. - -Mitigation: redaction policy must preserve control-state labels and evidence categories. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/TASKS.jsonl b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/TASKS.jsonl deleted file mode 100644 index f4d0e00..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/TASKS.jsonl +++ /dev/null @@ -1,11 +0,0 @@ -{"id":"T01","priority":"P0","phase":"scope-lock","title":"Lock package-manager local host as first harness target","owner":"implementation agent","rationale":"The first harness needs a concrete protected action boundary and must not drift into host-wide or x402-centered claims.","depends_on":[],"acceptance":["package-manager local host is named as the first target","package-install conformance is documented as a precondition","x402 is documented as calibration only","host-wide and ecosystem claims are explicitly excluded"],"candidate_paths":[".planning/macro/active/host-specific-bypass-harnesses/PLAN.md","docs/internal/decisions.md"],"non_goals":["implement probes","claim host-wide containment","recenter protocol on x402"]} -{"id":"T02","priority":"P0","phase":"fixture-contract","title":"Define HostFixtureManifest v1","owner":"implementation agent","rationale":"Posture cannot be derived until host identity, protected path, wrapper, raw siblings, freshness, redaction, and non-claims are bound.","depends_on":["T01"],"acceptance":["manifest binds host identity, environment, adapter version, protected action type, protected path, wrapper path, raw siblings, registry entry, policy identity, freshness, tool digest, expected posture, redaction, and non-claims","missing required fields fail closed","manifest language states fixture-specific scope"],"candidate_paths":["src/adapters/protected-path-probes","src/adapters/package-install","tests"],"non_goals":["define generic host sandbox","cover MCP host","cover browser shell or network"]} -{"id":"T03","priority":"P0","phase":"fixture-contract","title":"Create package-install host fixture seed","owner":"implementation agent","rationale":"The manifest needs concrete package-install fixture data before meaningful wrapped and raw sibling probes can run.","depends_on":["T02"],"acceptance":["fixture names one package-install protected path","fixture names configured wrapper and resolved path","fixture names raw sibling package-manager routes","fixture includes freshness timestamp and tool list digest","fixture includes explicit non-claims"],"candidate_paths":["src/adapters/package-install","tests/fixtures","docs/internal/protocol-notes.md"],"non_goals":["prove package-manager ecosystem safety","support multiple hosts initially","dashboard rendering"]} -{"id":"T04","priority":"P0","phase":"wrapped-path","title":"Prove wrapped path one-use greenlight behavior","owner":"implementation agent","rationale":"A harness must prove that the protected path executes only through an exact one-use gateway-bound greenlight.","depends_on":["T03"],"acceptance":["wrapped package-install attempt receives one exact greenlight","greenlight binds to one action contract","gateway check occurs before mutation","reuse of the greenlight is refused","gateway check and downstream result are recorded separately"],"candidate_paths":["src/adapters/protected-path-probes/executor.ts","src/adapters/package-install","tests"],"non_goals":["raw sibling coverage","host-wide readiness","MCP enforcement"]} -{"id":"T05","priority":"P0","phase":"raw-sibling-probes","title":"Add raw sibling package-manager bypass probes","owner":"implementation agent","rationale":"Wrapped success is meaningless if raw sibling mutation can bypass the contract boundary.","depends_on":["T03","T04"],"acceptance":["each named raw sibling route is attempted or proof-gapped","raw sibling mutation possibility blocks READY","raw sibling refusal records evidence","raw sibling probe class is recorded in proof packet inputs"],"candidate_paths":["src/adapters/protected-path-probes","src/adapters/package-install","tests"],"non_goals":["discover all possible host tools","claim complete package-manager safety","execute destructive real installs"]} -{"id":"T06","priority":"P0","phase":"wrapper-integrity","title":"Add wrapper integrity and gateway binding checks","owner":"implementation agent","rationale":"A configured wrapper path is not authority unless it resolves to the expected gateway-bound wrapper at freshness time.","depends_on":["T02","T03"],"acceptance":["missing wrapper exits WRAPPER_MISSING","digest drift exits WRAPPER_DRIFTED","missing gateway binding exits GATEWAY_UNBOUND","resolved path and adapter version are recorded"],"candidate_paths":["src/adapters/protected-path-probes","src/adapters/package-install","tests"],"non_goals":["trust configured path without resolution","allow wrapper drift under READY","host-wide wrapper inventory"]} -{"id":"T07","priority":"P0","phase":"freshness","title":"Implement stale metadata refusal and proof-gap rules","owner":"implementation agent","rationale":"Old probe success cannot authorize current posture after tool list, host digest, wrapper, or registry drift.","depends_on":["T02","T06"],"acceptance":["stale probe exits STALE_PROBE","changed host tool digest exits HOST_TOOL_DIGEST_CHANGED","missing freshness exits PROOF_GAP","stale metadata cannot produce READY"],"candidate_paths":["src/adapters/protected-path-probes","src/adapters/package-install","tests"],"non_goals":["best-effort freshness warnings","silent stale success","long-lived ambient authorization"]} -{"id":"T08","priority":"P0","phase":"proof-packet","title":"Define BypassProofPacket and redacted projection","owner":"implementation agent","rationale":"Reconstruction requires one evidence object that preserves gateway, downstream, refusal, bypass, freshness, and proof-gap distinctions.","depends_on":["T04","T05","T06","T07"],"acceptance":["packet includes manifest reference and probe results","packet separates gateway check from downstream execution","packet records refusal, bypass, and proof gaps separately","redacted projection hides secrets without erasing control distinctions","non-claims are included"],"candidate_paths":["src/adapters/protected-path-probes","src/adapters/package-install","tests"],"non_goals":["marketing report","lossy redaction","single pass fail boolean only"]} -{"id":"T09","priority":"P1","phase":"posture","title":"Derive protected-path posture from manifest and proof packet","owner":"implementation agent","rationale":"Posture must be computed from evidence, not asserted by adapter optimism.","depends_on":["T08"],"acceptance":["READY requires fresh manifest, wrapper integrity, gateway binding, one-use greenlight, and no raw sibling mutation evidence","ADVISORY_ONLY is used for non-blocking surfaces","all required exit states are represented","posture is fixture-specific and never host-wide"],"candidate_paths":["src/adapters/protected-path-probes","src/adapters/package-install","tests"],"non_goals":["manual posture override","host-wide posture","dashboard status badges"]} -{"id":"T10","priority":"P1","phase":"cli-report","title":"Specify CLI report shape for harness evidence","owner":"implementation agent","rationale":"Adoption starts with a report that makes evidence and non-claims explicit before dashboard work creates review theatre risk.","depends_on":["T08","T09"],"acceptance":["report shows protected path, tool list digest, wrapper integrity, gateway binding, probe freshness, raw sibling attempts, evidence, and non-claims","report supports READY, ADVISORY_ONLY, WRAPPER_MISSING, WRAPPER_DRIFTED, GATEWAY_UNBOUND, RAW_SIBLING_MUTATION_POSSIBLE, STALE_PROBE, HOST_TOOL_DIGEST_CHANGED, and PROOF_GAP","report does not claim enforcement without blocking gateway checks"],"candidate_paths":["src/cli","src/adapters/protected-path-probes","tests"],"non_goals":["dashboard implementation","operator approval UI","generic compliance report"]} -{"id":"T11","priority":"P0","phase":"claim-guards","title":"Add claim guards and closeout validation for harness scope","owner":"implementation agent","rationale":"The hardest failure is a correct fixture result turned into an incorrect product claim.","depends_on":["T01","T09","T10"],"acceptance":["claim guards reject host-wide, platform-wide, package-manager-wide, MCP-wide, browser shell network, x402 ecosystem, and engineering-agent-only claims","quality and repo checks are documented as closeout gates","validation includes non-claim report checks"],"candidate_paths":["scripts","docs/internal","tests","QUALITY.md"],"non_goals":["broaden product category incorrectly","ship without claim checks","turn planning labels into source API names"]} diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/VALIDATION.md deleted file mode 100644 index ae0f99d..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/VALIDATION.md +++ /dev/null @@ -1,93 +0,0 @@ -# Validation: Host-Specific Bypass Harnesses - -## Validation Principle - -A host harness passes only when it proves a narrow protected-path claim and records explicit non-claims. Broad confidence is failure. - -## Precondition Gates - -- Package-install conformance must pass before package-manager local host posture can be claimed. -- Existing x402 hostile bypass tests must remain passing as calibration. -- Existing bypass probe executor behavior must remain passing. -- Claim guards must reject engineering-agent-only framing and host-wide safety language. - -## Required Test Classes - -1. Host fixture manifest schema - - missing host fails - - missing protected path fails - - missing wrapper fails - - missing raw sibling list fails - - missing freshness fails - - missing non-claims fails - -2. Wrapped path success - - wrapped package-install path receives one exact greenlight - - greenlight binds to one action contract - - gateway check is recorded before mutation - - downstream execution is recorded separately - -3. Raw sibling probes - - named raw sibling attempts are executed or proof-gapped - - raw sibling mutation blocks `READY` - - raw sibling refusal records evidence - -4. Wrapper integrity - - missing wrapper exits `WRAPPER_MISSING` - - digest drift exits `WRAPPER_DRIFTED` - - gateway-unbound wrapper exits `GATEWAY_UNBOUND` - -5. Freshness - - stale probe exits `STALE_PROBE` - - changed host tool digest exits `HOST_TOOL_DIGEST_CHANGED` - - stale metadata cannot produce `READY` - -6. Bypass proof packet - - packet includes manifest reference - - packet separates gateway check from downstream result - - packet records refusal, bypass, and proof-gap evidence separately - -7. Redacted projection - - secrets are hidden - - control distinctions remain visible - - non-claims remain visible - -8. Protected-path posture - - `READY` requires wrapper integrity, gateway binding, fresh probes, and no raw sibling mutation evidence - - `ADVISORY_ONLY` is used when reporting exists without blocking enforcement - - `PROOF_GAP` is used when evidence is missing - -9. CLI report - - shows protected path - - shows tool list digest - - shows wrapper integrity - - shows gateway binding - - shows probe freshness - - shows raw sibling attempts - - shows evidence - - shows non-claims - -## Closeout Commands - -Run when implementation exists: - -- `npm run quality:claims` -- `npm run quality:architecture` -- `npm run format:check` -- `npm run check:repo` - -Focused commands should be added or used for: - -- host fixture manifest tests -- package-install conformance tests -- protected-path bypass probe tests -- x402 hostile bypass calibration tests -- claim guard tests - -## Acceptance Claim - -The only acceptable product claim after closeout: - -In environment E, host H, adapter A, policy P, action T, Handshake resisted named bypass routes B and recorded evidence R at freshness state F. - -Any stronger claim fails validation. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/input.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/input.md deleted file mode 100644 index a965057..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/input.md +++ /dev/null @@ -1,100 +0,0 @@ -# GSD Macro Input: Host-Specific Bypass Harnesses - -Run id: `host-specific-bypass-harnesses-20260524T084500Z` -Date: 2026-05-24 - -## Hard Frame - -Handshake is protected actions for automated decision making, not engineering-agent-only. - -x402 exact per-call protected action is the first wedge, not the protocol center. - -Host-specific bypass harnesses must prove a configured installed path resisted named host/runtime bypass in a specific environment. They must not claim host-wide MCP/browser/shell/network/package-manager protection. - -The target proof shape: - -```text -host fixture --> wrapped protected action succeeds only after gateway --> raw sibling attempt refused or detected --> bypass proof packet --> protected-path posture update -``` - -## Current Source State - -Existing source already contains: - -- `runBypassProbeExecutors()` and `BypassProbeExecutor` in `src/adapters/protected-path-probes/executor.ts`. -- `fixtureGatewayCheckedBypassProbeExecutors()` for conformance fixture probes. -- x402 hostile bypass probe executors in `src/adapters/x402-payment/bypass-probes.ts`. -- x402 hostile tests proving: - - policy greenlights only after gateway-owned hostile probes pass; - - raw x402 bypass paths cause policy refusal; - - official SDK side channels are raw sibling bypass evidence; - - direct payment, token passthrough, wrapper drift, and failure-open probes are distinct; - - conformance fixture probes cannot manufacture gateway-checked posture; - - fixture wallet custody is not establishment custody evidence. -- Auth.md bypass probes and MCP surface posture tests exist. - -Current `.planning/codebase/CONCERNS.md` says: - -- Broad host interception is not proven. -- Runtime ingress and MCP record observed or synthetic bypass-shaped evidence. -- They do not prove all browser, shell, MCP, package-manager, cloud, network, database, or repo mutation paths are intercepted in a real host. -- Require host-specific bypass probes and gateway-owned credentials before claiming protection for a runtime, MCP host, browser tool, shell wrapper, package manager, or cloud adapter. - -Current `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` says host-specific bypass harnesses should implement: - -```text -host fixture --> wrapped protected action succeeds only after gateway --> raw sibling attempt refused or detected --> bypass proof packet --> protected-path posture update -``` - -Mechanisms: - -- host/runtime fixture manifest; -- raw sibling attempt probes; -- wrapper integrity checks; -- stale host metadata refusal; -- redacted bypass projection. - -Tests: - -- fixture pass/fail tests; -- stale metadata tests; -- claim guards preventing host-wide protection language. - -Failure mode: - -- Host tool list changes after posture is recorded, but gateway still trusts old posture. -- Must refuse or downgrade posture until probes are refreshed. - -## Planning Question - -Create a macro plan for host-specific bypass harnesses that makes the harnesses source-owned, host-specific, freshness-bound, and impossible to launder into broad host protection claims. - -Select the first host harness target. Likely answer: start with local package-manager host harness after package-install adapter conformance, because package install is the next adapter pack and raw package-manager bypass is the sharpest first risk. Challenge if x402-hostile or MCP-host harness should come first. - -## Required Output Properties - -The plan must include: - -- selected first host harness and why; -- explicit non-goals and cut lines; -- host fixture manifest contract; -- raw sibling attempt probes; -- wrapper integrity checks; -- stale metadata and freshness refusal; -- protected-path posture update rules; -- bypass proof packet/redacted projection; -- relationship to package-install adapter expansion; -- relationship to MCP/CLI proposal-only surfaces; -- validation gates and closeout commands; -- claim guards preventing broad host protection language; -- 10-star product bar and antipatterns. - -Do not implement source changes in this run. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/ADOPTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/ADOPTION.md deleted file mode 100644 index 1fd2751..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/ADOPTION.md +++ /dev/null @@ -1,176 +0,0 @@ -# ADOPTION: Host-Specific Bypass Harnesses - -## Invariant At Stake - -A host-specific bypass harness may prove only one installed protected path. If it implies whole-host containment while raw sibling tools can still mutate, it becomes evidence theatre. - -## Operator Workflow - -1. Install one protected adapter path, e.g. `package-install`. -2. Register the expected host surface: - `handshake harness init --host codex --protected-path package-install` -3. Run readiness: - `handshake harness check --host codex --path package-install` -4. Run bypass probes: - `handshake harness probe --host codex --path package-install` -5. Review the report: - `handshake harness report --host codex --path package-install` -6. Decide posture: - `ready`, `advisory`, `blocked`, or `unknown`. - -The workflow should answer one question: - -> "For this host, is this installed protected package-install path actually gateway-bound, and what nearby raw paths remain outside Handshake?" - -Not: - -> "Is this host safe?" - -## Report Affordances - -The report should be intentionally narrow: - -```text -Host: codex -Protected path: package-install -Adapter version: ... -Tool list digest: sha256:... -Wrapper integrity: pass/fail/unknown -Probe freshness: 2026-05-24T... -Gateway authority holder: ... -Raw sibling attempts: detected/refused/unobserved/not-tested -Protected path posture: enforced/advisory/missing/drifted -Non-claims: listed explicitly -``` - -Required sections: - -- `Protected Path`: exact tool/action path under test. -- `Tool List Digest`: host-exposed tool inventory hash at probe time. -- `Wrapper Integrity`: whether the installed wrapper matches expected adapter identity/config. -- `Gateway Binding`: whether mutation requires exact greenlight verification. -- `Probe Freshness`: when probes last ran, against which host digest. -- `Raw Sibling Attempts`: nearby mutation routes attempted outside the wrapper. -- `Evidence`: receipts, refusals, proof gaps, bypass findings. -- `Non-Claims`: what this report does not prove. - -## Command Names - -Keep command names boring and explicit: - -```bash -handshake harness init --host codex --protected-path package-install -handshake harness check --host codex --protected-path package-install -handshake harness probe --host codex --protected-path package-install -handshake harness report --host codex --protected-path package-install -handshake harness doctor --host codex --protected-path package-install -``` - -Avoid names like `secure-host`, `contain`, `lockdown`, or `verify-agent`. They overclaim. - -Useful exit states: - -```text -READY -ADVISORY_ONLY -WRAPPER_MISSING -WRAPPER_DRIFTED -GATEWAY_UNBOUND -RAW_SIBLING_MUTATION_POSSIBLE -STALE_PROBE -HOST_TOOL_DIGEST_CHANGED -PROOF_GAP -``` - -## Diagnostics And Errors - -Good errors name the broken boundary. - -```text -GATEWAY_UNBOUND: -The package-install adapter produced evidence, but no gateway check enforced an exact greenlight before mutation. -This is advisory, not Handshake. -``` - -```text -RAW_SIBLING_MUTATION_POSSIBLE: -The protected package-install path is wrapped, but the host still exposes a raw sibling install path. -This harness does not prove host containment. -``` - -```text -HOST_TOOL_DIGEST_CHANGED: -The host tool list changed since the last passing probe. -Re-run bypass probes before relying on this readiness report. -``` - -```text -WRAPPER_DRIFTED: -The installed wrapper does not match the expected adapter digest. -Do not treat prior receipts as evidence for the current protected path. -``` - -```text -PROOF_GAP: -The harness could not determine whether the mutation reached the gateway before consequence. -Record the gap; do not smooth it into pass/fail. -``` - -## Anti-Frustration Details - -- Always show the one protected path that is in scope. -- Always show raw sibling paths separately from protected path failures. -- Do not fail the whole harness because whole-host containment is absent; mark posture as `ADVISORY_ONLY` or `RAW_SIBLING_MUTATION_POSSIBLE`. -- Cache prior passing probes, but invalidate on host digest, adapter digest, gateway config, or policy version change. -- Give a copy-paste next command after every failure. -- Make `doctor` explain whether the operator needs to install a wrapper, bind a gateway, rerun probes, or accept a non-claim. -- Let operators produce a report even when blocked. A blocked report is useful evidence. -- Do not require dashboard setup for first value. CLI report first; UI later. - -## 10-Star Bar - -A 10-star first host harness does this: - -- Proves one package-install path is gateway-bound before mutation. -- Detects wrapper drift deterministically. -- Hashes the host tool list and invalidates stale readiness. -- Attempts raw sibling package-install routes and reports their posture. -- Separates `protected path enforced` from `host contained`. -- Emits receipts/refusals/proof gaps with stable IDs. -- Produces an operator-readable report in under one minute. -- Gives precise remediation commands. -- Makes non-claims impossible to miss. -- Never lets CLI/MCP evidence masquerade as enforcement. - -## Cut Lines - -Cut whole-host containment claims. - -Cut "agent safety" language. - -Cut host-wide badges unless every consequential sibling path is gateway-enforced. - -Cut CLI/MCP mutation unless it performs a real gateway check before consequence. - -Cut dashboard dependency for the first harness. - -Cut generic "policy passed" language unless the exact contract and one-use greenlight are shown. - -Cut any report that cannot distinguish: - -```text -proposal observed -policy evaluated -gateway checked -mutation attempted -downstream result known -proof gap recorded -``` - -## Brutal Verdict - -Keep the host-specific bypass harness, but narrow it hard. - -The first harness should be a package-install protected-path readiness report, not a host security product. Its job is to make an operator confident that one installed adapter path is real Handshake enforcement, while loudly showing every adjacent path that remains advisory, raw, stale, or unproven. - -Smallest next mechanism to build: define the `package-install` harness report schema with `host`, `protectedPath`, `toolListDigest`, `wrapperIntegrity`, `probeFreshness`, `rawSiblingAttempts`, `protectedPathPosture`, `evidenceRefs`, and `nonClaims`. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/ARCH.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/ARCH.md deleted file mode 100644 index 34f77bd..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/ARCH.md +++ /dev/null @@ -1,230 +0,0 @@ -# ARCH: Host-Specific Bypass Harnesses - -## Invariant At Stake - -Host-specific bypass harnesses must prove only this: for a named environment, the protected path, wrapper path, raw sibling path, stale metadata path, and redacted evidence path behaved as expected under source-owned fixtures. They must not imply host-wide protection, platform-wide safety, or unobserved gateway enforcement. - -## Architecture Plan - -### 1. Host Fixture Manifest Contract - -Create a source-owned manifest that declares the named host fixture, not the host category. - -```ts -type HostFixtureManifest = { - schemaVersion: "host-fixture-manifest.v1"; - manifestId: string; - host: { - kind: "package-install" | "mcp" | "cli" | "x402" | "custom"; - name: string; - fixtureVersion: string; - adapterPackage?: string; - }; - protectedPaths: ProtectedPathFixture[]; - wrappers: WrapperFixture[]; - rawSiblings: RawSiblingFixture[]; - freshness: FreshnessPolicyFixture; - redaction: RedactionPolicyFixture; - expectedPosture: ProtectedPathPostureExpectation; -}; -``` - -The manifest must bind every probe to: - -- exact host fixture identity; -- exact protected path; -- gateway registry entry; -- wrapper entrypoint; -- raw sibling entrypoint, if known; -- expected refusal/proof-gap behavior; -- metadata freshness policy. - -No manifest field may say or imply "host protected." Valid language is "fixture observed," "fixture refused," "fixture proof gap," or "fixture inconclusive." - -### 2. Bypass Proof Packet - -`runBypassProbeExecutors()` should emit a packet that preserves the chain without overclaiming. - -```ts -type BypassProofPacket = { - packetId: string; - manifestId: string; - generatedAt: string; - host: HostFixtureManifest["host"]; - probes: BypassProbeRecord[]; - wrapperIntegrity: WrapperIntegrityRecord[]; - freshnessDecisions: FreshnessDecisionRecord[]; - protectedPathPosture: ProtectedPathPostureRecord; - projection: RedactedBypassProjection; -}; -``` - -The packet is evidence of a fixture run. It is not a receipt for real host behavior and not proof that all sibling mutation paths are covered. - -### 3. Freshness And Staleness Model - -Freshness should be explicit policy, not timestamp vibes. - -Each manifest declares: - -- `metadataIssuedAt`; -- `metadataExpiresAt`; -- `gatewayRegistryDigest`; -- `wrapperDigest`; -- `adapterDigest`; -- `hostFixtureDigest`; -- `maxAgeMs`; -- `requiredClockSkewMs`. - -Stale metadata must produce a refusal-like result: - -```ts -type FreshnessDecision = - | "fresh" - | "stale_metadata_refused" - | "missing_metadata_refused" - | "digest_mismatch_refused" - | "clock_uncertain_proof_gap"; -``` - -The important boundary: stale fixture metadata cannot update protected-path posture to "covered." At most it can produce `proof_gap_stale_metadata`. - -### 4. Protected-Path Posture Update Rules - -Posture must be derived from packet evidence, never set by the adapter claiming safety. - -Recommended posture states: - -```ts -type ProtectedPathPosture = - | "not_declared" - | "declared_unprobed" - | "gateway_checked_fixture_passed" - | "raw_sibling_refused" - | "raw_sibling_bypass_observed" - | "wrapper_integrity_failed" - | "stale_metadata_refused" - | "proof_gap" - | "inconclusive"; -``` - -Update rules: - -- gateway-checked probe passed: may mark only that exact protected path as `gateway_checked_fixture_passed`; -- raw sibling attempt refused: may mark only that named sibling path as `raw_sibling_refused`; -- raw sibling attempt succeeds: path becomes `raw_sibling_bypass_observed`; -- wrapper digest mismatch: `wrapper_integrity_failed`; -- stale metadata: `stale_metadata_refused`; -- missing executor or unmodeled sibling: `proof_gap`; -- conflicting records: `inconclusive`. - -Never aggregate from one fixture to a host-wide posture. - -### 5. Redacted Projection - -The redacted projection is the shareable artifact for docs, dashboards, CI, or package users. - -It should expose: - -- manifest id; -- host kind/name; -- protected path ids; -- probe outcomes; -- posture state; -- refusal/proof-gap reasons; -- timestamps; -- digests or digest prefixes; -- redacted executor labels. - -It must hide: - -- credentials; -- raw host tokens; -- concrete secret-bearing request bodies; -- local filesystem paths unless explicitly safe; -- environment variables; -- private package registry URLs if sensitive; -- full downstream responses that may contain secrets. - -Projection rule: redaction is not allowed to erase the distinction between gateway check, downstream execution, refusal, bypass, and proof gap. If redaction would destroy that distinction, emit `redaction_limited_projection` as a proof gap. - -### 6. Relationship To Package-Install Adapter Pack - -The package-install adapter pack should become the first named host-family proving ground, not a generic bypass guarantee. - -It should provide: - -- one manifest per package-manager fixture; -- gateway-checked install probe; -- raw sibling install attempt probe; -- wrapper integrity probe; -- stale metadata fixture; -- redacted bypass projection fixture. - -Example fixture families: - -- `npm-install.fixture.v1`; -- `pnpm-install.fixture.v1`; -- `bun-add.fixture.v1`; -- `pip-install.fixture.v1`, only when the adapter actually exists. - -Do not claim "package installs protected." Claim "this adapter fixture observed exact gateway enforcement and raw sibling refusal for these declared entrypoints." - -### 7. MCP / CLI Boundary - -MCP and CLI must be treated as separate host boundaries. - -For MCP: - -- manifest binds server name, tool name, tool schema digest, gateway registry id, and raw tool-call sibling if available; -- probe executor attempts both wrapped MCP call and declared raw sibling call; -- receipt must distinguish MCP transport acceptance from gateway authorization. - -For CLI: - -- manifest binds command, subcommand, argument normalization, wrapper binary digest, and raw executable sibling; -- raw sibling probe must prove whether direct command execution bypasses the wrapper; -- if the CLI can shell out to another executable, that must become either a declared sibling or a proof gap. - -Boundary rule: an MCP server exposing a CLI-backed tool does not inherit CLI protection unless the CLI path is separately declared and probed. - -### 8. Import / Export Posture - -Exports should be narrow and product-facing only where the invariant is stable. - -Recommended public exports: - -```ts -export type HostFixtureManifest; -export type BypassProofPacket; -export type RedactedBypassProjection; -export type ProtectedPathPosture; -export function runBypassProbeExecutors(...); -export function projectBypassProofPacket(...); -``` - -Keep internal: - -- hostile executor implementations; -- raw sibling harness internals; -- fixture secret handling; -- digest construction helpers if unstable; -- host-specific test-only executors. - -Import rule: adapters import manifest/probe contracts from core. Core must not import package-install, MCP, or CLI adapter internals. Adapter packs register fixtures outward. - -## Build Order - -1. Define `HostFixtureManifest` and validation tests. -2. Extend probe records into `BypassProofPacket`. -3. Add freshness refusal decisions. -4. Add raw sibling attempt probes. -5. Add wrapper integrity checks. -6. Implement protected-path posture derivation. -7. Add redacted projection. -8. Wire package-install adapter fixtures as the first adapter pack. -9. Add MCP and CLI manifests only after package-install proves the contract shape. - -## Brutal Verdict - -Keep the harness idea, but keep it small. Host harnesses are conformance fixtures, not universal host protection. The smallest next mechanism to build is the `HostFixtureManifest` plus a packet-level posture derivation test that proves stale metadata and raw sibling bypass cannot be smoothed into "protected." diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/EXECUTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/EXECUTION.md deleted file mode 100644 index 89de6bb..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/EXECUTION.md +++ /dev/null @@ -1,259 +0,0 @@ -# EXECUTION: Host-Specific Bypass Harnesses - -## Invariant At Stake - -Broad host interception is not proven until a host-specific harness shows the exact protected path is enforced, a raw sibling path is refused or detected, stale host posture is rejected, and the surviving evidence is reconstructable. - -## First Host Target - -First target: **package-manager local host**, after package-install conformance lands. - -Reason: package install is consequential, local, cheap to fixture, and has obvious raw siblings: `npm install`, `pnpm add`, `bun add`, `npx`, lockfile mutation, lifecycle scripts, and direct binary invocation. It is narrower and less flaky than preview deploys or cloud APIs, but still exercises the real primitive: generated automation can bypass the wrapped gateway path through the host. - -This plan must stay host-specific. Do not claim broad host interception from one package-manager harness. - -## Phase 0: Scope Lock And Preconditions - -Tasks: - -1. Confirm package-install conformance defines the canonical protected action contract. -2. Identify the wrapped package-install path that already requires policy greenlight and gateway check. -3. Define the raw sibling paths for the first host: - - direct package-manager command - - alternate package-manager binary if present - - package-manager subcommand that mutates lockfile or dependency manifest - - lifecycle-script-triggered mutation path if safe to fixture -4. Define the minimum host metadata required before any host claim: - - host kind - - package-manager binary path - - package-manager version - - project root - - manifest path - - lockfile path - - interception adapter version - - timestamp / freshness window - - fixture id - -Dependencies: - -- Package-install action catalog entry exists. -- Gateway check can bind greenlight to one exact package-install mutation attempt. -- Receipt model can distinguish gateway check from downstream package-manager result. - -Validation gate: - -- If package-install conformance is not landed, stop. A bypass harness without the canonical wrapped path becomes theatre. - -## Phase 1: Host Fixture Contract - -Tasks: - -1. Add a fixture definition for `package-manager-local`. -2. Make the fixture describe both paths: - - `wrappedPath`: expected to succeed only after exact gateway greenlight - - `rawSiblingPath`: expected to be refused, blocked, or detected as bypass -3. Require fixture metadata to be fresh. -4. Define stale metadata refusal: - - stale fixture timestamp - - binary path changed - - package-manager version changed - - manifest or lockfile path changed - - adapter version mismatch -5. Emit a refusal when metadata is stale, not a warning. - -Dependencies: - -- Host fixture model. -- Reason-code registry or equivalent refusal taxonomy. -- Protected path posture store. - -Validation gate: - -- A stale host fixture must produce a refusal/proof-gap receipt before any mutation attempt is allowed. - -## Phase 2: Wrapped Path Success - -Tasks: - -1. Use the package-manager fixture to propose one exact package-install contract. -2. Evaluate policy. -3. Issue one greenlight. -4. Run the wrapped package-manager path through the gateway. -5. Record: - - candidate action - - canonical contract hash - - policy decision - - gateway check result - - package-manager execution result - - manifest/lockfile evidence - - greenlight consumed state - -Dependencies: - -- Deterministic canonicalization. -- One-use greenlight enforcement. -- Receipt store can record gateway and downstream result separately. - -Validation gate: - -- The wrapped path must fail without greenlight. -- The wrapped path must succeed with exact greenlight. -- Reusing the same greenlight must fail. - -## Phase 3: Raw Sibling Refusal Or Detection - -Tasks: - -1. Execute the equivalent raw package-manager sibling path inside the host fixture. -2. Confirm one of the allowed outcomes: - - refused before mutation - - blocked by host interception - - detected as bypass with proof packet -3. Forbid success-without-evidence. -4. Record the bypass attempt against the same fixture id and protected surface. - -Dependencies: - -- Raw sibling command list. -- Interception adapter or detector for package-manager local host. -- Receipt shape for bypass proof packet. - -Validation gate: - -- If raw sibling mutation succeeds and no bypass proof packet is recorded, stop. The generated program escaped the contract boundary. - -## Phase 4: Bypass Proof Packet - -Tasks: - -1. Define the proof packet fields: - - fixture id - - host kind - - protected surface - - wrapped action contract hash if related - - raw sibling command or invocation fingerprint - - host metadata snapshot - - detection/refusal mechanism - - mutation evidence or non-mutation evidence - - timestamp - - posture update recommendation -2. Ensure the proof packet distinguishes: - - refused before mutation - - blocked before mutation - - detected after attempted mutation - - proof gap -3. Add claim guards so docs/tests cannot say "host interception works" without naming the specific host and proof packet. - -Dependencies: - -- Receipt/proof-gap schema. -- Protected path posture model. -- Quality claim guard script or equivalent repo quality check. - -Validation gate: - -- A bypass result without a proof packet is not a pass. -- A proof packet that cannot distinguish gateway check from downstream execution is evidence theatre. - -## Phase 5: Protected Path Posture Update - -Tasks: - -1. Update posture for `package-manager-local`. -2. Use narrow statuses: - - `unproven` - - `wrapped-path-conformant` - - `raw-sibling-detected` - - `raw-sibling-blocked` - - `proof-gap` - - `stale-host-metadata-refused` -3. Make posture host-specific and fixture-specific. -4. Prevent broad claims like "host bypass is solved." - -Dependencies: - -- Posture store or internal protocol note. -- Claim guards. -- Validation output from phases 2-4. - -Validation gate: - -- Posture cannot advance unless wrapped success, raw sibling refusal/detection, and proof packet all exist for the same host fixture. - -## Phase 6: Claim Guards And Closeout - -Tasks: - -1. Add guards that reject unsupported claims: - - "broad host interception" - - "host bypass solved" - - "raw tools blocked" without host target - - "package-manager protected" without proof packet -2. Require docs to name: - - host target - - fixture id or test family - - wrapped path result - - raw sibling result - - stale metadata refusal behavior -3. Keep `.planning/` scratch out of canonical claims. - -Dependencies: - -- Existing quality claim checks. -- Canonical docs ownership rules. - -Validation gate: - -- Any repo-facing claim about host interception must be backed by host-specific test evidence. - -## Closeout Commands - -Run only after implementation, not during this planning turn: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -Add focused gates when implemented: - -```bash -npm run test:package-install-conformance -npm run test:host-bypass:package-manager-local -``` - -If those script names do not exist, the implementation should add or map the focused checks before claiming closeout. - -## Rollback / Stop Conditions - -Stop immediately if: - -1. Package-install conformance is not landed. -2. The wrapped path does not require an exact gateway greenlight. -3. The same greenlight can authorize more than one mutation. -4. Raw sibling mutation succeeds without refusal, block, detection, or proof packet. -5. Host metadata can go stale and still allow a greenlight or gateway check. -6. The receipt cannot distinguish gateway check from downstream package-manager execution. -7. A claim guard allows broad host-interception language from one host fixture. - -Rollback posture to `unproven` if: - -1. Package-manager binary path/version changes without refreshed metadata. -2. The fixture no longer exercises a real raw sibling mutation path. -3. The bypass detector only observes logs after consequence and cannot bind evidence to the protected surface. -4. The proof packet cannot be reconstructed from stored evidence. - -## Smallest Implementation Slice - -Build the smallest slice as: - -1. `package-manager-local` fixture. -2. One wrapped package-install path that succeeds after exact gateway greenlight. -3. One raw sibling package-manager invocation that is refused or detected. -4. One bypass proof packet. -5. One stale host metadata refusal. -6. One claim guard preventing broad host-interception claims. - -Smallest next mechanism to build: **a package-manager-local fixture that proves wrapped install succeeds only after gateway greenlight while the equivalent raw sibling path produces a bypass proof packet or refusal.** diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/RISK.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/RISK.md deleted file mode 100644 index dee36d9..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/RISK.md +++ /dev/null @@ -1,72 +0,0 @@ -# RISK: Host-Specific Bypass Harnesses - -## Invariant At Stake - -A host-specific bypass harness may only prove that one named, configured, installed path resisted named bypass attempts at a recorded freshness/version state. Anything broader is advisory, not Handshake. - -## Threat Model / Premortem - -Six months from now, the failure is not that the x402 bypass harness was useless. The failure is that it got laundered into a broad claim: "host interception is covered." It was not. - -The actual threat is generated automation finding an adjacent mutation path that the harness did not name: another binary on `PATH`, a sibling package manager, a direct MCP call, a CLI subcommand, a token passthrough path, a fixture that reports authority without gateway proof, or a stale tool list that no longer matches the installed host. - -The harness must assume: - -- the automated system can inspect environment shape and choose the easiest reachable mutation path; -- wrapper coverage drifts as hosts upgrade, aliases change, symlinks move, or package managers add subcommands; -- MCP and CLI surfaces expose overlapping authority but different enforcement boundaries; -- source fixtures can fabricate or weaken authority if `sourceAuthority` is not tied to gateway evidence; -- receipts can project evidence from one protected path onto another unless scoped aggressively. - -## Risks - -| Risk | Failure Mode | Required Counter-Evidence | -|---|---|---| -| Stale host tool list | Harness tests old configured tools while new reachable tools exist. | Fresh host inventory with command path, version, checksum or equivalent identity, generated immediately before probe. | -| Wrapper drift | Wrapped binary no longer matches actual invoked binary, alias, shim, or subcommand path. | Resolution proof for every tested command: configured wrapper path, resolved executable path, and gateway-bound invocation path. | -| Raw sibling tool reachability | `npm` is wrapped but `pnpm`, `yarn`, `bun`, `npx`, `corepack`, or direct package-manager shims remain reachable. | Negative bypass probes for sibling package-manager binaries and direct shim execution. | -| MCP/CLI overclaim | Passing CLI bypass tests is treated as MCP protection, or MCP probes are treated as CLI protection. | Separate receipts for MCP tool calls and CLI invocations, with distinct authority boundary labels. | -| `sourceAuthority` weakness | Weak conformance fixtures claim source authority without proving gateway-side evaluation. | Fixture receipts must distinguish conformance-source authority from gateway-probe authority. Weak fixtures cannot support protection claims. | -| Token passthrough | Runtime obtains or reuses a token that lets raw tools mutate outside the gateway. | Tests showing raw token use fails or is quarantined when not bound to exact greenlight and gateway check. | -| Fixture laundering | A fixture produces a green-looking result that is later cited as enforcement evidence. | Fixture output must be marked non-enforcement unless it includes gateway decision, greenlight binding, gateway check, and mutation attempt result. | -| Evidence projection leakage | Evidence from x402 probes is used to imply package-manager, MCP, cloud, or host-wide protection. | Claim schema must bind evidence to action type, host tool, path, version, gateway registry entry, and freshness timestamp. | - -## Validation Gates - -1. **Scope Gate** - Every bypass harness result must name exactly what it covers: host, runtime, installed path, resolved binary, tool version, adapter version, gateway registry entry, action type, and timestamp. - -2. **Freshness Gate** - The harness must fail closed if host inventory is stale, incomplete, or not captured immediately before test execution. - -3. **Reachability Gate** - For package-manager expansion, test the wrapped path and raw sibling paths separately. Passing `x402` probes does not count. - -4. **Gateway Evidence Gate** - A passing result must include proposal, policy decision, one-use greenlight binding, gateway check, execution result or refusal, and proof-gap handling. - -5. **Boundary Label Gate** - Every receipt must label whether it came from fixture conformance, gateway probe, CLI path, MCP path, browser path, or adapter path. - -6. **Overclaim Gate** - Docs, test names, report names, and status summaries must not say "host protected," "interception covered," or "bypass-proof." They may say only: "named configured path resisted named bypass attempts at recorded freshness state." - -## Stop Conditions - -Stop and do not claim protection if: - -- host tool inventory cannot be refreshed; -- raw sibling package-manager reachability is untested; -- wrapper resolution differs from the actual executed binary; -- MCP and CLI evidence are mixed into one claim; -- `sourceAuthority` is fixture-derived without gateway proof; -- token passthrough can mutate without exact greenlight binding; -- a fixture result is cited as gateway enforcement; -- receipts cannot distinguish gateway check from downstream execution; -- evidence from x402 is projected onto package-manager, MCP, CLI, or host-wide claims. - -## Brutal Verdict - -Keep the host-specific bypass harnesses, but narrow the claim hard. They are useful as named-path adversarial probes. They are dangerous as host protection evidence. - -The smallest next mechanism to build: a bypass evidence claim schema that forces every result to bind to `hostToolIdentity`, `resolvedPath`, `adapterVersion`, `gatewayRegistryEntry`, `actionType`, `freshnessTimestamp`, `probeClass`, and `claimScope`. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/STRATEGY.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/STRATEGY.md deleted file mode 100644 index cbc9e2f..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/raw/STRATEGY.md +++ /dev/null @@ -1,82 +0,0 @@ -# STRATEGY: Host-Specific Bypass Harnesses - -## Invariant At Stake - -A bypass harness must prove only this: a configured installed protected-action path resisted a named bypass route in a named host/runtime environment. Anything broader becomes evidence theatre. - -## Strategic Sequencing - -1. **Package-manager host harness first** - - Choose local package-manager host after package-install conformance. - - This is the right first host target because package installs are already a protected automated-decision action in the current adapter context, they produce material side effects, and the next adapter plan already wants package-manager material attestation. The host surface is narrow enough to test honestly: `npm`/`pnpm`/`bun` invocation path, wrapper path, raw sibling path, lifecycle script posture, registry/custody source, lockfile/package manifest mutation, and failure-closed behavior. - -2. **x402-hostile harness second** - - x402 hostile probes already exist, so this should become the calibration harness, not the first strategic host claim. - - Use it to prove the harness model can express named bypasses cleanly: raw sibling, MCP direct, token passthrough, wrapper drift, custody source authority, failure closed. But do not let x402 become the category center. x402 exact is a wedge; Handshake is protected actions for automated decision making. - -3. **MCP-host harness third** - - MCP-host comes after the harness contract is boring and repeatable. - - MCP is strategically important, but first MCP harness claims will be easy to overstate. "Protected against MCP bypass" is too broad. The acceptable first MCP claim is closer to: this configured MCP server/tool route denied direct invocation of this protected action unless the gateway-bound contract and one-use greenlight matched. - -## Claim Boundary - -Acceptable claim: - -> In environment `E`, with host `H`, adapter version `A`, gateway policy `P`, and protected action type `T`, Handshake resisted named bypass route `B` and recorded receipt/refusal/proof-gap evidence `R`. - -Unacceptable claim: - -> Handshake protects package managers, MCP, shell, browser, network, or hosts generally. - -For the first package-manager harness, the claim should be: - -> Handshake proves that a configured package-install path cannot mutate the declared package-manager material surface through the named raw/wrapper/sibling bypass routes without exact contract canonicalization, policy decision, one-use greenlight, gateway check, and receipt/proof-gap evidence. - -## 10-Star Bar - -A 10-star host harness has to satisfy all of this: - -1. Names the host, version, OS/runtime, adapter, gateway registry, and protected action type. -2. Defines the protected material surface before execution. -3. Declares every tested bypass route by name. -4. Separates read-only package inspection from package-install mutation. -5. Verifies exact contract canonicalization before policy. -6. Verifies one-use greenlight binding at gateway check. -7. Proves wrapper drift fails closed. -8. Proves raw sibling invocation cannot silently mutate the protected surface. -9. Records refusal, bypass detection, proof gap, or execution receipt distinctly. -10. Emits reconstruction evidence sufficient to replay the decision chain six months later. - -For package-manager specifically, "material surface" should include at minimum: manifest, lockfile, installed artifact tree, lifecycle script execution posture, registry/source/custody metadata, package-manager binary path, and gateway decision/receipt linkage. - -## Cut Lines - -Cut any claim that says "host-wide protection." - -Cut any harness that only tests the happy adapter path. - -Cut any bypass result that says "pass" without distinguishing refusal, gateway denial, quarantine, proof gap, or no-op. - -Cut any test where the package manager can mutate through a raw shell path and Handshake merely notices afterward. That is advisory, not Handshake. - -Cut any x402-first sequencing that makes the company look like an x402 compliance/protocol tool. - -Cut any MCP-first sequencing that claims MCP protection before proving one named MCP tool route in one named runtime. - -Cut any "browser/shell/network/package-manager protection" language unless each is a named host harness with bounded environment evidence. - -## Brutal Verdict - -Keep package-manager host first. - -Use x402-hostile as the proving-ground for harness semantics, not as the category anchor. - -Defer MCP-host until the harness contract can resist overclaiming. - -Smallest next mechanism to build: define the package-manager host harness contract: `HostEnvironment`, `ProtectedMaterialSurface`, `BypassRoute`, `ExpectedGatewayDecision`, and `ReceiptOrProofGapEvidence`. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/synthesis.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/synthesis.md deleted file mode 100644 index 14d69cf..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/host-specific-bypass-harnesses/runs/host-specific-bypass-harnesses-20260524T084500Z/synthesis.md +++ /dev/null @@ -1,119 +0,0 @@ -# Chair Synthesis: Host-Specific Bypass Harnesses - -## Invariant At Stake - -Handshake is protected actions for automated decision making. The invariant is exact protected action control, not engineering-agent identity and not host-wide safety. - -A host harness may prove only that a named configured installed path resisted named bypass routes at a recorded freshness state. Anything broader is false precision. - -## Synthesis - -The council converges on package-manager local host first. - -Strategy is right to force the wedge after package-install conformance. Package install is concrete, consequential, and adoption-legible. x402 remains useful as hostile-probe calibration, but it must not become the center of the architecture. - -Architecture is right that the missing primitive is not another probe. The missing primitive is `HostFixtureManifest` v1 plus `BypassProofPacket`. Without those two contracts, probe results become prose confidence and then product overclaim. - -Execution is right to phase this through wrapped path success, raw sibling probes, wrapper integrity, stale metadata refusal, proof packet, posture derivation, and claim guards. The stop conditions are not optional. Raw sibling mutation without refusal or proof gap kills the claim. - -Risk is right that every evidence result must bind host tool identity, resolved path, adapter version, registry entry, action type, freshness timestamp, probe class, and claim scope. If any of those are missing, posture is advisory or proof-gapped. - -Adoption is right that CLI report comes before dashboard. The first user-facing product surface must teach the narrowness of the claim, not hide it. - -## Final Position - -Keep the macro item, but narrow it hard. - -The first deliverable is not "host bypass protection." The first deliverable is: - -For package-manager local host H, protected path T, adapter A, policy P, and freshness state F, Handshake can report whether the configured wrapper is gateway-bound, whether one-use greenlight behavior holds, whether named raw sibling routes bypass control, and what evidence or proof gaps remain. - -That is the product. Everything else is theatre until enforced. - -## Required Mechanisms - -1. `HostFixtureManifest` v1 - - host identity - - environment identity - - adapter identity and version - - protected action type - - protected path - - configured wrapper path - - resolved wrapper path - - raw sibling candidates - - registry entry - - policy identity - - tool list digest - - freshness timestamp - - expected posture - - redaction policy - - non-claims - -2. `BypassProofPacket` - - manifest reference - - probe classes - - probe inputs and outputs - - wrapper integrity - - gateway binding - - freshness decisions - - gateway check result - - downstream execution result - - refusal evidence - - bypass evidence - - proof gaps - - protected-path posture - - redacted projection - - non-claims - -3. Exit states - - `READY` - - `ADVISORY_ONLY` - - `WRAPPER_MISSING` - - `WRAPPER_DRIFTED` - - `GATEWAY_UNBOUND` - - `RAW_SIBLING_MUTATION_POSSIBLE` - - `STALE_PROBE` - - `HOST_TOOL_DIGEST_CHANGED` - - `PROOF_GAP` - -## Antipatterns - -- Treating wrapped path success as package-manager safety. -- Treating fixture probes as establishment custody evidence. -- Treating x402 exact per-call proof as protocol center. -- Treating MCP or CLI reports as enforcement. -- Treating stale probe results as current posture. -- Treating redacted reports as permission to flatten evidence. -- Treating a package-install harness as browser, shell, network, MCP, or platform coverage. -- Treating "agent safety" as the category instead of protected actions for automated decision making. -- Treating one greenlight as reusable authority. -- Treating downstream success as proof that the gateway enforced. - -## Closeout Standard - -This macro closes only when the implementation plan can be validated against: - -- package-install conformance precondition -- manifest schema tests -- wrapped one-use greenlight tests -- raw sibling refusal or proof-gap tests -- wrapper missing and drift tests -- stale metadata tests -- proof packet redaction tests -- protected-path posture tests -- CLI report non-claim tests -- claim guards -- `npm run quality:claims` -- `npm run quality:architecture` -- `npm run format:check` -- `npm run check:repo` - -## Brutal Verdict - -Keep, narrowed. - -The useful primitive is host-specific protected-path posture, not host protection. The first harness should be package-manager local host because it is concrete enough to falsify. If the implementation cannot keep fixture scope, gateway binding, raw sibling posture, freshness, and non-claims intact, cut the claim back to advisory evidence. - -## Smallest Next Mechanism - -Define `HostFixtureManifest` v1 for the package-manager local host harness, with freshness refusal and explicit non-claims, before adding another probe. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/ASSUMPTIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/ASSUMPTIONS.md deleted file mode 100644 index 1fd0ee5..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/ASSUMPTIONS.md +++ /dev/null @@ -1,41 +0,0 @@ -# Assumptions - -## Product Assumptions - -- Handshake is protected actions infrastructure for automated decision making. -- x402 exact per-call protected spend is the first wedge. -- Hosted admission and redacted evidence reads are Tier 2 mechanisms. -- Tier 1 kernel authority boundaries remain unchanged. -- Engineering-agent workflows are stress/adoption context, not the product boundary. -- The valid hosted claim is narrow: admit exact protected-call transitions before kernel invocation and expose redacted evidence through tenant-scoped read controls. - -## Source Assumptions - -- Hosted mode already exists as a transport admission seam. -- `HostedCallerVerifier`, `TransitionCallerIdentity`, role checks, freshness checks, and scope checks already happen before body parse/kernel invocation. -- Accepted hosted transitions already store digest/ref evidence rather than raw tokens or raw user headers. -- Evidence read routes already check tenant/org boundaries. -- Generic raw record reads already consult `rawReadPosture`. -- D1/HTTP tests already cover durable protocol surface and local D1 behavior. - -## External Assumptions - -- Cloudflare D1/KV local/dev posture is not production proof. -- Wrangler local/dev behavior and remote/prod behavior must be validated separately. -- Cloudflare D1 bindings, KV bindings, migrations, and remote deployment state require explicit proof. -- Sensitive values belong in Cloudflare secrets, not public vars. -- Readiness may report secret names and presence, never secret values. -- KV consistency limits make it unsuitable as authoritative evidence storage unless limitations are explicit. -- D1 should own structured evidence indexes and records for this plan. - -## Validation Requirements - -- Hosted admission must fail closed when deployment-mode config is absent or inferred. -- Role, scope, freshness, and tenant/org/project mapping must be checked before body parse/kernel invocation. -- Redacted reads must require tenant/org/project entitlement and exact receipt/evidence id. -- Missing and unauthorized records must produce oracle-safe denial. -- Raw reads must obey explicit `rawReadPosture`. -- Readiness must distinguish local/dev, preview, and production posture. -- Secret values must never appear in readiness, receipts, logs, exports, or support bundles. -- Redaction must be proven by fuzzing and read matrices, not wording. -- Hosted claims must be guarded by enforcement evidence. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/CONTEXT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/CONTEXT.md deleted file mode 100644 index e30621e..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/CONTEXT.md +++ /dev/null @@ -1,29 +0,0 @@ -# Context - -This run is planning-only for the macro item: hosted admission plus redacted evidence plane. - -The hard product frame is protected actions for automated decision making. The first wedge is exact x402 per-call protected action, not general engineering-agent execution control. Engineering agents are relevant as stress and adoption context only. - -The hosted surface must stay narrow. It may admit exact protected-call transitions before kernel invocation and expose redacted evidence records through tenant-scoped read controls. It must not become hosted mutation authority, payment management, settlement, provider custody, general hosted Handshake operation, or compliance/audit theatre. - -The goal path is: - -```text -caller role token --> route admission --> tenant/org/project scope --> protocol transition or redacted read --> durable D1/KV storage --> audit-safe response -``` - -Known source state to preserve: - -- hosted mode already exists as a transport admission seam; -- hosted caller role/freshness/scope checks happen before body parse/kernel invocation; -- accepted hosted transitions store digest/ref evidence, not raw tokens/user headers; -- evidence read routes check tenant/org boundaries; -- generic raw record reads consult rawReadPosture; -- D1/HTTP tests cover durable protocol surface/local D1. - -The macro plan closes the gap between local hosted mechanics and an operated hosted read/admission posture without pretending local D1 tests, provider-neutral identity, or redacted receipts prove production readiness. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/DECISIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/DECISIONS.md deleted file mode 100644 index df21adf..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/DECISIONS.md +++ /dev/null @@ -1,37 +0,0 @@ -# Decisions - -## D1 Owns Structured Evidence - -D1 is the authoritative store for structured evidence indexes and records in this plan. KV may be used only for non-authoritative acceleration, references, cache posture, or derived read support with explicit consistency/audit limitations. - -## Hosted Is Admission And Read Plane Only - -Hosted mode may perform route admission and redacted evidence reads. It does not hold general hosted mutation authority, payment-management authority, settlement authority, provider custody, or compliance certification authority. - -## Deployment Mode Is Mandatory - -Hosted behavior must declare deployment mode: `local-dev`, `test`, `preview`, or `production`. Promoted hosted behavior cannot run from inferred defaults. - -## Admission Roles Are Not Read Entitlements - -Transition admission identity and evidence read entitlement are separate. A caller admitted to submit a protected transition is not automatically entitled to read evidence. - -## Redacted Evidence Is The Default Read Surface - -The default hosted read path returns redacted evidence only. Raw evidence is unavailable, disabled, gated, or allowed according to explicit `rawReadPosture`. - -## Raw Reads Require Strong Posture - -Raw evidence access, if ever allowed, requires explicit role, scope, purpose, time bounds, tenant/org/project entitlement, and audit evidence. Convention-only raw access is forbidden. - -## Readiness Is Posture, Not Liveness - -Hosted readiness reports enforcement and configuration posture: mode, bindings, secrets presence, vars, migrations, schema, verifier, redaction, retention, export, and unsupported capabilities. It is not a production-readiness badge. - -## Secret Values Are Never Evidence - -Secret names and presence may be reported. Secret values must not appear in readiness, logs, receipts, evidence records, exports, or support bundles. - -## Claim Guard Is A Product Control - -Docs, scripts, and repo-facing claims must not imply hosted operation, production readiness, compliance audit, payment management, settlement, custody, or hosted mutation authority unless enforcement gates exist. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/PLAN.md deleted file mode 100644 index 183b3bb..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/PLAN.md +++ /dev/null @@ -1,303 +0,0 @@ -# GSD Macro Plan: Hosted Admission And Redacted Evidence Plane - -## Goal - -Invariant at stake: hosted admission and hosted reads must not become hosted mutation authority, payment management, settlement, provider custody, general Handshake operation, or compliance theatre. - -Build a Tier 2 hosted admission plus redacted evidence plane for exact x402 protected calls: - -```text -caller role token --> route admission --> tenant/org/project scope --> protocol transition or redacted read --> durable D1/KV storage --> audit-safe response -``` - -Permitted product claim after closeout: Handshake admits exact protected-call transitions before body/kernel trust and exposes redacted evidence records through tenant-scoped read controls. - -## Non-Goals - -- No hosted mutation execution authority. -- No hosted payment credential custody beyond gateway-held credential creation already required by exact x402 per-call protected spend. -- No settlement, billing operations, or payment-management product surface. -- No general hosted Handshake operation claim. -- No production-readiness claim until Cloudflare bindings, migrations, secrets, readiness, and redaction matrices are proven. -- No compliance, audit-certification, or retention-policy claim beyond explicit evidence classes and proof gaps. -- No raw evidence read by default. -- No expansion from x402 protected spend into general engineering-agent control. - -## Source Boundary - -Tier 1 kernel boundaries remain intact: - -- operating envelopes authorize attempts, not mutations; -- exact action contracts remain proposed commitments, not execution authority; -- greenlights remain one-use and gateway-bound; -- gateway checks remain the final enforcement point before consequence; -- receipts distinguish proposal, policy decision, gateway check, downstream execution, refusal, and proof gap; -- missing or unavailable evidence is recorded, not smoothed over. - -Hosted surfaces are Tier 2 mechanisms only: - -- route admission before body parse and kernel invocation; -- caller identity verification; -- tenant/org/project-scoped read authorization; -- redacted evidence response shaping; -- durable storage binding and readiness reporting. - -## Current State - -Known source state to preserve: - -- Hosted mode exists as a transport admission seam. -- `HostedCallerVerifier`, `TransitionCallerIdentity`, and role/freshness/scope checks happen before body parse and kernel invocation. -- Accepted hosted transitions store digest/ref evidence, not raw tokens or raw user headers. -- Evidence read routes check tenant/org boundaries. -- Generic raw record reads consult `rawReadPosture`. -- D1/HTTP tests cover durable protocol surface and local D1 behavior. - -Known gaps: - -- No operated deployment-mode config. -- No production org/project/RBAC/read entitlement model beyond provider-neutral identity. -- No retention/export policy or audit reader posture. -- No hosted readiness probe. -- No Cloudflare D1/KV deployment and secrets proof. -- No product-level redaction fuzzing or read-entitlement matrix. -- No hosted claim guard beyond no-hosted wording. - -## Target State - -A hosted admission and redacted evidence plane with these explicit boundaries: - -- Deployment modes: `local-dev`, `test`, `preview`, `production`. -- Config declares verifier strategy, freshness window, admitted roles, admitted scopes, tenant source, D1/KV bindings, secret names, public vars, raw read posture, redaction profiles, retention posture, export posture, and readiness expectations. -- Admission is deny-by-default when hosted behavior would run with inferred authority defaults. -- Reader authorization is separate from transition admission. -- Roles are explicit: `viewer`, `auditor`, `operator`, `rawEvidenceReader`. -- Scopes are exact: `evidence:redacted:read`, `evidence:raw:request`, `evidence:raw:read`, `evidence:export:create`, `evidence:retention:admin`, `hosted:readiness:read`. -- D1 owns structured evidence indexes and records. -- KV is non-authoritative unless consistency and audit limits are explicitly documented. -- Redacted reads accept exact receipt/evidence identifiers, tenant/org/project scope, and read entitlement. -- Raw reads are unavailable, disabled, gated, or allowed only through `rawReadPosture`. -- Readiness reports state, not secrets: mode, binding presence, secret names/presence, vars, D1 local vs remote posture, migration/schema status, verifier posture, redaction profile, retention/export posture, and unsupported capabilities. -- SDK/CLI/MCP clients are read-only by default and label authority class, mutation posture, gateway-authority posture, and raw-evidence posture. - -## Assumptions - -- Cloudflare D1/KV local/dev proof is not production proof. -- Wrangler local/dev and remote/prod posture must be validated separately. -- Sensitive values live in Cloudflare secrets, not public vars. -- Readiness may report secret names and presence, never values. -- KV must not become authoritative evidence storage unless consistency and audit limitations are explicit. -- D1 owns structured evidence indexes and records for this plan. -- Hosted admission cannot infer production behavior from missing config. -- Evidence reads must avoid missing-vs-cross-tenant oracles. -- Redaction correctness requires fuzzing and matrix tests, not snapshot-only confidence. -- Engineering agents remain stress/adoption context, not the product boundary. - -## Decisions - -1. Keep the wedge as exact x402 per-call protected actions. -2. Treat hosted admission and redacted evidence reads as Tier 2 mechanisms. -3. Add deployment-mode config before adding broader hosted surfaces. -4. Split transition roles from read entitlements. -5. Make redacted evidence the default read plane. -6. Keep raw evidence unavailable or gated by explicit posture, purpose, time bounds, and audit. -7. Use D1 as the authoritative structured evidence store. -8. Use KV only for non-authoritative acceleration or references with explicit limitations. -9. Add readiness as a posture report, not a liveness badge. -10. Add claim guards so docs and scripts cannot claim hosted operation beyond enforcement. - -## Phases - -### Phase 0 - Boundary And Claim Lock - -Codify the hosted claim boundary and stop hosted language from implying production operation, mutation authority, payment management, custody, settlement, or compliance-grade audit. - -Outputs: - -- hosted claim guard; -- forbidden claim list; -- docs wording updates if needed; -- validation that Tier 1 kernel claims remain unchanged. - -### Phase 1 - Deployment-Mode Admission Config - -Add operated deployment-mode config for hosted admission. - -Outputs: - -- `deploymentMode` with `local-dev`, `test`, `preview`, `production`; -- verifier strategy declaration; -- role/scope/freshness config; -- tenant/org/project source config; -- deny-by-default behavior for missing hosted authority config. - -### Phase 2 - Reader Authorization Boundary - -Split admission identity from evidence reader entitlement. - -Outputs: - -- read roles and scopes; -- tenant/org/project predicates on every read path; -- oracle-safe denial responses; -- SDK/CLI/MCP read-only posture labels. - -### Phase 3 - Redacted Evidence Contract And Raw Posture - -Define the redacted evidence response contract and harden raw-read posture. - -Outputs: - -- redacted evidence schema; -- receipt-id-only read input; -- raw read states: `unavailable`, `disabled`, `gated`, `allowed`; -- raw access purpose/time-bound audit requirements; -- proof-gap responses for unavailable evidence. - -### Phase 4 - D1/KV Durable Posture And Readiness - -Prove D1/KV binding posture and expose hosted readiness. - -Outputs: - -- D1 structured evidence index ownership; -- KV non-authoritative posture; -- local/dev vs remote/prod D1 status; -- migration/schema proof; -- secret presence reporting without values; -- readiness states: `active`, `configured_but_unverified`, `missing`, `disabled`, `read_only`, `not_promoted`. - -### Phase 5 - Retention, Export, And Redaction Proof - -Make evidence lifecycle explicit without claiming compliance certification. - -Outputs: - -- retention classes; -- export creation scope and receipt; -- redacted support bundle contract; -- redaction fuzz tests; -- product-level read matrix. - -## Task Graph - -```text -P0 claim boundary - -> P1 deployment-mode admission config - -> P2 reader authorization boundary - -> P3 redacted evidence contract - -> P3 rawReadPosture hardening - -> P4 D1/KV readiness - -> P4 secrets posture - -> P5 retention/export posture - -> P5 redaction fuzzing - -> P5 SDK/CLI/MCP read posture - -> P5 hosted closeout guard -``` - -Critical path: - -```text -deployment mode --> deny-by-default hosted config --> tenant/org/project read predicate --> redacted evidence schema --> D1 authoritative evidence proof --> readiness posture --> redaction/read matrix --> claim guard -``` - -## Risks And Mitigations - -- Auth bypass: deny-by-default admission, freshness checks, exact role/scope allowlist. -- Caller identity overreach: provider-neutral identity cannot imply org/project entitlement without mapping. -- Token/email leakage: store digest/ref evidence only and fuzz redaction. -- Cross-tenant read leak: tenant/org/project keying plus read predicates. -- Missing-vs-cross-tenant oracle: same denial shape for missing and unauthorized records. -- Raw record exfiltration: default unavailable/disabled posture, gated role/scope/purpose/time-bound audit. -- D1 config drift: readiness reports local/remote D1 mode, binding, migration, and schema status. -- Secret leakage: readiness reports secret names/presence only. -- Hosted theatre: claim guard blocks production/general-hosted/compliance wording until gates pass. -- Replay/status risk: replay rejection remains explicit evidence. -- Retention risk: retention class and proof-gap language required before export/read claims. - -## Validation Gates - -Required gates before claiming the plan complete: - -- Hosted admission rejects missing deployment-mode config in hosted paths. -- Hosted admission checks caller role, freshness, scope, tenant/org/project mapping before body parse/kernel invocation. -- Accepted hosted transitions store digest/ref evidence only. -- Redacted evidence reads require receipt id and tenant/org/project entitlement. -- Cross-tenant and missing records are oracle-safe. -- Raw reads obey `rawReadPosture`. -- D1 owns structured evidence indexes/records. -- KV posture is explicitly non-authoritative. -- Readiness reports Cloudflare binding, migration, schema, and secret presence without leaking values. -- Wrangler local/dev proof and remote/prod proof are separately labeled. -- Redaction fuzzing covers tokens, headers, emails, authorization strings, cookies, payment hints, and provider metadata. -- Claim guard rejects hosted mutation authority, hosted payment management, settlement, custody, production readiness, compliance audit, and general hosted Handshake claims. - -Suggested closeout commands: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -npm test -- --run hosted -npm test -- --run d1 -npm test -- --run evidence -npm test -- --run redaction -``` - -## Cut Lines - -Cut or defer: - -- full RBAC administration UI; -- payment management; -- settlement support; -- provider custody; -- general hosted Handshake operation; -- compliance certification; -- raw evidence browsing; -- hosted mutation orchestration; -- write-capable SDK/CLI/MCP clients; -- multi-provider production deployment automation. - -Keep: - -- deployment-mode config; -- route admission; -- tenant/org/project read boundary; -- redacted evidence contract; -- raw-read posture; -- D1/KV readiness; -- secret-safe readiness; -- redaction fuzzing; -- hosted claim guard. - -## Rollback / Stop Conditions - -Stop implementation or rollback the slice if: - -- hosted behavior can run with inferred authority defaults; -- redacted reads accept broad query filters instead of exact receipt ids; -- raw evidence is controlled only by convention; -- hosted readiness passes with in-memory or stub storage in a promoted mode; -- secret values appear in readiness, logs, receipts, exports, or support bundles; -- clients bypass reader authorization; -- export is a dump of receipts without redaction, entitlement, and audit posture; -- marketing/docs claim hosted operation beyond enforcement; -- Cloudflare local D1 tests are treated as production proof. - -## Smallest Next Action - -Add the deployment-mode hosted admission config and claim guard first: hosted routes must fail closed unless mode, verifier strategy, freshness, role/scope policy, tenant source, D1 binding posture, raw-read posture, and secret-name declarations are explicit. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/RISKS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/RISKS.md deleted file mode 100644 index 9520c32..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/RISKS.md +++ /dev/null @@ -1,18 +0,0 @@ -# Risk Register - -| Risk | Failure Mode | Impact | Mitigation | Validation | -|---|---|---:|---|---| -| Hosted auth bypass | Route accepts hosted transition without explicit deployment/verifier/role/scope config | Critical | Deny-by-default hosted config | Missing-config rejection tests | -| Caller identity overreach | Provider-neutral identity becomes org/project entitlement | Critical | Explicit tenant/org/project mapping | Cross-scope admission tests | -| Body trust before admission | Parser/kernel observes unadmitted request | Critical | Admission before body parse/kernel invocation | Route-order tests | -| Token/header leakage | Raw auth material appears in receipt/readiness/log/export | Critical | Digest/ref evidence only, redaction schema | Redaction fuzzing | -| Cross-tenant evidence leak | Read route misses tenant/org/project predicate | Critical | Storage keying plus read predicate | Tenant matrix tests | -| Missing-vs-unauthorized oracle | Response distinguishes absent record from cross-tenant record | High | Oracle-safe denial | Negative read matrix | -| Raw evidence exfiltration | Raw reads allowed by role name or convention | Critical | `rawReadPosture` with scope/purpose/time/audit | Raw posture tests | -| D1 production drift | Local D1 proof treated as remote/prod proof | High | Readiness labels local/remote and migration/schema status | Wrangler local and remote proof gates | -| KV authority creep | KV becomes evidence source of truth | High | D1 authoritative decision, KV limitation docs | Storage contract tests | -| Secret leakage | Readiness exposes secret values or dynamic env dump | Critical | Secret names/presence only | Snapshot and fuzz checks | -| Hosted theatre | Readiness says ready while storage/verifier/secrets are stubs | High | `configured_but_unverified`, `not_promoted`, `missing` states | Readiness fixture matrix | -| Claim overreach | Docs imply hosted Handshake, compliance audit, custody, or production operation | High | Claim guard | `quality:claims` | -| Export overreach | Export dumps raw receipts without entitlement/redaction/audit | High | Export scope, redaction, receipt, proof gaps | Export contract tests | -| Retention theatre | Retention language exceeds implemented lifecycle | Medium | Retention classes and proof gaps | Retention matrix | diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/TASKS.jsonl b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/TASKS.jsonl deleted file mode 100644 index f2f2487..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/TASKS.jsonl +++ /dev/null @@ -1,12 +0,0 @@ -{"id":"HOSTED-001","priority":"P0","phase":"Phase 0","title":"Lock hosted claim boundary","owner":"product-architecture","rationale":"Hosted admission/read surfaces must not imply mutation authority, production operation, payment management, custody, settlement, or compliance audit.","depends_on":[],"acceptance":["Forbidden hosted claims are enumerated","Permitted claim is limited to exact protected-call admission and redacted tenant-scoped reads","Tier 1 kernel language remains unchanged"],"candidate_paths":["AGENTS.md","README.md","docs/internal/decisions.md","docs/internal/protocol-notes.md","scripts/quality"],"non_goals":["Implement hosted runtime","Add payment management","Claim production readiness"]} -{"id":"HOSTED-002","priority":"P0","phase":"Phase 1","title":"Add explicit deployment-mode hosted admission config","owner":"runtime-protocol","rationale":"Hosted behavior must not run from inferred authority defaults.","depends_on":["HOSTED-001"],"acceptance":["deploymentMode supports local-dev test preview production","Hosted routes fail closed when required config is missing","Verifier strategy freshness roles scopes and tenant source are explicit"],"candidate_paths":["src/hosted","src/http","src/protocol","tests/hosted"],"non_goals":["Cloudflare deployment automation","RBAC admin UI","General hosted operation"]} -{"id":"HOSTED-003","priority":"P0","phase":"Phase 1","title":"Prove admission happens before body parse and kernel invocation","owner":"runtime-protocol","rationale":"The hosted seam is only meaningful if unadmitted requests cannot reach body trust or kernel state.","depends_on":["HOSTED-002"],"acceptance":["Role freshness scope and tenant checks run before body parsing","Rejected requests leave refusal/proof-gap evidence as appropriate","Tests fail if parser or kernel is invoked before admission"],"candidate_paths":["src/http","src/hosted","tests/http","tests/hosted"],"non_goals":["Change Tier 1 policy semantics","Add new action types"]} -{"id":"HOSTED-004","priority":"P0","phase":"Phase 2","title":"Split transition admission from evidence read entitlement","owner":"authorization","rationale":"A caller admitted to submit a transition must not automatically read evidence.","depends_on":["HOSTED-002"],"acceptance":["Read roles viewer auditor operator rawEvidenceReader are modeled","Read scopes are exact and separate from admission scopes","Tenant org project predicates gate every read"],"candidate_paths":["src/evidence","src/hosted","src/http","tests/evidence"],"non_goals":["Full production RBAC console","Human persona modeling"]} -{"id":"HOSTED-005","priority":"P0","phase":"Phase 2","title":"Make evidence read denial oracle-safe","owner":"authorization","rationale":"Missing-vs-cross-tenant distinctions can leak evidence existence.","depends_on":["HOSTED-004"],"acceptance":["Unauthorized and missing reads share safe denial shape","Logs/receipts preserve internal reason without leaking to caller","Read matrix covers same-tenant cross-tenant missing and malformed ids"],"candidate_paths":["src/evidence","src/http","tests/evidence"],"non_goals":["User-facing audit dashboard","Broad evidence search"]} -{"id":"HOSTED-006","priority":"P0","phase":"Phase 3","title":"Define redacted evidence response contract","owner":"evidence-plane","rationale":"Redacted evidence must be a typed contract, not ad hoc response shaping.","depends_on":["HOSTED-004"],"acceptance":["Redacted reads accept exact receipt/evidence id only","Response distinguishes stored redacted unavailable refused and proof-gap fields","Tokens headers emails cookies and payment hints are excluded or redacted"],"candidate_paths":["src/evidence","src/protocol","tests/evidence","tests/redaction"],"non_goals":["Raw evidence browsing","Compliance report format"]} -{"id":"HOSTED-007","priority":"P0","phase":"Phase 3","title":"Harden rawReadPosture","owner":"evidence-plane","rationale":"Raw evidence is the highest-leakage surface and must not be controlled by convention.","depends_on":["HOSTED-006"],"acceptance":["States unavailable disabled gated allowed are enforced","Raw reads require explicit role scope purpose time bound and audit when gated/allowed","Default posture blocks raw reads"],"candidate_paths":["src/evidence","src/http","tests/evidence"],"non_goals":["Make raw access easy","Support bundle raw dumps"]} -{"id":"HOSTED-008","priority":"P1","phase":"Phase 4","title":"Codify D1 authoritative and KV non-authoritative storage posture","owner":"storage","rationale":"KV must not become authoritative evidence storage without explicit consistency/audit limits.","depends_on":["HOSTED-006"],"acceptance":["D1 owns structured evidence indexes and records","KV usage is documented and tested as non-authoritative","Storage contract rejects promoted mode without D1 binding proof"],"candidate_paths":["src/storage","src/evidence","tests/d1","docs/internal/protocol-notes.md"],"non_goals":["Replace D1 with KV","Build analytics warehouse"]} -{"id":"HOSTED-009","priority":"P1","phase":"Phase 4","title":"Add hosted readiness posture probe","owner":"operations","rationale":"Readiness must report enforcement posture, not process liveness or marketing readiness.","depends_on":["HOSTED-002","HOSTED-008"],"acceptance":["Readiness reports mode bindings secrets names/presence vars local-vs-remote D1 migration schema verifier redaction retention export","Readiness states include active configured_but_unverified missing disabled read_only not_promoted","Secret values are never emitted"],"candidate_paths":["src/hosted","src/http","src/storage","tests/readiness"],"non_goals":["Production SLA monitor","Secret discovery by env dump"]} -{"id":"HOSTED-010","priority":"P1","phase":"Phase 5","title":"Add retention export and support-bundle posture","owner":"evidence-plane","rationale":"Audit-safe reads need explicit lifecycle and export limits without compliance theatre.","depends_on":["HOSTED-006","HOSTED-007"],"acceptance":["Retention classes are explicit","Export requires exact scope and creates receipt/proof-gap evidence","Support bundle is redacted only"],"candidate_paths":["src/evidence","src/export","tests/evidence","docs/internal/decisions.md"],"non_goals":["Compliance certification","Raw receipt dump export"]} -{"id":"HOSTED-011","priority":"P1","phase":"Phase 5","title":"Add product-level redaction fuzzing and read matrices","owner":"quality","rationale":"Redaction safety and entitlement safety need adversarial tests, not snapshot confidence.","depends_on":["HOSTED-005","HOSTED-006","HOSTED-007"],"acceptance":["Fuzz cases include tokens headers emails authorization strings cookies payment hints provider metadata","Read matrix covers roles scopes tenants orgs projects raw posture and missing records","Failures block hosted claim closeout"],"candidate_paths":["tests/redaction","tests/evidence","scripts/quality"],"non_goals":["Visual review QA","Manual-only audit"]} -{"id":"HOSTED-012","priority":"P1","phase":"Phase 5","title":"Expose read-only SDK CLI MCP client posture labels","owner":"developer-experience","rationale":"Clients must not launder read-plane access into gateway authority or mutation capability.","depends_on":["HOSTED-004","HOSTED-009"],"acceptance":["Clients are read-only by default","Output labels authority class mutation none gateway authority not held raw access disabled unavailable or configured","Clients cannot bypass reader authorization"],"candidate_paths":["src/sdk","src/cli","src/mcp","tests/sdk","tests/cli"],"non_goals":["Write-capable hosted client","Operator dashboard"]} diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/VALIDATION.md deleted file mode 100644 index 856ddbe..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/VALIDATION.md +++ /dev/null @@ -1,62 +0,0 @@ -# Validation Matrix - -| Gate | What Must Be Proven | Evidence | -|---|---|---| -| Hosted deployment mode | Hosted paths fail closed without explicit mode/config | Config tests | -| Admission ordering | Role/freshness/scope/tenant checks happen before body parse/kernel invocation | Route-order tests | -| Exact x402 boundary | Hosted plan remains exact per-call protected action only | Claim guard and protocol tests | -| Digest/ref storage | Hosted transitions do not store raw tokens/user headers | Receipt fixture tests and redaction fuzzing | -| Reader authorization | Evidence reads require tenant/org/project entitlement | Read matrix tests | -| Oracle-safe denial | Missing and unauthorized evidence reads do not leak record existence | Negative read tests | -| Raw-read posture | Raw reads obey unavailable/disabled/gated/allowed states | Raw posture tests | -| D1 authority | D1 owns structured evidence indexes/records | Storage contract tests | -| KV limits | KV is non-authoritative or explicitly limitation-bound | Storage posture tests | -| Cloudflare bindings | D1/KV binding and migration posture are reported separately for local/dev and remote/prod | Wrangler proof artifacts | -| Secrets posture | Secret names/presence are reported, never values | Readiness redaction tests | -| Readiness posture | Readiness returns active/configured_but_unverified/missing/disabled/read_only/not_promoted accurately | Readiness matrix | -| Retention/export | Retention class and export behavior are scoped, redacted, receipted, and proof-gap aware | Retention/export tests | -| Client posture | SDK/CLI/MCP clients are read-only by default and label authority class | Client output tests | -| Claim safety | Hosted claims do not exceed enforcement | Claim guard | - -# Closeout Commands - -Planning-only expected closeout command set: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -npm test -- --run hosted -npm test -- --run evidence -npm test -- --run redaction -npm test -- --run d1 -npm test -- --run readiness -``` - -Cloudflare posture proof must be separated: - -```bash -wrangler d1 migrations list --local -wrangler d1 migrations list --remote -wrangler d1 execute --local --command "select 1" -wrangler d1 execute --remote --command "select 1" -wrangler secret list -``` - -These commands are validation targets, not evidence in this planning run. - -# Closeout Bar - -The slice is not complete until the repo can answer: - -- who attempted the hosted transition; -- what exact protected x402 call was admitted; -- whether admission happened before body/kernel trust; -- which tenant/org/project owned the transition; -- what was stored, redacted, unavailable, or refused; -- whether raw access was blocked, gated, or allowed; -- whether D1/KV bindings and migrations were configured; -- whether secrets were present without exposing values; -- whether export/reconstruction is possible within declared limits; -- whether product claims match enforcement. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/input.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/input.md deleted file mode 100644 index bf0cb20..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/input.md +++ /dev/null @@ -1,156 +0,0 @@ -# Macro Plan Input: Hosted Admission And Redacted Evidence Plane - -Run id: hosted-admission-redacted-evidence-plane-20260524T075941Z -Date: 2026-05-24 - -## Hard Frame - -Handshake is protected actions for automated decision making. Engineering-agent workflows are a stress/adoption context, not the product boundary. x402 exact per-call paid HTTP is the first protected-action wedge, not the protocol. - -This is planning only. Do not edit source, tests, docs outside this planning run, package metadata, or previously staged files. - -## Goal - -Plan how to turn local HTTP/D1 capabilities into an operated boundary only after caller custody, reader authorization, durable storage posture, and evidence redaction are real. - -Mechanism target: - -```text -caller role token --> route admission --> tenant/org/project scope --> protocol transition or redacted read --> durable D1/KV storage --> audit-safe response -``` - -## Current Source Grounding - -Canonical posture: - -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` says hosted admission and redacted evidence is critical path item 3, after custody proof and terminal verifier trust plane. -- `docs/internal/decisions.md` says HTTP admission, caller custody, OpenAPI projection, and route-scope resolution are protocol transport seams. They may model deployment-mode custody and caller roles, but they do not prove hosted operation, production org auth, provider enforcement, or customer gateway installation. -- `docs/internal/decisions.md` says local HTTP and SDK evidence reads are redacted diagnostic projections, not hosted audit/search product surfaces. The generic raw record route must enforce `rawReadPosture`. -- `README.md` and `docs/internal/protocol-notes.md` explicitly do not claim hosted operation. - -Current source anchors: - -- `src/http/LANE.md` -- `src/http/app.ts` -- `src/http/app-options.ts` -- `src/http/admission/caller-auth.ts` -- `src/http/admission/hosted-caller-identity.ts` -- `src/http/admission/index.ts` -- `src/http/admission/request-context.ts` -- `src/http/handlers/evidence-read.ts` -- `src/http/handlers/internal-record-read.ts` -- `src/http/routes/evidence-read-route-registry.ts` -- `src/http/routes/transition-route-registry.ts` -- `src/http/routes/transition-scope-resolvers.ts` -- `src/http/store/resolution.ts` -- `src/storage/d1` -- `migrations/` -- `test/http/http.test.ts` -- `test/http/d1-http.test.ts` -- `test/sdk/role-clients.test.ts` -- `test/mcp/mcp-resource-redaction.test.ts` -- `src/surfaces/boundary-manifest.ts` - -Landed behavior: - -- Hosted mode exists as a transport admission seam. -- `HostedCallerVerifier` verifies caller identity server-side. -- `TransitionCallerIdentity` binds caller identity ref, subject digest, tenant/org, custody roles, provider ref, auth/session/service credential digests, expiry, revocation epoch, and claims digest. -- Hosted admission checks role, freshness, and tenant/org scope before transition body parsing and kernel invocation. -- Accepted hosted transitions store only caller digest/ref evidence, not raw bearer tokens or user-identifying headers. -- Evidence read routes check hosted tenant/org boundaries before returning projections. -- Generic raw record reads consult protocol object `rawReadPosture`, and internal-only records return not found. -- D1/HTTP tests cover durable protocol surface behavior and local D1 evidence paths. - -Current gaps: - -- No deployment-mode admission config that proves an operated hosted product boundary. -- No production org/project/RBAC/read entitlement model beyond provider-neutral hosted caller identity. -- No retention/export policy or audit-reader posture. -- No hosted readiness probe that states exactly which hosted claims are active. -- No operated Cloudflare D1/KV deployment proof, migration/readiness proof, or secrets posture. -- No proof that hosted evidence responses are safe under redaction fuzzing and reader-role matrices at product level. -- No hosted claim guard beyond current local no-hosted-operation wording. - -## Official Source Constraints - -Use official source constraints only as planning constraints: - -- Cloudflare Workers secrets docs: secrets are encrypted text bindings for sensitive values; do not use `vars` for secrets; deployed secrets can be configured with Wrangler and validated through required secrets configuration. -- Cloudflare Workers environment variable docs: non-secret text/JSON variables are runtime bindings and are not encrypted; with Node compatibility, values may be exposed through `process.env`. -- Cloudflare D1 docs: D1 is accessed from Workers through environment bindings such as `env.DB`; Workers need configured D1 bindings. -- Cloudflare Wrangler configuration docs: D1 database bindings require binding name, database name, and database id. -- Cloudflare D1 getting-started docs: local and remote/production D1 configuration differ; production deployment requires remote database configuration. - -Do not claim Cloudflare deployment, org auth, secrets hygiene, D1 production readiness, or hosted operation until implementation verifies the actual config, migrations, secrets, admission, read authorization, and response redaction. - -## Required Perspectives - -Produce five independent raw perspectives before chair synthesis: - -1. Strategy: product posture, hosted claim boundary, sequencing after custody/verifier, x402-first implications. -2. Architecture: admission config, role/read models, scope, durable storage, redacted routes, raw-read posture, readiness probe. -3. Execution: implementation slices, candidate files/tests, closeout commands, dependency graph. -4. Risk/Security: auth bypass, token leakage, tenant leakage, raw record exfiltration, D1/secret/config drift, hosted theatre. -5. Adoption/DevEx: operator setup, SDK/CLI read clients, readiness output, error affordances, support/audit workflow. - -## Chair Outputs - -Create: - -- `PLAN.md` -- `CONTEXT.md` -- `ASSUMPTIONS.md` -- `DECISIONS.md` -- `RISKS.md` -- `VALIDATION.md` -- `TASKS.jsonl` -- `runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/synthesis.md` - -The final `PLAN.md` must include: - -- Goal -- Non-Goals -- Source Boundary -- Current State -- Target State -- Assumptions -- Decisions -- Phases -- Task Graph -- Risks And Mitigations -- Validation Gates -- Cut Lines -- Rollback / Stop Conditions -- Smallest Next Action - -## Must-Haves - -- Hosted admission is not authority. It authenticates/contextualizes callers before protocol transitions and redacted reads. -- Route admission must happen before body parsing or kernel invocation for mutating transitions. -- Reader roles must be distinct from control-plane/runtime/gateway/review roles where product semantics require it. -- Raw records must remain gated by `rawReadPosture`; internal-only objects must not be revealed through public/hosted reads. -- Evidence responses must be projection-owned and redaction-tested, not generic raw-record dumps. -- Hosted readiness must state active claims and non-claims explicitly. -- Cloudflare/D1/secrets claims require official-source-informed deployment checks, not local harness evidence alone. - -## Antipatterns To Reject - -- Hosted dashboard before custody, verifier, admission, and redacted reads are real. -- Treating hosted caller identity as principal authority or greenlight. -- Treating HTTP transport as hosted operation. -- Treating D1 local tests as production deployment readiness. -- Exposing raw protocol records because the caller has a control-plane token. -- Returning different errors for missing vs cross-tenant anchors. -- Storing raw bearer tokens, emails, secrets, or provider tokens in protocol records. -- Reader role overreach that allows evidence exfiltration. -- Claiming provider/customer gateway custody from hosted route admission. - -## Closeout Expectations - -Planning closeout is successful when every required output exists, `TASKS.jsonl` parses, required plan sections exist, source working tree remains untouched, and the plan states validation commands for eventual implementation. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/ADOPTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/ADOPTION.md deleted file mode 100644 index 594a4bb..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/ADOPTION.md +++ /dev/null @@ -1,217 +0,0 @@ -# ADOPTION Perspective - -## Invariant At Stake - -Hosted operation must not imply hosted authority. The product may expose admission status and redacted evidence reads, but CLI/SDK/MCP surfaces must not become mutation paths unless separately contracted, promoted, and gateway-enforced. - -## Adoption / DevEx Position - -The adoption wedge should be: "I can install the hosted evidence plane, run one readiness command, and know exactly what Handshake is enforcing, what it is only observing, and what evidence is redacted, unavailable, retained, or exportable." - -Do not sell this as hosted Handshake execution yet. Sell it as hosted admission plus evidence-read posture. - -## Operator Setup - -The operator path should be boring and explicit: - -1. Provision hosted admission endpoint. -2. Bind D1 database. -3. Apply migrations. -4. Register role/scope policy. -5. Configure secrets. -6. Configure evidence redaction policy. -7. Configure raw-read posture. -8. Configure retention/export posture. -9. Run readiness. -10. Only then expose read clients. - -Setup should produce a machine-readable readiness document and a human-readable report. Every setup step must say whether it is: - -- active -- configured_but_unverified -- missing -- disabled -- read_only -- not_promoted - -The most important DevEx rule: never make operators infer posture from successful deploy logs. - -## SDK / CLI Read Clients - -CLI, SDK, and MCP clients should be evidence/read-only by default. - -Required client affordances: - -- handshake evidence status -- handshake evidence readiness -- handshake evidence get -- handshake evidence search --redacted -- handshake evidence export --redacted -- handshake admission status -- handshake raw-read posture -- handshake retention status - -Every command should visibly label its authority class: - -```text -Authority: read-only evidence surface -Mutation: none -Gateway authority: not held by this client -Raw evidence access: disabled / unavailable / separately configured -``` - -SDK methods should mirror that posture. No method names like approve, greenlight, admit, mutate, execute, or grant unless the surface has been separately promoted into an enforcement path. - -## Readiness Output - -Readiness is the adoption centerpiece. It should answer: "What exactly is active?" - -Minimum readiness fields: - -```json -{ - "hostedAdmission": { - "status": "active", - "endpoint": "configured", - "operationClaim": "not_claimed" - }, - "roleScopeChecks": { - "status": "active", - "lastVerifiedAt": "timestamp", - "failureMode": "deny" - }, - "d1": { - "binding": "active", - "migrations": "applied", - "schemaVersion": "..." - }, - "secretPosture": { - "status": "configured", - "rawValuesExposed": false, - "rotationEvidence": "missing|present" - }, - "redactedReads": { - "status": "active", - "policyVersion": "...", - "sampleCheck": "passed" - }, - "rawReads": { - "status": "disabled", - "reason": "not_promoted" - }, - "retentionExport": { - "retention": "configured", - "redactedExport": "active", - "rawExport": "disabled" - }, - "readiness": { - "status": "ready_for_evidence_reads", - "notReadyFor": ["hosted_execution_claim", "mutation_authority"] - } -} -``` - -The key product move: readiness should name what is not true. That prevents hosted evidence from being laundered into hosted operation. - -## Error Affordances - -Errors should be posture-revealing, not generic. - -Examples: - -- D1_BINDING_MISSING: "Evidence reads cannot be reconstructed because no D1 binding is active." -- MIGRATION_NOT_APPLIED: "Evidence store exists but schema version is not admitted." -- SECRET_POSTURE_UNVERIFIED: "Hosted admission cannot prove secret handling posture." -- RAW_READ_NOT_PROMOTED: "Raw reads are disabled. This client only exposes redacted evidence." -- ROLE_SCOPE_DENIED: "Caller is authenticated but does not hold the required evidence-read scope." -- HOSTED_OPERATION_NOT_CLAIMED: "This deployment supports hosted admission/evidence reads, not hosted execution authority." - -Every error should include: - -- failed check -- expected state -- observed state -- whether the system failed closed -- next operator action -- audit receipt or readiness event id, if available - -## Support / Audit Workflow - -Support should never require raw secret access or privileged mutation. - -A good support bundle should include: - -- readiness report -- schema version -- D1 binding status, not credentials -- policy version -- redaction policy version -- role/scope decision trace -- failed check ids -- retention/export posture -- sampled redacted receipt ids -- explicit raw-read posture -- timestamped environment identity - -Support workflow: - -1. Operator runs handshake evidence support-bundle --redacted. -2. Bundle excludes raw secrets and raw evidence by default. -3. Bundle includes enough posture evidence to prove whether the failure is setup, policy, read authorization, migration, or product limitation. -4. Raw-read escalation is a separate audited path, not a support convenience. - -## What A 10-Star Product Feels Like - -The operator can tell, within five minutes, whether hosted Handshake is actually doing anything consequential. - -A 10-star experience feels like: - -- the first readiness report is brutally clear; -- every command says whether it is read-only or authority-bearing; -- no dashboard copy overclaims hosted execution; -- redacted evidence reads are useful without exposing raw sensitive payloads; -- broken D1, stale migrations, missing scopes, and disabled raw reads are diagnosed directly; -- support can debug posture without asking for secrets; -- audit can reconstruct why a caller saw redacted evidence and why they could not see raw evidence; -- the system repeatedly says "not promoted" where a weaker product would imply "coming soon" or silently expose capability. - -## Cut Lines - -Cut from this plan: - -- hosted execution claims; -- mutation commands in CLI/SDK/MCP; -- approval or greenlight APIs; -- raw evidence reads by default; -- dashboards that summarize posture without exact readiness fields; -- support workflows that require secrets; -- "secure by default" language without concrete checks; -- retention/export claims without verifiable config; -- MCP tools that can mutate admission, policy, retention, migration, or redaction state. - -## Adoption Risks - -The main adoption risk is that users will interpret "hosted admission" as "hosted Handshake operation." The product must fight that confusion in command names, readiness output, docs, errors, and dashboard labels. - -The second risk is frustration if redacted reads are too thin. The answer is not raw access by default. The answer is better redacted evidence shape, clearer proof gaps, and explicit raw-read escalation posture. - -## Validation Gates - -Before this plan is executable, require: - -- readiness output proves admission without claiming operation; -- CLI/SDK/MCP commands are read-only by inspection and tests; -- redaction tests prove sensitive fields are removed; -- raw-read posture is explicit and disabled unless configured; -- D1 migration failure produces a clear not-ready state; -- role/scope denial is distinguishable from missing auth; -- retention/export status appears in readiness and support bundles; -- support bundle contains no secrets or raw evidence. - -## Brutal Verdict - -Keep, but narrow. - -The adoption product is not "hosted Handshake." It is "hosted admission readiness plus redacted evidence reads." That is a useful wedge because it gives operators proof without prematurely creating a new authority surface. - -Smallest next mechanism to build: a single readiness contract that enumerates admission, D1, migration, role/scope, secret posture, redaction, raw-read posture, retention/export, and explicitly says hosted_operation_claim: false. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/ARCH.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/ARCH.md deleted file mode 100644 index 277f054..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/ARCH.md +++ /dev/null @@ -1,205 +0,0 @@ -# ARCH Perspective - -## Invariant At Stake - -Hosted admission must prove only that a caller may enter the hosted service path. It must not become execution authority, evidence authority, raw-read authority, or proof that downstream storage/deployment posture is safe. - -## Architecture Position - -The plan should define a hosted evidence plane with three hard boundaries: - -1. Admission boundary: caller identity, role, freshness, and declared scope checked before body parse or kernel invocation. -2. Read entitlement boundary: redacted evidence reads authorized by tenant/org, role, scope, and production RBAC rules. -3. Storage/deployment boundary: D1/KV bindings, secrets, vars, retention, export, and readiness are explicitly configured and provable per deployment mode. - -Hosted admission is only the door. The read model and storage posture decide what the caller can see. - -## Admission Config - -Add an explicit deployment-mode admission configuration, likely: - -- local-dev -- test -- preview -- production - -Each mode should declare: - -- accepted issuer/verifier strategy; -- required freshness window; -- allowed roles; -- allowed scopes; -- tenant/org source; -- whether raw reads are impossible, disabled, or gated; -- required D1/KV bindings; -- required secret names; -- required public vars; -- readiness expectations. - -Do not infer production posture from local tests. Local D1 and remote D1 are different authority surfaces. - -## Role And Read Models - -Split roles from read entitlements. - -Roles answer: "who is this caller?" - -Read entitlements answer: "what evidence shape may this caller retrieve for this tenant/org/scope?" - -Minimum model: - -- viewer: redacted evidence only; -- auditor: expanded redacted evidence plus proof-gap/refusal metadata; -- operator: operational readiness/status only, no raw evidence by default; -- rawEvidenceReader: exceptional entitlement, never implied by hosted admission. - -Production RBAC must be a first-class policy input, not scattered route conditionals. - -## Scope Model - -Scopes should be exact capabilities, not vague access labels. - -Candidate scopes: - -- evidence:redacted:read -- evidence:raw:request -- evidence:raw:read -- evidence:export:create -- evidence:retention:admin -- hosted:readiness:read - -A caller with evidence:redacted:read cannot get raw fields through alternate route parameters, export, readiness payloads, debug responses, or error messages. - -## Durable Storage Posture - -D1 should own structured evidence indexes and redacted read records. - -KV should only be used where eventual consistency is acceptable, such as readiness markers, deployment metadata, or non-authoritative cache state. Do not put raw authority-bearing evidence in KV unless the plan explicitly accepts its consistency and audit limits. - -Retention/export needs a concrete posture: - -- retention class per evidence type; -- redacted export format; -- raw export disabled unless explicitly entitled; -- export receipt records; -- proof-gap behavior when export cannot verify completeness. - -## Redacted Routes - -Redacted routes must bind every read to: - -- tenant/org; -- caller identity; -- role; -- scope; -- evidence record id/query; -- redaction profile; -- storage binding used; -- receipt/read audit event. - -Routes should never return "best effort" evidence without labeling proof gaps. If a redaction rule cannot be applied deterministically, fail closed or return a proof gap envelope. - -## Raw-Read Posture - -Keep rawReadPosture, but make it production-visible and route-enforced. - -States should be explicit: - -- unavailable: raw evidence is not stored or not reachable in this deployment. -- disabled: raw evidence exists but reads are not allowed. -- gated: raw reads require separate entitlement and audit. -- allowed: only for tightly scoped internal/test modes, preferably never production default. - -A raw-read posture flag is not enough. The route must enforce it before storage access. - -## Readiness Probe - -Hosted readiness should verify configuration, not leak evidence. - -It should report: - -- deployment mode; -- D1 binding presence; -- KV binding presence if required; -- required secrets configured, names only, never values; -- required vars configured; -- local vs remote D1 posture; -- migration/schema version; -- admission verifier configured; -- redaction profiles loaded; -- retention/export config loaded. - -It should not prove that a caller may read evidence. It proves the hosted plane is configured enough to evaluate admission and reads. - -## Storage And Deployment Config - -The plan must add Cloudflare-specific proof: - -- wrangler.toml D1 binding names match source expectations; -- preview and production D1 databases are distinct; -- local tests do not masquerade as remote proof; -- secrets are configured through Cloudflare secrets, not vars; -- non-secret config uses vars; -- KV namespaces are explicitly bound per environment; -- deployment docs show exact commands/checks for local and remote D1. - -Do not accept "tests pass locally" as hosted readiness. - -## Import And Source Ownership - -Keep ownership boring: - -- admission config types live with hosted ingress/admission code; -- read entitlement policy lives near evidence read routes, not inside storage adapters; -- D1/KV binding validation lives in hosted platform config; -- redaction profiles live with evidence serialization; -- raw-read posture lives with evidence access policy; -- readiness probe composes config checks but owns no policy. - -No route should import kernel internals just to answer hosted read requests. - -## Risks - -- Admission becomes ambient evidence authority. -- Production RBAC is bolted onto routes after the fact. -- Raw reads leak through export, debug, readiness, or error envelopes. -- Local D1 tests create false confidence for remote Cloudflare deployment. -- Secrets are accidentally modeled as vars. -- KV is used for authoritative evidence because it is convenient. -- Redaction is unit-tested but not fuzzed at product boundary. - -## Validation Gates - -- Hosted request with valid identity but missing read scope is refused before evidence access. -- Hosted request with valid admission but wrong tenant/org cannot read redacted evidence. -- Raw evidence read fails unless posture and entitlement both allow it. -- Readiness fails when required D1/KV bindings are absent. -- Readiness reports secret presence without exposing secret values. -- Remote D1 deployment proof is separate from local D1 test proof. -- Redaction fuzz tests assert forbidden raw fields never appear in route bodies, export bodies, errors, logs, or readiness output. - -## Cut Lines - -Cut from this macro plan: - -- new dashboard UX; -- broad audit analytics; -- generalized compliance exports; -- mutation authority; -- gateway greenlight changes; -- multi-runtime adapter expansion; -- raw evidence browsing UI. - -Keep the wedge narrow: hosted admission plus redacted evidence reads plus deployment posture proof. - -## Brutal Verdict - -Keep the initiative, but narrow it. - -The current source appears to have the right early boundary: admission before body parse/kernel invocation and redacted reads with tenant/org checks. The missing pieces are production hardening, not product expansion. - -Hosted admission is not authority. Redacted evidence access is its own entitlement plane. Raw reads are exceptional. Cloudflare deployment proof is a separate gate from local D1 correctness. - -## Smallest Next Mechanism - -Define a typed HostedAdmissionConfig plus ReadEntitlementPolicy that makes deployment mode, role, scope, tenant/org binding, raw-read posture, and required Cloudflare bindings explicit before adding any new route surface. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/EXECUTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/EXECUTION.md deleted file mode 100644 index 47579d4..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/EXECUTION.md +++ /dev/null @@ -1,370 +0,0 @@ -# EXECUTION Perspective - -## Invariant At Stake - -Hosted operation must not turn redacted evidence reads into ambient authority. Admission, storage, read authorization, redaction, export, and claims all need explicit boundaries, or this becomes advisory evidence hosting rather than Handshake enforcement support. - -## Ordered Implementation Slices - -### 1. Deployment-Mode Admission Config - -Goal: make hosted/self-hosted/local admission behavior explicit before touching storage or reads. - -Candidate paths: - -- src/admission/* -- src/hosted/* -- src/config/* -- tests/admission/*.test.ts -- docs/internal/protocol-notes.md - -Work: - -- Add a typed deployment mode: local | self_hosted | hosted. -- Require hosted mode to declare admission authority holder, storage backend, read policy, retention policy, and raw-read posture. -- Refuse startup/readiness if hosted mode has implicit defaults for protected fields. -- Ensure deployment mode is evidence metadata, not permission. - -Tests: - -- hosted mode fails closed on missing read policy. -- local mode cannot accidentally expose hosted-read behavior. -- mode is captured in admission/readiness evidence. - -Stop condition: any hosted behavior can run with inferred authority defaults. - -### 2. Reader Authorization Boundary - -Goal: every redacted evidence read must pass a reader authorization check bound to evidence scope. - -Candidate paths: - -- src/evidence/read* -- src/readers/* -- src/auth/* -- src/protocol/* -- tests/evidence/read-authorization.test.ts - -Work: - -- Define EvidenceReadRequest, EvidenceReader, EvidenceReadDecision. -- Bind reader authorization to tenant/workspace, action contract id, receipt id, evidence class, redaction profile, and export purpose. -- Return refusal/proof gap for unreadable evidence rather than silently omitting. -- Log read decision separately from mutation receipt. - -Tests: - -- unauthorized reader cannot read redacted evidence. -- authorized reader cannot widen from receipt-level to workspace-level. -- read refusal is reconstructable. - -Stop condition: any redacted evidence read path accepts only a receipt id and returns data without reader context. - -### 3. rawReadPosture Hardening - -Goal: raw evidence access must be explicitly disabled, break-glass, or delegated to a storage-side authority. Never implicit. - -Candidate paths: - -- src/evidence/redaction* -- src/evidence/raw* -- src/protocol/evidence* -- tests/evidence/raw-read-posture.test.ts - -Work: - -- Make rawReadPosture an enum: disabled | storage_only | break_glass. -- Fail hosted mode unless raw reads are disabled or guarded by explicit break-glass policy. -- Make raw-read attempts produce refusal or proof-gap evidence. -- Ensure redacted reads cannot include raw fields through nested payloads or metadata. - -Tests: - -- hosted mode rejects rawReadPosture: allowed. -- raw evidence is absent from SDK/CLI read clients. -- fuzzed nested objects cannot leak raw payloads. - -Stop condition: raw read behavior is controlled by caller convention rather than schema/state. - -### 4. D1/KV Deployment Readiness - -Goal: hosted persistence must prove schema, namespace, migration, and consistency posture before claiming readiness. - -Candidate paths: - -- src/storage/d1* -- src/storage/kv* -- src/hosted/readiness* -- wrangler.toml -- migrations/* -- tests/storage/*.test.ts - -Work: - -- Add readiness checks for D1 schema version, KV namespace binding, receipt/evidence indexes, retention clock, and migration status. -- Separate write-store readiness from read-plane readiness. -- Record unavailable storage as readiness refusal, not degraded success. -- Add fixture-backed storage contract tests. - -Tests: - -- readiness fails with missing D1 binding. -- readiness fails with missing KV namespace. -- storage adapter round-trips redacted evidence only. -- migration version mismatch blocks hosted admission. - -Stop condition: hosted readiness can pass with in-memory or stub persistence. - -### 5. Secrets Posture - -Goal: hosted admission must not depend on undeclared secrets or leak secret-derived material into evidence. - -Candidate paths: - -- src/secrets/* -- src/config/secrets* -- src/hosted/readiness* -- tests/secrets/*.test.ts -- docs/internal/decisions.md - -Work: - -- Define required secret names per deployment mode. -- Add startup/readiness validation for present-but-not-logged secrets. -- Redact secret-like values in evidence and read responses. -- Prevent SDK/CLI from printing secret-bearing config. - -Tests: - -- missing hosted secret fails readiness. -- evidence redaction catches token/key/env patterns. -- logs/read responses do not include secret values. - -Stop condition: hosted mode can boot while discovering secrets dynamically from environment without declared posture. - -### 6. Retention And Export - -Goal: redacted evidence is useful only if retention/export rules are explicit and auditable. - -Candidate paths: - -- src/evidence/retention* -- src/evidence/export* -- src/storage/* -- tests/evidence/retention-export.test.ts - -Work: - -- Add retentionPolicyId, expiry, legal-hold posture, and export profile to evidence metadata. -- Implement redacted export only; raw export requires break-glass refusal/review path. -- Add export receipts distinct from execution receipts. -- Make expired evidence return tombstone/proof gap, not silent 404. - -Tests: - -- expired evidence is unavailable with reconstructable tombstone. -- export cannot widen redaction profile. -- raw export is refused in hosted mode unless break-glass path exists. - -Stop condition: export is just "dump stored receipts." - -### 7. Hosted Readiness Probe - -Goal: expose a probe that says whether hosted admission/read plane can enforce boundaries now. - -Candidate paths: - -- src/hosted/readiness* -- src/http/* -- src/cloudflare/* -- tests/hosted/readiness.test.ts - -Work: - -- Probe admission config, storage, read auth, redaction profile, raw posture, retention, secrets, and claim guard versions. -- Return machine-readable failed gates. -- Keep probe read-only. -- Ensure probe does not disclose secrets or raw evidence. - -Tests: - -- each missing subsystem maps to a named readiness failure. -- readiness cannot pass when redaction fuzz suite is disabled from claim guard metadata. -- probe response is safe for operator display. - -Stop condition: readiness reports "ok" based only on process health. - -### 8. Redaction Fuzzing - -Goal: prove redaction survives nested payloads, unknown keys, arrays, metadata, and future schema drift. - -Candidate paths: - -- src/evidence/redaction* -- tests/evidence/redaction-fuzz.test.ts -- tests/fixtures/evidence/* - -Work: - -- Add property/fuzz tests for secret-like strings, raw payload fields, nested command outputs, env names, URLs with credentials, tokens, and stack traces. -- Assert redacted output preserves structure enough for reconstruction without leaking raw values. -- Add regression corpus for known dangerous shapes. - -Tests: - -- no raw payload field survives. -- no known secret pattern survives. -- redaction is deterministic for canonical evidence. - -Stop condition: redaction is only snapshot-tested on happy-path receipts. - -### 9. SDK/CLI/Read Client Posture - -Goal: clients must expose redacted evidence reads without implying hosted mutation authority or raw evidence access. - -Candidate paths: - -- packages/sdk/* -- packages/cli/* -- src/client/* -- tests/sdk/*.test.ts -- tests/cli/*.test.ts - -Work: - -- Add read client methods that require reader context and requested redaction profile. -- Avoid generic getReceiptRaw or readEvidence(any) surfaces. -- CLI should show refusal/proof-gap/read-decision state explicitly. -- Client docs must say hosted read plane is not hosted execution authority. - -Tests: - -- CLI cannot request raw evidence in hosted mode. -- SDK method requires reader identity/scope. -- client output distinguishes redacted receipt, read refusal, proof gap, and expired evidence. - -Stop condition: SDK/CLI adds convenience methods that bypass the reader authorization model. - -### 10. Claim Guards - -Goal: repo claims must not say hosted operation exists until all enforcement and evidence gates pass. - -Candidate paths: - -- scripts/quality/* -- docs/internal/* -- README.md -- QUALITY.md -- tests/quality/*.test.ts - -Work: - -- Add claim guard terms for hosted, managed, cloud, evidence plane, redacted read, and raw evidence. -- Permit only narrow language until readiness, auth, redaction fuzzing, storage, and retention/export gates exist. -- Require docs to distinguish hosted admission seam from hosted operation. -- Add CI/local quality command coverage. - -Tests: - -- forbidden hosted claims fail quality checks. -- allowed guarded language passes. -- README cannot claim hosted operation without linking readiness/read authorization posture. - -Stop condition: marketing or README claims outpace gateway/read-plane enforcement. - -## Dependency Graph - -```text -deployment-mode config - -> reader authorization - -> rawReadPosture hardening - -> D1/KV readiness - -> secrets posture - -> retention/export - -> hosted readiness probe - -> SDK/CLI/read client posture - -> claim guards - -redaction fuzzing - -> rawReadPosture hardening - -> hosted readiness probe - -> claim guards - -D1/KV readiness - -> retention/export - -> hosted readiness probe - -reader authorization - -> SDK/CLI/read client posture - -> retention/export -``` - -## Parallelizable Work - -Can run in parallel after deployment-mode config lands: - -- reader authorization schema/design -- redaction fuzz corpus -- D1/KV readiness adapter planning -- secrets posture validation -- claim guard vocabulary draft - -Must stay serialized: - -- rawReadPosture hardening before SDK/CLI raw-read behavior -- storage readiness before hosted readiness probe -- retention/export before external export claims -- final claim guards after all enforcement gates are named - -## Closeout Commands - -Candidate closeout gates: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -Focused test candidates: - -```bash -npm test -- admission -npm test -- evidence -npm test -- storage -npm test -- hosted -npm test -- sdk -npm test -- cli -``` - -## Rollback / Stop Conditions - -Stop immediately if: - -- hosted mode can pass readiness with stub or local storage. -- redacted evidence reads do not require reader authorization. -- raw evidence is reachable through SDK, CLI, export, debug, or metadata. -- readiness proves process liveness instead of enforcement readiness. -- docs claim hosted operation before D1/KV, secrets, read auth, retention/export, and redaction fuzzing are gated. -- receipts blur execution evidence, read evidence, export evidence, and proof gaps. - -Rollback line: - -- keep hosted admission seam and redacted evidence reads as local/self-hosted primitives. -- do not expose hosted mode or hosted claims until readiness and claim guards pass. - -## Traps - -- Hosted admission can become a product claim without hosted enforcement. -- Redacted read clients can become ambient workspace observability. -- Raw evidence can leak through metadata, stack traces, debug fields, export paths, or CLI formatting. -- D1/KV bindings can exist while schema/index/readiness posture is unproven. -- Retention can delete evidence and destroy reconstructability unless tombstones/proof gaps survive. -- SDK convenience methods can erase the reader authorization boundary. -- Readiness probes often lie by checking uptime instead of enforcement gates. -- Claim guards must police docs and names, not just README prose. - -## Smallest Next Mechanism - -Build the deployment-mode admission config first: one typed hosted-mode object that fails closed unless reader policy, storage backend, rawReadPosture, secrets posture, and retention policy are explicitly declared. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/RISK.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/RISK.md deleted file mode 100644 index 166d706..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/RISK.md +++ /dev/null @@ -1,88 +0,0 @@ -# RISK Perspective - -## Invariant At Stake - -Hosted mode must not turn evidence reads or admission checks into ambient authority. Caller identity evidence, redacted receipts, and hosted verifier status are not permission unless the hosted boundary enforces role, freshness, scope, tenant, and raw-read posture server-side. - -## Risk Findings - -| Risk | Failure mode | Required control | -| --- | --- | --- | -| Auth bypass | Hosted endpoint becomes a second path around local verifier/gateway checks. | One hosted admission verifier, deny-by-default, no fallback to advisory mode. | -| Caller identity overreach | Caller-supplied digest/ref is treated as authority instead of evidence. | Digest/ref is evidence only; authorization derives from verified issuer, tenant, role, scope, freshness, and policy version. | -| Token/email leakage | Receipts expose bearer tokens, emails, headers, OAuth claims, webhook payloads, or secret-like refs. | Redaction schema with denylisted fields, typed secret markers, email hashing policy, and snapshot tests. | -| Cross-tenant leaks | Evidence read APIs return receipts from another org through guessed IDs, shared indexes, or weak filters. | Tenant/org boundary must be part of the storage key and every read predicate; no app-layer-only filtering. | -| Missing-vs-cross-tenant oracle | 404 missing vs 403 forbidden lets callers enumerate foreign receipt IDs. | Normalize unauthorized and nonexistent reads unless caller has tenant-scoped index permission. | -| Raw record exfiltration | rawReadPosture becomes a boolean escape hatch for full receipt payloads. | Raw reads require explicit role, purpose, time-bound scope, audit receipt, and field-level allowlist. | -| D1 config drift | Local D1 schema, bindings, migrations, or seed data differ from production. | Migration gate must prove local and production migration state, binding name, and schema hash alignment. | -| Secrets via process.env | Worker code accidentally depends on Node-style env or source-defined secrets. | Cloudflare env binding only; static check banning secret literals and process.env in worker/runtime paths. | -| Hosted theatre | Hosted verifier records "checked" but mutation/evidence access can still proceed through local/raw/sibling route. | Plan must identify every hosted and non-hosted ingress and mark bypass posture for each. | -| Replay/status risk | Stale verifier status or copied caller evidence authorizes later reads/admissions. | Nonce or timestamp freshness, policy version binding, single-use admission where consequential, replay receipt on rejection. | -| Retention risk | Evidence plane stores too much raw payload forever. | Retention class per evidence type, redaction-before-persist where possible, deletion/export policy, proof-gap when raw evidence is unavailable. | - -## Recommended Plan Shape - -1. Define Hosted Admission Contract. - Inputs: caller credential, caller identity digest/ref, tenant/org, requested action/evidence scope, freshness window, policy version, rawReadPosture. - Outputs: allow/refuse/review/quarantine plus reason code and receipt reference. - Non-output: no mutation permission, no proof of downstream execution. - -2. Build Redacted Evidence Read Model. - Separate redactedEvidenceRead from rawEvidenceRead. - Redacted reads are default and tenant-scoped. - Raw reads are exceptional, audited, scoped, and purpose-bound. - -3. Close Oracle And Exfiltration Paths. - Same response posture for missing and unauthorized records unless index authorization is proven. - No raw receipt fetch by ID without tenant-bound authorization. - No caller-controlled projection fields. - -4. Add Cloudflare Deployment Proof. - D1 binding proof. - Migration state proof. - Secret binding proof. - Production-vs-local config divergence recorded explicitly. - -## Cut Lines - -- Cut any plan that treats caller identity digest as authorization. -- Cut any read API that can return raw records by default. -- Cut any hosted verifier that does not enumerate bypass posture. -- Cut any production claim without Cloudflare binding and D1 migration proof. -- Cut process.env dependency from worker/runtime code. -- Cut separate error semantics that expose whether a foreign receipt exists. - -## Validation Gates - -- Auth matrix: tenant x role x scope x freshness x rawReadPosture. -- Cross-tenant negative tests using valid foreign IDs. -- Missing-vs-forbidden response equivalence tests. -- Redaction snapshot tests for tokens, emails, headers, secrets, env names, webhook bodies. -- Raw-read audit tests proving every raw access creates evidence. -- Replay tests for stale caller evidence and reused status. -- D1 migration drift check for local and production binding names/schema hashes. -- Static scan blocking secret literals and process.env in hosted worker paths. -- Hosted bypass test proving unwrapped local/sibling reads cannot access protected evidence. - -## Antipatterns - -- Hosted mode as a trust label instead of an enforced boundary. -- Redacted evidence implemented as UI filtering. -- Caller identity stored as a digest with no issuer, freshness, or tenant binding. -- Returning 403 for foreign records and 404 for missing records. -- Raw read as admin convenience. -- Production readiness based on local Wrangler success. -- Secrets in vars, source, logs, receipt metadata, or test fixtures. -- Receipts that do not distinguish admission check, evidence read, raw read, and downstream execution. - -## Blocked Checks - -- No filesystem, source, config, migration, or test verification was performed per instruction. -- Product-level hosted deployment proof remains unverified. -- Existing read authorization model remains unverified. - -## Brutal Verdict - -Narrow and keep, but only if hosted mode is treated as a new protected ingress, not a deployment flavor. The dangerous part is not transport; it is evidence authority moving server-side without a precise read contract. - -Smallest next mechanism to build: a tenant-bound EvidenceReadAuthorization contract with redacted vs raw posture, freshness, role/scope checks, oracle-safe denial semantics, and mandatory audit receipt for every raw read. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/STRATEGY.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/STRATEGY.md deleted file mode 100644 index 30c80c8..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/raw/STRATEGY.md +++ /dev/null @@ -1,139 +0,0 @@ -# STRATEGY Perspective - -## Invariant At Stake - -Hosted Handshake must not turn transport admission plus redacted storage into a product claim that exceeds enforcement. If hosted mode cannot prove caller admission, tenant-scoped evidence reads, redaction posture, deployment binding correctness, and secret handling, then it is a demo seam, not an operated evidence plane. - -## Product Posture - -The product posture should be narrow: hosted admission and redacted evidence plane for exact x402-protected calls, not "hosted Handshake" broadly. - -The wedge is not engineering-agent workflow control yet. Engineering agents remain a stress case. The first marketable primitive is: a remote caller can attempt an exact paid/protected call, Handshake admits or rejects the caller before request body trust, records only digest/ref caller evidence, and exposes evidence reads through tenant/org/project-scoped entitlement. - -x402 per-call enforcement forces a clean version of Handshake's doctrine: one exact call, one admission boundary, one evidence posture, no ambient authority. - -## Hosted Claim Boundary - -Permitted claim: - -> Handshake hosted mode can admit exact protected calls before kernel invocation and expose redacted evidence records through tenant-scoped read controls. - -Forbidden claims until proven: - -- Hosted production readiness. -- Full organization RBAC. -- Compliance-grade evidence retention. -- Secret-safe deployment. -- Cloudflare durable deployment proof. -- General hosted execution control for engineering agents. -- Raw evidence safety unless raw-read posture is explicitly enforced and tested. -- "Auditable" unless export, retention, redaction, and access evidence survive reconstruction. - -If the hosted claim guard does not exist, product copy will overreach. That is strategy debt, not docs cleanup. - -## Sequencing After Custody/Verifier - -The next macro sequence should be: - -1. Operated deployment mode. - Define local/test/hosted deployment modes, required bindings, secret sources, readiness checks, and failure behavior. - -2. Tenant/org/project/read entitlement model. - Make evidence reads impossible without explicit tenant/org/project authority. This is the product boundary for hosted evidence. - -3. Redacted evidence contract. - Define what is stored as digest/ref only, what is never stored, what rawReadPosture permits, and what proof gaps are recorded. - -4. Cloudflare D1/KV deployment proof. - Prove the hosted runtime can actually bind D1/KV correctly under remote configuration. Local D1 tests are not production proof. - -5. Hosted readiness probe. - Add a readiness surface that verifies mode, bindings, migrations/schema posture, secret availability by reference, and evidence-plane availability without leaking sensitive values. - -6. Product-level redaction fuzzing. - Fuzz evidence ingestion and reads for token-like, secret-like, header-like, and body-like leaks. - -7. Hosted claim guard. - Add automated guardrails against README/docs/product claims that exceed the current hosted proof. - -## x402-First Implications - -x402 should stay first because it forces exact per-call admission. Do not dilute it into general account auth, agent auth, or workflow approval. - -Strategically, x402 means: - -- The protected action is the call, not the customer journey. -- Admission happens before body parsing and kernel invocation. -- Evidence must prove admission/refusal posture without storing caller secrets. -- Pricing/payment is useful only if it strengthens exact-call control. -- Hosted mode must reject vague "session permission" language. - -The danger is turning x402 into a payment feature. The strategic value is not payment. The value is exact, externalized, per-call admission with reconstructable redacted evidence. - -## Cut Lines - -Cut from this macro plan: - -- General engineering-agent dashboards. -- Human review UI polish. -- Broad compliance language. -- Multi-cloud support. -- Full enterprise RBAC. -- Workflow orchestration. -- Raw evidence browsing by default. -- Any claim that hosted mode controls downstream business success. -- Any "agent auth" positioning. -- Any architecture that depends on Cloudflare vars for sensitive values. - -Keep only what proves hosted admission and redacted evidence under operated deployment constraints. - -## Success Criteria - -This plan succeeds when Handshake can prove: - -- Hosted mode refuses requests before body parsing/kernel invocation when caller role, freshness, or scope fails. -- Caller evidence is digest/ref only unless rawReadPosture explicitly permits otherwise. -- Evidence reads are tenant/org/project scoped and denied by default. -- Cloudflare D1/KV bindings are configured and tested in remote deployment posture, not only local durable tests. -- Sensitive values use Cloudflare secrets, not vars. -- Readiness probe reports binding/config posture without leaking sensitive data. -- Retention/export policy is explicit, even if minimal. -- Product docs cannot claim more than the hosted proof supports. -- Redaction fuzzing catches secret-like evidence leaks. -- Failures become refusals or proof gaps, not smoothed-over success records. - -## Risks - -The main risk is evidence theatre: hosted mode records something, but cannot later prove whether admission, redaction, tenant entitlement, and deployment posture were correct. - -The second risk is market theatre: calling this "hosted Handshake" before it handles production deployment and read entitlements. That invites enterprise expectations before the primitive is hard. - -The third risk is x402 dilution: selling payment instead of exact admission. Payment rails are distribution; exact-call enforcement is the product. - -## 10-Star Bar - -A 10-star version lets a skeptical org inspect one x402 protected call and answer: - -- Who attempted the call? -- Was the caller admitted before body/kernel trust? -- Which tenant/org/project owned the evidence? -- What exact evidence was stored? -- What was redacted, referenced, or deliberately unavailable? -- Was raw evidence blocked unless explicitly permitted? -- Were Cloudflare bindings and secrets configured in operated hosted mode? -- Could this be exported or reconstructed later? -- Did the product claim exactly match the enforced behavior? - -If any answer depends on "trust the host runtime," the bar is not met. - -## Brutal Verdict - -Keep the hosted admission and redacted evidence plane. - -Narrow the claim. - -Sequence it after custody/verifier, but before broader hosted product language. - -Make x402 the first exact-call proof surface, not a payment story. - -Smallest next mechanism to build: an operated hosted deployment-mode contract plus readiness probe that validates D1/KV bindings, secret posture, mode config, and evidence-plane availability without parsing protected request bodies or leaking sensitive values. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/synthesis.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/synthesis.md deleted file mode 100644 index 5754e41..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/hosted-admission-redacted-evidence-plane/runs/hosted-admission-redacted-evidence-plane-20260524T075941Z/synthesis.md +++ /dev/null @@ -1,68 +0,0 @@ -# Chair Synthesis: Hosted Admission And Redacted Evidence Plane - -## Invariant At Stake - -Hosted admission and hosted reads must remain evidence-plane mechanisms. They cannot become hosted mutation authority, payment management, settlement, provider custody, general hosted Handshake operation, or audit/compliance theatre. - -The core invariant is still exact protected action control: - -```text -vague intent is not authority -generated orchestration is not authority -hosted admission is not authority to mutate -redacted evidence is not proof of downstream success -readiness is not production proof -``` - -## Perspective Reconciliation - -STRATEGY is right to narrow the claim. The market/product claim must be hosted admission plus redacted evidence for exact x402-protected calls, not hosted Handshake. The necessary sequence is deployment mode, read entitlement, redaction contract, Cloudflare durable proof, readiness, redaction fuzzing, and claim guard. - -ARCH is right about the three boundaries: admission, read entitlement, and storage/deployment. The plan adopts deployment modes, explicit verifier/read config, separated roles/scopes, D1 authority, KV limitation, rawReadPosture, and readiness posture. - -EXECUTION is right about stop conditions. The plan fails if hosted behavior runs with inferred authority defaults, if raw reads are convention-controlled, if readiness passes against stubs, if export is a receipt dump, or if clients bypass reader authorization. - -RISK is right that the dangerous failures are not abstract. They are auth bypass, identity overreach, token leakage, cross-tenant leakage, oracle leaks, raw exfiltration, D1 drift, secret leakage, hosted theatre, replay/status confusion, and retention theatre. The mitigation set is now mapped into validation gates. - -ADOPTION is right that the operator path must be small: provision endpoint, bind D1, migrate, register role/scope policy, configure secrets/redaction/raw-read/retention-export, run readiness, expose read clients. The useful operator answer is what is enforcing, observing, redacted, unavailable, retained, and exportable. - -## 10-Star Bar - -A 10-star implementation can answer, from durable evidence and safe hosted reads: - -- who attempted the hosted transition; -- whether admission happened before body parse and kernel invocation; -- which tenant/org/project owned the attempt; -- what exact x402 protected call was admitted; -- what evidence was stored as digest/ref; -- what evidence was redacted; -- what evidence is unavailable; -- what raw evidence is blocked, gated, or allowed; -- whether D1 bindings, migrations, and schema are configured; -- whether KV is non-authoritative; -- whether required secrets are present without revealing values; -- whether export/reconstruction is possible within declared limits; -- whether the public claim matches enforcement. - -## Antipatterns - -- Hosted readiness passes because the process is alive. -- Local D1 tests are treated as Cloudflare production proof. -- Provider-neutral identity becomes tenant/org/project entitlement. -- A transition caller automatically becomes an evidence reader. -- Redacted read APIs accept broad filters instead of exact receipt/evidence ids. -- Raw reads are guarded by naming convention. -- KV becomes the de facto evidence source of truth. -- Readiness dumps `process.env` or secret values. -- Export is a raw receipt dump. -- SDK/CLI/MCP clients imply gateway authority. -- Docs say hosted Handshake when the system only admits transitions and serves redacted reads. -- Compliance language appears before retention/export/audit posture exists. - -## Final Verdict - -Keep, but narrow. - -This is a valid Tier 2 macro plan only if it remains hosted admission plus redacted evidence plane for exact x402 per-call protected actions. The plan should not promote hosted mutation authority, general engineering-agent execution control, payment management, custody, settlement, production readiness, or compliance audit. - -The smallest next mechanism is explicit deployment-mode hosted admission config with fail-closed defaults and a hosted claim guard. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/ASSUMPTIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/ASSUMPTIONS.md deleted file mode 100644 index 918c7db..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/ASSUMPTIONS.md +++ /dev/null @@ -1,51 +0,0 @@ -# Assumptions - -## Release Assumptions - -- The package remains public npm package `handshake-protocol-kernel`. -- The version for this macro starts from current source version `0.2.4`, but implementation must verify whether that version is publishable, already published, or needs incrementing. -- `package.json` remains the source of npm package identity. -- `server.json` remains the source of MCP Registry metadata. -- MCP Registry publication is separate from npm publication. -- Clean install verification must run against the public package artifact, not the local checkout. - -## Authority Assumptions - -- Publication is not an authority path. -- Installation is not authorization. -- MCP discoverability is not trust. -- Registry namespace verification is not policy authorization. -- Package provenance is artifact provenance, not runtime enforcement proof. -- CLI/MCP successful startup is runtime availability proof, not mutation proof. -- x402 exact per-call proves a narrow protected-action pattern, not all protected actions. - -## Operational Assumptions - -- Trusted publishing/OIDC is preferred over long-lived npm tokens. -- Any token path requires explicit 2FA and bypass-risk posture. -- Provenance may be available under supported npm trusted publishing conditions. -- Missing provenance support is a proof gap unless release policy explicitly blocks publication. -- MCP Registry preview instability may require blocking or recording preview proof gaps. - -## Documentation Assumptions - -- Public docs must describe Handshake as protected actions for automated decision making. -- Engineering-agent language may be retained only as a domain example or first wedge. -- Public docs must state that publication distributes package and metadata surfaces only. -- Public docs must not imply hosted operation, marketplace review, settlement, payment management, custody, trust, or host-wide enforcement. - -## Proof Gap Assumptions - -The following are proof gaps until evidenced: - -- npm account ownership posture -- namespace ownership posture -- 2FA/token posture -- OIDC/trusted publishing posture -- provenance availability -- actual npm publication for exact version -- clean install from public npm -- MCP Registry namespace auth -- MCP Registry metadata acceptance -- post-registry discoverability -- rollback/deprecation readiness diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/CONTEXT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/CONTEXT.md deleted file mode 100644 index f9ff6a8..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/CONTEXT.md +++ /dev/null @@ -1,67 +0,0 @@ -# Context: Public Distribution And Publication - -## Invariant At Stake - -Public distribution must not launder publication into authority. - -Handshake is protected actions for automated decision making. Publication can distribute package artifacts, proposal/evidence/read surfaces, and source-owned metadata. It cannot create permission, policy, greenlights, gateway checks, mutation authority, custody, settlement, payment handling, certification, trust, hosted operation, or host-wide enforcement. - -## Macro Item - -Public Distribution And Publication - -## Run - -`public-distribution-publication-20260524T090500Z` - -## Current Package Surface - -The current package is `handshake-protocol-kernel` at version `0.2.4`. - -The package declares MCP name `io.github.joelchan/handshake-protocol-kernel`. - -Public exports currently include root, conformance, runtime, SDK, role clients, CLI, MCP, experimental, and package metadata surfaces. - -Installed commands currently include: - -- `handshake` -- `handshake-mcp` -- package-name bin pointing to the MCP server - -Packaged files currently include bin/source/dist/server metadata/readme/quality/structure/internal docs. - -## Current Registry Surface - -`server.json` targets MCP Registry schema `2025-12-11`. - -It describes npm stdio package metadata and must remain non-authority. - -MCP Registry is preview metadata infrastructure. It does not host npm artifacts and does not make security, trust, enforcement, marketplace, payment, or custody guarantees. - -## Current Check Surface - -Existing scripts already verify parts of the release boundary: - -- package pack shape -- required files -- forbidden paths -- `private: false` -- MCP name sync -- bin shebangs -- CLI schema non-authority smoke -- MCP stdio official client smoke -- no raw `PaymentPayload` or `SIGNATURE` leakage - -These checks are necessary but not complete. They do not by themselves prove account posture, actual npm publication, clean install from the public registry, provenance, MCP Registry acceptance, or post-registry discoverability. - -## Canon Drift To Resolve Later - -README/docs already describe package entrypoints and MCP metadata, but some canon still uses older engineering-agent phrasing. - -That drift is a release blocker for this macro item because the hard invariant is broader: protected actions for automated decision making. Engineering-agent actions may remain a first domain or wedge, but cannot be the product center. - -## Strategy Boundary - -Do not use the cleanest proof surface as a first-market claim. - -x402 exact per-call is the first proof wedge because it is narrow, per-call, inspectable, and easy to test. It is not the protocol center. The protocol center is exact contract, one-use greenlight, gateway check, receipt/refusal/proof-gap, isolation, and bypass posture for protected actions. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/DECISIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/DECISIONS.md deleted file mode 100644 index a0c0ebb..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/DECISIONS.md +++ /dev/null @@ -1,47 +0,0 @@ -# Decisions - -## D-001: Publication Is Non-Authority - -Publication distributes package artifacts, source-owned metadata, and proposal/evidence/read surfaces. It does not create authority, decisions, greenlights, gateway checks, mutations, custody, hosted operation, certification, settlement, payment management, trust, or host-wide enforcement. - -## D-002: Protected Actions Are The Product Center - -Handshake is protected actions for automated decision making. Engineering-agent actions are a first domain, not the full product definition. - -## D-003: x402 Is First Proof Wedge Only - -x402 exact per-call is the first proof wedge because it is narrow, per-call, and inspectable. It must not become the protocol center in package, registry, or README language. - -## D-004: Release States Must Be Separate - -The release lifecycle must distinguish: - -- `ready_to_publish` -- `actually_published` -- `registry_discoverable` - -No state can imply the next one. - -## D-005: Release Proof Must Be Structured - -The release must produce or update a source-owned `PackageReleaseProof` shape with package shape, account/namespace, publish operation, provenance, registry discoverability, runtime smoke, authority boundary, and proof gaps. - -## D-006: Release Manifest Before Publish - -A release manifest must exist before npm publish. It must identify exact package, version, tag, expected pack contents, public entrypoints, account posture, provenance posture, authority-boundary false fields, and stop conditions. - -## D-007: Post-Publish Receipt After Publish - -A post-publish verification receipt must exist after npm publish. It must prove clean install, installed bins, installed exports, non-authority behavior, and any proof gaps. - -## D-008: MCP Registry Is Metadata Only - -MCP Registry publication must be treated as metadata/discoverability. It is not artifact hosting, certification, trust establishment, policy enforcement, or marketplace approval. - -## D-009: Public Claims Must Be Cut To Enforced Reality - -Any claim that exceeds package metadata, installability, proposal/evidence/read surfaces, or source-owned checks must be removed or rewritten. - -## D-010: Risky Publish Credentials Cannot Be Silent - -Long-lived token publish, bypass-2FA token usage, missing 2FA, unavailable provenance, or unknown namespace auth must be explicit blocker/proof-gap states, not hidden release details. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/PLAN.md deleted file mode 100644 index 0796844..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/PLAN.md +++ /dev/null @@ -1,296 +0,0 @@ -# GSD Macro Plan: Public Distribution And Publication - -## Goal - -Make Handshake publicly installable and discoverable as a non-authority protocol kernel for protected actions in automated decision making. - -The release must prove package shape, published entrypoints, MCP metadata, installability, runtime smoke behavior, provenance posture, and authority boundaries. Publication distributes proposal, evidence, read surfaces, and source-owned metadata only. Publication does not create authority, policy decisions, greenlights, gateway checks, mutations, custody, hosted operation, marketplace certification, settlement, payment management, trust, or host-wide enforcement. - -x402 exact per-call remains the first proof wedge. It is not the protocol center. - -## Non-Goals - -- Do not broaden Handshake into engineering-agent-only infrastructure. -- Do not claim npm publication creates enforcement. -- Do not claim MCP Registry listing creates trust, certification, security review, custody, or hosted operation. -- Do not add marketplace, settlement, payment management, or host-wide enforcement claims. -- Do not publish with stale engineering-agent-only canon unresolved. -- Do not treat local dry-run evidence as proof of public installability. -- Do not treat a registry metadata entry as proof that package artifacts are safe. - -## Source Boundary - -Authoritative source for this macro item is limited to current tracked repo surfaces and official publication constraints summarized for this run. - -Current source surfaces: - -- `package.json` -- `server.json` -- `scripts/check-package-surface.mjs` -- `scripts/check-published-entrypoints.mjs` -- `README.md` -- `QUALITY.md` -- `STRUCTURE.md` -- `docs/internal/decisions.md` -- `docs/internal/protocol-notes.md` - -Scratch planning files are not source authority. This macro plan may guide work, but implementation must land through tracked source, checks, and receipts. - -Official publication constraints: - -- npm publication publishes installable package artifacts by name and version. -- `npm pack --dry-run --json` is the local package-content inspection gate. -- `package.json` `name` and `version` identify the publishable package. -- `exports` defines public entrypoints and blocks arbitrary package entrypoints. -- `bin` installs commands and Node bins must use a Node shebang. -- `files` constrains package contents. -- Trusted publishing/OIDC is preferred over long-lived tokens and can generate provenance for public packages under supported conditions. -- 2FA/token posture must be explicit; bypass-2FA tokens are risky. -- MCP Registry is preview, hosts metadata rather than artifacts, uses `server.json`, requires public install methods, and for npm ownership verification requires `package.json#mcpName` to match `server.json#name`. - -## Current State - -The package currently declares: - -- package name `handshake-protocol-kernel` -- version `0.2.4` -- `mcpName` `io.github.joelchan/handshake-protocol-kernel` -- root, conformance, runtime, SDK, role client, CLI, MCP, experimental, and package metadata exports -- bins `handshake`, `handshake-mcp`, and a package-name bin pointing to the MCP server -- files covering bins, source, dist, `server.json`, README, quality/structure docs, and internal docs - -`server.json` currently uses MCP Registry schema `2025-12-11`, npm stdio package metadata, and a non-authority description. - -Existing checks cover: - -- npm pack dry-run JSON inspection -- required packaged files -- forbidden packaged paths -- `private: false` -- `mcpName` and `server.json#name` sync -- Node shebangs for bins -- CLI schema non-authority smoke -- MCP stdio official client smoke -- no raw `PaymentPayload` or `SIGNATURE` leakage in published entrypoints - -Known source drift: - -- README/docs already describe package entrypoints and MCP metadata. -- Current canon still contains older engineering-agent phrasing that must be corrected before publication. - -## Target State - -A release is ready only when there is a source-owned release proof that separates: - -- `ready_to_publish`: local package contract, pack evidence, metadata checks, runtime smoke, account/namespace posture, provenance posture, and authority-boundary checks have passed. -- `actually_published`: npm publish has occurred for the exact package/version and post-publish clean-install smoke has passed. -- `registry_discoverable`: MCP Registry metadata has been accepted and post-registry discoverability checks have passed, without implying artifact trust or enforcement. - -The target proof object is `PackageReleaseProof` with: - -- `packageShapeProof` -- `accountNamespaceProof` -- `publishOperationProof` -- `provenanceProof` -- `registryDiscoverabilityProof` -- `runtimeSmokeProof` -- `authorityBoundary` -- `proofGaps` - -`authorityBoundary` must explicitly record false/non-authority fields for: - -- createsAuthority -- createsPolicyDecision -- createsGreenlight -- performsGatewayCheck -- performsMutation -- holdsCustody -- hostsOperation -- certifiesMarketplace -- managesSettlement -- managesPayment -- establishesTrust -- enforcesHostWidePolicy - -## Assumptions - -- npm is the first artifact registry for the public package. -- MCP Registry is a preview discoverability surface, not an enforcement or trust root. -- The publishable package remains public and installable by package name. -- Publication receipt must distinguish local readiness, npm publication, post-publish install, MCP Registry metadata, and post-registry discoverability. -- x402 exact per-call is used as the first proof wedge only. -- Existing scripts are close enough to extend, but not sufficient until older engineering-agent-only canon is removed from public-facing claims. -- Any missing account, OIDC, 2FA, provenance, or namespace proof is a proof gap, not a release success. - -## Decisions - -1. Public distribution is a publication/readiness problem, not an authority primitive. -2. `ready_to_publish`, `actually_published`, and `registry_discoverable` are separate release states. -3. A release manifest must exist before publish; a post-publish verification receipt must exist after publish. -4. MCP Registry metadata must use non-authority wording and must not imply certification, trust, hosted operation, or enforcement. -5. npm trusted publishing/OIDC is preferred; long-lived token publishing requires explicit risk acceptance and proof-gap recording. -6. Clean install smoke after npm publish is mandatory before claiming public installability. -7. Publication checks must fail on package leakage, public export overexposure, stale metadata, missing provenance posture, or engineering-agent-only framing. -8. Rollback posture is deprecate/unpublish-within-registry-policy where possible, plus documentation correction; publication cannot be silently erased from downstream consumers. - -## Phases - -### Phase 1: Local Readiness Contract - -Define the release proof shape and readiness states. Align package metadata, docs, and checks to the protected-actions-for-automated-decision-making invariant. - -### Phase 2: npm Preflight - -Run dry-run package inspection, public export review, bin shebang checks, CLI/MCP smoke, metadata sync, dependency/install-script review, and authority-boundary wording checks. - -### Phase 3: npm Publish - -Publish only from an exact version/tag with explicit account, 2FA/token, and provenance posture. Record publish operation evidence and proof gaps. - -### Phase 4: Post-npm Verification - -Perform clean install by package name and version. Verify bins, exported entrypoints, proposal/evidence/read behavior, and non-authority messaging from installed artifacts. - -### Phase 5: MCP Registry Preflight - -Verify `server.json`, namespace auth, install method metadata, npm ownership sync, preview-status language, and non-certification claims. - -### Phase 6: MCP Registry Publication - -Submit registry metadata only after npm post-publish verification passes. Record registry operation evidence separately from npm artifact evidence. - -### Phase 7: Post-registry Verification - -Verify discoverability, install instructions, metadata drift, and preview limitations. Record `registry_discoverable` only if the metadata is findable and still non-authority. - -## Task Graph - -- `PD-01` has no dependencies. -- `PD-02` depends on `PD-01`. -- `PD-03` depends on `PD-01`. -- `PD-04` depends on `PD-02` and `PD-03`. -- `PD-05` depends on `PD-04`. -- `PD-06` depends on `PD-05`. -- `PD-07` depends on `PD-06`. -- `PD-08` depends on `PD-07`. -- `PD-09` depends on `PD-08`. -- `PD-10` depends on `PD-09`. -- `PD-11` depends on `PD-10`. -- `PD-12` depends on `PD-11`. - -## Risks And Mitigations - -- Package leakage: enforce pack dry-run forbidden paths and required files. -- Dist/source mismatch: smoke installed artifacts, not just source checkout paths. -- Public exports overexpose authority internals: review `exports` as public API, not convenience. -- Bins imply mutation: smoke CLI/MCP messaging for proposal/evidence/read posture only. -- Registry overclaims trust: constrain `server.json` and docs to metadata/discoverability. -- Token/2FA/provenance gaps: record account posture before publish and block silent token fallback. -- Namespace ownership gaps: require `mcpName`/`server.json#name` sync and namespace auth evidence. -- Metadata drift: compare package metadata, server metadata, README, and published install instructions. -- Node runtime failures: clean install smoke bins and exported entrypoints. -- Unexpected install scripts/dependencies: inspect package scripts and dependency surface before publish. -- Rollback/deprecation gaps: predefine stop/deprecate/correction procedure before publish. -- MCP preview instability: record registry proof gaps and never make enforcement claims from registry availability. - -## Validation Gates - -Local gates: - -- `npm pack --dry-run --json` evidence captured. -- Required files present in pack contents. -- Forbidden paths absent from pack contents. -- `private` is false. -- `package.json#mcpName` equals `server.json#name`. -- Node bins use Node shebangs. -- CLI schema smoke proves non-authority posture. -- MCP stdio smoke works through official client path. -- Raw `PaymentPayload` and `SIGNATURE` are not exposed through published entrypoints. -- Public docs no longer frame Handshake as engineering-agent-only infrastructure. - -Pre-publish gates: - -- version/tag are exact. -- account namespace ownership is evidenced. -- 2FA/token posture is explicit. -- provenance posture is explicit. -- rollback/deprecation posture is written. -- release manifest exists. - -Post-publish gates: - -- clean install by package name and version succeeds. -- installed bins run. -- installed exports resolve. -- proposal/evidence/read surfaces work without implying mutation authority. -- publication receipt distinguishes local, npm, provenance, runtime, and proof-gap evidence. - -Registry gates: - -- `server.json` uses public install methods only. -- registry wording is metadata/discoverability only. -- namespace auth evidence exists or is recorded as a blocker. -- registry acceptance is recorded separately from package artifact evidence. -- post-registry discoverability is verified without trust/certification claims. - -## Cut Lines - -Cut any claim that publication: - -- creates authority -- makes policy decisions -- creates greenlights -- performs gateway checks -- causes mutation -- holds custody -- hosts operation -- certifies trust -- manages settlement or payment -- enforces host-wide policy - -Cut any release path that: - -- relies on long-lived token publish without explicit risk recording -- treats MCP Registry as artifact validation -- treats x402 as protocol center -- keeps engineering-agent-only public framing -- cannot distinguish readiness from actual publication -- cannot reconstruct what was published, by whom, under which version/provenance posture - -## Rollback / Stop Conditions - -Stop before npm publish if: - -- pack contents include forbidden paths. -- public exports expose unstable authority internals. -- docs or metadata imply enforcement through publication. -- account/2FA/provenance posture is unknown. -- version/tag is ambiguous. -- release manifest is missing. -- clean local smoke fails. - -Stop after npm publish and before registry submission if: - -- clean install fails. -- installed bins fail. -- installed artifacts drift from source-owned metadata. -- post-publish receipt cannot be produced. -- non-authority messaging fails from installed artifacts. - -Stop after registry submission if: - -- registry metadata implies trust, certification, hosted operation, settlement, payment, or enforcement. -- namespace auth fails. -- discoverability cannot be verified. -- preview instability prevents a reliable registry receipt. - -Rollback posture: - -- prefer immediate correction release for package metadata or docs drift. -- use npm deprecation for unsafe or misleading versions where appropriate. -- use registry metadata correction/removal where supported. -- record every failed publish, deprecation, correction, and unresolved proof gap. - -## Smallest Next Action - -Define the `PackageReleaseProof` and release-state contract in source-owned docs/checks, with explicit false authority-boundary fields and proof-gap recording before any publish command is considered. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/RISKS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/RISKS.md deleted file mode 100644 index 3263d78..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/RISKS.md +++ /dev/null @@ -1,18 +0,0 @@ -# Risks - -| ID | Risk | Failure Mode | Mitigation | Stop Condition | -| --- | --- | --- | --- | --- | -| R-001 | Package leakage | Pack includes scratch plans, secrets, internal junk, or unintended source | Keep `npm pack --dry-run --json` as hard gate with required and forbidden path checks | Any forbidden path appears | -| R-002 | Dist/source mismatch | Local source passes but installed package fails | Clean install exact package/version after publish | Installed bins or exports fail | -| R-003 | Export overexposure | Public `exports` expose authority internals or unstable control surfaces | Review exports as public API and block arbitrary entrypoints | Export implies enforceable authority without gateway | -| R-004 | Bin overclaim | CLI or MCP bin language implies mutation or enforcement | Smoke installed bins for proposal/evidence/read posture | Bin says or implies publication-created authority | -| R-005 | Registry trust laundering | MCP Registry listing is described as certification or trust | Constrain registry language to metadata and discoverability | Metadata implies trust, certification, or security review | -| R-006 | Token/2FA weakness | Publish relies on risky long-lived or bypass-2FA credentials | Prefer OIDC trusted publishing; record credential posture | Account posture unknown or risky path unaccepted | -| R-007 | Missing provenance | Artifact provenance cannot be shown | Use trusted publishing where supported; otherwise record proof gap | Release policy requires provenance and proof is missing | -| R-008 | Namespace mismatch | `package.json#mcpName` and `server.json#name` drift | Keep sync check hard-gated | Names differ | -| R-009 | Metadata drift | README, package metadata, server metadata, and docs contradict | Add/reuse checks and manual release review | Public text reverts to engineering-agent-only center | -| R-010 | Install-script/dependency surprise | Package install runs unexpected lifecycle behavior or pulls broad dependencies | Inspect scripts/dependencies before publish | Unexpected mutation-capable install behavior appears | -| R-011 | Rollback fantasy | Bad release cannot be erased from consumers | Predefine deprecate/correction path | No rollback/deprecation posture exists | -| R-012 | MCP preview instability | Registry behavior changes or acceptance is unavailable | Treat registry as optional discoverability with proof gaps | Registry instability blocks reliable metadata receipt | -| R-013 | x402 center drift | Package language makes x402 the protocol center | Keep x402 as first proof wedge only | Public docs overfit Handshake to x402 | -| R-014 | Evidence theatre | Receipt conflates local checks, publish operation, registry metadata, and runtime success | Use separate proof sections and state transitions | Receipt cannot reconstruct state chain | diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/TASKS.jsonl b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/TASKS.jsonl deleted file mode 100644 index aef20b2..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/TASKS.jsonl +++ /dev/null @@ -1,12 +0,0 @@ -{"id":"PD-01","priority":"P0","phase":"local-readiness","title":"Define release-state and PackageReleaseProof contract","owner":"GSD executor","rationale":"Publication needs a structured proof boundary before any publish operation, or readiness will be confused with authority.","depends_on":[],"acceptance":["States ready_to_publish, actually_published, and registry_discoverable are distinct","PackageReleaseProof includes packageShapeProof, accountNamespaceProof, publishOperationProof, provenanceProof, registryDiscoverabilityProof, runtimeSmokeProof, authorityBoundary, and proofGaps","authorityBoundary contains explicit false fields for non-authority claims"],"candidate_paths":["docs/internal/decisions.md","docs/internal/protocol-notes.md","scripts/check-published-entrypoints.mjs"],"non_goals":["Do not publish","Do not create gateway enforcement","Do not add hosted operation"]} -{"id":"PD-02","priority":"P0","phase":"local-readiness","title":"Remove engineering-agent-only public framing","owner":"GSD executor","rationale":"The hard invariant is protected actions for automated decision making; engineering agents are a domain wedge, not the product center.","depends_on":["PD-01"],"acceptance":["README and package-facing docs use protected-actions framing","Engineering-agent language is limited to wedge/example status","x402 exact per-call is described as first proof wedge only"],"candidate_paths":["README.md","docs/internal/decisions.md","docs/internal/protocol-notes.md","server.json"],"non_goals":["Do not broaden into generic auth","Do not reposition x402 as protocol center","Do not rewrite unrelated docs"]} -{"id":"PD-03","priority":"P0","phase":"local-readiness","title":"Harden non-authority publication wording","owner":"GSD executor","rationale":"Package and registry metadata must not imply authority, policy decisions, greenlights, gateway checks, mutation, custody, trust, settlement, or hosted operation.","depends_on":["PD-01"],"acceptance":["server.json remains metadata-only","README states publication does not create authority","CLI/MCP descriptions avoid mutation or enforcement claims"],"candidate_paths":["server.json","README.md","package.json","src"],"non_goals":["Do not add enforcement implementation","Do not add marketplace claims","Do not add payment management claims"]} -{"id":"PD-04","priority":"P0","phase":"npm-preflight","title":"Extend package surface checks for authority-boundary claims","owner":"GSD executor","rationale":"Existing package checks cover shape but not the full publication authority boundary.","depends_on":["PD-02","PD-03"],"acceptance":["Pack dry-run remains mandatory","Forbidden path checks remain mandatory","Checks fail on authority-overclaiming metadata or public text","Checks preserve no raw PaymentPayload or SIGNATURE leakage"],"candidate_paths":["scripts/check-package-surface.mjs","scripts/check-published-entrypoints.mjs","package.json","server.json"],"non_goals":["Do not publish","Do not inspect private npm account state in source","Do not certify downstream security"]} -{"id":"PD-05","priority":"P0","phase":"npm-preflight","title":"Create release manifest preflight requirements","owner":"GSD executor","rationale":"A publish operation without an exact manifest is not reconstructable six months later.","depends_on":["PD-04"],"acceptance":["Manifest records package name, version, tag, pack evidence, exports, bins, account posture, provenance posture, authority boundary, stop conditions, and proof gaps","Manifest separates local readiness from publish evidence","Manifest blocks unknown credential posture"],"candidate_paths":["docs/internal/protocol-notes.md","scripts","package.json"],"non_goals":["Do not store secrets","Do not publish","Do not mark actually_published"]} -{"id":"PD-06","priority":"P0","phase":"npm-preflight","title":"Verify npm account, 2FA, token, and provenance posture","owner":"release operator","rationale":"Credential posture is part of publication risk; silent fallback to risky tokens is unacceptable.","depends_on":["PD-05"],"acceptance":["OIDC/trusted publishing availability is recorded","2FA/token posture is recorded","Bypass-2FA token usage is blocked or explicitly recorded as rejected risk","Provenance support is recorded or proof gap is named"],"candidate_paths":["release manifest","npm account configuration","CI publication configuration"],"non_goals":["Do not commit secrets","Do not bypass 2FA silently","Do not treat provenance as runtime enforcement"]} -{"id":"PD-07","priority":"P0","phase":"npm-publish","title":"Publish exact npm package version only after preflight passes","owner":"release operator","rationale":"Publication mutates public artifact state and must be tied to exact package/version/provenance evidence.","depends_on":["PD-06"],"acceptance":["Publish uses exact package version and tag","Publish operation evidence is captured","Failure does not advance actually_published","Provenance evidence or proof gap is recorded"],"candidate_paths":["package.json","release manifest","npm publish output"],"non_goals":["Do not submit MCP Registry metadata yet","Do not claim registry discoverability","Do not claim enforcement"]} -{"id":"PD-08","priority":"P0","phase":"post-npm-smoke","title":"Run clean install smoke against public npm artifact","owner":"GSD executor","rationale":"Local source success does not prove public installability or installed runtime behavior.","depends_on":["PD-07"],"acceptance":["Clean install by package name and version succeeds","Installed handshake bin runs","Installed handshake-mcp bin runs","Installed package-name bin runs","Installed exports resolve","Installed messaging remains non-authority"],"candidate_paths":["published package","dist","bin","exports"],"non_goals":["Do not rely on local checkout","Do not mutate protected surfaces","Do not infer downstream business success"]} -{"id":"PD-09","priority":"P0","phase":"post-npm-smoke","title":"Write post-publish verification receipt","owner":"GSD executor","rationale":"The receipt must distinguish package shape, publish operation, provenance, install smoke, and proof gaps.","depends_on":["PD-08"],"acceptance":["Receipt marks actually_published only after clean install passes","Receipt records proof gaps separately","Receipt preserves authorityBoundary false fields","Receipt is reconstructable from source-owned evidence"],"candidate_paths":["docs/internal/protocol-notes.md","release manifest","post-publish receipt"],"non_goals":["Do not claim MCP discoverability","Do not erase failed publish attempts","Do not merge registry evidence into npm evidence"]} -{"id":"PD-10","priority":"P1","phase":"mcp-registry-preflight","title":"Verify MCP Registry metadata and namespace posture","owner":"release operator","rationale":"MCP Registry is metadata/discoverability only and requires namespace/package-name alignment.","depends_on":["PD-09"],"acceptance":["server.json uses public install methods","package.json mcpName matches server.json name","Namespace auth evidence exists or blocks","Registry wording stays metadata-only","Preview limitations are recorded"],"candidate_paths":["server.json","package.json","README.md","MCP Registry submission metadata"],"non_goals":["Do not imply registry certification","Do not host artifacts in registry","Do not claim enforcement"]} -{"id":"PD-11","priority":"P1","phase":"mcp-registry-publish","title":"Submit MCP Registry metadata after npm proof passes","owner":"release operator","rationale":"Registry submission before npm artifact verification would create discoverability for an unproven package.","depends_on":["PD-10"],"acceptance":["Registry submission evidence is captured","Failure does not advance registry_discoverable","Registry operation evidence is separate from npm publish evidence"],"candidate_paths":["server.json","MCP Registry submission output","post-publish receipt"],"non_goals":["Do not republish npm package","Do not claim trust","Do not claim marketplace approval"]} -{"id":"PD-12","priority":"P1","phase":"post-registry-smoke","title":"Verify registry discoverability and finalize release support bundle","owner":"GSD executor","rationale":"Discoverability must be evidenced and packaged with explicit readiness statuses and proof gaps.","depends_on":["PD-11"],"acceptance":["Registry listing is discoverable","Listing install instructions match source-owned metadata","Support bundle uses allowed readiness statuses","registry_discoverable is set only after verification","MCP preview instability is recorded if present"],"candidate_paths":["server.json","README.md","support bundle","release receipt"],"non_goals":["Do not claim host-wide enforcement","Do not claim payment or settlement management","Do not certify downstream aggregators"]} diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/VALIDATION.md deleted file mode 100644 index 4a2cdfb..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/VALIDATION.md +++ /dev/null @@ -1,97 +0,0 @@ -# Validation - -## Invariant Gate - -A release passes only if every public surface preserves this statement: - -Handshake is protected actions for automated decision making. Publication distributes package artifacts, proposal/evidence/read surfaces, and source-owned metadata. Publication does not create authority, policy decisions, greenlights, gateway checks, mutations, custody, hosted operation, marketplace certification, settlement, payment management, trust, or host-wide enforcement. - -## Local Readiness Gates - -- Package identity is explicit: name, version, `mcpName`. -- `server.json#name` matches `package.json#mcpName`. -- `server.json` uses MCP Registry schema `2025-12-11`. -- `server.json` describes npm stdio install metadata only. -- `package.json#private` is false. -- `exports` are reviewed as the public interface. -- `bin` entries point to Node-shebang executables. -- `files` allow required publication files and exclude forbidden paths. -- `npm pack --dry-run --json` evidence is captured. -- CLI schema smoke proves non-authority behavior. -- MCP stdio smoke proves runtime startup through official client path. -- Published entrypoints do not leak raw `PaymentPayload` or `SIGNATURE`. - -## Documentation Gates - -- README/package/server metadata do not frame Handshake as engineering-agent-only infrastructure. -- Engineering-agent language is limited to a domain example or wedge. -- x402 exact per-call is described as first proof wedge, not protocol center. -- Public docs do not imply publication-created authority. -- Public docs do not imply MCP Registry trust, certification, security review, custody, settlement, payment management, hosted operation, or enforcement. - -## npm Preflight Gates - -- Exact version/tag is chosen. -- Release manifest exists. -- Account ownership posture is recorded. -- 2FA/token posture is recorded. -- OIDC/trusted publishing posture is recorded. -- Provenance posture is recorded. -- Rollback/deprecation posture is recorded. -- Known proof gaps are explicit. - -## npm Publish Gates - -- Publish command uses exact intended package/version/tag. -- Publish operation evidence is captured. -- Provenance evidence is captured or proof gap recorded. -- Failure does not advance `actually_published`. - -## Post-npm Gates - -- Clean install by package name and exact version succeeds. -- Installed `handshake` bin runs. -- Installed `handshake-mcp` bin runs. -- Installed package-name bin runs. -- Installed exports resolve. -- Proposal/evidence/read surfaces operate without implying mutation authority. -- Post-publish receipt exists. -- `actually_published` is set only after clean install smoke passes. - -## MCP Registry Preflight Gates - -- npm package metadata is public and installable. -- `package.json#mcpName` equals `server.json#name`. -- Namespace auth evidence exists or blocks. -- Install methods are public. -- Registry wording is metadata/discoverability only. -- Preview limitations are stated. - -## MCP Registry Post Gates - -- Registry metadata submission evidence is captured. -- Discoverability is verified. -- Registry listing does not imply artifact trust or enforcement. -- `registry_discoverable` is set only after post-registry verification. -- Any registry preview instability is recorded as proof gap. - -## Release Status Vocabulary - -Allowed readiness statuses: - -- `ready:proposal-mode` -- `ready:gateway-mode` -- `blocked:metadata` -- `blocked:runtime` -- `blocked:mcp-stdio` -- `blocked:package-contents` -- `blocked:namespace-auth` -- `blocked:provenance` -- `preview:unsupported-enforcement` - -Forbidden status implications: - -- no status may imply publication-created authority -- no status may imply MCP Registry certification -- no status may imply gateway enforcement unless a gateway check actually exists and is evidenced -- no status may imply payment or settlement management diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/input.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/input.md deleted file mode 100644 index 1eda42a..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/input.md +++ /dev/null @@ -1,153 +0,0 @@ -# Input: Public Distribution And Publication - -## Hard Frame - -Handshake is protected actions for automated decision making, not engineering-agent-only infrastructure. - -x402 exact per-call is the first proof wedge, not the protocol center. - -Public distribution means packaging and publishing proposal/evidence/read surfaces and source-owned metadata. It does not create authority, gateway custody, hosted operation, marketplace trust, certification, settlement, payment management, or host-wide enforcement. - -CLI/MCP/SDK publication is distribution, not enforcement. Any command, server, package metadata, or registry listing must keep the boundary: - -```text -proposal/read/evidence surface != policy decision -proposal/read/evidence surface != greenlight -proposal/read/evidence surface != gateway check -proposal/read/evidence surface != mutation -proposal/read/evidence surface != receipt export -proposal/read/evidence surface != hosted verifier trust -``` - -## Current Source State - -Tracked source already has a publishable package boundary: - -- `package.json` - - name: `handshake-protocol-kernel` - - version: `0.2.4` - - `mcpName`: `io.github.joelchan/handshake-protocol-kernel` - - bin commands: - - `handshake` -> `bin/handshake` - - `handshake-mcp` -> `bin/handshake-mcp` - - `handshake-protocol-kernel` -> `bin/handshake-mcp` - - exports: - - `.` - - `./conformance` - - `./runtime` - - `./sdk/role-clients` - - `./cli` - - `./mcp` - - `./experimental` - - `./package.json` - - files include `bin`, `src`, `dist`, `server.json`, repo canon, and compact internal docs. - -- `server.json` - - schema: `https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json` - - name: `io.github.joelchan/handshake-protocol-kernel` - - package: npm/stdio `handshake-protocol-kernel` version `0.2.4` - - description explicitly says proposal/evidence only and no policy, greenlight, gateway check, mutation, receipt export, authority certificate, provider custody, hosted operation, or broad MCP protection. - -- `scripts/check-package-surface.mjs` - - runs `npm pack --dry-run --json` - - verifies required files - - rejects package leakage of `.planning/`, `.agents/`, tests, old docs trees, `.DS_Store`, and other forbidden paths - - rejects `package.json#private === true` - -- `scripts/check-published-entrypoints.mjs` - - asserts `package.json#mcpName` matches `server.json#name` - - asserts `server.json` version/package metadata matches `package.json` - - asserts bin wrappers exist and use Node shebangs - - smoke-tests `node bin/handshake schema` - - smoke-tests `bin/handshake-mcp` through the official MCP client SDK - - confirms CLI/MCP outputs do not create authority, greenlight, gateway check, mutation, raw records, credential material, receipt export, or certificate mint. - -Current local package docs: - -- `README.md` describes packaged CLI/MCP entrypoints and MCP Registry metadata. -- `docs/internal/decisions.md` records package boundary decision. -- `.planning/codebase/STACK.md` and `.planning/codebase/INTEGRATIONS.md` record publication posture as scratch mapper outputs. - -## Official External Source Constraints - -Use these source constraints in the plan: - -- npm publish docs: - - `npm publish` publishes a package installable by name. - - npm defaults to the public registry unless registry config/scope changes it. - - `npm pack --dry-run` is the way to inspect what will be included before publication. - - `npm publish` has `access`, `dry-run`, `otp`, `provenance`, and `provenance-file` configuration surfaces. - - Source: https://docs.npmjs.com/cli/publish/ - -- npm pack docs: - - `npm pack --dry-run --json` can report what would be packed without creating changes and can output JSON. - - Source: https://docs.npmjs.com/cli/v11/commands/npm-pack - -- npm package.json docs: - - `name` and `version` are required identifiers for publishable packages. - - `exports` defines the public interface and prevents arbitrary entrypoints outside exports. - - `bin` installs executable commands and bin files should start with `#!/usr/bin/env node`. - - `files` controls what is included. - - Source: https://docs.npmjs.com/cli/v11/configuring-npm/package-json - -- npm trusted publishing docs: - - trusted publishing uses short-lived scoped OIDC credentials and avoids long-lived publish tokens. - - npm recommends restricting traditional token access after trusted publishing is configured. - - trusted publishing can automatically generate provenance for public packages from public repositories under supported conditions. - - Source: https://docs.npmjs.com/trusted-publishers/ - -- npm access token / 2FA docs: - - granular tokens can be scoped and can bypass 2FA only if configured. - - bypassing 2FA should not be used when fully enforced 2FA is required. - - `Require two-factor authentication and disallow tokens` prevents granular token publishing. - - Sources: - - https://docs.npmjs.com/about-access-tokens/ - - https://docs.npmjs.com/requiring-2fa-for-package-publishing-and-settings-modification/ - -- MCP Registry docs: - - the official MCP Registry is currently preview and may have breaking changes or data resets before GA. - - it hosts metadata, not package artifacts. - - server metadata lives in standardized `server.json`. - - npm package metadata in `server.json` uses `registryType: "npm"` and package identifier/version/transport. - - npm package ownership verification requires `package.json#mcpName` to match `server.json#name`. - - the registry supports only public installation methods / public servers and does not support private servers. - - namespace authentication determines allowed server names. - - the registry focuses on namespace authentication and metadata hosting; underlying package registries and downstream aggregators handle broader security scanning/curation. - - Sources: - - https://modelcontextprotocol.io/registry/about - - https://modelcontextprotocol.io/registry/quickstart - - https://modelcontextprotocol.io/registry/package-types - - https://modelcontextprotocol.io/registry/authentication - - https://modelcontextprotocol.io/registry/github-actions - -## Planning Question - -Create a macro plan for public distribution and publication that makes the package actually release-ready without overclaiming authority. - -The plan must cover: - -- npm package release readiness; -- MCP Registry publication readiness; -- source-owned package metadata and schema validation; -- CLI/MCP/SDK public-surface boundaries; -- provenance/trusted publishing posture; -- 2FA/token posture; -- dry-run and post-publish verification; -- release rollback/deprecation posture; -- support/readiness bundle; -- versioning/tagging/registry drift; -- docs and claim guards; -- end criteria for "ready to publish" versus "published"; -- what a 10-star publication surface looks like; -- antipatterns to avoid. - -## Required Output Properties - -- The plan must keep CLI/MCP/SDK as proposal/evidence/read surfaces unless paired with actual gateway enforcement. -- The plan must not imply npm or MCP Registry publication is trust, certification, marketplace status, hosted operation, custody, or authority. -- The plan must separate package shape proof, account/namespace proof, publish operation proof, provenance proof, registry discoverability proof, and runtime smoke proof. -- The plan must be executable slice-by-slice. -- The plan must name validation gates and closeout commands. -- The plan must include external-source decisions and cut lines. -- The plan must include non-goals and stop conditions. -- The plan must not implement source changes. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/ADOPTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/ADOPTION.md deleted file mode 100644 index 1cab9c2..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/ADOPTION.md +++ /dev/null @@ -1,211 +0,0 @@ -# ADOPTION: Public Distribution And Publication - -## Invariant At Stake - -Public distribution must not convert a proposal/evidence surface into an authority claim. If npm, CLI, MCP, README, or support output implies enforcement without a blocking gateway check, this is advisory, not Handshake. - -## First Install/Test-Drive Flow - -### npm user - -The first-run path should prove three things fast: - -1. The package installs by public name. -2. The CLI/bin exports work on the supported Node runtime. -3. A user can generate or inspect an exact protected-action proposal without believing mutation is enforced. - -Recommended flow: - -```bash -npm install -npx --version -npx doctor -npx demo x402 -npx support-bundle --dry-run -``` - -The demo should show: - -- exact per-call action contract; -- policy decision shape; -- evidence/receipt shape; -- explicit statement that no real mutation occurred; -- explicit statement that enforcement requires a gateway integration. - -Do not make the first demo depend on hosted accounts, secrets, payment credentials, or real x402 traffic. - -### MCP user - -The MCP path should prove stdio startup and read/proposal capability only: - -```json -{ - "mcpServers": { - "handshake": { - "command": "npx", - "args": ["", "mcp"] - } - } -} -``` - -Expected first MCP actions: - -- `handshake.readiness`; -- `handshake.describeCatalog`; -- `handshake.proposeAction`; -- `handshake.renderEvidence`; -- `handshake.supportBundle`. - -Avoid MCP tools named as if they execute protected work unless they really perform gateway-blocked enforcement. Prefer `propose*`, `inspect*`, `explain*`, `read*`, `render*`. - -## README/Quickstart Posture - -The README should open with a tight boundary: - -> Handshake turns consequential automated actions into exact proposed action contracts, policy decisions, gateway checks, and reconstructable evidence. This package provides public SDK, CLI, MCP, and readiness surfaces. Enforcement exists only where a blocking gateway check is integrated before mutation. - -The quickstart should separate: - -- **Proposal/read mode:** CLI, MCP, SDK can form contracts and evidence. -- **Gateway mode:** protected mutation is blocked unless an exact greenlight is checked at the gateway. -- **Preview status:** package is public/preview; enforcement coverage is intentionally narrow. - -The x402 wedge should be framed as the first proof path: - -> The first packaged wedge is exact per-call x402 authorization evidence. Handshake is not x402-only; x402 is the first narrow protected-action surface used to prove contract binding, one-use greenlights, and receipt evidence. - -## CLI/MCP Expectations And Non-Claims - -### CLI may claim - -- creates exact action proposals; -- canonicalizes known action contracts; -- runs readiness checks; -- emits support bundles; -- validates package/MCP metadata; -- demonstrates x402 per-call contract/evidence flow; -- shows whether a gateway is configured. - -### CLI must not claim - -- "protects your agents" by itself; -- "enforces MCP tools" broadly; -- "secures payments" generally; -- "manages x402 payments"; -- "approves actions" unless policy decision semantics are exact; -- "blocks mutation" unless the command is paired with a real gateway check. - -### MCP may claim - -- exposes proposal/read/evidence tools to MCP clients; -- lets an agent inspect catalog, policy posture, and receipts; -- can participate in review flows. - -### MCP must not claim - -- that stdio itself is the enforcement boundary; -- that MCP registration protects tools; -- that an agent cannot bypass it; -- that all CLI/MCP actions are protected; -- that a rendered plan is permission. - -If MCP can propose but not block, say so directly: - -> This MCP server is a proposal and evidence surface. It does not enforce protected mutation unless the downstream gateway checks the exact greenlight before consequence. - -## Support Bundle/Readiness Report - -The support bundle should be boring, local, and redacted by default. - -It should include: - -- package name/version; -- Node version and platform; -- binary resolution; -- export resolution; -- package files included; -- `server.json` presence and parse result; -- MCP stdio smoke result; -- namespace/auth status where relevant; -- provenance status; -- preview/GA status; -- configured gateway status; -- action catalog version; -- x402 demo readiness; -- last readiness failure code; -- redaction summary. - -It should not include: - -- secrets; -- raw env vars; -- payment credentials; -- private keys; -- full filesystem listings; -- hosted account tokens; -- mutation payloads unless explicitly redacted. - -Readiness status should be explicit: - -- `ready:proposal-mode` -- `ready:gateway-mode` -- `blocked:metadata` -- `blocked:runtime` -- `blocked:mcp-stdio` -- `blocked:package-contents` -- `blocked:namespace-auth` -- `blocked:provenance` -- `preview:unsupported-enforcement` - -## Error Message Guidance - -| Failure | Message Shape | -|---|---| -| Namespace auth | `Namespace authorization failed for . Publish/install identity could not be verified. This blocks public distribution readiness, not local proposal-mode use.` | -| Metadata | `Package metadata is incomplete: missing . npm/MCP users need stable name, version, bin, exports, files, and preview status before public install can be trusted.` | -| Provenance | `Package provenance is missing or unverifiable. Public publication can proceed only as preview if this is intentional; otherwise fix provenance before release.` | -| Package contents | `Published files do not include required runtime assets: . The package may install but cannot provide the documented CLI/MCP surface.` | -| Node runtime | `Unsupported Node runtime: detected , requires . Handshake cannot guarantee CLI/MCP behavior on this runtime.` | -| MCP metadata/server.json | `MCP Registry metadata is invalid: . This blocks registry readiness, not npm install by name.` | -| MCP stdio smoke | `MCP stdio smoke failed before capability registration: . The server is not ready for MCP clients.` | -| Gateway missing | `No blocking gateway configured. CLI/MCP/SDK are available in proposal/evidence mode only.` | -| x402 demo unavailable | `x402 per-call demo is unavailable: . This does not mean Handshake is x402-only; it means the first public proof wedge is not ready.` | - -Error messages should say what is blocked and what is still usable. Do not collapse metadata failure, enforcement failure, and demo failure into one vague "setup failed." - -## 10-Star First Public Package Experience - -A 10-star first package experience looks like this: - -- `npm install` works by name without private registry assumptions. -- `npx doctor` gives a crisp readiness report in under a few seconds. -- MCP users can paste one config block and get a successful stdio smoke. -- The first demo produces an exact x402 per-call proposal/evidence artifact without requiring real money movement. -- Every screen distinguishes proposal, policy decision, gateway check, execution result, refusal, and proof gap. -- README tells users exactly what is enforced today and what is only preview/proposal mode. -- Package contents match docs: bins, exports, server metadata, examples, and support command all work. -- Failure messages are actionable and scoped. -- No hosted operation is implied. -- No broad "agent security" claim appears before gateway enforcement exists. - -## What To Avoid - -Avoid: - -- naming commands `approve`, `execute`, `protect`, or `enforce` unless they actually bind to gateway checks; -- presenting MCP as the enforcement point; -- making x402 read as the whole product; -- making Handshake sound like payment management; -- claiming engineering-agent-only scope in public positioning; -- implying hosted control plane dependency; -- using "trust," "secure," "policy," or "approval" without exact mechanism; -- showing a review UI that is not bound to the exact action contract; -- letting support output imply downstream business success; -- hiding preview limitations behind friendly onboarding copy. - -## Brutal Verdict - -Keep public distribution narrow. The package should make Handshake feel easy to try, but hard to misunderstand. Public DevEx wins only if users can install, inspect, propose, and verify readiness while clearly seeing that real protection begins at the gateway check. - -Smallest next mechanism to build: a single `doctor`/readiness contract that reports `proposal-mode` versus `gateway-mode` and drives the README, CLI, MCP smoke, and support bundle from the same status vocabulary. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/ARCH.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/ARCH.md deleted file mode 100644 index 001d477..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/ARCH.md +++ /dev/null @@ -1,201 +0,0 @@ -# ARCH: Public Distribution And Publication - -## Invariant At Stake - -Publication must never be confused with authority. - -Public Distribution And Publication is a distribution/read surface for proposal, evidence, metadata, and installability. It must not create policy, greenlights, gateway checks, mutation rights, custody, hosted operation, marketplace certification, or broad enforcement claims. If publication can be interpreted as "installed equals authorized," the architecture has already failed. - -## Architecture Guidance - -### Package Release Proof Object - -Define a durable `PackageReleaseProof` as a receipt bundle, not a trust badge. - -```ts -type PackageReleaseProof = { - proofId: string; - releaseId: string; - packageName: string; - version: string; - packageManager: "npm"; - createdAt: string; - - packageShapeProof: PackageShapeProof; - accountNamespaceProof: AccountNamespaceProof; - publishOperationProof: PublishOperationProof; - provenanceProof: ProvenanceProof; - registryDiscoverabilityProof: RegistryDiscoverabilityProof; - runtimeSmokeProof: RuntimeSmokeProof; - - releaseManifestDigest: string; - postPublishVerificationDigest?: string; - - authorityBoundary: { - createsPolicy: false; - createsGreenlight: false; - createsGatewayCheck: false; - performsMutation: false; - holdsCustody: false; - certifiesThirdParty: false; - }; - - proofGaps: ProofGap[]; -}; -``` - -This object proves only that a package was shaped, published, discoverable, and smoke-tested under declared constraints. It does not prove that any downstream protected action is authorized or safe. - -### Split Proofs - -Do not collapse release evidence into one "published successfully" flag. That is evidence theatre. - -Use separate proofs: - -- `PackageShapeProof`: npm dry-run pack JSON, files included, exports, bins, package name, version, `mcpName`, `server.json`, license/readme presence, no undeclared source leakage. -- `AccountNamespaceProof`: npm org/user ownership, MCP namespace authorization, `mcpName` matching registry server name, explicit account/2FA/token posture. -- `PublishOperationProof`: exact package/version attempted, actor, CI run, command class, environment, dry-run predecessor, publish result, package digest. -- `ProvenanceProof`: OIDC/trusted publishing status, provenance bundle URL/digest, CI provider identity, source commit, build workflow identity. -- `RegistryDiscoverabilityProof`: MCP Registry preview metadata accepted, `server.json` present, public install method valid, namespace/auth checks passed, metadata not artifact-hosting. -- `RuntimeSmokeProof`: installed-from-packed or installed-from-registry package executes CLI/MCP in non-authority mode only. - -Each proof must carry `verifiedAt`, `source`, `digest`, `result`, and `proofGaps`. - -### Release Manifest - -Create a release manifest that is generated before publish and immutable after publish. - -It should bind: - -- source commit; -- package name/version; -- npm package shape; -- packed tarball digest; -- export map; -- bin map; -- MCP server metadata; -- `server.json` digest; -- expected public install command; -- expected non-authority smoke commands; -- intended registry namespace/name; -- explicit authority boundary. - -The manifest is not a greenlight. It is the expected release contract for publication evidence. - -### Post-Publish Verification Receipts - -After publish, create a separate receipt comparing public reality against the release manifest. - -It should verify: - -- npm package exists at exact version; -- installed package digest or contents match expected release shape; -- CLI bins resolve and run non-authority commands; -- SDK exports expose only allowed public APIs; -- MCP metadata resolves and advertises only proposal/evidence/read tools; -- registry metadata points to npm install method; -- provenance is present or a proof gap is recorded; -- deprecation status is correct; -- no hidden publish-time files appeared. - -If the manifest and public package diverge, record a proof gap or quarantine release status. Do not silently "fix docs." - -### CLI / MCP / SDK Boundaries - -Public package surfaces must be boring and non-authoritative. - -Allowed: - -- inspect release metadata; -- validate local config; -- render proposal/evidence/read surfaces; -- emit candidate action contracts; -- verify receipts; -- run smoke checks; -- explain authority boundaries. - -Forbidden unless gateway-bound: - -- mutate protected surfaces; -- create greenlights; -- evaluate policy as final authority; -- perform gateway checks; -- hold secrets for downstream mutation; -- execute protected actions directly; -- imply certification or marketplace approval. - -CLI bins should have names that do not imply hosted authority. MCP tools must be classified as `read`, `validate`, `propose`, or `receipt`. If a tool can mutate, it does not belong in this publication package unless it is a gateway adapter with exact greenlight verification. - -### Metadata Validation - -Metadata validation should be treated as release blocking. - -Validate: - -- `package.json` `name`, `version`, `files`, `exports`, `bin`; -- `mcpName` presence and match to MCP Registry server name; -- `server.json` schema and install method; -- npm pack dry-run JSON against allowlist; -- registry namespace ownership; -- public install command; -- README claims against authority boundary; -- no package metadata says or implies "approval," "enforcement," "certified," or "trusted" unless the mechanism exists. - -Metadata is not marketing. Metadata is an install-time contract surface. - -### Provenance And Secret Posture - -Preferred path: trusted publishing with OIDC and provenance. - -Architecture posture: - -- publish from CI, not a local machine; -- no long-lived npm token when trusted publishing is available; -- if token publishing is used, record token class, 2FA posture, expiry, storage boundary, and rotation plan; -- provenance absence is a proof gap, not a warning buried in logs; -- package digest must bind to source commit and release manifest; -- CI identity must be explicit. - -A package published with an opaque token and no provenance can still be distributed, but it cannot carry strong release proof. - -### Rollback, Deprecation, Versioning - -Do not design rollback as "delete the bad version." npm publication is append-heavy in practice and unpublish has constraints. - -Use: - -- immutable version receipts; -- deprecation receipts for bad versions; -- replacement version receipts; -- registry metadata update receipts; -- release status: `active`, `deprecated`, `quarantined`, `superseded`; -- semver policy separating public API changes from metadata-only corrections; -- documented refusal to reuse versions. - -A rollback is a new evidence event. It does not erase the bad release. - -### Import / Export Guard Architecture - -Guard the package boundary like an authority boundary. - -Use checks that install or inspect the packed artifact, not just source paths. - -Guard against: - -- exporting internal policy/gateway modules; -- exporting mutation-capable adapters by accident; -- bins reaching private source paths; -- wildcard exports; -- package files including `.planning`, internal reports, secrets, fixtures with credentials, or unpublished authority code; -- MCP tools exposing hidden mutation handlers; -- SDK import paths bypassing intended public APIs. - -The test posture should be: "Can an external consumer import or invoke anything that sounds like authority?" If yes, block release. - -## Brutal Verdict - -Keep the publication macro item, but narrow it hard. - -This is not the "public Handshake platform." It is release evidence for public package distribution and registry discoverability. The first wedge is x402 exact per-call because it gives a clean proof surface, not because x402 is the protocol center. The product remains protected actions for automated decision making. - -Smallest next mechanism to build: a release manifest plus post-publish verification receipt that proves package shape, metadata, provenance posture, registry discoverability, and non-authority runtime behavior for one exact package version. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/EXECUTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/EXECUTION.md deleted file mode 100644 index c1e7a47..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/EXECUTION.md +++ /dev/null @@ -1,303 +0,0 @@ -# EXECUTION: Public Distribution And Publication - -## Invariant At Stake - -Publication must distribute proposal/evidence/read surfaces only. It must not imply gateway enforcement, execution authority, or protected mutation control until those paths are actually enforced. - -# Execution Plan: Public Distribution And Publication - -## Phase 0: Local Source Readiness - -Tasks: - -1. Confirm package surface is intentional: - ```bash - npm run build - node scripts/check-package-surface.mjs - node scripts/check-published-entrypoints.mjs - ``` - -2. Confirm repo quality gates: - ```bash - npm run format:check - npm run check:repo - ``` - -3. Confirm package metadata: - - `package.json` has correct `name`, `version`, `description`, `license`, `repository`, `bin`, `files`, `exports`. - - `bin` wrappers point only at built distributable files. - - `dist/` contains every exported runtime entrypoint. - - README package install docs match the actual package name and command shape. - - No `.planning/` paths leak into repo-facing package docs or package metadata. - -Dry-run gate: - -```bash -npm pack --dry-run --json -``` - -Stop conditions: - -- Unexpected files in packed tarball. -- Missing `dist` bundle or bin wrapper. -- Package docs claim enforcement, authority, gateway checks, or mutation protection beyond the implemented package. -- Any check script fails. - -## Phase 1: NPM Publication Preflight - -Tasks: - -1. Confirm npm identity and registry: - ```bash - npm whoami - npm config get registry - npm view version - ``` - -2. Confirm version uniqueness: - ```bash - npm view @ version - ``` - - Expected: not found for a new version. - -3. Confirm 2FA/token posture: - - Prefer npm trusted publishing with provenance from CI. - - If using local publish, verify account 2FA is enabled and token scope is minimal. - - Do not use broad long-lived automation tokens unless there is no CI alternative. - -4. Run publish dry-run: - ```bash - npm publish --dry-run --access public - ``` - -CI/release gate: - -- Release must run from a clean git tag matching `package.json` version. -- CI must run build, package-surface checks, published-entrypoint checks, format, and repo check before publish. -- Trusted publishing/provenance should be required for the real publish job: - ```bash - npm publish --access public --provenance - ``` - -Stop conditions: - -- `npm whoami` is wrong. -- Registry is not `https://registry.npmjs.org/`. -- Version already exists. -- Provenance/trusted publishing is unavailable but release policy requires it. -- Dry-run tarball differs from expected package surface. - -Rollback posture: - -- npm versions are effectively immutable. -- If a bad version publishes, immediately deprecate it: - ```bash - npm deprecate @ "Do not use: publication error. Upgrade to ." - ``` -- Publish a corrected patch version. Do not attempt to pretend the bad artifact never existed. - -## Phase 2: NPM Publish - -Tasks: - -1. Create and push release tag only after all local gates pass: - ```bash - git status --short - git tag v - git push origin v - ``` - -2. Publish through CI trusted publishing, or locally only if explicitly accepted: - ```bash - npm publish --access public --provenance - ``` - -3. Capture evidence: - ```bash - npm view @ --json - npm view @ dist.integrity - npm view @ dist.tarball - ``` - -Stop conditions: - -- Dirty worktree before tag. -- CI quality gates fail. -- Publish succeeds but package metadata does not match intended version, tarball, or entrypoints. - -## Phase 3: Post-NPM Smoke Tests - -Tasks: - -1. Install from npm in a clean temp project: - ```bash - mkdir -p /tmp/handshake-npm-smoke - cd /tmp/handshake-npm-smoke - npm init -y - npm install @ - ``` - -2. Verify package import surface: - ```bash - node -e "import('').then(m => console.log(Object.keys(m).sort()))" - ``` - -3. Verify bin wrapper: - ```bash - npx --help - ``` - -4. Verify published entrypoint assumptions: - ```bash - node -e "import('/').then(() => console.log('ok'))" - ``` - -Stop conditions: - -- Installed package cannot import. -- Bin wrapper fails. -- Public entrypoints differ from README or check scripts. -- Help/docs imply authority enforcement where only read/proposal/evidence publication exists. - -## Phase 4: MCP Registry Preflight - -Tasks: - -1. Validate `server.json` shape: - - `mcpName` is stable and namespace-qualified. - - Package reference points to the published npm package and exact version range policy. - - Public install/preview commands match the npm package. - - Description is distribution-scoped, not enforcement-scoped. - - Registry metadata does not claim gateway authority unless the package actually performs gateway checks. - -2. Validate with the official MCP Registry publisher/validator once pinned: - ```bash - mcp-publisher validate server.json - ``` - -3. Preview rendered registry listing if supported: - ```bash - mcp-publisher preview server.json - ``` - -Stop conditions: - -- `server.json` package reference does not match the npm-published package. -- `mcpName`/namespace conflicts or is not owned. -- Public install command fails in a clean environment. -- Registry listing claims Handshake provides enforcement authority through publication alone. - -## Phase 5: MCP Registry Publish - -Tasks: - -1. Authenticate with the registry using the intended namespace owner. -2. Publish the validated `server.json`: - ```bash - mcp-publisher publish server.json - ``` - -3. Capture registry publish evidence: - ```bash - curl -s - ``` - -Stop conditions: - -- Namespace ownership is not verified. -- Registry publish points at unpublished or wrong npm version. -- Registry generated install command does not work. -- Registry listing cannot be reconstructed from `server.json`. - -Rollback posture: - -- If registry metadata is wrong, publish a corrected registry update if the registry supports replacement. -- If package artifact is wrong, deprecate npm version and update registry to point at the corrected patch. -- If namespace is wrong, halt. Do not create a second public identity without an explicit naming decision. - -## Phase 6: Post-Registry Smoke Tests - -Tasks: - -1. Search registry by name: - ```bash - curl -s "?q=" - ``` - -2. Fetch registry server record: - ```bash - curl -s "/" - ``` - -3. Install exactly as public users would: - ```bash - - ``` - -4. Verify MCP server startup/read surfaces: - ```bash - --help - ``` - -5. Confirm registry metadata agrees with npm: - - package name - - version/range - - bin command - - README link - - source repo - - license - - description - -Stop conditions: - -- Registry search cannot find the server after propagation window. -- Registry API returns stale or mismatched metadata. -- Public install command fails. -- MCP startup path differs from package docs. - -## Docs And Claim Guards Needed Later - -Likely updates when implementing: - -- README: add install, CLI/bin, MCP install, and smoke-test examples. -- `docs/internal/decisions.md`: record that publication distributes proposal/evidence/read surfaces, not authority. -- `docs/internal/protocol-notes.md`: clarify published package boundary versus gateway enforcement boundary. -- Claim guard: reject README/docs language that says publication "enforces," "authorizes," "secures mutations," or "approves actions" unless tied to implemented gateway checks. -- Package guard: ensure `.planning/`, internal-only reports, local scratch files, and unpublished source paths cannot enter npm tarball. -- Entry-point guard: ensure README-documented imports and bin commands are present in built `dist`. - -## Task Dependency Graph - -```mermaid -graph TD - A["Local build"] --> B["Package surface checks"] - B --> C["Published entrypoint checks"] - C --> D["Repo quality gates"] - D --> E["npm pack dry-run"] - E --> F["npm publish dry-run"] - F --> G["CI trusted publishing gate"] - G --> H["npm publish"] - H --> I["npm install smoke test"] - I --> J["MCP server.json validation"] - J --> K["MCP Registry preview"] - K --> L["MCP Registry publish"] - L --> M["Registry API/search verification"] - M --> N["Public install smoke test"] - N --> O["Closeout evidence recorded"] -``` - -## Closeout Commands - -```bash -npm view @ --json -npm install @ -npx --help -curl -s "?q=" -curl -s "/" -npm run check:repo -``` - -Brutal verdict: keep the publication plan narrow. npm and MCP Registry make Handshake installable and inspectable; they do not create authority. Any copy, registry metadata, or release note that implies gateway enforcement from publication alone is advisory theatre. - -Smallest next mechanism to build: a single release preflight script that runs build, package-surface checks, published-entrypoint checks, `npm pack --dry-run --json`, and fails on forbidden authority claims in package-facing docs. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/RISK.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/RISK.md deleted file mode 100644 index 744ea7b..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/RISK.md +++ /dev/null @@ -1,30 +0,0 @@ -# RISK: Public Distribution And Publication - -## Invariant At Stake - -Publishing must not convert proposal, evidence, or read surfaces into implied authority. Public distribution is only acceptable if the package cannot leak protected internals, cannot mutate protected surfaces, cannot imply gateway enforcement where none exists, and can be reconstructed after publication. - -| Risk | Failure Mode | Mitigation | Validation Evidence | Stop Condition | -|---|---|---|---|---| -| Package leaks planning, test, secret, or internal source | npm tarball includes `.planning/`, fixtures with raw receipts, test credentials, internal docs, local env files, or unpublished gateway/signer code. | Use explicit `files` allowlist. Add tarball inspection gate. Block `.planning/`, `test`, `fixtures`, `.env*`, internal docs, raw receipt samples, credential references, and private adapters unless intentionally public. | `npm pack --dry-run` artifact list reviewed and committed as release evidence. Automated denylist check passes against packed tarball, not repo tree. | Any unreviewed internal, planning, credential, raw record, or protected adapter file appears in package contents. | -| Dist/source mismatch | Published `dist` does not match reviewed source; stale build ships hidden behavior, broken APIs, or authority internals removed from source. | Clean build before pack. Verify source-to-dist mapping. Require generated declaration files and JS output to be regenerated from current commit. | Build hash, `git diff --exit-code` after build, packed `dist` file inventory, and smoke import from packed tarball. | Build creates uncommitted drift, packed `dist` differs from current source expectations, or source maps reveal private paths. | -| Public exports overexpose authority internals | `exports` exposes signer primitives, gateway acceptance internals, raw receipt stores, credential resolution internals, or mutation helpers. Downstream users can treat internals as supported authority APIs. | Export only proposal, evidence, read, and metadata surfaces. Keep signer/gateway/credential/raw-record modules private. Add export-boundary tests. | `package.json exports` audit. Type-level import tests prove internal paths are unavailable. Runtime import attempts fail for private modules. | Any public import path exposes greenlight minting, signer material, gateway verification internals, raw receipt mutation, credential access, or receipt-export authority. | -| Bins imply mutation or enforcement | CLI names or help text imply it can approve, enforce, mutate, publish receipts authoritatively, or operate as a gateway when it only reads/proposes/validates metadata. | Rename or scope bins to read/proposal/evidence operations. CLI help must state it does not grant authority or execute protected mutations. Remove mutation-like commands. | `--help` snapshots. CLI command inventory. Smoke test proving no command mutates protected surfaces or emits greenlight-like authority. | Any bin verb such as `approve`, `greenlight`, `enforce`, `execute`, `gateway`, `export-receipt`, or equivalent exists without real gateway-bound enforcement. | -| MCP Registry listing overclaims trust/certification | Registry metadata makes users believe listing certifies code safety, authority correctness, or official enforcement. This is review theatre. | Metadata must say MCP Registry hosts metadata, not artifacts, and does not certify safety. Claims limited to package identity, capabilities, and install path. | Registry preview text reviewed against claim checklist. No "certified," "trusted," "secure," "approved," or "enforced" claims unless mechanically true. | Listing implies registry approval, safety certification, authority enforcement, or audited gateway behavior. | -| npm token, 2FA, or provenance failures | Publish uses weak token, missing 2FA, no provenance, wrong account, or local machine credentials that cannot be audited. | Use npm automation token with least privilege, account 2FA enforced, provenance enabled where supported, and publish from controlled CI if possible. | npm account/package settings screenshot or command output. Provenance visible on published package. Token scope documented. | 2FA disabled, provenance absent without explicit exception, broad personal token used, or publish path cannot be reconstructed. | -| Namespace/account ownership gaps | Package name or scope is controlled by the wrong account, individual owner, stale org, or ambiguous namespace. Attackers or future maintainers can publish lookalikes or take over ownership. | Publish under owned org scope. Require at least two maintainers with explicit ownership. Reserve related names if necessary. Document owner transfer process. | npm owner list, org scope verification, package access settings, MCP Registry namespace ownership proof. | Scope ownership is unclear, single-person account is sole owner, or package name can be confused with an unowned sibling. | -| Version/metadata drift | npm package, Git tag, MCP metadata, README, and registry preview describe different capabilities. Users install one thing and read another. | Version from one source of truth. Release checklist updates package metadata, README, registry metadata, changelog, and tag together. | Git tag matches package version. Packed README matches repository README or intentional release README. MCP metadata references same version/package. | Any published metadata claims capabilities not present in the packed package, or package version cannot be tied to a commit. | -| Post-publish package does not run under Node | Package imports fail due to ESM/CJS mismatch, missing files, wrong `types`, unsupported Node version, bad bin shebangs, or absent runtime dependencies. | Test from packed tarball in a clean temp project under supported Node versions. Verify import, require if supported, bin execution, and type resolution. | Clean install smoke logs from packed tarball. Node version matrix. `npm pack` install test, CLI help test, TypeScript compile test. | Any supported Node runtime cannot import the package, execute bins, or resolve types from the packed artifact. | -| Downstream install executes unexpected scripts or dependencies | Install triggers lifecycle scripts, dependency postinstall behavior, native builds, network calls, telemetry, or dependency confusion. | Avoid lifecycle scripts. Minimize dependencies. Pin/lock release dependencies. Audit transitive scripts. Prefer zero-dependency public core if feasible. | `npm pack` manifest inspection. Dependency tree review. `npm install --ignore-scripts` and normal install comparison. Script inventory is empty or justified. | Any install-time script, native build, network behavior, telemetry, or unexplained transitive dependency appears. | -| Rollback/deprecation gaps | Bad package ships and there is no tested unpublish/deprecate path, no advisory language, no replacement version, and no way to warn downstream users. | Predefine rollback playbook: deprecate version, publish patched version, update registry metadata, tag incident note, and revoke affected tokens if needed. | Dry-run rollback checklist. npm deprecation command prepared. Owner permissions verified. Incident template exists. | Maintainers cannot deprecate, cannot publish a patched version, or cannot update registry metadata promptly. | -| External registry preview instability | MCP Registry preview behavior changes, metadata rendering drifts, validation accepts unsafe claims, or listing breaks after external changes. | Treat registry preview as unstable external display, not canonical truth. Keep canonical package metadata and docs in repo. Re-validate preview before publication and after changes. | Preview screenshot or exported metadata captured at release time. Post-publish registry check. Drift issue filed if rendered claims differ. | Registry preview renders misleading capability, trust, install, or certification claims, or cannot be verified before publication. | - -## Brutal Verdict - -Keep the publication plan only if publication is treated as distribution of non-authority surfaces. Cut any CLI, MCP metadata, export, README phrase, or package file that lets a downstream user infer mutation authority, receipt export authority, gateway enforcement, signer access, or certification. - -The highest-risk failure is not a broken install. It is a package that looks like Handshake authority while only shipping advisory surfaces. That would publish the theatre as product. - -## Smallest Next Mechanism To Build - -Add a release gate that inspects the packed tarball, public exports, bin help text, and registry metadata preview, then fails on authority leakage, mutation implication, internal file exposure, provenance gaps, or metadata overclaim. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/STRATEGY.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/STRATEGY.md deleted file mode 100644 index acdcf5a..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/raw/STRATEGY.md +++ /dev/null @@ -1,177 +0,0 @@ -# STRATEGY: Public Distribution And Publication - -## Invariant At Stake - -Public distribution must not launder installability into authority. A published package, MCP listing, CLI, SDK, or metadata file can make Handshake easier to inspect and install. It cannot prove enforcement, gateway custody, hosted operation, certification, marketplace trust, settlement, or host-wide control. - -## Strategic Posture - -This macro item succeeds only if publication makes the protocol kernel legible, installable, inspectable, and verifiable without overstating what has been enforced. - -Handshake should be presented as: - -> protected actions for automated decision making, with exact per-call x402 as the first proof wedge. - -Not: - -> agent auth, a payment network, a hosted enforcement layer, an MCP trust system, or a certification authority. - -x402 is the proof wedge because it gives a concrete, high-signal surface: exact per-call consequence, declared contract, explicit evidence, and verifiable refusal/proof-gap posture. It is not the protocol center. - -## Ready-To-Publish vs Actually Published - -**Ready-to-publish** means the repo can prove the package shape locally: - -- `handshake-protocol-kernel` has correct `name`, `version`, `exports`, `bin`, `files`, `server.json`, and `mcpName`. -- `npm pack --dry-run` contents match the intended public surface. -- Published entrypoints resolve from the packed artifact, not just local source. -- CLI/MCP/SDK entrypoints work from the package artifact. -- `server.json#name` and `package.json#mcpName` match MCP Registry requirements. -- README and public docs describe distribution as distribution, not enforcement. -- Security posture is documented: trusted publishing/OIDC preferred, npm 2FA/token posture explicit. -- No planning scratch, internal labels, stale claims, or non-public dependency assumptions leak into the package. - -**Actually published** means external systems now carry the public surface: - -- npm package version is published and installable by name. -- Fresh install from npm works in a clean environment. -- CLI bin executes from installed package. -- SDK/package exports resolve from installed package. -- MCP server metadata is accepted by the preview registry using public install methods. -- Post-publish evidence confirms npm contents and registry metadata match source-owned metadata. -- Docs distinguish "listed/installable" from "trusted/enforced/certified." - -Ready-to-publish is a local evidence state. Actually published is an external distribution state. Do not collapse them. - -## Sequencing - -1. **Local Package Contract** - Freeze the intended public package shape: `package.json`, `exports`, `bin`, `files`, `server.json`, `mcpName`, README install commands, and public claim language. - -2. **Pack Evidence** - Run pack dry-run and artifact-level entrypoint checks. The question is not "does the repo build?" The question is "does the artifact contain only the intended public surface and still work when consumed externally?" - -3. **Security Posture** - Decide and document publish auth: trusted publishing/OIDC preferred; if not available, npm 2FA/token posture must be explicit. Long-lived token publishing should be treated as a risk exception, not normal posture. - -4. **npm Publish** - Publish `handshake-protocol-kernel` by exact version. npm is the artifact distribution authority for package installability, not a Handshake authority boundary. - -5. **Clean Install Verification** - Verify install by package name from npm. Check imports, bins, package metadata, and any published entrypoint behavior from a clean project. - -6. **MCP Registry Submission** - Submit metadata only after npm install works. MCP Registry hosts metadata, not package artifacts. Its preview status and namespace checks do not certify code or enforcement. - -7. **Post-Publish Evidence** - Capture the public install commands, resolved version, npm package contents, registry metadata, and known limitations. This becomes the publication receipt. - -## Product Claim Boundaries - -Allowed claims: - -- Public protocol kernel package. -- Installable CLI/MCP/SDK distribution surface. -- Source-owned metadata for npm and MCP Registry. -- Exact per-call x402 proof wedge. -- Public read surfaces for proposal, evidence, and protocol inspection. -- Metadata and artifact checks that make the package reconstructable. - -Forbidden or unsafe claims: - -- "Handshake enforces protected actions" unless a gateway check actually enforces. -- "MCP Registry trust" or "certified server." -- "Marketplace trust." -- "Hosted Handshake." -- "Payment management." -- "Settlement." -- "Host-wide enforcement." -- "Secure by MCP listing." -- "Agent auth." -- "Approval system." -- "Auditable" unless the published artifact includes enough source-owned evidence to reconstruct the chain being claimed. - -## 10-Star Publication Surface - -A 10-star publication surface is boring, exact, and hard to misread: - -- One npm package with clear package name, version, exports, bins, and files. -- One `server.json` whose identity matches `package.json#mcpName`. -- README install path that starts from npm install by name. -- Public examples that exercise exact protected-action proposal/evidence/read surfaces. -- CLI help text that does not imply gateway custody. -- SDK exports that expose kernel primitives, not hosted authority. -- MCP metadata that points to public install methods only. -- Security section covering trusted publishing/OIDC, npm 2FA, token posture, and registry-preview limitations. -- Post-publish verification notes showing clean install and entrypoint checks. -- Claim boundary section saying explicitly what publication does not provide. - -The public surface should make the narrow wedge look inevitable because it is precise, not because it sounds broad. - -## What To Cut - -Cut anything that implies authority where there is only distribution: - -- Hosted enforcement language. -- "Trust," "secure," or "certified" phrasing tied to npm or MCP Registry. -- Marketplace positioning. -- Payment network or settlement language. -- Claims that CLI/MCP/SDK publication means gateway enforcement. -- Internal planning-stage names in public package shape. -- Scratch `.planning/` references. -- Demo copy that makes x402 sound like the whole protocol. -- Any registry language that treats metadata validation as code validation. -- Any "agent infrastructure" framing that narrows the category back to engineering agents only. - -## Success Criteria - -The macro item is complete when: - -- Local package artifact is inspectable and matches intended public files. -- npm published version is installable by package name. -- Published exports and bins work from clean install. -- MCP Registry metadata is accepted or, if blocked by preview constraints, the blocker is recorded as an external distribution proof gap. -- Public docs state exact claim boundaries. -- x402 is presented as first proof wedge, not protocol center. -- Post-publish evidence records artifact, metadata, install, entrypoint, and limitation checks. -- No public surface claims gateway enforcement, hosted custody, certification, marketplace trust, settlement, or host-wide authority unless that mechanism actually exists. - -## End Criteria - -End the macro when there is a publication receipt with: - -- package name and version; -- npm install verification; -- pack contents verification; -- published entrypoint verification; -- MCP Registry submission or proof-gap status; -- public docs claim-boundary check; -- security posture note; -- list of intentionally unsupported claims. - -If any one of those is missing, the item is not done. It may be ready-to-publish, partially published, or blocked, but not complete. - -## Antipatterns - -- Treating `npm publish` as product validation. -- Treating MCP Registry acceptance as trust. -- Publishing before clean artifact checks. -- Publishing metadata that points to non-public install methods. -- Letting README language outrun the package's actual authority boundary. -- Using x402 as brand center instead of proof wedge. -- Calling CLI/MCP/SDK publication "enforcement." -- Hiding npm token or 2FA posture as operational detail. -- Shipping broad category language without a narrow reconstructable proof surface. -- Letting package exports expose unstable internals because "it is just distribution." - -## Brutal Verdict - -Keep the macro item, but narrow it hard. - -This is not "launch Handshake." -This is not "stand up enforcement." -This is not "become trusted infrastructure." - -This is publication of the protocol kernel's proposal/evidence/read surface, with x402 exact per-call as the first proof wedge, through npm artifact distribution and MCP metadata distribution. - -Smallest next mechanism to build: a publication receipt checklist that separates `ready_to_publish`, `npm_published`, `mcp_registry_listed`, and `post_publish_verified`, with explicit proof gaps for anything not externally verified. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/synthesis.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/synthesis.md deleted file mode 100644 index 3162f2a..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/public-distribution-publication/runs/public-distribution-publication-20260524T090500Z/synthesis.md +++ /dev/null @@ -1,122 +0,0 @@ -# Synthesis: Public Distribution And Publication - -## Invariant At Stake - -Publication must not become ambient authority wearing package metadata. - -Handshake is protected actions for automated decision making. Public distribution can make the protocol kernel installable and discoverable, but it cannot authorize protected actions. It cannot create a policy decision, greenlight, gateway check, mutation, custody path, hosted operation, settlement path, payment manager, trust root, certification mark, or host-wide enforcement boundary. - -## Chair Synthesis - -The perspectives converge on one severe release model: - -1. Prove local package shape before publication. -2. Prove credential, namespace, and provenance posture before mutation of public package state. -3. Publish npm artifact only from an exact manifest. -4. Verify clean install from public npm before any registry discoverability work. -5. Submit MCP Registry metadata only after npm artifact proof exists. -6. Verify registry discoverability as metadata only. -7. Record every gap instead of smoothing it into release success. - -The strategic correction is important: x402 exact per-call is the first proof wedge, not the center. The center is protected action control for automated decision making: exact contract, one-use greenlight, gateway check, receipt/refusal/proof-gap, isolation, and bypass posture. - -## Adopted Model - -Use three separate release states: - -- `ready_to_publish` -- `actually_published` -- `registry_discoverable` - -A local pack dry-run can support `ready_to_publish`. It cannot support `actually_published`. - -An npm publish operation can support `actually_published` only after clean install smoke passes. - -An MCP Registry submission can support `registry_discoverable` only after post-registry verification passes. It cannot support trust, certification, artifact safety, or enforcement. - -## Required Proof Shape - -The release proof should be structured as `PackageReleaseProof`: - -- `packageShapeProof` -- `accountNamespaceProof` -- `publishOperationProof` -- `provenanceProof` -- `registryDiscoverabilityProof` -- `runtimeSmokeProof` -- `authorityBoundary` -- `proofGaps` - -The `authorityBoundary` must make false claims explicit: - -- `createsAuthority: false` -- `createsPolicyDecision: false` -- `createsGreenlight: false` -- `performsGatewayCheck: false` -- `performsMutation: false` -- `holdsCustody: false` -- `hostsOperation: false` -- `certifiesMarketplace: false` -- `managesSettlement: false` -- `managesPayment: false` -- `establishesTrust: false` -- `enforcesHostWidePolicy: false` - -## Release Sequence - -1. Local readiness contract -2. npm preflight -3. npm publish -4. post-npm clean install smoke -5. MCP Registry preflight -6. MCP Registry metadata submission -7. post-registry discoverability smoke - -This sequence prevents a common failure: making a package discoverable before the artifact and its public claims have survived installation from the public registry. - -## Risk Synthesis - -The largest risks are not mechanical publication failures. The largest risks are semantic boundary failures: - -- package metadata implies authority -- docs narrow Handshake to engineering agents -- x402 becomes the protocol center -- MCP Registry listing is treated as trust -- provenance is confused with runtime enforcement -- clean install is skipped -- a release receipt conflates local checks, npm publish, registry metadata, and runtime smoke - -Those are not wording nits. They are product-boundary failures. - -## Adoption Synthesis - -The first public install/test-drive should prove: - -- package can be installed -- bins can start -- exports resolve -- proposal/evidence/read surfaces are available -- non-authority boundaries are visible -- proof gaps are explicit - -It should not require a team to integrate every protected-action gateway up front. - -Allowed support statuses: - -- `ready:proposal-mode` -- `ready:gateway-mode` -- `blocked:metadata` -- `blocked:runtime` -- `blocked:mcp-stdio` -- `blocked:package-contents` -- `blocked:namespace-auth` -- `blocked:provenance` -- `preview:unsupported-enforcement` - -## Brutal Verdict - -Keep the publication plan, but narrow its claims. - -Public distribution is useful only if it makes Handshake installable, inspectable, and reconstructable without pretending to enforce anything by existing in npm or MCP Registry. Any implementation that treats publication as trust, authority, certification, or gateway enforcement is advisory theatre, not Handshake. - -Smallest next mechanism: define the `PackageReleaseProof` and release-state contract with explicit authority-boundary false fields before any publish operation. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/ASSUMPTIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/ASSUMPTIONS.md deleted file mode 100644 index 366e3da..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/ASSUMPTIONS.md +++ /dev/null @@ -1,35 +0,0 @@ -# Assumptions: Terminal Verifier Trust Plane - -## Product Assumptions - -- The externally useful question is evidence portability for protected automated actions, not payment settlement or generalized identity. -- x402 is the first wedge because exact per-call paid HTTP is concrete and auditable. -- Engineering-agent workflows remain an adoption/stress context, not the product boundary. - -## Architecture Assumptions - -- Existing certificate verification can be extended with a read model instead of replaced. -- `AuthorityCertificate` remains terminal evidence and should not acquire permission semantics. -- Issuer/key/status data can begin as local deterministic protocol records before durable service storage exists. -- A native verifier key-set model is required before JWKS projection. -- Hosted verifier responses can be redacted through an explicit allowlist. - -## Security Assumptions - -- Unknown issuer, unknown key, unauthorized role, revoked key, stale key, malformed key material, algorithm mismatch, and status unavailable must fail closed. -- Status unavailable is a `proof_gap`, not a reason to treat old evidence as verified. -- Hosted verification must not fetch arbitrary remote trust material. -- Public key discovery does not prove trust. - -## Execution Assumptions - -- Candidate implementation paths stay near authority-certificate protocol, CLI certificate handling, HTTP routes, and existing tests. -- Existing quality gates remain authoritative. -- The plan should not introduce source paths, package names, or CI labels from `.planning/` scratch terms. -- If exact test commands differ, implementers should use repo-native focused equivalents and record the substitution. - -## User-Owned Open Questions - -- Which hosted route naming convention should become canonical? -- Should initial status records live entirely in protocol fixtures/local config, or behind an HTTP-backed read provider? -- Which x402 receiver/auditor integration should be the first external proof target? diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/CONTEXT.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/CONTEXT.md deleted file mode 100644 index 1a60bbd..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/CONTEXT.md +++ /dev/null @@ -1,63 +0,0 @@ -# Context: Terminal Verifier Trust Plane - -## Invariant At Stake - -`AuthorityCertificate` is terminal evidence. It is not permission, identity, settlement, approval, actor trust, certification, compliance, or downstream business success. - -## Product Frame - -Handshake is protected actions for automated decision making. Engineering-agent workflows are stress and adoption context, not the product boundary. - -The first wedge is x402 exact per-call paid HTTP because it creates a crisp protected-action evidence question: did this exact per-call action produce terminal evidence that can be verified without trusting the caller's narrative? - -## Current Source State - -- Certificate minting is limited to terminal evidence kinds: `receipt`, `durable_refusal`, `proof_gap`, `replay_refusal`. -- Verification already checks schema, digests, signed-over binding, algorithm prefix, pinned trust keys, signer roles, artifact kinds, gateway admission binding, and terminal binding. -- Production rejects HMAC. -- Trust material is local/pinned with active/retired keys. -- CLI verification is non-mutating and evidence-plane only. - -## Missing Trust Plane - -The current verifier has enough local mechanics to become portable, but lacks: - -- issuer read model; -- key version read model; -- role/status/time-window model; -- status/revocation records; -- native verifier key-set projection; -- JWKS projection; -- hosted verifier; -- redacted verification response; -- explicit status unavailable and revoked failure model; -- claim guard around validity semantics. - -## Plane Separation - -Evidence plane: - -- `AuthorityCertificate`; -- terminal artifact kind; -- signed-over binding; -- gateway admission binding; -- terminal binding; -- receipt/refusal/proof-gap/replay evidence. - -Discovery plane: - -- metadata; -- native verifier key-set; -- JWKS projection; -- status endpoint address; -- hosted verifier endpoint address. - -Trust decision plane: - -- pinned issuer/key acceptance; -- signer role acceptance; -- key version status; -- revocation/status record interpretation; -- caller-owned decision about whether a verifier is trusted. - -JWKS sits in discovery. It does not create trust. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/DECISIONS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/DECISIONS.md deleted file mode 100644 index 1e5ddc9..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/DECISIONS.md +++ /dev/null @@ -1,29 +0,0 @@ -# Decisions: Terminal Verifier Trust Plane - -## D1: AuthorityCertificate Semantics Stay Narrow - -`AuthorityCertificate` proves terminal evidence binding only. It does not prove approval, authorization, payment, settlement, trust, certification, compliance, or success. - -## D2: Verification Result Must Be Structured - -No boolean-only `isValid()` surface. Verification result must separate crypto validity, trusted signer, key status, role status, artifact match, gateway binding, terminal binding, status/revocation, and audit projection. - -## D3: Native Verifier Key Set Precedes JWKS - -The protocol-owned verifier key set is the authority-bearing read model. JWKS is an interoperability projection of public key material only. - -## D4: Discovery Is Not Trust - -Metadata and `jwks_uri` help locate public key material. They do not establish issuer trust, role authorization, status acceptance, or certificate validity. - -## D5: Hosted Verifier Is Non-Mutating - -Hosted verification may parse, validate, redact, and report. It must not mutate certificate state, status records, receipt stores, gateway records, or audit state. - -## D6: Fail Closed On Status Ambiguity - -Revoked, stale, unknown, and status-unavailable states cannot produce verified. Status unavailable should produce `proof_gap` with explicit failure reason. - -## D7: x402 Is Profile, Not Root Protocol - -x402 exact per-call paid HTTP is the first evidence profile built on top of the trust plane. It must not redefine `AuthorityCertificate` semantics. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/PLAN.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/PLAN.md deleted file mode 100644 index 5f38c8f..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/PLAN.md +++ /dev/null @@ -1,301 +0,0 @@ -# Plan: Terminal Verifier Trust Plane - -## Goal - -Invariant at stake: `AuthorityCertificate` must remain terminal evidence for protected automated actions, not permission, identity, settlement, certification, or downstream success. - -Build a Terminal Verifier Trust Plane that lets external receivers, auditors, SDKs, CLI users, MCP tools, and hosted verifier clients answer one narrow question: - -Does this `AuthorityCertificate` verify against pinned or published verifier trust material, current issuer/key/status records, and the exact terminal artifact binding it claims? - -The first protected-action wedge is x402 exact per-call paid HTTP, but the trust plane must stay protocol-owned and evidence-plane first. x402 is the adoption stress case, not the root protocol. - -## Non-Goals - -- Do not make `AuthorityCertificate` an approval, authorization, payment receipt, settlement proof, actor identity, compliance badge, certificate authority artifact, or proof that the principal understood the action. -- Do not make JWKS discovery a trust decision. -- Do not fetch certificate-supplied `jwks_uri` values. -- Do not expose raw receipts, gateway credentials, secrets, principal-private context, policy internals, or mutable audit state through hosted verification. -- Do not build a clearing house, settlement network, or general CA. -- Do not make hosted verification mutate certificate, receipt, issuer, key, or status state. -- Do not expose boolean-only `isValid()` APIs. - -## Source Boundary - -Canonical and candidate source areas: - -- `src/protocol/areas/authority-certificate/` -- `src/cli/certificate.ts` -- `src/http` -- existing authority-certificate protocol tests -- new verifier/key/status/http/cli tests near existing test ownership - -Planning source hierarchy: - -1. This run input and official constraints. -2. Tracked repo canon: `AGENTS.md`, `README.md`, `QUALITY.md`, `STRUCTURE.md`, `docs/internal/decisions.md`, `docs/internal/protocol-notes.md`. -3. Current source and tests. -4. `.planning/` as scratch only. - -External standards are constraint sources, not inherited product semantics: - -- RFC 7517: JWK/JWK Set are key representations; protect non-public key material. -- RFC 7515: JWS signing, validation, and protected key identifiers inform trust-binding checks. -- RFC 8414: `jwks_uri` can point to a JWK Set document; OAuth semantics are not inherited. -- RFC 7009: borrow endpoint security and ambiguity lessons only; OAuth token revocation is not certificate revocation. - -## Current State - -Implemented source state: - -- `createAuthorityCertificate()` mints terminal evidence for only `receipt`, `durable_refusal`, `proof_gap`, and `replay_refusal`. -- `verifyAuthorityCertificate()` checks schema, envelope digest, signing input digest, signed-over binding, algorithm prefix, pinned trust keys, signer roles, required artifact kinds, gateway admission binding, and terminal binding. -- Production rejects HMAC. -- Trust material is local and pinned with active/retired keys. -- CLI `cert verify` is evidence-plane only and non-mutating. - -Known gaps: - -- No verifier key-set/JWKS projection. -- No issuer/signer role/key version read model. -- No certificate status/revocation record model. -- No hosted verification route. -- No redacted hosted verification response. -- No explicit stale/revoked/status-unavailable failure model. -- No claim guard that prevents "valid" from meaning approved, paid, settled, trusted, certified, authorized, or compliant. - -## Target State - -Terminal verifier clients can submit or inspect an `AuthorityCertificate` and receive a structured non-mutating verification response that separates: - -- schema validity; -- cryptographic validity; -- signing input digest match; -- signed-over artifact binding; -- trusted issuer/key presence; -- signer role allowability; -- key version status and time window; -- required artifact kind match; -- gateway admission binding; -- terminal artifact binding; -- status/revocation result; -- replay refusal or proof-gap evidence; -- redacted audit projection; -- failure reasons. - -Hosted routes expose: - -- verifier metadata; -- verifier key-set projection; -- JWKS projection; -- certificate status lookup; -- hosted certificate verification. - -The verifier key set is the native model. JWKS is only a projection for interoperability. - -All public and SDK language says `verified`, `refused`, or `proof_gap`, never `authorized`, `approved`, `paid`, `settled`, `certified`, `trusted`, `compliant`, or bare `valid`. - -## Assumptions - -- Existing certificate creation and verification functions are stable enough to extend without redesigning terminal certificate semantics. -- Local pinned verification remains the root trust posture; hosted verification is a projection and convenience surface. -- Status records can be represented as append-only or immutable read records even if their storage implementation is initially in-memory or file-backed. -- x402 evidence profile can wait until verifier primitives exist. -- Production HMAC rejection remains mandatory. -- Status unavailable must fail closed as `proof_gap`, not silently degrade to verified. - -## Decisions - -1. Separate planes: - - evidence plane: `AuthorityCertificate` and terminal artifact verification; - - discovery plane: metadata, verifier key set, JWKS projection; - - trust decision plane: pinned/local or caller-owned acceptance of issuer/key/status records. -2. Add protocol-owned models: - - `AuthorityCertificateIssuer`; - - `AuthorityCertificateKeyVersion`; - - `AuthorityCertificateStatusRecord`; - - `AuthorityCertificateVerificationRequest`; - - `AuthorityCertificateVerificationResponse`. -3. Treat JWKS as projection: - - native verifier key-set model owns issuer, role, algorithm, key version, status, and time window; - - JWKS only emits public key material and integrity-protected identifiers compatible with RFC 7517 and RFC 7515 expectations. -4. Hosted verifier is audit-safe: - - deterministic parse; - - request size limits; - - rate limits where route infrastructure supports them; - - no arbitrary remote key fetching; - - no mutation; - - redacted response only. -5. Verification response is structured: - - no boolean-only API; - - explicit failure reasons; - - explicit stale, revoked, unknown, and status-unavailable outcomes. -6. x402 arrives after verifier trust plane: - - first prove `AuthorityCertificate` portability; - - then define exact per-call paid HTTP evidence profile. - -## Phases - -### Phase 0: Claim Guard And Vocabulary Fence - -Add product and code claim guards that make terminal evidence semantics mechanically hard to blur. Ban or flag certificate language that implies approval, authorization, paid status, settlement, actor trust, certification, compliance, or downstream success. - -Exit when `quality:claims` fails on forbidden verifier/certificate claims and current approved wording says terminal evidence only. - -### Phase 1: Trust Read Model - -Introduce issuer, key version, role, algorithm, status, and validity-window read models near authority-certificate protocol ownership. Keep them deterministic and local-first. Require verification to distinguish unknown issuer, unknown key, role mismatch, retired key, revoked key, stale key, and algorithm mismatch. - -Exit when pinned local verification can consume the new read model without changing current terminal artifact semantics. - -### Phase 2: Verifier Key Set And JWKS Projection - -Create native verifier key-set projection first, then a JWKS projection from it. Public JWKS must include only public material and protected identifiers; it must not carry private key material or imply trust. - -Exit when malformed JWK, duplicate keys, algorithm confusion, unknown key, retired key, and role mismatch negative tests fail closed. - -### Phase 3: Status And Revocation Records - -Add status records for certificate/key/issuer verification posture. Model active, retired, revoked, stale, unknown, and status-unavailable distinctly. Status unavailable returns `proof_gap` and prevents verified outcome. - -Exit when revoked/stale/status-outage tests fail closed and responses preserve ambiguity instead of smoothing it. - -### Phase 4: Verification Request And Response Projection - -Define `AuthorityCertificateVerificationRequest` and `AuthorityCertificateVerificationResponse`. Response must separate crypto validity, trusted signer, role/key status, artifact match, gateway binding, terminal binding, status/revocation, and redacted audit projection. - -Exit when CLI and protocol tests prove no boolean-only `isValid()` style surface is introduced. - -### Phase 5: Hosted Verifier Routes - -Add non-mutating hosted routes for metadata, key-set/JWKS, status, and verify. Hosted verification must not fetch arbitrary `jwks_uri`, must reject oversized payloads, must redact sensitive material, and must never mutate receipt/status/certificate state. - -Exit when hosted route tests cover payload size, malformed input, redaction, no raw leak, unknown issuer, revoked key, status outage, and deterministic refusal/proof-gap responses. - -### Phase 6: CLI / SDK / MCP Parity - -Update CLI evidence-plane output to match structured verification results. SDK/MCP-facing surfaces should expose the same categories without a boolean-only shortcut. Keep all surfaces non-mutating. - -Exit when CLI parity tests confirm local and hosted-style response projections preserve the same semantic boundaries. - -### Phase 7: x402 Evidence Profile - -Define the x402 exact per-call paid HTTP evidence profile on top of the verifier trust plane. The profile states what exact protected-action evidence an `AuthorityCertificate` proves or fails to prove for a single paid HTTP call. - -Exit when an external x402 receiver/auditor can ask whether a certificate verifies against published verifier keys/current status and what exact evidence it proves, without treating it as settlement or payment success. - -## Task Graph - -```text -T0 claim guard - -> T1 trust read model - -> T2 key-set projection - -> T3 JWKS projection - -> T4 status records - -> T5 verification response - -> T6 hosted metadata/status routes - -> T7 hosted verify route - -> T8 CLI parity - -> T9 x402 evidence profile -T10 quality gates depends on all implementation tasks -``` - -## Risks And Mitigations - -- Risk: "valid certificate" becomes market shorthand for approved/paid/trusted. - Mitigation: claim guard, API naming discipline, structured result categories, no boolean-only API. -- Risk: JWKS discovery is mistaken for trust. - Mitigation: native key-set model owns trust posture; JWKS docs and tests call it projection only; verifier never fetches certificate-supplied trust. -- Risk: hosted verification leaks raw evidence. - Mitigation: redaction allowlist, negative raw-leak tests, no raw receipt/gateway credential/principal-private fields in response. -- Risk: status outage silently verifies stale evidence. - Mitigation: status unavailable maps to `proof_gap` and fail-closed verification. -- Risk: role/key/version drift creates ambient authority. - Mitigation: signed-over key identifiers, issuer/key/role/algorithm/status/time-window checks, retired/revoked handling. -- Risk: x402 profile broadens into settlement or payment attestation. - Mitigation: profile limited to exact per-call protected-action evidence and terminal certificate verification. - -## Validation Gates - -Required closeout commands: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -Required focused checks: - -```bash -npm test -- authority-certificate -npm test -- verifier -npm test -- certificate -npm test -- http -npm test -- cli -``` - -If exact script names differ, use the repo's existing equivalent focused test selectors and record the substitution. - -Required test coverage: - -- schema-invalid certificate; -- malformed JWK; -- duplicate keys; -- algorithm confusion; -- unknown issuer; -- unknown key version; -- unauthorized signer role; -- retired key; -- revoked key; -- stale key; -- status unavailable; -- missing required artifact kind; -- gateway admission mismatch; -- terminal binding mismatch; -- tenant or issuer mismatch; -- oversized hosted verify payload; -- hosted route raw leak attempt; -- arbitrary `jwks_uri` rejection; -- replay refusal terminal evidence; -- proof gap terminal evidence; -- x402 evidence profile does not imply paid/settled/success. - -## Cut Lines - -Cut before implementation if the plan requires: - -- hosted verifier mutation; -- remote trust fetching from certificate-supplied URLs; -- public exposure of raw receipts or gateway credentials; -- certificate semantics beyond terminal evidence; -- boolean-only validity API; -- x402 settlement/payment-success claims; -- OAuth revocation semantics as certificate revocation semantics. - -Cut scope for first implementation if needed: - -- defer x402 profile until verifier routes and response model are stable; -- defer full SDK/MCP wrappers until CLI parity is proven; -- ship native verifier key-set before JWKS; -- ship local status records before hosted status route; -- ship hosted verify after redaction tests exist. - -## Rollback / Stop Conditions - -Stop and redesign if: - -- any verifier path can return verified while status is revoked, stale, unknown, or unavailable; -- hosted verification mutates state; -- a response leaks raw receipt, gateway credential, secret, or principal-private context; -- JWKS projection becomes the authority source; -- public wording says certificate means approved, authorized, paid, settled, trusted, certified, compliant, or successful; -- one key or greenlight can validate multiple unbound terminal artifacts; -- gateway admission and terminal artifact evidence cannot be distinguished in response output. - -Rollback by disabling hosted routes and preserving local pinned verification if route safety or redaction fails. - -## Smallest Next Action - -Implement the claim guard and vocabulary fence for `AuthorityCertificate` validity semantics, then add the protocol-owned trust read model behind existing local verification. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/RISKS.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/RISKS.md deleted file mode 100644 index 4a113cf..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/RISKS.md +++ /dev/null @@ -1,43 +0,0 @@ -# Risks: Terminal Verifier Trust Plane - -## R1: Validity Meaning Drift - -Risk: users and APIs collapse certificate verifies into approved, paid, trusted, or settled. - -Mitigation: claim guard, API naming constraints, structured response, docs wording, negative wording tests. - -## R2: JWKS As Fake Authority - -Risk: consumers treat key discovery as trust. - -Mitigation: native verifier key-set model; JWKS projection docs; no certificate-supplied `jwks_uri`; explicit issuer/key/status checks. - -## R3: Hosted Verification Leaks Sensitive Evidence - -Risk: hosted response exposes raw receipts, gateway credentials, principal-private context, policy internals, or secrets. - -Mitigation: allowlisted response projection, redaction tests, raw-leak golden negatives. - -## R4: Status Ambiguity Becomes Success - -Risk: status outage or unknown status gets treated as valid. - -Mitigation: status unavailable maps to `proof_gap`; stale/revoked/unknown fail closed. - -## R5: Algorithm Or Key Confusion - -Risk: malformed JWK, duplicate key IDs, algorithm prefix confusion, or retired key drift lets the wrong signer pass. - -Mitigation: deterministic parsing, duplicate rejection, protected key identifiers, algorithm allowlist, key version status checks. - -## R6: Hosted Route Becomes Mutation Channel - -Risk: verify/status endpoints mutate state or become audit side effects. - -Mitigation: route contract says non-mutating; tests assert no write calls; observability must not alter certificate/status meaning. - -## R7: x402 Overclaims - -Risk: x402 evidence profile implies paid, settled, delivered, or business-success proof. - -Mitigation: profile language limited to exact protected-action evidence and terminal certificate verification. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/TASKS.jsonl b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/TASKS.jsonl deleted file mode 100644 index 08aa3b9..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/TASKS.jsonl +++ /dev/null @@ -1,11 +0,0 @@ -{"id":"T0","priority":"P0","phase":"Phase 0","title":"Add AuthorityCertificate claim guard","owner":"protocol","rationale":"Prevent terminal evidence from drifting into approval, payment, settlement, trust, certification, compliance, or success claims.","depends_on":[],"acceptance":["Forbidden validity/approval/payment/trust terms fail claim checks in certificate/verifier-facing docs and user-facing strings.","Approved wording states AuthorityCertificate is terminal evidence only.","quality:claims passes with the new guard."],"candidate_paths":["docs/internal/decisions.md","docs/internal/protocol-notes.md","src/protocol/areas/authority-certificate/","scripts/"],"non_goals":["Do not change certificate minting semantics.","Do not add hosted routes."]} -{"id":"T1","priority":"P0","phase":"Phase 1","title":"Introduce authority certificate issuer and key version read model","owner":"protocol","rationale":"Verification needs protocol-owned issuer/key/role/algorithm/status/time-window records instead of ad hoc pinned key shape.","depends_on":["T0"],"acceptance":["Models exist for issuer, key version, signer role, algorithm, status, and validity window.","Existing local pinned verification consumes or adapts to the read model.","Unknown issuer, unknown key, role mismatch, retired key, and algorithm mismatch are distinct outcomes."],"candidate_paths":["src/protocol/areas/authority-certificate/","tests/"],"non_goals":["Do not expose JWKS yet.","Do not fetch remote keys."]} -{"id":"T2","priority":"P0","phase":"Phase 2","title":"Create native verifier key-set projection","owner":"protocol","rationale":"JWKS must be a projection from a native trust model, not the authority source.","depends_on":["T1"],"acceptance":["Native verifier key-set projection exposes only allowed public metadata and key material.","Projection includes issuer, key id/version, role, algorithm, status, and time-window fields where appropriate.","Private key material is never projected."],"candidate_paths":["src/protocol/areas/authority-certificate/","tests/"],"non_goals":["Do not claim key discovery establishes trust.","Do not implement hosted metadata yet."]} -{"id":"T3","priority":"P0","phase":"Phase 2","title":"Add JWKS projection from verifier key set","owner":"protocol","rationale":"External verifiers need RFC 7517-compatible public key representation without inheriting OAuth or CA semantics.","depends_on":["T2"],"acceptance":["JWKS emits public key material only.","Duplicate key ids, malformed JWK material, and algorithm confusion have negative tests.","Docs or protocol comments state JWKS is projection, not trust."],"candidate_paths":["src/protocol/areas/authority-certificate/","tests/"],"non_goals":["Do not publish private key material.","Do not accept certificate-supplied jwks_uri as authority."]} -{"id":"T4","priority":"P0","phase":"Phase 3","title":"Add authority certificate status records","owner":"protocol","rationale":"Verification must fail closed on revoked, stale, unknown, and status-unavailable states.","depends_on":["T1"],"acceptance":["Status record model represents active, retired, revoked, stale, unknown, and unavailable outcomes.","Revoked and stale cannot return verified.","Status unavailable returns proof_gap with explicit reason."],"candidate_paths":["src/protocol/areas/authority-certificate/","tests/"],"non_goals":["Do not borrow OAuth token revocation semantics wholesale.","Do not make status lookup mutating."]} -{"id":"T5","priority":"P0","phase":"Phase 4","title":"Define structured verification request and response","owner":"protocol","rationale":"Consumers need audit-safe categories, not a boolean validity shortcut.","depends_on":["T2","T3","T4"],"acceptance":["Request and response models exist for authority certificate verification.","Response separates schema, crypto, signer trust, role, key status, artifact match, gateway binding, terminal binding, status, and failure reasons.","No boolean-only isValid-style API is introduced."],"candidate_paths":["src/protocol/areas/authority-certificate/","src/cli/certificate.ts","tests/"],"non_goals":["Do not expose raw receipts or secrets.","Do not imply authorization or payment success."]} -{"id":"T6","priority":"P1","phase":"Phase 5","title":"Add hosted verifier metadata, key-set, JWKS, and status routes","owner":"http","rationale":"External auditors and receivers need non-mutating discovery and status surfaces before hosted verification.","depends_on":["T3","T4"],"acceptance":["Routes expose metadata, native key-set projection, JWKS projection, and status lookup.","Routes are non-mutating and redacted.","Metadata may include jwks_uri but does not inherit OAuth semantics or establish trust."],"candidate_paths":["src/http","src/protocol/areas/authority-certificate/","tests/"],"non_goals":["Do not add verify route side effects.","Do not fetch remote trust material."]} -{"id":"T7","priority":"P1","phase":"Phase 5","title":"Add hosted certificate verification route","owner":"http","rationale":"Hosted verifier must answer the external evidence question without becoming a mutation or leakage channel.","depends_on":["T5","T6"],"acceptance":["Route deterministically parses bounded requests.","Oversized, malformed, unknown issuer, revoked, stale, and status-unavailable cases fail closed.","Response is redacted and excludes raw receipts, gateway credentials, secrets, and principal-private context."],"candidate_paths":["src/http","src/protocol/areas/authority-certificate/","tests/"],"non_goals":["Do not mutate certificate, receipt, key, issuer, or status state.","Do not return authorized, approved, paid, settled, trusted, certified, or compliant."]} -{"id":"T8","priority":"P1","phase":"Phase 6","title":"Update CLI verification output for structured parity","owner":"cli","rationale":"CLI, SDK, and MCP verification surfaces must preserve evidence-plane semantics consistently.","depends_on":["T5"],"acceptance":["CLI cert verify reports structured categories matching protocol response.","CLI remains non-mutating.","CLI does not expose boolean-only validity language."],"candidate_paths":["src/cli/certificate.ts","tests/"],"non_goals":["Do not add mutation commands.","Do not make CLI output settlement or payment proof."]} -{"id":"T9","priority":"P2","phase":"Phase 7","title":"Define x402 exact per-call evidence profile","owner":"protocol","rationale":"x402 is the first protected-action wedge and needs a narrow evidence profile after verifier primitives exist.","depends_on":["T7","T8"],"acceptance":["Profile states what AuthorityCertificate proves and fails to prove for one exact paid HTTP call.","Profile does not claim settlement, payment success, delivery, authorization, or compliance.","External receiver/auditor flow can verify certificate against published keys/current status and inspect exact protected-action evidence."],"candidate_paths":["src/protocol/areas/authority-certificate/","docs/internal/protocol-notes.md","tests/"],"non_goals":["Do not create a payment clearing house.","Do not generalize beyond exact per-call protected-action evidence."]} -{"id":"T10","priority":"P0","phase":"Quality","title":"Run closeout quality and architecture gates","owner":"verification","rationale":"The trust plane is only credible if claim, architecture, formatting, focused tests, and repo checks all pass.","depends_on":["T0","T1","T2","T3","T4","T5","T6","T7","T8","T9"],"acceptance":["quality:claims passes.","quality:architecture passes.","format:check passes.","check:repo passes.","Focused authority-certificate, verifier, certificate, http, and cli tests pass or substitutions are recorded."],"candidate_paths":["package.json","tests/","docs/internal/decisions.md"],"non_goals":["Do not implement additional product scope during closeout.","Do not clean unrelated dirty worktree drift."]} diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/VALIDATION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/VALIDATION.md deleted file mode 100644 index 3982775..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/VALIDATION.md +++ /dev/null @@ -1,73 +0,0 @@ -# Validation: Terminal Verifier Trust Plane - -## Quality Gates - -Run before closeout: - -```bash -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -## Focused Test Gates - -Use repo-native focused selectors for: - -```bash -npm test -- authority-certificate -npm test -- verifier -npm test -- certificate -npm test -- http -npm test -- cli -``` - -## Required Negative Tests - -- schema-invalid certificate refuses; -- malformed JWK refuses; -- duplicate key IDs refuse; -- algorithm mismatch refuses; -- HMAC production verification refuses; -- unknown issuer refuses; -- unknown key version refuses; -- unauthorized signer role refuses; -- retired key refuses or reports retired according to policy; -- revoked key refuses; -- stale key refuses; -- status unavailable returns `proof_gap`; -- required artifact kind mismatch refuses; -- gateway admission binding mismatch refuses; -- terminal artifact binding mismatch refuses; -- tenant mismatch refuses; -- oversized hosted verify payload refuses; -- arbitrary `jwks_uri` input is ignored or rejected; -- hosted response excludes raw receipts; -- hosted response excludes gateway credentials; -- hosted response excludes principal-private context; -- x402 profile does not imply paid, settled, or downstream success. - -## Required Positive Tests - -- local pinned active issuer/key verifies terminal `receipt` evidence; -- local pinned active issuer/key verifies `durable_refusal`; -- local pinned active issuer/key verifies `proof_gap`; -- local pinned active issuer/key verifies `replay_refusal`; -- native verifier key-set projection exposes active public key metadata; -- JWKS projection emits public key material only; -- hosted verify returns redacted structured response; -- CLI output matches structured verification categories. - -## Closeout Evidence - -A closeout is credible only if it records: - -- exact commands run; -- focused test results; -- claim guard result; -- architecture guard result; -- formatting result; -- repo check result; -- any substituted test commands; -- unresolved proof gaps. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/input.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/input.md deleted file mode 100644 index 88a3ae1..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/input.md +++ /dev/null @@ -1,144 +0,0 @@ -# Macro Plan Input: Terminal Verifier Trust Plane - -Run id: terminal-verifier-trust-plane-20260524T074226Z -Date: 2026-05-24 - -## Hard Frame - -Handshake is protected actions for automated decision making. Engineering-agent workflows are a current stress case and adoption context, not the product boundary. x402 exact per-call paid HTTP is the first protected-action wedge, not the protocol. - -This plan is planning only. Do not edit source, tests, docs outside this planning run, package metadata, or previously staged files. Each perspective worker may write only its assigned raw output file. If a worker cannot comply, it must write a BLOCKED note in its assigned file only. - -## Goal - -Plan the terminal verifier trust plane that makes terminal `AuthorityCertificate` evidence portable without turning it into permission, identity, settlement, marketplace certification, or clearing-house language. - -Mechanism target: - -```text -terminal evidence --> AuthorityCertificate --> verifier key set --> revocation/status check --> verification response --> audit-safe projection -``` - -## Current Source Grounding - -Canonical posture: - -- `.planning/macro/DEFERRED-INTEGRATE-ELIMINATE.md` says terminal verification is critical path item 2, after claim boundary cleanup and customer-owned gateway custody proof. -- `.planning/macro/active/claim-boundary-cleanup/PLAN.md` makes category wording a P0 claim boundary: protected actions for automated decision making, x402 first wedge, engineering agents only adoption context/threat model. -- `.planning/macro/active/customer-owned-gateway-custody-proof/PLAN.md` requires credential custody proof before hosted claims. -- `docs/internal/decisions.md` states `AuthorityCertificate` is local terminal signed evidence only, not greenlight, gateway check, mutation proof, identity, settlement, marketplace status, or hosted trust. -- `docs/internal/protocol-notes.md` says cross-org JWKS, revocation, hosted verify APIs, marketplace certification, and provider custody remain outside the local foundation. - -Source anchors: - -- `src/protocol/areas/authority-certificate/schemas.ts` -- `src/protocol/areas/authority-certificate/signing.ts` -- `src/protocol/areas/authority-certificate/transitions.ts` -- `src/protocol/areas/authority-certificate/verify.ts` -- `src/cli/certificate.ts` -- `src/surfaces/boundary-manifest.ts` -- `test/protocol/authority-certificate.test.ts` -- `test/cli/cli-evidence.test.ts` -- `test/sdk/role-clients.test.ts` -- `test/mcp/mcp-resource-redaction.test.ts` -- `test/architecture/claim-boundary.test.ts` -- `test/architecture/root-exports.test.ts` -- `test/architecture/import-posture.test.ts` - -Current landed behavior: - -- `createAuthorityCertificate()` mints terminal evidence only for receipt, durable refusal, proof gap, or replay refusal terminals. -- Certificate signing input excludes signatures/signingInputDigest and includes terminal, envelope, artifacts, verification policy, consumer bindings, extensions, and emittedAt. -- `verifyAuthorityCertificate()` validates schema, envelope digest, signing input digest, signature signed-over binding, algorithm prefix, pinned trust keys, signer roles, required artifact kinds, gateway admission binding, and terminal binding. -- Production verification rejects `hmac-sha256`; HMAC is dev-only behind `allowDevHmac`. -- Trust material is local/pinned: keys have `keyIdentityRef`, optional `signerRole`, algorithm, public key or HMAC secret, and status `active|retired`. -- CLI `cert verify` is evidence-plane only. It verifies supplied certificate material against supplied trust material without minting, mutation, protocol-store access, or raw dumps. - -Current gaps to plan: - -- No verifier key-set projection or JWKS-compatible public-key surface. -- No issuer/signer role/key version/read model beyond local trust material. -- No revocation or status record for certificates/signers/key material. -- No hosted verifier route. -- No route admission, reader authorization, retention, or redacted response plane for hosted verification. -- No stale-key, revoked-key, unknown-key, wrong-issuer, wrong-envelope, or status-unavailable failure model beyond local `trust_key_missing` and `trust_key_inactive`. -- No public claim guard that "valid certificate" means terminal evidence verified at a time/status boundary, not permission, identity, settlement, certification, or final business success. - -## Official Source Constraints - -Use these only as planning constraints; do not invent compatibility claims without implementation and tests: - -- RFC 7517 defines JWK/JWK Set as JSON representations of cryptographic keys and key sets. It explicitly requires protection for non-public key material. -- RFC 7515 defines JWS signing/validation concepts, key identification, and integrity-protected header considerations. -- RFC 8414 defines `jwks_uri` as metadata for a URL pointing to a JWK Set document. -- RFC 7009 is OAuth token revocation, not a certificate revocation standard. Its transferable lesson is security posture: revocation/status endpoints need trustworthy discovery, HTTPS/authentication, and careful failure handling. - -Open question for the plan: whether Handshake should implement a JWKS-compatible public-key projection now or a Handshake-native verifier key-set first, with JWKS compatibility as a later adapter. The answer must preserve modularity and not make OAuth/JWT semantics part of the protocol unless explicitly implemented. - -## Required Perspectives - -Produce five independent raw perspectives before chair synthesis: - -1. Strategy: trust-plane product posture, category boundaries, x402-first-wedge implications, adoption sequence. -2. Architecture: protocol schema/state/route/read-model design, key set/status/revocation, redaction, integration points. -3. Execution: ordered implementation slices, file-level candidates, tests, gates, dependency graph. -4. Risk/Security: threat model, stale key and revocation failure modes, hosted route abuse, response leakage, claim drift. -5. Adoption/DevEx: CLI/SDK/MCP/hosted verifier usage shape, customer integration without boiling the ocean, error affordances. - -## Chair Synthesis Requirements - -Create: - -- `PLAN.md` -- `CONTEXT.md` -- `ASSUMPTIONS.md` -- `DECISIONS.md` -- `RISKS.md` -- `VALIDATION.md` -- `TASKS.jsonl` -- `runs/terminal-verifier-trust-plane-20260524T074226Z/synthesis.md` - -The plan must include: - -- Summary -- Source Grounding -- Non-Goals -- Recommended Architecture -- Phased Implementation -- Validation Gates -- Success Criteria -- End Criteria -- 10-Star Product Bar -- Antipatterns -- Open Questions -- Smallest Next Mechanism - -## Must-Haves - -- Keep `AuthorityCertificate` as terminal evidence, not permission, identity, settlement, certification, or downstream success. -- Separate key discovery from trust decision. A key being visible in a key set is not enough; signer role, issuer/tenant scope, key version, status, revocation, and certificate terminal binding must be evaluated. -- Treat status/revocation failure explicitly. Decide fail-closed vs proof-gap behavior for unavailable status checks. -- Never expose private keys, symmetric keys, HMAC secrets, signing material, raw protocol records, raw custody material, `PaymentPayload`, `PAYMENT-SIGNATURE`, bearer tokens, or mutation credentials. -- Preserve local/offline verification. Hosted verifier is additive, not a replacement for offline pinned verification. -- Keep CLI/MCP/SDK evidence surfaces non-mutating unless a later implementation explicitly promotes a mutation surface through policy/gateway checks. -- Respect the sequence: custody proof first, terminal verifier trust plane second, hosted evidence/admission after both are stable. - -## Antipatterns To Reject - -- Certificate equals approval, identity, settlement, marketplace certification, clearing-house readiness, or downstream success. -- JWKS equals trust. -- Revocation endpoint copied from OAuth semantics without Handshake-specific certificate/status semantics. -- Hosted verification route that returns raw certificate envelopes, raw records, secrets, or operational internals. -- Trust plane that only works if every actor is honest. -- Verifier route that reads or mutates protocol state while claiming to be offline/portable verification. -- CLI/MCP/SDK surfaces that mint certificates or issue authority. -- x402-specific signer fields leaking into generic certificate trust semantics. - -## Closeout Expectations - -Planning closeout is successful when every required output exists, `TASKS.jsonl` parses, required plan sections exist, source working tree remains untouched, and the plan states validation commands for eventual implementation. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/ADOPTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/ADOPTION.md deleted file mode 100644 index 1af21c8..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/ADOPTION.md +++ /dev/null @@ -1,244 +0,0 @@ -# Adoption And DevEx Perspective - -## Invariant At Stake - -Terminal evidence can be portable only if verification remains non-mutating and evidence-plane only. If valid certificate starts meaning permission, identity, settlement, compliance approval, or business success, the verifier becomes authority theatre. - -## Adoption Thesis - -The first wedge is not agent safety. It is verifiable evidence for exact protected paid HTTP actions, starting with x402 per-call payment receipts/refusals/proof gaps as terminal artifacts. - -Customer value should read as: - -> Given this terminal event, can I independently verify that it was signed by a trusted issuer, bound to the exact admitted protected action, not revoked, and safe to project into audit/reporting systems? - -That is narrower, buyable, and easier to integrate than trust infrastructure for agents. - -## Usage Shape - -### CLI - -Primary DevEx loop: - -```bash -handshake cert verify receipt.json \ - --trust-bundle ./handshake-trust.json \ - --status-url https://verifier.example.com/status \ - --required-kind receipt \ - --format json -``` - -Expected outputs: - -- `verified` -- `refused` -- `revoked` -- `stale` -- `status_unavailable` -- `untrusted_issuer` -- `unsupported_algorithm` -- `artifact_kind_mismatch` -- `gateway_binding_mismatch` -- `terminal_binding_mismatch` - -The CLI must never imply mutation authority. No approve, authorize, settle, certify, or clear verbs. - -### SDK - -SDK should expose one boring call: - -```ts -const result = await verifier.verifyAuthorityCertificate({ - certificate, - trustBundle, - requiredArtifactKinds: ["receipt"], - statusPolicy: "fail_closed", -}); -``` - -Result shape must separate: - -- cryptographic validity; -- trusted signer status; -- key version/status; -- artifact kind match; -- gateway admission binding; -- terminal evidence binding; -- revocation/status result; -- audit-safe projection. - -No boolean-only `isValid()`. That invites product misuse. - -### MCP - -MCP tool should be read-only: - -```text -verify_authority_certificate -``` - -It returns structured verification evidence. It must not expose mutation, payment retry, settlement, or permission actions. MCP integration is for hosts that need portable terminal evidence inside workflows, not for granting authority. - -### Hosted Verifier - -Hosted route: - -```http -POST /verify -GET /.well-known/handshake-verifier -GET /jwks.json -GET /status/{certificateId} -``` - -The hosted verifier returns an audit-safe projection, not the full sensitive certificate by default. It should redact principal/runtime/environment details unless explicitly configured. - -## Customer Integration Sequence - -1. Local verification first: customer pins a local trust bundle and verifies sample terminal artifacts from x402 protected calls. -2. Key-set projection: customer consumes issuer/verifier metadata and JWKS-style public keys without learning private trust material. -3. Status checks: customer enables fail-closed revocation/status checks for production audit paths. -4. Hosted verifier: customer points downstream audit/reporting systems at a hosted non-mutating verifier endpoint. -5. Report projection: customer exports redacted verification summaries into finance, risk, support, or compliance systems. - -This sequence avoids boiling the ocean. No runtime replacement, no identity migration, no payment clearing-house posture. - -## Trust Bundle And Key-Set Ergonomics - -Trust bundle needs a human-readable read model: - -```json -{ - "issuer": "acme-handshake", - "environment": "production", - "keys": [ - { - "kid": "2026-05-prod-ed25519-01", - "status": "active", - "roles": ["authority_certificate_signer"], - "notBefore": "2026-05-01T00:00:00Z", - "notAfter": "2026-08-01T00:00:00Z" - } - ] -} -``` - -JWKS projection should expose public key material and key IDs only. It must not expose policy, private authority, settlement state, or customer-sensitive certificate internals. - -Developer affordances needed: - -- `handshake trust inspect` -- `handshake trust diff` -- `handshake trust pin` -- `handshake cert explain` -- `handshake cert verify --why` - -Why failed is mandatory. A cryptographic verifier without explainability will become support debt immediately. - -## Revocation And Status Errors - -Status affordances must be explicit and fail-closed by default for production: - -| Condition | Meaning | Default | -| --- | --- | --- | -| `revoked` | certificate/key/artifact is no longer acceptable evidence | fail | -| `stale` | status freshness exceeded verifier policy | fail | -| `status_unavailable` | verifier cannot determine current status | fail in prod, warn in dev | -| `unknown_kid` | key not in pinned or fetched trust set | fail | -| `retired_key` | key was valid historically but not active now | configurable historical verify | -| `issuer_mismatch` | certificate issuer not in trust bundle | fail | -| `role_mismatch` | signer lacks required certificate-signing role | fail | - -Do not copy RFC 7009 semantics into certificates. Use only the security lesson: revocation/status checks are active controls and must not leak sensitive state casually. - -## Docs And Report Shape - -Docs should be built around evidence questions: - -- What artifact am I verifying? -- Who signed it? -- Which key version signed it? -- What role was the signer allowed to perform? -- What terminal event kind is bound? -- What gateway admission is bound? -- Is the certificate current, stale, revoked, or unverifiable? -- What can I safely project into audit systems? -- What must I not infer? - -Report shape: - -```json -{ - "verification": { - "outcome": "verified", - "verifiedAt": "2026-05-24T00:00:00Z", - "evidencePlaneOnly": true - }, - "certificate": { - "artifactKind": "receipt", - "issuer": "example", - "kid": "2026-05-prod-ed25519-01" - }, - "bindings": { - "gatewayAdmission": "matched", - "terminalEvidence": "matched", - "envelopeDigest": "matched" - }, - "status": { - "state": "active", - "checkedAt": "2026-05-24T00:00:00Z" - }, - "projection": { - "safeForAudit": true, - "redactionsApplied": true - } -} -``` - -## Cut Lines - -Cut: - -- certified payment; -- trusted agent; -- authorized action; -- settlement proof; -- identity verification; -- compliance approval; -- clearing network; -- valid means safe. - -Keep: - -- terminal evidence verified; -- issuer key trusted; -- status checked; -- gateway binding matched; -- audit-safe projection; -- non-mutating verifier. - -## 10-Star Bar - -A 10-star DevEx means a skeptical customer can do this in under 30 minutes: - -1. Verify one sample certificate locally. -2. Inspect why it passed. -3. Break one field and see the exact failure. -4. Rotate/pin a trust key. -5. See stale/revoked/status-unavailable behavior. -6. Call the hosted verifier. -7. Export a redacted audit projection. -8. Explain internally what the verifier does not mean. - -If they cannot explain the non-goals after using it, product language failed. - -## Recommended Plan Shape - -1. Read model and wording guard: issuer/signer role/key version projection and claim guards around valid certificate. -2. Trust bundle and JWKS projection: public key-set projection with pinned/local trust ergonomics. -3. Status and revocation: status records, freshness policy, revoked/stale/status-unavailable outcomes. -4. Hosted verifier: non-mutating verify, metadata, JWKS, and status routes. -5. Audit projection: redacted report objects for downstream systems. - -## Smallest Next Mechanism - -Build a structured verification response type with issuer, key id, signer role, status outcome, binding checks, and an `evidencePlaneOnly: true` projection flag. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/ARCH.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/ARCH.md deleted file mode 100644 index 7d4d5dc..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/ARCH.md +++ /dev/null @@ -1,186 +0,0 @@ -# Architecture Perspective - -## Invariant At Stake - -`AuthorityCertificate` evidence must be portable without turning into permission. The verifier plane can say this terminal artifact was signed by a recognized evidence signer over this exact envelope and status was acceptable at verification time. It must not say this actor may execute, this identity is trusted, settlement happened, or Handshake certifies the business outcome. - -## Core Boundary - -Separate the system into three planes: - -1. Evidence plane: `AuthorityCertificate` issuance, terminal artifact binding, signature, envelope digest, artifact-kind requirements, gateway admission binding, and terminal binding. -2. Discovery plane: public verifier key set projection, issuer metadata, signer role metadata, key version metadata, and status endpoint discovery. -3. Trust decision plane: local verifier policy over pinned issuers, accepted roles, accepted key versions, required artifact kinds, acceptable status freshness, revocation behavior, and failure mode. - -Key discovery must never imply trust. JWKS can publish public keys. Only local verifier policy decides whether a key, issuer, signer role, and certificate status are acceptable. - -## Protocol Schema And State - -Add protocol-owned models, not route-owned ad hoc shapes: - -- `AuthorityCertificate`: existing signed evidence envelope. Keep terminal-only issuance. -- `AuthorityCertificateIssuer`: stable issuer identifier, evidence-plane service name, metadata URL, supported algorithms, current status. -- `AuthorityCertificateSignerRole`: narrow enum or registry-backed type such as `terminal_evidence_signer`, maybe later `status_signer`. Avoid broad names like `trusted_signer`. -- `AuthorityCertificateKeyVersion`: key id, issuer id, signer role, algorithm, public key material reference, activation time, retirement time, status. -- `AuthorityCertificateStatusRecord`: certificate id or digest, issuer id, status, reason code, observed time, effective time, optional expires time, status signer binding. -- `AuthorityCertificateVerificationRequest`: certificate plus requested policy knobs: required artifact kinds, required issuer, accepted signer roles, freshness budget. -- `AuthorityCertificateVerificationResponse`: evidence-safe result: `valid`, `invalid`, `revoked`, `stale`, `status_unavailable`, `untrusted_issuer`, `untrusted_key`, `unsupported_algorithm`, `artifact_requirement_failed`, `binding_failed`. - -Do not encode approved, authorized, certified, settled, identity verified, or safe to execute in these names. - -## Verifier Key Set Vs JWKS Projection - -There are two different artifacts: - -- Verifier key set: Handshake-native read model with issuer id, signer role, key version, lifecycle state, algorithm, activation/retirement timestamps, and policy-relevant metadata. -- JWKS projection: standards-compatible public-key representation derived from verifier key set. It exposes public verification material and `kid`/algorithm mapping, but it is not the canonical trust model. - -The JWKS endpoint is a public projection, not the source of trust. RFC 7517 gives representation. RFC 7515 gives key identification/signature integrity lessons. RFC 8414-style metadata can advertise `jwks_uri`. None of those documents turn discovery into acceptance. - -## Signer Role And Key Version Model - -Minimum model: - -- `issuerId` -- `keyId` -- `keyVersion` -- `signerRole` -- `algorithm` -- `publicKeyMaterial` -- `status`: `active | retired | revoked` -- `validFrom` -- `retiredAt` -- `revokedAt` -- `rotationReason` - -Verification must require both key match and role match. A key valid for status records must not automatically validate terminal evidence. A retired key may verify historical certificates only if the certificate signing time falls inside the acceptable window and local policy allows historical validation. - -## Certificate Status And Revocation Semantics - -Revocation is evidence-plane invalidation, not OAuth token semantics. RFC 7009 is useful only for transferable security lessons: authenticated revocation, ambiguous public responses where appropriate, replay resistance, and privacy-preserving status behavior. - -Recommended status values: - -- `good` -- `revoked` -- `superseded` -- `unknown` -- `stale` -- `issuer_unavailable` - -Verification must fail closed for live trust decisions when status is unavailable or stale. For audit-only reconstruction, it may return a redacted `status_unavailable` result with enough metadata to explain the gap. - -Status records should be append-only and separately signed or gateway-recorded. Do not silently mutate certificate validity in place. - -## Hosted Verifier Route Boundaries - -Allowed: - -- accept certificate verification input; -- fetch/project local issuer key material; -- check pinned trust material; -- check revocation/status; -- return audit-safe verification result; -- optionally emit receipt/proof-gap for verification-attempt observability if later scoped. - -Forbidden: - -- mint new authority; -- authorize mutation; -- settle payment; -- certify identity; -- imply principal approval; -- infer business success; -- accept arbitrary remote JWKS as trusted without local policy; -- expose full terminal receipts when caller is not entitled to them. - -Suggested routes: - -- `GET /.well-known/handshake-authority-certificate` -- `GET /authority-certificates/jwks.json` -- `POST /authority-certificates/verify` -- `GET /authority-certificates/status/:certificateDigest` - -## Redaction And Audit-Safe Projection - -Default response should include: - -- verification result; -- issuer id; -- key id / key version; -- signer role; -- artifact kinds observed; -- envelope digest; -- terminal evidence kind; -- status result; -- status checked at; -- failure reason code; -- redacted proof-gap markers. - -Default response should exclude: - -- secrets; -- full receipt payloads; -- raw gateway credentials; -- principal private context; -- settlement internals; -- downstream execution details not signed into the certificate; -- unrelated terminal artifacts. - -If full evidence is needed, require a separate entitlement path. Hosted verification must not become a receipt exfiltration endpoint. - -## CLI, SDK, And MCP Integration Points - -CLI: - -- `cert verify` remains non-mutating. -- Add flags for `--issuer`, `--jwks-uri`, `--trust-policy`, `--required-artifact-kind`, `--status-url`, `--allow-stale=false`. -- Output must say certificate evidence valid, not authorized. - -SDK: - -- provide `verifyAuthorityCertificate`; -- provide `loadVerifierKeySet`; -- provide `projectVerifierKeySetToJwks`; -- provide `checkAuthorityCertificateStatus`; -- keep policy explicit: no default remote trust. - -MCP: - -- expose read-only tools only: `handshake.certificate.verify`, `handshake.certificate.status`, `handshake.issuer.metadata`, `handshake.issuer.jwks`; -- tool descriptions must state non-mutating evidence verification; -- do not expose certificate verification as approval or gateway admission. - -## Source Ownership - -Recommended ownership should stay near existing source areas, not generic helper buckets: - -- `src/protocol/areas/authority-certificate/` for canonical schema and verifier extensions; -- `src/protocol/areas/authority-certificate/status.ts` for status and revocation schema; -- `src/protocol/areas/authority-certificate/key-set.ts` for Handshake-native key set model and JWKS projection; -- `src/http/...` for metadata and verifier route adapters when hosted is promoted; -- `src/cli/certificate.ts` for CLI surface; -- SDK/evidence clients for non-mutating helpers. - -Keep RFC-specific projection code at the boundary. Do not let JWKS types invade internal trust semantics. - -## Import Posture - -Accept standards libraries for JWK/JWKS parsing only if boring, maintained, and testable. Do not import a general auth framework that smuggles OAuth, identity-provider, token-introspection, or permission semantics into the model. - -Internal verification policy should remain Handshake-owned. External specs give wire formats, not authority semantics. - -## Validation Gates - -- A valid certificate cannot authorize a new gateway mutation. -- Verification fails when signer role is wrong even if signature is valid. -- Verification fails when a key is discovered through JWKS but not pinned by local trust policy. -- Retired key verifies only historical certificates inside allowed policy window. -- Revoked certificate returns revoked, not invalid generic. -- Status unavailable is distinct from bad signature. -- Hosted verifier never returns full private receipt fields by default. -- CLI/SDK/MCP copy never says permission, approval, identity, settlement, or certified. - -## Smallest Next Mechanism - -Define `VerifierKeySet`, `AuthorityCertificateStatusRecord`, and `AuthorityCertificateVerificationResponse` as protocol-owned types. Make JWKS a projection from that model rather than the trust model itself. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/EXECUTION.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/EXECUTION.md deleted file mode 100644 index 5a1fdee..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/EXECUTION.md +++ /dev/null @@ -1,284 +0,0 @@ -# Execution Perspective - -## Invariant At Stake - -Terminal certificate evidence may become portable, but it must not become permission, identity, settlement, certification, or downstream success. The verifier can answer only: this terminal evidence is structurally and cryptographically consistent with this pinned verifier trust posture and status record. - -## Ordered Slices - -### Slice 0 - Claim Guard Before Code - -Goal: prevent implementation from smuggling product claims into names, docs, routes, CLI output, or tests. - -Candidate paths: - -- `docs/internal/decisions.md` -- `docs/internal/protocol-notes.md` -- `README.md` -- `src/**/authority-certificate*` -- `src/**/cert*` -- `test/**/authority-certificate*` -- `scripts/**/quality*claims*` - -Execution: - -1. Add or update internal wording that says verifier responses are evidence-plane only. -2. Ban language like certified, trusted agent, authorized, approved, settled, cleared, identity verified. -3. Make CLI and hosted verifier response wording use evidence-valid phrasing, not authority phrasing. - -Stop if existing product copy treats a valid certificate as authority. - -### Slice 1 - Issuer / Signer / Key Version Read Model - -Goal: expose trust posture used during verification without changing verification semantics. - -Candidate source paths: - -- `src/protocol/areas/authority-certificate/schemas.ts` -- `src/protocol/areas/authority-certificate/verify.ts` -- `src/protocol/areas/authority-certificate/key-set.ts` - -Candidate tests: - -- `test/protocol/authority-certificate.test.ts` -- `test/protocol/authority-certificate-verifier.test.ts` -- `test/protocol/verifier-trust.test.ts` - -Implement: - -- `VerifierTrustKey` -- `VerifierKeyStatus = active | retired | revoked` -- `VerifierSignerRole` -- `VerifierKeyVersion` -- `VerifierTrustSnapshot` -- deterministic lookup by issuer, key id, algorithm, role, and status. - -Validation gates: - -- active signing key verifies; -- retired key verifies only when allowed by explicit historical semantics; -- revoked key does not verify once status slice lands; -- unknown key id fails closed; -- role mismatch fails closed. - -Trap: `issuer` is local verifier namespace, not legal identity. - -### Slice 2 - RFC 7517 JWKS Projection - -Goal: publish or expose public verifier keys as a JWK Set projection of local pinned trust material. - -Candidate source paths: - -- `src/protocol/areas/authority-certificate/key-set.ts` -- `src/protocol/areas/authority-certificate/jwks.ts` -- `src/http/verifier-metadata.ts` - -Candidate tests: - -- `test/protocol/verifier-key-set.test.ts` -- `test/http/verifier-metadata.test.ts` - -Implement: - -- `toPublicJwkSet(trustSnapshot)`; -- public members only: `kty`, `kid`, `alg`, `use` or `key_ops` if locally modeled; -- private material exclusion; -- stable ordering by `kid`; -- optional metadata projection with `jwks_uri` following RFC 8414 shape without claiming OAuth/OIDC semantics. - -Validation gates: - -- serialized JWKS contains no private fields; -- HMAC keys are rejected from production projection; -- unsupported algorithms fail closed; -- duplicate `kid` fails closed; -- active and retired public keys can appear if historical portability requires it; -- revoked keys are either excluded or status-marked only in status plane, not silently trusted. - -### Slice 3 - Revocation / Status Record - -Goal: add verifier-owned status plane for terminal certificates and signer keys. - -Candidate source paths: - -- `src/protocol/areas/authority-certificate/status.ts` -- `src/protocol/areas/authority-certificate/verify.ts` -- `src/protocol/store/` only if existing store ownership fits. - -Candidate tests: - -- `test/protocol/certificate-status.test.ts` -- `test/protocol/authority-certificate-revocation.test.ts` - -Implement: - -- `CertificateStatusRecord`; -- statuses: `active`, `revoked`, `stale`, `unknown`, `status_unavailable`; -- revocation reason codes as controlled enum; -- status lookup result included in verification response; -- fail-closed behavior for required online status when unavailable; -- local/in-memory status adapter first unless existing durable storage abstraction fits. - -Validation gates: - -- revoked certificate fails verification; -- stale certificate fails or returns non-valid response based on explicit policy; -- status unavailable fails closed when status is required; -- no RFC 7009 certificate semantics. - -### Slice 4 - Verification Response Projection - -Goal: create an audit-safe response object separate from internal verifier diagnostics. - -Candidate source paths: - -- `src/protocol/areas/authority-certificate/verification-response.ts` -- `src/protocol/areas/authority-certificate/verify.ts` -- `src/cli/certificate.ts` -- `src/http/authority-certificate-verifier.ts` - -Candidate tests: - -- `test/protocol/authority-certificate-verification-response.test.ts` -- `test/cli/cli-evidence.test.ts` - -Implement response fields: - -- `result: valid | invalid | revoked | stale | status_unavailable` -- `artifactKind` -- `envelopeDigest` -- `terminalEvidenceBinding` -- `gatewayAdmissionBinding` -- `issuer` -- `kid` -- `signerRole` -- `keyVersion` -- `statusCheckedAt` -- `verificationCheckedAt` -- `failureReasons[]` -- `auditWarnings[]` - -Validation gates: - -- response never exposes private key material; -- response never says permission, authorization, settlement, or certification; -- response distinguishes gateway admission binding from downstream execution evidence; -- missing evidence is a proof gap, not successful verification. - -### Slice 5 - Hosted Verifier Route - -Goal: non-mutating hosted verifier endpoint that accepts a certificate and returns the audit-safe projection. - -Candidate source paths: - -- `src/http/authority-certificate-verifier.ts` -- `src/http/routes/authority-certificate.ts` -- `src/http/server.ts` -- `src/http/verifier-metadata.ts` - -Candidate tests: - -- `test/http/authority-certificate-verifier.test.ts` -- `test/integration/authority-certificate-verifier-route.test.ts` - -Implement: - -- `GET /.well-known/handshake-verifier`; -- `GET /verifier/jwks.json`; -- `POST /verifier/authority-certificates/verify`; -- request size limits; -- schema validation; -- no mutation, minting, admission, or policy greenlight creation. - -Validation gates: - -- malformed certificate returns invalid projection, not crash; -- oversized request rejected; -- route cannot create or update status records; -- unavailable status store produces explicit `status_unavailable`; -- hosted response matches protocol verifier response. - -### Slice 6 - CLI Parity - -Goal: CLI and hosted verifier share the same verifier core and response projection. - -Candidate paths: - -- `src/cli/certificate.ts` -- `src/cli/index.ts` -- `src/protocol/areas/authority-certificate/verify.ts` - -Candidate tests: - -- `test/cli/cli-evidence.test.ts` -- `test/integration/cert-verify-smoke.test.ts` - -Validation gates: - -- CLI rejects HMAC production certificates; -- CLI valid output does not imply authority; -- CLI and hosted route produce equivalent projection for same certificate/trust/status fixture. - -### Slice 7 - Claim / Architecture Quality Gate - -Goal: make forbidden semantics hard to regress. - -Candidate paths: - -- `scripts/check-claims*.mjs` -- `test/architecture/claim-boundary.test.ts` -- `docs/internal/protocol-notes.md` - -Validation: - -- guard forbidden strings near verifier/certificate routes; -- fixture tests prove response wording; -- docs state terminal verifier trust plane is evidence portability only. - -## Dependency Graph - -```text -Slice 0 Claim Guard - -> Slice 1 Trust Read Model - -> Slice 2 JWKS Projection - -> Slice 3 Status Record - -> Slice 4 Verification Response Projection - -> Slice 5 Hosted Verifier Route - -> Slice 6 CLI Parity - -> Slice 7 Quality Gate -``` - -Parallelizable after Slice 1: - -- JWKS projection and status record can proceed independently. -- Hosted route and CLI parity can proceed in parallel after Slice 4. -- Claim guard can start immediately and continue through all slices. -- Tests for fixtures can be prepared in parallel once response schema is fixed. - -## Closeout Commands - -```bash -npm run test -- test/protocol/authority-certificate.test.ts -npm run test -- test/protocol/authority-certificate-verifier.test.ts test/protocol/verifier-key-set.test.ts test/protocol/certificate-status.test.ts -npm run test -- test/http/authority-certificate-verifier.test.ts test/cli/cli-evidence.test.ts -npm run quality:claims -npm run quality:architecture -npm run format:check -npm run check:repo -``` - -## Rollback / Stop Conditions - -Stop implementation if: - -- verifier response implies authorization, identity, settlement, or certification; -- JWKS projection exposes private or symmetric key material; -- revocation/status check silently degrades to valid; -- route creates greenlights, admissions, receipts, or mutations; -- certificate validity is treated as downstream business success; -- one verifier key can satisfy multiple roles without explicit role binding; -- unknown key, unknown issuer, unknown status, or unsupported algorithm passes open. - -## Smallest Next Mechanism - -Add the verifier trust read model and public JWKS projection tests first: pinned key input, deterministic public JWK Set output, no private/HMAC material, stable key id/role/version metadata, and no change to existing `AuthorityCertificate` verification semantics. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/RISK.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/RISK.md deleted file mode 100644 index d39c8d3..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/RISK.md +++ /dev/null @@ -1,104 +0,0 @@ -# Risk And Security Perspective - -## Invariant At Stake - -A terminal `AuthorityCertificate` is portable evidence, not permission. Verification must never imply authority, identity, settlement, compliance certification, clearing-house status, or downstream business success. - -## Risk Posture - -- Stale key: fail closed unless the certificate proves it was signed during an accepted key validity window and status data is available for that window. -- Revoked key: refuse verification with a precise reason such as `revoked_signing_key` or `revoked_issuer_keyset`, not generic invalidity. -- Status outage: return `proof_gap` or `status_unavailable`; never return `valid`. -- Unknown issuer, tenant, role, or key version: refuse, not warn. -- Raw evidence exposure: never return full terminal evidence from hosted verification; return audit-safe projections only. -- Hosted verifier abuse: rate-limit, size-limit, require deterministic parsing, reject recursive fetches, and never fetch arbitrary `jwks_uri` supplied by a certificate. -- Replay/tamper: certificate verification must bind envelope digest, signing input digest, artifact kind, terminal event id, gateway admission id, and issuer key version. -- OAuth/JWKS confusion: use JWK/JWKS only as key representation. Do not import OAuth authorization, token revocation, introspection, identity provider, or bearer-token language. -- x402 overfitting: x402 is the first protected-action wedge, not verifier ontology. Keep action kind, gateway binding, and evidence projection generic. -- Claim drift: guard all docs/CLI/API strings so valid certificate means only signature, binding, status, and projection checks passed. - -## Required Security Mechanisms - -### Issuer / Verifier Read Model - -- `issuer_id` -- `tenant_scope` -- `signer_role` -- `key_id` -- `key_version` -- `key_status: active | retired | revoked` -- `valid_from` -- `valid_until` -- `revoked_at` -- `revocation_reason` -- `allowed_artifact_kinds` - -### Verifier Key Set Projection - -- Publish public verification keys as RFC 7517 JWK Set. -- Protect non-public key material by never placing it in projections, logs, fixtures, or snapshots. -- Treat `kid` as selector metadata, not proof of trust. -- Bind accepted keys to local/pinned issuer trust configuration. - -### Status / Revocation Check - -- Local status record first. -- Optional hosted status endpoint later. -- No OAuth revocation semantics. RFC 7009 contributes only security lessons: authenticated status changes, non-leaky responses, replay resistance, and clear client behavior. -- Verification must distinguish `revoked`, `unknown`, `retired_outside_window`, and `status_unavailable`. - -### Hosted Verification Response - -Response states: - -- `verified` -- `refused` -- `proof_gap` - -Never return authorized, approved, paid, settled, certified, trusted, or compliant. - -Include only redacted projection: - -- certificate id; -- issuer id; -- key version; -- artifact kinds; -- terminal evidence kind; -- gateway binding presence; -- status result; -- refusal/proof-gap reason. - -### Admission / Terminal Binding - -Verification remains invalid unless the certificate binds both exact gateway admission evidence and exact terminal evidence artifact. A certificate without gateway binding is evidence-plane residue, not Handshake evidence. - -## Validation Gates - -- Golden tests for active, retired-valid-window, retired-outside-window, revoked, unknown key, wrong role, wrong tenant, wrong artifact kind. -- Hosted verifier tests for oversized payloads, malformed JWK, bad key id, duplicate keys, algorithm confusion, and arbitrary `jwks_uri` injection. -- Claim-guard tests banning permission/identity/settlement/certification language in CLI, API responses, docs, and examples. -- Redaction tests proving raw terminal evidence and non-public key material never appear in hosted responses. -- Status-outage tests proving verifier returns proof gap/status unavailable, not verified. -- Replay tests proving reused certificate material cannot validate against a different terminal artifact, gateway admission, tenant, or artifact kind. -- x402 regression tests proving x402 examples do not leak into generic verifier schemas. - -## Antipatterns To Cut - -- Valid certificate means the action was allowed. -- JWKS means OAuth trust. -- Revocation endpoint means OAuth token revocation. -- Hosted verifier is a source of authority. -- Retired key is always invalid. -- Status unavailable but signature valid, so pass. -- Return raw evidence so integrators can inspect it. -- Use x402 names in core verifier schema. -- Trust any `jwks_uri` referenced by the certificate. -- One verifier response doubles as audit receipt and business success proof. - -## Brutal Verdict - -Keep the terminal verifier trust plane, but narrow it hard: it verifies evidence binding and key/status posture only. Anything broader is trust confusion. The dangerous failure is not bad cryptography; it is letting a portable evidence artifact become ambient authority wearing certificate language. - -## Smallest Next Mechanism - -Build a local issuer/key-status read model plus verifier result enum `verified | refused | proof_gap`, with stale/revoked/status-unavailable tests before any hosted route. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/STRATEGY.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/STRATEGY.md deleted file mode 100644 index a515f71..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/raw/STRATEGY.md +++ /dev/null @@ -1,145 +0,0 @@ -# Strategy Perspective - -## Invariant At Stake - -Portable terminal evidence must not become portable permission. An `AuthorityCertificate` can prove that Handshake recorded terminal evidence for an exact action contract under a pinned verifier trust set. It must not imply identity, settlement, compliance, certification, business success, or authority to mutate anything. - -## Strategy Posture - -Handshake should position this work as an evidence portability layer for protected automated actions, starting with x402 exact per-call paid HTTP. The wedge is not "x402 support." The wedge is that paid HTTP calls are consequential, frequent, atomic, externally observable, and naturally require proof that an exact call was greenlit or refused before consequence. - -The verifier trust plane should make terminal evidence portable across systems without expanding Handshake's role. Handshake issues and verifies evidence. It does not become a payment processor, identity provider, certificate authority, compliance auditor, or clearing house. - -## Category Boundaries - -Keep: - -- `AuthorityCertificate` as signed terminal evidence. -- Verifier key sets as public trust material. -- Revocation/status as evidence freshness and trust-state checks. -- Verification response as an audit-safe projection. -- x402 as the first protected-action surface. - -Cut: - -- certificate means approved; -- certificate means paid; -- certificate means the principal authorized all downstream effects; -- certificate means the actor is trusted; -- certificate means settlement succeeded; -- certificate means compliance; -- certificate authority language unless Handshake intentionally accepts CA expectations, liability, lifecycle, audits, and revocation semantics. - -Preferred language: - -- terminal evidence certificate; -- evidence verifier; -- verifier key set; -- certificate status; -- audit-safe verification response; -- protected action evidence. - -Avoid: - -- trust network; -- identity layer; -- payment certification; -- settlement proof; -- authorization certificate; -- approved certificate; -- clearing house. - -## x402-First Wedge Implications - -x402 is strategically useful because it forces exactness: - -- one paid HTTP request; -- one gateway admission; -- one terminal outcome; -- one receipt/refusal/proof gap; -- one certificate; -- one verifier response. - -That maps cleanly onto Handshake's core primitive. - -x402 is also dangerous because the market will try to pull Handshake into protocol claims: payment validity, payer identity, merchant trust, settlement finality, and dispute resolution. Reject that pull. Handshake's job is to prove whether the automated actor had a gateway-bound terminal evidence record for the exact protected call. Payment protocol semantics remain outside the product boundary. - -The product claim should be: - -> For x402-protected automated calls, Handshake makes the terminal evidence portable: what exact action was proposed, what terminal evidence exists, which verifier key signed it, whether the certificate is currently verifiable, and what must remain unknown. - -## Adoption Sequence - -1. Local verifier model: add issuer/signer role/key-version read models over existing pinned trust material. No hosted route yet. Prove the trust vocabulary without network product surface. -2. Public key-set projection: expose RFC 7517-shaped JWK Set projection for active and retired verifier public keys. Protect non-public material. Include key ids and signer roles without turning this into identity. -3. Status and revocation records: add certificate status records: `active`, `revoked`, `stale`, `unknown`, `status_unavailable`. Treat unavailable status as a verification failure unless explicitly configured otherwise. -4. Verification response plane: return redacted, audit-safe verification responses with certificate digest, terminal evidence kind, issuer, signer role, key id/version, status, checked-at, artifact checks, gateway binding, terminal binding, and explicit non-claims. -5. Hosted verifier route: add a read-only route that verifies submitted certificates against projected key set and status store. It must be non-mutating and must not mint authority. -6. x402 integration profile: define the minimal verification profile an x402 receiver or auditor needs: exact paid-call contract digest, terminal evidence kind, gateway admission binding, certificate status, and proof-gap handling. - -## Cut Lines - -- Do not build settlement proof. -- Do not build principal identity assertions. -- Do not build merchant reputation. -- Do not build generalized credentials. -- Do not build org-wide trust federation. -- Do not allow verification response consumers to treat `valid` as safe to execute. -- Do not use RFC 7009 semantics directly. Borrow only the security lesson: revocation/status endpoints require careful authentication, denial-of-service posture, and status ambiguity handling. -- Do not expose raw receipts if the verifier response can answer the audit question with redaction. - -## Assumptions - -- x402 paid HTTP calls remain atomic enough to model as one protected action attempt. -- The current certificate signing model already binds terminal evidence to envelope digest, signing input digest, signer role, gateway admission, and terminal artifact kind. -- Local pinned trust material is acceptable for the next phase but not sufficient for external verifier adoption. -- External consumers need portable evidence, not raw internal receipt stores. -- Revocation/status is about trust in certificate evidence, not undoing the underlying action. - -## Dependencies - -- Stable certificate schema and digest canonicalization. -- Public-key signing path suitable for production. -- Key id and key version model. -- Signer role model. -- Issuer model. -- Status store with revocation reason and checked-at timestamps. -- Audit-safe redaction policy. -- Claim guard copy and tests preventing overstatement. -- x402 action-contract profile defining required fields and evidence expectations. - -## Risks - -- `valid: true` becomes authorization theatre if the response does not say what validity means. -- Hosted verifier becomes a de facto trust authority if product language drifts. -- Revocation gets misread as payment cancellation. -- x402 positioning gets mistaken for protocol infrastructure rather than protected-action enforcement. -- Status-unavailable handling becomes a soft pass under adoption pressure. -- Key rotation breaks old audits if retired keys are not verifiable with clear status. -- Redaction strips too much, making the response useless for reconstruction. -- Redaction strips too little, leaking principal, action, or business-sensitive data. - -## Validation Gates - -- A certificate with a valid signature but revoked status must fail verification. -- A certificate signed by a retired-but-allowed key must verify only according to explicit policy. -- A certificate with unknown key id must fail. -- A certificate with valid signature but missing required terminal artifact kind must fail. -- A certificate with valid receipt evidence but no gateway admission binding must fail. -- A certificate with proof-gap terminal evidence must verify as a proof gap, not as success. -- Hosted verifier must be read-only and non-mutating. -- Verification response must include explicit non-claims. -- Claim guard must reject valid certificate means approved/paid/authorized/settled/certified. -- x402 profile must prove one protected paid-call attempt, not generalized payment legitimacy. - -## 10-Star Bar - -A 10-star version makes an external x402 receiver or auditor comfortable asking one narrow question: - -> Does this submitted terminal evidence certificate verify against Handshake's published verifier keys and current status policy, and what exact protected-action evidence does it prove or fail to prove? - -The answer is deterministic, redacted, reconstructable, and boring. It includes enough evidence to audit the exact protected action attempt. It refuses to imply authority. It survives key rotation. It handles revocation and stale status explicitly. It treats proof gaps as first-class outcomes. It makes overclaiming hard in code, docs, and API shape. - -## Smallest Next Mechanism - -Build the verifier read model and response contract first: issuer, signer role, key id/version, active/retired status, certificate status, verification result, terminal evidence projection, and explicit non-claims. Then expose the same model through a JWKS projection and only after that through a hosted verifier route. diff --git a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/synthesis.md b/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/synthesis.md deleted file mode 100644 index 84f8ceb..0000000 --- a/.planning/macro/archive/implemented-sprints/2026-05-24-tier2-macro-closeout/terminal-verifier-trust-plane/runs/terminal-verifier-trust-plane-20260524T074226Z/synthesis.md +++ /dev/null @@ -1,75 +0,0 @@ -# Synthesis: Terminal Verifier Trust Plane - -## Chair Read - -The perspectives converge on one hard boundary: the trust plane must make `AuthorityCertificate` portable without letting portability become authority. - -The weak version of this initiative would publish keys, add a hosted `/verify`, and market certificates as proof that an x402 call was paid or approved. That is advisory theatre. The strong version separates evidence, discovery, and trust decision planes, then gives external receivers a structured answer about exact terminal evidence. - -## Coherent Sequence - -The correct order is: - -1. Claim guard. -2. Trust read model. -3. Native key-set projection. -4. JWKS projection. -5. Status/revocation records. -6. Structured verification response. -7. Hosted discovery/status routes. -8. Hosted verify route. -9. CLI/SDK/MCP parity. -10. x402 evidence profile. - -This order is chosen because hosted verification before status semantics would produce false confidence, and JWKS before native key-set would turn projection into authority. x402 must wait until certificate verification cannot be confused with payment settlement. - -## Key Reconciliations - -Strategy wanted external portability for x402 receivers and auditors. Architecture required plane separation and protocol-owned read models. Execution proposed slices near existing authority-certificate, CLI, HTTP, and tests. Risk forced fail-closed status and redaction. Adoption required CLI/SDK/MCP surfaces without boolean validity shortcuts. - -The merged plan keeps the strategic wedge but makes architecture and risk constraints the gate. x402 is not allowed to define certificate meaning. - -## Chosen Primitive - -The primitive is structured terminal evidence verification: - -- exact certificate; -- exact terminal artifact kind; -- exact signed-over binding; -- exact issuer/key/role/status model; -- exact gateway admission binding; -- exact terminal binding; -- explicit refusal or proof gap when evidence is missing, stale, revoked, or unavailable. - -## Boundaries Preserved - -- Vague intent is not authority. -- Generated action is not permission. -- `AuthorityCertificate` is not greenlight. -- JWKS is not trust. -- Hosted verifier is not mutation. -- Verification is not settlement. -- Redacted audit response is not raw receipt disclosure. - -## Main Product Cut - -Cut every claim that says or implies: - -- certificate means approved; -- certificate means paid; -- certificate means settled; -- certificate means the actor is trusted; -- certificate means compliance; -- certificate means downstream success; -- JWKS means the verifier is trusted. - -The acceptable language is narrower: certificate verifies, refuses, or produces a proof gap against a declared verifier trust plane. - -## Readiness To Execute - -The plan is ready to execute if the team accepts two user-owned decisions: - -- hosted route naming convention; -- initial storage/read-provider posture for status records. - -Neither blocks Phase 0 or Phase 1. The smallest next mechanism is the claim guard followed by the issuer/key-version read model. diff --git a/.planning/macro/concierge-demand-buyer-template.md b/.planning/macro/concierge-demand-buyer-template.md new file mode 100644 index 0000000..28e17c0 --- /dev/null +++ b/.planning/macro/concierge-demand-buyer-template.md @@ -0,0 +1,16 @@ +# Concierge demand buyer worksheet + +**Status: PLANNING SCRATCH — not product canon** (D-62) + +Linked from [concierge-demand-test-scaffold.md](./concierge-demand-test-scaffold.md). Fill-in only; do not cite from product docs. + +| Field | Your notes | +| --- | --- | +| Named buyer (role + org type) | | +| Protected action they care about | | +| Current workaround | | +| Budget / urgency signal | | +| Evidence they would accept as clearance | | +| Disconfirming observation slot 1 | | +| Disconfirming observation slot 2 | | +| Date observed | | diff --git a/.planning/macro/concierge-demand-test-scaffold.md b/.planning/macro/concierge-demand-test-scaffold.md new file mode 100644 index 0000000..97cb845 --- /dev/null +++ b/.planning/macro/concierge-demand-test-scaffold.md @@ -0,0 +1,38 @@ +# Concierge demand test scaffold + +**Status: PLANNING SCRATCH — not product canon** (D-62) + +Operator-track strategy artifact. This file does not create engineering tasks, proof gates, or product authority. Quarantine enforcement lives in plan 05-11. + +## Named buyer hypothesis + +| Field | Notes | +| --- | --- | +| Segment label | _(placeholder — not a real customer name)_ | +| Pain in one sentence | | +| Budget signal | | +| Why now | | +| Disconfirming observation to watch | | + +## Disconfirming evidence checklist + +- [ ] Buyer cannot name a concrete protected action they would clear through Handshake this quarter. +- [ ] Buyer treats admission middleware as sufficient protection (admission-only framing). +- [ ] Buyer will not run a live-fetch readback on a real gateway-held credential path. +- [ ] Buyer expects Handshake to host custody or settle funds (hosted promotion test). +- [ ] Buyer only wants payment-rail plumbing without exact contract + gateway check discipline. + +## Observation protocol + +1. Run one operator-track conversation with the hypothesis fields filled honestly. +2. Record what would **falsify** pull (buyer walks away when asked for gateway-before-mutation evidence). +3. Do not mark product-completion or protocol proof gates from this scaffold. +4. Keep artifacts under `.planning/macro/` only — no `src/`, `test/`, `docs/internal/`, or CI promotion. + +## Explicit boundary + +- **Operator-track execution** — not Phase-05 engineering. +- **Not** proof gate material for `check:repo` or keel audit. +- **Not** promoted to `docs/internal/` or README without a separate canon decision. + +See companion worksheet: [concierge-demand-buyer-template.md](./concierge-demand-buyer-template.md). diff --git a/.planning/phases/02-address-concerns/02-01-PLAN.md b/.planning/phases/02-address-concerns/02-01-PLAN.md new file mode 100644 index 0000000..ec8f397 --- /dev/null +++ b/.planning/phases/02-address-concerns/02-01-PLAN.md @@ -0,0 +1,154 @@ +--- +phase: 02-address-concerns +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/surfaces/boundary-manifest.ts + - test/architecture/surface-boundary-posture.test.ts + - test/architecture/claim-boundary.test.ts +autonomous: true +requirements: + - GOAL-manifest-coverage + - D-05 + - D-07 + - D-08 + - D-20 +must_haves: + truths: + - Every new CLI handler file and public surface export listed in CONCERNS is covered by a boundary-manifest sourceRoots entry + - A2A negotiation support and readback surfaces exist in surfaceIds with evidence_only posture and explicit non-authority flags + - hosted-admission and service-workflow-admission exports map to manifest rows with claimBoundaryLabels + artifacts: + - src/surfaces/boundary-manifest.ts + - test/architecture/surface-boundary-posture.test.ts + key_links: + - surface-boundary-posture.test.ts expectedSurfaceIds includes new surface ids + - cli.operator/cli.evidence sourceRoots include doctor, quality, simulate, state, x402 helper commands +--- + + +Backfill `boundary-manifest.ts` so architecture posture tests apply to all CLI and surface paths called out in CONCERNS.md. + +Purpose: Close the highest-risk debt — unlisted files skip `existingSurfaceFiles()` enforcement (per D-01, D-05, D-20). +Output: New surface IDs, extended sourceRoots, updated expectedSurfaceIds in architecture tests. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/02-address-concerns/02-CONTEXT.md +@.planning/codebase/CONCERNS.md +@src/surfaces/boundary-manifest.ts +@test/architecture/surface-boundary-posture.test.ts +@src/cli/command-manifest.ts +@package.json + + + + + + Task 1: Add A2A and product surface manifest entries (D-05, D-20) + src/surfaces/boundary-manifest.ts + + - src/surfaces/boundary-manifest.ts (cli.operator, cli.evidence, mcp.runtime patterns) + - src/surfaces/a2a-negotiation-support/ingress-admission.ts (A2ANegotiationIngressAdmissionAuthorityBoundarySchema) + - src/surfaces/a2a-negotiation-readback/index.ts (AuthorityBoundarySchema on readback) + - src/surfaces/service-workflow-admission/index.ts + - src/hosted-admission/index.ts + + + Per D-05 and D-20, extend `surfaceIds` with new entries (dot-notation, consistent with existing ids): + - `surfaces.a2a_negotiation` — plane `evidence`, posture `evidence_only`, sourceRoots `["src/surfaces/a2a-negotiation-support"]`, allowedRouteFamilies include `runtime_evidence_write` / `evidence_projection_read` only (no authority route families from `forbiddenAuthorityRouteFamilies`), requiredNonAuthorityFlags mirror A2A ingress boundary literals (`gatewayCheckPerformed: false`, `greenlightCreated: false`, etc.), claimBoundaryLabels include `admission_readback_is_not_receipt_evidence` and `agreement_is_not_permission`. + - `surfaces.a2a_readback` — plane `evidence`, posture `evidence_only`, sourceRoots `["src/surfaces/a2a-negotiation-readback"]`, claimBoundaryLabels preserve `gatewayCheckRemainsFinalEnforcementPoint`. + - `surfaces.service_workflow_admission` — plane `evidence`, posture `evidence_only`, sourceRoots `["src/surfaces/service-workflow-admission"]`, align with `test/architecture/workflow-admission-boundary.test.ts` non-claims. + - `surfaces.hosted_admission` — plane `evidence`, posture `evidence_only` or `setup_only` per existing hosted-admission LANE; sourceRoots `["src/hosted-admission"]` (not `src/http/admission`). + + Do NOT use directory-wide `src/cli/` wildcards (D-07). Do NOT add protocol kernel paths. + + + - `surfaceIds` includes `surfaces.a2a_negotiation`, `surfaces.a2a_readback`, `surfaces.service_workflow_admission`, `surfaces.hosted_admission` + - Each new boundary forbids all entries in `forbiddenAuthorityRouteFamilies` for model/operator surfaces + - `surfaceBoundaryManifest[surfaces.a2a_negotiation].sourceRoots` includes `src/surfaces/a2a-negotiation-support` + + bun test test/architecture/surface-boundary-posture.test.ts + Architecture manifest defines A2A and package-export surfaces with explicit non-authority posture. + + + + Task 2: Extend CLI sourceRoots for unlisted commands (D-05) + src/surfaces/boundary-manifest.ts + + - src/cli/command-manifest.ts (plane per command: host.doctor/mcp.doctor → operator; quality.report → evidence; state.inspect, simulate → operator/evidence) + - src/cli/host/doctor.ts, src/cli/mcp/doctor.ts, src/cli/quality/report.ts, src/cli/state/inspect.ts, src/cli/simulate/x402-payment.ts, src/cli/demo/x402.ts, src/cli/quickstart/x402.ts, src/cli/x402/readiness.ts + - src/surfaces/boundary-manifest.ts (cli.operator, cli.evidence, cli.process entries) + + + Per D-05, add explicit file paths to existing CLI surface `sourceRoots` (not new surface ids unless a command truly needs a new plane): + - `cli.operator`: add `src/cli/host/doctor.ts`, `src/cli/mcp/doctor.ts`, `src/cli/state/inspect.ts`, `src/cli/demo/x402.ts`, `src/cli/quickstart/x402.ts`, `src/cli/x402/readiness.ts` where plane is operator. + - `cli.evidence`: add `src/cli/quality/report.ts`, `src/cli/simulate/x402-payment.ts` where plane is evidence. + - Keep `cli.process` for process supervision only; do not sweep unrelated files. + + Preserve separation of operator vs evidence vs process (D-07). + + + - Each path in CONCERNS.md CLI list appears in at least one manifest `sourceRoots` array + - No single CLI surface uses `src/cli/` as sole root + + bun test test/architecture/surface-boundary-posture.test.ts test/architecture/cli-command-posture.test.ts + New CLI modules are inside manifest sourceRoots; posture tests can walk them. + + + + Task 3: Update expectedSurfaceIds in architecture tests + test/architecture/surface-boundary-posture.test.ts, test/architecture/claim-boundary.test.ts + + - test/architecture/surface-boundary-posture.test.ts (expectedSurfaceIds, existingSurfaceFiles) + - test/architecture/claim-boundary.test.ts + + + Update `expectedSurfaceIds` to match new `surfaceIds` from Task 1. Ensure `existingSurfaceFiles()` traversal includes A2A support files once roots are listed. Add claim-boundary expectations for new surface ids if `claim-boundary.test.ts` enumerates surfaces. + + + - `bun test test/architecture/surface-boundary-posture.test.ts` exits 0 + - `bun test test/architecture/claim-boundary.test.ts` exits 0 + - Test failure message no longer skips `src/cli/host/doctor.ts` or `src/surfaces/a2a-negotiation-support` due to missing roots + + npm run quality:architecture + Architecture tests enforce posture on backfilled surfaces. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Product surface → consumer | MCP/CLI/SDK output must not imply greenlight or gateway check | +| Manifest → CI | Incorrect posture labels create false confidence | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-02-01-01 | Elevation of Privilege | boundary-manifest mis-label | mitigate | evidence_only + forbidden route families on A2A/CLI | +| T-02-01-02 | Information Disclosure | broad sourceRoots wildcard | mitigate | per-file roots only (D-07) | + + + +- `npm run quality:architecture` passes +- Grep confirms CONCERNS CLI paths appear in `boundary-manifest.ts` +- Record in 02-01-SUMMARY.md: count of files walked by `existingSurfaceFiles()` for new surfaces (scorecard vs CONCERNS list) + + + +Manifest backfill complete; architecture tests cover A2A, hosted-admission, service-workflow-admission, and new CLI modules without kernel changes. + + + +Create `.planning/phases/02-address-concerns/02-01-SUMMARY.md` when done + diff --git a/.planning/phases/02-address-concerns/02-01-SUMMARY.md b/.planning/phases/02-address-concerns/02-01-SUMMARY.md new file mode 100644 index 0000000..5695dfb --- /dev/null +++ b/.planning/phases/02-address-concerns/02-01-SUMMARY.md @@ -0,0 +1,32 @@ +# Plan 02-01 Summary — Manifest backfill + +**Completed:** 2026-05-28 +**Phase:** 02-address-concerns + +## What shipped + +- Added `surfaces.a2a_negotiation`, `surfaces.a2a_readback`, `surfaces.service_workflow_admission`, `surfaces.hosted_admission` to `boundary-manifest.ts` with `evidence_only` / `setup_only` posture and explicit claim labels. +- Extended `cli.operator` and `cli.evidence` `sourceRoots` for doctor, quality, simulate, state, x402 helper commands. +- Updated `expectedSurfaceIds` and `modelOrOperatorSurfaces` in `surface-boundary-posture.test.ts`. +- Posture test helper: strip declared non-authority schema literals on evidence-only surfaces so negative-boundary zod fields do not false-positive on `signer` / `receiptExport` substrings. + +## existingSurfaceFiles scorecard (CONCERNS closure) + +| Surface | Roots | Approx. `.ts` files walked | +|---------|-------|---------------------------| +| surfaces.a2a_negotiation | `src/surfaces/a2a-negotiation-support` | 12 | +| surfaces.a2a_readback | `src/surfaces/a2a-negotiation-readback` | 1 | +| surfaces.service_workflow_admission | `src/surfaces/service-workflow-admission` | 1 | +| surfaces.hosted_admission | `src/hosted-admission` | 4 | +| cli.operator (new paths) | +7 files | 7 added to walk | +| cli.evidence (new paths) | +3 files | 3 added to walk | + +## Verification + +- `bun test test/architecture/surface-boundary-posture.test.ts` +- `bun test test/architecture/claim-boundary.test.ts` +- `bun test test/architecture/cli-command-posture.test.ts` + +## Kernel + +No `src/protocol/` transition changes. diff --git a/.planning/phases/02-address-concerns/02-02-PLAN.md b/.planning/phases/02-address-concerns/02-02-PLAN.md new file mode 100644 index 0000000..2185837 --- /dev/null +++ b/.planning/phases/02-address-concerns/02-02-PLAN.md @@ -0,0 +1,143 @@ +--- +phase: 02-address-concerns +plan: 02 +type: execute +wave: 2 +depends_on: ["02-01"] +files_modified: + - test/architecture/manifest-coverage.test.ts + - test/architecture/package-surface.test.ts +autonomous: true +requirements: + - GOAL-manifest-drift-gate + - D-06 + - D-08 +must_haves: + truths: + - CI fails when a new package.json surface export ships without a boundary-manifest entry + - CI fails when a new cli command handler file is not covered by any manifest sourceRoots path + artifacts: + - test/architecture/manifest-coverage.test.ts + key_links: + - Reads package.json exports and cliCommandManifest; compares to boundary-manifest.ts +--- + + +Add an architecture test that prevents manifest drift — the durable fix after one-time backfill (D-06). + +Purpose: Hand-authored posture (D-08) plus automated detection of missing coverage. +Output: `manifest-coverage.test.ts` (or extend `package-surface.test.ts` if cleaner). + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/02-address-concerns/02-CONTEXT.md +@.planning/codebase/CONCERNS.md +@package.json +@src/cli/command-manifest.ts +@src/cli/main.ts +@src/surfaces/boundary-manifest.ts +@test/architecture/package-surface.test.ts +@test/architecture/surface-boundary-posture.test.ts + + + + + + Task 1: Map package exports to manifest surfaces (D-06) + test/architecture/manifest-coverage.test.ts + + - package.json exports block (especially ./surfaces/*, ./hosted-admission) + - src/surfaces/boundary-manifest.ts + - test/architecture/package-surface.test.ts (existing export checks) + + + Create `test/architecture/manifest-coverage.test.ts` that: + - Collects public export subpaths from package.json matching `./surfaces/*`, `./hosted-admission`, and other product surface exports (exclude `.`, `./conformance`, `./adapter-sdk` if internal-only per existing tests). + - For each export, asserts a `surfaceIds` entry exists whose `sourceRoots` includes the dist/source path equivalent (e.g. `./surfaces/a2a-negotiation-readback` → `src/surfaces/a2a-negotiation-readback`). + - Allowlist documented internal exports already covered by `package-surface.test.ts`. + + Fail with actionable message: export X missing manifest surface Y. + + + - Test fails if a new `./surfaces/foo` export is added to package.json without manifest update + - Test passes on current tree after Plan 01 + + bun test test/architecture/manifest-coverage.test.ts + Export-to-manifest drift gate exists. + + + + Task 2: Map CLI handler files to manifest sourceRoots (D-06) + test/architecture/manifest-coverage.test.ts, src/cli/main.ts + + - src/cli/command-manifest.ts (all active commands) + - src/cli/main.ts (handler dispatch map) + - src/surfaces/boundary-manifest.ts (all sourceRoots flattened) + - test/architecture/cli-command-posture.test.ts (cliSource helper if reusable) + + + Extend manifest-coverage test to: + - Resolve each active command's implementation module path (from main.ts imports or a single COMMAND_IMPL map — follow existing cli-command-posture patterns). + - Assert each implementation file path is under at least one manifest `sourceRoots` entry (normalize paths, allow directory prefix match only when root is a specific file path, not `src/cli/` alone). + - Allowlist: `src/cli/command-manifest.ts`, `src/cli/main.ts`, `src/cli/output.ts`, `src/cli/index.ts`. + + Per D-07: test must fail if someone adds `src/cli/` as only root. + + + - Removing a CLI file from manifest sourceRoots causes test failure + - Allowlisted shared files do not require duplicate roots + + bun test test/architecture/manifest-coverage.test.ts + CLI handler coverage gate exists. + + + + Task 3: Negative drift proof (mandatory verifier) + test/architecture/manifest-coverage.test.ts + + Add a self-contained test case (or describe block) that temporarily asserts failure semantics without leaving the repo broken: + - Document in 02-02-SUMMARY.md the exact command to prove drift detection: e.g. add a fake export `./surfaces/__manifest_drift_probe__` in a throwaway branch OR use an in-test synthetic export map fixture that omits manifest row and expect rejection. + - Preferred: in-test fixture object mimicking package.json exports missing manifest — assert helper `assertExportCovered(exportPath)` throws with message containing export path. + + SUMMARY must record: date, command run, observed failure message (premortem gate — not optional spot-check). + + + - 02-02-SUMMARY.md includes "Negative drift proof" section with command + observed failure output + - In-repo test proves missing manifest mapping is detectable without manual branch hack + + bun test test/architecture/manifest-coverage.test.ts + Drift gate proven to fail when coverage is missing. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| CI gate → merge | Uncovered surface ships without review of authority posture | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-02-02-01 | Tampering | new export without manifest | mitigate | manifest-coverage.test.ts fails CI | + + + +- `npm run quality:architecture` passes +- Task 3 negative drift proof recorded in 02-02-SUMMARY.md (mandatory) + + + +Automated manifest drift detection for exports and CLI handlers; complements Plan 01 backfill. + + + +Create `.planning/phases/02-address-concerns/02-02-SUMMARY.md` when done + diff --git a/.planning/phases/02-address-concerns/02-02-SUMMARY.md b/.planning/phases/02-address-concerns/02-02-SUMMARY.md new file mode 100644 index 0000000..1051c42 --- /dev/null +++ b/.planning/phases/02-address-concerns/02-02-SUMMARY.md @@ -0,0 +1,30 @@ +# Plan 02-02 Summary — Manifest drift gate + +**Completed:** 2026-05-28 +**Phase:** 02-address-concerns + +## What shipped + +- Added `test/architecture/manifest-coverage.test.ts`: + - Product exports (`./hosted-admission`, `./surfaces/*`, `./mcp`, `./x402-protected-tool`) must map to manifest `sourceRoots`. + - `./cli` covered by union of `cli.operator`, `cli.evidence`, `cli.process` roots. + - CLI handler implementation files must sit under manifest roots (no `src/cli/` wildcard). + - In-test negative drift proofs for synthetic export and handler paths. + +## Negative drift proof (mandatory) + +**Command:** `bun test test/architecture/manifest-coverage.test.ts` + +**Observed failure messages:** + +- `manifest export coverage failed: export ./surfaces/__manifest_drift_probe__ maps to src/surfaces/__manifest_drift_probe__ but surfaces.a2a_readback sourceRoots do not cover it` +- `manifest CLI handler coverage failed: src/cli/__manifest_drift_probe__.ts is not under any manifest sourceRoots entry` + +## CONCERNS update + +After Plan 01–02, the "Boundary manifest lags new CLI and package export surfaces" tech-debt row is **partially closed** (backfill + drift gate). Remaining: evidence-type separation and hosted projection slices (Plans 03–05). + +## Verification + +- `bun test test/architecture/manifest-coverage.test.ts` — pass +- `bun test test/architecture/surface-boundary-posture.test.ts` — pass diff --git a/.planning/phases/02-address-concerns/02-03-PLAN.md b/.planning/phases/02-address-concerns/02-03-PLAN.md new file mode 100644 index 0000000..235a53f --- /dev/null +++ b/.planning/phases/02-address-concerns/02-03-PLAN.md @@ -0,0 +1,133 @@ +--- +phase: 02-address-concerns +plan: 03 +type: execute +wave: 3 +depends_on: ["02-02"] +files_modified: + - src/surfaces/proof-packets/shared.ts + - src/protocol/evidence-projections/schemas.ts + - src/surfaces/proof-packets/product-completion.ts + - scripts/check-product-completion.mjs + - test/architecture/proof-packets.test.ts +autonomous: true +requirements: + - GOAL-evidence-separation + - D-02 + - D-13 + - D-14 + - D-15 + - D-22 +must_haves: + truths: + - Proof packet authorityBoundary and readbackBoundary literals are shared, not duplicated inconsistently + - product-completion projector and check-product-completion.mjs validate the same blocked/incomplete statuses + - Blocked gates remain blocked (--expect-status unchanged) + artifacts: + - src/surfaces/proof-packets/shared.ts (extended) + - scripts/check-product-completion.mjs + key_links: + - proof-packets.test.ts asserts createsAuthority false on new surfaces +--- + + +Wave 2 foundation: shared evidence-type schemas and proof-packet/script parity (D-02, D-13, D-14). + +Purpose: Stop evidence theatre and closeout drift without touching protocol transitions. +Output: Reusable schema fragments; synchronized product-completion validation. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/02-address-concerns/02-CONTEXT.md +@.planning/codebase/CONCERNS.md +@src/surfaces/proof-packets/shared.ts +@src/surfaces/proof-packets/product-completion.ts +@scripts/check-product-completion.mjs +@test/architecture/proof-packets.test.ts + + + + + + Task 1: Extract shared non-authority schema fragments (D-13) + src/surfaces/proof-packets/shared.ts, src/protocol/evidence-projections/schemas.ts + + - src/surfaces/proof-packets/shared.ts (NonAuthorityBoundary, existing patterns) + - src/surfaces/service-workflow-admission/index.ts (readbackBoundary literal) + - src/surfaces/a2a-negotiation-readback/index.ts + - src/protocol/evidence-projections/schemas.ts + + + Per D-13 step 1, add shared zod fragments in `proof-packets/shared.ts` (or `src/protocol/foundation/evidence-boundary-schemas.ts` if protocol-owned literals are needed — prefer surfaces layer unless kernel types must be shared): + - `EvidenceKindSchema` / `ReadbackBoundarySchema` / `AuthorityBoundaryProofPacketSchema` with `createsAuthority: z.literal(false)` and related fields. + - Export fragments for import by proof-packets, evidence-projections (read paths only), SDK repair typings — do NOT move policy/greenlight schemas into protocol. + + Refactor at least `product-completion.ts` and one admission readback module to import shared fragments (minimal diff proving pattern). Do not split `projections.ts` in this task (secondary per D-13). + + + - `shared.ts` exports reusable authorityBoundary schema used by at least two consumers + - No change to greenlight or gateway transition semantics in `src/protocol/areas/` + + bun test test/architecture/proof-packets.test.ts + Shared evidence boundary schemas exist and are adopted in proof-packet paths. + + + + Task 2: Sync product-completion projector and check script (D-14, D-22) + src/surfaces/proof-packets/product-completion.ts, scripts/check-product-completion.mjs + + - src/surfaces/proof-packets/product-completion.ts + - scripts/check-product-completion.mjs + - package.json pack:check script (--expect-status incomplete) + - test/architecture/product-closeout-bundle.test.ts + + + Per D-14 and D-22: + - Extract shared status enum / gate names used by both TS projector and mjs checker (import from TS build output or duplicate minimal const object in script with comment pointing to projector — prefer single source in TS re-exported for script if existing pattern exists in repo). + - Ensure `check-product-completion.mjs` validates the same fields as projector schema (blocked/incomplete, nonClaims). + - Do NOT change `--expect-status incomplete` to pass early (D-22). + + If script cannot import TS, document parity test that compares sample packet JSON against script expectations. + + + - `node scripts/check-product-completion.mjs --expect-status incomplete` exits 0 + - `bun test test/architecture/product-closeout-bundle.test.ts` exits 0 + - Projector and script both reference same status field names for distribution and launch gates + + npm run check:product-completion 2>/dev/null || node scripts/check-product-completion.mjs --expect-status incomplete + Closeout validation cannot drift between script and projector. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Proof packet → operator narrative | Blocked status must read as proof gap | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-02-03-01 | Spoofing | product-completion misread | mitigate | shared createsAuthority false + blocked status | +| T-02-03-02 | Tampering | script/projector drift | mitigate | D-14 same-patch rule | + + + +- `npm run quality:architecture` passes +- pack:check expect-status values unchanged from before plan + + + +Evidence-type literals centralized for proof surfaces; product-completion script and projector stay aligned; blocked gates unchanged. + + + +Create `.planning/phases/02-address-concerns/02-03-SUMMARY.md` when done + diff --git a/.planning/phases/02-address-concerns/02-04-PLAN.md b/.planning/phases/02-address-concerns/02-04-PLAN.md new file mode 100644 index 0000000..7b273bf --- /dev/null +++ b/.planning/phases/02-address-concerns/02-04-PLAN.md @@ -0,0 +1,184 @@ +--- +phase: 02-address-concerns +plan: 04 +type: execute +wave: 3 +depends_on: ["02-03"] +files_modified: + - test/mcp/mcp-schema-contract.test.ts + - test/mcp/mcp-reference-transcript.test.ts + - src/cli/host/doctor.ts + - src/cli/mcp/doctor.ts + - src/cli/quality/report.ts + - src/cli/simulate/x402-payment.ts + - src/cli/output.ts +autonomous: true +requirements: + - GOAL-evidence-separation + - D-02 + - D-13 +must_haves: + truths: + - MCP tool/resource schemas cannot be mistaken for greenlight or gateway-check authority + - CLI doctor/simulate/quality outputs carry explicit non-authority envelopes + - A2A readback fixtures assert admission vs receipt separation + artifacts: + - test/mcp/mcp-schema-contract.test.ts + - test/product/a2a-external-protocol-evidence.test.ts (extend if exists) + key_links: + - mcp-schema-contract compares catalog to runtime evidence schemas +--- + + +Wave 2 parity and labeling: MCP↔runtime schema alignment, CLI/MCP non-authority output envelopes, A2A evidence tests (D-09–D-12). + +Purpose: Prevent evidence theatre at product surfaces without kernel changes (D-13). +Output: Failing tests if MCP catalog drifts from evidence schemas; structured CLI output labels; human-string sell-test on CLI copy. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/02-address-concerns/02-CONTEXT.md +@src/mcp/catalog.ts +@src/mcp/resources.ts +@test/mcp/mcp-schema-contract.test.ts +@src/cli/output.ts +@src/cli/host/doctor.ts +@src/cli/mcp/doctor.ts + + + + + + Task 1: MCP catalog vs evidence schema parity test (D-13) + test/mcp/mcp-schema-contract.test.ts + + - src/mcp/catalog.ts + - src/mcp/resources.ts + - src/protocol/evidence-projections/schemas.ts + - test/mcp/mcp-schema-contract.test.ts + + + Per D-13 (layered stack step 2), extend or add tests that: + - For each MCP resource/tool that returns evidence readback, assert output schema includes `createsAuthority: false` (or equivalent non-authority marker from shared fragments in Plan 03). + - Assert no MCP tool description or schema property name implies `greenlight`, `gatewayCheckPassed`, or `AuthorityCertificate` issuance unless tool is explicitly labeled proof-gap/read-only. + - Compare catalog entry ids to evidence projection kinds where paired. + + Do not add new MCP tools; test-only + schema annotation fixes if drift found. + + + - Test fails if a catalog tool omits non-authority boundary on evidence-returning tools + - `bun test test/mcp/mcp-schema-contract.test.ts` passes on clean tree + + bun test test/mcp/mcp-schema-contract.test.ts test/mcp/mcp-reference-transcript.test.ts + MCP surface cannot silently claim authority via schema drift. + + + + Task 2: CLI doctor/simulate/quality non-authority envelopes (D-13) + src/cli/output.ts, src/cli/host/doctor.ts, src/cli/mcp/doctor.ts, src/cli/quality/report.ts, src/cli/simulate/x402-payment.ts + + - src/cli/output.ts (existing envelope helpers) + - src/cli/host/doctor.ts, src/cli/mcp/doctor.ts + - src/cli/quality/report.ts, src/cli/simulate/x402-payment.ts + - test/cli/cli-mcp-doctor.test.ts, test/cli/cli-quality-report.test.ts, test/cli/cli-simulate.test.ts + + + Per D-13 (layered stack step 3): + - Add consistent top-level fields on JSON/text output: `evidenceKind`, `createsAuthority: false`, `gatewayCheckPerformed: false` where applicable (reuse shared literals). + - Doctor commands: label readiness as diagnostic, not clearance. + - Simulate x402: label as simulation/proof-gap path, not live settlement. + - Quality report: separate "architecture gate status" from "cleared protected action". + + Update CLI tests to assert envelopes present. Minimal copy changes in human-readable strings where they say "authorized" or "cleared" incorrectly. + + + - `bun test test/cli/cli-mcp-doctor.test.ts test/cli/cli-quality-report.test.ts test/cli/cli-simulate.test.ts` pass + - JSON output from doctor includes createsAuthority false + - Architecture or CLI test greps human-readable doctor/quality/simulate output for forbidden clearance verbs without adjacent proof-gap context: `authorized`, `cleared`, `greenlight issued`, `safe to execute`, `ready to pay` (case-insensitive); allow when paired with `proof gap`, `non-authority`, `diagnostic`, or `simulation` + + bun test test/cli/cli-mcp-doctor.test.ts test/cli/cli-quality-report.test.ts test/cli/cli-simulate.test.ts + CLI outputs cannot be read as authority certificates. + + + + Task 3: A2A external protocol evidence assertions (D-20, D-21) + test/product/a2a-external-protocol-evidence.test.ts + + - test/product/a2a-external-protocol-evidence.test.ts + - test/product/a2a-ingress-admission.test.ts + - src/surfaces/a2a-negotiation-support/external-protocol-evidence.ts + - examples/a2a-negotiated-x402-room/mcp-readback.json (if fixture) + + + Per D-20 and D-21, strengthen tests that: + - Admission ingress records are not interchangeable with terminal receipt evidence. + - External protocol evidence blobs carry proof-gap or non-authority markers. + - Align with manifest claimBoundaryLabels from Plan 01. + + No new A2A protocol authority routes. + + + - Tests assert admission artifact ≠ receipt artifact for same negotiation id + - `bun test test/product/a2a-external-protocol-evidence.test.ts` passes + + bun test test/product/a2a-external-protocol-evidence.test.ts test/product/a2a-ingress-admission.test.ts + A2A evidence chain separation is test-enforced. + + + + Task 4: Runtime ingress ↔ MCP x402 proposal parity (D-13) + test/adapters/x402-bypass-probes.test.ts, test/mcp/mcp-schema-contract.test.ts + + - src/runtime/ingress/registry.ts + - src/mcp/x402-proposal.ts + - test/adapters/x402-bypass-probes.test.ts + - test/integration/x402-d1-http.test.ts (fixture shapes only) + + + Per D-13 step 2, add or extend tests for aligned refusal/binding-mismatch shapes across: + - MCP x402 proposal path + - runtime ingress family for x402 + - action-proposal candidate boundary (read-only assertion on shared reason codes / non-authority flags) + + Use valid, refusal, and binding-mismatch fixtures. Do not add new ingress families (D-11). + + + - Refusal reason codes or boundary literals match between MCP and ingress for same fixture input + - Tests pass without modifying gateway-gate transitions + + bun test test/adapters/x402-bypass-probes.test.ts test/mcp/mcp-schema-contract.test.ts + Cross-surface x402 evidence shapes stay aligned. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| MCP/CLI → agent | Model may treat doctor output as permission | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-02-04-01 | Spoofing | CLI doctor as clearance | mitigate | explicit envelopes (D-10) | +| T-02-04-02 | Repudiation | MCP schema drift | mitigate | parity test (D-09) | + + + +- `npm run quality` or `bun test test/mcp test/cli/cli-mcp-doctor.test.ts test/product/a2a-external-protocol-evidence.test.ts` + + + +MCP and CLI surfaces label evidence vs authority; A2A tests enforce admission/receipt separation. + + + +Create `.planning/phases/02-address-concerns/02-04-SUMMARY.md` when done + diff --git a/.planning/phases/02-address-concerns/02-05-PLAN.md b/.planning/phases/02-address-concerns/02-05-PLAN.md new file mode 100644 index 0000000..bb5ef87 --- /dev/null +++ b/.planning/phases/02-address-concerns/02-05-PLAN.md @@ -0,0 +1,169 @@ +--- +phase: 02-address-concerns +plan: 05 +type: execute +wave: 3 +depends_on: ["02-01"] +files_modified: + - src/http/handlers/hosted-record-scope.ts + - src/http/handlers/raw-read-audit.ts + - src/http/handlers/evidence-read.ts + - src/protocol/evidence-projections/projections.ts + - test/http/hosted-identity-evidence.test.ts +autonomous: true +requirements: + - GOAL-hosted-hardening + - D-03 + - D-04 + - D-16 + - D-17 + - D-18 +must_haves: + truths: + - Raw internal record reads require scope + audit trail + - Hosted evidence read routes return redacted projections, not ambient authority fields + - No new HTTP routes that mint greenlights or gateway checks + artifacts: + - src/http/handlers/raw-read-audit.ts + - test/http/hosted-identity-evidence.test.ts + key_links: + - hosted-record-scope resolver used by evidence-read handlers +--- + + +Parallel hosted-admission hardening: scope enforcement, audit readback, redacted projections (D-03, D-04, D-16–D-18). + +Purpose: Close hosted identity/evidence gaps from CONCERNS without expanding authority HTTP surface. +Output: Tighter scope checks, audit records on raw read, projection redaction tests. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/02-address-concerns/02-CONTEXT.md +@.planning/codebase/CONCERNS.md + +**Priority `audit_read` object types (D-16 — implement projections for these first):** +1. `refusal` — transition evidence; used in hosted identity / admission refusal readback paths +2. `receipt` — receipt evidence; must redact gateway/raw credential fields; never imply permission +3. `greenlight` — policy evidence; projection must not read as reusable authority (readback only) + +@src/http/handlers/hosted-record-scope.ts +@src/http/handlers/raw-read-audit.ts +@src/http/handlers/evidence-read.ts +@src/http/handlers/hosted-readiness.ts +@test/http/hosted-identity-evidence.test.ts + + + + + + Task 1: Enforce hosted record scope on evidence reads (D-16, D-17) + src/http/handlers/hosted-record-scope.ts, src/http/handlers/evidence-read.ts + + - src/http/handlers/hosted-record-scope.ts + - src/http/handlers/evidence-read.ts + - src/http/routes/evidence-read-route-registry.ts + - src/hosted-admission/hosted-caller-identity.ts + - test/http/hosted-identity-evidence.test.ts + + + Per D-16 and D-17: + - Centralize scope resolution: caller role + record type + operation id must match before any internal record read. + - Return structured refusal envelope (not 500) when scope denied; reason codes from foundation/reason-codes. + - Do not add routes under authority route families; evidence read only. + + Extend `hosted-identity-evidence.test.ts` with denied-scope cases. + + + - Out-of-scope record read returns refusal with reason code, not empty 200 + - In-scope read still returns projection payload + - No new POST routes that perform mutations + + bun test test/http/hosted-identity-evidence.test.ts test/http/http.test.ts + Hosted evidence reads are scope-bound. + + + + Task 2: Raw read audit trail (D-18) + src/http/handlers/raw-read-audit.ts, src/http/handlers/internal-record-read.ts + + - src/http/handlers/raw-read-audit.ts + - src/http/handlers/internal-record-read.ts + - src/protocol/events/records.ts (audit event shapes if any) + + + Per D-18: + - On any raw/internal record read path, append audit record: caller id, scope id, record id, timestamp, redaction profile id. + - Audit is evidence-only (createsAuthority false); not a receipt. + - Wire audit into existing internal-record-read handler; avoid duplicate read paths. + + Add test asserting audit record exists after raw read and is reconstructable in readback fixture. + + + - Raw read produces audit evidence distinct from returned projection body + - Test proves audit fields do not include greenlight ids + + bun test test/http/hosted-identity-evidence.test.ts + Raw reads leave reconstructable audit evidence. + + + + Task 3: Redacted audit_read projections (D-03, D-04) + src/protocol/evidence-projections/projections.ts, src/http/handlers/evidence-read.ts + + - src/protocol/evidence-projections/projections.ts + - src/protocol/evidence-projections/schemas.ts + - src/mcp/resources.ts (redaction patterns) + - test/mcp/mcp-resource-redaction.test.ts + + + Per D-03, D-04, and D-16: + - Register redacted projections in evidence-read route registry for priority object types: `refusal`, `receipt`, `greenlight` (see context list). + - Each uses explicit redaction profile id constant shared with MCP (`hosted_audit_read_redacted` or existing profile name if present). + - Strip secrets, principal tokens, raw gateway payloads, greenlight binding material from projection output. + - HTTP evidence-read returns projection only; document proof-gap when full raw chain unavailable. + - Reuse redaction helpers from MCP resource layer where possible (D-04: same redaction semantics HTTP and MCP). + + Extend hosted-identity-evidence tests: sensitive fields absent in projection for at least `refusal` and `receipt`. + + + - Projection output omits fields listed in redaction test fixture + - MCP and HTTP use same redaction profile id constant + + bun test test/http/hosted-identity-evidence.test.ts test/mcp/mcp-resource-redaction.test.ts + Hosted audit readback is redacted and consistent across surfaces. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Hosted HTTP → caller | Scoped read must not leak cross-tenant records | +| Raw read → audit | Audit must not become reusable auth token | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-02-05-01 | Information Disclosure | cross-scope read | mitigate | scope resolver + refusal | +| T-02-05-02 | Elevation of Privilege | audit as permission | mitigate | createsAuthority false on audit records | + + + +- `bun test test/http/hosted-identity-evidence.test.ts` +- Confirm no new routes in `forbiddenAuthorityRouteFamilies` sets + + + +Hosted admission evidence path is scope-checked, audited on raw read, and redacted on projection readback. + + + +Create `.planning/phases/02-address-concerns/02-05-SUMMARY.md` when done + diff --git a/.planning/phases/02-address-concerns/02-06-PLAN.md b/.planning/phases/02-address-concerns/02-06-PLAN.md new file mode 100644 index 0000000..e1517d4 --- /dev/null +++ b/.planning/phases/02-address-concerns/02-06-PLAN.md @@ -0,0 +1,138 @@ +--- +phase: 02-address-concerns +plan: 06 +type: execute +wave: 4 +depends_on: ["02-03"] +files_modified: + - src/surfaces/proof-packets/host-generated-code-containment.ts + - src/surfaces/proof-packets/live-x402/paid-retry.ts + - src/surfaces/product-launch-gate-resolution.ts + - test/architecture/proof-packets.test.ts + - test/architecture/product-launch-gate-resolution.test.ts + - README.md + - docs/internal/decisions.md +autonomous: true +requirements: + - D-09 + - D-10 + - D-11 + - D-12 + - D-15 + - D-22 +must_haves: + truths: + - host-generated-code-containment, live-x402 paid retry, and product completion remain blocked/incomplete in pack:check + - Public copy states proof-gap posture for these gates + - No ingress registry expansion solely to unblock containment + artifacts: + - test/architecture/proof-packets.test.ts + key_links: + - check scripts --expect-status unchanged +--- + + +Wave 4 — honest blocked-gate posture: preserve `--expect-status blocked|incomplete`, tighten non-claims copy, guard against gate weakening (D-09–D-12, D-15, D-22). + +Purpose: Close "evidence theatre" where docs or UI imply readiness while gates stay blocked. +Output: Architecture tests + doc strings; no change to expect-status values. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/02-address-concerns/02-CONTEXT.md +@src/surfaces/proof-packets/host-generated-code-containment.ts +@src/surfaces/proof-packets/live-x402/paid-retry.ts +@src/surfaces/product-launch-gate-resolution.ts +@scripts/check-host-generated-code-containment.mjs +@scripts/check-live-x402-paid-retry.mjs +@test/architecture/proof-packets.test.ts + + + + + + Task 1: Architecture guard on blocked expect-status (D-09, D-12, D-22) + test/architecture/proof-packets.test.ts + + - package.json scripts (pack:check, check:host-generated-code-containment, check:live-x402-paid-retry, check:product-completion) + - test/architecture/proof-packets.test.ts + - test/architecture/product-launch-gate-resolution.test.ts + + + Add tests that read package.json script argv and assert: + - `check-host-generated-code-containment.mjs` includes `--expect-status blocked` (or equivalent constant). + - `check-live-x402-paid-retry.mjs` includes blocked/incomplete expectation per current repo truth. + - `check-product-completion.mjs` includes `--expect-status incomplete`. + + Test fails if someone weakens gates to `pass` or removes expect-status without updating decisions.md. + + Per D-11: assert no new runtime ingress family was added only for containment (grep registry length or snapshot of family ids vs baseline in test). + + + - Weakening expect-status in package.json scripts fails architecture test + - `npm run quality:architecture` passes on current tree + + npm run quality:architecture + CI prevents silent unblocking of proof gates. + + + + Task 2: Non-claims copy on containment and live x402 packets (D-09, D-10, D-15) + src/surfaces/proof-packets/host-generated-code-containment.ts, src/surfaces/proof-packets/live-x402/paid-retry.ts, src/surfaces/product-launch-gate-resolution.ts + + - src/surfaces/proof-packets/host-generated-code-containment.ts (nonClaims, narrative) + - src/surfaces/proof-packets/live-x402/paid-retry.ts + - src/surfaces/product-launch-gate-resolution.ts + - docs/internal/decisions.md (launch gates) + + + Per D-09 and D-10: + - Ensure `nonClaims` and human-readable status text say **adapter-specific transcript proof** for containment, not host-wide enforcement. + - Live x402 packet: state customer-gateway funded retry is proof-gap; reference Phase 03 / deferred (D-03). + - Product launch gate resolutions: npm/MCP registry do not imply authority (D-15). + + Optional: add README one-liner under proof/check section pointing to blocked gates — only if README already documents pack:check; minimal diff. + + Do NOT implement Codex capture in this phase unless already green; D-10 is optional future investment. + + + - proof-packets.test.ts still expects createsAuthority false and blocked statuses + - No new marketing strings claim "host-wide containment" or "live x402 ready" + + bun test test/architecture/proof-packets.test.ts test/architecture/product-launch-gate-resolution.test.ts + Blocked gates read honestly in packet metadata and docs. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Proof packet → release narrative | Blocked status must not be rebranded as shipped | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-02-06-01 | Tampering | expect-status weakened | mitigate | arch test on package.json argv | +| T-02-06-02 | Spoofing | containment overclaim | mitigate | nonClaims copy (D-09) | + + + +- Run pack:check scripts with current expect-status — all exit 0 +- `npm run quality:architecture` + + + +Blocked gates stay blocked; copy and tests prevent theatre and accidental unblocking. + + + +Create `.planning/phases/02-address-concerns/02-06-SUMMARY.md` when done. Include **ROADMAP alignment** note: this phase (`02-address-concerns`) closes CONCERNS manifest/evidence debt; `docs/plans/02-plan-eng-review-authority-hardening.md` remains the separate eng-review authority track — do not duplicate manifest work there without explicit merge. + diff --git a/.planning/phases/02-address-concerns/02-CONTEXT.md b/.planning/phases/02-address-concerns/02-CONTEXT.md new file mode 100644 index 0000000..3908b3f --- /dev/null +++ b/.planning/phases/02-address-concerns/02-CONTEXT.md @@ -0,0 +1,216 @@ +# Phase 02: Address Concerns (edge hardening) - Context + +**Gathered:** 2026-05-28 +**Status:** Ready for planning + + +## Phase Boundary + +Pay down **product-surface and enforcement-boundary debt** documented in `.planning/codebase/CONCERNS.md` while the **protocol kernel stays wedge-agnostic and unchanged in authority semantics**. + +This phase delivers: + +- Closed gaps where new CLI commands, package exports, and A2A surfaces bypass architecture posture enforcement. +- Machine-enforced separation of gateway check, downstream execution, readback, terminal certificate, and proof-packet evidence — without collapsing types in user-facing output. +- Honest proof-gap posture for blocked gates (host containment, live x402, product completion) — no weakening `--expect-status blocked` to fake readiness. +- Targeted hosted-admission hardening on existing paths only (scope/audit/projections), not hosted operation claims. + +This phase does **not** deliver: + +- Live customer-gateway x402 execution, provider custody, settlement, or marketplace claims. +- Host-wide generated-code containment claims. +- New runtime ingress families unless required to close a manifest-listed surface gap (default: no new families). +- Phase 03 preview-deploy scope (protected MCP/CLI deploy wedge) — prepare only via clean boundaries. + +**Evidence basis:** `.planning/codebase/CONCERNS.md` (2026-05-28), advisor research on five decision axes (sequencing, manifest, containment, evidence theatre, hosted slice), `.planning/ROADMAP.md` Phase 02 goals. + + + + +## Implementation Decisions + +### Non-negotiables (kernel integrity) + +- **D-00:** Do not change protocol kernel authority semantics (one-use greenlight, exact gateway check, receipt vs proof-gap distinction) to absorb product debt. Debt closure happens at **surfaces, adapters, manifests, schemas, and architecture tests** — not by relaxing `src/protocol/` transitions or widening greenlight scope. +- **D-00b:** Keep runtime ingress **wedge-agnostic**: registry changes are limited to shared scaffolding or explicit per-family bundles (registry + schemas + bypass probes + tests). Do not embed x402-only or A2A-only logic into `src/protocol/`. +- **D-00c:** Preserve modular package exports: consumers use `handshake-protocol-kernel/hosted-admission` and surface subpaths, not HTTP internals (`test/product/hosted-package-consumer.test.ts` posture). + +### Remediation sequencing (evidence: CONCERNS priority table + architecture test skip behavior) + +- **D-01:** **Wave 1 — boundary manifest + architecture coverage** before any live-proof or ingress-expansion work. Backfill known gaps, then add a CI gate so new exports/CLI handlers cannot ship unlisted. +- **D-02:** **Wave 2 — evidence-type separation** (shared schema fragments, proof-packet/script parity, output labeling) immediately after Wave 1 — prevents blocked `pack:check` outcomes and admission/MCP/doctor readbacks from being read as clearance or execution. +- **D-03:** **Wave 3 — deferred to Phase 03 or dedicated proof gates:** live x402 paid retry, host containment transcript beyond blocked status, hosted operation/custody, auth.md+x402 composite execution marketing. +- **D-04:** Hosted readback work runs as a **bounded parallel track** (projections + scope tightening), not as the lead sequence for CLI/MCP authority hardening. + +### Boundary manifest enforcement (evidence: `existingSurfaceFiles()` skip, six known unlisted paths) + +- **D-05:** One-time **manual backfill** of `src/surfaces/boundary-manifest.ts` for: + - CLI: `src/cli/host/doctor.ts`, `src/cli/mcp/doctor.ts`, `src/cli/quality/report.ts`, `src/cli/state/inspect.ts`, `src/cli/simulate/x402-payment.ts`, `src/cli/demo/x402.ts`, `src/cli/quickstart/x402.ts`, `src/cli/x402/readiness.ts` (grouped under existing `cli.operator` / `cli.evidence` / `cli.process` planes per command role). + - Surfaces: `src/surfaces/a2a-negotiation-support/` (new surface id), `src/surfaces/a2a-negotiation-readback/` (export `./surfaces/a2a-negotiation-readback`). + - Package exports: ensure `./surfaces/service-workflow-admission` and `./hosted-admission` map to manifest rows with explicit `authorityPosture` and `claimBoundaryLabels`. +- **D-06:** Add an **architecture test** that fails when: + - `package.json` `exports` surface subpaths lack a manifest surface + `sourceRoots` entry, and + - `cliCommandManifest` handler implementation files lack coverage under a manifest `sourceRoots` path. + - Use allowlists for shared files (`command-manifest.ts`, `main.ts`, transport helpers). +- **D-07:** **Reject** directory-wide wildcards (e.g. entire `src/cli/`) as the primary fix — preserves operator vs evidence vs process separation. +- **D-08:** **Reject** annotation/codegen-only manifest as the first mechanism — posture metadata (`authorityPosture`, `allowedRouteFamilies`, `claimBoundaryLabels`) stays hand-authored and reviewable; automation only detects drift. + +### Generated-code containment (evidence: blocked `host-generated-code-containment`, three-family registry) + +- **D-09:** Keep `host_generated_code_containment` proof packet and `check-host-generated-code-containment.mjs` at **`--expect-status blocked`** through Phase 02 completion. Public copy must state **host-specific transcript proof**, not host-wide containment. +- **D-10:** When investing in containment evidence, use **Codex-first live adapter transcript** via existing `capture` / `build` / `check` pipeline — not profile/fixture projection as containment proof. +- **D-11:** **Do not** expand runtime ingress registry solely to close the containment gate; ingress expansion is out of scope unless a new family is explicitly scoped in a later phase with full bundle (registry + schemas + bypass probes + arch tests + manifest rows). +- **D-12:** **Do not** drop the containment product gate in favor of bypass-probes-only narrative — that would contradict `product-completion` and `decisions.md` transcript requirements. + +### Receipt and evidence theatre (evidence: listed theatre patterns in CONCERNS) + +- **D-13:** Use a **layered prevention stack** (not documentation-only): + 1. Extract **shared schema fragments** for `evidenceKind`, `readbackBoundary`, `authorityBoundary` used by MCP proposal, runtime ingress, A2A readback, proof packets, SDK repair. + 2. Add **MCP x402 ↔ runtime ingress ↔ action-proposal parity tests** for valid, refusal, and binding-mismatch inputs. + 3. Extend **CLI/MCP/A2A output labeling** to match existing `cliOutput` non-authority envelope patterns (`gatewayCheckPerformed: false`, explicit non-claims). + 4. **Split** monolithic projector files only where review risk is high (`evidence-projections/projections.ts`, `proof-packets/product-completion.ts`) — split is secondary to schema separation. +- **D-14:** Change **proof-packet projectors and check scripts in the same patch** (`product-completion.ts` + `check-product-completion.mjs`) to prevent closeout drift. +- **D-15:** External ship/distribution claims remain **proof-packet-only** with blocked/incomplete expected statuses; npm/MCP registry state does not enter policy or greenlight paths. + +### Hosted admission next slice (evidence: Hosted Admission Lock, scope narrowing gap) + +- **D-16:** **Primary mechanism:** object-specific **redacted projection endpoints** per `audit_read` types in `src/protocol/areas/object-registry/index.ts` — not new generic raw HTTP read surfaces. +- **D-17:** **Parallel mechanism:** tighten **raw-read audit + fail-closed scope** in `src/http/handlers/hosted-record-scope.ts` and `raw-read-audit.ts` — including tests for records missing `projectId`/`workspaceId` in payload. +- **D-18:** **Defer** mandatory `projectId`/`workspaceId` on all `audit_read` schemas until tenancy semantics are proven — do not invent scope fields org-wide without object-type justification. +- **D-19:** **Freeze** expansion of hosted HTTP routes that imply custody, settlement, search, or mutation authority; package-only integrators continue via `./hosted-admission` exports. + +### A2A surfaces (evidence: product tests without surface-boundary-posture coverage) + +- **D-20:** Register **A2A negotiation support and readback** in boundary manifest **now** (Wave 1), with explicit non-authority flags aligned to `A2ANegotiationIngressAdmissionAuthorityBoundarySchema` and readback `AuthorityBoundarySchema`. +- **D-21:** Extend `test/architecture/surface-boundary-posture.test.ts` / `claim-boundary.test.ts` coverage to A2A surface roots — agreement evidence must not read as permission (`gatewayCheckRemainsFinalEnforcementPoint` preserved in readback). + +### Live x402 and product completion (evidence: blocked gates, local/reference only) + +- **D-22:** Keep **live x402 paid retry**, **distribution launch gate**, and **product completion** at blocked/incomplete expected statuses through Phase 02; narrative docs must not outpace `productLaunchGateResolutions` non-claims. +- **D-23:** Phase 03 plan (`docs/plans/03-plan-protected-mcp-cli-preview-deploy.md`) owns preview-deploy and MCP/CLI wedge paths — not this concerns phase. + +### Claude's Discretion + +- Exact manifest surface IDs and `sourceRoots` groupings for new CLI files (must preserve operator/evidence/process separation). +- Which `audit_read` object types get redacted projections first (prioritize types referenced by service-workflow-admission and hosted identity evidence tests). +- File-split boundaries for evidence projectors (follow `STRUCTURE.md` one-concept-per-folder rule). + + + + +## Canonical References + +**Downstream agents MUST read these before planning or implementing.** + +### Authority doctrine and decisions + +- `AGENTS.md` — kernel invariants, generated-code threat model, strategy discipline +- `docs/internal/decisions.md` — Hosted Admission Lock, Evidence Read Boundary, product launch gates +- `docs/internal/protocol-notes.md` — compact protocol notes +- `.planning/codebase/CONCERNS.md` — debt inventory and safe-modification guidance (2026-05-28) +- `.planning/codebase/ARCHITECTURE.md` — authority boundary, x402 flow +- `.planning/codebase/STRUCTURE.md` — where to add code +- `.planning/codebase/TESTING.md` — test commands and architecture test layout +- `.planning/ROADMAP.md` — Phase 02/03 execution order + +### Enforcement surfaces (Wave 1–2 touch points) + +- `src/surfaces/boundary-manifest.ts` — surface posture contract +- `src/cli/command-manifest.ts` — CLI command registry +- `package.json` — public exports map +- `test/architecture/surface-boundary-posture.test.ts` +- `test/architecture/claim-boundary.test.ts` +- `test/architecture/cli-command-posture.test.ts` +- `test/architecture/workflow-admission-boundary.test.ts` +- `test/architecture/negotiation-no-authority-surface.test.ts` + +### Proof packets and blocked gates (honest posture) + +- `src/surfaces/proof-packets/host-generated-code-containment.ts` +- `src/surfaces/proof-packets/live-x402/paid-retry.ts` +- `src/surfaces/proof-packets/product-completion.ts` +- `src/surfaces/product-launch-gate-resolution.ts` +- `scripts/check-host-generated-code-containment.mjs` +- `scripts/check-live-x402-paid-retry.mjs` +- `scripts/check-product-completion.mjs` + +### Runtime and gateway (read-only for this phase unless D-11 exception) + +- `src/runtime/ingress/registry.ts` +- `src/adapters/x402-payment/wallet-gateway.ts` +- `src/protocol/areas/gateway-gate/` + +### Hosted admission (bounded track) + +- `src/hosted-admission/LANE.md` +- `src/http/handlers/hosted-record-scope.ts` +- `src/http/handlers/raw-read-audit.ts` +- `src/protocol/areas/object-registry/index.ts` + + + + +## Existing Code Insights + +### Reusable Assets + +- `src/surfaces/boundary-manifest.ts` + `test/architecture/surface-boundary-posture.test.ts` — posture enforcement framework; needs coverage extension, not redesign. +- `src/surfaces/proof-packets/shared.ts` — `NonAuthorityBoundary`, `authorityBoundary.createsAuthority: false` patterns for proof packets. +- `src/cli/output.ts` — non-authority CLI envelope patterns to extend to new doctor/quality/simulate commands. +- `src/surfaces/a2a-negotiation-support/ingress-admission.ts` — existing admission authority boundary schema for manifest registration. +- Host containment pipeline: `scripts/capture-host-generated-code-containment.mjs`, `scripts/build-host-generated-code-containment-transcript.mjs`, `scripts/check-host-generated-code-containment.mjs`. + +### Established Patterns + +- **Manifest-before-export:** LANE docs require manifest update before new surface/CLI exposure. +- **Blocked-as-proof-gap:** `pack:check` expects blocked/incomplete for gates without live evidence — debt fix must not weaken these expectations. +- **Protocol store atomicity:** D1/memory alignment tests are kernel contracts — do not shortcut for product convenience. + +### Integration Points + +- New architecture test wires `package.json` exports + `cliCommandManifest` → `boundary-manifest.ts`. +- Schema fragments consumed by MCP, runtime ingress, A2A readback, proof packets, SDK repair. +- Hosted projections register in evidence-read route registry (follow existing evidence projection patterns). + + + + +## Specific Ideas + +- User confirmed: kernel is mostly solid; debt is **edge polishing** (surfaces, manifest lag, evidence collapse, proof-gate misreads) — not kernel redesign. +- User delegated to **evidence-based advisor conclusions** (2026-05-28 research): manifest+arch tests first, layered evidence separation, blocked containment with optional Codex transcript later, hosted projections not HTTP expansion, defer live x402 to Phase 03. + + + + +## Deferred Ideas + +### Phase 03 / dedicated proof gates + +- Live customer-gateway x402 paid retry with funded custody and post-gateway signer proof. +- Protected MCP/CLI preview deploy wedge (`docs/plans/03-plan-protected-mcp-cli-preview-deploy.md`). +- Auth.md + x402 composite execution (`readyForCompositeExecution: false` until separate gate). + +### Later phases (capability expansion) + +- Host-wide generated-code containment beyond named-adapter transcripts. +- Runtime ingress family expansion beyond three families (each family = full bundle). +- Mandatory `projectId`/`workspaceId` on all `audit_read` types (until tenancy model proven). +- Provider-grade credential custody lifecycle (vault integration, rotation). +- Hosted operation: custody, settlement, marketplace, cross-org trust, aggregate spend, retention/search. +- MCP Registry acceptance and npm distribution unblocking (update launch-gate evidence when external state changes — do not weaken non-claims). +- Evidence projection batching stress tests (`RECEIPT_TIMELINE_EVENT_BATCH_SIZE` boundary) — low priority. + +### Reviewed alternatives (rejected for this phase) + +- Directory-wide `sourceRoots` wildcards — rejected (D-07): weakens CLI plane separation. +- Documentation/runbook-only evidence theatre fix — rejected (D-13): insufficient vs structured output consumers. +- Drop containment gate; bypass probes only — rejected (D-12): contradicts product-completion contract. +- Expand runtime ingress before manifest gates — rejected (D-11): increases consequential surface without posture enforcement. + + + +--- + +*Phase: 02-address-concerns* +*Context gathered: 2026-05-28* diff --git a/.planning/phases/02-address-concerns/02-DISCUSSION-LOG.md b/.planning/phases/02-address-concerns/02-DISCUSSION-LOG.md new file mode 100644 index 0000000..c5a1743 --- /dev/null +++ b/.planning/phases/02-address-concerns/02-DISCUSSION-LOG.md @@ -0,0 +1,100 @@ +# Phase 02: Address Concerns - Discussion Log + +> **Audit trail only.** Do not use as input to planning, research, or execution agents. +> Decisions are captured in `02-CONTEXT.md`. + +**Date:** 2026-05-28 +**Phase:** 02-address-concerns +**Areas discussed:** sequencing, manifest enforcement, containment proof, evidence theatre, hosted slice, A2A registration, live x402 gates + +--- + +## Remediation sequencing + +| Option | Description | Selected | +|--------|-------------|----------| +| Manifest + arch tests first | Stop new surfaces skipping posture enforcement | ✓ | +| Proof separation second | Schema/labeling/gate parity | ✓ | +| Runtime ingress expansion first | Broaden families before gates | | +| Live x402 first | Clear product-completion pressure early | | +| Hosted projections as lead | Hosted read models before CLI hardening | | + +**User's choice:** Advisor-recommended Wave 1 → Wave 2; defer live proof and ingress expansion; hosted as parallel track only. +**Notes:** User: kernel solid, edge debt; preserve wedge-agnostic protocol. + +--- + +## Boundary manifest enforcement + +| Option | Description | Selected | +|--------|-------------|----------| +| Hand backfill + automated drift test | Manual posture rows; CI maps exports/CLI to manifest | ✓ | +| Hand-update only per PR | No automated gate | | +| Directory wildcards | Whole-tree sourceRoots | | +| Codegen/annotations manifest | Generated manifest | | + +**User's choice:** Backfill six+ known gaps (D-05) + automated coverage test (D-06). + +--- + +## Generated-code containment + +| Option | Description | Selected | +|--------|-------------|----------| +| Stay blocked + narrow claims | Honest proof gap | ✓ | +| Codex-first live transcript | Clear gate when ready | ✓ (later, not Wave 1) | +| Expand ingress registry first | More families before transcript | | +| Drop containment gate | Probes only | | + +**User's choice:** D-09 blocked through Phase 02; D-10 Codex path when explicitly scoped. + +--- + +## Evidence theatre prevention + +| Option | Description | Selected | +|--------|-------------|----------| +| Layered: schemas + labeling + arch gates | Machine-enforced separation | ✓ | +| Split files only | Reviewer ergonomics | (secondary) | +| Proof-packet-only external claims | Ship narrative guard | ✓ | +| Documentation only | Runbook | | + +**User's choice:** D-13 layered stack; D-14 projector/script same-patch rule. + +--- + +## Hosted admission next slice + +| Option | Description | Selected | +|--------|-------------|----------| +| Redacted projections per audit_read | Evidence Read Boundary aligned | ✓ | +| Tighten raw-read audit + scope | Fail-closed without new authority | ✓ | +| Mandatory scope on all audit_read | Schema retrofit | (deferred D-18) | +| Freeze hosted HTTP | Claim hygiene only | (partial — no new authority routes) | +| Package-only | npm integrators | ✓ (ongoing, not HTTP fix) | + +**User's choice:** D-16 + D-17 parallel; defer mandatory scope fields. + +--- + +## A2A + live x402 + +| Option | Description | Selected | +|--------|-------------|----------| +| Register A2A in manifest now | Arch test coverage | ✓ | +| Keep live x402/product gates blocked | Phase 02 honest posture | ✓ | + +**User's choice:** D-20, D-22; Phase 03 owns preview deploy (D-23). + +--- + +## Claude's Discretion + +- Manifest surface ID naming and CLI file groupings under operator/evidence/process. +- Order of first `audit_read` projection types. +- Projector file split boundaries. + +## Deferred Ideas + +- Live x402, host-wide containment, hosted operation, auth.md composite — Phase 03+. +- Runtime family expansion — only with full bundle in a future phase. diff --git a/.planning/phases/02-address-concerns/02-PLANS-INDEX.md b/.planning/phases/02-address-concerns/02-PLANS-INDEX.md new file mode 100644 index 0000000..06823c2 --- /dev/null +++ b/.planning/phases/02-address-concerns/02-PLANS-INDEX.md @@ -0,0 +1,47 @@ +# Phase 02 — Executable plans + +**Status:** Executing — Plans 01–02 complete (2026-05-28); Plans 03–06 pending +**Context:** [02-CONTEXT.md](./02-CONTEXT.md) +**Research:** [02-RESEARCH.md](./02-RESEARCH.md) (skipped; CONTEXT + CONCERNS) + +**Premortem adjustments:** Plan 02 mandatory negative drift proof; Plan 04 human-string clearance grep; Plan 05 priority `audit_read` types (`refusal`, `receipt`, `greenlight`); Plan 06 ROADMAP alignment note; Plan 01 existingSurfaceFiles scorecard in SUMMARY. Close CONCERNS manifest row in Plan 02 SUMMARY when drift gate lands. + +## Wave graph + +```text +Wave 1: 02-01 (manifest backfill) → 02-02 (drift gate) +Wave 2: 02-03 (schemas + closeout parity) → 02-04 (MCP/CLI/A2A labeling) +Wave 3: 02-05 (hosted scope/audit/redaction) — parallel after 02-01 +Wave 4: 02-06 (blocked gates honesty) — after 02-03 +``` + +## Plans + +| Plan | File | Depends on | Decisions | +|------|------|------------|-----------| +| 01 | [02-01-PLAN.md](./02-01-PLAN.md) — **done** | — | D-05, D-07, D-08, D-20 | +| 02 | [02-02-PLAN.md](./02-02-PLAN.md) — **done** | 01 | D-06, D-08 | +| 03 | [02-03-PLAN.md](./02-03-PLAN.md) | 02 | D-02, D-13, D-14, D-22 | +| 04 | [02-04-PLAN.md](./02-04-PLAN.md) | 03 | D-02, D-13, D-20, D-21 | +| 05 | [02-05-PLAN.md](./02-05-PLAN.md) | 01 | D-03, D-04, D-16, D-17, D-18, D-19 | +| 06 | [02-06-PLAN.md](./02-06-PLAN.md) | 03 | D-09–D-12, D-15, D-22 | + +## Kernel invariants (all plans) + +- **D-00 / D-00b / D-00c:** No protocol transition or greenlight semantic changes; no wedge logic in `src/protocol/`; preserve modular exports. + +## Deferred (not in these plans) + +- Live x402 paid retry execution (D-03, Phase 03) +- Host-wide containment proof (D-10 optional transcript only) +- Runtime ingress family expansion (D-11) +- Mandatory audit_read tenancy fields (D-18) +- Preview deploy wedge (D-23) + +## Execute + +```bash +/gsd-execute-phase 02-address-concerns +``` + +Recommended order: `01 → 02 → 03 → 04` and `05` after `01`; `06` after `03`. diff --git a/.planning/phases/02-address-concerns/02-RESEARCH.md b/.planning/phases/02-address-concerns/02-RESEARCH.md new file mode 100644 index 0000000..4cf4140 --- /dev/null +++ b/.planning/phases/02-address-concerns/02-RESEARCH.md @@ -0,0 +1,16 @@ +# Phase 02 — Research (skipped) + +**Status:** Skipped per `/gsd-plan-phase 02-address-concerns --skip-research` + +## Inputs used instead + +| Source | Role | +|--------|------| +| `.planning/codebase/CONCERNS.md` | Debt inventory (2026-05-28 map) | +| `.planning/phases/02-address-concerns/02-CONTEXT.md` | Locked decisions D-00–D-23 | +| `.planning/phases/02-address-concerns/02-DISCUSSION-LOG.md` | Advisor audit trail | +| Live codebase spot-check | `boundary-manifest.ts`, `command-manifest.ts`, `package.json` exports | + +## Conclusion + +No separate RESEARCH.md findings required. Executable plans derive directly from CONTEXT waves and CONCERNS severity ordering. diff --git a/.planning/phases/04-service-agent-gating/04-01-PLAN.md b/.planning/phases/04-service-agent-gating/04-01-PLAN.md new file mode 100644 index 0000000..38618d9 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-01-PLAN.md @@ -0,0 +1,172 @@ +--- +phase: 04-service-agent-gating +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - docs/internal/service-workflow-story.md + - docs/internal/protocol-layman.md + - docs/internal/decisions.md + - docs/internal/protocol-notes.md + - test/architecture/dual-enforcement-posture.test.ts + - test/architecture/claim-boundary.test.ts +product_user_audit: applied-2026-05-28 +autonomous: true +requirements: + - D-00 + - D-00b + - D-01 + - D-02 + - D-03 + - D-04 + - D-05 + - D-06 + - D-12 +must_haves: + truths: + - Agent lane docs teach Standing Bounds → Delegated Mandate → Compile → Work Order → Clearance → Outcome with schema-native names unchanged + - Clerk-for-agents framing states admission is middleware identity; adapter gateway check is route-handler enforcement + - Architecture tests fail if docs claim admission alone authorizes mutation + - Ecosystem layer discipline (Layer 0–5) unchanged; no Layer 5 clearing claims added + artifacts: + - docs/internal/service-workflow-story.md + - docs/internal/protocol-layman.md + - docs/internal/decisions.md + - test/architecture/dual-enforcement-posture.test.ts + key_links: + - service-workflow-story.md agent lane maps OperatingEnvelope and DelegatedAuthorityRef per D-01/D-02 + - claim-boundary.test.ts requires dual-enforcement phrases and forbids ingress-only protection claims per D-00 +--- + + +Deliver **S1 — Doctrine & dual-lane canon**: product vocabulary, Clerk-for-agents dual enforcement, and architecture tests that forbid middleware theatre (D-00, D-00b, D-01–D-06, D-12). + +Purpose: Every downstream plan assumes operators understand admission ≠ gateway enforcement. +Output: Agent-lane docs in workflow story + layman, dual-enforcement recorded in decisions/protocol-notes, architecture tests — **no** protocol-definition or ecosystem-strategy prose expansion (04-PRODUCT-USER-AUDIT). + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-CONTEXT.md +@.planning/phases/04-service-agent-gating/04-DELIVERY-ARCHITECTURE.md +@.planning/phases/04-service-agent-gating/PATTERNS.md +@docs/internal/service-workflow-story.md +@docs/internal/protocol-layman.md +@docs/internal/decisions.md +@docs/internal/protocol-notes.md +@test/architecture/claim-boundary.test.ts + + + + + + Task 1: Agent lane vocabulary in service-workflow-story (D-05, D-06, D-01–D-04) + docs/internal/service-workflow-story.md, docs/internal/protocol-layman.md + + Extend `service-workflow-story.md` with a parallel **Agent lane** section (do not replace canonical state path). + + Add mapping table per D-05: + - Standing Bounds → `OperatingEnvelope` (class-level attempt bounds; not permission — D-01) + - Delegated Mandate → `DelegatedAuthorityRef` (episodic mandate evidence; not greenlight — D-02) + - Compile → `IntentCompilationRecord` / `CandidateAction` (no authority — D-03) + - Work Order → `ActionContract` (exact commitment — D-04) + - Clearance → policy + one-use greenlight + gateway check + - Outcome → receipt / refusal / proof gap + + Copy non-authority flag block from existing projection pattern (createsAuthority: false, freshActionContractRequired: true — D-06). + + Mirror shortened chain in `protocol-layman.md` with explicit "does not mean permission" bullets. + + + bun test test/architecture/claim-boundary.test.ts + + Agent lane vocabulary present in both docs with schema-native names and non-authority flags. + + + + Task 2: Record Clerk-for-agents dual enforcement in decisions + protocol-notes (D-00, D-12) + docs/internal/decisions.md, docs/internal/protocol-notes.md + + Add compact **Clerk-for-agents** subsection to `decisions.md` (and one-paragraph cross-ref in `protocol-notes.md`): + Request → http/admission (identity + transition scope) → kernel transitions → service handler (adapter.run*Gateway before mutation) → downstream effect. + + State explicitly per D-00: ingress/admission alone is **advisory**, not Handshake. + + Add D-12 note: external PEP (Envoy/Kong/OPA) may sit in front as deployment glue; Handshake still requires adapter-side observed-parameter re-check. + + **Do not** expand `protocol-definition.md` or `ecosystem-strategy.md` in this phase — canonical protocol docs stay stable; operator journey (plan 02) carries the diagram for TTHW readers. + + + grep -v '^#' docs/internal/decisions.md | grep -c 'run\*Gateway' + + Dual enforcement chain recorded in decisions/protocol-notes without protocol-definition or ecosystem-strategy rewrites. + + + + Task 3: dual-enforcement-posture architecture test (D-00, D-00b) + test/architecture/dual-enforcement-posture.test.ts, test/architecture/claim-boundary.test.ts + + Create `test/architecture/dual-enforcement-posture.test.ts`: + - Scan canonical docs (service-workflow-story, protocol-layman, decisions.md, AGENTS.md, service-operator-golden-path when present) for forbidden phrases implying admission authorizes mutation + - Require phrases: "gateway check before mutation", "admission alone is not Handshake" (or equivalent locked wording) + - Assert x402 remains proof wedge language per D-00b (any-service gating, not payment-only product) + + Extend `claim-boundary.test.ts` with claim matrix entries for dual-enforcement required/forbidden patterns per PATTERNS.md. + + + bun test test/architecture/dual-enforcement-posture.test.ts + + CI fails if docs regress to admission-only protection claims. + + + + Task 4: Canonical state path integrity check (D-06) + test/architecture/claim-boundary.test.ts + + Add claim-boundary test asserting `protocol-definition.md` canonical state path section is unchanged in substance (compile → contract → policy → gateway → receipt) and does not rename schema exports (D-05 product vocabulary only in agent-facing docs). + + Agent lane in service-workflow-story is additive cross-link only — test must fail if agent lane replaces canonical path wording. + + + bun test test/architecture/claim-boundary.test.ts + + Canonical protocol spine preserved; agent lane is parallel projection only. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Doc reader → operator belief | Unqualified "admission" language creates false security | +| Agent lane → protocol kernel | Vocabulary must not imply new authority types | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-01-01 | Elevation | service-workflow-story.md | mitigate | Non-authority flags + architecture test per D-06 | +| T-04-01-02 | Spoofing | protocol-definition.md | mitigate | Dual enforcement diagram; forbid admission=protection | +| T-04-01-03 | Information disclosure | claim-boundary.test.ts | mitigate | Forbidden phrase patterns for middleware theatre | +| T-04-01-SC | Tampering | npm installs | accept | No new packages in this plan | + + + +- `bun test test/architecture/dual-enforcement-posture.test.ts` +- `bun test test/architecture/claim-boundary.test.ts` + + + +- All D-00, D-00b, D-01–D-06, D-12 doc obligations satisfied with automated claim tests +- No protocol kernel or schema export changes + + + +Create `.planning/phases/04-service-agent-gating/04-01-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-02-PLAN.md b/.planning/phases/04-service-agent-gating/04-02-PLAN.md new file mode 100644 index 0000000..464929a --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-02-PLAN.md @@ -0,0 +1,176 @@ +--- +phase: 04-service-agent-gating +plan: 02 +type: execute +wave: 1 +depends_on: [] +files_modified: + - docs/internal/service-operator-golden-path.md + - docs/internal/developer-experience-index.md + - examples/service-operator-golden-path/README.md + - examples/service-operator-golden-path/run.ts + - package.json +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-05 + - D-07 + - D-08 + - D-09 + - D-13 + - D-22 +must_haves: + truths: + - One unified operator journey with step-3 custody fork (service API vs agent host) + - Service operator can follow primary TTHW without reading kernel source or integrator appendix in first 30 minutes + - developer-experience-index Start Here lists service path first; host path only under fork + - npm run demo:service-workflow-admission is the canonical service-side runnable demo + - Golden path documents verify caller → admission/handle → clearance (x402) → readback chain + - Proof-gap families listed in prose (auth.md, package-install, registry) — not runnable-shaped stub packages + artifacts: + - docs/internal/service-operator-golden-path.md + - docs/internal/developer-experience-index.md + key_links: + - service-operator-golden-path.md links demo:service-workflow-admission and plan 03 bootstrap + - developer-experience-index.md references golden path as single operator entry (not dual Start Here) +--- + + +Deliver **S2 — Service-operator golden path product**: unified operator journey, devex index routing, canonized admission demo, D-09 contrast, proof-gap prose (D-05, D-07, D-08, D-09, D-13, D-22). + +Purpose: Service operators get runnable spine narrative before bootstrap CLI lands in plan 03; host operators fork at step 3 — not a second top-level Start Here. +Output: `service-operator-golden-path.md` (includes unified journey), updated devex index, optional golden-path example wrapper. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-CONTEXT.md +@.planning/phases/04-service-agent-gating/04-DELIVERY-ARCHITECTURE.md +@.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md +@docs/internal/developer-experience-index.md +@docs/internal/service-workflow-story.md +@examples/service-workflow-admission/run.ts +@examples/service-workflow-admission/README.md +@package.json + + + + + + Task 1: Author service-operator-golden-path.md with unified operator journey (D-05, D-13, D-09) + docs/internal/service-operator-golden-path.md + + Create `docs/internal/service-operator-golden-path.md` as **primary TTHW** for all operators (service-first). + + **Section 0 — Unified operator journey (required)** + 1. What Handshake is (protected actions; not agent auth) + 2. Dual enforcement (admission = middleware; gateway = route handler — link decisions.md) + 3. **Step 3 — Choose your custody role (fork)** + - **Branch A — I operate the service API** → continue in this doc (default path; first 30 minutes) + - **Branch B — I operate the agent host (MCP/runtime)** → link `host-golden-paths-and-trace-guidance.md`; canonical commands: `host doctor`, `quickstart x402`, `simulate x402-payment`; optional convenience: `quickstart agent-spine` (plan 04 — not required for service operators) + + **Branch A body (service operator)** + - Product chain: Standing Bounds → Delegated Mandate (when required) → Compile → Work Order → Clearance → Outcome (D-05) + - Progressive onboarding: catalog triplet per family first (D-07) + - **Regulated exception (D-09):** full day-one `OperatingEnvelope` + policy pack only for fixed-tenant/regulated — **not** default multi-agent hosted path; contrast table + - Atomic install placeholder for plan 03 bootstrap (D-08) + - **x402 only runnable clearance wedge** (D-13) + - End-to-end: verify caller → admission/handle → clearance → readback + - **Proof-gap list (D-14):** auth.md live gateway, package-install live gateway, MCP registry discoverability — `runnable: false`; do not link to quickstart-shaped stub directories + - **Failure taxonomy (placeholder):** section header "Operator-visible failures" — table filled by plan 05 (`failureClass` × status × safe retry × forbidden actions) + + Include copy-paste command blocks with expected non-authority outputs. + + **Advanced (not first 30 minutes):** single link to `integrator-tier-1-transitions.md` (plan 07 appendix). + + + test -f docs/internal/service-operator-golden-path.md && grep -q 'Step 3' docs/internal/service-operator-golden-path.md && grep -q 'Branch A' docs/internal/service-operator-golden-path.md && grep -qE 'fixed-tenant|regulated' docs/internal/service-operator-golden-path.md && grep -q 'Proof-gap' docs/internal/service-operator-golden-path.md + + Golden path includes unified journey, service branch, host fork, D-09 contrast, proof-gap prose, failure table placeholder. + + + + Task 2: Update developer-experience-index — single Start Here (D-13, D-22) + docs/internal/developer-experience-index.md + + Update `developer-experience-index.md`: + - **Start Here — Operator journey** → `service-operator-golden-path.md` (single entry; includes step-3 fork) + - **Service operator commands** table (first): golden path, `demo:service-workflow-admission`, future `handshake service bootstrap` + - **Host operator commands** table (second, labeled "only if you operate the host"): `host doctor`, `quickstart x402`, `simulate x402-payment`, optional `quickstart agent-spine` + - **Do not** list `integrator-tier-1-transitions.md` in Start Here — move to **Advanced** section with one-line deferral + - **Do not** state "dual runnable spines both required" — state: service API gating is primary buyer path; host branch required only when you operate MCP/runtime binding + - Link `service-workflow-story.md` for plain-language vocabulary + + + grep -v '^#' docs/internal/developer-experience-index.md | grep -c 'service-operator-golden-path' && ! grep -q 'both required' docs/internal/developer-experience-index.md + + Devex index has one Start Here; service-first; integrator doc not in first session. + + + + Task 3: Canonize demo:service-workflow-admission (D-13) + docs/internal/service-operator-golden-path.md, docs/internal/developer-experience-index.md, package.json + + Verify `package.json` script `demo:service-workflow-admission` exists and document it prominently in golden path Branch A and devex index. + + Add step-by-step: run demo → inspect latest.json/latest.md → identify authorityBoundary non-authority flags → follow to x402 clearance readback cross-ref. + + Do not create second runnable path; demo remains admission/handle projection only until gateway step references x402 wedge externally. + + + npm run demo:service-workflow-admission + + Admission demo is canonical service-side runnable artifact in docs and scripts. + + + + Task 4: Optional service-operator-golden-path example wrapper (D-07, D-13) + examples/service-operator-golden-path/README.md, examples/service-operator-golden-path/run.ts + + Add thin wrapper `examples/service-operator-golden-path/` that: + - README points to golden path doc as source of truth + - `run.ts` orchestrates: print doc links → invoke service-workflow-admission demo subprocess → emit summary JSON with nextCommands including future `handshake service bootstrap` + + Keep wrapper non-authority; no kernel transitions beyond what admission demo already performs. + + + bun run examples/service-operator-golden-path/run.ts + + Example wrapper exists and defers to canonical demo + golden path doc. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Operator doc → runtime action | Golden path must not imply demo output grants mutation authority | +| Service vs host persona | Journey fork must not collapse custody boundaries (D-22) | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-02-01 | Elevation | service-operator-golden-path.md | mitigate | Explicit x402-only runnable; non-authority flags on demo outputs | +| T-04-02-02 | Repudiation | demo script | mitigate | latest.json records authorityBoundary | +| T-04-02-SC | Tampering | npm installs | accept | No new packages | + + + +- `npm run demo:service-workflow-admission` +- `bun run examples/service-operator-golden-path/run.ts` + + + +- Single operator journey with step-3 fork; service TTHW in < 30 minutes without integrator appendix +- Admission demo canonized with honest non-authority boundaries + + + +Create `.planning/phases/04-service-agent-gating/04-02-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-03-PLAN.md b/.planning/phases/04-service-agent-gating/04-03-PLAN.md new file mode 100644 index 0000000..0dac532 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-03-PLAN.md @@ -0,0 +1,180 @@ +--- +phase: 04-service-agent-gating +plan: 03 +type: execute +wave: 2 +depends_on: + - 04-01 + - 04-02 +files_modified: + - examples/service-operator-bootstrap/run.ts + - examples/service-operator-bootstrap/README.md + - examples/service-operator-bootstrap/latest.json + - src/cli/service/bootstrap.ts + - src/cli/command-manifest.ts + - src/cli/index.ts + - docs/internal/service-operator-golden-path.md + - test/product/service-operator-bootstrap.test.ts + - test/http/http.test.ts +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-07 + - D-08 + - D-13 +must_haves: + truths: + - Service operator can atomically register x402 catalog triplet via InstallClient recipe + - handshake service bootstrap CLI runs x402-family install only and refuses orphan catalog + - Golden path contains copy-paste bootstrap blocks linked from example + - HTTP install path test proves registerInstallProposalCompiledRecords end-to-end + artifacts: + - examples/service-operator-bootstrap/run.ts + - src/cli/service/bootstrap.ts + - test/product/service-operator-bootstrap.test.ts + key_links: + - bootstrap.ts calls compileX402InstallProposal then InstallClient.registerInstallProposalCompiledRecords per D-08 + - service-operator-golden-path.md links example and CLI command +--- + + +Deliver **S3 — Atomic install executable**: runnable service-operator bootstrap recipe and CLI for x402-family catalog triplet (D-07, D-08, D-13). + +Purpose: Close D-08 executability gap — operators install catalog + gateway + policy atomically or get refusal. +Output: `examples/service-operator-bootstrap/`, `handshake service bootstrap`, product + HTTP tests. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-CONTEXT.md +@.planning/phases/04-service-agent-gating/04-DELIVERY-ARCHITECTURE.md +@src/adapters/x402-payment/install-proposal.ts +@src/sdk/surface-clients/install-client.ts +@src/cli/command-manifest.ts +@docs/internal/service-operator-golden-path.md +@test/http/http.test.ts + + + + + + Task 1: service-operator-bootstrap example recipe (D-07, D-08) + examples/service-operator-bootstrap/run.ts, examples/service-operator-bootstrap/README.md, examples/service-operator-bootstrap/latest.json + + Create `examples/service-operator-bootstrap/` TypeScript recipe: + - Input: tenant/service config fixture (endpoint domain, gateway readiness refs — mirror x402 install-proposal patterns) + - Call `compileX402InstallProposal` from adapter install-proposal module + - On success, call `InstallClient.registerInstallProposalCompiledRecords` against local/test worker URL (use env HANDSHAKE_BASE_URL or in-memory test harness pattern from other examples) + - Write `latest.json` with compiled record refs, refusal reasonCodes on failure, explicit non-authority flags + + README: copy-paste blocks, link to golden path, state x402-only family scope. + + + bun test test/product/service-operator-bootstrap.test.ts + + Example recipe performs atomic install or structured refusal with evidence artifact. + + + + Task 2: handshake service bootstrap CLI (D-08, D-13) + src/cli/service/bootstrap.ts, src/cli/command-manifest.ts, src/cli/index.ts + + Implement `src/cli/service/bootstrap.ts`: + - Command: `handshake service bootstrap` (x402 family only — reject other action families with explicit reason code) + - Parse CLI flags matching example recipe inputs + - Delegate to compileX402InstallProposal + InstallClient path + - Output via cliOutput with authorityCreated: false, nonClaims array + + Register in command-manifest.ts with plane: operator, custodyRole: control_plane, nonGoals including live mutation and second-family install. + + Wire in cli/index.ts main router. + + + bun test test/product/service-operator-bootstrap.test.ts + + CLI command exists in manifest and executes x402 atomic install flow. + + + + Task 3: Product + HTTP install path tests (D-08) + test/product/service-operator-bootstrap.test.ts, test/http/http.test.ts + + Create `test/product/service-operator-bootstrap.test.ts`: + - Happy path: compiled records include ToolCapability, ActionType, GatewayRegistryEntry, **policy pack reference**, and **OperatingEnvelope** record (full D-08 atomic bundle per x402 `buildCompiledKernelRecords`) + - Refusal path: missing gateway readiness → install proposal refuses; no orphan catalog + - CLI smoke: bootstrap command returns ok:false with reasonCodes when inputs incomplete + + Extend `test/http/http.test.ts` install path as reference: POST compiled-records route accepts valid InstallProposal and rejects orphan catalog entries per D-08. + + + bun test test/product/service-operator-bootstrap.test.ts test/http/http.test.ts + + Automated tests prove atomic install contract on example, CLI, and HTTP layers. + + + + Task 4: Golden path copy-paste integration (D-08, D-13) + docs/internal/service-operator-golden-path.md + + Update `service-operator-golden-path.md`: + - Add **Atomic bootstrap** section with commands: `bun run examples/service-operator-bootstrap/run.ts` and `handshake service bootstrap` + - Document expected success/refusal JSON shapes + - Place bootstrap after catalog triplet explanation (D-07) and before agent clearance readback step + - Cross-link InstallClient role-scoped transport (control_plane credential required) + - Link only from golden path Branch A — not from devex Start Here host section or integrator appendix + + + grep -v '^#' docs/internal/service-operator-golden-path.md | grep -c 'service bootstrap' + + Golden path documents executable bootstrap as first-class service operator step. + + + + Task 5: Idempotency smoke for bootstrap re-run (D-08) + test/product/service-operator-bootstrap.test.ts + + Add test case: second bootstrap run with same idempotency key either no-ops cleanly or returns explicit replay/refusal — never creates duplicate gateway registry entries silently. + + Document behavior in example README. + + + bun test test/product/service-operator-bootstrap.test.ts + + Re-run posture is explicit; no silent duplicate catalog commits. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| InstallClient → kernel | Control-plane credential must not imply runtime mutation authority | +| CLI operator → service | Bootstrap must not execute gateway or wallet mutations | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-03-01 | Elevation | service/bootstrap.ts | mitigate | x402-only family guard; non-authority cliOutput flags | +| T-04-03-02 | Tampering | InstallProposal | mitigate | Atomic compiled-records transition; orphan catalog test refusal | +| T-04-03-03 | Spoofing | bootstrap CLI | mitigate | Refuse non-x402 families explicitly | + + + +- `bun test test/product/service-operator-bootstrap.test.ts` +- `bun test test/http/http.test.ts` + + + +- D-08 atomic install is executable via example, CLI, and HTTP tests +- Golden path links bootstrap with copy-paste blocks + + + +Create `.planning/phases/04-service-agent-gating/04-03-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-04-PLAN.md b/.planning/phases/04-service-agent-gating/04-04-PLAN.md new file mode 100644 index 0000000..c717729 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-04-PLAN.md @@ -0,0 +1,170 @@ +--- +phase: 04-service-agent-gating +plan: 04 +type: execute +wave: 2 +depends_on: + - 04-01 + - 04-02 +files_modified: + - src/cli/quickstart/agent-spine.ts + - src/cli/command-manifest.ts + - src/cli/index.ts + - docs/internal/host-golden-paths-and-trace-guidance.md + - docs/internal/developer-experience-index.md + - test/cli/cli-agent-spine-sequencer.test.ts +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-13 + - D-16 + - D-22 + - D-23 +must_haves: + truths: + - handshake quickstart agent-spine is a **recommended** convenience command chaining doctor → x402 quickstart → simulate + - Canonical host path remains discrete commands in devex index (doctor, x402 quickstart, simulate) + - Sequencer steps carry authorityCreated/greenlightCreated/gatewayCheckPerformed/mutationAttempted false + - Anti-theatre tests fail if sequencer bundles execute or reuses greenlight + - Host golden path documents service prerequisite; service golden path host fork does not mandate agent-spine + artifacts: + - src/cli/quickstart/agent-spine.ts + - test/cli/cli-agent-spine-sequencer.test.ts + key_links: + - agent-spine.ts delegates to existing doctor, quickstart/x402, simulate/x402-payment modules per D-16 + - command-manifest lists quickstart.agent-spine as active operator command (recommended, not completion-gate required) +--- + + +Deliver **S4 — Agent-host spine (recommended)**: convenience `quickstart agent-spine` sequencer with anti-theatre tests (D-13, D-16, D-22, D-23). + +Purpose: Host operators can run one bundled non-authority sequencer; discrete commands remain canonical per 04-PRODUCT-USER-AUDIT. +Output: `agent-spine.ts`, CLI manifest entry, sequencer invariant tests, bilateral doc cross-links — **not** a second Start Here or operator-completion requirement. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md +@src/cli/quickstart/x402.ts +@src/cli/host/doctor.ts +@src/cli/simulate/x402-payment.ts +@src/cli/command-manifest.ts +@docs/internal/host-golden-paths-and-trace-guidance.md + + + + + + Task 1: Implement quickstart agent-spine sequencer (D-16, D-13) + src/cli/quickstart/agent-spine.ts + + Create `src/cli/quickstart/agent-spine.ts` mirroring `quickstart/x402.ts` step envelope pattern: + - Step 1: `handshake host doctor` (or host doctor sub-invocation) + - Step 2: `handshake quickstart x402` (existing module) + - Step 3: `handshake simulate x402-payment` (non-authority simulation — D-16) + + Each step records: step id, command string, ok, reasonCodes, evidenceRefs, and literal false authority flags. + + Result includes nonClaims: no bundled execute, no greenlight reuse, no live wallet mutation. + Result description: **convenience sequencer** — equivalent to running the three canonical commands in order. + + Export `runAgentSpineQuickstart` for tests. + + + bun test test/cli/cli-agent-spine-sequencer.test.ts + + Agent spine sequencer chains three existing commands with non-authority envelopes. + + + + Task 2: Register recommended CLI command (D-16) + src/cli/command-manifest.ts, src/cli/index.ts, docs/internal/developer-experience-index.md + + Add manifest entry `quickstart.agent-spine` with aliases `quickstart agent-spine`, status active, plane operator. + + nonGoals must include: bundled execute API, greenlight reuse, authority creation, live x402 operation beyond existing quickstart scope. + + Add manifest metadata or description field marking command as **recommended convenience** — not required for operator-product-completion (plan 12). + + Wire router in cli/index.ts to call agent-spine module. + + Update devex index host table: list doctor → x402 → simulate as canonical; agent-spine as optional bundled equivalent. + + + bun test test/architecture/cli-command-posture.test.ts + + agent-spine in manifest; devex index shows discrete commands as canonical. + + + + Task 3: Anti-theatre sequencer tests (D-16) + test/cli/cli-agent-spine-sequencer.test.ts + + Create `test/cli/cli-agent-spine-sequencer.test.ts`: + - Assert every step has authorityCreated: false, greenlightCreated: false, gatewayCheckPerformed: false, mutationAttempted: false + - Assert result.nonClaims includes forbidden bundled execute language + - Assert no step invokes kernel gatewayCheck or mutation APIs directly (grep/spy on mocked subcommands) + - Assert simulate step warnings include non-authority simulation copy + - Failure injection: if doctor fails, later steps do not claim success theatre + + Pattern from quickstart/x402 tests and host-trusted-binding parity row tables. + + + bun test test/cli/cli-agent-spine-sequencer.test.ts + + Tests fail if sequencer becomes authority-bearing or bundles execute. + + + + Task 4: Bilateral cross-links without mandatory agent-spine (D-22, D-23) + docs/internal/host-golden-paths-and-trace-guidance.md + + Update host golden path doc: + - Add **Service operator prerequisite** section: gateway registry before host attestation (D-22) + - Link `service-operator-golden-path.md` Branch B and bootstrap command + - Frame doctor output as attestation evidence for binding digests (D-23) — not parallel identity system + - Document canonical host commands (doctor, x402 quickstart, simulate) as primary; mention agent-spine as optional convenience only + + **Do not** update service golden path to say agent-spine is mandatory — Branch B already lists discrete commands first. + + + grep -v '^#' docs/internal/host-golden-paths-and-trace-guidance.md | grep -c 'host doctor' + + Bilateral setup order documented; agent-spine optional in host doc. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Sequencer → kernel | Recipe must not create greenlight or perform gateway check (D-16) | +| Doctor output → operator belief | Attestation is evidence only (D-23) | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-04-01 | Elevation | agent-spine.ts | mitigate | Literal false authority flags on every step | +| T-04-04-02 | Spoofing | cli-agent-spine-sequencer.test.ts | mitigate | Forbid bundled execute; mock subcommand boundaries | +| T-04-04-03 | Repudiation | doctor attestation | mitigate | D-23 framing in docs; nonClaims on output | + + + +- `bun test test/cli/cli-agent-spine-sequencer.test.ts` +- `bun test test/architecture/cli-command-posture.test.ts` + + + +- `handshake quickstart agent-spine` ships as recommended convenience with anti-theatre tests green +- Host operators can use discrete canonical commands without agent-spine + + + +Create `.planning/phases/04-service-agent-gating/04-04-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-05-PLAN.md b/.planning/phases/04-service-agent-gating/04-05-PLAN.md new file mode 100644 index 0000000..0275d9e --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-05-PLAN.md @@ -0,0 +1,189 @@ +--- +phase: 04-service-agent-gating +plan: 05 +type: execute +wave: 3 +depends_on: [] +files_modified: + - src/http/errors/transition-error-envelope.ts + - src/http/admission/caller-auth.ts + - src/http/openapi/index.ts + - src/protocol/foundation/reason-code-remediation/index.ts + - docs/internal/service-operator-golden-path.md + - docs/internal/developer-experience-index.md + - test/http/transition-error-failure-class.test.ts +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-17 + - D-18 + - D-19 + - D-20 +must_haves: + truths: + - TransitionErrorEnvelope exposes failureClass and failurePhase separating auth from clearance failures + - HTTP status mapping uses 401/403 auth only; 409 refusals/replay; 422 proof gaps + - OpenAPI documents new envelope fields and status discipline + - Dedicated readback routes can return 200 with claim status; mutation refusals never masquerade as auth 403 + artifacts: + - src/http/errors/transition-error-envelope.ts + - test/http/transition-error-failure-class.test.ts + key_links: + - classifyTransitionError maps HandshakeProtocolError codes to failureClass per D-17 + - caller-auth.ts admission failures emit hosted_admission or auth class not protected_action_refusal +--- + + +Deliver **S5 — Failure taxonomy HTTP + operator-visible failure table**: extend TransitionErrorEnvelope with failureClass, HTTP status discipline, OpenAPI, positive readback tests, and **one** golden-path failure matrix for humans/agents (D-17–D-20). + +Purpose: Service API consumers and agents distinguish credential failures from clearance refusals — single learning surface (plan 06 proves transport parity only). +Output: Envelope schema extension, classification helpers, HTTP tests, OpenAPI docs, failure table in golden path + devex index. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-CONTEXT.md +@.planning/phases/04-service-agent-gating/04-RESEARCH.md +@src/http/errors/transition-error-envelope.ts +@src/http/admission/caller-auth.ts +@src/http/openapi/index.ts +@src/protocol/foundation/reason-code-remediation/index.ts + + + + + + Task 1: Extend TransitionErrorEnvelope schema (D-17, D-19) + src/http/errors/transition-error-envelope.ts + + Add to TransitionErrorEnvelopeSchema (strict, backward compatible): + - failureClass: enum auth | hosted_admission | protected_action_refusal | proof_gap | replay_refusal | stale_admission | internal + - failurePhase: enum admission | transition | readback | null + - problemType: string url nullable (RFC 9457 type URI — D-19) + + Implement failureClassForProtocolError(error) using code prefixes from RESEARCH.md pattern. + + Wire problemType from remediation.docsUrl + code slug where available. + + Do NOT remove existing code/message/retryability fields — SDK compatibility. + + + bun test test/http/transition-error-failure-class.test.ts + + Envelope parses failureClass on all classified errors. + + + + Task 2: HTTP status discipline mapping (D-18) + src/http/errors/transition-error-envelope.ts, src/http/admission/caller-auth.ts + + Implement httpStatusForFailureClass(failureClass) per D-18: + - auth → 401 or 403 (preserve existing caller-auth semantics) + - hosted_admission → 403 + - protected_action_refusal, replay_refusal, stale_admission → 409 + - proof_gap → 422 + - internal → 500 + + Update classifyTransitionError and admission error paths so policy/gateway refusals never map to generic 403 forbidden. + + Add remediation entries in reason-code-remediation for new failure classes with requiresNewContract where appropriate. + + + bun test test/http/transition-error-failure-class.test.ts + + Status codes align with failureClass; clearance failures are not OAuth-style 403. + + + + Task 3: HTTP failure class test suite (D-17, D-18, D-20) + test/http/transition-error-failure-class.test.ts + + Create comprehensive tests: + - Negative cases per failureClass with expected status + - Positive readback case (D-20): dedicated admission/readback route returns 200 + claim status in body — not on mutation attempt routes + - Replay refusal returns 409 + failureClass replay_refusal + - Proof gap returns 422 + - Auth missing bearer returns 401 + failureClass auth + + Use existing HTTP test harness patterns from test/http/. + + + bun test test/http/transition-error-failure-class.test.ts + + Automated matrix covers negative and positive readback posture per D-20. + + + + Task 4: OpenAPI documentation for failure taxonomy (D-19) + src/http/openapi/index.ts + + Update OpenAPI components: + - Document failureClass, failurePhase, problemType on TransitionErrorEnvelope schema + - Document status code expectations per failureClass in route response tables + - Note RFC 9457 problemType URI is additive; primary body remains existing error envelope for SDK + + Do not claim full application/problem+json negotiation in this plan — additive fields only per RESEARCH resolved Q1. + + + bun test test/http/openapi-contract.test.ts + + OpenAPI reflects failure taxonomy fields and status discipline. + + + + Task 5: Operator-visible failure table in golden path + devex index (D-17, D-18) + docs/internal/service-operator-golden-path.md, docs/internal/developer-experience-index.md + + Fill the "Operator-visible failures" section in `service-operator-golden-path.md` with a single table: + + Columns: `failureClass`, typical HTTP status, safe retry?, forbidden actions, what to run next (CLI/SDK hint). + + Rows minimum: auth, hosted_admission, protected_action_refusal, proof_gap, replay_refusal, stale_admission. + + Include OAuth BCP warning: clearance refusals must not be retried as credential refresh. + + Add short pointer in devex index under service operator section — **one table**, not separate HTTP/MCP/SDK cheat sheets (plan 06 extends repair helpers only). + + **Do not** add `handshake failures explain` CLI in this phase — defer; use `explainHandshakeError` after plan 06 wires failureClass. + + + grep -v '^#' docs/internal/service-operator-golden-path.md | grep -c 'failureClass' + + Operators and agents have one failure story entry point in golden path. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| HTTP client → error interpretation | Mis-mapped 403 causes dangerous agent retries | +| Public API → SDK | Envelope extension must remain backward compatible | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-05-01 | Information disclosure | transition-error-envelope.ts | mitigate | D-18 status discipline; no clearance as 403 | +| T-04-05-02 | Elevation | caller-auth.ts | mitigate | Separate auth vs hosted_admission vs refusal classes | +| T-04-05-03 | Repudiation | readback routes | mitigate | D-20 positive 200+claim only on readback routes | + + + +- `bun test test/http/transition-error-failure-class.test.ts` +- `bun test test/http/openapi-contract.test.ts` + + + +- failureClass on all HTTP transition errors with correct status mapping +- OpenAPI documents taxonomy; D-20 readback success pattern tested + + + +Create `.planning/phases/04-service-agent-gating/04-05-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-06-PLAN.md b/.planning/phases/04-service-agent-gating/04-06-PLAN.md new file mode 100644 index 0000000..a731ffd --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-06-PLAN.md @@ -0,0 +1,164 @@ +--- +phase: 04-service-agent-gating +plan: 06 +type: execute +wave: 4 +depends_on: + - 04-05 +files_modified: + - src/sdk/client.ts + - src/sdk/repair.ts + - src/sdk/surface-clients/transport.ts + - src/mcp/x402-proposal.ts + - src/protocol/foundation/failure-class.ts + - test/sdk/role-clients-failure-class.test.ts + - test/mcp/mcp-failure-class-parity.test.ts +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-17 + - D-18 + - D-19 + - D-20 +must_haves: + truths: + - HandshakeClientError carries failureClass parsed from TransitionErrorEnvelope + - SDK Policy/Gateway/Evidence clients surface typed failures with retry guidance + - MCP x402 proposal errors align with HTTP failureClass semantics + - MCP and SDK parity tests agree on classification for same reason codes + artifacts: + - src/protocol/foundation/failure-class.ts + - test/sdk/role-clients-failure-class.test.ts + - test/mcp/mcp-failure-class-parity.test.ts + key_links: + - transport.ts parses failureClass from error envelope body + - mcp/x402-proposal.ts uses shared classifyFailureClass helper +--- + + +Deliver **S6 — Failure taxonomy multi-surface (implementation parity only)**: SDK and MCP parity with HTTP failureClass — **no separate operator-facing docs** (D-17–D-20). + +Purpose: Prove plan 05 golden-path failure table is true on SDK/MCP transports; extend repair helpers to consume failureClass. +Output: Shared classifier, SDK error extension, MCP parity tests, role-client failure tests. Operators read only plan 05 table. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-CONTEXT.md +@src/http/errors/transition-error-envelope.ts +@src/sdk/surface-clients/transport.ts +@src/sdk/client.ts +@src/mcp/x402-proposal.ts +@test/mcp/mcp-x402-proposal.test.ts + + + + + + Task 1: Shared failureClass classifier module (D-17) + src/protocol/foundation/failure-class.ts, src/protocol/foundation/index.ts + + Create `src/protocol/foundation/failure-class.ts`: + - Export FailureClass enum matching HTTP envelope + - classifyFailureClassFromReasonCodes(reasonCodes: string[]): FailureClass + - classifyFailureClassFromProtocolError(error: HandshakeProtocolError): FailureClass + - Map logic shared with HTTP layer (import from foundation in transition-error-envelope to avoid drift) + + Export from foundation/index.ts. + + + bun test test/http/transition-error-failure-class.test.ts + + Single classifier source used by HTTP, SDK, MCP. + + + + Task 2: SDK HandshakeClientError + transport parsing (D-17, D-18) + src/sdk/client.ts, src/sdk/surface-clients/transport.ts, src/sdk/repair.ts + + Extend HandshakeClientError with optional failureClass and failurePhase fields parsed from TransitionErrorEnvelope in transport errorEnvelopeForResponse. + + Update repair.ts and `explainHandshakeError` / `nextHandshakeCommand` to surface failureClass and map to same retry guidance as golden-path table (auth vs requiresNewContract per remediation). + + Preserve existing status and code fields for backward compatibility. + + **Do not** add new `handshake failures explain` CLI — repair helpers are the human/agent normalization surface. + + + bun test test/sdk/role-clients-failure-class.test.ts + + SDK throws typed errors with failureClass on HTTP error responses. + + + + Task 3: Role-scoped client failure surface tests (D-17, D-20) + test/sdk/role-clients-failure-class.test.ts + + Create tests for PolicyClient, GatewayClient, EvidenceClient (mock fetch returning envelope bodies): + - Policy refusal → failureClass protected_action_refusal, status 409 + - Auth failure → failureClass auth, status 401 + - Evidence readback success → no HandshakeClientError; 200 + claim (D-20 parity with HTTP readback) + + Use RoleScopedTransport mock pattern from existing SDK tests. + + + bun test test/sdk/role-clients-failure-class.test.ts + + Each Tier-1 role client surfaces failureClass consistently. + + + + Task 4: MCP failureClass parity (D-17, D-19) + src/mcp/x402-proposal.ts, test/mcp/mcp-failure-class-parity.test.ts + + Wire MCP pre-contract refusal outcomes to include failureClass via shared classifier (binding missing → proof_gap or protected_action_refusal as appropriate — not auth). + + Create `test/mcp/mcp-failure-class-parity.test.ts`: + - Row table mirroring host-trusted-binding-parity pattern + - For each MCP refusal reasonCodes set, assert failureClass matches HTTP classifier expectation + - Assert MCP never classifies clearance/binding failures as auth + + Extend mcp-x402-proposal.test.ts only if needed for backward compat — prefer dedicated parity file. + + + bun test test/mcp/mcp-failure-class-parity.test.ts test/mcp/mcp-x402-proposal.test.ts + + MCP and HTTP agree on failure classification for x402 proposal path. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| MCP host → agent | Misclassified auth encourages credential retry loops | +| SDK consumer → retry logic | Wrong failureClass causes greenlight reuse attempts | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-06-01 | Spoofing | MCP proposal errors | mitigate | Shared classifier; parity tests | +| T-04-06-02 | Elevation | SDK repair.ts | mitigate | requiresNewContract from remediation + failureClass | +| T-04-06-03 | Information disclosure | HandshakeClientError | mitigate | D-18 parity across surfaces | + + + +- `bun test test/sdk/role-clients-failure-class.test.ts` +- `bun test test/mcp/mcp-failure-class-parity.test.ts` +- `bun test test/http/transition-error-failure-class.test.ts` + + + +- SDK and MCP surface failureClass matching HTTP taxonomy +- Parity tests green for binding missing, auth, refusal, proof gap cases + + + +Create `.planning/phases/04-service-agent-gating/04-06-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-07-PLAN.md b/.planning/phases/04-service-agent-gating/04-07-PLAN.md new file mode 100644 index 0000000..29a64c4 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-07-PLAN.md @@ -0,0 +1,166 @@ +--- +phase: 04-service-agent-gating +plan: 07 +type: execute +wave: 4 +depends_on: + - 04-03 +files_modified: + - src/protocol/navigation/index.ts + - docs/internal/integrator-tier-1-transitions.md + - test/architecture/integrator-tier-1-parity.test.ts + - test/sdk/role-clients-walkthrough.test.ts +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-07 + - D-08 + - D-15 + - D-16 +must_haves: + truths: + - protocol/navigation entries tagged integratorTier1 for catalog, install, compile, propose, policy, gateway, reconcile + - integrator-tier-1-transitions.md documents IDs, roles, HTTP routes, SDK clients + - Parity test asserts every Tier-1 ID exists in transition-route-registry with matching role + - SDK walkthrough test exercises Tier-1 clients in order without bundled execute + artifacts: + - docs/internal/integrator-tier-1-transitions.md + - test/architecture/integrator-tier-1-parity.test.ts + key_links: + - navigation integratorTier1 metadata matches HTTP routes in transition-route-registry.ts + - InstallClient.registerInstallProposalCompiledRecords is Tier-1 documented per D-08 +--- + + +Deliver **S7 — Tier-1 integrator platform**: navigation metadata, integrator doc, HTTP/SDK parity tests (D-07, D-08, D-15, D-16). + +Purpose: Integrators get a bounded transition surface without kernel semantic changes. +Output: Tier-1 tags, integrator doc, architecture parity test, SDK walkthrough test. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-RESEARCH.md +@src/protocol/navigation/index.ts +@src/http/routes/transition-route-registry.ts +@src/sdk/surface-clients/index.ts +@docs/internal/service-operator-golden-path.md + + + + + + Task 1: integratorTier1 navigation metadata (D-15) + src/protocol/navigation/index.ts + + Add integratorTier1: true (or integratorTier: 1) to ProtocolNavigationEntry for Tier-1 set from RESEARCH: + - registerToolCapability, registerActionType, registerGatewayRegistryEntry, registerOperatingEnvelope + - registerInstallProposalCompiledRecords + - registerDelegatedAuthorityRef + - compileIntent, proposeActionContract, evaluatePolicy, gatewayCheck, reconcileSurfaceOperation + + Export const integratorTier1TransitionIds readonly array. + + Do NOT remove or alter transition semantics — metadata only per kernel freeze. + + + bun test test/architecture/integrator-tier-1-parity.test.ts + + Tier-1 IDs tagged and exported from navigation module. + + + + Task 2: integrator-tier-1-transitions.md (D-15, D-07, D-08) + docs/internal/integrator-tier-1-transitions.md + + Author doc as **Advanced / appendix** (not Start Here): + + Opening banner: "Do not read in your first 30 minutes — service operators use service-operator-golden-path.md Branch A." + + Table columns: transitionId, phase, HTTP method+path, SDK client+method, caller role, authority boundary, runnable in phase 04? + + Include progressive onboarding narrative (D-07): catalog triplet → atomic install (D-08) → compile/propose → policy → gateway → readback. + + Explicitly list Tier-2+ transitions as reference-only (negotiation, recovery, bypass probes, certificates). + + Link service bootstrap as operator recipe; host path references discrete doctor/x402/simulate — not Tier-1 kernel transitions. + + Add back-link requirement: golden path "Advanced" section must link here (verify in plan 02 or this task). + + + grep -v '^#' docs/internal/integrator-tier-1-transitions.md | grep -c 'registerInstallProposalCompiledRecords' && grep -q 'first 30 minutes' docs/internal/integrator-tier-1-transitions.md + + Integrator doc is Tier-1 appendix with advanced-only banner; golden path links it. + + + + Task 3: integrator-tier-1-parity architecture test (D-15) + test/architecture/integrator-tier-1-parity.test.ts + + Create test: + - For each integratorTier1TransitionIds entry, assert matching route in transition-route-registry.ts + - Assert HTTP method and role match navigation metadata + - Assert no Tier-1 transition is missing from registry (404 drift prevention) + - Assert Tier-2 transitions are NOT required in registry subset unless explicitly tagged + + Pattern from existing architecture parity tests (host-trusted-binding-parity, workflow-admission-boundary). + + + bun test test/architecture/integrator-tier-1-parity.test.ts + + CI fails if Tier-1 navigation and HTTP registry diverge. + + + + Task 4: SDK role-clients walkthrough test (D-16) + test/sdk/role-clients-walkthrough.test.ts + + Create walkthrough test composing InstallClient → ControlPlaneClient (delegated mandate) → RuntimeClient propose path → PolicyClient → GatewayClient (mocked HTTP): + - Assert each step uses correct role credential + - Assert no single method bundles policy+gateway+mutation + - Assert fresh action contract required on simulated retry (different idempotency key) + - Document as integrator recipe example in integrator-tier-1-transitions.md + + Non-authority: test uses mocks; does not perform real mutations. + + + bun test test/sdk/role-clients-walkthrough.test.ts + + SDK walkthrough proves Tier-1 client composition without bundled execute. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Integrator → kernel | Tier-1 doc must not imply skipped gateway step | +| Navigation metadata → HTTP | Drift causes integrator 404 and bypass confusion | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-07-01 | Elevation | SDK walkthrough | mitigate | D-16 no bundled execute; role-scoped clients | +| T-04-07-02 | Tampering | navigation/index.ts | mitigate | Parity test vs route registry | +| T-04-07-03 | Repudiation | integrator doc | mitigate | Runnable flags honest (x402 only) | + + + +- `bun test test/architecture/integrator-tier-1-parity.test.ts` +- `bun test test/sdk/role-clients-walkthrough.test.ts` + + + +- Tier-1 tagged, documented, and parity-tested against HTTP routes +- SDK walkthrough validates D-16 non-authority composition + + + +Create `.planning/phases/04-service-agent-gating/04-07-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-08-PLAN.md b/.planning/phases/04-service-agent-gating/04-08-PLAN.md new file mode 100644 index 0000000..dd838f2 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-08-PLAN.md @@ -0,0 +1,177 @@ +--- +phase: 04-service-agent-gating +plan: 08 +type: execute +wave: 5 +depends_on: + - 04-05 +files_modified: + - src/adapters/http-profile/index.ts + - src/adapters/http-profile/schemas.ts + - src/adapters/http-profile/canonicalize.ts + - src/adapters/http-profile/generic-gateway-skeleton.ts + - src/adapters/auth-md/action-proposal.ts + - docs/internal/integrator-tier-1-transitions.md + - test/adapters/http-profile-canonicalization.test.ts + - test/adapters/http-profile-orphan-catalog.test.ts +autonomous: true +requirements: + - D-10 + - D-11 + - D-12 +must_haves: + truths: + - HttpProtectedMutationProfileSchema canonicalizes method, path template, header/body digests + - auth-md adapter composes shared http-profile module without semantic drift + - generic-gateway-skeleton exposes definition_only conformance probe — no live mutation + - Orphan catalog without gateway registry entry fails compile/install tests + artifacts: + - src/adapters/http-profile/index.ts + - src/adapters/http-profile/generic-gateway-skeleton.ts + - test/adapters/http-profile-canonicalization.test.ts + key_links: + - auth-md action-proposal imports HttpProtectedMutationProfileSchema from http-profile per D-11 + - generic-gateway-skeleton marked definition_only in exports and tests +--- + + +Deliver **S8 — HTTP profile & adapter platform**: shared transport schema, auth.md refactor, generic skeleton probe, orphan catalog guard (D-10, D-11, D-12). + +Purpose: Arbitrary REST-like endpoints share transport canonicalization; family adapters retain semantic enforcement. +Output: http-profile module, auth-md composition, skeleton gateway, canonicalization + orphan catalog tests. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-RESEARCH.md +@src/adapters/auth-md/action-proposal.ts +@src/adapters/auth-md/gateway.ts +@src/adapters/x402-payment/install-proposal.ts +@src/conformance/index.ts + + + + + + Task 1: http-profile module extraction (D-10, D-11) + src/adapters/http-profile/index.ts, src/adapters/http-profile/schemas.ts, src/adapters/http-profile/canonicalize.ts + + Create http-profile module with HttpProtectedMutationProfileSchema fields from auth-md prototype: + - targetHttpMethod, endpointUrl, pathTemplate, requestBodyDigest, selectedHeadersDigest + - Anti-bypass flags: dynamicEndpointConstructionObserved, dynamicHostConstructionObserved, retryAuthorityReuseDetected + + Implement canonicalizeHttpProfile(input) deterministic normalization (method uppercasing, path template rules, digest validation). + + Export types and schemas from index.ts. + + + bun test test/adapters/http-profile-canonicalization.test.ts + + Shared HTTP profile schema and canonicalizer exist independent of auth-md. + + + + Task 2: Refactor auth-md to compose http-profile (D-11) + src/adapters/auth-md/action-proposal.ts + + Refactor AuthMdProtectedApiCallParametersSchema to compose HttpProtectedMutationProfileSchema via merge/extend — auth-md semantic fields remain family-specific. + + Ensure runAuthMdProtectedApiCallGateway observed parameter parsing still passes existing auth-md tests. + + Do not change gateway enforcement semantics — import-only refactor plus shared canonicalization call at proposal boundary. + + + bun test test/adapters/http-profile-canonicalization.test.ts test/adapters/x402-bypass-probes.test.ts + + auth-md uses http-profile without behavioral regression on existing adapter tests. + + + + Task 3: generic-gateway-skeleton definition_only probe (D-10, D-12) + src/adapters/http-profile/generic-gateway-skeleton.ts + + Implement generic-gateway-skeleton.ts: + - Exports runGenericHttpProfileGatewaySkeleton with posture definition_only: true + - Performs schema validation + gateway check interface shape only — throws or returns proof_gap if invoked for live mutation + - Documents external PEP may sit in front (D-12) but adapter re-check remains required for Handshake + + Include conformance probe hook compatible with assertProtectedMutationAdapterConformance pattern. + + Never perform real HTTP mutation in skeleton — explicit proof_gap outcome if surface.execute called without family adapter. + + + bun test test/adapters/http-profile-canonicalization.test.ts + + Skeleton exists with definition_only posture enforced in code and tests. + + + + Task 4: Orphan catalog compile failure test (D-08, D-10) + test/adapters/http-profile-orphan-catalog.test.ts, docs/internal/integrator-tier-1-transitions.md + + Create test asserting install compile refuses when ToolCapability/ActionType present without GatewayRegistryEntry in compiled records (orphan catalog). + + Document install triplet template section in integrator-tier-1-transitions.md with HTTP profile + gateway registry requirement. + + Link to service bootstrap example as runnable x402 triplet reference. + + + bun test test/adapters/http-profile-orphan-catalog.test.ts + + Orphan catalog without gateway fails compile; documented in integrator guide. + + + + Task 5: HTTP profile canonicalization test matrix (D-10) + test/adapters/http-profile-canonicalization.test.ts + + Test matrix: + - Valid profile canonicalization stable across re-parse + - Dynamic endpoint flag triggers refusal classification + - Invalid digest rejected + - Skeleton gateway returns definition_only proof_gap on mutation attempt + - auth-md composed profile round-trips + + Use fixtures from auth-md existing tests where possible. + + + bun test test/adapters/http-profile-canonicalization.test.ts + + Canonicalization rules codified with comprehensive adapter tests. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Generic HTTP profile → mutation | Skeleton must not become live gateway (definition_only) | +| PEP → operator belief | External auth in front does not replace adapter re-check (D-12) | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-08-01 | Elevation | generic-gateway-skeleton | mitigate | definition_only; proof_gap on live execute | +| T-04-08-02 | Tampering | http-profile canonicalize | mitigate | Digest + dynamic construction flags | +| T-04-08-03 | Elevation | orphan catalog | mitigate | Compile refusal test per D-08 | + + + +- `bun test test/adapters/http-profile-canonicalization.test.ts` +- `bun test test/adapters/http-profile-orphan-catalog.test.ts` + + + +- HTTP profile module extracted; auth-md composes it +- Generic skeleton is definition_only; orphan catalog fails compile + + + +Create `.planning/phases/04-service-agent-gating/04-08-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-09-PLAN.md b/.planning/phases/04-service-agent-gating/04-09-PLAN.md new file mode 100644 index 0000000..4fc0ce0 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-09-PLAN.md @@ -0,0 +1,156 @@ +--- +phase: 04-service-agent-gating +plan: 09 +type: execute +wave: 6 +depends_on: + - 04-08 +files_modified: + - docs/internal/service-operator-golden-path.md + - examples/external-adapter-sdk/README.md + - test/architecture/proof-gap-honesty.test.ts +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-14 + - D-13 +must_haves: + truths: + - Proof-gap families documented in golden-path prose only — no runnable-shaped stub example directories + - external-adapter-sdk README includes dual-enforcement checklist + - Architecture test fails if docs claim auth.md or package-install are runnable quickstarts + - Golden path states x402 as only runnable clearance wedge + artifacts: + - test/architecture/proof-gap-honesty.test.ts + key_links: + - proof-gap list in service-operator-golden-path.md per D-14 (not separate example packages) + - external-adapter-sdk checklist links golden path +--- + + +Deliver **S9 — Proof-gap honesty (prose + CI)**: document non-runnable families without quickstart-shaped stub packages (D-14, D-13). + +Purpose: Transfer confidence without frustration from fake runnable directories; integrators read proof-gap list + checklist only. +Output: Golden-path proof-gap section (may already exist from plan 02 — verify/extend), external-adapter-sdk checklist, proof-gap-honesty architecture test. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md +@.planning/phases/04-service-agent-gating/04-CONTEXT.md +@examples/service-workflow-admission/run.ts +@examples/external-adapter-sdk/README.md +@src/adapters/package-install/gateway.ts +@src/adapters/auth-md/gateway.ts + + + + + + Task 1: Verify and extend golden-path proof-gap list (D-14, D-13) + docs/internal/service-operator-golden-path.md + + Ensure `service-operator-golden-path.md` contains structured **Proof-gap families** section (from plan 02) with table: + + | Family | Runnable in phase 04? | proofGaps (summary) | What to use instead | + | auth.md protected API | false | live gateway, admission packet | x402 wedge + http-profile module (plan 08) | + | package install | false | live gateway, composite admission | x402 install triplet pattern | + | MCP registry discoverability | false | registry acceptance | local MCP doctor only | + + **Do not** create `examples/auth-md-protected-api-stub/` or `examples/package-install-protected-action-stub/` — eliminated per 04-PRODUCT-USER-AUDIT. + + Forbid language: "run the auth.md quickstart", "bootstrap package install clearance". + + + grep -q 'Proof-gap' docs/internal/service-operator-golden-path.md && grep -q 'runnable: false' docs/internal/service-operator-golden-path.md && ! test -d examples/auth-md-protected-api-stub + + Proof-gap families are prose-only in golden path; no stub example dirs. + + + + Task 2: proof-gap-honesty architecture test (D-14, D-13) + test/architecture/proof-gap-honesty.test.ts + + Create `test/architecture/proof-gap-honesty.test.ts`: + - Assert `examples/auth-md-protected-api-stub` and `examples/package-install-protected-action-stub` do **not** exist + - Scan golden path + devex index + README for forbidden phrases implying auth.md/package-install runnable clearance + - Require golden path to mention x402 as only runnable clearance wedge + - Scan package.json scripts — no `demo:auth-md` or `quickstart:package-install` style scripts added in phase 04 + + Fail if any new example directory under `examples/` for phase 04 proof-gap families includes `run.ts` that performs live gateway execute. + + + bun test test/architecture/proof-gap-honesty.test.ts + + CI enforces no quickstart-shaped proof-gap packages and honest prose. + + + + Task 3: external-adapter-sdk dual-enforcement checklist (D-00, D-12) + examples/external-adapter-sdk/README.md + + Upgrade README with checklist section: + - [ ] Catalog triplet registered (ToolCapability, ActionType, GatewayRegistryEntry) + - [ ] Atomic install or compiled-records refusal on orphan catalog (D-08) + - [ ] Service HTTP handler calls adapter.run*Gateway before mutation + - [ ] Hosted admission configured for transition scope + - [ ] External PEP (if any) is glue only — adapter re-check required (D-12) + - [ ] Conformance probe registered (ProtectedMutationAdapter) + - [ ] Proof gaps documented honestly — do not fake pack:check green + + Link `service-operator-golden-path.md` proof-gap section (not stub examples). + + + grep -v '^#' examples/external-adapter-sdk/README.md | grep -c 'run\*Gateway' + + External adapter SDK README includes dual-enforcement checklist. + + + + Task 4: Tier-1 doc proof-gap runnable flags (D-14) + docs/internal/integrator-tier-1-transitions.md + + In integrator-tier-1 appendix, ensure "runnable in phase 04" column marks only x402-family install/clearance paths as true; auth.md and package-install families false with proof-gap note. + + Cross-link golden path proof-gap table — single source of operator truth. + + + grep -v '^#' docs/internal/integrator-tier-1-transitions.md | grep -c 'proof.gap\|proof_gap\|runnable' + + Integrator appendix aligns runnable flags with golden-path proof-gap list. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Stub reader → production deploy | Runnable-shaped stubs must not exist | +| Proof-gap honesty → trust | Fake runnable flags violate D-13/D-14 | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-09-01 | Elevation | proof-gap prose | mitigate | architecture test forbids stub dirs | +| T-04-09-02 | Spoofing | external-adapter-sdk README | mitigate | Dual-enforcement checklist per D-00 | +| T-04-09-03 | Repudiation | golden path | mitigate | proof-gap table required | + + + +- `bun test test/architecture/proof-gap-honesty.test.ts` + + + +- Proof-gap honesty enforced without stub example packages +- external-adapter-sdk documents dual-enforcement checklist + + + +Create `.planning/phases/04-service-agent-gating/04-09-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-10-PLAN.md b/.planning/phases/04-service-agent-gating/04-10-PLAN.md new file mode 100644 index 0000000..7aecd88 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-10-PLAN.md @@ -0,0 +1,173 @@ +--- +phase: 04-service-agent-gating +plan: 10 +type: execute +wave: 6 +depends_on: + - 04-02 + - 04-04 +files_modified: + - docs/internal/decisions.md + - docs/internal/service-operator-golden-path.md + - docs/internal/host-golden-paths-and-trace-guidance.md + - src/cli/host/doctor.ts + - src/cli/mcp/doctor.ts + - test/architecture/custody-matrix-parity.test.ts +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-21 + - D-22 + - D-23 +must_haves: + truths: + - decisions.md production acceptance matrix includes configured-by columns for service vs host operator + - Bilateral setup order documented in golden path + host golden path sections (not separate runbook files in phase 04) + - Doctor CLI/MCP output framed as attestation evidence with explicit nonClaims + - Architecture test verifies custody matrix rows reference correct surface owners + artifacts: + - test/architecture/custody-matrix-parity.test.ts + key_links: + - service golden path Branch A covers gateway registry custody (D-21) + - host golden path covers trusted binding digests; forbids gateway ownership claims (D-21) +--- + + +Deliver **S10 — Custody & bilateral operations**: responsibility matrix, bilateral sections in existing golden paths, doctor attestation framing (D-21, D-22, D-23). + +Purpose: Operators know who configures gateway vs host binding without custody collapse or new runbook files before CLI output stabilizes. +Output: Extended decisions matrix, bilateral sections in golden path docs, doctor copy updates, custody parity test. + +**Deferred post-execute:** `service-operator-runbook.md` and `host-operator-runbook.md` standalone files — extract from golden path sections after doctor/bootstrap commands freeze. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md +@docs/internal/decisions.md +@docs/internal/host-golden-paths-and-trace-guidance.md +@docs/internal/service-operator-golden-path.md +@src/cli/host/doctor.ts +@src/cli/mcp/doctor.ts + + + + + + Task 1: Production acceptance matrix configured-by columns (D-21) + docs/internal/decisions.md + + Extend production acceptance / operator matrix in decisions.md: + - Add column configuredBy: service_operator | host_operator | shared + - Rows: gateway registry entry, gateway credential custody, adapter mutation enforcement, trusted binding digests, MCP proposal wiring, policy pack baseline, hosted admission verifier + + Pattern from x402ProtectedToolAcceptanceMatrix (surfaceOwner, proofGaps, stopCondition). + + Do not claim hosted marketplace trust or cross-org federation (deferred). + + + bun test test/architecture/custody-matrix-parity.test.ts + + Matrix documents custody split with configured-by columns. + + + + Task 2: Bilateral setup sections in golden paths (D-22) — no standalone runbooks + docs/internal/service-operator-golden-path.md, docs/internal/host-golden-paths-and-trace-guidance.md + + Add **Bilateral setup order** section to service-operator-golden-path.md Branch A: + - Service first: catalog triplet → atomic bootstrap → gateway readiness → hosted admission → handler adapter binding + - Commands: service bootstrap, demo:service-workflow-admission + - Failure taxonomy quick reference pointer (plan 05 table) + - Stale registry blocks host attestation downstream (D-22) + + Add symmetric section to host-golden-paths-and-trace-guidance.md: + - Host after service registry: doctor → quickstart x402 → simulate (canonical); optional agent-spine + - Trusted binding digest rotation; stale digests fail closed + - Explicit: host does not own gateway registry (D-21) + + **Do not** create `service-operator-runbook.md` or `host-operator-runbook.md` in this phase. + + Add comment in decisions.md or phase SUMMARY: runbook file extraction is post-execute follow-up. + + + grep -v '^#' docs/internal/service-operator-golden-path.md | grep -c 'Bilateral' && ! test -f docs/internal/service-operator-runbook.md + + Bilateral order in golden paths; standalone runbooks deferred. + + + + Task 3: Doctor attestation framing in CLI/MCP (D-23) + src/cli/host/doctor.ts, src/cli/mcp/doctor.ts + + Update doctor output copy (not behavior semantics): + - evidenceKind remains cli_diagnostic + - Add attestationEvidence: { bindingDigestRefs, policyVersionDigest, gatewayReadinessDigest } when available + - nonClaims: not identity system, not SPIFFE replacement (SPIFFE analogy prose in host golden path only) + - liveHostVerificationStatus: not_performed unchanged + - configMutationPerformedByDoctor: false explicit + + MCP doctor mirrors host doctor attestation fields for parity. + + Do not add new authority fields or kernel transitions. + + + bun test test/cli/cli-mcp-doctor.test.ts + + Doctor outputs framed as attestation evidence with honest nonClaims. + + + + Task 4: custody-matrix-parity architecture test (D-21, D-22) + test/architecture/custody-matrix-parity.test.ts + + Create test: + - Parse decisions.md matrix rows for required configuredBy values + - Assert service-operator-golden-path mentions gateway registry before host attestation + - Assert host-golden-paths forbids claiming gateway ownership + - Assert standalone runbook files do not exist (phase 04 scope) + - Assert doctor modules include attestationEvidence or equivalent field in result type exports + + Use claim-boundary style doc scanning patterns. + + + bun test test/architecture/custody-matrix-parity.test.ts + + Custody documentation and doctor types satisfy parity test without runbook files. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Host operator → service gateway | Host must not configure gateway registry (custody split) | +| Doctor output → identity | Attestation must not become bearer permission (D-23) | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-10-01 | Elevation | doctor.ts | mitigate | nonClaims; no config mutation by doctor | +| T-04-10-02 | Spoofing | custody matrix | mitigate | configuredBy columns; parity test | +| T-04-10-03 | Repudiation | bilateral sections | mitigate | Ordered setup with fail-closed stale digest policy | + + + +- `bun test test/architecture/custody-matrix-parity.test.ts` +- `bun test test/cli/cli-mcp-doctor.test.ts` + + + +- D-21 matrix, D-22 bilateral sections in golden paths, D-23 doctor attestation framing delivered with tests +- Standalone runbook files explicitly out of phase 04 scope + + + +Create `.planning/phases/04-service-agent-gating/04-10-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-11-PLAN.md b/.planning/phases/04-service-agent-gating/04-11-PLAN.md new file mode 100644 index 0000000..635d7eb --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-11-PLAN.md @@ -0,0 +1,115 @@ +--- +phase: 04-service-agent-gating +plan: 11 +type: execute +wave: 7 +depends_on: + - 04-03 + - 04-07 + - 04-08 +files_modified: + - test/architecture/http-handler-mutation-gating.test.ts +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-24 + - D-25 +must_haves: + truths: + - http-handler-mutation-gating test walks handlers for adapter binding posture and fails CI on violations + - Operator TTHW is not blocked on manifest/registry sync (deferred) + artifacts: + - test/architecture/http-handler-mutation-gating.test.ts + key_links: + - handler walk enforces adapter.run*Gateway before mutation per D-24 + - D-25: full manifest + product-completion slice deferred — not operator-completion gate +--- + + +Deliver **S11 — Bypass enforcement (minimal, operator-unblocking)**: handler mutation gating architecture test required before phase gate; full manifest system **deferred** (D-24, D-25). + +Purpose: Structural proof that first-party handlers are adapter-gated without delaying operator TTHW until wave 8. +Output: `http-handler-mutation-gating.test.ts` only in phase 04 execute scope. + +**Deferred to phase 05 or post-operator maintainer lane (document in 04-PLANS-INDEX):** +- `service-mutation-route-manifest` module +- `sync-service-mutation-manifest-from-registry.mjs` +- `http-profile-adapter-conformance.test.ts` expansion +- `check-product-completion.mjs` first-party dual-enforcement inventory slice + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md +@.planning/phases/04-service-agent-gating/04-DELIVERY-ARCHITECTURE.md +@test/architecture/workflow-admission-boundary.test.ts + + + + + + Task 1 (required): http-handler-mutation-gating architecture test (D-24) + test/architecture/http-handler-mutation-gating.test.ts + + Create repo walk test: + - Scan src/http/handlers (and app route wiring) for consequential mutation patterns + - Assert each listed first-party mutation route references adapter.run*Gateway or delegates to adapter module import + - Flag handlers that perform downstream mutation without adapter import (violations array) + - Allowlisted read-only evidence routes excluded explicitly + + Use walkTs helper from workflow-admission-boundary.test.ts pattern. + + Fail CI with sorted violation list — not prose-only D-24 compliance. + + Document in test header: manifest module deferred; this test is the phase-04 D-24 enforcement mechanism. + + + bun test test/architecture/http-handler-mutation-gating.test.ts + + Handler walk fails on unwrapped mutation posture. + + + + +## Deferred tasks (not in phase 04 execute — track in 04-PLANS-INDEX) + +The following were in the original comprehensive plan 11; defer to **maintainer lane** (phase 05 or follow-up milestone): + +| Deferred item | Original task | Rationale | +|---------------|---------------|-----------| +| service-mutation-route-manifest module | Task 1 (original) | Maintainer inventory; not operator TTHW | +| Manifest registry sync script | Task 2 | Drift detection after manifest exists | +| http-profile-adapter-conformance test | Task 4 | Depends on full manifest/conformance wiring | +| check-product-completion inventory slice | Task 5 | Maintainer gate; blocked gates stay blocked | + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| HTTP handler → downstream mutation | Unlisted routes bypass gateway enforcement | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-11-01 | Elevation | http handlers | mitigate | Handler walk test per D-24 | +| T-04-11-02 | Tampering | route manifest | defer | Registry sync deferred | +| T-04-11-03 | Repudiation | check-product-completion | defer | Inventory slice deferred | + + + +- `bun test test/architecture/http-handler-mutation-gating.test.ts` + + + +- Handler mutation gating test enforces D-24 structurally in phase 04 +- Manifest/sync/conformance/product-completion extensions explicitly deferred + + + +Create `.planning/phases/04-service-agent-gating/04-11-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-12-PLAN.md b/.planning/phases/04-service-agent-gating/04-12-PLAN.md new file mode 100644 index 0000000..ba3306f --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-12-PLAN.md @@ -0,0 +1,198 @@ +--- +phase: 04-service-agent-gating +plan: 12 +type: execute +wave: 8 +depends_on: + - 04-01 + - 04-02 + - 04-03 + - 04-04 + - 04-05 + - 04-06 + - 04-07 + - 04-08 + - 04-09 + - 04-10 + - 04-11 +files_modified: + - test/integration/service-operator-golden-path.test.ts + - test/architecture/operator-product-completion-contract.test.ts + - test/architecture/maintainer-product-completion-contract.test.ts + - scripts/check-service-agent-gating-phase.mjs + - .planning/phases/04-service-agent-gating/04-VERIFICATION.md + - package.json +autonomous: true +product_user_audit: applied-2026-05-28 +requirements: + - D-00 + - D-13 + - D-24 + - D-25 +must_haves: + truths: + - Integration test runs admission demo + bootstrap idempotency smoke end-to-end + - operator-product-completion-contract asserts operator-facing artifacts (no runbooks, no stub dirs, agent-spine optional) + - check-service-agent-gating-phase.mjs supports --tier operator (waves 1-6 + handler walk) and --tier full + - 04-VERIFICATION.md lists operator vs maintainer sign-off criteria + artifacts: + - test/integration/service-operator-golden-path.test.ts + - scripts/check-service-agent-gating-phase.mjs + - .planning/phases/04-service-agent-gating/04-VERIFICATION.md + key_links: + - operator tier: dual-enforcement, failureClass, bootstrap, golden path integration, custody matrix, handler gating + - full tier: adds integrator parity, http-profile, proof-gap-honesty, maintainer contract (manifest deferred) +--- + + +Deliver **S12 — Operator E2E verification**: two-tier phase gates — **operator** (TTHW complete) and **full** (maintainer completeness) (D-00, D-13, D-24, D-25). + +Purpose: Service operators can sign off after waves 1–6 without waiting for deferred manifest work. +Output: Integration test, operator + maintainer contract tests, tiered phase gate script, VERIFICATION.md. + + + +@/Users/joelchan/.cursor/get-shit-done/workflows/execute-plan.md + + + +@.planning/phases/04-service-agent-gating/04-DELIVERY-ARCHITECTURE.md +@.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md +@.planning/phases/04-service-agent-gating/04-PLANS-INDEX.md +@test/integration/ + + + + + + Task 1: service-operator-golden-path integration test (D-13, D-08) + test/integration/service-operator-golden-path.test.ts + + Create integration test: + - Spawn or invoke service-workflow-admission demo logic; assert authorityBoundary non-authority + - Invoke service-operator-bootstrap recipe (or CLI bootstrap in test mode); assert compiled records or structured refusal + - Idempotency smoke: second bootstrap call behavior explicit (plan 03 contract) + - Assert golden path doc exists with Step 3 fork, Branch A, proof-gap section, failureClass table (after plan 05) + + Use test timeouts appropriate for subprocess; mock HTTP worker if integration harness exists elsewhere. + + Do not require live x402 paid retry or registry — honest proof gaps remain. + + + bun test test/integration/service-operator-golden-path.test.ts + + Service operator golden path integration smoke passes. + + + + Task 2: Two-tier product completion contracts (D-24, D-25) + test/architecture/operator-product-completion-contract.test.ts, test/architecture/maintainer-product-completion-contract.test.ts + + **operator-product-completion-contract.test.ts** — operator TTHW (required for `--tier operator`): + - Docs: service-operator-golden-path.md, developer-experience-index.md, integrator-tier-1-transitions.md (appendix exists) + - CLI: service bootstrap in command-manifest + - Modules: failure-class foundation, http-profile + - Examples: service-operator-bootstrap only (no auth-md/package-install stub dirs) + - Tests: dual-enforcement-posture, transition-error-failure-class, service-operator-bootstrap, cli-agent-spine-sequencer (if agent-spine ships), proof-gap-honesty, custody-matrix-parity, service-operator-golden-path integration + - **Must not require:** service-operator-runbook.md, host-operator-runbook.md, service-mutation-route-manifest, quickstart agent-spine as mandatory completion item + - **Host branch:** require host doctor + quickstart x402 in manifest OR document discrete commands in golden path fork — agent-spine optional + + **maintainer-product-completion-contract.test.ts** — full phase (required for `--tier full`): + - Everything in operator contract, plus: integrator-tier-1-parity, http-profile tests, http-handler-mutation-gating, mcp/sdk failure parity + - Explicitly **fail if** manifest module exists without deferred note OR assert manifest still absent (phase 04 deferral) + - Document deferred manifest items in test skip message until phase 05 + + Fail with sorted missing list per tier. + + + bun test test/architecture/operator-product-completion-contract.test.ts + + Operator and maintainer contracts separated; operator tier shippable without manifest. + + + + Task 3: check-service-agent-gating-phase.mjs with --tier (D-00, D-24) + scripts/check-service-agent-gating-phase.mjs, package.json + + Create phase gate script accepting `--tier operator` (default) or `--tier full`: + + **--tier operator** runs: + 1. operator-product-completion-contract.test.ts + 2. dual-enforcement-posture, transition-error-failure-class + 3. service-operator-bootstrap, service-operator-golden-path integration + 4. proof-gap-honesty, custody-matrix-parity + 5. http-handler-mutation-gating (minimal plan 11) + 6. role-clients-failure-class + mcp-failure-class-parity if present + + **--tier full** runs operator tier plus: + - integrator-tier-1-parity, http-profile-canonicalization, http-profile-orphan-catalog + - cli-agent-spine-sequencer, maintainer-product-completion-contract + + Skip missing test files with `SKIP (not yet implemented)` during partial waves; hard-fail missing once wave complete. + + Exit non-zero on any failure; print summary table with tier label. + + Add npm scripts: + - `check:service-agent-gating-phase` → operator tier default + - `check:service-agent-gating-phase:full` → full tier + + Header comment: D-25 — must not assert blocked proof gates green; manifest deferred in operator tier. + + + node scripts/check-service-agent-gating-phase.mjs --tier operator + + Phase gate script supports operator early sign-off and full maintainer sign-off. + + + + Task 4: Author 04-VERIFICATION.md with operator vs maintainer tiers + .planning/phases/04-service-agent-gating/04-VERIFICATION.md + + Write 04-VERIFICATION.md with: + - **Operator success** (5 capabilities from DELIVERY-ARCHITECTURE, adjusted): golden path + bootstrap + failure table + bilateral sections + handler walk + - **Maintainer success** (additive): Tier-1 parity, http-profile, full test bundle; manifest/sync deferred with explicit phase 05 pointer + - Per-subsystem S1–S12 truth checklist mapped to plans 01–12 + - Explicit non-goals (kernel changes, second runnable path, fake green gates, stub example dirs, mandatory agent-spine) + - Sign-off: `node scripts/check-service-agent-gating-phase.mjs --tier operator` for operator ship; `--tier full` for phase complete + + Reference 04-PRODUCT-USER-AUDIT applied patches. + + + grep -v '^#' .planning/phases/04-service-agent-gating/04-VERIFICATION.md | grep -c 'operator tier' + + VERIFICATION.md documents two-tier acceptance for /gsd-verify-work. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Phase gate → ship claim | Operator tier must not imply full maintainer completeness | +| VERIFICATION → scope creep | Must not add requirements beyond patched plans | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-04-12-01 | Repudiation | phase gate script | mitigate | Tiered exits; non-zero on failure | +| T-04-12-02 | Elevation | integration test | mitigate | Non-authority assertions; no live paid x402 | +| T-04-12-03 | Information disclosure | VERIFICATION.md | mitigate | Honest non-goals and deferred manifest | + + + +- `node scripts/check-service-agent-gating-phase.mjs --tier operator` +- `bun test test/integration/service-operator-golden-path.test.ts` +- `bun test test/architecture/operator-product-completion-contract.test.ts` + + + +- Operator tier mechanically verifiable before maintainer manifest work +- Full tier covers comprehensive 12-plan engineering slice + + + +Create `.planning/phases/04-service-agent-gating/04-12-SUMMARY.md` when done + diff --git a/.planning/phases/04-service-agent-gating/04-12-SUMMARY.md b/.planning/phases/04-service-agent-gating/04-12-SUMMARY.md new file mode 100644 index 0000000..6df6bb4 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-12-SUMMARY.md @@ -0,0 +1,92 @@ +--- +phase: 04-service-agent-gating +plan: 12 +subsystem: testing +tags: [e2e, phase-gate, operator-tier, dual-enforcement] + +requires: + - phase: 04-service-agent-gating + provides: plans 01-11 operator product surface +provides: + - service-operator-golden-path integration smoke test + - operator and maintainer product completion contracts + - check-service-agent-gating-phase.mjs tiered gate + - 04-VERIFICATION.md with status passed +affects: [05-product-coherence] + +tech-stack: + added: [] + patterns: [two-tier phase gate, operator vs maintainer completion contracts] + +key-files: + created: + - test/integration/service-operator-golden-path.test.ts + - test/architecture/operator-product-completion-contract.test.ts + - test/architecture/maintainer-product-completion-contract.test.ts + - scripts/check-service-agent-gating-phase.mjs + - .planning/phases/04-service-agent-gating/04-VERIFICATION.md + modified: + - package.json + +key-decisions: + - "Operator tier sign-off available after waves 1-6 plus handler walk without manifest module" + - "Full tier adds integrator parity, http-profile tests, and maintainer contract" + +patterns-established: + - "Two-tier phase gate: --tier operator vs --tier full" + - "Product completion contracts fail with sorted missing artifact lists" + +requirements-completed: [D-00, D-13, D-24, D-25] + +duration: 45min +completed: 2026-05-29 +--- + +# Phase 04 Plan 12: Operator E2E verification Summary + +**Two-tier phase gate proves operator TTHW shippable before maintainer manifest work lands in Phase 05.** + +## Performance + +- **Duration:** ~45 min (continuation session; builds on waves 1-11) +- **Completed:** 2026-05-29 +- **Tasks:** 4 completed +- **Files modified:** 6 + +## Accomplishments + +- Integration smoke covers admission demo, bootstrap idempotency, and golden path doc anchors +- Operator and maintainer completion contracts separated with manifest deferral explicit +- `check-service-agent-gating-phase.mjs` supports `--tier operator` (10 checks) and `--tier full` (15 checks) +- `04-VERIFICATION.md` documents sign-off criteria with `status: passed` + +## Task Commits + +1. **Task 1: service-operator-golden-path integration test** - `283c015` (feat) +2. **Task 2: Two-tier product completion contracts** - `283c015` (feat) +3. **Task 3: check-service-agent-gating-phase.mjs** - `283c015`, `cb6d266` (feat, fix) +4. **Task 4: Author 04-VERIFICATION.md** - `d18f2d3` (docs) + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] Duplicate npm scripts in package.json** +- **Found during:** Task 3 verification +- **Issue:** `check:service-agent-gating-phase` entries duplicated after merge +- **Fix:** Removed duplicate lines +- **Files modified:** package.json +- **Commit:** cb6d266 + +## Verification + +- `node scripts/check-service-agent-gating-phase.mjs --tier operator` — PASS +- `node scripts/check-service-agent-gating-phase.mjs --tier full` — PASS +- `bun test test/integration/service-operator-golden-path.test.ts` — PASS + +## Self-Check: PASSED + +- FOUND: test/integration/service-operator-golden-path.test.ts +- FOUND: scripts/check-service-agent-gating-phase.mjs +- FOUND: .planning/phases/04-service-agent-gating/04-VERIFICATION.md +- FOUND: d18f2d3, 283c015, cb6d266 diff --git a/.planning/phases/04-service-agent-gating/04-BASELINE-AUDIT.md b/.planning/phases/04-service-agent-gating/04-BASELINE-AUDIT.md new file mode 100644 index 0000000..4c136b7 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-BASELINE-AUDIT.md @@ -0,0 +1,356 @@ +# Phase 04 — Baseline audit against `1e801b7` + +**Generated:** 2026-05-29 +**Baseline:** `1e801b7` (merge-base with `main` at `ab382f7`; eight unpushed `main` commits through `d4a5513`…`ab382f7` are ancestors) +**Branch:** `phase-04-service-agent-gating` (also contains Phase 02 A2A negotiation commits after merge-base) +**Plans audited:** 12 (`04-01-PLAN.md` … `04-12-PLAN.md`) +**Tasks audited:** 48 + +## Executive summary + +| Status | Count | Share | +|--------|------:|------:| +| **already-done** | 0 | 0% | +| **partially-done** | 5 | 10% | +| **not-started** | 43 | 90% | +| **needs-revision** | 0 | 0% | +| **obsolete** | 0 | 0% | + +- **Plans flagged for revision:** 2 (04-01, 04-02 — integrate existing baseline artifacts; do not redo from scratch) +- **Plans ready for execution as-is:** 10 (04-03 through 04-12 — plan text still valid; dependencies unchanged) +- **Estimated remaining execution work:** ~95% of original 48 tasks (5 tasks need gap-closure only; 43 full build) + +### Baseline product surface already landed (from `main` lineage) + +These commits predate Phase 04 plan execution but materially overlap plan intent: + +| Commit | Delivers (partial overlap) | +|--------|---------------------------| +| `61c17e2` | `service-workflow-admission` surface, initial `service-workflow-story.md`, `workflow-admission-boundary.test.ts` | +| `a1cd5e5` | Doc convergence in `decisions.md`, `protocol-notes.md`, `protocol-layman.md` | +| `025888f` | Surface LANE alignment (CLI/MCP/SDK), posture tests | +| `56f3cbd` | `examples/service-workflow-admission/`, `demo:service-workflow-admission`, product test | +| `539947d` / `0125173` | Misuse gates, protected-action fixture in demo | +| `ab382f7` | Hosted Admission Lock in `decisions.md` / `protocol-notes.md`, `claim-boundary` hosted-admission-lock matrix | + +**Not landed at baseline:** golden-path docs, failureClass HTTP taxonomy, bootstrap CLI, http-profile module, tier-1 integrator platform, phase gate script, handler mutation walk, or any plan-specific architecture tests beyond workflow-admission boundary. + +--- + +## Per-plan audit + +### 04-01-PLAN: S1 dual-lane doctrine + +**Baseline status of files_modified:** + +| File | Exists? | Source | Matches plan task? | +|------|---------|--------|-------------------| +| `docs/internal/service-workflow-story.md` | YES | `61c17e2`, extended in branch | Partial — Passport/admission/handle story + non-authority flags; **no** Agent lane D-05 mapping table | +| `docs/internal/protocol-layman.md` | YES | pre-existing + `a1cd5e5` | Partial — Service Workflow Surface section; **no** shortened agent chain with schema-native names | +| `docs/internal/decisions.md` | YES | many commits incl. `ab382f7` | Partial — Hosted Admission Lock (`decisions.md:233-257`); **no** Clerk-for-agents / `run*Gateway` chain | +| `docs/internal/protocol-notes.md` | YES | `a1cd5e5`, `ab382f7` | Partial — hosted admission notes; **no** dual-enforcement cross-ref paragraph per T2 | +| `test/architecture/dual-enforcement-posture.test.ts` | NO | — | Not started | +| `test/architecture/claim-boundary.test.ts` | YES | `ab382f7` + prior | Partial — hosted-admission-lock matrix (`claim-boundary.test.ts:203-228`); **no** D-00 dual-enforcement / canonical-path additive tests from T3–T4 | + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | Agent lane vocabulary in service-workflow-story | **partially-done** | `service-workflow-story.md:27-53` non-authority flags; `service-workflow-story.md:67-84` protected-action boundary mentions gateway check | Missing parallel **Agent lane** section and D-05 table (Standing Bounds → `OperatingEnvelope`, etc.); `protocol-layman.md` lacks matching shortened chain | +| 2 | Clerk-for-agents dual enforcement in decisions + protocol-notes | **partially-done** | `decisions.md:233-257` Hosted Admission Lock; `claim-boundary.test.ts:203-228` hosted admission lock claims | Missing Clerk-for-agents request chain with `run*Gateway`; `grep run*Gateway docs/internal/decisions.md` → 0 matches | +| 3 | dual-enforcement-posture architecture test | **not-started** | File absent | Create test + extend claim-boundary per D-00 / D-00b | +| 4 | Canonical state path integrity check | **not-started** | `claim-boundary.test.ts` has projection/hosted tests but not T4 assertions | Add protocol-definition canonical path + agent-lane-additive-only tests | + +**Plan summary:** 0 / 2 partial / 2 not-started / 0 / 0 +**Recommendation:** **revise** — planner should add “extend existing docs” notes so executor does not replace Passport/admission story or Hosted Admission Lock. +**Justification:** Foundational service-workflow docs exist; plan tasks are additive gap-closure, not greenfield. + +--- + +### 04-02-PLAN: S2 golden path product + +**Baseline status of files_modified:** + +| File | Exists? | Source | Matches plan task? | +|------|---------|--------|-------------------| +| `docs/internal/service-operator-golden-path.md` | NO | — | Not started | +| `docs/internal/developer-experience-index.md` | NO | — | Not started (also listed in CONTEXT canonical refs but missing repo-wide) | +| `examples/service-operator-golden-path/*` | NO | — | Not started | +| `package.json` | YES | `56f3cbd` | Partial — `demo:service-workflow-admission` present; no golden-path wrapper scripts | + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | Author service-operator-golden-path.md | **not-started** | File missing | Full doc: unified journey, Step 3 fork, D-09 contrast, proof-gap prose, failure table placeholder | +| 2 | Update developer-experience-index | **not-started** | File missing | Create single Start Here → golden path | +| 3 | Canonize demo:service-workflow-admission | **partially-done** | `package.json:95`; `test/product/service-workflow-admission.test.ts:14-76` proves demo output + non-authority boundary | Missing documentation in golden path + devex index (target docs do not exist) | +| 4 | Optional golden-path example wrapper | **not-started** | `examples/service-operator-golden-path/` absent | Create thin wrapper per plan | + +**Plan summary:** 0 / 1 / 3 / 0 / 0 +**Recommendation:** **revise** — note T3 demo is runnable and tested; T1/T2 are net-new files, not updates. +**Justification:** Executor should link to existing demo test fixtures rather than re-validating demo mechanics from zero. + +--- + +### 04-03-PLAN: S3 atomic install bootstrap + +**Baseline status:** All `files_modified` absent except `src/cli/command-manifest.ts`, `src/cli/index.ts`, `test/http/http.test.ts` (exist but without plan deliverables). + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | service-operator-bootstrap example | **not-started** | No `examples/service-operator-bootstrap/` | Full recipe | +| 2 | handshake service bootstrap CLI | **not-started** | No `src/cli/service/bootstrap.ts`; manifest has `doctor` only | CLI + manifest entry | +| 3 | Product + HTTP install path tests | **not-started** | `http.test.ts:403-459` happy-path install exists; no `service-operator-bootstrap.test.ts`; no orphan-catalog refusal | New tests + orphan assertions | +| 4 | Golden path copy-paste integration | **not-started** | Golden path doc missing | Blocked on 04-02 T1 | +| 5 | Idempotency smoke | **not-started** | — | — | + +**Plan summary:** 0 / 0 / 5 / 0 / 0 +**Recommendation:** **proceed-as-is** (after 04-02 T1) +**Justification:** No conflicting baseline implementation; x402 install-proposal adapter is the integration anchor per plan context. + +--- + +### 04-04-PLAN: S4 agent-spine (recommended) + +**Baseline status:** `src/cli/quickstart/agent-spine.ts`, tests, and `host-golden-paths-and-trace-guidance.md` all **absent**. (`host-golden-paths…` is referenced in CONTEXT canonical refs but not in repo.) + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | Implement quickstart agent-spine sequencer | **not-started** | — | — | +| 2 | Register recommended CLI command | **not-started** | `command-manifest.ts` has `doctor`; no `quickstart.agent-spine` | — | +| 3 | Anti-theatre sequencer tests | **not-started** | — | — | +| 4 | Bilateral cross-links in host golden path doc | **not-started** | Host golden path file missing entirely | Create doc + cross-links | + +**Plan summary:** 0 / 0 / 4 / 0 / 0 +**Recommendation:** **proceed-as-is** +**Justification:** Plan already lists host golden path as `files_modified`; executor creates missing canonical doc. + +--- + +### 04-05-PLAN: S5 failure taxonomy HTTP + +**Baseline status:** `transition-error-envelope.ts` exists but schema ends at line 38 with **no** `failureClass`, `failurePhase`, or `problemType` fields. + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | Extend TransitionErrorEnvelope schema | **not-started** | `transition-error-envelope.ts:27-38` — no failureClass | Full D-17/D-19 extension | +| 2 | HTTP status discipline mapping | **not-started** | `classifyTransitionError` uses legacy status logic | D-18 mapping | +| 3 | HTTP failure class test suite | **not-started** | No `transition-error-failure-class.test.ts` | — | +| 4 | OpenAPI documentation | **not-started** | OpenAPI lacks failureClass fields | — | +| 5 | Operator-visible failure table | **not-started** | Golden path missing | Blocked on 04-02 T1 | + +**Plan summary:** 0 / 0 / 5 / 0 / 0 +**Recommendation:** **proceed-as-is** +**Justification:** Clean extension point; no baseline drift. + +--- + +### 04-06-PLAN: S6 failure parity (SDK/MCP) + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | Shared failureClass classifier module | **not-started** | No `src/protocol/foundation/failure-class.ts` | — | +| 2 | SDK HandshakeClientError + transport parsing | **not-started** | `src/sdk/client.ts` has no failureClass fields | Depends on 04-05 | +| 3 | Role-scoped client failure tests | **not-started** | Only `role-clients.test.ts` exists (unrelated) | — | +| 4 | MCP failureClass parity | **not-started** | No `mcp-failure-class-parity.test.ts` | Depends on 04-05 | + +**Plan summary:** 0 / 0 / 4 / 0 / 0 +**Recommendation:** **proceed-as-is** + +--- + +### 04-07-PLAN: S7 tier-1 integrator platform + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | integratorTier1 navigation metadata | **not-started** | `grep integratorTier1 src/protocol/navigation/index.ts` → 0 | Metadata-only tags | +| 2 | integrator-tier-1-transitions.md | **not-started** | File absent | — | +| 3 | integrator-tier-1-parity architecture test | **not-started** | File absent | — | +| 4 | SDK role-clients walkthrough test | **not-started** | File absent | — | + +**Plan summary:** 0 / 0 / 4 / 0 / 0 +**Recommendation:** **proceed-as-is** + +--- + +### 04-08-PLAN: S8 HTTP profile adapter platform + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | http-profile module extraction | **not-started** | No `src/adapters/http-profile/` | auth-md inlines HTTP fields in `action-proposal.ts:19-46` | +| 2 | Refactor auth-md to compose http-profile | **not-started** | Inline schema, no http-profile import | — | +| 3 | generic-gateway-skeleton definition_only probe | **not-started** | — | — | +| 4 | Orphan catalog compile failure test | **not-started** | No `http-profile-orphan-catalog.test.ts` | — | +| 5 | HTTP profile canonicalization test matrix | **not-started** | No `http-profile-canonicalization.test.ts` | — | + +**Plan summary:** 0 / 0 / 5 / 0 / 0 +**Recommendation:** **proceed-as-is** + +--- + +### 04-09-PLAN: S9 proof-gap honesty + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | Verify/extend golden-path proof-gap list | **not-started** | Golden path absent; no `Proof-gap` section in repo docs | Depends on 04-02 | +| 2 | proof-gap-honesty architecture test | **not-started** | File absent | — | +| 3 | external-adapter-sdk dual-enforcement checklist | **partially-done** | `examples/external-adapter-sdk/README.md:29-32` definition-only boundaries | Missing checklist with `run*Gateway`, catalog triplet, D-12 PEP glue | +| 4 | Tier-1 doc proof-gap runnable flags | **not-started** | `integrator-tier-1-transitions.md` absent | Depends on 04-07 | + +**Plan summary:** 0 / 1 / 3 / 0 / 0 +**Recommendation:** **proceed-as-is** + +--- + +### 04-10-PLAN: S10 custody & bilateral operations + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | Production acceptance matrix configured-by columns | **partially-done** | `decisions.md:182-200` Production Proof Ledger table exists | Missing `configuredBy: service_operator \| host_operator \| shared` column per D-21 | +| 2 | Bilateral setup sections in golden paths | **not-started** | Golden path + host golden path files missing | — | +| 3 | Doctor attestation framing in CLI/MCP | **not-started** | `grep attestationEvidence src/cli/host/doctor.ts` → 0 | Copy/field framing only | +| 4 | custody-matrix-parity architecture test | **not-started** | File absent | — | + +**Plan summary:** 0 / 1 / 3 / 0 / 0 +**Recommendation:** **proceed-as-is** + +--- + +### 04-11-PLAN: S11 bypass enforcement (minimal) + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | http-handler-mutation-gating architecture test | **not-started** | File absent; `workflow-admission-boundary.test.ts` covers surface boundary, not HTTP handler adapter walk | Create handler walk per D-24 | + +**Plan summary:** 0 / 0 / 1 / 0 / 0 +**Recommendation:** **proceed-as-is** + +--- + +### 04-12-PLAN: S12 E2E verification + +**Task-by-task:** + +| # | Title | Status | Evidence | Gap | +|---|-------|--------|----------|-----| +| 1 | service-operator-golden-path integration test | **not-started** | File absent | — | +| 2 | Two-tier product completion contracts | **not-started** | Operator/maintainer contract tests absent | — | +| 3 | check-service-agent-gating-phase.mjs | **not-started** | Script absent; no npm `check:service-agent-gating-phase` | — | +| 4 | Author 04-VERIFICATION.md | **not-started** | File absent | — | + +**Plan summary:** 0 / 0 / 4 / 0 / 0 +**Recommendation:** **proceed-as-is** + +--- + +## Updated wave graph + +Wave graph **unchanged** from `04-PLANS-INDEX.md`. Baseline partial work does not satisfy wave outputs; dependencies remain valid. + +```text +Wave 1: 04-01 ∥ 04-02 (both have partial baseline — execute gap-closure, not rewrite) +Wave 2: 04-03 ∥ 04-04 (depends on 01, 02) +Wave 3: 04-05 +Wave 4: 04-06 ∥ 04-07 (06 after 05; 07 after 03) +Wave 5: 04-08 (after 05) +Wave 6: 04-09 ∥ 04-10 (09 after 08; 10 after 02, 04) +Wave 7: 04-11 (after 03, 07, 08) +Wave 8: 04-12 (after 01–11) +``` + +**Execution note:** Wave 1 should treat 04-01 and 04-02 as **extend-in-place** given baseline docs and demo; do not revert `service-workflow-story.md` Passport narrative or `ab382f7` Hosted Admission Lock. + +--- + +## Tasks the executor can skip + +| Plan | Task | Why skip | File evidence | +|------|------|----------|---------------| +| — | — | **None** under strict acceptance criteria | No task meets full `` criteria at baseline | + +**Near-skip (executor should narrow scope, not skip):** + +| Plan | Task | Narrow to | +|------|------|-----------| +| 04-02 | T3 | Document + link existing demo; re-run `npm run demo:service-workflow-admission` for verify — do not rebuild demo | +| 04-01 | T1–T2 | Additive sections only — preserve `service-workflow-story.md:1-116` and Hosted Admission Lock | + +--- + +## Revision queue (handoff to gsd-planner) + +| Plan | Task | Revision needed | Suggested fix | +|------|------|-----------------|---------------| +| 04-01 | T1, T2 | Integrate baseline | Add plan preamble: extend existing service-workflow docs; do not replace Passport flow; Clerk subsection is **additive** to Hosted Admission Lock | +| 04-02 | T1, T2, T3 | Integrate baseline | T3 verify step = doc + link work; reference existing `service-workflow-admission.test.ts` as acceptance anchor | +| — | — | CONTEXT canonical gap | `04-CONTEXT.md` lists `host-golden-paths-and-trace-guidance.md` and `developer-experience-index.md` as canonical but both are missing — plans 02/04/10 already create them; no plan rewrite required unless orchestrator wants CONTEXT updated | + +No task-level **needs-revision** for wrong file paths or deleted-code references at this baseline. + +--- + +## Coverage check vs 04-CONTEXT.md goals + +| Goal / decision cluster | Covered by (plan tasks) | Baseline status | +|-------------------------|-------------------------|-----------------| +| D-00 dual enforcement (admission + gateway) | 04-01 T2–T3, 04-11 T1 | **Uncovered** — no dual-enforcement tests or Clerk chain | +| D-00b x402 proof wedge | 04-01 T3, 04-02 T1, 04-09 | **Partial** — demo + story mention x402 clearance; no golden-path prose | +| D-01–D-06 agent vocabulary / dual-lane docs | 04-01 T1, T4 | **Partial** — non-authority flags in story; no Agent lane mapping table | +| D-07–D-09 progressive onboarding | 04-02 T1, 04-03, 04-07 | **Uncovered** | +| D-08 atomic install | 04-03 | **Uncovered** | +| D-10–D-12 HTTP profile / hybrid adapters | 04-08 | **Uncovered** — auth-md inline only | +| D-13 runnable spine | 04-02, 04-03, 04-12 | **Partial** — admission demo only | +| D-14 proof-gap stubs (prose only) | 04-02 T1, 04-09 | **Uncovered** at doc level | +| D-15–D-16 Tier-1 integrator + sequencer | 04-07, 04-04 | **Uncovered** | +| D-17–D-20 failure taxonomy | 04-05, 04-06 | **Uncovered** | +| D-21–D-23 custody split | 04-10 | **Partial** — production proof ledger without configuredBy | +| D-24 bypass enforcement | 04-11 | **Uncovered** — workflow boundary test ≠ handler walk | +| D-25 launch gates deferred | 04-11, 04-12 | **Aligned** — manifest not present (correct deferral) | + +**New baseline context not in original plans:** Phase 02 A2A negotiation surfaces on branch (`b2f277a`…`e710924`) — out of Phase 04 scope per CONTEXT; no new plan tasks required. + +--- + +## Final recommendation + +- [x] **Phase 04 plans need revision before execution:** YES (light revision — 04-01 and 04-02 integration notes only; not a full replan) +- [x] **If YES: dispatch gsd-planner to revise plans:** `04-01-PLAN.md`, `04-02-PLAN.md` (add baseline-integration preamble per Revision queue) +- [ ] **If NO: proceed directly to wave 1 execution** + +**Suggested execution start (after light 04-01/04-02 plan patch):** + +```text +Wave 1: 04-01 (gap-closure on existing docs) ∥ 04-02 (create golden path + devex index; narrow T3 to doc/link) +``` + +Operator checkpoint remains unavailable until waves 1–6 + plan 11 complete. + +--- + +## Open questions for orchestrator + +1. **`host-golden-paths-and-trace-guidance.md`** is listed in `04-CONTEXT.md` canonical refs but does not exist at `1e801b7`. Should Wave 2 plan 04 create it from scratch, or should a prior doc be restored from another branch before execution? +2. **`developer-experience-index.md`** is similarly missing but referenced as canonical. Confirm plan 02 T2 is the authoritative creation path (recommended: yes). + +--- + +*Audit method: read-only inspection of all 48 plan tasks against HEAD file contents and git ancestry; no code modified.* diff --git a/.planning/phases/04-service-agent-gating/04-CONTEXT.md b/.planning/phases/04-service-agent-gating/04-CONTEXT.md new file mode 100644 index 0000000..9958f77 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-CONTEXT.md @@ -0,0 +1,210 @@ +# Phase 04: Service agent gating — Context + +**Gathered:** 2026-05-28 +**Status:** Ready for execution (comprehensive replan 2026-05-28) +**Synthesis:** Eight advisor runs (discuss) + six advisor runs (plan review) + user mandate: **full product, not MVP** + + +## Phase Boundary + +**Deliver:** A **complete agent-first operator product** so **any service** can gate agents on consequential endpoints — doctrine, runnable service-side spine, executable atomic install, multi-surface failure taxonomy, Tier-1 integrator platform, HTTP adapter platform, custody runbooks, and **structural bypass enforcement** — without weakening the protocol kernel. **x402 remains the only runnable clearance wedge**; service-side runnable artifacts are admission, bootstrap, and dual-enforcement demos, not second payment/product completion paths. + +**Not in scope for this phase:** Kernel transition semantic changes; faking blocked live-x402/host-containment/registry gates green; schema export renames; external PEP as sole enforcement. + +**Product chain (agent lane):** + +```text +Vague intent +→ Scoped bounds (standing envelope + optional delegated mandate per instance) +→ Protected proposal (compile → exact work order) +→ Clearance (policy → one-use greenlight → gateway check) +→ Outcome (receipt / refusal / proof gap) +``` + +**Enforcement chain (locked):** + +```text +Hosted/API admission (who may talk to the kernel) ++ +Gateway check on every mutation (whether this exact greenlight authorizes this exact change) +``` + +**Explicit rule:** Ingress, middleware, or API auth **alone** is not Handshake unless **every consequential route** is adapter-wrapped and gateway-checked. Document and test that rule; do not imply admission equals protection. + +**In scope:** + +- Product vocabulary and dual-lane docs mapping agent story ↔ protocol spine (schema names unchanged). +- Progressive service onboarding: catalog triplet per endpoint family + per-instance bounds/mandate. +- Tier-1 integrator golden path (docs, tests, optional non-authority recipe sequencer). +- Hybrid adapter strategy for arbitrary HTTP + existing family adapters. +- Public failure taxonomy (auth vs execution-control) on service APIs. +- Custody split productization (service vs host operator). +- Structural bypass enforcement (architecture tests + service scaffold); not docs-only. + +**Out of scope:** + +- Protocol kernel transition semantic changes (same constraint as Phase 03). +- Turning blocked proof gates green (live x402 paid retry, host containment, registry). +- Second **runnable** non-payment golden path unless that domain’s admission packet is already green. +- Schema renames of `OperatingEnvelope`, `DelegatedAuthorityRef`, etc. +- External PEP (Envoy/OPA sidecar) as **substitute** for adapter-side gateway enforcement. +- Layer 5 clearing network, hosted marketplace trust, cross-org federation. +- Per-domain siloed golden paths that fragment the agent-first spine. + + + + +## Implementation Decisions + +### Locked before advisor research (user) + +- **D-00 — Dual enforcement:** Service operators need **admission** (caller identity / scope before kernel transitions) **and** **gateway check** (before mutation). Ingress-only posture is **advisory**, not Handshake. +- **D-00b — Wedge vs platform:** `x402_payment.exact` remains the **proof wedge**; phase 04 optimizes **any-service agent gating**, not payment-only product. + +### Vision → protocol mapping (advisor + canon) + +- **D-01 — Standing bounds:** `OperatingEnvelope` = class-level attempt bounds for principal+agent (not permission, not vague intent). +- **D-02 — Delegated mandate:** `DelegatedAuthorityRef` = episodic principal→agent mandate evidence for an instance (e.g. delegated spend); status transitions + isolation; **not** a greenlight or bearer pass. +- **D-03 — Compile bridge:** `IntentCompilationRecord` = vague intent/runtime evidence → one `CandidateAction` (uncertainty recorded, no authority). +- **D-04 — Work order:** `ActionContract` = exact proposed commitment; only this shape enters policy and gateway binding. +- **D-05 — Product vocabulary:** Teach **Standing Bounds → Delegated Mandate (when required) → Compile → Work Order → Clearance → Outcome** in agent-facing docs; keep schema-native names in protocol/API (attenuation-chain dual vocabulary, no export renames in this phase). +- **D-06 — Dual-lane docs:** Extend `service-workflow-story.md` pattern: agent lane parallel to unchanged canonical state path; every projection keeps explicit non-authority flags (`createsAuthority: false`, `freshActionContractRequired: true`). + +### Service onboarding order + +- **D-07 — Progressive two-tier (default):** Service registers **catalog triplet** per endpoint family (`ToolCapability`, `ActionType`, `GatewayRegistryEntry`) first so gateway binding and bypass posture are real; **per-instance** `OperatingEnvelope` + policy pack and/or `DelegatedAuthorityRef` at delegation/admission time. +- **D-08 — Atomic install per family:** Control-plane `InstallProposal` commits catalog + gateway + baseline policy bundle per family **or refuses** — no orphan catalog without gateway entry. +- **D-09 — Full day-one envelope:** Reserved for **fixed-tenant / regulated** services only — not the default multi-agent hosted path. + +### Adapter extensibility + +- **D-10 — Hybrid layered model:** Shared **HTTP transport profile** (method, path template, allowlisted headers, raw body digest) for arbitrary REST-like endpoints; **family adapters** (x402, package install, preview deploy, repo write, auth.md) where semantic canonicalization and bypass probes matter. +- **D-11 — auth.md as profile prototype:** Treat `auth_md_protected_api_call.exact` as the pattern for HTTP-profile canonicalization, not as proof that one generic adapter covers all consequence shapes. +- **D-12 — External PEP optional:** Envoy/Kong/OPA may sit **in front** for deployment; Handshake still requires adapter-side observed-parameter re-check against exact greenlight — PEP is glue, not enforcement substitute. + +### Operator golden path & kernel UX + +- **D-13 — One runnable spine:** Single agent-first recipe: register catalog → agent proposes → policy → gateway → readback; **x402** is the only **runnable** reference implementation in this phase. +- **D-14 — Proof-gap stubs:** Add **non-runnable** recipe stubs for auth.md and package install (transition map + schema + explicit proof-gap / admission boundaries) if integrators need transfer confidence — not second runnable paths. +- **D-15 — Tier-1 kernel UX:** Document and test a **Tier-1** transition set for integrators (catalog, compile/propose, evaluatePolicy, gatewayCheck, readback); full `protocol/navigation` matrix remains reference for extenders. +- **D-16 — Optional recipe sequencer:** SDK/CLI helper that calls transitions in order is allowed only as **explicitly non-authority**, with invariant tests: no greenlight reuse, gateway required, fresh contract on retry, no bundled “execute” API. + +### Public failure surface + +- **D-17 — Extend `TransitionErrorEnvelope`:** Add `failureClass` / `phase` separating `auth`, `hosted_admission`, `protected_action_refusal`, `proof_gap`, `replay_refusal`, `stale_admission`. +- **D-18 — HTTP status discipline:** **401/403** only for credential/identity; **409** refusals/replay/stale binding; **422** proof gaps; never map clearance failure to generic forbidden (OAuth BCP anti-pattern). +- **D-19 — RFC 9457 compatibility:** Problem Details `type` URIs + `reason-code-remediation` extensions for public HTTP consumers. +- **D-20 — Outcome-as-success:** **200 + claim status** only on dedicated admission/readback routes — not on mutation attempts. + +### Custody split (service vs host) + +- **D-21 — Responsibility matrix:** Extend production acceptance / operator docs with **configured-by** columns: service operator (gateway registry, gateway credential, mutation enforcement) vs host operator (trusted binding digests, MCP/runtime proposal wiring). +- **D-22 — Bilateral runbooks:** Paired `service-operator` and `host-operator` setup order (registry before host attestation; stale digests fail closed). +- **D-23 — Doctor as attestation:** Host `doctor` / readiness output framed as **attestation evidence** for binding digests — not a parallel identity system (SPIFFE analogy only in prose). + +### Bypass proof + +- **D-24 — Not documentation-only:** “Every consequential route adapter-wrapped” requires **architecture tests** + **conformance-gated service scaffold** — not prose alone. +- **D-25 — Launch gates deferred:** Product-completion-style per-service bypass proof packets (like x402/MCP activation) ship when route inventory and host evidence exist — not claimed in phase 04 for all services. + +### Claude's Discretion + +- Exact Tier-1 transition ID list and where it lives (`protocol/navigation` tags vs new doc). +- Whether proof-gap stubs ship in phase 04 or immediately after plan 01. +- Recipe sequencer module placement (`sdk/` vs `cli/quickstart/`). +- How many HTTP profile canonicalization rules are codified vs documented first. + + + + +## Canonical References + +**Downstream agents MUST read these before planning or implementing.** + +### Protocol & invariants +- `AGENTS.md` — Doctrine; vague intent vs contract; gateway enforcement; generated-code bypass. +- `docs/internal/protocol-definition.md` — Authority rule, required separation, canonical state path. +- `docs/internal/protocol-kernel-architecture.md` — Catalog objects, layers, transition map. +- `docs/internal/protocol-layman.md` — Plain-language spine for operator docs. +- `docs/internal/protocol-notes.md` — `delegated-authority`, catalog-envelope, compile/propose notes. +- `docs/internal/decisions.md` — DelegatedAuthorityRef, role-scoped clients, production acceptance matrix, live x402 boundaries. + +### Agent-first product story +- `docs/internal/service-workflow-story.md` — Passport → Admission → Handle → Clearance; non-authority IDs. +- `docs/internal/ecosystem-strategy.md` — Layer 0–5 model; do not collapse layers. +- `docs/internal/host-golden-paths-and-trace-guidance.md` — Host golden path (x402 reference). + +### Code spine (implementation anchors) +- `src/protocol/kernel.ts` — HandshakeKernel façade. +- `src/protocol/navigation/index.ts` — Full transition catalog. +- `src/protocol/foundation/host-trusted-binding.ts` — Host trusted binding (Phase 03). +- `src/http/admission/index.ts` — Transition admission. +- `src/http/routes/transition-route-registry.ts` — HTTP parity with kernel. +- `src/adapters/` — Family gateway adapters. +- `src/surfaces/service-workflow-admission/` — Admission/handle projections. +- `src/protocol/foundation/reason-code-remediation/` — Remediation on failures. +- `src/http/errors/transition-error-envelope.ts` — Error envelope extension point. + +### Prior phase (do not re-litigate) +- `.planning/phases/03-close-enforcement-gaps/03-CONTEXT.md` — Host trusted binding parity; kernel frozen. +- `.planning/phases/03-close-enforcement-gaps/03-VERIFICATION.md` — Phase 03 complete. + +### Codebase map (scratch) +- `.planning/codebase/ARCHITECTURE.md` — Layer diagram, Phase 03 spine. +- `.planning/codebase/CONCERNS.md` — Open launch blockers vs recently closed binding parity. + + + + +## Existing Code Insights + +### Reusable Assets +- `HandshakeKernel` + `protocol/navigation` — Tier-1 tagging and parity tests without new transitions. +- `InstallClient` / install-setup transitions — Atomic per-family catalog bootstrap. +- `service-workflow-admission` surfaces — Dual-lane agent story already modeled. +- `host-trusted-binding` + MCP/adapter proposal paths — Custody split for host vs service. +- `auth_md_protected_api_call` adapter — HTTP profile template for hybrid extensibility. +- `transition-error-envelope` + `reason-code-remediation` — Public failure surface extension. +- x402 + architecture bypass/activation tests — Reference runnable path and bypass patterns. + +### Established Patterns +- Catalog presence is not permission; fresh action contract per consequential event. +- Role-scoped SDK clients (`PolicyClient`, `GatewayClient`, etc.) — custody boundaries. +- Proof packets and `pack:check` — Honest blocked gates; do not fake green in phase 04. +- Architecture tests for boundaries (`workflow-admission-boundary`, `claim-boundary`, host-trusted parity). + +### Integration Points +- HTTP transition routes + hosted admission for service operators. +- MCP/runtime proposal for agent hosts (binding digests, not gateway ownership). +- Adapter `run*Gateway` functions as mutation enforcement boundary. +- CLI `doctor`, `simulate`, `quickstart` for recipe sequencer and attestation UX. + + + + +## Specific Ideas + +- Build for **agents first**: principal delegates to agent within **scoped bounds** for a **particular instance**; policy decides on the **exact** action; service gateway enforces before mutation. +- User concern: kernel feels **rigid** — acceptable; usability via **vocabulary, tiers, recipes, and docs** — not fewer transitions or authority shortcuts. +- Comparative patterns cited by advisors: OAuth delegation/attenuation, Macaroon caveats, Cedar/OPA permit query, Stripe Connect matrix, Envoy ext_authz, MCP gateway CI, SLSA/in-toto conformance — adopt **mechanisms**, not bearer-token or online-only authz models. + + + + +## Deferred Ideas + +- **Second runnable golden path** (auth.md or package install) in same phase — until admission packet + focused gates green (`decisions.md` proof contexts). +- **Schema export aliases** (`StandingBounds`, `DelegatedMandate`) — product docs only in phase 04. +- **Generic HTTP-only platform claim** without family adapters for wallet/repo/deploy/install — insufficient bypass posture. +- **External PEP as sole gate** — evidence theatre without adapter re-check. +- **Per-domain operator doc silos** — fragments agent-first spine. +- **Layer 5 clearing / cross-org verification** — `ecosystem-strategy.md` Layer 5. +- **Full kernel transition reduction** — breaks reconstruction and parity tests. +- **Hosted operation go-ahead** — separate hosted workspace per `protocol-notes.md` hosted admission lock. + + + +--- + +*Phase: 04-service-agent-gating* +*Context gathered: 2026-05-28* diff --git a/.planning/phases/04-service-agent-gating/04-DELIVERY-ARCHITECTURE.md b/.planning/phases/04-service-agent-gating/04-DELIVERY-ARCHITECTURE.md new file mode 100644 index 0000000..aeaf39e --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-DELIVERY-ARCHITECTURE.md @@ -0,0 +1,146 @@ +# Phase 04 — Delivery architecture (comprehensive) + +**Purpose:** Engineering blueprint for replanned `04-0N-PLAN.md` files. This is **not** an MVP enablement slice. + +## Product surfaces (three operator personas) + +| Persona | Runnable artifacts this phase | Authority boundary | +|---------|------------------------------|-------------------| +| **Service operator** | `service-operator-golden-path.md`, `examples/service-operator-bootstrap/`, canonized `demo:service-workflow-admission`, `handshake service bootstrap` (x402 family) | Owns gateway registry, adapter wiring, per-route `run*Gateway` | +| **Host operator** | Mandatory `handshake quickstart agent-spine`, host golden path sync, doctor attestation chain | Owns trusted binding digests, MCP proposal wiring — not gateway ownership | +| **Integrator (SDK/HTTP)** | Tier-1 navigation + parity, role-scoped clients walkthrough tests, failure taxonomy on all transports | Uses kernel transitions; never bundles execute | + +## Clerk-for-agents (enforced in code + docs + CI) + +```text +Request + → http/admission (middleware: identity + transition scope) + → kernel transitions (compile, propose, policy, gatewayCheck evidence) + → service app handler (route handler: adapter.run*Gateway before mutation) + → downstream effect +``` + +**Failure mode to eliminate:** Operators deploy admission + API auth and believe agents are gated. + +## Operator journey (single Start Here — product/user audit) + +| Step | All operators | Service branch (Branch A) | Host branch (Branch B) | +|------|---------------|---------------------------|------------------------| +| 1–2 | What Handshake is; dual enforcement | — | — | +| 3 | **Custody fork** | Golden path continues | `host doctor` → `quickstart x402` → `simulate` | +| Runnable | — | `demo:service-workflow-admission`, `handshake service bootstrap` | Optional convenience: `quickstart agent-spine` | + +**Not runnable (prose proof-gap list only):** auth.md live gateway, package install live gateway, registry discoverability — no quickstart-shaped stub packages. + +## Subsystems delivered + +### S1 — Doctrine & dual-lane canon (Plan 01) +- Agent lane in `service-workflow-story.md`, `protocol-layman.md`, `protocol-definition.md` +- `dual-enforcement-posture.test.ts`, extended `claim-boundary.test.ts` +- `ecosystem-strategy.md` layer discipline unchanged + +### S2 — Service-operator golden path product (Plan 02) +- `docs/internal/service-operator-golden-path.md` as **primary TTHW** with unified journey + step-3 custody fork +- `docs/internal/developer-experience-index.md` single Start Here → golden path (not dual spines) +- Branch A: verify caller → admission/handle → clearance (x402) → readback +- Branch B: host commands in fork (agent-spine optional) + +### S3 — Atomic install executable (Plan 03) +- `examples/service-operator-bootstrap/` — TypeScript recipe: catalog triplet + `InstallClient.registerInstallProposalCompiledRecords` +- `src/cli/service/bootstrap.ts` + manifest entry `handshake service bootstrap` (x402 family only) +- Tests: `test/product/service-operator-bootstrap.test.ts`, extend `http.test.ts` install path as reference +- Golden path links with copy-paste blocks + +### S4 — Agent-host spine recommended (Plan 04) +- `src/cli/quickstart/agent-spine.ts` — **recommended** convenience chaining: doctor → x402 quickstart → simulate (non-authority) +- Canonical host path remains discrete commands in devex index +- `test/cli/cli-agent-spine-sequencer.test.ts` — anti-theatre: no bundled execute, no greenlight reuse + +### S5 — Failure taxonomy — HTTP + operator table (Plan 05) +- `failureClass`, `failurePhase`, `problemType` on `TransitionErrorEnvelope` +- `httpStatusForFailureClass` — 401/403 auth only; 409 refusals; 422 proof gaps +- `test/http/transition-error-failure-class.test.ts` — negative + **positive** readback 200+claim (D-20) +- `src/http/openapi/index.ts` documents new fields +- Golden path + devex index: **one** `failureClass` operator table (not three transport cheat sheets) + +### S6 — Failure taxonomy — multi-surface parity only (Plan 06) +- SDK: `failureClass` on `HandshakeClientError` via `transport.ts` / `repair.ts` +- MCP: shared classifier helper used by `mcp/x402-proposal.ts` + `test/mcp/mcp-failure-class-parity.test.ts` +- `test/sdk/role-clients-failure-class.test.ts` — Policy/Gateway/Evidence clients surface typed failures + +### S7 — Tier-1 integrator platform (Plan 07) +- `integratorTier1: true` metadata on navigation entries +- `docs/internal/integrator-tier-1-transitions.md` — IDs, roles, HTTP routes, SDK clients +- `test/architecture/integrator-tier-1-parity.test.ts` +- Tier-1 set: catalog quartet, `registerInstallProposalCompiledRecords`, `registerDelegatedAuthorityRef`, `compileIntent`, `proposeActionContract`, `evaluatePolicy`, `gatewayCheck`, `reconcileSurfaceOperation`, evidence readbacks + +### S8 — HTTP profile & adapter platform (Plan 08) +- `src/adapters/http-profile/` — shared transport schema + `canonicalizeHttpProfile` +- auth.md refactored to compose profile +- `src/adapters/http-profile/generic-gateway-skeleton.ts` — conformance probe only, **definition_only** posture, no live mutation +- `test/adapters/http-profile-canonicalization.test.ts` +- Install triplet template doc section + test that orphan catalog without gateway registry entry fails compile + +### S9 — Proof-gap honesty (Plan 09) +- Prose proof-gap table in golden path (no stub example directories) +- `test/architecture/proof-gap-honesty.test.ts` +- Upgrade `examples/external-adapter-sdk/README.md` with dual-enforcement checklist + +### S10 — Custody & bilateral operations (Plan 10) +- `decisions.md` production acceptance matrix: configured-by columns +- Bilateral setup sections in golden path + host golden path (standalone runbooks **post-execute**) +- Doctor output framed as attestation evidence in `src/cli/host/doctor.ts` copy + `mcp/doctor.ts` + +### S11 — Bypass enforcement minimal (Plan 11) +- `test/architecture/http-handler-mutation-gating.test.ts` — walk handlers for adapter binding posture (**phase 04 D-24**) +- **Deferred:** manifest module, registry sync, conformance expansion, product-completion inventory slice → phase 05 + +### S12 — Two-tier E2E verification (Plan 12) +- `test/integration/service-operator-golden-path.test.ts` — admission demo + bootstrap idempotency smoke +- `operator-product-completion-contract` vs `maintainer-product-completion-contract` +- `04-VERIFICATION.md` with operator vs full sign-off +- `scripts/check-service-agent-gating-phase.mjs --tier operator|full` + +## Wave execution graph + +```text +Wave 1: 01, 02 (doctrine + golden path product) +Wave 2: 03, 04 (service bootstrap + agent spine) — parallel +Wave 3: 05 (failure HTTP + operator failure table) +Wave 4: 06, 07 (failure parity + tier-1) — parallel; 06 after 05; 07 after 03 +Wave 5: 08 (HTTP profile platform) — after 05 +Wave 6: 09, 10 (proof-gap honesty + custody) — parallel; 09 after 08; 10 after 02, 04 +Wave 7: 11 (handler mutation gating) — after 03, 07, 08 +Wave 8: 12 (E2E verification) — after all +``` + +## Success definition + +### Operator tier (waves 1–6 + handler walk — shippable TTHW) + +A service operator can: + +1. Follow **one** golden path (step-3 fork) and run **admission demo** + **service bootstrap** in < 30 minutes without integrator appendix. +2. Use the **failureClass table** for HTTP errors (SDK/MCP parity proven in CI, not separate reading). +3. Understand custody split via bilateral sections and decisions matrix. + +A host operator can: + +4. Use **doctor → x402 quickstart → simulate** (agent-spine optional). + +CI: + +5. Fails if docs claim admission-only protection. +6. Fails if first-party handlers lack adapter binding (`http-handler-mutation-gating`). + +### Full tier (wave 8 — engineering complete) + +Adds integrator Tier-1 parity, http-profile platform, proof-gap honesty tests, maintainer contract bundle. Manifest/sync still deferred to phase 05 with explicit pointer. + +## Explicit non-goals (unchanged locks) + +- Second runnable clearance path (auth.md, package install live) +- Kernel transition changes +- Schema renames +- MCP registry acceptance green +- Per-customer production route `pack:check` for arbitrary third-party services (D-25 scoped to first-party dogfood + scaffold) diff --git a/.planning/phases/04-service-agent-gating/04-DEVIATIONS.md b/.planning/phases/04-service-agent-gating/04-DEVIATIONS.md new file mode 100644 index 0000000..79027f4 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-DEVIATIONS.md @@ -0,0 +1,10 @@ +# Phase 04 execution deviations + +## Deferred (out of Antipattern Rule radius) + +### test/http/http.test.ts — D-18 HTTP status discipline + +- **Found during:** post-wave verification / full test suite +- **Issue:** Two failures — expired hosted identity expects 412 but handler returns 409; recovery terminal conflict expects 409 but handler returns 422 +- **Reason not fixed inline:** `test/http/http.test.ts` not in any executed plan task `files_modified` +- **Recommendation:** Phase 05 HTTP status normalization or targeted plan with explicit files_modified diff --git a/.planning/phases/04-service-agent-gating/04-EXECUTION-LOG.md b/.planning/phases/04-service-agent-gating/04-EXECUTION-LOG.md new file mode 100644 index 0000000..ab7929b --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-EXECUTION-LOG.md @@ -0,0 +1,32 @@ +# Phase 04 execution log + +Branch: `phase-04-service-agent-gating` +Baseline: `1e801b7` +Completed range: `1e801b7..d18f2d3` + +## Wave 6–8 (this session continuation) + +| Timestamp (UTC) | Task | Status | Commit | Note | +| --- | --- | --- | --- | --- | +| 2026-05-29 | 04-09 T1-T2 | built | f682013 | Proof-gap table + proof-gap-honesty.test.ts | +| 2026-05-29 | 04-09 T3 | extended | 8b3e056 | Consolidated dual-enforcement checklist in external-adapter-sdk README | +| 2026-05-29 | 04-09 T4 | built | 1a1153d | Integrator tier-1 runnable/proof-gap flags (in 04-10 commit bundle) | +| 2026-05-29 | 04-10 T1-T4 | built | 1a1153d | configuredBy matrix, bilateral sections, doctor framing, custody test | +| 2026-05-29 | 04-10 T3 | extended | db771bf, b4e0cad | MCP doctor test + x402 digest ref binding fix | +| 2026-05-29 | 04-11 T1 | built | d777a21 | http-handler-mutation-gating.test.ts | +| 2026-05-29 | 04-12 T1-T3 | built | 283c015 | Integration smoke, completion contracts, tiered gate script | +| 2026-05-29 | 04-12 T3 | extended | cb6d266 | Removed duplicate npm phase-gate scripts | +| 2026-05-29 | 04-12 T4 | built | d18f2d3 | 04-VERIFICATION.md status passed | + +## Waves 1–5 (pre-baseline continuation, skipped in this session) + +Plans 01–08 tasks marked **already-done** or **partially-done** in `04-BASELINE-AUDIT.md` were completed at commits through `ac7b8a8` before this executor continuation. + +## Verification + +- `node scripts/check-service-agent-gating-phase.mjs --tier operator` — PASS (10 checks) +- `node scripts/check-service-agent-gating-phase.mjs --tier full` — PASS (15 checks) + +## Open questions + +- `test/http/http.test.ts` D-18 status discipline mismatches (412 vs 409, 409 vs 422) — logged in `04-DEVIATIONS.md`, out of plan 05 files_modified radius. diff --git a/.planning/phases/04-service-agent-gating/04-PLAN-ADVISOR-REVIEW.md b/.planning/phases/04-service-agent-gating/04-PLAN-ADVISOR-REVIEW.md new file mode 100644 index 0000000..22070d0 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-PLAN-ADVISOR-REVIEW.md @@ -0,0 +1,93 @@ +# Phase 04 — Plan advisor review (full lens) + +**Date:** 2026-05-28 +**Calibration:** `full_maturity` +**Lens:** Six parallel `gsd-advisor-researcher` passes against `04-01`–`04-06` vs phase goal in `04-CONTEXT.md` + +**Superseded:** User rejected MVP framing. Replaced by **12-plan comprehensive delivery** — see `04-DELIVERY-ARCHITECTURE.md`, `04-PLANS-INDEX.md`, plans `04-01`–`04-12`. + +## Verdict (historical — pre-replan) + +**Your concern was right for the original 6-plan slice.** That slice was a **strong MVP integrator-enablement slice**, not a **shippable “clone any service and gate agents” product**. That is **consistent with locked constraints** (kernel frozen, x402-only runnable, D-25 deferral) but **under-delivers the marketing phrase “any service”** unless you add **2–3 targeted plan augmentations** before execute. + +| Dimension | Plans deliver? | MVP risk | +|-----------|----------------|----------| +| Clerk-for-agents framing + anti-middleware theatre | Yes (01 + arch tests) | Low | +| Public failure taxonomy (agent retries) | Mostly (02); gap on MCP/SDK parity | Medium | +| Tier-1 integrator surface | Yes (03) | Low | +| HTTP extensibility foundation | Yes (04 schema + stubs) | Low if positioned as transport layer only | +| Custody split | Yes (05 docs) | Low for phase scope | +| Structural bypass proof | **Floor only** (06 manifest) | **High** — inventory ≠ enforcement | +| **Executable service onboarding** | **No** | **High** — D-08 doc-only | +| **Service-side runnable spine** | **No** (x402 agent-side only) | **High** — Clerk “route handler” gap | + +## Recommended augmentations (before `/gsd-execute-phase`) + +Priority order — smallest mechanism that closes the largest honesty gap: + +### 1. Plan 07 (or expand 01 + 03): **InstallClient bootstrap** — closes D-08 executability + +- One x402-only script/recipe: `compileX402InstallProposal` → `InstallClient.registerInstallProposalCompiledRecords` +- Linked from `service-operator-golden-path.md` as the **service operator** copy-paste step (not host MCP) +- **Advisor consensus:** (A) alone teaches vocabulary; **(A)+(B)** is lowest-regret + +### 2. Plan 07 (or expand 01): **Service-side admission demo canon** — closes Clerk route-handler gap + +- Canonize existing `npm run demo:service-workflow-admission` in golden path + devex index +- Optional thin `examples/service-operator-golden-path/` wrapper if README drift is bad +- **Not** A2A room as template (wrong abstraction) +- **Advisor consensus:** x402 quickstart + docs = **middleware side only** without this + +### 3. Expand 06: **D-24 floor + structural walk** — not manifest-only theatre + +- Keep manifest schema (A) +- **Add:** conformance/architecture test walking `src/http/handlers` (or registry) for unwrapped mutation posture (D) +- **Defer:** full `pack:check` inventory for all services (D-25) + +### 4. Expand 02: **MCP failure parity** — agent-complete failure surface + +- Add task: MCP stdio / x402 proposal errors align with `failureClass` retry semantics (C) +- Optional: SDK `HandshakeClientError` carries `failureClass` (B) if SDK is same release train + +### 5. Plan 03: **Mandatory** `quickstart agent-spine` (not optional) — if agent host is co-equal persona + +- Only if you want stronger agent TTHW in same phase; does **not** fix service-operator gap alone + +## What to keep as intentionally MVP (do not expand without new phase) + +- Second runnable golden path (auth.md, package install live) +- Generic HTTP-only gateway claiming full REST coverage +- Manifest wired to every customer production route table (operator-specific) +- Full RFC 9457 dual `application/problem+json` mode +- Turning blocked proof gates green + +## Phase goal reframing (honest) + +| Claim | Honest after current 6 plans | Honest after augmentations 1–4 | +|-------|------------------------------|--------------------------------| +| “Integrators won’t mistake admission for protection” | Yes | Yes | +| “Agents get safer HTTP failure semantics” | Mostly | Yes | +| “Any service can gate agents” (operator TTHW) | **Narrative + patterns** | **Narrative + one runnable service bootstrap + one admission demo** | +| “Bypass impossible without adapters” | **Scaffold + examples** | **Scaffold + handler walk** | + +## Per-plan advisor notes + +| Plan | Adequate for locked decisions? | MVP slice? | Suggested action | +|------|-------------------------------|------------|------------------| +| 01 | D-01–D-06 yes; D-07–D-09 prose only | Yes for onboarding | Add bootstrap link or plan 07 | +| 02 | D-17–D-20 HTTP yes | Partial for agents | Add MCP parity task | +| 03 | D-15–D-16 yes | No if sequencer optional | Make sequencer mandatory OR accept doc-only Tier-1 | +| 04 | D-10–D-11–D-14 yes | No if sold as “any REST” | Keep; position as transport + stubs | +| 05 | D-21–D-23 yes | No | Execute as written | +| 06 | D-24 floor; D-25 defer OK | **Yes for bypass depth** | Add handler-walk test | + +## Split alternative (if “any service” is non-negotiable this milestone) + +**04a** — current six plans (docs, taxonomy, tier-1, profile, custody, manifest floor) +**04b** — runnable service reference: InstallClient bootstrap + admission demo + handler conformance walk + optional manifest↔registry dogfood + +Only choose split if you will **commit to 04b** before claiming operator product complete. + +--- + +*Synthesized from advisor runs: phase granularity, plan 01 onboarding, plan 06 bypass, runnable spine, HTTP profile, plan 02 failures.* diff --git a/.planning/phases/04-service-agent-gating/04-PLANS-INDEX.md b/.planning/phases/04-service-agent-gating/04-PLANS-INDEX.md new file mode 100644 index 0000000..1d6c09b --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-PLANS-INDEX.md @@ -0,0 +1,122 @@ +# Phase 04 — Service agent gating (comprehensive delivery) + +**Status:** Ready to execute (product/user audit + wave dependency fix 2026-05-28) +**Context:** [04-CONTEXT.md](./04-CONTEXT.md) +**Delivery architecture:** [04-DELIVERY-ARCHITECTURE.md](./04-DELIVERY-ARCHITECTURE.md) +**Product/user audit:** [04-PRODUCT-USER-AUDIT.md](./04-PRODUCT-USER-AUDIT.md) (applied to all plans) +**Research:** [04-RESEARCH.md](./04-RESEARCH.md) +**Patterns:** [PATTERNS.md](./PATTERNS.md) +**Validation:** [04-VALIDATION.md](./04-VALIDATION.md) +**Verification (post-execute):** [04-VERIFICATION.md](./04-VERIFICATION.md) (created in plan 12) + +> **Comprehensive delivery — not MVP.** Twelve plans deliver full operator product with **two-tier sign-off**: operator TTHW (waves 1–6 + handler walk) vs full maintainer completeness (deferred manifest lane). + +**Invariant:** Admission identifies callers; only adapter-wrapped `VerifiedGatewayCheck` before mutation is Handshake. Ingress-only posture is advisory (D-00). Kernel transition semantics stay frozen (Phase 03 lock). + +**Clerk-for-agents framing:** + +```text +Request + → http/admission (middleware: identity + transition scope) + → kernel transitions (compile, propose, policy, gatewayCheck evidence) + → service app handler (route handler: adapter.run*Gateway before mutation) + → downstream effect +``` + +## Operator journey (single Start Here) + +```text +developer-experience-index → service-operator-golden-path.md + Steps 1–2: what Handshake is + dual enforcement + Step 3 fork: + Branch A (service API) → demo / service bootstrap → failure table + Branch B (agent host) → host doctor → quickstart x402 → simulate + (optional: quickstart agent-spine) + Advanced (not first 30 min) → integrator-tier-1-transitions.md +``` + +## Wave graph + +```text +Wave 1: 01 dual-lane doctrine, 02 unified golden path product +Wave 2: 03 atomic install bootstrap, 04 agent-spine (recommended) — parallel +Wave 3: 05 failure taxonomy HTTP + operator failure table +Wave 4: 06 parity-only multi-surface, 07 tier-1 integrator platform (appendix doc) — parallel; 06 after 05; 07 after 03 +Wave 5: 08 HTTP profile adapter platform — after 05 +Wave 6: 09 proof-gap prose + honesty test, 10 custody (matrix + bilateral sections) — parallel; 09 after 08; 10 after 02, 04 +Wave 7: 11 handler mutation gating only (manifest deferred) +Wave 8: 12 two-tier E2E verification — after all +``` + +**Operator sign-off available after Wave 6** (`check-service-agent-gating-phase.mjs --tier operator`). + +## Plans (12) + +| Plan | File | Subsystem | Wave | Depends on | Tasks | Objective | +|------|------|-----------|------|------------|-------|-----------| +| 01 | [04-01-PLAN.md](./04-01-PLAN.md) | S1 dual-lane doctrine | 1 | — | 4 | **executed** — Agent lane in workflow story; dual-enforcement in decisions/notes + arch tests | +| 02 | [04-02-PLAN.md](./04-02-PLAN.md) | S2 golden path product | 1 | — | 4 | **executed** — Unified journey + step-3 fork; service-first index | +| 03 | [04-03-PLAN.md](./04-03-PLAN.md) | S3 atomic install | 2 | 01, 02 | 5 | **executed** — service bootstrap example + CLI + HTTP tests | +| 04 | [04-04-PLAN.md](./04-04-PLAN.md) | S4 agent-spine | 2 | 01, 02 | 4 | **executed** — recommended quickstart agent-spine + anti-theatre tests | +| 05 | [04-05-PLAN.md](./04-05-PLAN.md) | S5 failure HTTP | 3 | — | 5 | **executed** — failureClass envelope + golden-path failure table | +| 06 | [04-06-PLAN.md](./04-06-PLAN.md) | S6 failure parity | 4 | 05 | 4 | **executed** — shared failureClass; SDK/MCP parity + repair helpers | +| 07 | [04-07-PLAN.md](./04-07-PLAN.md) | S7 tier-1 integrator | 4 | 03 | 4 | **executed** — integratorTier1 navigation + appendix + parity tests | +| 08 | [04-08-PLAN.md](./04-08-PLAN.md) | S8 HTTP platform | 5 | 05 | 5 | **executed** — http-profile module; auth.md compose; orphan guard | +| 09 | [04-09-PLAN.md](./04-09-PLAN.md) | S9 proof-gap honesty | 6 | 08 | 4 | **executed** — proof-gap prose + honesty test; no stub dirs | +| 10 | [04-10-PLAN.md](./04-10-PLAN.md) | S10 custody | 6 | 02, 04 | 4 | **executed** — configuredBy matrix + bilateral sections + doctor attestation | +| 11 | [04-11-PLAN.md](./04-11-PLAN.md) | S11 bypass (minimal) | 7 | 03, 07, 08 | 1 | **executed** — http-handler-mutation-gating test; manifest deferred | +| 12 | [04-12-PLAN.md](./04-12-PLAN.md) | S12 E2E verification | 8 | 01–11 | 4 | **executed** — tiered gate script; integration + completion contracts | + +**Total:** 48 tasks across 12 plans, 8 waves. + +## Two-tier phase gates + +| Tier | When | Command | Meaning | +|------|------|---------|---------| +| **Operator** | After wave 6 (+ plan 11 handler test) | `node scripts/check-service-agent-gating-phase.mjs --tier operator` | Service operator TTHW shippable | +| **Full** | After wave 8 | `node scripts/check-service-agent-gating-phase.mjs --tier full` | Complete engineering slice; manifest still deferred to phase 05 | + +## Deferred (maintainer lane — not blocking operator TTHW) + +| Item | Was in | Now | +|------|--------|-----| +| `service-mutation-route-manifest` + registry sync | Plan 11 | Phase 05 / post-operator | +| `http-profile-adapter-conformance` expansion | Plan 11 | Phase 05 | +| `check-product-completion` dual-enforcement inventory slice | Plan 11 | Phase 05 | +| `service-operator-runbook.md`, `host-operator-runbook.md` | Plan 10 | Post-execute extract from golden paths | +| `examples/auth-md-protected-api-stub/`, `package-install-protected-action-stub/` | Plan 09 | **Eliminated** — prose proof-gap list only | +| `handshake failures explain` CLI | Discussed in 05/06 | **Eliminated** — `explainHandshakeError` + failureClass | +| `protocol-definition` / `ecosystem-strategy` dual-lane expansion | Plan 01 | **Eliminated** — decisions.md + protocol-notes | + +## Decision coverage (D-00..D-25) + +Unchanged — see prior index; D-24 satisfied in phase 04 by handler walk; full manifest D-24 deferred with explicit phase 05 pointer in plan 11/12. + +## Kernel invariants (all plans) + +- **No protocol kernel transition semantic changes** — navigation metadata, HTTP envelope, surfaces, docs, tests only. +- **No schema export renames** — product vocabulary in docs; API names unchanged. +- **One runnable clearance wedge** — x402 only; auth.md and package install remain proof-gap prose. +- **Do not fake blocked proof gates green** — live x402 paid retry, host containment, registry discoverability. +- **Dual enforcement** — admission + gateway on every consequential route; external PEP is glue only. +- **D-25:** Per-customer product-completion bypass packets deferred; first-party dogfood + scaffold only. + +## Execute + +```bash +/gsd-execute-phase 04-service-agent-gating +``` + +Recommended wave order: **01, 02** → **03 ∥ 04** → **05** → **06 ∥ 07** → **08** → **09 ∥ 10** → **11** → **12**. + +Operator checkpoint (optional mid-phase): + +```bash +node scripts/check-service-agent-gating-phase.mjs --tier operator +``` + +Full phase gate (after plan 12): + +```bash +node scripts/check-service-agent-gating-phase.mjs --tier full +``` diff --git a/.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md b/.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md new file mode 100644 index 0000000..f3046bb --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-PRODUCT-USER-AUDIT.md @@ -0,0 +1,190 @@ +# Phase 04 — Product / user perspective audit (GSD advisor synthesis) + +**Status:** ✅ **Applied** to all `04-0N-PLAN.md`, `04-PLANS-INDEX.md`, and `04-DELIVERY-ARCHITECTURE.md` on 2026-05-28. + +**Date:** 2026-05-28 +**Scope:** Comprehensive 12-plan delivery (`04-01` … `04-12`) +**Method:** Five parallel `gsd-advisor-researcher` gray-area passes (dual-spine UX, doc sprawl, integrator overload, failure fragmentation, bypass/wave delay) +**Audience:** Service operator (“gate agents on my API”), host operator, agent/automation loop — not protocol researchers + +**Invariant at stake:** Operators must not believe agents are gated when only admission or host doctor ran. Product debt that reads like completeness but does not shorten TTHW is enforcement theatre. + +--- + +## Executive verdict + +The 12-plan engineering slice is **correct for custody and Clerk-for-agents truth**. The **product/user debt** is mostly **navigation, sequencing, and mandatory reading** — not missing subsystems. + +| Verdict | Area | +|---------|------| +| **Keep (code + tests)** | Dual enforcement, atomic install (03), failureClass (05→06), Tier-1 parity (07), http-profile (08), handler mutation gating (11 minimal), phase gate (12) | +| **Reframe (docs + index)** | Two equal “Start Here” spines → one journey with step-3 custody fork; hub in existing index + workflow story, not 4+ new doc filenames | +| **Demote (operator mandatory)** | `handshake quickstart agent-spine` as convenience, not second required spine; proof-gap stubs as one paragraph, not runnable-shaped packages | +| **Defer or slim (maintainer-only)** | Plan 11 manifest + registry sync before operator E2E; bilateral runbook *files* until CLI/doctor output is stable | +| **Do not cut** | Plan 05→06 mechanical parity; plan 11 handler-walk test; runnable x402 service bootstrap | + +**Brutal summary:** A payments-API operator should reach a gated route in **waves 1–3** (~plans 01–06), not after wave 7. Today’s index and plan deliverables imply they must survive integrator platform and bypass CI first — that is frustration debt, not safety. + +--- + +## Persona: what “done” feels like + +### Service operator (primary buyer) + +**Success in < 30 minutes:** + +1. `developer-experience-index.md` → one **service-operator** section (not host/MCP rows first). +2. Plain flow: verify caller → admission → clearance (x402) → readback. +3. Run `demo:service-workflow-admission` or `handshake service bootstrap`. +4. One **failure table** (`failureClass` × safe retry × forbidden actions) for HTTP errors they see. + +**Must not read first:** Tier-1 transition matrix, http-profile module, proof-gap stub READMEs, kernel architecture map, bypass manifest, ecosystem-strategy essays, `.planning/` scratch. + +### Host operator (secondary, same phase) + +**Success:** doctor → x402 quickstart → simulate (already in index). +**Frustration to eliminate:** A second top-level “mandatory spine” that re-chains the same three commands under a new name. + +### Agent / automation (user of failures) + +**Success:** Same `failureClass` semantics whether the loop hit HTTP, MCP, or SDK — one golden-path matrix, not three cheat sheets. +**Danger:** 403 on clearance → credential retry loops (OAuth BCP failure mode). + +--- + +## Consolidated recommendations (apply before `/gsd-execute-phase`) + +### 1. Unified operator journey (plans 02 + 04 + index) + +| Current | Change | +|---------|--------| +| Dual runnable spines both labeled “required” / parallel Start Here | **One** `operator-journey` narrative (new section in golden path or workflow story): steps 1–2 shared (what Handshake is, dual enforcement), **step 3 fork** — “I operate the API” vs “I operate the agent host” | +| Plan 04 mandatory `quickstart agent-spine` | **Recommended** convenience command; discrete `host doctor` / `quickstart x402` / `simulate` remain canonical in index | +| `operator-product-completion-contract` requires agent-spine | Require **host branch runnable** (doctor + x402 quickstart), not necessarily the bundled sequencer | + +**Keep under the hood:** `service bootstrap`, `agent-spine` CLI, both demos — custody split stays real (D-21/D-22). + +### 2. Documentation debt elimination (plans 01, 02, 07, 10) + +| Planned new file | Recommendation | +|------------------|----------------| +| `service-operator-golden-path.md` | **Primary TTHW content** — OK as one file **or** major section in `service-workflow-story.md` + index anchors; not both plus 3 siblings | +| `integrator-tier-1-transitions.md` | **Appendix only** — one link from golden path “Advanced”; never in Start Here | +| `service-operator-runbook.md` / `host-operator-runbook.md` | **Defer file creation** to post-execute (plan 10): ship matrix + doctor behavior first; prose runbooks when CLI output is stable | +| Plan 01 `protocol-definition` / `ecosystem-strategy` dual-lane expansion | **Cut** — record vocabulary in `decisions.md` / `protocol-notes.md`; tests carry doctrine | +| Bulk `protocol-layman.md` rewrite | **Cut unless** user-facing terms change — link from index | + +**Hub rule:** Extend `developer-experience-index.md` + `service-workflow-story.md`; avoid 8 parallel internal doc entry points. + +### 3. Integrator platform vs operator TTHW (plans 07–09) + +| Plan | Operator-visible? | Recommendation | +|------|-------------------|----------------| +| 07 Tier-1 | No (first session) | **Execute** navigation tags + parity tests; **hide** doc behind “Advanced” | +| 08 http-profile | No | **Execute** for plan 11 + auth.md composition; not golden-path reading | +| 09 proof-gap stubs | **Harmful** if shaped like quickstarts | **Eliminate standalone stub packages**; replace with golden-path **proof-gap list** (auth.md, package-install, registry) + arch test that they stay `runnable: false` | + +**Do not move 07–09 to phase 05** unless you also defer plan 11 — plan 11 depends on 07+08. + +### 4. One failure story (plans 05 + 06 + 02) + +| Current | Change | +|---------|--------| +| 05 = HTTP, 06 = SDK/MCP (two learning surfaces) | **05 delivers operator-visible matrix** in golden path + devex index | +| 06 | **Implementation-only** parity proof — same `failure-class.ts`, tests prove rows match | +| New `handshake failures explain` CLI | **Defer** — extend `explainHandshakeError` / `nextHandshakeCommand` to consume `failureClass` first (plan 06) | +| Defer MCP/SDK parity | **Reject** — agent spine + MCP loops need parity in same phase | + +### 5. Wave order / maintainer debt (plans 11 + 12) + +| Current | Change | +|---------|--------| +| Full plan 11 (manifest, sync, conformance, pack slice) before plan 12 E2E | **Minimal 11:** `http-handler-mutation-gating.test.ts` (handler walk) **before** 12; **defer** manifest + registry sync + conformance skeleton to post-operator gate or phase 05 | +| Plan 12 waits for all 11 tasks | **Split contract:** `operator-product-completion` after 01–06 + 03 + 10 matrix; `maintainer-completion` adds 11 full + 12 | + +**Optional:** Social “phase 04 operator shipped” after wave 3–4; maintainer lane completes waves 5–8. + +### 6. Mandatory agent-spine (plan 04) + +| Issue | Fix | +|-------|-----| +| Duplicates P0 commands already in gold-standard devex | Demote to **recommended**; document as “runs doctor → x402 → simulate in order” | +| Service operator sees second required spine | Journey fork makes host branch explicit; service path never mentions agent-spine in first 30 minutes | + +--- + +## First 30 minutes — canonical path (target state) + +```text +README / npm install + → developer-experience-index (Service operator section) + → service-operator golden path (or workflow story + section) + → demo:service-workflow-admission OR handshake service bootstrap + → skim failureClass table (HTTP only) + → (optional) Advanced → integrator-tier-1 appendix +``` + +**Host branch (only if they operate MCP/host):** same index → fork step 3 → `host doctor` → `quickstart x402` → `simulate` (or optional `quickstart agent-spine`). + +--- + +## Plan-by-plan edit checklist + +| Plan | User-facing change | +|------|-------------------| +| **01** | Drop ecosystem/protocol-definition prose expansion; keep arch tests | +| **02** | Add unified journey + step-3 fork; service-first index; failure matrix stub for plan 05; D-09 contrast without new doc sprawl | +| **03** | Unchanged runnable core; link only from golden path | +| **04** | agent-spine **recommended**; anti-theatre tests stay; no second Start Here | +| **05** | Add golden-path failure table deliverable | +| **06** | Label “parity only”; wire repair helpers to `failureClass` | +| **07** | Tier-1 doc = appendix link; tags/tests unchanged | +| **08–09** | Execute code; 09 stubs → prose proof-gap list + tests, no fake quickstart dirs | +| **10** | Matrix + doctor in phase; runbook **files** post-execute | +| **11** | Handler-walk required before 12; manifest/sync optional/deferred | +| **12** | Two-tier gate: operator completion vs full phase completion | + +--- + +## What not to eliminate (user frustration ≠ safety) + +- Dual enforcement tests and claim boundaries (plan 01) +- Runnable service bootstrap + install HTTP tests (plan 03) +- failureClass on HTTP + SDK + MCP (plans 05–06) +- Tier-1 parity tests (plan 07) — integrators need this; operators do not read it day one +- http-profile + auth.md refactor (plan 08) — prevents wrong-family copy-paste +- Handler mutation gating test (plan 11 minimal) +- Honest blocked proof gates (live x402 paid retry, registry, host containment) — **do not** greenwash + +--- + +## Frustration scorecard (before vs after edits) + +| Dimension | Before (12-plan as written) | After recommended edits | +|-----------|----------------------------|-------------------------| +| “Where do I start?” | 2+ equal spines | 1 journey, step-3 fork | +| Docs to open | 8+ internal files | 2 hubs + 1 golden path + appendix | +| Time to first gated route | After wave 7–8 narrative | Waves 1–3 runnable | +| Failure learning | 3 transports implied | 1 table + repair helpers | +| Host operator | Mandatory new sequencer | Same commands, optional bundle | +| Proof-gap stubs | Look like broken quickstarts | Explicit non-runnable list | + +--- + +## Next steps + +1. ~~Patch plans~~ **Done.** +2. Re-run `gsd-plan-checker` on patched plans (D-09 still in plan 02; handler walk satisfies D-24 for operator tier). +3. `/gsd-execute-phase 04-service-agent-gating` — Wave 1: **01 ∥ 02**; optional operator checkpoint after wave 6. + +--- + +## Advisor agent references (internal) + +| Gray area | Agent ID | +|-----------|----------| +| Dual-spine UX | `fed27db6-b35f-4acd-ad0d-96ed1049a49d` | +| Doc sprawl | `d138ec5f-7780-49ed-8949-e21dc2a849e7` | +| Integrator overload | `54e3c8eb-d4b1-4b46-bfcf-c7a1d8a36fbc` | +| Failure fragmentation | `69ede836-fe17-4646-82ab-8f0d08719067` | +| Bypass / waves | `509bccfb-a5a4-4dc3-be1d-9b88593efbf2` | diff --git a/.planning/phases/04-service-agent-gating/04-RECONCILIATION.md b/.planning/phases/04-service-agent-gating/04-RECONCILIATION.md new file mode 100644 index 0000000..c654a97 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-RECONCILIATION.md @@ -0,0 +1,664 @@ +# Phase 04 — Working tree reconciliation + +**Generated:** 2026-05-29 +**Branch:** codex/architectural-north-star-simplification +**Last clean commit:** 1e801b7 +**Working tree entries:** 265 +**Disposition tallies:** +- plan-04-NN-task-M-complete: 0 +- independent-fix: 19 +- out-of-scope-defer: 179 +- phase-05-candidate: 45 +- plan-04-01-task-1-partial: 2 +- plan-04-01-task-2-partial: 2 +- plan-04-01-task-3-partial: 1 +- plan-04-02-task-2-partial: 1 +- plan-04-02-task-3-partial: 1 +- plan-04-03-task-2-partial: 2 +- plan-04-03-task-3-partial: 1 +- plan-04-04-task-1-partial: 1 +- plan-04-04-task-4-partial: 1 +- plan-04-05-task-1-partial: 1 +- plan-04-05-task-2-partial: 2 +- plan-04-06-task-2-partial: 3 +- plan-04-06-task-4-partial: 1 +- plan-04-07-task-1-partial: 1 +- plan-04-10-task-3-partial: 2 +- revert: 0 + +**Drift percentage** (independent-fix + revert + out-of-scope-defer ÷ total): 74.7% + +> Halt condition per plan: drift > 20% halts reconciliation pending user triage. + +**Halt verdict:** HALT — drift 74.7% exceeds 20% threshold. Working tree is predominantly north-star / phase-05 product-coherence drift (179 defer + 45 phase-05 park) against 22 phase-04 partial matches and 0 complete. + +--- + +## Commit landing order (per Step 2 of execution plan) + +### Order 1 — plan task complete commits (per matched plan task) + +_No files classified as plan-task-complete. All phase-04 `files_modified` matches are partial relative to locked acceptance criteria._ + +### Order 2 — plan task partial commits (with gap notes) + +#### `wip(04-01): partial — No shortened agent chain with schema-native non-authority bullets` +Files (2): +- `docs/internal/protocol-layman.md` — evidence: protocol-layman.md; gap: No shortened agent chain with schema-native non-authority bullets per 04-01-T1 +- `docs/internal/service-workflow-story.md` — evidence: service-workflow-story.md:1-150; gap: Passport/admission story present but Agent lane D-05 mapping table absent per 04-01-T1 +**Gap to close in Step 3:** No shortened agent chain with schema-native non-authority bullets per 04-01-T1 + +#### `wip(04-01): partial — Large north-star edits but missing Clerk-for-agents run*Gateway subsection and configuredBy custody matrix` +Files (2): +- `docs/internal/decisions.md` — evidence: decisions.md; gap: Large north-star edits but missing Clerk-for-agents run*Gateway subsection and configuredBy custody matrix per 04-01-T2/04-10-T1 +- `docs/internal/protocol-notes.md` — evidence: protocol-notes.md; gap: Updated notes lack dual-enforcement cross-ref paragraph per 04-01-T2 +**Gap to close in Step 3:** Large north-star edits but missing Clerk-for-agents run*Gateway subsection and configuredBy custody matrix per 04-01-T2/04-10-T1 + +#### `wip(04-01): partial — Modified but dual-enforcement-posture.test.ts still missing` +Files (1): +- `test/architecture/claim-boundary.test.ts` — evidence: claim-boundary.test.ts; gap: Modified but dual-enforcement-posture.test.ts still missing; D-00 claim matrix extensions unverified +**Gap to close in Step 3:** Modified but dual-enforcement-posture.test.ts still missing; D-00 claim matrix extensions unverified + +#### `wip(04-02): partial — Start Here lists host/CLI surfaces not service-operator-golden-path.md single entry` +Files (1): +- `docs/internal/developer-experience-index.md` — evidence: developer-experience-index.md:7-19; gap: Start Here lists host/CLI surfaces not service-operator-golden-path.md single entry per 04-02-T2 +**Gap to close in Step 3:** Start Here lists host/CLI surfaces not service-operator-golden-path.md single entry per 04-02-T2 + +#### `wip(04-02): partial — Scripts expanded for product closeout` +Files (1): +- `package.json` — evidence: package.json; gap: Scripts expanded for product closeout; demo:service-workflow-admission canonization and check-service-agent-gating-phase.mjs absent per 04-02-T3/04-12-T3 +**Gap to close in Step 3:** Scripts expanded for product closeout; demo:service-workflow-admission canonization and check-service-agent-gating-phase.mjs absent per 04-02-T3/04-12-T3 + +#### `wip(04-03): partial — Manifest adds doctor/quality/simulate but not handshake service bootstrap or quickstart agent-spine` +Files (2): +- `src/cli/command-manifest.ts` — evidence: command-manifest.ts; gap: Manifest adds doctor/quality/simulate but not handshake service bootstrap or quickstart agent-spine per 04-03/04-04 +- `src/cli/index.ts` — evidence: cli/index.ts; gap: Router wired for north-star CLI modules; service bootstrap and agent-spine routes missing per 04-03/04-04 +**Gap to close in Step 3:** Manifest adds doctor/quality/simulate but not handshake service bootstrap or quickstart agent-spine per 04-03/04-04 + +#### `wip(04-03): partial — HTTP tests modified` +Files (1): +- `test/http/http.test.ts` — evidence: http.test.ts; gap: HTTP tests modified; InstallProposal orphan-catalog assertions from 04-03-T3 not verified +**Gap to close in Step 3:** HTTP tests modified; InstallProposal orphan-catalog assertions from 04-03-T3 not verified + +#### `wip(04-04): partial — Directory has x402 quickstart only` +Files (1): +- `src/cli/quickstart/` — evidence: src/cli/quickstart/x402.ts; gap: Directory has x402 quickstart only; agent-spine.ts sequencer missing per 04-04-T1 +**Gap to close in Step 3:** Directory has x402 quickstart only; agent-spine.ts sequencer missing per 04-04-T1 + +#### `wip(04-04): partial — New untracked host guidance doc` +Files (1): +- `docs/internal/host-golden-paths-and-trace-guidance.md` — evidence: host-golden-paths-and-trace-guidance.md; gap: New untracked host guidance doc; bilateral setup order and service prerequisite sections incomplete vs 04-04-T4/04-10-T2 +**Gap to close in Step 3:** New untracked host guidance doc; bilateral setup order and service prerequisite sections incomplete vs 04-04-T4/04-10-T2 + +#### `wip(04-05): partial — Schema still lacks failureClass, failurePhase, problemType fields` +Files (1): +- `src/http/errors/transition-error-envelope.ts` — evidence: transition-error-envelope.ts:32-45; gap: Schema still lacks failureClass, failurePhase, problemType fields per 04-05-T1 +**Gap to close in Step 3:** Schema still lacks failureClass, failurePhase, problemType fields per 04-05-T1 + +#### `wip(04-05): partial — Minor edits` +Files (2): +- `src/http/admission/caller-auth.ts` — evidence: caller-auth.ts; gap: Minor edits; admission errors not mapped to failureClass/httpStatus discipline per 04-05-T2 +- `src/protocol/foundation/reason-code-remediation/` — evidence: reason-code-remediation/index.ts; gap: Module exists; failureClass remediation rows for new classes not verified per 04-05-T2 +**Gap to close in Step 3:** Minor edits; admission errors not mapped to failureClass/httpStatus discipline per 04-05-T2 + +#### `wip(04-06): partial — HandshakeClientError lacks failureClass/failurePhase parsing` +Files (3): +- `src/sdk/client.ts` — evidence: sdk/client.ts; gap: HandshakeClientError lacks failureClass/failurePhase parsing per 04-06-T2 +- `src/sdk/surface-clients/transport.ts` — evidence: transport.ts; gap: Transport parses envelope but not failureClass per 04-06-T2 +- `src/sdk/repair.ts` — evidence: sdk/repair.ts; gap: Repair helpers present but not wired to failureClass retry guidance per 04-06-T2 +**Gap to close in Step 3:** HandshakeClientError lacks failureClass/failurePhase parsing per 04-06-T2 + +#### `wip(04-06): partial — Proposal path updated` +Files (1): +- `src/mcp/x402-proposal.ts` — evidence: x402-proposal.ts; gap: Proposal path updated; shared failureClass classifier wiring and parity test absent per 04-06-T4 +**Gap to close in Step 3:** Proposal path updated; shared failureClass classifier wiring and parity test absent per 04-06-T4 + +#### `wip(04-07): partial — integratorTier1 metadata tags and export array not present` +Files (1): +- `src/protocol/navigation/index.ts` — evidence: navigation/index.ts; gap: integratorTier1 metadata tags and export array not present per 04-07-T1 +**Gap to close in Step 3:** integratorTier1 metadata tags and export array not present per 04-07-T1 + +#### `wip(04-10): partial — Contains doctor.ts` +Files (2): +- `src/cli/host/` — evidence: src/cli/host/doctor.ts:23-42; gap: Contains doctor.ts; lacks attestationEvidence/nonClaims attestation framing per 04-10-T3 +- `src/cli/mcp/` — evidence: src/cli/mcp/doctor.ts; gap: Contains MCP doctor; attestation parity vs host doctor not verified per 04-10-T3 +**Gap to close in Step 3:** Contains doctor.ts; lacks attestationEvidence/nonClaims attestation framing per 04-10-T3 + +### Order 3 — independent-fix scrub commits (max 5) + +#### `chore(scrub): CLI and operator surface companions` +Files: +- `examples/service-workflow-admission/README.md` — Admission demo README companion for 04-02 demo canonization +- `examples/service-workflow-admission/run.ts` — Canonical service-workflow-admission demo referenced by 04-02-T3 +- `src/cli/LANE.md` — CLI lane doc for new operator commands in manifest 04-04 +- `src/cli/output.ts` — Shared cliOutput helper for bootstrap/doctor CLI surfaces 04-03/04-10 +- `src/cli/projection-evidence.ts` — Projection evidence helper for SDK repair/readback 04-06 +- `src/cli/support-bundle.ts` — Support bundle CLI uses reason-code remediation metadata 04-05 +- `src/cli/x402/index.ts` — x402 CLI surface for host quickstart path 04-04 +- `src/http/LANE.md` — HTTP lane doc adjacent to transition-error envelope work 04-05 +- `test/architecture/cli-command-posture.test.ts` — CLI manifest posture test companion to command-manifest 04-04-T2 +- `test/cli/cli-evidence.test.ts` — Evidence CLI tests companion to SDK repair 04-06 +- `test/cli/cli-support-bundle.test.ts` — Support bundle CLI test companion 04-05 failure taxonomy surfaces +- `test/cli/cli-x402-install-probes.test.ts` — Host/x402 install probe tests companion to doctor CLI 04-10 +- `test/sdk/role-clients.test.ts` — Role client tests adjacent to failureClass SDK work 04-06 +- `src/cli/demo/` — CLI demo module adjacent to quickstart/host operator path 04-04 +- `src/cli/quality/` — Quality report CLI in devex index 04-04 +- `src/cli/simulate/` — Simulate x402-payment module referenced by agent-spine plan 04-04-T1 +- `src/cli/state/` — State inspect CLI listed in devex index host path 04-04 +- `src/cli/x402/readiness.ts` — x402 readiness helper for host operator commands 04-04 +- `test/cli/cli-mcp-doctor.test.ts` — MCP doctor test companion to 04-10-T3 + +### Order 4 — revert commits + +_None. No working-tree changes contradict locked phase-04 decisions strongly enough to require restore (D-62 concierge lock not evidenced in modified src paths)._ + +### Order 5 — phase-05-candidate (PARK, do not commit on this branch) + +Files to leave uncommitted on `codex/architectural-north-star-simplification` branch: +- `README.md` — matches 05-10-PLAN files_modified +- `src/cli/main.ts` — matches 05-06-PLAN files_modified +- `src/http/admission/hosted-admission-config.ts` — matches 05-09-PLAN files_modified +- `src/http/admission/hosted-caller-identity.ts` — matches 05-09-PLAN files_modified +- `src/http/app.ts` — matches 05-01-PLAN files_modified +- `src/http/routes/evidence-read-route-registry.ts` — matches 05-08-PLAN files_modified +- `src/index.ts` — matches 05-07-PLAN files_modified +- `src/mcp/resources.ts` — matches 05-06-PLAN files_modified +- `src/protocol/evidence-projections/projections.ts` — matches 05-08-PLAN files_modified +- `src/protocol/evidence-projections/schemas.ts` — matches 05-08-PLAN files_modified +- `src/sdk/surface-clients/evidence-client.ts` — matches 05-06-PLAN files_modified +- `src/surfaces/boundary-manifest.ts` — matches 05-09-PLAN files_modified +- `src/surfaces/proof-packets/index.ts` — matches 05-05-PLAN files_modified +- `src/surfaces/proof-packets/live-x402-requirement.ts` — Deleted monolith replaced by live-x402/ directory per product-completion refactor +- `src/surfaces/proof-packets/product-completion.ts` — matches 05-03-PLAN files_modified +- `src/surfaces/service-workflow-admission/index.ts` — matches 05-05-PLAN files_modified +- `src/x402-protected-tool/index.ts` — matches 05-13-PLAN files_modified +- `test/adapters/x402-wallet-gateway.test.ts` — matches 05-13-PLAN files_modified +- `test/architecture/root-exports.test.ts` — matches 05-07-PLAN files_modified +- `scripts/build-product-closeout-bundle.mjs` — Product closeout bundle builder for phase 05 product coherence +- `scripts/build-publish-handoff-packet.mjs` — Publish handoff packet builder for product completion +- `scripts/check-live-x402-paid-retry.mjs` — Product completion proof script cluster +- `scripts/check-product-completion.mjs` — matches 05-03-PLAN files_modified +- `src/cli/evidence/` — Evidence readback CLI for 05-08 +- `src/hosted-admission/` — Hosted admission reexport module for 05-09 +- `src/http/admission/hosted-verifier-adapter.ts` — matches 05-09-PLAN files_modified +- `src/http/handlers/scoped-evidence-record.ts` — matches 05-08-PLAN files_modified +- `src/protocol/evidence-projections/store-reader.ts` — matches 05-08-PLAN files_modified +- `src/protocol/foundation/host-trusted-binding.ts` — matches 05-13-PLAN files_modified +- `src/sdk/transport-url.ts` — SDK transport URL helper for export surface 05-07 +- `src/surfaces/proof-packets/live-x402/` — Live x402 proof packet split aligns with product-completion phase 05-03 +- `src/surfaces/proof-packets/product-completion-contract.ts` — matches 05-03-PLAN files_modified +- `test/adapters/x402-host-trusted-binding.test.ts` — matches 05-13-PLAN files_modified +- `test/adapters/x402-hosted-custody-readiness.test.ts` — Hosted custody readiness adapter test +- `test/architecture/cli-non-authority-copy.test.ts` — matches 05-11-PLAN files_modified +- `test/architecture/host-trusted-binding-parity.test.ts` — Host trusted binding parity for 05-13 +- `test/architecture/hosted-admission-reexport-only.test.ts` — matches 05-09-PLAN files_modified +- `test/architecture/pack-check-expect-status.test.ts` — Pack check posture for product completion +- `test/architecture/planning-scratch-quarantine.test.ts` — matches 05-11-PLAN files_modified +- `test/architecture/product-closeout-bundle.test.ts` — Product closeout architecture test +- `test/architecture/product-completion-parity.test.ts` — matches 05-03-PLAN files_modified +- `test/architecture/proof-script-build-freshness.test.ts` — Proof script freshness gate +- `test/architecture/publish-handoff-packet.test.ts` — Publish handoff architecture test +- `test/http/hosted-identity-evidence.test.ts` — Hosted identity evidence HTTP tests +- `test/protocol/host-trusted-binding.test.ts` — Protocol host-trusted-binding tests + +### Order 6 — out-of-scope-defer (PARK to .planning/inbox/) + +Files to park for later evaluation: +- `.gitignore` — Repo metadata/orientation outside phase-04/05 files_modified +- `.planning/codebase/ARCHITECTURE.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/codebase/CONCERNS.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/codebase/CONVENTIONS.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/codebase/INTEGRATIONS.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/codebase/STACK.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/codebase/STRUCTURE.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/codebase/TESTING.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/AGENT-HANDOFF.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/DECISIONS.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/EVIDENCE-PLAN.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/EXECUTION-SLICES.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/MACRO-PLAN.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/PROTECTED-ACTION-GATES.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/README.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/REVIEW-GATES.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/RISKS.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/RUNTIME-GATES.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/macro-plan/TASKS.jsonl` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `.planning/phases/02-address-concerns/02-PLANS-INDEX.md` — Planning scratch / macro-plan edits; not phase-04 executable deliverable +- `CHANGELOG.md` — Repo metadata/orientation outside phase-04/05 files_modified +- `QUALITY.md` — Repo metadata/orientation outside phase-04/05 files_modified +- `STRUCTURE.md` — Repo metadata/orientation outside phase-04/05 files_modified +- `docs/internal/protocol-definition.md` — Canonical/protocol doc drift from north-star; not in phase-04 files_modified +- `docs/internal/protocol-kernel-architecture.md` — Canonical/protocol doc drift from north-star; not in phase-04 files_modified +- `docs/internal/release-admin-runbook.md` — Canonical/protocol doc drift from north-star; not in phase-04 files_modified +- `examples/a2a-negotiated-x402-room/README.md` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `examples/a2a-negotiated-x402-room/agent-handoff.md` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `examples/a2a-negotiated-x402-room/evaluation.md` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `examples/a2a-negotiated-x402-room/generate.ts` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `examples/a2a-negotiated-x402-room/latest.json` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `examples/a2a-negotiated-x402-room/latest.md` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `examples/a2a-negotiated-x402-room/local-reference-records.ts` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `examples/a2a-negotiated-x402-room/local-reference-room.ts` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `scripts/build-package-bundles.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-clean-installed-activation.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-codex-host-activation.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-distribution-provenance.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-npm-maintainer-posture.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-package-surface.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-published-entrypoints.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-release-proof.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/install-codex-host-activation.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `server.json` — Repo metadata/orientation outside phase-04/05 files_modified +- `src/adapters/downstream-failure-evidence.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/adapters/x402-payment/action-proposal.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/adapters/x402-payment/protected-tool-profile/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/adapters/x402-payment/protected-tool-readiness/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/http/app-options.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/http/errors/codes.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/http/handlers/evidence-read.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/http/handlers/hosted-readiness.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/http/handlers/internal-record-read.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/http/routes/transition-scope-resolvers.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/mcp/catalog.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/mcp/reference-transcript-fixtures.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/mcp/reference-transcript.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/mcp/stdio/process-proof.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/mcp/stdio/server.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/action-attempt-lifecycle/matrix.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/authority-certificate/transitions.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/generated-execution-graph/transitions.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/intent-compilation/transitions.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/negotiation/LANE.md` — Negotiation protocol area edits outside phase-04 kernel-freeze scope +- `src/protocol/areas/negotiation/inputs.ts` — Negotiation protocol area edits outside phase-04 kernel-freeze scope +- `src/protocol/areas/negotiation/policy.ts` — Negotiation protocol area edits outside phase-04 kernel-freeze scope +- `src/protocol/areas/negotiation/schemas.ts` — Negotiation protocol area edits outside phase-04 kernel-freeze scope +- `src/protocol/areas/negotiation/transitions.ts` — Negotiation protocol area edits outside phase-04 kernel-freeze scope +- `src/protocol/areas/object-registry/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/object-registry/schemas.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/operation-lifecycle/inputs.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/operation-lifecycle/schemas.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/operation-lifecycle/transitions.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/policy-greenlight/policy-record/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/policy-greenlight/schemas.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/policy-greenlight/sequence-dependencies.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/areas/policy-greenlight/transitions.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/events/records.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/events/schemas.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/evidence-projections/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/foundation/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/foundation/reason-codes.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/kernel.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/runtime/ingress/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/sdk/surface-clients/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/storage/d1/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/storage/kv/index.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/surfaces/LANE.md` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/surfaces/a2a-negotiation-readback/index.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/index.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/product-launch-gate-resolution.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/surfaces/proof-packets/clean-installed-activation.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/surfaces/proof-packets/codex-host-activation.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/surfaces/proof-packets/distribution-provenance.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/surfaces/proof-packets/shared.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/surfaces/release-proof.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/x402-protected-tool/LANE.md` — Source changes from north-star simplification; not in phase-04 files_modified +- `test/adapters/package-install-gateway.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/adapters/x402-bypass-probes.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/adapters/x402-protected-tool-claude-code-activation.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/adapters/x402-protected-tool-codex-activation.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/adapters/x402-protected-tool-generic-mcp-activation.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/adapters/x402-protected-tool-hermes-activation.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/adapters/x402-protected-tool-openclaw-activation.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/architecture/negotiation-no-authority-surface.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/architecture/npm-maintainer-posture.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/architecture/package-release-proof.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/architecture/package-surface.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/architecture/product-launch-gate-resolution.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/architecture/proof-packets.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/architecture/release-repository-projection.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/architecture/workflow-admission-boundary.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/integration/auth-md-receipt-reconstruction.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/integration/x402-d1-http.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/mcp/mcp-reference-transcript.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/mcp/mcp-resource-redaction.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/mcp/mcp-schema-contract.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/product/a2a-negotiated-x402-room.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/agent-proof-slice.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/product/service-workflow-admission.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/product/x402-protected-spend-demo-report.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/authority-certificate.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/evidence-projections.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/kernel-operation-lifecycle.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/kernel-policy-gateway.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/negotiation-events.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/protocol/negotiation-object-registry.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/protocol/negotiation-policy.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/protocol/negotiation-schemas.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/protocol/negotiation-transitions.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/protocol/object-registry.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/protocol-navigation.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/reason-code-registry.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/transition-matrix.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/runtime/runtime-ingress.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/support/http-protocol-fixtures.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/support/negotiation-fixtures.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/support/x402-negotiation-fixture.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `.github/CODEOWNERS` — Repo metadata/orientation outside phase-04/05 files_modified +- `docs/internal/ecosystem-strategy.md` — 04-PLANS-INDEX eliminated ecosystem-strategy dual-lane expansion; park until strategy scope re-opened +- `docs/internal/gold-standard-devex-build-order.md` — Working-tree drift not mapped to phase-04/05 plan files_modified +- `examples/a2a-negotiated-x402-room/mcp-readback.json` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `examples/a2a-negotiated-x402-room/mcp-readback.md` — A2A negotiated room example; negotiation surface work outside phase-04 scope +- `scripts/build-host-generated-code-containment-transcript.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/capture-host-generated-code-containment.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-auth-md-x402-admission-packet.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `scripts/check-host-generated-code-containment.mjs` — Release/proof script maintenance from north-star; not phase-04 files_modified +- `src/http/handlers/hosted-record-scope.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/http/handlers/raw-read-audit.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/protocol/foundation/telemetry-context/` — Source changes from north-star simplification; not in phase-04 files_modified +- `src/surfaces/a2a-negotiation-support/adapter-apply.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/adapter-contract.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/adapter-transcript/` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/agreement-linker/` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/external-protocol-evidence.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/ingress-admission.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/ingress-normalizer.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/ingress-pressure.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/move-compiler.ts` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/a2a-negotiation-support/obligation-binder/` — A2A negotiation support surface; not phase-04 service-agent-gating deliverable +- `src/surfaces/proof-packets/host-generated-code-containment.ts` — Source changes from north-star simplification; not in phase-04 files_modified +- `test/cli/cli-quality-report.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/cli/cli-simulate.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/cli/cli-state-inspect.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/mcp/mcp-stdio-binding-integration.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/product/a2a-adapter-move-contract.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/a2a-adapter-transcript.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/a2a-agreement-linker.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/a2a-external-protocol-evidence.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/a2a-ingress-admission.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/a2a-ingress-normalizer.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/a2a-ingress-pressure.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/a2a-move-compiler.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/a2a-obligation-binder.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/product/hosted-package-consumer.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/a2a-ingress-checkpoint.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/protocol/evidence-audit-read-projections.test.ts` — Test updates from north-star/product-coherence; not phase-04 files_modified +- `test/protocol/negotiation-game-state.test.ts` — A2A/negotiation test cluster outside phase-04 plans +- `test/storage/` — Test updates from north-star/product-coherence; not phase-04 files_modified + +--- + +## Full per-file disposition table + +| # | path | status | disposition | plan/task | evidence | one-line note | +|---|------|--------|-------------|-----------|----------|---------------| +| 1 | `.gitignore` | M | out-of-scope-defer | - | .gitignore | Repo metadata/orientation outside phase-04/05 files_modified | +| 2 | `.planning/codebase/ARCHITECTURE.md` | M | out-of-scope-defer | - | .planning/codebase/ARCHITECTURE.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 3 | `.planning/codebase/CONCERNS.md` | M | out-of-scope-defer | - | .planning/codebase/CONCERNS.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 4 | `.planning/codebase/CONVENTIONS.md` | M | out-of-scope-defer | - | .planning/codebase/CONVENTIONS.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 5 | `.planning/codebase/INTEGRATIONS.md` | M | out-of-scope-defer | - | .planning/codebase/INTEGRATIONS.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 6 | `.planning/codebase/STACK.md` | M | out-of-scope-defer | - | .planning/codebase/STACK.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 7 | `.planning/codebase/STRUCTURE.md` | M | out-of-scope-defer | - | .planning/codebase/STRUCTURE.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 8 | `.planning/codebase/TESTING.md` | M | out-of-scope-defer | - | .planning/codebase/TESTING.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 9 | `.planning/macro-plan/AGENT-HANDOFF.md` | M | out-of-scope-defer | - | .planning/macro-plan/AGENT-HANDOFF.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 10 | `.planning/macro-plan/DECISIONS.md` | M | out-of-scope-defer | - | .planning/macro-plan/DECISIONS.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 11 | `.planning/macro-plan/EVIDENCE-PLAN.md` | M | out-of-scope-defer | - | .planning/macro-plan/EVIDENCE-PLAN.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 12 | `.planning/macro-plan/EXECUTION-SLICES.md` | M | out-of-scope-defer | - | .planning/macro-plan/EXECUTION-SLICES.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 13 | `.planning/macro-plan/MACRO-PLAN.md` | M | out-of-scope-defer | - | .planning/macro-plan/MACRO-PLAN.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 14 | `.planning/macro-plan/PROTECTED-ACTION-GATES.md` | M | out-of-scope-defer | - | .planning/macro-plan/PROTECTED-ACTION-GATES.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 15 | `.planning/macro-plan/README.md` | M | out-of-scope-defer | - | .planning/macro-plan/README.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 16 | `.planning/macro-plan/REVIEW-GATES.md` | M | out-of-scope-defer | - | .planning/macro-plan/REVIEW-GATES.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 17 | `.planning/macro-plan/RISKS.md` | M | out-of-scope-defer | - | .planning/macro-plan/RISKS.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 18 | `.planning/macro-plan/RUNTIME-GATES.md` | M | out-of-scope-defer | - | .planning/macro-plan/RUNTIME-GATES.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 19 | `.planning/macro-plan/TASKS.jsonl` | M | out-of-scope-defer | - | .planning/macro-plan/TASKS.jsonl | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 20 | `.planning/phases/02-address-concerns/02-PLANS-INDEX.md` | M | out-of-scope-defer | - | .planning/phases/02-address-concerns/02-PLANS-INDEX.md | Planning scratch / macro-plan edits; not phase-04 executable deliverable | +| 21 | `CHANGELOG.md` | M | out-of-scope-defer | - | CHANGELOG.md | Repo metadata/orientation outside phase-04/05 files_modified | +| 22 | `QUALITY.md` | M | out-of-scope-defer | - | QUALITY.md | Repo metadata/orientation outside phase-04/05 files_modified | +| 23 | `README.md` | M | phase-05-candidate | 05-10-PLAN | README.md | matches 05-10-PLAN files_modified | +| 24 | `STRUCTURE.md` | M | out-of-scope-defer | - | STRUCTURE.md | Repo metadata/orientation outside phase-04/05 files_modified | +| 25 | `docs/internal/decisions.md` | M | plan-04-01-task-2-partial | 04-01/T2 | decisions.md | Large north-star edits but missing Clerk-for-agents run*Gateway subsection and configuredBy custody matrix per 04-01-T2/04-10-T1 | +| 26 | `docs/internal/protocol-definition.md` | M | out-of-scope-defer | - | docs/internal/protocol-definition.md | Canonical/protocol doc drift from north-star; not in phase-04 files_modified | +| 27 | `docs/internal/protocol-kernel-architecture.md` | M | out-of-scope-defer | - | docs/internal/protocol-kernel-architecture.md | Canonical/protocol doc drift from north-star; not in phase-04 files_modified | +| 28 | `docs/internal/protocol-layman.md` | M | plan-04-01-task-1-partial | 04-01/T1 | protocol-layman.md | No shortened agent chain with schema-native non-authority bullets per 04-01-T1 | +| 29 | `docs/internal/protocol-notes.md` | M | plan-04-01-task-2-partial | 04-01/T2 | protocol-notes.md | Updated notes lack dual-enforcement cross-ref paragraph per 04-01-T2 | +| 30 | `docs/internal/release-admin-runbook.md` | M | out-of-scope-defer | - | docs/internal/release-admin-runbook.md | Canonical/protocol doc drift from north-star; not in phase-04 files_modified | +| 31 | `docs/internal/service-workflow-story.md` | M | plan-04-01-task-1-partial | 04-01/T1 | service-workflow-story.md:1-150 | Passport/admission story present but Agent lane D-05 mapping table absent per 04-01-T1 | +| 32 | `examples/a2a-negotiated-x402-room/README.md` | M | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/README.md | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 33 | `examples/a2a-negotiated-x402-room/agent-handoff.md` | M | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/agent-handoff.md | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 34 | `examples/a2a-negotiated-x402-room/evaluation.md` | M | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/evaluation.md | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 35 | `examples/a2a-negotiated-x402-room/generate.ts` | M | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/generate.ts | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 36 | `examples/a2a-negotiated-x402-room/latest.json` | M | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/latest.json | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 37 | `examples/a2a-negotiated-x402-room/latest.md` | M | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/latest.md | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 38 | `examples/a2a-negotiated-x402-room/local-reference-records.ts` | M | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/local-reference-records.ts | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 39 | `examples/a2a-negotiated-x402-room/local-reference-room.ts` | M | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/local-reference-room.ts | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 40 | `examples/service-workflow-admission/README.md` | M | independent-fix | 04-02/T3 | examples/service-workflow-admission/README.md | Admission demo README companion for 04-02 demo canonization | +| 41 | `examples/service-workflow-admission/run.ts` | M | independent-fix | 04-02/T3 | examples/service-workflow-admission/run.ts | Canonical service-workflow-admission demo referenced by 04-02-T3 | +| 42 | `package.json` | M | plan-04-02-task-3-partial | 04-02/T3 | package.json | Scripts expanded for product closeout; demo:service-workflow-admission canonization and check-service-agent-gating-phase.mjs absent per 04-02-T3/04-12-T3 | +| 43 | `scripts/build-package-bundles.mjs` | M | out-of-scope-defer | - | scripts/build-package-bundles.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 44 | `scripts/check-clean-installed-activation.mjs` | M | out-of-scope-defer | - | scripts/check-clean-installed-activation.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 45 | `scripts/check-codex-host-activation.mjs` | M | out-of-scope-defer | - | scripts/check-codex-host-activation.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 46 | `scripts/check-distribution-provenance.mjs` | M | out-of-scope-defer | - | scripts/check-distribution-provenance.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 47 | `scripts/check-npm-maintainer-posture.mjs` | M | out-of-scope-defer | - | scripts/check-npm-maintainer-posture.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 48 | `scripts/check-package-surface.mjs` | M | out-of-scope-defer | - | scripts/check-package-surface.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 49 | `scripts/check-published-entrypoints.mjs` | M | out-of-scope-defer | - | scripts/check-published-entrypoints.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 50 | `scripts/check-release-proof.mjs` | M | out-of-scope-defer | - | scripts/check-release-proof.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 51 | `scripts/install-codex-host-activation.mjs` | M | out-of-scope-defer | - | scripts/install-codex-host-activation.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 52 | `server.json` | M | out-of-scope-defer | - | server.json | Repo metadata/orientation outside phase-04/05 files_modified | +| 53 | `src/adapters/downstream-failure-evidence.ts` | M | out-of-scope-defer | - | src/adapters/downstream-failure-evidence.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 54 | `src/adapters/x402-payment/action-proposal.ts` | M | out-of-scope-defer | - | src/adapters/x402-payment/action-proposal.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 55 | `src/adapters/x402-payment/protected-tool-profile/index.ts` | M | out-of-scope-defer | - | src/adapters/x402-payment/protected-tool-profile/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 56 | `src/adapters/x402-payment/protected-tool-readiness/index.ts` | M | out-of-scope-defer | - | src/adapters/x402-payment/protected-tool-readiness/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 57 | `src/cli/LANE.md` | M | independent-fix | 04-04/T2 | src/cli/LANE.md | CLI lane doc for new operator commands in manifest 04-04 | +| 58 | `src/cli/command-manifest.ts` | M | plan-04-03-task-2-partial | 04-03/T2 | command-manifest.ts | Manifest adds doctor/quality/simulate but not handshake service bootstrap or quickstart agent-spine per 04-03/04-04 | +| 59 | `src/cli/index.ts` | M | plan-04-03-task-2-partial | 04-03/T2 | cli/index.ts | Router wired for north-star CLI modules; service bootstrap and agent-spine routes missing per 04-03/04-04 | +| 60 | `src/cli/main.ts` | M | phase-05-candidate | 05-06-PLAN | src/cli/main.ts | matches 05-06-PLAN files_modified | +| 61 | `src/cli/output.ts` | M | independent-fix | 04-03/T2 | src/cli/output.ts | Shared cliOutput helper for bootstrap/doctor CLI surfaces 04-03/04-10 | +| 62 | `src/cli/projection-evidence.ts` | M | independent-fix | 04-06/T2 | src/cli/projection-evidence.ts | Projection evidence helper for SDK repair/readback 04-06 | +| 63 | `src/cli/support-bundle.ts` | M | independent-fix | 04-05/T5 | src/cli/support-bundle.ts | Support bundle CLI uses reason-code remediation metadata 04-05 | +| 64 | `src/cli/x402/index.ts` | M | independent-fix | 04-04/T2 | src/cli/x402/index.ts | x402 CLI surface for host quickstart path 04-04 | +| 65 | `src/http/LANE.md` | M | independent-fix | 04-05/T1 | src/http/LANE.md | HTTP lane doc adjacent to transition-error envelope work 04-05 | +| 66 | `src/http/admission/caller-auth.ts` | M | plan-04-05-task-2-partial | 04-05/T2 | caller-auth.ts | Minor edits; admission errors not mapped to failureClass/httpStatus discipline per 04-05-T2 | +| 67 | `src/http/admission/hosted-admission-config.ts` | M | phase-05-candidate | 05-09-PLAN | src/http/admission/hosted-admission-config.ts | matches 05-09-PLAN files_modified | +| 68 | `src/http/admission/hosted-caller-identity.ts` | M | phase-05-candidate | 05-09-PLAN | src/http/admission/hosted-caller-identity.ts | matches 05-09-PLAN files_modified | +| 69 | `src/http/app-options.ts` | M | out-of-scope-defer | - | src/http/app-options.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 70 | `src/http/app.ts` | M | phase-05-candidate | 05-01-PLAN | src/http/app.ts | matches 05-01-PLAN files_modified | +| 71 | `src/http/errors/codes.ts` | M | out-of-scope-defer | - | src/http/errors/codes.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 72 | `src/http/errors/transition-error-envelope.ts` | M | plan-04-05-task-1-partial | 04-05/T1 | transition-error-envelope.ts:32-45 | Schema still lacks failureClass, failurePhase, problemType fields per 04-05-T1 | +| 73 | `src/http/handlers/evidence-read.ts` | M | out-of-scope-defer | - | src/http/handlers/evidence-read.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 74 | `src/http/handlers/hosted-readiness.ts` | M | out-of-scope-defer | - | src/http/handlers/hosted-readiness.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 75 | `src/http/handlers/internal-record-read.ts` | M | out-of-scope-defer | - | src/http/handlers/internal-record-read.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 76 | `src/http/routes/evidence-read-route-registry.ts` | M | phase-05-candidate | 05-08-PLAN | src/http/routes/evidence-read-route-registry.ts | matches 05-08-PLAN files_modified | +| 77 | `src/http/routes/transition-scope-resolvers.ts` | M | out-of-scope-defer | - | src/http/routes/transition-scope-resolvers.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 78 | `src/index.ts` | M | phase-05-candidate | 05-07-PLAN | src/index.ts | matches 05-07-PLAN files_modified | +| 79 | `src/mcp/catalog.ts` | M | out-of-scope-defer | - | src/mcp/catalog.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 80 | `src/mcp/reference-transcript-fixtures.ts` | M | out-of-scope-defer | - | src/mcp/reference-transcript-fixtures.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 81 | `src/mcp/reference-transcript.ts` | M | out-of-scope-defer | - | src/mcp/reference-transcript.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 82 | `src/mcp/resources.ts` | M | phase-05-candidate | 05-06-PLAN | src/mcp/resources.ts | matches 05-06-PLAN files_modified | +| 83 | `src/mcp/stdio/process-proof.ts` | M | out-of-scope-defer | - | src/mcp/stdio/process-proof.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 84 | `src/mcp/stdio/server.ts` | M | out-of-scope-defer | - | src/mcp/stdio/server.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 85 | `src/mcp/x402-proposal.ts` | M | plan-04-06-task-4-partial | 04-06/T4 | x402-proposal.ts | Proposal path updated; shared failureClass classifier wiring and parity test absent per 04-06-T4 | +| 86 | `src/protocol/areas/action-attempt-lifecycle/matrix.ts` | M | out-of-scope-defer | - | src/protocol/areas/action-attempt-lifecycle/matrix.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 87 | `src/protocol/areas/authority-certificate/transitions.ts` | M | out-of-scope-defer | - | src/protocol/areas/authority-certificate/transitions.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 88 | `src/protocol/areas/generated-execution-graph/transitions.ts` | M | out-of-scope-defer | - | src/protocol/areas/generated-execution-graph/transitions.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 89 | `src/protocol/areas/intent-compilation/transitions.ts` | M | out-of-scope-defer | - | src/protocol/areas/intent-compilation/transitions.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 90 | `src/protocol/areas/negotiation/LANE.md` | M | out-of-scope-defer | - | src/protocol/areas/negotiation/LANE.md | Negotiation protocol area edits outside phase-04 kernel-freeze scope | +| 91 | `src/protocol/areas/negotiation/inputs.ts` | M | out-of-scope-defer | - | src/protocol/areas/negotiation/inputs.ts | Negotiation protocol area edits outside phase-04 kernel-freeze scope | +| 92 | `src/protocol/areas/negotiation/policy.ts` | M | out-of-scope-defer | - | src/protocol/areas/negotiation/policy.ts | Negotiation protocol area edits outside phase-04 kernel-freeze scope | +| 93 | `src/protocol/areas/negotiation/schemas.ts` | M | out-of-scope-defer | - | src/protocol/areas/negotiation/schemas.ts | Negotiation protocol area edits outside phase-04 kernel-freeze scope | +| 94 | `src/protocol/areas/negotiation/transitions.ts` | M | out-of-scope-defer | - | src/protocol/areas/negotiation/transitions.ts | Negotiation protocol area edits outside phase-04 kernel-freeze scope | +| 95 | `src/protocol/areas/object-registry/index.ts` | M | out-of-scope-defer | - | src/protocol/areas/object-registry/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 96 | `src/protocol/areas/object-registry/schemas.ts` | M | out-of-scope-defer | - | src/protocol/areas/object-registry/schemas.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 97 | `src/protocol/areas/operation-lifecycle/inputs.ts` | M | out-of-scope-defer | - | src/protocol/areas/operation-lifecycle/inputs.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 98 | `src/protocol/areas/operation-lifecycle/schemas.ts` | M | out-of-scope-defer | - | src/protocol/areas/operation-lifecycle/schemas.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 99 | `src/protocol/areas/operation-lifecycle/transitions.ts` | M | out-of-scope-defer | - | src/protocol/areas/operation-lifecycle/transitions.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 100 | `src/protocol/areas/policy-greenlight/policy-record/index.ts` | M | out-of-scope-defer | - | src/protocol/areas/policy-greenlight/policy-record/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 101 | `src/protocol/areas/policy-greenlight/schemas.ts` | M | out-of-scope-defer | - | src/protocol/areas/policy-greenlight/schemas.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 102 | `src/protocol/areas/policy-greenlight/sequence-dependencies.ts` | M | out-of-scope-defer | - | src/protocol/areas/policy-greenlight/sequence-dependencies.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 103 | `src/protocol/areas/policy-greenlight/transitions.ts` | M | out-of-scope-defer | - | src/protocol/areas/policy-greenlight/transitions.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 104 | `src/protocol/events/records.ts` | M | out-of-scope-defer | - | src/protocol/events/records.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 105 | `src/protocol/events/schemas.ts` | M | out-of-scope-defer | - | src/protocol/events/schemas.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 106 | `src/protocol/evidence-projections/index.ts` | M | out-of-scope-defer | - | src/protocol/evidence-projections/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 107 | `src/protocol/evidence-projections/projections.ts` | M | phase-05-candidate | 05-08-PLAN | src/protocol/evidence-projections/projections.ts | matches 05-08-PLAN files_modified | +| 108 | `src/protocol/evidence-projections/schemas.ts` | M | phase-05-candidate | 05-08-PLAN | src/protocol/evidence-projections/schemas.ts | matches 05-08-PLAN files_modified | +| 109 | `src/protocol/foundation/index.ts` | M | out-of-scope-defer | - | src/protocol/foundation/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 110 | `src/protocol/foundation/reason-codes.ts` | M | out-of-scope-defer | - | src/protocol/foundation/reason-codes.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 111 | `src/protocol/kernel.ts` | M | out-of-scope-defer | - | src/protocol/kernel.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 112 | `src/protocol/navigation/index.ts` | M | plan-04-07-task-1-partial | 04-07/T1 | navigation/index.ts | integratorTier1 metadata tags and export array not present per 04-07-T1 | +| 113 | `src/runtime/ingress/index.ts` | M | out-of-scope-defer | - | src/runtime/ingress/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 114 | `src/sdk/client.ts` | M | plan-04-06-task-2-partial | 04-06/T2 | sdk/client.ts | HandshakeClientError lacks failureClass/failurePhase parsing per 04-06-T2 | +| 115 | `src/sdk/surface-clients/evidence-client.ts` | M | phase-05-candidate | 05-06-PLAN | src/sdk/surface-clients/evidence-client.ts | matches 05-06-PLAN files_modified | +| 116 | `src/sdk/surface-clients/index.ts` | M | out-of-scope-defer | - | src/sdk/surface-clients/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 117 | `src/sdk/surface-clients/transport.ts` | M | plan-04-06-task-2-partial | 04-06/T2 | transport.ts | Transport parses envelope but not failureClass per 04-06-T2 | +| 118 | `src/storage/d1/index.ts` | M | out-of-scope-defer | - | src/storage/d1/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 119 | `src/storage/kv/index.ts` | M | out-of-scope-defer | - | src/storage/kv/index.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 120 | `src/surfaces/LANE.md` | M | out-of-scope-defer | - | src/surfaces/LANE.md | Source changes from north-star simplification; not in phase-04 files_modified | +| 121 | `src/surfaces/a2a-negotiation-readback/index.ts` | M | out-of-scope-defer | - | src/surfaces/a2a-negotiation-readback/index.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 122 | `src/surfaces/a2a-negotiation-support/index.ts` | M | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/index.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 123 | `src/surfaces/boundary-manifest.ts` | M | phase-05-candidate | 05-09-PLAN | src/surfaces/boundary-manifest.ts | matches 05-09-PLAN files_modified | +| 124 | `src/surfaces/product-launch-gate-resolution.ts` | M | out-of-scope-defer | - | src/surfaces/product-launch-gate-resolution.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 125 | `src/surfaces/proof-packets/clean-installed-activation.ts` | M | out-of-scope-defer | - | src/surfaces/proof-packets/clean-installed-activation.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 126 | `src/surfaces/proof-packets/codex-host-activation.ts` | M | out-of-scope-defer | - | src/surfaces/proof-packets/codex-host-activation.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 127 | `src/surfaces/proof-packets/distribution-provenance.ts` | M | out-of-scope-defer | - | src/surfaces/proof-packets/distribution-provenance.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 128 | `src/surfaces/proof-packets/index.ts` | M | phase-05-candidate | 05-05-PLAN | src/surfaces/proof-packets/index.ts | matches 05-05-PLAN files_modified | +| 129 | `src/surfaces/proof-packets/live-x402-requirement.ts` | D | phase-05-candidate | 05-03 | deleted→live-x402/ | Deleted monolith replaced by live-x402/ directory per product-completion refactor | +| 130 | `src/surfaces/proof-packets/product-completion.ts` | M | phase-05-candidate | 05-03-PLAN | src/surfaces/proof-packets/product-completion.ts | matches 05-03-PLAN files_modified | +| 131 | `src/surfaces/proof-packets/shared.ts` | M | out-of-scope-defer | - | src/surfaces/proof-packets/shared.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 132 | `src/surfaces/release-proof.ts` | M | out-of-scope-defer | - | src/surfaces/release-proof.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 133 | `src/surfaces/service-workflow-admission/index.ts` | M | phase-05-candidate | 05-05-PLAN | src/surfaces/service-workflow-admission/index.ts | matches 05-05-PLAN files_modified | +| 134 | `src/x402-protected-tool/LANE.md` | M | out-of-scope-defer | - | src/x402-protected-tool/LANE.md | Source changes from north-star simplification; not in phase-04 files_modified | +| 135 | `src/x402-protected-tool/index.ts` | M | phase-05-candidate | 05-13-PLAN | src/x402-protected-tool/index.ts | matches 05-13-PLAN files_modified | +| 136 | `test/adapters/package-install-gateway.test.ts` | M | out-of-scope-defer | - | test/adapters/package-install-gateway.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 137 | `test/adapters/x402-bypass-probes.test.ts` | M | out-of-scope-defer | - | test/adapters/x402-bypass-probes.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 138 | `test/adapters/x402-protected-tool-claude-code-activation.test.ts` | M | out-of-scope-defer | - | test/adapters/x402-protected-tool-claude-code-activation.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 139 | `test/adapters/x402-protected-tool-codex-activation.test.ts` | M | out-of-scope-defer | - | test/adapters/x402-protected-tool-codex-activation.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 140 | `test/adapters/x402-protected-tool-generic-mcp-activation.test.ts` | M | out-of-scope-defer | - | test/adapters/x402-protected-tool-generic-mcp-activation.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 141 | `test/adapters/x402-protected-tool-hermes-activation.test.ts` | M | out-of-scope-defer | - | test/adapters/x402-protected-tool-hermes-activation.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 142 | `test/adapters/x402-protected-tool-openclaw-activation.test.ts` | M | out-of-scope-defer | - | test/adapters/x402-protected-tool-openclaw-activation.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 143 | `test/adapters/x402-wallet-gateway.test.ts` | M | phase-05-candidate | 05-13-PLAN | test/adapters/x402-wallet-gateway.test.ts | matches 05-13-PLAN files_modified | +| 144 | `test/architecture/claim-boundary.test.ts` | M | plan-04-01-task-3-partial | 04-01/T3 | claim-boundary.test.ts | Modified but dual-enforcement-posture.test.ts still missing; D-00 claim matrix extensions unverified | +| 145 | `test/architecture/cli-command-posture.test.ts` | M | independent-fix | 04-04/T2 | test/architecture/cli-command-posture.test.ts | CLI manifest posture test companion to command-manifest 04-04-T2 | +| 146 | `test/architecture/negotiation-no-authority-surface.test.ts` | M | out-of-scope-defer | - | test/architecture/negotiation-no-authority-surface.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 147 | `test/architecture/npm-maintainer-posture.test.ts` | M | out-of-scope-defer | - | test/architecture/npm-maintainer-posture.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 148 | `test/architecture/package-release-proof.test.ts` | M | out-of-scope-defer | - | test/architecture/package-release-proof.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 149 | `test/architecture/package-surface.test.ts` | M | out-of-scope-defer | - | test/architecture/package-surface.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 150 | `test/architecture/product-launch-gate-resolution.test.ts` | M | out-of-scope-defer | - | test/architecture/product-launch-gate-resolution.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 151 | `test/architecture/proof-packets.test.ts` | M | out-of-scope-defer | - | test/architecture/proof-packets.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 152 | `test/architecture/release-repository-projection.test.ts` | M | out-of-scope-defer | - | test/architecture/release-repository-projection.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 153 | `test/architecture/root-exports.test.ts` | M | phase-05-candidate | 05-07-PLAN | test/architecture/root-exports.test.ts | matches 05-07-PLAN files_modified | +| 154 | `test/architecture/workflow-admission-boundary.test.ts` | M | out-of-scope-defer | - | test/architecture/workflow-admission-boundary.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 155 | `test/cli/cli-evidence.test.ts` | M | independent-fix | 04-06/T2 | test/cli/cli-evidence.test.ts | Evidence CLI tests companion to SDK repair 04-06 | +| 156 | `test/cli/cli-support-bundle.test.ts` | M | independent-fix | 04-05/T5 | test/cli/cli-support-bundle.test.ts | Support bundle CLI test companion 04-05 failure taxonomy surfaces | +| 157 | `test/cli/cli-x402-install-probes.test.ts` | M | independent-fix | 04-10/T3 | test/cli/cli-x402-install-probes.test.ts | Host/x402 install probe tests companion to doctor CLI 04-10 | +| 158 | `test/http/http.test.ts` | M | plan-04-03-task-3-partial | 04-03/T3 | http.test.ts | HTTP tests modified; InstallProposal orphan-catalog assertions from 04-03-T3 not verified | +| 159 | `test/integration/auth-md-receipt-reconstruction.test.ts` | M | out-of-scope-defer | - | test/integration/auth-md-receipt-reconstruction.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 160 | `test/integration/x402-d1-http.test.ts` | M | out-of-scope-defer | - | test/integration/x402-d1-http.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 161 | `test/mcp/mcp-reference-transcript.test.ts` | M | out-of-scope-defer | - | test/mcp/mcp-reference-transcript.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 162 | `test/mcp/mcp-resource-redaction.test.ts` | M | out-of-scope-defer | - | test/mcp/mcp-resource-redaction.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 163 | `test/mcp/mcp-schema-contract.test.ts` | M | out-of-scope-defer | - | test/mcp/mcp-schema-contract.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 164 | `test/product/a2a-negotiated-x402-room.test.ts` | M | out-of-scope-defer | - | test/product/a2a-negotiated-x402-room.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 165 | `test/product/agent-proof-slice.test.ts` | M | out-of-scope-defer | - | test/product/agent-proof-slice.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 166 | `test/product/service-workflow-admission.test.ts` | M | out-of-scope-defer | - | test/product/service-workflow-admission.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 167 | `test/product/x402-protected-spend-demo-report.test.ts` | M | out-of-scope-defer | - | test/product/x402-protected-spend-demo-report.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 168 | `test/protocol/authority-certificate.test.ts` | M | out-of-scope-defer | - | test/protocol/authority-certificate.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 169 | `test/protocol/evidence-projections.test.ts` | M | out-of-scope-defer | - | test/protocol/evidence-projections.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 170 | `test/protocol/kernel-operation-lifecycle.test.ts` | M | out-of-scope-defer | - | test/protocol/kernel-operation-lifecycle.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 171 | `test/protocol/kernel-policy-gateway.test.ts` | M | out-of-scope-defer | - | test/protocol/kernel-policy-gateway.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 172 | `test/protocol/negotiation-events.test.ts` | M | out-of-scope-defer | - | test/protocol/negotiation-events.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 173 | `test/protocol/negotiation-object-registry.test.ts` | M | out-of-scope-defer | - | test/protocol/negotiation-object-registry.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 174 | `test/protocol/negotiation-policy.test.ts` | M | out-of-scope-defer | - | test/protocol/negotiation-policy.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 175 | `test/protocol/negotiation-schemas.test.ts` | M | out-of-scope-defer | - | test/protocol/negotiation-schemas.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 176 | `test/protocol/negotiation-transitions.test.ts` | M | out-of-scope-defer | - | test/protocol/negotiation-transitions.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 177 | `test/protocol/object-registry.test.ts` | M | out-of-scope-defer | - | test/protocol/object-registry.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 178 | `test/protocol/protocol-navigation.test.ts` | M | out-of-scope-defer | - | test/protocol/protocol-navigation.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 179 | `test/protocol/reason-code-registry.test.ts` | M | out-of-scope-defer | - | test/protocol/reason-code-registry.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 180 | `test/protocol/transition-matrix.test.ts` | M | out-of-scope-defer | - | test/protocol/transition-matrix.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 181 | `test/runtime/runtime-ingress.test.ts` | M | out-of-scope-defer | - | test/runtime/runtime-ingress.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 182 | `test/sdk/role-clients.test.ts` | M | independent-fix | 04-06/T2 | test/sdk/role-clients.test.ts | Role client tests adjacent to failureClass SDK work 04-06 | +| 183 | `test/support/http-protocol-fixtures.ts` | M | out-of-scope-defer | - | test/support/http-protocol-fixtures.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 184 | `test/support/negotiation-fixtures.ts` | M | out-of-scope-defer | - | test/support/negotiation-fixtures.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 185 | `test/support/x402-negotiation-fixture.ts` | M | out-of-scope-defer | - | test/support/x402-negotiation-fixture.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 186 | `.github/CODEOWNERS` | ?? | out-of-scope-defer | - | .github/CODEOWNERS | Repo metadata/orientation outside phase-04/05 files_modified | +| 187 | `docs/internal/developer-experience-index.md` | ?? | plan-04-02-task-2-partial | 04-02/T2 | developer-experience-index.md:7-19 | Start Here lists host/CLI surfaces not service-operator-golden-path.md single entry per 04-02-T2 | +| 188 | `docs/internal/ecosystem-strategy.md` | ?? | out-of-scope-defer | - | docs/internal/ecosystem-strategy.md | 04-PLANS-INDEX eliminated ecosystem-strategy dual-lane expansion; park until strategy scope re-opened | +| 189 | `docs/internal/gold-standard-devex-build-order.md` | ?? | out-of-scope-defer | - | docs/internal/gold-standard-devex-build-order.md | Working-tree drift not mapped to phase-04/05 plan files_modified | +| 190 | `docs/internal/host-golden-paths-and-trace-guidance.md` | ?? | plan-04-04-task-4-partial | 04-04/T4 | host-golden-paths-and-trace-guidance.md | New untracked host guidance doc; bilateral setup order and service prerequisite sections incomplete vs 04-04-T4/04-10-T2 | +| 191 | `examples/a2a-negotiated-x402-room/mcp-readback.json` | ?? | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/mcp-readback.json | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 192 | `examples/a2a-negotiated-x402-room/mcp-readback.md` | ?? | out-of-scope-defer | - | examples/a2a-negotiated-x402-room/mcp-readback.md | A2A negotiated room example; negotiation surface work outside phase-04 scope | +| 193 | `scripts/build-host-generated-code-containment-transcript.mjs` | ?? | out-of-scope-defer | - | scripts/build-host-generated-code-containment-transcript.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 194 | `scripts/build-product-closeout-bundle.mjs` | ?? | phase-05-candidate | 05-03 | scripts/build-product-closeout-bundle.mjs | Product closeout bundle builder for phase 05 product coherence | +| 195 | `scripts/build-publish-handoff-packet.mjs` | ?? | phase-05-candidate | 05-03 | scripts/build-publish-handoff-packet.mjs | Publish handoff packet builder for product completion | +| 196 | `scripts/capture-host-generated-code-containment.mjs` | ?? | out-of-scope-defer | - | scripts/capture-host-generated-code-containment.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 197 | `scripts/check-auth-md-x402-admission-packet.mjs` | ?? | out-of-scope-defer | - | scripts/check-auth-md-x402-admission-packet.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 198 | `scripts/check-host-generated-code-containment.mjs` | ?? | out-of-scope-defer | - | scripts/check-host-generated-code-containment.mjs | Release/proof script maintenance from north-star; not phase-04 files_modified | +| 199 | `scripts/check-live-x402-paid-retry.mjs` | ?? | phase-05-candidate | 05-03 | scripts/check-live-x402-paid-retry.mjs | Product completion proof script cluster | +| 200 | `scripts/check-product-completion.mjs` | ?? | phase-05-candidate | 05-03-PLAN | scripts/check-product-completion.mjs | matches 05-03-PLAN files_modified | +| 201 | `src/cli/demo/` | ?? | independent-fix | 04-04/T2 | src/cli/demo/ | CLI demo module adjacent to quickstart/host operator path 04-04 | +| 202 | `src/cli/evidence/` | ?? | phase-05-candidate | 05-08 | src/cli/evidence/operation-readback-view.ts | Evidence readback CLI for 05-08 | +| 203 | `src/cli/host/` | ?? | plan-04-10-task-3-partial | 04-10/T3 | src/cli/host/doctor.ts:23-42 | Contains doctor.ts; lacks attestationEvidence/nonClaims attestation framing per 04-10-T3 | +| 204 | `src/cli/mcp/` | ?? | plan-04-10-task-3-partial | 04-10/T3 | src/cli/mcp/doctor.ts | Contains MCP doctor; attestation parity vs host doctor not verified per 04-10-T3 | +| 205 | `src/cli/quality/` | ?? | independent-fix | 04-04/T2 | src/cli/quality/ | Quality report CLI in devex index 04-04 | +| 206 | `src/cli/quickstart/` | ?? | plan-04-04-task-1-partial | 04-04/T1 | src/cli/quickstart/x402.ts | Directory has x402 quickstart only; agent-spine.ts sequencer missing per 04-04-T1 | +| 207 | `src/cli/simulate/` | ?? | independent-fix | 04-04/T1 | src/cli/simulate/ | Simulate x402-payment module referenced by agent-spine plan 04-04-T1 | +| 208 | `src/cli/state/` | ?? | independent-fix | 04-04/T2 | src/cli/state/ | State inspect CLI listed in devex index host path 04-04 | +| 209 | `src/cli/x402/readiness.ts` | ?? | independent-fix | 04-04/T2 | src/cli/x402/readiness.ts | x402 readiness helper for host operator commands 04-04 | +| 210 | `src/hosted-admission/` | ?? | phase-05-candidate | 05-09 | src/hosted-admission/index.ts | Hosted admission reexport module for 05-09 | +| 211 | `src/http/admission/hosted-verifier-adapter.ts` | ?? | phase-05-candidate | 05-09-PLAN | src/http/admission/hosted-verifier-adapter.ts | matches 05-09-PLAN files_modified | +| 212 | `src/http/handlers/hosted-record-scope.ts` | ?? | out-of-scope-defer | - | src/http/handlers/hosted-record-scope.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 213 | `src/http/handlers/raw-read-audit.ts` | ?? | out-of-scope-defer | - | src/http/handlers/raw-read-audit.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 214 | `src/http/handlers/scoped-evidence-record.ts` | ?? | phase-05-candidate | 05-08-PLAN | src/http/handlers/scoped-evidence-record.ts | matches 05-08-PLAN files_modified | +| 215 | `src/protocol/evidence-projections/store-reader.ts` | ?? | phase-05-candidate | 05-08-PLAN | src/protocol/evidence-projections/store-reader.ts | matches 05-08-PLAN files_modified | +| 216 | `src/protocol/foundation/host-trusted-binding.ts` | ?? | phase-05-candidate | 05-13-PLAN | src/protocol/foundation/host-trusted-binding.ts | matches 05-13-PLAN files_modified | +| 217 | `src/protocol/foundation/reason-code-remediation/` | ?? | plan-04-05-task-2-partial | 04-05/T2 | reason-code-remediation/index.ts | Module exists; failureClass remediation rows for new classes not verified per 04-05-T2 | +| 218 | `src/protocol/foundation/telemetry-context/` | ?? | out-of-scope-defer | - | src/protocol/foundation/telemetry-context/ | Source changes from north-star simplification; not in phase-04 files_modified | +| 219 | `src/sdk/repair.ts` | ?? | plan-04-06-task-2-partial | 04-06/T2 | sdk/repair.ts | Repair helpers present but not wired to failureClass retry guidance per 04-06-T2 | +| 220 | `src/sdk/transport-url.ts` | ?? | phase-05-candidate | 05-07 | src/sdk/transport-url.ts | SDK transport URL helper for export surface 05-07 | +| 221 | `src/surfaces/a2a-negotiation-support/adapter-apply.ts` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/adapter-apply.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 222 | `src/surfaces/a2a-negotiation-support/adapter-contract.ts` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/adapter-contract.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 223 | `src/surfaces/a2a-negotiation-support/adapter-transcript/` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/adapter-transcript/ | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 224 | `src/surfaces/a2a-negotiation-support/agreement-linker/` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/agreement-linker/ | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 225 | `src/surfaces/a2a-negotiation-support/external-protocol-evidence.ts` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/external-protocol-evidence.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 226 | `src/surfaces/a2a-negotiation-support/ingress-admission.ts` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/ingress-admission.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 227 | `src/surfaces/a2a-negotiation-support/ingress-normalizer.ts` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/ingress-normalizer.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 228 | `src/surfaces/a2a-negotiation-support/ingress-pressure.ts` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/ingress-pressure.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 229 | `src/surfaces/a2a-negotiation-support/move-compiler.ts` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/move-compiler.ts | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 230 | `src/surfaces/a2a-negotiation-support/obligation-binder/` | ?? | out-of-scope-defer | - | src/surfaces/a2a-negotiation-support/obligation-binder/ | A2A negotiation support surface; not phase-04 service-agent-gating deliverable | +| 231 | `src/surfaces/proof-packets/host-generated-code-containment.ts` | ?? | out-of-scope-defer | - | src/surfaces/proof-packets/host-generated-code-containment.ts | Source changes from north-star simplification; not in phase-04 files_modified | +| 232 | `src/surfaces/proof-packets/live-x402/` | ?? | phase-05-candidate | 05-03 | src/surfaces/proof-packets/live-x402/ | Live x402 proof packet split aligns with product-completion phase 05-03 | +| 233 | `src/surfaces/proof-packets/product-completion-contract.ts` | ?? | phase-05-candidate | 05-03-PLAN | src/surfaces/proof-packets/product-completion-contract.ts | matches 05-03-PLAN files_modified | +| 234 | `test/adapters/x402-host-trusted-binding.test.ts` | ?? | phase-05-candidate | 05-13-PLAN | test/adapters/x402-host-trusted-binding.test.ts | matches 05-13-PLAN files_modified | +| 235 | `test/adapters/x402-hosted-custody-readiness.test.ts` | ?? | phase-05-candidate | 05-13 | test/adapters/x402-hosted-custody-readiness.test.ts | Hosted custody readiness adapter test | +| 236 | `test/architecture/cli-non-authority-copy.test.ts` | ?? | phase-05-candidate | 05-11-PLAN | test/architecture/cli-non-authority-copy.test.ts | matches 05-11-PLAN files_modified | +| 237 | `test/architecture/host-trusted-binding-parity.test.ts` | ?? | phase-05-candidate | 05-13 | test/architecture/host-trusted-binding-parity.test.ts | Host trusted binding parity for 05-13 | +| 238 | `test/architecture/hosted-admission-reexport-only.test.ts` | ?? | phase-05-candidate | 05-09-PLAN | test/architecture/hosted-admission-reexport-only.test.ts | matches 05-09-PLAN files_modified | +| 239 | `test/architecture/pack-check-expect-status.test.ts` | ?? | phase-05-candidate | 05-03 | test/architecture/pack-check-expect-status.test.ts | Pack check posture for product completion | +| 240 | `test/architecture/planning-scratch-quarantine.test.ts` | ?? | phase-05-candidate | 05-11-PLAN | test/architecture/planning-scratch-quarantine.test.ts | matches 05-11-PLAN files_modified | +| 241 | `test/architecture/product-closeout-bundle.test.ts` | ?? | phase-05-candidate | 05-03 | test/architecture/product-closeout-bundle.test.ts | Product closeout architecture test | +| 242 | `test/architecture/product-completion-parity.test.ts` | ?? | phase-05-candidate | 05-03-PLAN | test/architecture/product-completion-parity.test.ts | matches 05-03-PLAN files_modified | +| 243 | `test/architecture/proof-script-build-freshness.test.ts` | ?? | phase-05-candidate | 05-03 | test/architecture/proof-script-build-freshness.test.ts | Proof script freshness gate | +| 244 | `test/architecture/publish-handoff-packet.test.ts` | ?? | phase-05-candidate | 05-03 | test/architecture/publish-handoff-packet.test.ts | Publish handoff architecture test | +| 245 | `test/cli/cli-mcp-doctor.test.ts` | ?? | independent-fix | 04-10/T3 | test/cli/cli-mcp-doctor.test.ts | MCP doctor test companion to 04-10-T3 | +| 246 | `test/cli/cli-quality-report.test.ts` | ?? | out-of-scope-defer | - | test/cli/cli-quality-report.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 247 | `test/cli/cli-simulate.test.ts` | ?? | out-of-scope-defer | - | test/cli/cli-simulate.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 248 | `test/cli/cli-state-inspect.test.ts` | ?? | out-of-scope-defer | - | test/cli/cli-state-inspect.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 249 | `test/http/hosted-identity-evidence.test.ts` | ?? | phase-05-candidate | 05-09 | test/http/hosted-identity-evidence.test.ts | Hosted identity evidence HTTP tests | +| 250 | `test/mcp/mcp-stdio-binding-integration.test.ts` | ?? | out-of-scope-defer | - | test/mcp/mcp-stdio-binding-integration.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 251 | `test/product/a2a-adapter-move-contract.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-adapter-move-contract.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 252 | `test/product/a2a-adapter-transcript.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-adapter-transcript.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 253 | `test/product/a2a-agreement-linker.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-agreement-linker.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 254 | `test/product/a2a-external-protocol-evidence.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-external-protocol-evidence.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 255 | `test/product/a2a-ingress-admission.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-ingress-admission.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 256 | `test/product/a2a-ingress-normalizer.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-ingress-normalizer.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 257 | `test/product/a2a-ingress-pressure.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-ingress-pressure.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 258 | `test/product/a2a-move-compiler.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-move-compiler.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 259 | `test/product/a2a-obligation-binder.test.ts` | ?? | out-of-scope-defer | - | test/product/a2a-obligation-binder.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 260 | `test/product/hosted-package-consumer.test.ts` | ?? | out-of-scope-defer | - | test/product/hosted-package-consumer.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 261 | `test/protocol/a2a-ingress-checkpoint.test.ts` | ?? | out-of-scope-defer | - | test/protocol/a2a-ingress-checkpoint.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 262 | `test/protocol/evidence-audit-read-projections.test.ts` | ?? | out-of-scope-defer | - | test/protocol/evidence-audit-read-projections.test.ts | Test updates from north-star/product-coherence; not phase-04 files_modified | +| 263 | `test/protocol/host-trusted-binding.test.ts` | ?? | phase-05-candidate | 05-13 | test/protocol/host-trusted-binding.test.ts | Protocol host-trusted-binding tests | +| 264 | `test/protocol/negotiation-game-state.test.ts` | ?? | out-of-scope-defer | - | test/protocol/negotiation-game-state.test.ts | A2A/negotiation test cluster outside phase-04 plans | +| 265 | `test/storage/` | ?? | out-of-scope-defer | - | test/storage/ | Test updates from north-star/product-coherence; not phase-04 files_modified | + +--- + +## Open questions for orchestrator + +- Q1: Drift is 74.7% (>20% halt threshold). Confirm whether to HALT and triage ~179 out-of-scope-defer north-star files before any phase-04 partial commits, or cherry-pick only the 22 phase-04 partial + 19 independent-fix rows. +- Q2: `docs/internal/decisions.md` mixes north-star acceptance matrix work with phase-04 Clerk-for-agents/custody obligations — should executor split into separate commits or one partial 04-01/04-10 commit? diff --git a/.planning/phases/04-service-agent-gating/04-REGRESSION-TRUTH.md b/.planning/phases/04-service-agent-gating/04-REGRESSION-TRUTH.md new file mode 100644 index 0000000..2e232b6 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-REGRESSION-TRUTH.md @@ -0,0 +1,54 @@ +# Phase 04 — Regression Ground Truth (orchestrator-adjudicated) + +**Method:** Ran the full `bun test` suite at baseline `1e801b7` in an isolated +git worktree and set-diffed against current HEAD `06c6214`. This is empirical +ground truth, not the executor's or first-fixer's self-report. + +## Headline + +- Baseline `1e801b7`: **22 test failures**, 3 tsc errors. +- After Phase 04 + first regression-fix pass (`6b06c6a`): **17 test failures**, **0 tsc errors**. +- Phase 04 **fixed 19** baseline failures but **introduced 14 new** ones. +- Net count (22→17) masked a near-complete turnover of *which* tests fail. + +The first fixer labeled all 17 "pre-existing baseline debt." That is **false**. +Only **3** are pre-existing. **12 are phase-introduced and fixable**. 2 are +environmental test-fragility (local gitignored files). + +## Classification (authoritative) + +### A. Phase-introduced + FIXABLE (12) — MUST clear before ship + +| # | Failing test | Root cause (evidence) | Fix direction | +|---|---|---|---| +| 1 | `repo naming posture > keeps source paths named by owned concepts instead of buckets` | Phase 04 created `src/cli/service/` — `service` is a banned bucket segment in `naming-posture.test.ts` (`bannedSourcePathSegments`). | Rename dir `src/cli/service/` → `src/cli/service-operator/` (segment `service-operator` is NOT banned). Update all imports, manifest sourceRoots, boundary allowlists, tests. Only file inside is `bootstrap.ts`. | +| 2 | `repo naming posture > keeps source directories below the loose-file threshold` | Phase 04 added `failure-class.ts` → `src/protocol/foundation/` now has 8 loose `.ts` files (limit 7). | Move `failure-class.ts` → `src/protocol/foundation/failure-class/index.ts` (dir import `foundation/failure-class` still resolves). Restores loose count to 7. Update relative imports if needed. | +| 3 | `repo naming posture > keeps internal planning-stage labels out of repo-facing surfaces` | Phase 04 D-15 "Tier-1 integrator" work leaked the banned stage label `Tier 1` into `src/protocol/navigation/index.ts` and `test/architecture/integrator-tier-1-parity.test.ts`. AGENTS.md doctrine forbids planning-stage labels (Tier N) in repo-facing surfaces. | **LOCKED RENAME (orchestrator decision):** rename the integrator "Tier 1" concept to a doctrine-compliant label that contains no `tier`. Use **`integrator parity`** / symbol `integratorParity` (was `integratorTier1`). Rename the test file `integrator-tier-1-parity.test.ts` → `integrator-parity.test.ts`. Preserve D-15 BEHAVIORAL intent (which integrators get parity + the parity checks); only the surface label changes. If the D-15 plan text locks the literal string "Tier 1" as a required exported symbol, STOP and write `04-FIX-HALT.md`. | +| 4 | `repo naming posture > keeps references to deleted documentation trees out of repo-facing surfaces` | `src/protocol/foundation/reason-code-remediation/index.ts` (new in Phase 04) references a deleted docs tree matching `docs/(adr\|audits\|business\|plans\|product\|protocol\|reference\|specs)` or `00-product-requirements-spine`. | Remove/repoint the stale docs reference to a canonical path (`docs/internal/...`) or drop it. | +| 5–9 | `MCP x402 reference transcript > …` (5 cases) | Phase 04 plan 04-06 (MCP failureClass parity) changed MCP behavior/output; the source-owned reference transcript + its CLI-readback pairing drifted. | Regenerate/realign the reference transcript fixtures (`src/mcp/reference-transcript*.ts`) to current MCP behavior. Ensure every row pairs with an existing CLI readback command. Do NOT expand MCP authority — transcript is evidence only. | +| 10–11 | `CLI evidence surface > exposes only active non-mutating command metadata …` and `> returns structured non-authority usage errors …` | Phase 04 added CLI commands (service-operator bootstrap, agent-spine, etc.) not registered in the evidence-surface allowlist / metadata. | Register new commands in the CLI command manifest / evidence surface so metadata + non-authority usage errors are exposed. Keep them non-mutating / non-authority. | +| 12 | `surface boundary posture > enforces allowed internal import roots for existing surface implementation roots` | `src/mcp/output.ts` and `src/mcp/x402-proposal.ts` import `../protocol/foundation/failure-class` — outside `mcp.runtime`'s allowed import roots. (0 such imports at baseline; 1 each now.) | Either (a) add `protocol/foundation/failure-class` to mcp.runtime allowed roots in the boundary manifest if doctrine permits, or (b) re-export failureClass through a root mcp is already allowed to import. Prefer the path that keeps the manifest honest. Coordinate with fix #2 (failure-class becomes a dir). | + +### B. Environmental test-fragility (2) — NOT Phase 04's fault, do NOT chase + +These fail in ANY working-dir run (including baseline-in-working-dir) because of +local gitignored files absent from a clean checkout. They are pre-existing test +design fragility, deferred to Phase 05 keel audit — NOT this fix pass. + +| Failing test | Why environmental | +|---|---| +| `repo naming posture > keeps workspace metadata junk out of active repo surfaces` | Local `.DS_Store` files (macOS). Removed root+test ones as hygiene; they regenerate. | +| `repo naming posture > keeps deleted scratch documents out of the active tree` | `.agents/` + `skills-lock.json` are the local gstack skills install (gitignored). Not a tracked tree artifact. | + +### C. Genuinely pre-existing (3) — out of scope (failed at baseline too) + +- `CLI self-hosted activation readbacks > reads self-hosted packet artifacts as evidence without becoming an authority surface` +- `Self-hosted activation packet > emits one install-and-prove packet with APS, CLI, and MCP process evidence` +- `manifest coverage > maps each product surface export to a manifest surface with matching sourceRoots` + +## Target after corrective pass + +- tsc: keep **0** (or ≤3). +- bun test: **≤ 5 failures** (the 2 environmental + 3 pre-existing = 5 acceptable ceiling; ideally lower if environmental ones are quieted). +- Tier gates: operator 10/10 + full 15/15 must stay green. +- No `as any` / type-weakening. No naming-posture test weakening to force a pass. diff --git a/.planning/phases/04-service-agent-gating/04-RESEARCH.md b/.planning/phases/04-service-agent-gating/04-RESEARCH.md new file mode 100644 index 0000000..dc00389 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-RESEARCH.md @@ -0,0 +1,572 @@ +# Phase 04: Service agent gating — Research + +**Researched:** 2026-05-28 +**Domain:** Agent-first service operator UX — dual enforcement (hosted/API admission + gateway-checked mutation) without protocol kernel semantic changes +**Confidence:** HIGH for codebase anchors and locked decisions; MEDIUM for exact Tier-1 ID list and RFC 9457 wire shape (needs planner confirmation on backward compatibility) + +## Summary + +Phase 04 makes Handshake legible to **service operators** who must gate **agents** on consequential endpoints while keeping the protocol kernel frozen. The product chain is already modeled in `service-workflow-admission` (Passport → Admission → Handle → fresh Clearance per event) and enforced in the kernel spine (compile → contract → policy → gateway → receipt). What is missing is **operator-grade packaging**: dual-lane vocabulary, a **Tier-1 integrator transition surface**, a **public failure taxonomy** that separates auth from execution-control, **custody matrices** (service vs host), **HTTP-profile generalization** from auth.md, and **structural bypass proof** (architecture tests + conformance-gated service scaffold) — not prose claiming “middleware = protection.” + +**Clerk-for-agents analogy (user-locked framing):** In Next.js, Clerk middleware can identify the session and attach identity to the request, but **route handlers** must still enforce authorization before a consequential write. Handshake is the same shape for agents: **hosted/API admission** (`src/http/admission/index.ts`) answers “who may invoke kernel transitions / read evidence,” while **adapter-wrapped gateway checks** (`src/adapters/*/gateway.ts`, `src/conformance/`) answer “does this exact greenlight authorize this exact mutation.” Admission alone is **advisory**; only gateway-checked adapter paths are Handshake. + +**Primary recommendation:** Extend product surfaces and HTTP error taxonomy in place; tag `protocol/navigation` with Tier-1 integrator metadata; generalize auth.md’s HTTP parameter profile into a shared adapter contract; add architecture + conformance tests that fail if a service registers consequential routes without adapter binding — **one runnable spine remains x402** (`src/cli/quickstart/x402.ts`, `docs/internal/host-golden-paths-and-trace-guidance.md`). + +## Architectural Responsibility Map + +| Capability | Primary Tier | Secondary Tier | Rationale | +|------------|-------------|----------------|-----------| +| Caller identity before kernel HTTP | API / Backend (`src/http/admission/`) | Hosted verifier adapters (`src/hosted-admission/`) | Admission runs before transition handlers; no mutation authority | +| Catalog triplet + atomic install | API / Backend (control-plane transitions) | SDK `InstallClient` (`src/sdk/surface-clients/install-client.ts`) | Service operator registers ToolCapability, ActionType, GatewayRegistryEntry + envelope atomically | +| Intent → exact contract | Protocol kernel (`compileIntent`, `proposeActionContract`) | Runtime ingress / MCP proposal surfaces | Compilation is evidence; contract is the commitment shape | +| Policy greenlight / refusal | Protocol kernel (`evaluatePolicy`) | HTTP POST + `PolicyClient` | One-use greenlight is kernel-owned | +| Mutation enforcement | Adapter / gateway (`run*Gateway` + `VerifiedGatewayCheck`) | External PEP in front (optional glue only) | Enforcement is observed-parameter re-check at mutation boundary | +| Agent workflow correlation | Product projection (`src/surfaces/service-workflow-admission/`) | MCP metadata on x402 proposal | Non-authority handles; fresh contract per protected action | +| Host binding attestation | Host operator CLI (`src/cli/host/doctor.ts`, MCP doctor) | `host-trusted-binding` classifier | Digests attest host posture; not service gateway ownership | +| Public HTTP errors | HTTP transport (`transition-error-envelope.ts`) | `reason-code-remediation` | Service consumers need auth vs clearance separation | +| Bypass proof | Test + conformance (`test/architecture/*`, `src/conformance/`) | Proof packets (deferred per-service launch) | Structural gates, not documentation-only | + +## User Constraints + + +## User Constraints (from CONTEXT.md) + +### Locked Decisions + +- **D-00 — Dual enforcement:** Service operators need **admission** (caller identity / scope before kernel transitions) **and** **gateway check** (before mutation). Ingress-only posture is **advisory**, not Handshake. +- **D-00b — Wedge vs platform:** `x402_payment.exact` remains the **proof wedge**; phase 04 optimizes **any-service agent gating**, not payment-only product. +- **D-01 — Standing bounds:** `OperatingEnvelope` = class-level attempt bounds for principal+agent (not permission, not vague intent). +- **D-02 — Delegated mandate:** `DelegatedAuthorityRef` = episodic principal→agent mandate evidence for an instance (e.g. delegated spend); status transitions + isolation; **not** a greenlight or bearer pass. +- **D-03 — Compile bridge:** `IntentCompilationRecord` = vague intent/runtime evidence → one `CandidateAction` (uncertainty recorded, no authority). +- **D-04 — Work order:** `ActionContract` = exact proposed commitment; only this shape enters policy and gateway binding. +- **D-05 — Product vocabulary:** Teach **Standing Bounds → Delegated Mandate (when required) → Compile → Work Order → Clearance → Outcome** in agent-facing docs; keep schema-native names in protocol/API (attenuation-chain dual vocabulary, no export renames in this phase). +- **D-06 — Dual-lane docs:** Extend `service-workflow-story.md` pattern: agent lane parallel to unchanged canonical state path; every projection keeps explicit non-authority flags (`createsAuthority: false`, `freshActionContractRequired: true`). +- **D-07 — Progressive two-tier (default):** Service registers **catalog triplet** per endpoint family (`ToolCapability`, `ActionType`, `GatewayRegistryEntry`) first; **per-instance** `OperatingEnvelope` + policy pack and/or `DelegatedAuthorityRef` at delegation/admission time. +- **D-08 — Atomic install per family:** Control-plane `InstallProposal` commits catalog + gateway + baseline policy bundle per family **or refuses** — no orphan catalog without gateway entry. +- **D-09 — Full day-one envelope:** Reserved for **fixed-tenant / regulated** services only — not the default multi-agent hosted path. +- **D-10 — Hybrid layered model:** Shared **HTTP transport profile** (method, path template, allowlisted headers, raw body digest) for arbitrary REST-like endpoints; **family adapters** (x402, package install, preview deploy, repo write, auth.md) where semantic canonicalization and bypass probes matter. +- **D-11 — auth.md as profile prototype:** Treat `auth_md_protected_api_call.exact` as the pattern for HTTP-profile canonicalization, not as proof that one generic adapter covers all consequence shapes. +- **D-12 — External PEP optional:** Envoy/Kong/OPA may sit **in front** for deployment; Handshake still requires adapter-side observed-parameter re-check against exact greenlight — PEP is glue, not enforcement substitute. +- **D-13 — One runnable spine:** Single agent-first recipe: register catalog → agent proposes → policy → gateway → readback; **x402** is the only **runnable** reference implementation in this phase. +- **D-14 — Proof-gap stubs:** Add **non-runnable** recipe stubs for auth.md and package install (transition map + schema + explicit proof-gap / admission boundaries) if integrators need transfer confidence — not second runnable paths. +- **D-15 — Tier-1 kernel UX:** Document and test a **Tier-1** transition set for integrators (catalog, compile/propose, evaluatePolicy, gatewayCheck, readback); full `protocol/navigation` matrix remains reference for extenders. +- **D-16 — Optional recipe sequencer:** SDK/CLI helper that calls transitions in order is allowed only as **explicitly non-authority**, with invariant tests: no greenlight reuse, gateway required, fresh contract on retry, no bundled “execute” API. +- **D-17 — Extend `TransitionErrorEnvelope`:** Add `failureClass` / `phase` separating `auth`, `hosted_admission`, `protected_action_refusal`, `proof_gap`, `replay_refusal`, `stale_admission`. +- **D-18 — HTTP status discipline:** **401/403** only for credential/identity; **409** refusals/replay/stale binding; **422** proof gaps; never map clearance failure to generic forbidden (OAuth BCP anti-pattern). +- **D-19 — RFC 9457 compatibility:** Problem Details `type` URIs + `reason-code-remediation` extensions for public HTTP consumers. +- **D-20 — Outcome-as-success:** **200 + claim status** only on dedicated admission/readback routes — not on mutation attempts. +- **D-21 — Responsibility matrix:** Extend production acceptance / operator docs with **configured-by** columns: service operator vs host operator. +- **D-22 — Bilateral runbooks:** Paired `service-operator` and `host-operator` setup order (registry before host attestation; stale digests fail closed). +- **D-23 — Doctor as attestation:** Host `doctor` / readiness output framed as **attestation evidence** for binding digests — not a parallel identity system (SPIFFE analogy only in prose). +- **D-24 — Not documentation-only:** “Every consequential route adapter-wrapped” requires **architecture tests** + **conformance-gated service scaffold** — not prose alone. +- **D-25 — Launch gates deferred:** Product-completion-style per-service bypass proof packets (like x402/MCP activation) ship when route inventory and host evidence exist — not claimed in phase 04 for all services. + +### Claude's Discretion + +- Exact Tier-1 transition ID list and where it lives (`protocol/navigation` tags vs new doc). +- Whether proof-gap stubs ship in phase 04 or immediately after plan 01. +- Recipe sequencer module placement (`sdk/` vs `cli/quickstart/`). +- How many HTTP profile canonicalization rules are codified vs documented first. + +### Deferred Ideas (OUT OF SCOPE) + +- **Second runnable golden path** (auth.md or package install) in same phase — until admission packet + focused gates green (`decisions.md` proof contexts). +- **Schema export aliases** (`StandingBounds`, `DelegatedMandate`) — product docs only in phase 04. +- **Generic HTTP-only platform claim** without family adapters for wallet/repo/deploy/install — insufficient bypass posture. +- **External PEP as sole gate** — evidence theatre without adapter re-check. +- **Per-domain operator doc silos** — fragments agent-first spine. +- **Layer 5 clearing / cross-org verification** — `ecosystem-strategy.md` Layer 5. +- **Full kernel transition reduction** — breaks reconstruction and parity tests. +- **Hosted operation go-ahead** — separate hosted workspace per `protocol-notes.md` hosted admission lock. + + + +## Standard Stack + +### Core (existing — do not replace) + +| Component | Version | Purpose | Why Standard | +|-----------|---------|---------|--------------| +| `handshake-protocol-kernel` | 0.2.8 (local) | Protocol kernel, HTTP, SDK, surfaces | Source-owned authority spine [VERIFIED: `package.json`] | +| `bun` test runner | via `bun test` | Unit + architecture tests | Repo standard [VERIFIED: `package.json` scripts] | +| `zod` | workspace dep | Envelopes, admission, adapter params | All transition I/O validated [VERIFIED: codebase] | +| `hono` | HTTP app | Worker transition routes | `src/http/app.ts` [VERIFIED: ARCHITECTURE.md] | + +### Supporting (extend in-phase) + +| Component | Location | Purpose | When to Use | +|-----------|----------|---------|-------------| +| `protocol/navigation` | `src/protocol/navigation/index.ts` | Full transition catalog | Add Tier-1 metadata; no semantic edits | +| `InstallClient` | `src/sdk/surface-clients/install-client.ts` | Atomic catalog install | Service operator onboarding (D-07, D-08) | +| `ProtectedMutationAdapter` conformance | `src/conformance/index.ts` | Gateway-before-mutation probe | Every family adapter + service scaffold (D-24) | +| `adapter-sdk` | `src/adapter-sdk/` | External service adapter packs | Service-defined families (see `examples/external-adapter-sdk/`) | +| `reason-code-remediation` | `src/protocol/foundation/reason-code-remediation/` | Operator next steps on errors | Wire into `failureClass` + RFC 9457 `type` URIs (D-17, D-19) | + +### Alternatives Considered + +| Instead of | Could Use | Tradeoff | +|------------|-----------|----------| +| Extend `TransitionErrorEnvelope` | New parallel error API | Breaks SDK `transitionErrorResult` consumers; duplicate taxonomy | +| Tier-1 tags in navigation | Separate integrator-only route registry | Drift from HTTP `transition-route-registry.ts`; tags + parity test is safer | +| Generic HTTP-only adapter | Family adapters only | Insufficient bypass posture per D-10/D-11 and `claim-boundary` expansion criteria | +| External PEP as enforcement | Adapter `VerifiedGatewayCheck` | Advisory-only path; violates D-00 and AGENTS.md | + +**Installation:** No new npm dependencies required for phase scope. [VERIFIED: phase goal is docs, tests, envelope extension, navigation metadata] + +## Package Legitimacy Audit + +> Phase 04 does not introduce new external packages. Existing dependencies remain governed by repo `package.json` and supply-chain checks in `pack:check`. + +| Package | Registry | slopcheck | Disposition | +|---------|----------|-----------|-------------| +| (none proposed) | — | — | N/A | + +**Packages removed due to slopcheck [SLOP] verdict:** none +**Packages flagged as suspicious [SUS]:** none + +## Architecture Patterns + +### System Architecture Diagram + +```text + ┌──────────────────────────────────────┐ + │ Agent / host runtime (MCP, CLI) │ + │ proposal + host-trusted binding │ + └─────────────────┬────────────────────┘ + │ evidence / proposal only + v +┌─────────────────────────────────────────────────────────────────────────┐ +│ Service operator plane │ +│ Passport / Admission / Handle (service-workflow-admission) │ +│ Catalog triplet + InstallClient atomic setup │ +│ Service HTTP routes (app handlers) ──must──> adapter.run*Gateway │ +└───────────────────────────────┬─────────────────────────────────────────┘ + │ HTTP + bearer / hosted admission + v +┌─────────────────────────────────────────────────────────────────────────┐ +│ Handshake HTTP Worker │ +│ authorizeTransitionAdmission() ──> caller identity / roles │ +│ kernel transitions: compile → propose → evaluatePolicy → gatewayCheck │ +└───────────────────────────────┬─────────────────────────────────────────┘ + │ VerifiedGatewayCheck only + v +┌─────────────────────────────────────────────────────────────────────────┐ +│ Gateway adapter (x402, auth.md, package-install, service-defined…) │ +│ observed params re-check → mutation OR refusal / proof_gap evidence │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### Recommended file touch map (planner task seeds) + +| Workstream | Primary paths | Tests | +|------------|---------------|-------| +| Tier-1 integrator UX | `src/protocol/navigation/index.ts`, new `docs/internal/integrator-tier-1-transitions.md` | `test/architecture/integrator-tier-1-parity.test.ts` | +| Public failure taxonomy | `src/http/errors/transition-error-envelope.ts`, `src/http/admission/caller-auth.ts`, `src/http/openapi/index.ts` | `test/http/transition-error-failure-class.test.ts` | +| Dual-lane agent docs | `docs/internal/service-workflow-story.md`, `docs/internal/protocol-layman.md`, `docs/internal/protocol-definition.md` (cross-link only) | `test/architecture/claim-boundary.test.ts` (new required strings) | +| Service operator golden path | new `docs/internal/service-operator-golden-path.md`, extend `docs/internal/decisions.md` | `test/architecture/dual-enforcement-posture.test.ts` | +| Host/service custody | `docs/internal/decisions.md`, `docs/internal/host-golden-paths-and-trace-guidance.md`, `src/surfaces/x402-protected-tool-acceptance.ts` (pattern) | `test/architecture/custody-matrix-parity.test.ts` | +| HTTP profile layer | new `src/adapters/http-profile/` (extract from `src/adapters/auth-md/action-proposal.ts` + `profiles.ts`) | `test/adapters/http-profile-canonicalization.test.ts` | +| Proof-gap recipe stubs | `examples/auth-md-protected-api-stub/`, `examples/package-install-protected-action-stub/` | `test/architecture/proof-gap-recipe-stub.test.ts` | +| Recipe sequencer (optional) | `src/cli/quickstart/agent-spine.ts` or `src/sdk/agent-spine-sequencer.ts` | `test/cli/cli-agent-spine-sequencer.test.ts` | +| Service bypass scaffold | new `src/surfaces/service-mutation-route-manifest/` + `test/architecture/service-mutation-route-manifest.test.ts` | extend `test/conformance/protected-mutation-adapter-conformance.test.ts` | + +### Pattern 1: Tier-1 transition tagging (D-15) + +**What:** Add `integratorTier: 1 | 2 | 3` (or `integratorSurface: "tier1" | "extender"`) on `ProtocolNavigationEntry` entries in `src/protocol/navigation/index.ts`, plus exported `integratorTier1TransitionIds` const. + +**Recommended Tier-1 IDs** (align with D-15 + existing HTTP routes in `src/http/routes/transition-route-registry.ts`): + +| Tier-1 transition | Phase | Runnable in phase 04? | +|-------------------|-------|------------------------| +| `registerToolCapability` | catalog | Yes (setup) | +| `registerActionType` | catalog | Yes | +| `registerGatewayRegistryEntry` | catalog | Yes | +| `registerOperatingEnvelope` | catalog | Yes (per-instance or regulated day-one) | +| `registerInstallProposalCompiledRecords` | install_setup | Yes (atomic family install) | +| `registerDelegatedAuthorityRef` | delegated_authority | Yes (agent mandate evidence) | +| `compileIntent` | intent_compilation | Yes | +| `proposeActionContract` | action_contract | Yes | +| `evaluatePolicy` | policy | Yes | +| `gatewayCheck` | gateway | Yes | +| `reconcileSurfaceOperation` | operation_lifecycle | Yes (outcome readback) | + +**Explicitly Tier-2+ (document, do not hide):** negotiation graph, recovery terminal conflict, bypass probes, review artifacts, authority certificate mint, isolation/breaker — still in navigation for extenders. + +**When to use:** Integrator docs, SDK quickstart, architecture parity tests (every Tier-1 ID has HTTP route + role + non-authority sequencer guard). + +### Pattern 2: `failureClass` on `TransitionErrorEnvelope` (D-17–D-20) + +**What:** Extend `TransitionErrorEnvelopeSchema` in `src/http/errors/transition-error-envelope.ts`: + +```typescript +// Recommended fields (planner: exact enum names + migration) +failureClass: z.enum([ + "auth", + "hosted_admission", + "protected_action_refusal", + "proof_gap", + "replay_refusal", + "stale_admission", + "internal", +]), +failurePhase: z.enum(["admission", "transition", "readback"]).nullable(), +problemType: z.string().url().nullable(), // RFC 9457 type URI +``` + +Map in `classifyTransitionError()` and admission paths (`caller-auth.ts`, hosted verifier errors) using existing `HandshakeProtocolError.code` prefixes and `reason-code-remediation` owner surfaces. + +**HTTP status discipline (D-18):** + +| failureClass | Status | Examples | +|--------------|--------|----------| +| `auth` | 401 / 403 | Missing bearer, wrong role | +| `hosted_admission` | 403 | Stale hosted identity, org mismatch | +| `protected_action_refusal` | 409 | Policy refusal, gateway refusal | +| `replay_refusal` | 409 | Greenlight reuse | +| `stale_admission` | 409 | Handle/admission stale vs fresh contract | +| `proof_gap` | 422 | Missing evidence, ambiguous commit | +| `internal` | 500 | Unexpected | + +**RFC 9457 (D-19):** Add optional `Content-Type: application/problem+json` variant or dual-body policy documented in OpenAPI — **keep** existing `{ error: TransitionErrorEnvelope }` for SDK compatibility; add `problemType` URI derived from `remediation.docsUrl` + code slug. [MEDIUM confidence: no existing Problem Details in repo — verified by grep] + +### Pattern 3: HTTP transport profile (D-10, D-11) + +**What:** Extract shared fields from `AuthMdProtectedApiCallParametersSchema` (`src/adapters/auth-md/action-proposal.ts` lines 19–46) into reusable `HttpProtectedMutationProfileSchema`: + +- `targetHttpMethod`, `endpointUrl`, `pathTemplate`, `requestBodyDigest`, `selectedHeadersDigest` +- anti-bypass flags: `dynamicEndpointConstructionObserved`, `dynamicHostConstructionObserved`, `retryAuthorityReuseDetected` + +Family adapters **narrow** the profile with semantic fields (x402 payment params, package coordinates, etc.). `auth_md` remains the reference implementation, not the only adapter. + +**Source pattern:** `runAuthMdProtectedApiCallGateway` in `src/adapters/auth-md/gateway.ts` — gateway check → credential resolution → surface execute → reconcile. + +### Pattern 4: Service mutation route manifest (D-24) + +**What:** Source-owned manifest type (similar to `boundary-manifest.ts`) listing each service consequential HTTP route with: + +- `routeId`, `actionClass`, `adapterGatewayFn`, `conformanceProbeRef` +- `admissionOnly: false` (must be false for consequential) +- `requiresVerifiedGatewayCheck: true` + +Architecture test: every manifest entry must register a `ProtectedMutationAdapterProbe`; unlisted service routes in example scaffolds fail CI. + +**Do not** claim per-service `pack:check` bypass packets in phase 04 (D-25). + +### Pattern 5: Proof-gap recipe stubs (D-14) + +**What:** Non-runnable example packages under `examples/*-stub/` with: + +- Transition map excerpt (Tier-1 only) +- JSON schema fixtures +- `proofGaps: [...]` and `runnable: false` +- Explicit admission boundaries copied from `service-workflow-story.md` + +Mirror structure of `examples/service-workflow-admission/run.ts` but stop before live gateway/signers. + +### Anti-Patterns to Avoid + +- **Admission-as-protection:** Returning 403 on policy refusal from admission middleware only — violates D-00/D-18. +- **Bundled “execute” API:** Single SDK method that policy+gateway+mutates — violates D-16 and greenlight reuse invariants. +- **Generic HTTP adapter without family probes:** Declaring platform support without `ProtectedMutationAdapter` conformance — violates D-10 and D-24. +- **Second runnable quickstart:** auth.md or package-install quickstart that hits signers — deferred until admission packets green. +- **Kernel transition edits:** Any change to transition semantics or outcome classes — forbidden (Phase 03 lock). + +## Don't Hand-Roll + +| Problem | Don't Build | Use Instead | Why | +|---------|-------------|-------------|-----| +| Gateway-before-mutation guard | Custom boolean in each service route | `assertProtectedMutationAdapterConformance` | Proven pattern in `test/conformance/protected-mutation-adapter-conformance.test.ts` | +| Atomic catalog registration | Three separate POSTs without install transition | `registerInstallProposalCompiledRecords` + `InstallClient` | Orphan catalog without gateway is a bypass vector (D-08) | +| Operator error taxonomy | Ad-hoc string codes per service | `TransitionErrorEnvelope` + `failureClass` + `reason-code-remediation` | SDK already parses envelope (`src/sdk/client.ts`) | +| Service workflow authority | New “workflow permission” object | `service-workflow-admission` + fresh `ActionContract` | Already guarded by `workflow-admission-boundary.test.ts` | +| Host identity system | Parallel SPIFFE-like IDs in product | `host-trusted-binding` + `handshake host doctor` | Phase 03 parity; D-23 | +| Per-service launch proof | Fake green bypass packets | Architecture manifest + deferred proof packets | D-25; honest proof gaps | + +**Key insight:** The repo already has the enforcement primitive (`VerifiedGatewayCheck`); phase 04 packages **operator mental models** and **failure surfaces** around it without new authority types. + +## Common Pitfalls + +### Pitfall 1: Middleware theatre + +**What goes wrong:** Docs or examples imply hosted admission or Passport/Handle replaces gateway enforcement. +**Why it happens:** Clerk/OAuth analogies overextended. +**How to avoid:** Dual-lane docs + `dual-enforcement-posture.test.ts` forbidding phrases like “admission authorizes mutation.” +**Warning signs:** 403 on clearance failures; missing adapter on service REST handlers. + +### Pitfall 2: Tier-1 / HTTP route drift + +**What goes wrong:** Integrators call transitions that exist in kernel but lack HTTP routes or roles. +**Why it happens:** `protocolNavigation` and `transitionRouteDefinitions` maintained separately today. +**How to avoid:** `integrator-tier-1-parity.test.ts` asserts Tier-1 ⊆ `transition-route-registry.ts` with matching roles. +**Warning signs:** SDK client methods 404 on Worker deploy. + +### Pitfall 3: failureClass / status mis-map + +**What goes wrong:** Policy refusals returned as 403; agents retry with same contract. +**Why it happens:** Default `HandshakeProtocolError.status` mapping in `classifyTransitionError`. +**How to avoid:** Explicit mapping table in `transition-error-envelope.ts` + tests per class. +**Warning signs:** OAuth-style “forbidden” for stale greenlight. + +### Pitfall 4: HTTP profile over-generalization + +**What goes wrong:** Single “generic REST adapter” without family-specific bypass probes. +**Why it happens:** Desire to avoid N adapters. +**How to avoid:** Shared profile schema + mandatory family adapter for wallet/repo/deploy/install consequence shapes (D-10). +**Warning signs:** No `createBypassProbe` or conformance probe for new family. + +### Pitfall 5: Proof script / dist staleness + +**What goes wrong:** Surface changes without `npm run build` pass `pack:check` falsely. +**Why it happens:** Proof scripts import `dist/surfaces/index.mjs`. +**How to avoid:** Keep `proof-script-build-freshness.test.ts`; document in operator runbooks. [VERIFIED: CONCERNS.md] + +## Code Examples + +### Protected mutation conformance (existing) + +```typescript +// Source: test/conformance/protected-mutation-adapter-conformance.test.ts +await assertProtectedMutationAdapterConformance({ + name: "package-install", + mutationCount: () => surface.mutationCount, + async attemptWithoutVerifiedGatewayCheck() { + await runPackageInstallGateway({ /* greenlight without verified gate */ }); + }, +}); +``` + +### Service workflow non-authority boundary (existing) + +```typescript +// Source: test/architecture/workflow-admission-boundary.test.ts +expect(admission.authorityBoundary).toEqual(serviceWorkflowNonAuthorityBoundary()); +expect(admission.nextActionRequirement).toBe("fresh_action_contract_required"); +``` + +### HTTP profile fields (auth.md prototype) + +```typescript +// Source: src/adapters/auth-md/action-proposal.ts — extract to http-profile +targetHttpMethod: z.string().min(1), +endpointUrl: z.string().url(), +pathTemplate: z.string().min(1), +requestBodyDigest: DigestSchema.nullable(), +selectedHeadersDigest: DigestSchema, +dynamicEndpointConstructionObserved: z.boolean(), +``` + +### Recommended failureClass classification (new) + +```typescript +// Source: pattern from src/http/errors/transition-error-envelope.ts classifyTransitionError +function failureClassForProtocolError(error: HandshakeProtocolError): FailureClass { + if (error.code.startsWith("caller_") || error.code === "unauthorized") return "auth"; + if (error.code.startsWith("hosted_")) return "hosted_admission"; + if (error.code.includes("replay")) return "replay_refusal"; + if (error.code.includes("proof_gap") || error.status === 422) return "proof_gap"; + if (error.code.includes("refusal") || error.status === 409) return "protected_action_refusal"; + return "internal"; +} +``` + +## State of the Art + +| Old Approach | Current Approach | When Changed | Impact | +|--------------|------------------|--------------|--------| +| Host-trusted binding diverged MCP vs adapter | Shared `classifyHostTrustedProposalBinding` | Phase 03 | Host parity tests — do not replan | +| Single error code string only | `TransitionErrorEnvelope` + remediation | Pre-04 | Extend with `failureClass`, not replace | +| x402-only operator story | Service workflow + multi-family adapters | Phase 02–03 surfaces | Phase 04 generalizes operator UX | +| auth.md+x402 admission packet local green | Still blocked for live composite execution | 2026-05 CONCERNS | Stubs only in phase 04 | + +**Deprecated/outdated:** + +- Treating `ServiceWorkflowHandle` as bearer permission — forbidden by `service-workflow-story.md` and architecture tests. +- Ingress-only generated-code blocking as sole enforcement — runtime ingress is evidence, not gateway (AGENTS.md). + +## What NOT to Build (phase boundary) + +| Item | Reason | +|------|--------| +| New kernel transitions or outcome class changes | CONTEXT + Phase 03 freeze | +| Runnable auth.md / package-install quickstart | D-14; admission packets not green | +| `StandingBounds` / `DelegatedMandate` export aliases | Deferred | +| Per-service product-completion bypass packets | D-25 | +| Envoy/OPA as enforcement substitute | D-12; advisory only | +| Hosted operation go-ahead workspace | Deferred hosted lock | +| Turning `pack:check` live x402 / host containment green | Out of scope | +| Schema renames in protocol public API | D-05 product vocabulary only | + +## Assumptions Log + +| # | Claim | Section | Risk if Wrong | +|---|-------|---------|---------------| +| A1 | RFC 9457 can be additive (dual JSON shape) without breaking SDK | failureClass | SDK clients ignore unknown fields if envelope preserved | +| A2 | Tier-1 list should include `registerDelegatedAuthorityRef` for agent mandate story | Tier-1 | Integrators skip mandate evidence path | +| A3 | `src/adapters/http-profile/` is the right extraction point | HTTP profile | Could live in `adapter-sdk` instead — planner discretion | +| A4 | Proof-gap stubs ship as `examples/*-stub/` in phase 04 | D-14 discretion | May slip to plan 02 if scope tight | + +## Open Questions + +1. **RFC 9457 wire format** + - What we know: No `application/problem+json` today [VERIFIED: repo grep]. + - What's unclear: Single response body vs `Accept` negotiation. + - Recommendation: Plan 01 — extend envelope with `problemType` URI; optional Problem Details wrapper behind content negotiation in Plan 02 if needed. + +2. **Recipe sequencer placement** + - What we know: `quickstart/x402.ts` pattern is non-authority stepped CLI with explicit flags. + - Recommendation: `src/cli/quickstart/agent-spine.ts` delegating to x402 steps only (runnable), linking to stubs (non-runnable). + +3. **Service manifest location** + - Recommendation: `src/surfaces/service-mutation-route-manifest/index.ts` + example manifest in `examples/external-adapter-sdk/` for conformance gate. + +## Environment Availability + +| Dependency | Required By | Available | Version | Fallback | +|------------|------------|-----------|---------|----------| +| Node.js | build, some scripts | ✓ | ≥20 (engines) | — | +| bun | `npm test` | ✓ | (project default) | — | +| npm run build | proof scripts / dist | ✓ | package scripts | Required before pack:check | + +**Missing dependencies with no fallback:** none identified for phase scope. + +## Validation Architecture + +### Test Framework + +| Property | Value | +|----------|-------| +| Framework | bun test [VERIFIED: package.json] | +| Config file | none (bun native) | +| Quick run command | `bun test test/architecture/integrator-tier-1-parity.test.ts` (after added) | +| Full suite command | `bun test` | + +### Phase Requirements → Test Map + +| Req / Decision | Behavior | Test Type | Automated Command | File Exists? | +|----------------|----------|-----------|-------------------|-------------| +| D-00 dual enforcement | Docs/tests forbid admission-only protection claims | architecture | `bun test test/architecture/dual-enforcement-posture.test.ts` | ❌ Wave 0 | +| D-15 Tier-1 UX | Tier-1 transitions ⊆ HTTP routes + roles | architecture | `bun test test/architecture/integrator-tier-1-parity.test.ts` | ❌ Wave 0 | +| D-17–D-19 failure taxonomy | failureClass + status mapping | unit/http | `bun test test/http/transition-error-failure-class.test.ts` | ❌ Wave 0 | +| D-06 dual-lane docs | Agent vocabulary in canonical docs | architecture | extend `bun test test/architecture/claim-boundary.test.ts` | ✅ extend | +| D-24 bypass scaffold | Manifest + conformance gate | architecture + conformance | `bun test test/architecture/service-mutation-route-manifest.test.ts` | ❌ Wave 0 | +| D-14 proof-gap stubs | Non-runnable examples | architecture | `bun test test/architecture/proof-gap-recipe-stub.test.ts` | ❌ Wave 0 | +| D-11 HTTP profile | Shared canonicalization rules | unit | `bun test test/adapters/http-profile-canonicalization.test.ts` | ❌ Wave 0 | +| D-16 sequencer | No authority leakage | cli | `bun test test/cli/cli-agent-spine-sequencer.test.ts` | ❌ Wave 0 (optional) | +| Regression | Service workflow boundary | architecture | `bun test test/architecture/workflow-admission-boundary.test.ts` | ✅ | +| Regression | Protected mutation adapters | conformance | `bun test test/conformance/protected-mutation-adapter-conformance.test.ts` | ✅ | + +### Sampling Rate + +- **Per task commit:** targeted `bun test` on touched test files +- **Per wave merge:** `bun test test/architecture test/http test/conformance` +- **Phase gate:** full `bun test` green before `/gsd-verify-work` + +### Wave 0 Gaps + +- [ ] `test/architecture/integrator-tier-1-parity.test.ts` +- [ ] `test/architecture/dual-enforcement-posture.test.ts` +- [ ] `test/http/transition-error-failure-class.test.ts` +- [ ] `test/architecture/service-mutation-route-manifest.test.ts` +- [ ] `test/architecture/proof-gap-recipe-stub.test.ts` +- [ ] `test/adapters/http-profile-canonicalization.test.ts` (if http-profile extracted) +- [ ] `docs/internal/integrator-tier-1-transitions.md` +- [ ] `docs/internal/service-operator-golden-path.md` + +## Security Domain + +### Applicable ASVS Categories + +| ASVS Category | Applies | Standard Control | +|---------------|---------|------------------| +| V2 Authentication | yes | Hosted verifier + bearer tokens; 401/403 only for auth class (D-18) | +| V3 Session Management | yes | Hosted identity freshness (`assertHostedCallerFresh`) | +| V4 Access Control | yes | Role-scoped transition admission; separate clearance failure class | +| V5 Input Validation | yes | Zod on all transition bodies and adapter observed parameters | +| V6 Cryptography | partial | Digests for contracts/params; no hand-rolled crypto | + +### Known Threat Patterns for this stack + +| Pattern | STRIDE | Standard Mitigation | +|---------|--------|---------------------| +| Raw tool / route bypass | Elevation of privilege | Adapter conformance + route manifest (D-24) | +| Greenlight reuse / ambient authority | Spoofing | Kernel gateway binding + sequencer invariant tests (D-16) | +| Admission token → mutation | Elevation | Dual enforcement docs + failureClass separation | +| Dynamic endpoint construction | Tampering | HTTP profile flags from auth.md pattern | +| Confusing auth vs refusal | Information disclosure | HTTP status discipline (D-18) | + +## Project Constraints (from .cursor/rules/) + +No `.cursor/rules/` directory in repo. **`AGENTS.md`** is authoritative doctrine: gateway enforcement, no authority from surfaces, proof gaps over fake certainty, planning scratch quarantine (`.planning/` not canonical exports). + +## Sources + +### Primary (HIGH confidence) + +- `.planning/phases/04-service-agent-gating/04-CONTEXT.md` — locked decisions D-00–D-25 +- `.planning/codebase/ARCHITECTURE.md` — layer diagram, admission vs kernel flow +- `src/http/admission/index.ts`, `src/http/errors/transition-error-envelope.ts` — admission and envelope extension point +- `src/protocol/navigation/index.ts` — full transition catalog +- `src/adapters/auth-md/action-proposal.ts`, `gateway.ts` — HTTP profile prototype +- `src/conformance/index.ts`, `test/conformance/protected-mutation-adapter-conformance.test.ts` — bypass enforcement pattern +- `test/architecture/workflow-admission-boundary.test.ts` — non-authority workflow surfaces +- `docs/internal/service-workflow-story.md`, `docs/internal/decisions.md` (acceptance matrix pattern) + +### Secondary (MEDIUM confidence) + +- OAuth BCP / 403 vs 409 discipline — aligned with D-18; exact code→status table to be finalized in implementation + +### Tertiary (LOW confidence) + +- RFC 9457 dual-response negotiation — no prior art in repo; validate with integrator consumers during plan review + +## Metadata + +**Confidence breakdown:** + +- Standard stack: HIGH — repo-native; no new packages +- Architecture: HIGH — anchors exist; phase is packaging + tests +- Pitfalls: HIGH — enforced by existing tests and AGENTS.md +- failureClass / RFC 9457 wire: MEDIUM — extension design clear; wire compatibility TBD + +**Research date:** 2026-05-28 +**Valid until:** 2026-06-28 (stable kernel); 2026-06-14 for failureClass API if external consumers integrate early + +--- + +## RESEARCH COMPLETE + +**Phase:** 04 - service-agent-gating +**Confidence:** HIGH + +### Key Findings + +- Phase 04 is **operator UX and structural proof** on an existing kernel spine — not new transitions; dual enforcement (admission + gateway) is already architecturally present but under-documented and under-tested for generic services. +- **Clerk-for-agents:** admission identifies callers; only **adapter-wrapped `VerifiedGatewayCheck`** paths are Handshake for mutation — must be tested and documented, not implied. +- **Tier-1** should be tagged in `src/protocol/navigation/index.ts` with parity tests against `transition-route-registry.ts`; recommended IDs listed above include catalog, atomic install, delegated mandate, compile/propose, policy, gateway, reconcile. +- **`TransitionErrorEnvelope`** is the correct extension point for `failureClass` + HTTP status discipline; RFC 9457 should be additive via `problemType` URIs tied to `reason-code-remediation`. +- **auth.md** already implements the HTTP transport profile prototype; extract to shared `http-profile` module and keep family adapters + `ProtectedMutationAdapter` conformance for bypass proof (D-24). +- **One runnable spine stays x402** (`quickstart/x402.ts`); auth.md and package-install ship as **non-runnable proof-gap stubs** only. + +### File Created + +`.planning/phases/04-service-agent-gating/04-RESEARCH.md` + +### Confidence Assessment + +| Area | Level | Reason | +|------|-------|--------| +| Standard stack | HIGH | No new deps; existing Handshake modules | +| Architecture | HIGH | Code paths verified in repo | +| Pitfalls | HIGH | Prior phase tests + doctrine | +| Public error wire | MEDIUM | Envelope extension clear; RFC 9457 shape TBD | + +### Open Questions (RESOLVED) + +- **RFC 9457 wire shape** — **RESOLVED:** Additive `problemType` URI on existing `TransitionErrorEnvelope` only (Plan 02). Full `application/problem+json` negotiation deferred until an external consumer requires it. +- **Recipe sequencer placement** — **RESOLVED:** `src/cli/quickstart/agent-spine.ts` with `cli-agent-spine-sequencer` anti-theatre tests (Plan 03). No bundled SDK `execute()` API. +- **Proof-gap stub timing** — **RESOLVED:** Stubs ship in Plan 04 (`examples/*-stub/`); Plan 01 docs link to stubs after merge. +- **Service mutation manifest location** — **RESOLVED:** `src/surfaces/service-mutation-route-manifest/` + example JSON under `examples/external-adapter-sdk/` (Plan 06). + +### Ready for Planning + +Research complete. Planner can now create PLAN.md files with concrete paths, test Wave 0, and explicit out-of-scope table above. diff --git a/.planning/phases/04-service-agent-gating/04-REVIEW-FIX.md b/.planning/phases/04-service-agent-gating/04-REVIEW-FIX.md new file mode 100644 index 0000000..234b6b2 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-REVIEW-FIX.md @@ -0,0 +1,92 @@ +--- +phase: 04-service-agent-gating +fixed_at: 2026-05-29T09:20:00Z +review_path: .planning/phases/04-service-agent-gating/04-REVIEW.md +iteration: 1 +findings_in_scope: 9 +fixed: 9 +skipped: 0 +status: all_fixed +--- + +# Phase 04: Code Review Fix Report + +**Fixed at:** 2026-05-29 +**Source review:** `.planning/phases/04-service-agent-gating/04-REVIEW.md` +**Iteration:** 1 + +**Summary:** +- Findings in scope: 9 (4 HIGH + 5 MEDIUM; H-03 doc-only; L-01/L-02 out of scope) +- Fixed: 9 +- Skipped: 0 + +## Fixed Issues + +### H-01: Policy-decision refusals misclassified as proof_gap + +**Files modified:** `src/protocol/foundation/failure-class/index.ts`, `src/protocol/foundation/reason-codes.ts` +**Commit:** `62757b6`, `c7bba7e` +**Applied fix:** `failureClassFromReasonCodeMetadata` branches on `decisionPolarity` for `policy_decision`; negative policy codes tagged `decisionPolarity: "refusal"` in the reason-code registry. Parity tests in `test/protocol/failure-class-taxonomy.test.ts`. + +### H-02: Over-broad "proof" substring match + +**Files modified:** `src/protocol/foundation/failure-class/index.ts` +**Commit:** `62757b6` +**Applied fix:** Removed `code.includes("proof")` heuristic; classification uses metadata kind/phase and explicit registry fields. Custody `gateway_custody_proof_*` codes regress to `internal`, not `proof_gap`. + +### H-04: SDK loses taxonomy on non-envelope HTTP errors + +**Files modified:** `src/sdk/surface-clients/transport.ts`, `src/sdk/client.ts`, `src/surfaces/boundary-manifest.ts` +**Commit:** `8674616`, `c7bba7e` +**Applied fix:** `failureClassFromHttpStatus` when envelope parse fails; SDK tests for empty/malformed 401/409/422 bodies. Surface manifest allows `protocol/foundation/failure-class` for sdk.* transport roots. + +### M-01: Dual-enforcement test doc-grep only + +**Files modified:** `test/architecture/dual-enforcement-posture.test.ts` +**Commit:** `abde73b` +**Applied fix:** Top-of-file and `describe()` label clarify doctrine-prose guard, not runtime bypass proof. + +### M-02: Recovery reason-code path ignores refusal polarity + +**Files modified:** `src/protocol/foundation/failure-class/index.ts` +**Commit:** `62757b6` +**Applied fix:** `failureClassFromReasonCodeMetadata` recovery branch uses `options.proofRef` like protocol-error path. + +### M-03: Auth.md gateway preflight throws generic Error + +**Files modified:** `src/adapters/auth-md/gateway.ts` +**Commit:** `dfd6531` +**Applied fix:** Unsafe observed parameters return structured `gateway_check_refused` with reason codes instead of `new Error()`. + +### M-04: requireInstallProposalGatewayRegistryEntry throws plain Error + +**Files modified:** `src/install/install-proposal/index.ts` +**Commit:** `50721dd` +**Applied fix:** Throws `HandshakeProtocolError("install_orphan_catalog_missing_gateway", …, 422)`. Test in `test/install/install-proposal-gateway-registry.test.ts`. + +### M-05: Unknown protocol errors default to internal + +**Files modified:** `src/protocol/foundation/failure-class/index.ts`, `src/http/errors/transition-error-envelope.ts` +**Commit:** `62757b6`, `c7bba7e` +**Applied fix:** Unknown 4xx → `protected_action_refusal` (or `proof_gap` with `proofRef`); registered HTTP shaping codes stay `internal` with preserved 400/404/413 status. + +### Regression fix (Hono HTTP status collapse) + +**Files modified:** `src/http/errors/transition-error-envelope.ts`, `src/protocol/foundation/failure-class/index.ts`, `test/http/transition-error-failure-class.test.ts` +**Commit:** `c7bba7e` +**Applied fix:** `failureClassForProtocolError` treats non-admission HTTP registry codes as `internal` so M-05 defaults do not map `invalid_request`/`record_not_found` to 409. + +## Skipped Issues + +None — all in-scope findings were fixed. + +## Out of scope (verified) + +- **H-03:** No golden-path doc claims that arbitrary integrator services are structurally gate-enforced; no edits required. +- **L-01, L-02:** Not touched. + +--- + +_Fixed: 2026-05-29_ +_Fixer: Claude (gsd-code-fixer)_ +_Iteration: 1_ diff --git a/.planning/phases/04-service-agent-gating/04-REVIEW.md b/.planning/phases/04-service-agent-gating/04-REVIEW.md new file mode 100644 index 0000000..67b3337 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-REVIEW.md @@ -0,0 +1,133 @@ +# Phase 04 Code Review + +**Reviewer:** gsd-code-reviewer · **Date:** 2026-05-29 · **Range:** 1e801b7..979b99c + +## Summary + +**Verdict: SHIP-WITH-FIXES** + +Phase 04 delivers honest dual-enforcement doctrine, a runnable x402 service-operator bootstrap, adapter-level gateway gating on first-party surfaces, and fail-closed orphan-catalog refusal at the install transition. Nullable `gatewayRegistryEntry` guards refuse or throw — no silent null-skip on the gateway path was found. Tier gates (10/10 operator, 15/15 full) pass. + +The main risk is **failureClass taxonomy drift**: several policy-refusal reason codes classify as `proof_gap` (422) instead of `protected_action_refusal` (409), which violates D-17/D-18 and can mislead MCP/SDK integrators on retry semantics. Structural bypass proof for arbitrary integrator HTTP routes remains deferred (D-25). + +| Severity | Count | +| --- | --- | +| CRITICAL | 0 | +| HIGH | 4 | +| MEDIUM | 5 | +| LOW | 2 | + +--- + +## CRITICAL + +_No CRITICAL findings. Nullable gateway-registry guards fail loud; first-party mutation paths remain adapter-gated._ + +--- + +## HIGH + +### H-01. Policy-decision refusals misclassified as `proof_gap` — `src/protocol/foundation/failure-class/index.ts:75-76,132-133` + +- **Invariant at stake:** D-17/D-18 — clearance refusals must not map to generic forbidden or proof-gap HTTP semantics; `failureClass` must separate auth, admission, refusal, replay, and proof gap. +- **Problem:** For `metadata.kind === "policy_decision"`, codes without `"refusal"` or `"refused"` in the string (e.g. `envelope_not_active`, `action_class_outside_envelope`, `prior_action_not_greenlit`, `contract_expired`) classify as `proof_gap`. These are policy denials from `policy-greenlight/policy.ts`, not missing-evidence gaps. MCP/SDK consumers using `classifyFailureClassFromReasonCodes` will surface 422-style semantics and `read_evidence` retry guidance for hard refusals. +- **Fix:** Treat negative policy-decision codes as `protected_action_refusal` unless explicitly tagged `proof_gap` in reason-code metadata (e.g. add `decisionPolarity: "refusal" | "pass" | "proof_gap"` to reason-code registry, or maintain an explicit refusal set). Add parity tests for `envelope_not_active`, `action_class_outside_envelope`, and `prior_action_not_greenlit`. + +### H-02. Over-broad `"proof"` substring match — `src/protocol/foundation/failure-class/index.ts:146` + +- **Invariant at stake:** failureClass taxonomy integrity across HTTP + MCP; proof gaps must not be used to soften operational/custody failures. +- **Problem:** `code.includes("proof")` matches custody and transition errors such as `gateway_custody_proof_custody_mismatch` (metadata kind `transition_error`) after the metadata switch falls through. These become `proof_gap` instead of `protected_action_refusal` or `internal`. +- **Fix:** Remove the substring heuristic; rely on `resolveProtocolReasonCodeMetadata` kind/phase, explicit prefix sets, or a dedicated `failureClass` field on reason-code entries. Add regression tests for `gateway_custody_proof_*` codes. + +### H-03. D-24 structural enforcement stops at first-party handlers — `test/architecture/http-handler-mutation-gating.test.ts:6-79` + +- **Invariant at stake:** D-00/D-24 — ingress/admission alone is advisory; every consequential route on an integrator service must be adapter-wrapped and gateway-checked. +- **Problem:** Mutation gating is proven for `src/http/handlers/**` (read-only allowlist) and three example runners only. An integrator deploying Handshake HTTP routes outside this inventory can still expose unwrapped mutation endpoints. Phase gate passes; arbitrary-service bypass posture is not structurally enforced (honestly deferred as D-25, but the gap is real). +- **Fix:** Phase 05 `service-mutation-route-manifest` + CI gate; until then, golden-path docs should avoid implying full-service structural proof. Consider a conformance scaffold that fails closed when new handler files appear outside the allowlist without manifest entry. + +### H-04. SDK loses taxonomy on non-envelope HTTP errors — `src/sdk/surface-clients/transport.ts:73-93`, `src/sdk/client.ts:325-340` + +- **Invariant at stake:** D-17 — public failure surface must expose typed `failureClass` on all protected-action error paths. +- **Problem:** When the HTTP body is empty, malformed, or not `TransitionErrorResponseSchema`, both transports synthesize `code: "http_error"` with `failureClass` from `failureClassForProtocolError(...)` → typically `internal`. A proxy or middleware returning HTML/empty 403/409 strips refusal/replay/proof-gap classification from `HandshakeClientError` and `explainHandshakeError`. +- **Fix:** Preserve HTTP status in a dedicated field; map status bands (401→auth, 409→refusal/replay, 422→proof_gap) when envelope parse fails. Record `proof_gap` when classification is indeterminate rather than defaulting to `internal`. Add SDK tests for malformed-body 409/422 responses. + +--- + +## MEDIUM + +### M-01. Dual-enforcement “structural” test is doc-grep only — `test/architecture/dual-enforcement-posture.test.ts:20-58` + +- **Invariant at stake:** D-00 — do not conflate admission with enforcement; structural claims need runtime evidence. +- **Problem:** The test validates prose patterns in markdown, not that an integrator HTTP service cannot mutate without `run*Gateway`. This is appropriate as a doctrine guard but can be mistaken for runtime bypass proof. +- **Fix:** Rename or annotate test intent (`doctrine-prose`); pair with D-25 manifest gate for runtime claims. Keep doc test; do not cite it as structural enforcement evidence. + +### M-02. Recovery reason-code path ignores refusal polarity — `src/protocol/foundation/failure-class/index.ts:134-135` vs `79-80` + +- **Invariant at stake:** Receipt honesty — recovery conflicts with `proofRef` are proof gaps; without proofRef they are refusals. +- **Problem:** `classifyFailureClassFromReasonCode` always returns `proof_gap` for `metadata.kind === "recovery"`, while `classifyFailureClassFromProtocolError` branches on `error.metadata.proofRef`. MCP reason-code-only paths can misclassify recovery refusals. +- **Fix:** Align reason-code classifier with protocol-error branch (check associated proofRef when available, or tag recovery codes with expected failureClass in reason-code metadata). + +### M-03. Auth.md gateway preflight throws generic `Error` — `src/adapters/auth-md/gateway.ts:253-260` + +- **Invariant at stake:** Gateway check is the enforcement boundary; unsafe observed parameters must produce structured refusal/proof-gap evidence, not uncaught exceptions. +- **Problem:** `assertNoGatewayUnsafeObservedParameters` throws `new Error(...)` instead of returning a typed gateway refusal result. Callers may not record refusal/proof-gap receipts or attach `failureClass`. +- **Fix:** Return the same structured refusal shape used by other adapters (e.g. x402 wallet gateway early return with reason codes) or throw `HandshakeProtocolError` with appropriate metadata refs. + +### M-04. `requireInstallProposalGatewayRegistryEntry` throws plain `Error` — `src/install/install-proposal/index.ts:35-41` + +- **Invariant at stake:** Nullable registry handling must fail loud with typed, reconstructable outcomes. +- **Problem:** CLI compile paths (`src/cli/x402/index.ts:323-325`) call this helper; an uncaught throw surfaces as generic 500/internal rather than `install_orphan_catalog_missing_gateway` refusal. Kernel transition path correctly refuses at `install-setup/transitions.ts:37-41`. +- **Fix:** Throw `HandshakeProtocolError("install_orphan_catalog_missing_gateway", ..., 422)` or return null and let caller refuse with typed reason codes. Add CLI test for orphan compiled records. + +### M-05. Unknown protocol errors default to `internal` — `src/protocol/foundation/failure-class/index.ts:88-91` + +- **Invariant at stake:** Missing evidence must be recorded as proof gap, not smoothed over; unknown clearance failures must not look like server misconfiguration. +- **Problem:** HandshakeProtocolError without metadata, reason-code metadata, or 5xx status becomes `failureClass: "internal"`. New refusal codes added without metadata registration silently degrade to internal until metadata is updated. +- **Fix:** Default unknown 4xx to `protected_action_refusal` (or `proof_gap` when `proofRef` present); reserve `internal` for 5xx and explicit misconfiguration codes. Fail CI when new reason codes lack metadata. + +--- + +## LOW + +### L-01. Schema validation errors use `failureClass: internal` with HTTP 400 — `src/http/errors/transition-error-envelope.ts:171-187` + +- **Invariant at stake:** D-18 HTTP status discipline. +- **Problem:** `invalid_request` returns 400 with `failureClass: "internal"`, which is semantically odd for client malformed input (not server internal error). +- **Fix:** Introduce `failureClass: "auth"` or a dedicated client-error class, or document 400+internal as intentional for malformed transition bodies. + +### L-02. Generic HTTP profile skeleton is honestly non-mutating — `src/adapters/http-profile/generic-gateway-skeleton.ts:13-23` + +- **Invariant at stake:** Do not claim structural enforcement where only transport validation exists. +- **Problem:** Low risk — skeleton returns `definition_only` + `generic_http_profile_live_mutation_forbidden`. Integrators could still wire it as a live gateway without reading posture. +- **Fix:** Export type branding or runtime guard that rejects mutation attempts at call sites; keep tests asserting proof-gap code. + +--- + +## Enforcement-doctrine checklist + +| Lens | Verdict | Evidence | +| --- | --- | --- | +| 1. Enforcement vs advisory | **PASS (scoped)** | Golden path + bootstrap explicitly non-authority (`src/cli/service-operator/bootstrap.ts:179-184,207-210`); HTTP handlers read-only (`http-handler-mutation-gating.test.ts`); example runners require `run*Gateway`. Admission alone not claimed as enforcement. | +| 2. One-use greenlight | **PASS (wedge)** | `consumeGreenlight` returns `already_consumed`; MCP maps replay codes (`src/mcp/x402-proposal.ts:302-316`); agent-spine forbids greenlight reuse claims (`test/cli/cli-agent-spine-sequencer.test.ts:23-25`). Not exhaustively re-audited across all adapters. | +| 3. Gateway bypass | **PARTIAL** | First-party HTTP + 3 example runners gated; runtime ingress refuses unsafe dispatch shapes (`src/runtime/ingress/families.ts:304-318`). No inventory for arbitrary integrator routes (D-25 deferred). | +| 4. failureClass taxonomy integrity | **FAIL (fixable)** | HTTP envelope path solid for tested codes (`transition-error-failure-class.test.ts`); MCP parity tests cover subset (`mcp-failure-class-parity.test.ts`). Policy-decision misclassification (H-01, H-02). | +| 5. Receipt honesty | **PASS (adapter spine)** | Bootstrap/install transitions set `gatewayCheckPerformed: false`, `mutationAttempted: false` (`install-setup/transitions.ts:16-26`). x402 CLI digests credential refs, not raw secrets (`src/cli/x402/index.ts:310-317`). | +| 6. Nullable gateway-registry handling | **PASS** | Refuses at transition (`install-setup/transitions.ts:37-41`); throws in catalog record builder (`115-120`); orphan test passes (`http-profile-orphan-catalog.test.ts:35-37`). No silent null-skip found. | +| 7. Naming-doctrine renames | **PASS** | No `Tier-1`, `integratorTier1`, `src/cli/service/`, or `service/bootstrap` in repo-facing surfaces (grep clean). `integratorParity` in `src/protocol/navigation/index.ts`. | +| 8. SQL/secret/eval surfaces | **PASS (scoped)** | Bootstrap uses `secretref:` fixture refs (`bootstrap.ts:79`); WorkerBindings tokens in-memory only (`216-222`); output JSON excludes tokens (`examples/service-operator-bootstrap/run.ts:19-43`). No eval/new SQL surfaces in diff. | + +--- + +## Out of scope / deferred to Phase 05 + +- Full service mutation route manifest and registry sync (`04-CONTEXT.md` D-25; `http-handler-mutation-gating.test.ts:6-8`). +- MCP Registry discoverability proof (documented proof gap in AGENTS.md). +- Manifest coverage export mapping (`manifest-coverage.test.ts` — pre-existing at baseline). +- Standalone service/host operator runbook extraction. +- Exhaustive failureClass parity for all policy-decision and custody reason codes (recommended Phase 05 hardening alongside H-01/H-02 fixes). + +--- + +_Reviewed: 2026-05-29T12:00:00Z_ +_Reviewer: gsd-code-reviewer (adversarial, standard depth)_ +_Files reviewed: 72 under `src/`, `test/`, `scripts/`, `examples/` in range 1e801b7..979b99c_ diff --git a/.planning/phases/04-service-agent-gating/04-SECURITY.md b/.planning/phases/04-service-agent-gating/04-SECURITY.md new file mode 100644 index 0000000..f423b05 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-SECURITY.md @@ -0,0 +1,145 @@ +# Phase 04 Security Audit + +**Auditor:** gsd-security-auditor · **Date:** 2026-05-29 · **Range:** 1e801b7..979b99c + +## Verdict + +**PASS-WITH-FINDINGS** — Wedge-path enforcement (x402 wallet gateway, kernel HTTP read-only posture, bootstrap refusal boundaries, failureClass taxonomy, custody proof checks) is structurally present and tested. No declared `mitigate` threat in phase plans lacks code evidence. The highest-confidence gap is **partial structural bypass coverage for arbitrary integrator services** (honestly deferred to Phase 05), not a silent regression in the runnable x402 spine. + +| Severity | Count | +|----------|------:| +| HIGH | 0 | +| MEDIUM | 1 | +| LOW | 2 | +| Watch (≤6/10) | 2 | + +**Threat register:** 33/33 `mitigate` CLOSED · 2/2 `accept` CLOSED · 2/2 `defer` documented + +--- + +## Findings + +### [MEDIUM] P04-SEC-01. Integrator mutation routes lack inventory-level gateway binding — `test/architecture/http-handler-mutation-gating.test.ts:6-8` + +- Threat (STRIDE): **Elevation of privilege** — generated agent code or a sibling HTTP handler can mutate outside `run*Gateway` if an integrator adds unlisted consequential routes. +- Attack scenario: A service operator follows Phase 04 docs, registers catalog via bootstrap, and ships a custom Express/Fastify route that calls a wallet signer directly. Handshake kernel HTTP remains read-only, but the operator’s **own** service process is not inventory-gated in this phase. +- Evidence (code): D-24 enforcement is limited to first-party handler allowlist + three example runners; manifest deferred explicitly: + +```6:8:test/architecture/http-handler-mutation-gating.test.ts + * Phase 04 D-24 enforcement: handler walk only. + * service-mutation-route-manifest deferred to maintainer lane (phase 05). +``` + +- Mitigation status: **partial** — `T-04-11-01` CLOSED for repo kernel; `T-04-11-02` / `T-04-11-03` deferred. +- Recommendation: Phase 05 must land `service-mutation-route-manifest` + CI inventory before marketing “any service” as structurally gated. + +### [LOW] P04-SEC-02. Default bootstrap seeds `fixture_gateway_held` catalog posture — `src/cli/service-operator/bootstrap.ts:77-79` + +- Threat (STRIDE): **Spoofing / elevation confusion** — operators may treat bootstrap output as production gateway-held enforcement. +- Attack scenario: Agent runs `handshake service bootstrap` with defaults; catalog records `enforcementMode: reference_fixture` and `credentialCustodyStatus: fixture_gateway_held` while CLI prints success. Operator skips live custody packet and readiness registration; later runtime facade refuses mutation (fail-closed), but catalog posture overstates production readiness. +- Evidence (code): + +```77:79:src/cli/service-operator/bootstrap.ts + signerCustodyStatus: "fixture_gateway_held", + signerRef: "secretref:service-bootstrap-fixture-signer", +``` + +```388:390:src/adapters/x402-payment/install-proposal.ts + credentialCustodyStatus: gateway.signerCustodyStatus, + enforcementMode: + gateway.signerCustodyStatus === "fixture_gateway_held" ? "reference_fixture" : "customer_gateway_adapter", +``` + +- Mitigation status: **partial** — runtime facade + CLI readiness refuse unverified `customer_gateway_evidence` (`src/adapters/x402-payment/protected-tool-facade/index.ts:290-308`); bootstrap CLI warnings state no mutation (`bootstrap.ts:207-210`). +- Recommendation: Emit explicit `proofGapRefs` or `enforcementMode` in bootstrap CLI result so operators cannot confuse fixture catalog with live gateway-held posture. + +### [LOW] P04-SEC-03. Dual-enforcement structural proof is doc-grep for arbitrary services — `test/architecture/dual-enforcement-posture.test.ts:20-57` + +- Threat (STRIDE): **Repudiation** — doctrine tests grep markdown; they do not exercise an integrator’s unwrapped route at runtime. +- Attack scenario: Docs claim dual enforcement; integrator code bypasses adapters; architecture tests still pass. +- Evidence (code): Test only scans documentation files for gateway/admission language patterns. +- Mitigation status: **partial** (honest deferral per `04-VERIFICATION.md` G0/D-24 row). +- Recommendation: Pair doc-grep with Phase 05 manifest gate; keep doc test as necessary but not sufficient. + +### Watch items (confidence ≤6/10) + +1. **Agent-supplied `signerRef` in bootstrap `installInput`** — Zod-validated ref strings are stored in gateway registry (`mutationCredentialHolderRef`) but bootstrap result omits raw credential material (`credentialMaterialIncluded: false` in CLI envelope). Risk is misconfiguration, not direct secret exfil via failureClass payloads; no ≥7/10 exploit path found without subsequent unverified custody claims (which facade rejects). +2. **`fixture_gateway_held` idempotent re-bootstrap** — Second bootstrap run does not duplicate registry entries (`service-operator-bootstrap.test.ts:92-101`); no ambient authority amplification observed. + +--- + +## Threat-model mitigation verification + +Claims sourced from per-plan `` blocks in `04-01-PLAN.md` … `04-12-PLAN.md` and D-decisions in `04-CONTEXT.md`. + +| Claimed mitigation (plan threat ID) | Exists in code? | Evidence | +|-------------------------------------|-----------------|----------| +| Non-authority dual-lane docs (T-04-01-01, T-04-01-02) | Yes | `test/architecture/claim-boundary.test.ts`, `test/architecture/dual-enforcement-posture.test.ts` | +| Forbid middleware theatre claims (T-04-01-03) | Yes | `claim-boundary.test.ts` forbiddenPatterns | +| No new npm deps (T-04-01-SC, T-04-02-SC) | Yes | `git diff 1e801b7..HEAD -- package.json` — scripts only | +| Golden path x402-only runnable + authorityBoundary (T-04-02-01, T-04-02-02) | Yes | `docs/internal/service-operator-golden-path.md`; `examples/service-operator-golden-path/run.ts` | +| Bootstrap x402-only + non-authority flags (T-04-03-01) | Yes | `bootstrap.ts:141-147`, `193-213`; `service-operator-bootstrap.test.ts:70-81` | +| Atomic install / orphan catalog refusal (T-04-03-02, T-04-08-03) | Yes | `http-profile-orphan-catalog.test.ts:35-37`; `install-setup/transitions.ts:190-193` | +| Refuse non-x402 families (T-04-03-03) | Yes | `bootstrap.ts:141-147` | +| Agent-spine non-authority sequencer (T-04-04-01, T-04-04-02) | Yes | `cli-agent-spine-sequencer.test.ts:11-36` | +| Doctor attestation nonClaims (T-04-04-03, T-04-10-01) | Yes | `src/cli/host/doctor.ts`; `custody-matrix-parity.test.ts:28-33` | +| failureClass HTTP status discipline (T-04-05-01, T-04-05-02) | Yes | `transition-error-envelope.ts:102-124`; `transition-error-failure-class.test.ts` | +| Readback-only 200+claim (T-04-05-03) | Yes | `http.test.ts` readback cases; OpenAPI failureClass notes | +| MCP/SDK failureClass parity (T-04-06-01, T-04-06-03) | Yes | `mcp-failure-class-parity.test.ts`; `role-clients-failure-class.test.ts` | +| SDK repair requires fresh contract (T-04-06-02) | Yes | `src/sdk/repair.ts:51-63` | +| Integrator parity / no bundled execute (T-04-07-01, T-04-07-02) | Yes | `integrator-parity.test.ts`; `role-clients-walkthrough.test.ts` | +| HTTP profile definition_only skeleton (T-04-08-01) | Yes | `generic-gateway-skeleton.ts:5-22` | +| Dynamic construction refusal (T-04-08-02) | Yes | `http-profile-canonicalization.test.ts:25-31` | +| Proof-gap honesty / no stub runnable paths (T-04-09-01) | Yes | `proof-gap-honesty.test.ts` | +| Custody matrix configuredBy (T-04-10-02, T-04-10-03) | Yes | `custody-matrix-parity.test.ts`; `docs/internal/decisions.md` | +| Handler mutation gating (T-04-11-01) | Yes | `http-handler-mutation-gating.test.ts:48-79` | +| Route manifest inventory (T-04-11-02) | **Deferred** | Documented Phase 05; no `service-mutation-route-manifest` module | +| Product-completion inventory slice (T-04-11-03) | **Deferred** | `maintainer-product-completion-contract.test.ts` | +| Phase gate tier exits (T-04-12-01) | Yes | `scripts/check-service-agent-gating-phase.mjs:61-63` | +| Integration non-authority (T-04-12-02) | Yes | `service-operator-golden-path.test.ts` | +| VERIFICATION honest gaps (T-04-12-03) | Yes | `04-VERIFICATION.md` partial rows | + +### User-requested control areas (04-CONTEXT invariants) + +| Control area | Status | Evidence | +|--------------|--------|----------| +| Ambient authority / greenlight reuse | **Enforced (wedge)** | `x402-wallet-gateway.test.ts:224-253` (`already_consumed`, single signature); `recovery/schemas.ts:70` `mayReuseGreenlight: false` | +| Gateway bypass (kernel + examples) | **Enforced (partial)** | Read-only handler allowlist; `runX402WalletGateway` gates before sign (`wallet-gateway.ts:201-213`); example runners require `run*Gateway` | +| Credential / secret custody | **Enforced** | `agent_exposed` install refused (`install-proposal.ts:419-420`, `service-operator-bootstrap.test.ts:37-50`); customer custody claims require verification (`protected-tool-facade/index.ts:295-307`); CLI envelope `credentialMaterialIncluded: false` | +| Trusted-binding integrity | **Enforced** | Tampered readiness fails doctor (`cli-x402-install-probes.test.ts:432-474`); MCP refuses missing bindings before runtime (`mcp-x402-proposal.test.ts:161-178`) | +| Replay / idempotency | **Enforced** | Changed params refused pre-sign (`x402-wallet-gateway.test.ts:199-221`); replay maps to `replay_refusal` (`failure-class/index.ts:118-119`) | +| Supply chain / CI | **Enforced** | No new dependencies; CI uses `npm run check:repo` without publish (`naming-posture.test.ts:161-167`) | +| Injection into privileged ops | **Bounded** | Bootstrap/control-plane inputs Zod-parsed (`ServiceBootstrapInputSchema`); MCP oversized fields refused pre-runtime; HTTP profile rejects dynamic construction | +| Proof-gap honesty | **Enforced** | Proof gaps recorded in adapter outcomes (`payment_signature_proof_gap`); generic HTTP skeleton returns proof gap code; architecture forbids fake runnable stubs | + +--- + +## Supply-chain / CI posture + +| Check | Status | +|-------|--------| +| New `package.json` dependencies in diff | **PASS** — none added | +| Phase scripts only (`check:service-agent-gating-phase*`) | **PASS** | +| CI bound to `npm run check:repo` | **PASS** — `naming-posture.test.ts:165` | +| CI excludes `npm publish` / trusted-publish | **PASS** — `naming-posture.test.ts:166-167` | +| GitHub Actions pinned to commit SHAs | **PASS** — `naming-posture.test.ts:170-179` | +| Publish token surfaces untouched by Phase 04 diff | **PASS** — no `.github/workflows` changes in range | + +--- + +## Deferred / accepted risk (with rationale) + +| ID | Disposition | Rationale | +|----|-------------|-----------| +| T-04-11-02 | **defer** | Full mutation route manifest requires integrator inventory not available in Phase 04 scope (D-25). Bypass risk acknowledged in `04-VERIFICATION.md` and P04-SEC-01. | +| T-04-11-03 | **defer** | `check-product-completion` inventory slice depends on manifest module. | +| T-04-01-SC / T-04-02-SC | **accept** | No new npm packages; supply-chain delta limited to scripts and tests. | +| MCP Registry discoverability | **proof gap (honest)** | Documented in AGENTS.md; not faked green (`proof-gap-honesty.test.ts`). | + +--- + +## Auditor notes + +- **ASVS level:** 2 (protocol control plane; no payment PAN/storage in scope). +- **block_on policy:** `open` mitigations → **0 open**; deferred threats documented. +- **Highest-severity finding:** P04-SEC-01 (integrator route inventory gap) — advisory for Phase 04 operator tier, blocking for “any arbitrary service structurally gated” product claim until Phase 05. diff --git a/.planning/phases/04-service-agent-gating/04-VALIDATION.md b/.planning/phases/04-service-agent-gating/04-VALIDATION.md new file mode 100644 index 0000000..209614f --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-VALIDATION.md @@ -0,0 +1,210 @@ +--- +phase: 04 +slug: service-agent-gating +status: approved +nyquist_compliant: true +wave_0_complete: false +created: 2026-05-28 +replanned: 2026-05-28 +plans: 12 +tasks: 48 +product_user_audit: applied-2026-05-28 +--- + +# Phase 04 — Validation Strategy (comprehensive 12-plan delivery) + +> Per-phase validation contract for feedback sampling during execution. Maps 48 tasks across plans 01–12 (post product/user audit patch). + +--- + +## Test Infrastructure + +| Property | Value | +|----------|-------| +| **Framework** | bun test | +| **Config file** | none (bun native) | +| **Phase gate command** | `node scripts/check-service-agent-gating-phase.mjs` (plan 12) | +| **Quick run command** | `bun test test/architecture/dual-enforcement-posture.test.ts` | +| **Full suite command** | `bun test` | +| **Estimated runtime** | ~150 seconds full suite; targeted subsets 5–20s | + +--- + +## Sampling Rate + +- **After every task commit:** Run the task `` verify command from PLAN.md +- **After every wave:** `bun test test/architecture test/http test/adapters test/cli test/conformance test/integration test/product test/sdk test/mcp` +- **Before `/gsd-verify-work`:** `node scripts/check-service-agent-gating-phase.mjs` then full `bun test` +- **Max feedback latency:** 30 seconds (targeted files) + +--- + +## Per-Task Verification Map + +### Plan 01 — dual-lane doctrine (S1) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-01-01 | 01 | 1 | D-05, D-06, D-01–D-04 | T-04-01-01 | architecture | `bun test test/architecture/claim-boundary.test.ts` | ✅ extend | ⬜ pending | +| 04-01-02 | 01 | 1 | D-00, D-12 | T-04-01-02 | doc+grep | `grep -v '^#' docs/internal/protocol-definition.md \| grep -c 'run\*Gateway'` | — | ⬜ pending | +| 04-01-03 | 01 | 1 | D-00, D-00b | T-04-01-03 | architecture | `bun test test/architecture/dual-enforcement-posture.test.ts` | ❌ W0 | ⬜ pending | +| 04-01-04 | 01 | 1 | D-06 | T-04-01-01 | architecture | `bun test test/architecture/claim-boundary.test.ts` | ✅ extend | ⬜ pending | + +### Plan 02 — service-operator golden path (S2) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-02-01 | 02 | 1 | D-05, D-13 | T-04-02-01 | doc+grep | `test -f docs/internal/service-operator-golden-path.md && grep -q 'Step 3' docs/internal/service-operator-golden-path.md && grep -q 'Branch A' docs/internal/service-operator-golden-path.md` | ❌ W0 | ⬜ pending | +| 04-02-02 | 02 | 1 | D-13, D-22 | — | doc+grep | `grep -v '^#' docs/internal/developer-experience-index.md \| grep -c 'service-operator-golden-path'` | ✅ extend | ⬜ pending | +| 04-02-03 | 02 | 1 | D-13 | T-04-02-02 | integration | `npm run demo:service-workflow-admission` | ✅ | ⬜ pending | +| 04-02-04 | 02 | 1 | D-07, D-13 | T-04-02-01 | example | `bun run examples/service-operator-golden-path/run.ts` | ❌ W0 | ⬜ pending | + +### Plan 03 — atomic install bootstrap (S3) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-03-01 | 03 | 2 | D-07, D-08 | T-04-03-02 | product | `bun test test/product/service-operator-bootstrap.test.ts` | ❌ W0 | ⬜ pending | +| 04-03-02 | 03 | 2 | D-08, D-13 | T-04-03-01 | product | `bun test test/product/service-operator-bootstrap.test.ts` | ❌ W0 | ⬜ pending | +| 04-03-03 | 03 | 2 | D-08 | T-04-03-02 | http+product | `bun test test/product/service-operator-bootstrap.test.ts test/http/http.test.ts` | ✅ extend | ⬜ pending | +| 04-03-04 | 03 | 2 | D-08, D-13 | — | doc+grep | `grep -v '^#' docs/internal/service-operator-golden-path.md \| grep -c 'service bootstrap'` | ❌ W0 | ⬜ pending | +| 04-03-05 | 03 | 2 | D-08 | T-04-03-02 | product | `bun test test/product/service-operator-bootstrap.test.ts` | ❌ W0 | ⬜ pending | + +### Plan 04 — agent-host spine (S4) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-04-01 | 04 | 2 | D-16, D-13 | T-04-04-01 | cli | `bun test test/cli/cli-agent-spine-sequencer.test.ts` | ❌ W0 | ⬜ pending | +| 04-04-02 | 04 | 2 | D-16 | T-04-04-01 | architecture | `bun test test/architecture/cli-command-posture.test.ts` | ✅ | ⬜ pending | +| 04-04-03 | 04 | 2 | D-16 | T-04-04-02 | cli | `bun test test/cli/cli-agent-spine-sequencer.test.ts` | ❌ W0 | ⬜ pending | +| 04-04-04 | 04 | 2 | D-22, D-23 | T-04-04-03 | doc+grep | `grep -v '^#' docs/internal/host-golden-paths-and-trace-guidance.md \| grep -c 'host doctor'` | ✅ extend | ⬜ pending | + +### Plan 05 — failure taxonomy HTTP (S5) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-05-01 | 05 | 3 | D-17, D-19 | T-04-05-01 | http | `bun test test/http/transition-error-failure-class.test.ts` | ❌ W0 | ⬜ pending | +| 04-05-02 | 05 | 3 | D-18 | T-04-05-01 | http | `bun test test/http/transition-error-failure-class.test.ts` | ❌ W0 | ⬜ pending | +| 04-05-03 | 05 | 3 | D-17, D-18, D-20 | T-04-05-03 | http | `bun test test/http/transition-error-failure-class.test.ts` | ❌ W0 | ⬜ pending | +| 04-05-04 | 05 | 3 | D-19 | — | openapi | `bun test test/http/openapi-contract.test.ts` | ✅ | ⬜ pending | +| 04-05-05 | 05 | 3 | D-17, D-18 | — | doc+grep | `grep -v '^#' docs/internal/service-operator-golden-path.md \| grep -c 'failureClass'` | ❌ W0 | ⬜ pending | + +### Plan 06 — failure taxonomy multi-surface (S6) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-06-01 | 06 | 4 | D-17 | — | http | `bun test test/http/transition-error-failure-class.test.ts` | ❌ W0 | ⬜ pending | +| 04-06-02 | 06 | 4 | D-17, D-18 | T-04-06-02 | sdk | `bun test test/sdk/role-clients-failure-class.test.ts` | ❌ W0 | ⬜ pending | +| 04-06-03 | 06 | 4 | D-17, D-20 | T-04-06-03 | sdk | `bun test test/sdk/role-clients-failure-class.test.ts` | ❌ W0 | ⬜ pending | +| 04-06-04 | 06 | 4 | D-17, D-19 | T-04-06-01 | mcp | `bun test test/mcp/mcp-failure-class-parity.test.ts test/mcp/mcp-x402-proposal.test.ts` | ❌ W0 | ⬜ pending | + +### Plan 07 — tier-1 integrator platform (S7) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-07-01 | 07 | 4 | D-15 | T-04-07-02 | architecture | `bun test test/architecture/integrator-tier-1-parity.test.ts` | ❌ W0 | ⬜ pending | +| 04-07-02 | 07 | 4 | D-15, D-07, D-08 | — | doc+grep | `grep -v '^#' docs/internal/integrator-tier-1-transitions.md \| grep -c 'first 30 minutes'` | ❌ W0 | ⬜ pending | +| 04-07-03 | 07 | 4 | D-15 | T-04-07-02 | architecture | `bun test test/architecture/integrator-tier-1-parity.test.ts` | ❌ W0 | ⬜ pending | +| 04-07-04 | 07 | 4 | D-16 | T-04-07-01 | sdk | `bun test test/sdk/role-clients-walkthrough.test.ts` | ❌ W0 | ⬜ pending | + +### Plan 08 — HTTP profile adapter platform (S8) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-08-01 | 08 | 5 | D-10, D-11 | T-04-08-02 | adapter | `bun test test/adapters/http-profile-canonicalization.test.ts` | ❌ W0 | ⬜ pending | +| 04-08-02 | 08 | 5 | D-11 | — | adapter | `bun test test/adapters/http-profile-canonicalization.test.ts test/adapters/x402-bypass-probes.test.ts` | ✅ | ⬜ pending | +| 04-08-03 | 08 | 5 | D-10, D-12 | T-04-08-01 | adapter | `bun test test/adapters/http-profile-canonicalization.test.ts` | ❌ W0 | ⬜ pending | +| 04-08-04 | 08 | 5 | D-08, D-10 | T-04-08-03 | adapter | `bun test test/adapters/http-profile-orphan-catalog.test.ts` | ❌ W0 | ⬜ pending | +| 04-08-05 | 08 | 5 | D-10 | T-04-08-02 | adapter | `bun test test/adapters/http-profile-canonicalization.test.ts` | ❌ W0 | ⬜ pending | + +### Plan 09 — proof-gap honesty (S9) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-09-01 | 09 | 6 | D-14, D-13 | T-04-09-01 | doc+grep | `grep -q 'Proof-gap' docs/internal/service-operator-golden-path.md && ! test -d examples/auth-md-protected-api-stub` | ❌ W0 | ⬜ pending | +| 04-09-02 | 09 | 6 | D-14, D-13 | T-04-09-01 | architecture | `bun test test/architecture/proof-gap-honesty.test.ts` | ❌ W0 | ⬜ pending | +| 04-09-03 | 09 | 6 | D-00, D-12 | T-04-09-02 | doc+grep | `grep -v '^#' examples/external-adapter-sdk/README.md \| grep -c 'run\*Gateway'` | ✅ extend | ⬜ pending | +| 04-09-04 | 09 | 6 | D-14 | — | doc+grep | `grep -v '^#' docs/internal/integrator-tier-1-transitions.md \| grep -c 'runnable'` | ❌ W0 | ⬜ pending | + +### Plan 10 — custody bilateral operations (S10) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-10-01 | 10 | 6 | D-21 | T-04-10-02 | architecture | `bun test test/architecture/custody-matrix-parity.test.ts` | ❌ W0 | ⬜ pending | +| 04-10-02 | 10 | 6 | D-22 | — | doc+grep | `grep -v '^#' docs/internal/service-operator-golden-path.md \| grep -c 'Bilateral' && ! test -f docs/internal/service-operator-runbook.md` | ❌ W0 | ⬜ pending | +| 04-10-03 | 10 | 6 | D-23 | T-04-10-01 | cli | `bun test test/cli/cli-mcp-doctor.test.ts` | ✅ | ⬜ pending | +| 04-10-04 | 10 | 6 | D-21, D-22 | T-04-10-02 | architecture | `bun test test/architecture/custody-matrix-parity.test.ts` | ❌ W0 | ⬜ pending | + +### Plan 11 — bypass enforcement minimal (S11) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-11-01 | 11 | 7 | D-24 | T-04-11-01 | architecture | `bun test test/architecture/http-handler-mutation-gating.test.ts` | ❌ W0 | ⬜ pending | + +### Plan 12 — operator E2E verification (S12) + +| Task ID | Plan | Wave | Requirement | Threat Ref | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------|-------------------|-------------|--------| +| 04-12-01 | 12 | 8 | D-13, D-08 | T-04-12-02 | integration | `bun test test/integration/service-operator-golden-path.test.ts` | ❌ W0 | ⬜ pending | +| 04-12-02 | 12 | 8 | D-24, D-25 | T-04-12-01 | architecture | `bun test test/architecture/operator-product-completion-contract.test.ts` | ❌ W0 | ⬜ pending | +| 04-12-03 | 12 | 8 | D-00, D-24 | T-04-12-01 | script | `node scripts/check-service-agent-gating-phase.mjs --tier operator` | ❌ W0 | ⬜ pending | +| 04-12-04 | 12 | 8 | D-00–D-25 | T-04-12-03 | doc+grep | `grep -v '^#' .planning/phases/04-service-agent-gating/04-VERIFICATION.md \| grep -c 'operator tier'` | ❌ W0 | ⬜ pending | + +*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky* + +--- + +## Wave 0 Requirements (new test files — create during first owning task) + +> Post product/user audit (2026-05-28): stub example dirs, standalone runbooks, manifest module, and conformance expansion are **not** Wave 0 for phase 04 — see [04-PLANS-INDEX.md](./04-PLANS-INDEX.md) deferred table. + +- [ ] `test/architecture/dual-enforcement-posture.test.ts` +- [ ] `test/architecture/integrator-tier-1-parity.test.ts` +- [ ] `test/http/transition-error-failure-class.test.ts` +- [ ] `test/sdk/role-clients-failure-class.test.ts` +- [ ] `test/sdk/role-clients-walkthrough.test.ts` +- [ ] `test/mcp/mcp-failure-class-parity.test.ts` +- [ ] `test/adapters/http-profile-canonicalization.test.ts` +- [ ] `test/adapters/http-profile-orphan-catalog.test.ts` +- [ ] `test/architecture/proof-gap-honesty.test.ts` +- [ ] `test/architecture/custody-matrix-parity.test.ts` +- [ ] `test/architecture/http-handler-mutation-gating.test.ts` +- [ ] `test/product/service-operator-bootstrap.test.ts` +- [ ] `test/cli/cli-agent-spine-sequencer.test.ts` +- [ ] `test/integration/service-operator-golden-path.test.ts` +- [ ] `test/architecture/operator-product-completion-contract.test.ts` +- [ ] `scripts/check-service-agent-gating-phase.mjs` +- [ ] `docs/internal/service-operator-golden-path.md` +- [ ] `docs/internal/integrator-tier-1-transitions.md` +- [ ] `src/adapters/http-profile/` (module) +- [ ] `src/protocol/foundation/failure-class.ts` +- [ ] `src/cli/service/bootstrap.ts` +- [ ] `src/cli/quickstart/agent-spine.ts` +- [ ] `examples/service-operator-bootstrap/` +- [ ] `examples/service-operator-golden-path/` + +**Deferred to phase 05 (not Wave 0 here):** `service-mutation-route-manifest`, `http-profile-adapter-conformance`, maintainer completion contract expansion. + +**Eliminated (audit):** `proof-gap-recipe-stub.test.ts`, stub example dirs, standalone `service-operator-runbook.md` / `host-operator-runbook.md`. + +--- + +## Manual-Only Verifications + +| Behavior | Requirement | Why Manual | Test Instructions | +|----------|-------------|------------|-------------------| +| Operator golden path readability | D-05, D-13 | Doc sell-test | Read `service-operator-golden-path.md` for Clerk analogy and complete product chain | +| Bilateral setup operator walkthrough | D-22 | Human sequencing validation | Follow bilateral sections in golden path + host golden path (standalone runbooks post-execute) | + +--- + +## Validation Sign-Off + +- [x] All 48 tasks have `` verify or Wave 0 dependencies +- [x] Sampling continuity: no 3 consecutive tasks without automated verify +- [x] Wave 0 covers all MISSING test references +- [x] No watch-mode flags +- [x] Feedback latency < 30s (targeted bun test) +- [x] `nyquist_compliant: true` +- [x] Comprehensive 12-plan delivery (not MVP slice) + +**Approval:** approved 2026-05-28 (comprehensive replan) diff --git a/.planning/phases/04-service-agent-gating/04-VERIFICATION.md b/.planning/phases/04-service-agent-gating/04-VERIFICATION.md new file mode 100644 index 0000000..fb1ac65 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/04-VERIFICATION.md @@ -0,0 +1,313 @@ +--- +phase: 04-service-agent-gating +verified: 2026-05-29T12:00:00Z +status: passed +score: 13/13 +overrides_applied: 0 +note: >- + Frontmatter reconciled by orchestrator after the post-verification regression + cleanup + guard-fix passes (final code HEAD c7bba7e; re-verified tsc 0, + bun test 794 pass / 3 fail, tier gates 10/10 + 15/15). The original verifier + frontmatter (passed-with-gaps, 35 failures, 91 tsc errors) predated cleanup + and is preserved in the body's "Independent Verifier Findings" section as the + pre-cleanup snapshot. See "Regression cleanup" + "Revised status" below and + 04-REGRESSION-TRUTH.md for empirical ground truth. +gaps: + - truth: "MCP Registry discoverability verified" + status: partial + reason: "Documented external proof gap in AGENTS.md; not faked green. Closable only on registry acceptance + lookup verification (not a Phase 04 regression)." + missing: + - "Registry acceptance and lookup verification when channel is live" + - truth: "Every consequential route adapter-wrapped (full inventory)" + status: partial + reason: "D-25 manifest honestly deferred to Phase 05; D-24 structural gating limited to handler allowlist + adapter-gated example runners (not a Phase 04 regression)." + missing: + - "service-mutation-route-manifest module and inventory gate" + - truth: "Whole-repo manifest coverage (every export mapped)" + status: partial + reason: "Pre-existing at baseline 1e801b7 (failed before Phase 04). ./hosted-admission + ./surfaces/service-workflow-admission export mapping. Not a Phase 04 regression; carried to Phase 05." + missing: + - "Map ./hosted-admission and ./surfaces/service-workflow-admission to manifest surfaces" +deferred: + - truth: "Service mutation route manifest enforcement" + addressed_in: "Phase 05" + evidence: "04-CONTEXT.md D-25; http-handler-mutation-gating.test.ts comment lines 6-8" + - truth: "Whole-repo manifest export coverage" + addressed_in: "Phase 05" + evidence: "Pre-existing baseline gap; 04-REGRESSION-TRUTH.md section C" +health_reverified: + tsc_errors: 0 + bun_test: "794 pass / 3 fail (2 environmental gitignored-file fragility, 1 pre-existing manifest-coverage)" + tier_operator: "10/10" + tier_full: "15/15" + baseline_comparison: "baseline-or-better (baseline 1e801b7: 3 tsc errors, 22 test failures)" +human_verification: [] +--- + +# Phase 04 verification — service-operator dual-enforcement gating + +## Executor verification (preserved) + +Two-tier sign-off: **operator tier** (TTHW / service-operator ship) and **full tier** +(maintainer completeness). Manifest-based mutation inventory remains deferred to Phase 05. + +### Operator tier success + +Service operators can: + +1. Follow [service-operator-golden-path.md](../../docs/internal/service-operator-golden-path.md) with Step 3 fork, Branch A bootstrap, proof-gap honesty, and failureClass table. +2. Run `handshake service bootstrap` (or `examples/service-operator-bootstrap/run.ts`) with idempotent compiled-records registration. +3. Read bilateral setup order in golden paths without standalone runbook files. +4. Use doctor attestation output (host + MCP) as binding digest evidence only — not authority. +5. Rely on handler mutation gating architecture test for first-party HTTP read-only posture and adapter-gated example runners. + +Mechanical sign-off: + +```bash +node scripts/check-service-agent-gating-phase.mjs --tier operator +# or: npm run check:service-agent-gating-phase +``` + +### Maintainer tier success (additive) + +Everything in operator tier, plus: + +- Integrator Tier-1 transition parity and walkthrough tests +- HTTP profile canonicalization and orphan-catalog refusal tests +- SDK/MCP failureClass parity +- Maintainer product completion contract (manifest still absent) + +Mechanical sign-off: + +```bash +node scripts/check-service-agent-gating-phase.mjs --tier full +# or: npm run check:service-agent-gating-phase:full +``` + +### Subsystem checklist (S1–S12 → plans 01–12) + +| Subsystem | Plan | Operator tier | Full tier | +| --- | --- | --- | --- | +| Dual-lane doctrine | 01 | required | required | +| Golden path docs | 02 | required | required | +| Service bootstrap | 03 | required | required | +| Agent-spine CLI | 04 | optional convenience | required test if present | +| Failure taxonomy HTTP | 05 | required | required | +| SDK/MCP failureClass | 06 | required | required | +| Integrator Tier-1 | 07 | appendix exists | parity tests | +| HTTP profile platform | 08 | module exists | full adapter tests | +| Proof-gap honesty | 09 | required | required | +| Custody & bilateral ops | 10 | required | required | +| Handler mutation gating | 11 | required | required | +| Operator E2E gate | 12 | required | required | + +### Explicit non-goals (phase 04) + +- Kernel protocol changes or second runnable clearance path beyond buyer-side `x402_payment.exact` +- Stub example directories for auth.md or package-install proof-gap families +- Mandatory `handshake quickstart agent-spine` for operator sign-off +- `service-operator-runbook.md` / `host-operator-runbook.md` standalone files +- `service-mutation-route-manifest` module or registry sync script (Phase 05) +- Fake green gates for blocked proof surfaces (hosted operation, registry discoverability, marketplace trust) + +### Deferred to Phase 05 + +- Full mutation route manifest and `check-product-completion` inventory slice +- Standalone operator runbook extraction from golden path sections +- Complete [host-golden-paths-and-trace-guidance.md](../../docs/internal/host-golden-paths-and-trace-guidance.md) expansion beyond phase-04 stub pointer + +### Product user audit + +Applied patches from `04-PRODUCT-USER-AUDIT.md` (2026-05-28): no proof-gap stub packages, +bilateral sections in golden paths, two-tier phase gate, agent-spine optional on operator tier. + +**Executor frontmatter claim:** `status: passed` — independent audit finds gate contract met but repo-wide proof gaps remain (see below). + +--- + +## Independent Verifier Findings + +**Verified:** 2026-05-29 +**Branch:** phase-04-service-agent-gating @ 3db4730 (+ verifier fix pending commit) +**Verifier:** gsd-verifier (goal-backward, adversarial) + +### Phase goal (04-CONTEXT.md) + +Deliver a complete agent-first operator product for any-service agent gating — doctrine, runnable spine, atomic install, failure taxonomy, Tier-1 integrator platform, HTTP adapter platform, custody runbooks, and **structural bypass enforcement** — without weakening the kernel. x402 remains the only runnable clearance wedge. + +### Goal-decomposition checklist + +| ID | Deliverable / invariant / D-decision | Status | Evidence | +| --- | --- | --- | --- | +| G0 | Phase goal: agent-first operator product spine | **verified** | 15/15 phase gate; golden path + bootstrap integration tests | +| D-00 | Dual enforcement: admission + gateway; ingress-only advisory | **verified** | `service-operator-golden-path.md:20-31`; `dual-enforcement-posture.test.ts` | +| D-00b | x402 proof wedge, not payment-only product | **verified** | `dual-enforcement-posture.test.ts:60-72`; `proof-gap-honesty.test.ts` | +| D-01–D-06 | Vision→protocol mapping + dual-lane docs | **verified** | `claim-boundary.test.ts`; service-workflow story patterns in gate docs | +| D-07–D-08 | Progressive catalog triplet + atomic install; orphan refused | **verified** | `service-operator-bootstrap.test.ts`; `http-profile-orphan-catalog.test.ts:35-36` | +| D-09 | Full day-one envelope reserved (not default) | **verified** | Golden path progressive onboarding prose; bootstrap CLI scope | +| D-10–D-12 | HTTP profile hybrid; auth.md prototype; PEP optional | **verified** | `src/adapters/http-profile/`; `http-profile-canonicalization.test.ts` | +| D-13 | One runnable spine (x402 reference) | **verified** | `service-operator-golden-path.test.ts`; proof-gap honesty forbids second runnable paths | +| D-14 | Proof-gap stubs non-runnable | **verified** | `proof-gap-honesty.test.ts` forbids stub example dirs | +| D-15 | Tier-1 integrator transition parity | **verified** | `integrator-tier-1-parity.test.ts` (full tier) | +| D-16 | Recipe sequencer non-authority | **verified** | `cli-agent-spine-sequencer.test.ts:16-35` | +| D-17–D-20 | failureClass taxonomy + HTTP status discipline | **verified** | `failure-class.ts:51-55`; `transition-error-envelope.ts:102-124`; gate classifier tests | +| D-21–D-23 | Custody matrix + bilateral order + doctor attestation | **verified** | `custody-matrix-parity.test.ts` | +| D-24 | Structural bypass enforcement (not docs-only) | **partial** | Handler allowlist + example runners + conformance; no route manifest | +| D-25 | Launch bypass packets deferred | **verified (honest deferral)** | Explicit in CONTEXT + gate script comments | + +### Dual-enforcement structural finding (central claim) + +**Verdict: STRUCTURAL at the adapter enforcement boundary; PARTIAL at full-service route inventory.** + +Handshake enforcement for protected mutation is **not** admission-only. The structural chain is: + +1. **HTTP kernel surface is read-only** — all handlers under `src/http/handlers/` are allowlisted read/evidence routes; direct mutation patterns are forbidden (`http-handler-mutation-gating.test.ts:48-68`). + +2. **Example service mutation paths require `run*Gateway` before downstream effect** — `examples/x402-protected-spend/run.ts`, `examples/package-install-end-to-end/run.ts`, `examples/auth-md-protected-call/run.ts` must import/call `run*Gateway` (`http-handler-mutation-gating.test.ts:71-79`). + +3. **Adapter gateway functions gate before mutation** — e.g. `runX402WalletGateway` calls `protocol.gatewayCheck` and returns without signing/mutating when `verifiedGatewayCheckFromResult` fails (`src/adapters/x402-payment/wallet-gateway.ts:198-213`); same pattern in repo-write, package-install, preview-deploy, auth-md gateways. + +4. **Conformance contract rejects adapters that mutate without VerifiedGatewayCheck** — `checkProtectedMutationAdapterConformance` fails unsafe probes (`test/conformance/protected-mutation-adapter-conformance.test.ts:39-47`). + +**What is NOT yet structural:** inventory of every consequential HTTP route on an arbitrary integrator service (D-25 manifest deferred). Dual-enforcement posture test (`dual-enforcement-posture.test.ts`) validates **doctrine prose**, not runtime bypass of an unwrapped route. That gap is honestly deferred, not hidden. + +**Not advisory:** admission middleware alone cannot authorize mutation because first-party HTTP handlers do not mutate, and runnable demos route through adapter gateway checks. + +### Independent command results + +**Operator tier gate** — PASS (10/10): + +```text +node scripts/check-service-agent-gating-phase.mjs --tier operator +All 10 checks passed for tier operator. +``` + +**Full tier gate** — PASS (15/15): + +```text +node scripts/check-service-agent-gating-phase.mjs --tier full +All 15 checks passed for tier full. +``` + +**Full test suite** — NOT GREEN: + +```text +bun test → 745 pass, 35 fail, 780 tests (HEAD @ 3db4730) +baseline 1e801b7 → 704 pass, 18 fail, 722 tests +``` + +**TypeScript** — NOT CLEAN: + +```text +npx tsc --noEmit → 91 errors (HEAD) +baseline 1e801b7 → 3 errors +``` + +Primary ripple: `gatewayRegistryEntry: null` in orphan-catalog compiled records vs non-null types in fixtures (`test/sdk/role-clients.test.ts`, `test/support/x402-negotiation-fixture.ts`). + +### http.test.ts D-18 — pre-existing vs introduced + +| Case | Baseline `1e801b7` | HEAD before verifier fix | Assessment | +| --- | --- | --- | --- | +| Stale hosted identity | Expected 412 | Updated to 409 + `failureClass: stale_admission` (`http.test.ts:896-902`) | **Phase 04 intentional D-18 alignment** — passes | +| Recovery terminal conflict + proofRef | Expected 409; **passed** | Classifier returns 422 (`failure-class.ts:53-55`, `transition-error-envelope.ts:120-121`); integration still expected 409 | **Phase 04 introduced** — contradicts gate unit test | + +`04-DEVIATIONS.md` claim of "pre-existing" is **overstated** for recovery terminal conflict. Expired-identity case was resolved in phase; recovery conflict was classifier change without integration test update. + +**Verifier fix (iteration 1):** updated `http.test.ts` recovery conflict case to expect **422** + `failureClass: proof_gap` + `failurePhase: transition` (aligns with `transition-error-failure-class.test.ts:75-84`). Not committed per verifier no-commit rule for planning artifacts; test fix staged in working tree. + +### Coherence invariant spot-check + +| AGENTS.md / 04 invariant | Spot-check | Verdict | +| --- | --- | --- | +| No advisory-claimed-as-structural | Docs + tests state admission alone is advisory; enforcement at `run*Gateway` | **honest** | +| Greenlight is one-use | Gateway replay tests in x402 wallet gateway + MCP parity replay_refusal | **enforced in wedge tests** (not re-audited exhaustively) | +| Receipt distinguishes gateway check from downstream | `runX402WalletGateway` separates `gatewayCheck` outcome from `signatureEvidence` / reconciliation paths | **enforced in adapter spine** | +| Proof gaps recorded honestly | `proof-gap-honesty.test.ts`; MCP registry not faked; manifest deferred | **enforced** | + +### Executor claim cross-check + +| Executor claim | Independent result | +| --- | --- | +| 48/48 tasks, tier gates green | **Confirmed** — 10/10 operator, 15/15 full independently | +| `status: passed` in executor frontmatter | **Overstated** — phase gate passed; full suite + tsc + manifest/MCP gaps remain | +| http.test.ts deferral pre-existing | **Partially false** — recovery conflict is phase-introduced | + +### Fix iterations + +| # | Change | Commit | +| --- | --- | --- | +| 1 | Align `http.test.ts` recovery terminal conflict expectations with D-18 classifier (422 + proof_gap) | **not committed** (verifier policy: no commit) | + +### Final independent status + +**`passed-with-gaps`** + +Phase 04 achieves the operator/maintainer tier contract: dual-enforcement doctrine, runnable x402 bootstrap, failureClass taxonomy, Tier-1 parity, HTTP profile scaffolding, custody matrix, and adapter-level structural gating — all confirmed by independently re-run gates. + +Remaining gaps are documented honestly: MCP registry proof gap, deferred mutation-route manifest, 35 full-suite failures (+17 vs baseline), 91 TypeScript errors (+88 vs baseline), and doc-grep-only dual-enforcement posture for arbitrary services. + +### Open questions for orchestrator + +1. Should Phase 05 treat `tsc --noEmit` cleanliness as a hard gate, or remain bun-test-only? +2. Should the recovery-conflict http.test fix be committed as `fix(04-verify): align recovery conflict HTTP status with D-18` before merge? +3. Full-suite 35 failures include many repo-naming-posture and x402 integration tests — triage which are phase regressions vs intentional posture tightening. + +--- + +## Regression cleanup (orchestrator-adjudicated, post-verification) + +The verifier's open questions #1 and #3 were resolved by establishing empirical +ground truth: the full `bun test` suite was run at baseline `1e801b7` in an +isolated worktree and set-diffed against HEAD. See `04-REGRESSION-TRUTH.md`. + +**Finding:** the executor + first fixer mislabeled phase-introduced failures as +"pre-existing." Baseline had **22** failures; Phase 04 *fixed 19* but +*introduced 14*. Of the 17 remaining after the first tsc-fix pass, only 3 were +genuinely pre-existing; 12 were phase-introduced and fixable; 2 were +environmental (local gitignored `.DS_Store` / `.agents` absent in clean checkout). + +**Resolution (two Composer fix passes):** + +| Pass | Cleared | Commits | +| --- | --- | --- | +| tsc + test contracts | 91→0 tsc errors; 35→17 failures | `2a46970 920e38a 86e0758 401a866 3840c25 6b06c6a` + D-18 `06c6214` | +| naming + MCP + CLI evidence | 17→3 failures (all 12 phase-introduced cleared) | `2acddf1 bafc2ee a85f93b 738a34c 42b1fb3` | + +Notable doctrine fixes: renamed banned `src/cli/service` bucket → `service-operator`; +moved `failure-class.ts` into a subdir to clear the foundation loose-file threshold; +**renamed the D-15 "Tier 1" integrator concept → "integrator parity"** to honor the +AGENTS.md ban on planning-stage labels in repo-facing surfaces (behavioral contract +preserved; surface label only); realigned MCP reference transcript + import roots + +CLI evidence surface to the Phase 04 failureClass taxonomy. No `as any`, no +test-weakening, no D-decision violations. + +### Corrected final health (independently re-verified at `42b1fb3`) + +| Metric | Baseline `1e801b7` | Final `42b1fb3` | Verdict | +| --- | --- | --- | --- | +| `npx tsc --noEmit` | 3 errors | **0 errors** | better | +| `bun test` | 22 fail | **3 fail** | much better | +| Tier operator | — | **10/10 PASS** | green | +| Tier full | — | **15/15 PASS** | green | + +The 3 residual failures are NOT phase regressions: +- `repo naming posture > keeps workspace metadata junk` — local `.DS_Store` (absent in clean CI checkout). +- `repo naming posture > keeps deleted scratch documents` — local `.agents/` + `skills-lock.json` gstack install (gitignored; absent in clean CI checkout). +- `manifest coverage > maps each product surface export …` — **pre-existing** (failed at baseline); deferred to Phase 05 (`./hosted-admission`, `./surfaces/service-workflow-admission` export mapping). + +In a clean CI checkout the first two do not exist, leaving the single pre-existing +manifest-coverage gap — honestly carried into Phase 05. + +### Revised status + +**`passed`** for the Phase 04 goal and health bar (baseline-or-better on tsc and +tests; both tier gates green). One pre-existing manifest-coverage gap and the +MCP-Registry proof gap remain documented and deferred to Phase 05 — neither is a +Phase 04 regression. + +--- + +_Verified: 2026-05-29_ +_Verifier: gsd-verifier (independent goal-backward audit)_ +_Regression truth + cleanup adjudication: orchestrator, 2026-05-29_ diff --git a/.planning/phases/04-service-agent-gating/PATTERNS.md b/.planning/phases/04-service-agent-gating/PATTERNS.md new file mode 100644 index 0000000..8afe319 --- /dev/null +++ b/.planning/phases/04-service-agent-gating/PATTERNS.md @@ -0,0 +1,1046 @@ +# Phase 04: Service Agent Gating — Pattern Map + +**Mapped:** 2026-05-28 +**Files analyzed:** 28 new/modified (inferred from `04-CONTEXT.md`) +**Analogs found:** 24 / 28 + +## File Classification + +| New/Modified File | Role | Data Flow | Closest Analog | Match Quality | +|-------------------|------|-----------|----------------|---------------| +| `docs/internal/service-workflow-story.md` (agent lane extension) | config | transform | `docs/internal/service-workflow-story.md` | exact | +| `docs/internal/protocol-layman.md` (product vocabulary chain) | config | transform | `docs/internal/protocol-layman.md` | exact | +| `docs/internal/decisions.md` (custody matrix, dual enforcement) | config | transform | `docs/internal/decisions.md` | exact | +| `docs/internal/host-golden-paths-and-trace-guidance.md` (bilateral runbooks) | config | transform | `docs/internal/host-golden-paths-and-trace-guidance.md` | exact | +| `src/http/errors/transition-error-envelope.ts` (`failureClass` / `phase`) | middleware | request-response | `src/http/errors/transition-error-envelope.ts` | exact | +| `src/protocol/foundation/reason-codes.ts` (auth vs execution-control codes) | model | transform | `src/protocol/foundation/reason-codes.ts` | exact | +| `src/protocol/foundation/reason-code-remediation/index.ts` | utility | transform | same file | exact | +| `test/architecture/service-agent-gating-boundary.test.ts` (new) | test | batch | `test/architecture/workflow-admission-boundary.test.ts` | role-match | +| `test/architecture/claim-boundary.test.ts` (dual enforcement claims) | test | batch | same file | exact | +| `test/architecture/host-trusted-binding-parity.test.ts` (extend parity rows) | test | batch | same file | exact | +| `src/adapters/http-transport-profile/` (new hybrid layer) | service | request-response | `src/adapters/auth-md/gateway.ts` + `action-proposal.ts` | role-match | +| `src/adapters/auth-md/*` (HTTP profile prototype docs/tests) | adapter | request-response | `src/adapters/auth-md/gateway.ts` | exact | +| `src/adapters/x402-payment/*` (runnable wedge reference) | adapter | request-response | `src/adapters/x402-payment/wallet-gateway.ts` | exact | +| `src/adapters/package-install/*` (proof-gap stub only) | adapter | request-response | `src/adapters/package-install/gateway.ts` | exact | +| `src/cli/quickstart/agent-gating.ts` or extend `quickstart/x402.ts` | hook | batch | `src/cli/quickstart/x402.ts` | role-match | +| `src/cli/simulate/agent-gating.ts` or extend simulate | hook | request-response | `src/cli/simulate/x402-payment.ts` | exact | +| `src/cli/host/doctor.ts` (attestation framing) | hook | request-response | same file | exact | +| `src/cli/command-manifest.ts` (new commands) | config | transform | same file | exact | +| `src/install/install-proposal/index.ts` | model | CRUD | same file | exact | +| `src/adapters/*/install-proposal.ts` (per-family atomic install) | service | batch | `src/adapters/x402-payment/install-proposal.ts` | exact | +| `src/protocol/navigation/index.ts` (Tier-1 integrator subset) | config | transform | same file | exact | +| `src/surfaces/service-workflow-admission/index.ts` (agent projections) | service | event-driven | same file | exact | +| `src/surfaces/service-agent-acceptance.ts` (new matrix, optional) | service | transform | `src/surfaces/x402-protected-tool-acceptance.ts` | role-match | +| `src/sdk/recipe/` or `cli/quickstart/` recipe sequencer | utility | batch | `src/cli/quickstart/x402.ts` + role clients | partial | +| `src/sdk/surface-clients/*.ts` (Tier-1 recipe consumers) | service | request-response | `src/sdk/surface-clients/` | exact | +| `examples/service-workflow-admission/run.ts` (agent golden path) | hook | batch | same file | exact | +| `examples/agent-gating-x402/` (new runnable spine, optional) | hook | batch | `examples/service-workflow-admission/run.ts` | role-match | +| Conformance-gated service scaffold (new) | test | batch | `test/architecture/workflow-admission-boundary.test.ts` repo walk | partial | + +--- + +## Pattern Assignments + +### `docs/internal/service-workflow-story.md` — dual-lane agent extension (config, transform) + +**Analog:** `docs/internal/service-workflow-story.md` + +**Plain-flow + mapping table pattern** (lines 7–25): + +```markdown +## Plain Flow + +```text +Agent shows Passport +-> Service returns ServiceWorkflowAdmission +-> Agent carries ServiceWorkflowHandle +-> Agent requests Clearance for one protected action +-> Handshake records Outcome +``` + +| Plain word | Meaning | Not allowed to mean | +| ------------------------ | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | +| Passport | Evidence package the agent presents. | Identity, trust, permission, spend approval, signer access, or reusable auth. | +``` + +**Non-authority flag block** (lines 44–53) — copy verbatim structure for every new projection: + +```text +createsAuthority: false +createsPolicyDecision: false +createsGreenlight: false +performsGatewayCheck: false +permitsMutation: false +exportsReceipt: false +mintsTerminalCertificate: false +freshActionContractRequired: true +``` + +**Protected action boundary** (lines 87–104) — use for dual enforcement (admission ≠ gateway): + +```text +Every consequential event still needs: + +CandidateAction +-> ActionContract +-> PolicyDecision +-> one-use Greenlight or Refusal +-> GatewayCheck before mutation +-> Receipt / Refusal / ReplayRefusal / ProofGap / AuthorityCertificate + +If the gateway cannot enforce the exact greenlight before consequence, the path +is advisory, not Handshake. +``` + +**Phase 04 addition pattern:** Add a parallel **agent lane** section mapping product vocabulary (Standing Bounds → Delegated Mandate → Compile → Work Order → Clearance → Outcome) to schema-native names without renaming exports. + +--- + +### `docs/internal/protocol-layman.md` — product vocabulary (config, transform) + +**Analog:** `docs/internal/protocol-layman.md` + +**Service workflow surface intro** (lines 32–69): + +```markdown +## The Service Workflow Surface + +The simple service-facing story is: + +```text +Show Passport +-> ServiceWorkflowAdmission +-> ServiceWorkflowHandle +-> Request Clearance +-> Read Outcome +``` + +That story hides protocol detail from the user. It does not hide authority. +``` + +**Work order forcing pattern** (lines 104–130): + +```markdown +Handshake forces the agent to produce the exact work order: + +```text +action: x402_payment.exact +... +``` + +That exact work order is the action contract. +``` + +**Gate enforcement prose** (lines 149–163): + +```markdown +If the gateway cannot block the change, Handshake can observe or record, but it +cannot protect that path. +``` + +Copy this section shape when documenting **any-service** agent gating: plain chain first, then explicit “does not mean permission” bullets, then gateway-as-enforcement-point. + +--- + +### `docs/internal/decisions.md` — custody matrix & dual enforcement (config, transform) + +**Analog:** `docs/internal/decisions.md` + +**Role-scoped client definition** (lines 48–54 area): + +```markdown +- `role-scoped protocol transition client`: an SDK or HTTP client that transports a specific kernel transition under custody. It is not a product authority surface and does not make product nouns authoritative. +``` + +**Production acceptance matrix pattern** (lines 1063–1122): + +```text +package install +-> init / doctor +-> install x402-payment +-> local probes +-> register x402 gateway readiness +-> install health +-> host profile generation +-> protected tool proposal +-> policy decision +-> gateway check before signer use +-> redacted readback/support evidence +``` + +Each `InstallClient` / `PolicyClient` / `GatewayClient` paragraph names **what the client may transport** and a hard **cannot** list. Phase 04 should extend with **configured-by** columns (service operator vs host operator) using the same row structure as `x402ProtectedToolAcceptanceMatrix` fields: `surfaceOwner`, `authorityPosture`, `proofGaps`, `stopCondition`. + +--- + +### `docs/internal/host-golden-paths-and-trace-guidance.md` — bilateral runbooks (config, transform) + +**Analog:** `docs/internal/host-golden-paths-and-trace-guidance.md` + +**Golden path rule** (lines 7–26): + +```text +host tool config +-> Handshake MCP proposal tool +-> exact x402 proposal input +-> local readiness/proposal projection +-> redacted evidence/readback +``` + +**Non-claims list** (lines 19–26): + +```markdown +- no live host config mutation by Handshake; +- no native host behavior certification; +- no host-wide containment; +... +``` + +**Doctor command posture** (lines 38–42): + +```bash +handshake host doctor --host codex +handshake mcp doctor --stdio +handshake state inspect --cwd . +``` + +Extend with paired **service-operator** setup order (catalog triplet → gateway registry → policy pack) mirroring host sections per host alias. + +--- + +### `src/http/errors/transition-error-envelope.ts` — public failure taxonomy (middleware, request-response) + +**Analog:** `src/http/errors/transition-error-envelope.ts` + +**Schema extension point** (lines 32–45): + +```typescript +export const TransitionErrorEnvelopeSchema = z.strictObject({ + code: z.string(), + message: z.string(), + transitionName: z.string().nullable(), + callerCustodyRole: z.enum(["control_plane", "runtime_evidence", "gateway_custody", "review_custody"]).nullable(), + retryability: TransitionErrorRetryabilitySchema, + commitState: TransitionCommitStateSchema, + requestIdentity: z.string().nullable(), + proofRef: z.string().nullable(), + refusalRef: z.string().nullable(), + docUrl: z.string().url().nullable().optional(), + remediation: ReasonCodeRemediationSchema.optional(), + issues: z.array(JsonValueSchema).optional(), +}); +``` + +**Classification + HTTP status** (lines 65–84, 102–131): + +```typescript +export function transitionErrorResult(error: unknown, context: TransitionErrorContext = {}): TransitionErrorResult { + const classification = classifyTransitionError(error); + const body = TransitionErrorResponseSchema.parse({ + error: { + code: classification.code, + ... + remediation: classification.remediation, + }, + }); + return { body, status: classification.status }; +} + +if (error instanceof HandshakeProtocolError) { + return { + code: error.code, + message: error.message, + status: error.status, + ... + remediation: remediationForReasonCode(error.code), + }; +} +``` + +**Phase 04 pattern:** Add `failureClass` (`auth` | `hosted_admission` | `protected_action_refusal` | `proof_gap` | `replay_refusal` | `stale_admission`) and `phase` to the schema; map in `classifyTransitionError` with **401/403** only for credential/identity, **409** for refusals/replay/stale binding, **422** for proof gaps (D-17–D-19). Wire RFC 9457 `type` URI into `docUrl` or a new optional field alongside existing `remediation.docsUrl`. + +--- + +### `src/protocol/foundation/reason-code-remediation/index.ts` — remediation on failures (utility, transform) + +**Analog:** `src/protocol/foundation/reason-code-remediation/index.ts` + +**Exact remediation registry** (lines 50–62, 69–82): + +```typescript +export const ReasonCodeRemediationSchema = z.strictObject({ + code: z.string().min(1), + summary: z.string().min(1), + ownerSurface: ReasonCodeRemediationOwnerSurfaceSchema, + supportSeverity: ReasonCodeRemediationSupportSeveritySchema, + safeRetry: ReasonCodeRemediationSafeRetrySchema, + nextMechanism: ReasonCodeRemediationNextMechanismSchema, + nextCommand: z.string().min(1).nullable(), + docsUrl: z.string().url(), + requiresNewContract: z.boolean(), + parameterRepair: z.string().min(1).nullable(), + forbiddenActions: z.array(z.string().min(1)).default([]), +}); + +const exactRemediations = new Map([ + [ + "cli_command_unsupported", + { + summary: "The CLI command is not part of the active Handshake command manifest.", + ownerSurface: "cli", + ... + forbiddenActions: ["do_not_infer_hidden_cli_mutation_commands"], + }, + ], +``` + +**Lookup chain** (lines 367–385): + +```typescript +export function remediationForReasonCode(code: string): ReasonCodeRemediation { + const exact = exactRemediations.get(code); + if (exact) return parseRemediation(code, exact); + const registered = protocolReasonCodes.find((entry) => entry.code === code); + if (registered) return parseRemediation(code, genericProtocolRemediation(registered)); + const prefixed = protocolReasonCodePrefixes.find((entry) => code.startsWith(entry.prefix)); + ... +} +``` + +Add exact entries for new auth vs execution-control reason codes; set `requiresNewContract: true` and `forbiddenActions` for replay/stale admission cases. + +--- + +### `test/architecture/workflow-admission-boundary.test.ts` — admission non-authority (test, batch) + +**Analog:** `test/architecture/workflow-admission-boundary.test.ts` + +**Schema boundary assertion** (lines 46–57): + +```typescript +it("defines admission and handle as explicit non-authority surfaces", () => { + const admission = ServiceWorkflowAdmissionSchema.parse(validAdmission()); + + expect(admission.authorityBoundary).toEqual(serviceWorkflowNonAuthorityBoundary()); + expect(admission.nextActionRequirement).toBe("fresh_action_contract_required"); + expect(admission.clearanceBoundary).toBe("fresh_action_contract_required_for_each_protected_action"); +}); +``` + +**Forbidden authority field rejection** (lines 89–99): + +```typescript +for (const authorityField of [ + "policyDecisionRef", + "greenlightRef", + "gatewayCheckRef", + ... +]) { + expect(ServiceWorkflowContextRefsSchema.safeParse({ ...contextRefs, [authorityField]: "x" }).success).toBe(false); +} +``` + +**Repo walk — keep nouns out of authority roots** (lines 284–298): + +```typescript +it("keeps workflow admission nouns out of authority-bearing source roots", () => { + const violations: string[] = []; + for (const root of forbiddenAuthorityRoots) { + for (const file of walkTs(root)) { + const text = readFileSync(file, "utf8"); + for (const name of workflowSurfaceNames) { + if (text.includes(name)) violations.push(`${relative(process.cwd(), file)} mentions ${name}`); + } + } + } + expect(violations.sort()).toEqual([]); +}); +``` + +**Phase 04 bypass test pattern:** Clone the repo-walk helper (`walkTs`, `forbiddenAuthorityRoots`) to assert every consequential HTTP route in a **conformance scaffold** imports an adapter `run*Gateway` (D-24), not middleware-only auth. + +--- + +### `test/architecture/claim-boundary.test.ts` — doc/export claim matrix (test, batch) + +**Analog:** `test/architecture/claim-boundary.test.ts` + +**Claim matrix helper** (lines 17–45): + +```typescript +type ClaimMatrixEntry = { + label: string; + sources: ClaimSource[]; + required?: string[]; + requiredPatterns?: RegExp[]; + forbiddenPatterns?: RegExp[]; +}; + +function expectClaimMatrix(entries: ClaimMatrixEntry[]) { + for (const entry of entries) { + for (const source of entry.sources) { + for (const phrase of entry.required ?? []) { + expect(normalizedSource).toContain(normalizeRequiredClaim(phrase)); + } + for (const pattern of entry.forbiddenPatterns ?? []) { + expect(source.text).not.toMatch(pattern); + } + } + } +} +``` + +**Export boundary check** (lines 48–91): + +```typescript +it("keeps public entrypoints separated by authority boundary", async () => { + const root = await import("../../src"); + ... + expect(Object.keys(root)).not.toContain("proposeRuntimeIngressActionContracts"); + expect(adapterSdkExportNames.join(" ")).not.toMatch( + /GatewayCheck|Greenlight|Mutation|PolicyDecision|ReceiptExport/, + ); +}); +``` + +Add entries requiring dual enforcement language (“admission alone is not Handshake”, “gateway check before mutation”) in agent-facing docs; forbid “ingress equals protection” patterns. + +--- + +### `test/architecture/host-trusted-binding-parity.test.ts` — cross-surface parity (test, batch) + +**Analog:** `test/architecture/host-trusted-binding-parity.test.ts` + +**Parity row table** (lines 17–59): + +```typescript +const parityRows = [ + { + name: "complete binding", + input: completeBinding, + expectedReasonCodes: [] as string[], + }, + { + name: "readiness missing", + input: { ... }, + expectedReasonCodes: ["mcp_trusted_readiness_binding_missing"], + }, + ... +] as const; +``` + +**Classifier + MCP agreement** (lines 100–118): + +```typescript +for (const row of parityRows) { + it(`classifier, MCP, and runtime agree for ${row.name}`, async () => { + const classifier = classifyHostTrustedProposalBinding(row.input); + expect(sorted(classifier.reasonCodes)).toEqual(sorted(row.expectedReasonCodes)); + const mcpResult = await proposeMcpX402Payment(validProposalInput(), { ...row.input }); + ... + }); +} +``` + +Use the same row-driven pattern when adding service-side admission vs gateway reason-code parity for agent gating failures. + +--- + +### `src/adapters/auth-md/gateway.ts` — HTTP profile / family adapter gateway (adapter, request-response) + +**Analog:** `src/adapters/auth-md/gateway.ts` (also `package-install/gateway.ts` for slimmer variant) + +**Outcome union + protocol injection** (lines 75–117, 119–136): + +```typescript +export type AuthMdProtectedApiCallGatewayResult = + | { outcome: "gateway_check_refused"; gatewayCheck: GatewayCheckResult; ... } + | { outcome: "gateway_check_not_authoritative"; ... } + | { outcome: "protected_api_call_reconciled"; ... } + | { outcome: "protected_api_call_proof_gap"; ... } + | { outcome: "protected_api_call_failed"; ... }; + +export async function runAuthMdProtectedApiCallGateway( + input: AuthMdProtectedApiCallGatewayInput, +): Promise { + const observedParameters = AuthMdProtectedApiCallParametersSchema.parse(input.observedParameters); + const gatewayCheck = await input.protocol.gatewayCheck({ ... }); + + const verifiedGate = verifiedGatewayCheckFromResult(gatewayCheck); + if (!verifiedGate) { + const outcome = + gatewayCheck.gateAttempt.gateDecision === "refused" ? "gateway_check_refused" : "gateway_check_not_authoritative"; + return { outcome, gatewayCheck, ... }; + } +``` + +**Post-gate mutation + reconcile** (lines 160–195): + +```typescript +const apiCallEvidence = AuthMdProtectedApiCallEvidenceSchema.parse( + await input.surface.executeProtectedApiCall(command), +); +const { reconciliation } = await input.protocol.reconcileSurfaceOperation({ + mutationAttemptId: verifiedGate.mutationAttemptId, + idempotencyKey: verifiedGate.idempotencyKey, + observedSurfaceOperationRef: apiCallEvidence.surfaceOperationRef, + ... +}); +return { outcome: outcomeFor(apiCallEvidence.downstreamStatus), gatewayCheck, ... }; +``` + +**HTTP transport profile:** Canonicalize method, path template, allowlisted headers, body digest in parameters schema (see `AuthMdProtectedApiCallParametersSchema` in `action-proposal.ts`); family adapters add semantic fields on top (D-10, D-11). + +--- + +### `src/adapters/x402-payment/wallet-gateway.ts` — runnable wedge gateway (adapter, request-response) + +**Analog:** `src/adapters/x402-payment/wallet-gateway.ts` + +**Strict observed parameters** (lines 46–81): + +```typescript +export const X402PaymentParametersSchema = z.strictObject({ + endpointUrl: z.string().url(), + ... + gatewayCredentialRefId: z.string().min(1), + gatewayCredentialRefDigest: DigestSchema, + gatewayReadinessRef: z.string().min(1), + gatewayReadinessDigest: DigestSchema, + policyVersionRef: z.string().min(1), + policyVersionDigest: DigestSchema, +}); +``` + +**Command carries verified gate only** (lines 84–91): + +```typescript +export type X402PaymentSignatureCommand = { + verifiedGate: VerifiedGatewayCheck; + parameters: X402PaymentParameters; + credentialResolutionEvidence: CredentialResolutionEvidence; + ... +}; +``` + +Phase 04 runnable golden path should stay on this adapter; do not generalize payment semantics into the HTTP profile layer. + +--- + +### `src/adapters/package-install/gateway.ts` — proof-gap stub gateway (adapter, request-response) + +**Analog:** `src/adapters/package-install/gateway.ts` + +**Simpler gateway without credential resolution** (lines 100–117): + +```typescript +export async function runPackageInstallGateway( + input: PackageInstallGatewayInput, +): Promise { + const gatewayCheck = await input.protocol.gatewayCheck({ ... }); + const verifiedGate = verifiedGatewayCheckFromResult(gatewayCheck); + if (!verifiedGate) { + const outcome = + gatewayCheck.gateAttempt.gateDecision === "refused" ? "gateway_check_refused" : "gateway_check_not_authoritative"; + return { outcome, gatewayCheck, reconciliation: null, mutationEvidence: null }; + } +``` + +Use for **non-runnable** recipe stubs (D-14): transition map + schema + explicit proof-gap boundaries only. + +--- + +### `src/adapters/*/adapter-pack.ts` — catalog triplet + bypass plan (service, batch) + +**Analog:** `src/adapters/x402-payment/install-proposal.ts` (adapter pack) + `src/adapters/package-install/adapter-pack.ts` + +**Adapter pack registration** (x402 lines 43–62): + +```typescript +export const x402PaymentExactAdapterPack = ProtectedActionAdapterPackSchema.parse({ + adapterPackId: "adapter_pack_x402_payment_exact", + actionFamily: "x402_payment.exact", + protectedSurfaceKind: "x402_payment", + parameterSchemaRef: "schema:x402-payment-exact-parameters:v1", + ... + bypassProbeKinds: requiredGatewayCheckedBypassProbeKinds satisfies BypassProbeKind[], + hostileFixtureRefs: [ "fixture:x402:raw-private-key-env", ... ], +}); +``` + +**Package-install pack** (`adapter-pack.ts` lines 19–41) shows second family with different `hostileFixtureRefs`. + +**Atomic install compile** (install-proposal lines 133–149): + +```typescript +export async function compileX402InstallProposal(inputValue: X402InstallProposalInput): Promise { + const input = X402InstallProposalInputSchema.parse(inputValue); + const refusalReasonCodes = refusalReasons(input, endpointDomain); + ... +} +``` + +D-07/D-08: Service registers catalog triplet per endpoint family via `InstallProposal` with `compiledRecords` or refuses atomically — copy `compileX402InstallProposal` refusal-first compile pattern for new families. + +--- + +### `src/adapters/auth-md/bypass-probes.ts` — structural bypass enforcement (service, batch) + +**Analog:** `src/adapters/auth-md/bypass-probes.ts` + +**Posture schema + probe specs** (lines 8–35): + +```typescript +export const AuthMdProtectedApiCallBypassPostureSchema = z.strictObject({ + credentialCustodyStatus: z.enum(["gateway_held", "runtime_exposed", "fixture_gateway_held", "unknown"]), + rawBearerPassthroughStatus: ReachabilityStatusSchema, + directHttpCallStatus: ReachabilityStatusSchema, + ... +}); + +const probeSpecs: AuthMdProbeSpec[] = [ + { + probeKind: "credential_custody", + evaluate(posture) { + if (posture.credentialCustodyStatus === "gateway_held") { + return { postureLabel: "prevented", evidenceDetails: ["credential_custody_gateway_held"] }; + } + ... + }, + }, +``` + +Wire new HTTP-profile bypass probes into `InstallProposal.bypassProbePlan` the same way x402 hostile fixtures attach to adapter packs. + +--- + +### `src/cli/quickstart/x402.ts` — recipe sequencer / golden path (hook, batch) + +**Analog:** `src/cli/quickstart/x402.ts` + +**Step envelope with explicit non-authority flags** (lines 23–35, 37–71): + +```typescript +type QuickstartX402Step = { + step: QuickstartX402StepId; + command: string; + ok: boolean; + nextAction: CliNextAction; + reasonCodes: readonly string[]; + evidenceRefs: readonly string[]; + authorityCreated: false; + greenlightCreated: false; + gatewayCheckPerformed: false; + mutationAttempted: false; + credentialMaterialIncluded: false; +}; + +type QuickstartX402Result = { + schemaVersion: typeof QUICKSTART_X402_SCHEMA_VERSION; + ... + nonClaims: readonly string[]; +}; +``` + +**Orchestration:** Sequential CLI subcommand invocations (`demoX402Command`, `installX402PaymentCommand`, …) with dossier file writes. Phase 04 agent-first spine: catalog register → propose → policy → gateway → readback — keep the same literal `false` authority flags and `nonClaims` array (D-13, D-16). + +--- + +### `src/cli/simulate/x402-payment.ts` — non-authority simulation (hook, request-response) + +**Analog:** `src/cli/simulate/x402-payment.ts` + +**Simulated runtime client + proposal only** (lines 29–76): + +```typescript +export async function simulateX402PaymentCommand(input: { cwd: string; inputValue: unknown }) { + const simulation = simulatedRuntimeClient(); + const proposal = await proposeMcpX402Payment(input.inputValue, { + runtimeClient: simulation.client, + installPosture: simulationInstallPosture(readiness), + gatewayPosture: simulationGatewayPosture(readiness), + ... + }); + return cliOutput({ + command: "simulate x402-payment", + plane: "operator", + ok: outcome.outcome === "action_contract_proposed" && readiness.reasonCodes.length === 0, + warnings: [ + "Simulation is a local readiness and proposal projection only.", + "No durable protocol record, policy decision, greenlight, gateway check, ...", + ], + evidenceKind: "cli_diagnostic", + ... + }); +} +``` + +Use for Tier-1 transition rehearsal without bundling “execute” APIs. + +--- + +### `src/cli/host/doctor.ts` — host attestation evidence (hook, request-response) + +**Analog:** `src/cli/host/doctor.ts` + +**Attestation result shape** (lines 23–42): + +```typescript +type HostDoctorResult = { + schemaVersion: typeof HOST_DOCTOR_SCHEMA_VERSION; + evidenceKind: "cli_diagnostic"; + ... + liveHostVerificationStatus: "not_performed"; + localReadinessProofRequired: true; + hostWideContainmentClaimed: false; + authorityBoundary: typeof x402ProtectedToolHostProfileAuthorityBoundary; + proofGaps: readonly string[]; + nextCommands: readonly string[]; + nonClaims: readonly string[]; +}; +``` + +Frame doctor output as **attestation evidence** for binding digests (D-23), not parallel identity — mirror `profileDescriptor` + `installGuide` with `configMutationPerformedByDoctor: false`. + +--- + +### `src/cli/command-manifest.ts` — command registration (config, transform) + +**Analog:** `src/cli/command-manifest.ts` + +**Manifest entry shape** (lines 96–110, 187–211): + +```typescript +{ + id: "doctor", + aliases: ["doctor"], + status: "active", + plane: "operator", + custodyRole: "none", + ... + agentSafe: true, + redactionPosture: "manifest_only", + nonGoals: sharedNonGoals, +}, +{ + id: "quickstart.x402", + aliases: ["quickstart x402"], + ... + agentSafe: false, + nonGoals: [ + ...sharedNonGoals, + "live x402 operation", + "provider custody", + ... + ], +}, +``` + +New agent-gating / recipe commands must declare `custodyRole`, `nonGoals`, and `agentSafe` explicitly; add `firstUseExamples` block at file bottom (lines 452+). + +--- + +### `src/sdk/surface-clients/` — role-scoped clients (service, request-response) + +**Analog:** `src/sdk/surface-clients/transport.ts`, `install-client.ts`, `policy-client.ts`, `gateway-client.ts`, `runtime-client.ts`, `control-plane-client.ts` + +**Role-scoped transport** (transport.ts lines 15–29, 46–65): + +```typescript +export type RoleScopedTransportRole = Extract< + TransitionCallerRole, + "control_plane" | "gateway_custody" | "review_custody" | "runtime_evidence" +>; + +export class RoleScopedTransport { + private async request(method: "GET" | "POST", path: string, body?: unknown): Promise { + const headers: Record = { + [HANDSHAKE_PROTOCOL_VERSION_HEADER]: this.options.protocolVersion ?? PROTOCOL_VERSION, + [HANDSHAKE_REQUEST_IDENTITY_HEADER]: this.nextRequestIdentity(), + authorization: `Bearer ${this.options.roleCredential}`, + }; + ... + if (!response.ok) { + throw new HandshakeClientError(response.status, await this.errorEnvelopeForResponse(response)); + } +``` + +**InstallClient — atomic catalog commit** (install-client.ts lines 17–29): + +```typescript +export class InstallClient { + constructor(baseUrl: string, options: InstallClientOptions, fetchImpl?: HandshakeFetch) { + this.transport = new RoleScopedTransport(baseUrl, { ...options, role: "control_plane" }, fetchImpl); + } + + async registerInstallProposalCompiledRecords( + input: InstallProposal, + ): Promise { + const proposal = InstallProposalSchema.parse(input); + return this.transport.post("/v0.2/install-proposals/compiled-records", proposal); + } +} +``` + +**PolicyClient — authority boundary on return type** (policy-client.ts lines 8–22): + +```typescript +export type PolicyClientEvaluationResult = { + decision: PolicyDecision; + greenlight: Greenlight | null; + authorityCreated: boolean; + gatewayCheckPerformed: false; + mutationAttempted: false; + nextAction: "use_greenlight_at_gateway" | "read_evidence" | "request_review"; + ... +}; +``` + +**GatewayClient — gateway custody only** (gateway-client.ts lines 40–65): + +```typescript +export class GatewayClient { + constructor(baseUrl: string, options: GatewayClientOptions, fetchImpl?: HandshakeFetch) { + this.transport = new RoleScopedTransport(baseUrl, { ...options, role: "gateway_custody" }, fetchImpl); + } + gatewayCheck(input: GatewayCheckInput): Promise { + return this.transport.post("/v0.2/gateway-check-attempts", input); + } +} +``` + +**ControlPlaneClient — delegated mandate** (control-plane-client.ts lines 11–26): + +```typescript +export class ControlPlaneClient { + registerDelegatedAuthorityRef(input: RegisterDelegatedAuthorityRefInput): Promise { + return this.transport.post("/v0.2/delegated-authority-refs", input); + } + transitionDelegatedAuthorityStatus(input: TransitionDelegatedAuthorityStatusInput): Promise { + return this.transport.post("/v0.2/delegated-authority-status-transitions", input); + } +} +``` + +Recipe sequencer (D-16) must compose these clients in order without adding a bundled execute API; parse errors via `HandshakeClientError` + `TransitionErrorEnvelope`. + +--- + +### `src/protocol/navigation/index.ts` — Tier-1 transition subset (config, transform) + +**Analog:** `src/protocol/navigation/index.ts` + +**Catalog + atomic install entries** (lines 124–146): + +```typescript +export const protocolNavigation = [ + catalogEntry("registerToolCapability", "tool_capability"), + catalogEntry("registerActionType", "action_type"), + catalogEntry("registerGatewayRegistryEntry", "gateway_registry_entry"), + catalogEntry("registerOperatingEnvelope", "operating_envelope"), + { + transitionId: "registerInstallProposalCompiledRecords", + kernelMethod: "registerInstallProposalCompiledRecords", + phase: "install_setup", + authorityBoundary: "install setup evidence only", + evidenceObligation: + "atomically register compiled setup records or refusal without issuing policy, greenlight, gate, credential, mutation, receipt, or certificate authority", + }, + { + transitionId: "compileIntent", + ... + authorityBoundary: "candidate evidence only", + }, +``` + +Tag Tier-1 integrator transitions (`compileIntent`, `proposeActionContract`, `evaluatePolicy`, `gatewayCheck`, readback routes) with a `tier: "integrator"` or document subset — do not remove full matrix entries (D-15). + +--- + +### `src/surfaces/service-workflow-admission/index.ts` — agent lane projections (service, event-driven) + +**Analog:** `src/surfaces/service-workflow-admission/index.ts` + +**Authority boundary schema** (lines 25–54): + +```typescript +export const ServiceWorkflowAuthorityBoundarySchema = ProofPacketNonAuthorityBoundarySchema.extend({ + permitsMutation: z.literal(false), + exportsReceipt: z.literal(false), + mintsTerminalCertificate: z.literal(false), + ... + freshActionContractRequired: z.literal(true), +}); + +export const serviceWorkflowAuthorityBoundary = { + createsAuthority: false, + ... + freshActionContractRequired: true, +} as const satisfies ServiceWorkflowAuthorityBoundary; +``` + +**PrincipalAgentLink — scoped evidence** (lines 66–99): + +```typescript +export const PrincipalAgentLinkSchema = z.strictObject({ + ... + allowedUse: z.literal("scoped_evidence_for_envelope_setup_and_readback_only"), +}); +``` + +Extend projections for Standing Bounds / Delegated Mandate **readback only** — map to `OperatingEnvelope` / `DelegatedAuthorityRef` without schema renames (D-01–D-05). + +--- + +### `src/surfaces/x402-protected-tool-acceptance.ts` — production acceptance matrix (service, transform) + +**Analog:** `src/surfaces/x402-protected-tool-acceptance.ts` + +**Matrix row shape** (lines 15–27, 49–63): + +```typescript +export type X402ProtectedToolAcceptanceStep = { + readonly id: string; + readonly label: string; + readonly surfaceOwner: string; + readonly authorityPosture: X402ProtectedToolAcceptanceAuthorityPosture; + readonly inputEvidence: readonly string[]; + readonly outputRecord: string; + readonly requiredNonAuthorityFlags: readonly string[]; + readonly bypassPosture: string; + readonly proofGaps: readonly string[]; + readonly validationGate: string; + readonly stopCondition: string; +}; + +export const x402ProtectedToolAcceptanceMatrix = [ + { + id: "package_install", + label: "Install published package", + surfaceOwner: "package.json, server.json, bin, package surface checks", + authorityPosture: "distribution_only", + ... + }, +``` + +Copy for **service-agent** acceptance rows with **configured-by** (`service_operator` | `host_operator`) in `surfaceOwner` or new field; keep `commonSurfaceNonAuthorityFlags` (lines 29–39). + +--- + +### `examples/service-workflow-admission/run.ts` — runnable dual-lane example (hook, batch) + +**Analog:** `examples/service-workflow-admission/run.ts` + +**Hosted admission + non-authority boundary** (lines 23–26, 28–76): + +```typescript +const authorityBoundary = serviceWorkflowNonAuthorityBoundary(); + +const hostedVerifier = createHostedCallerVerifierFromAdapter( + { providerKind: "oauth_oidc", async verify() { return { ... rawIdentityMaterialPersisted: false, ... }; } }, + { allowedProviderKinds: ["clerk", "oauth_oidc"], requireActiveOrganization: true }, +); +const hostedCallerIdentity = await hostedVerifier.verify({ ... requiredRole: "runtime_evidence", ... }); +``` + +**Output artifacts:** writes `latest.json` / `latest.md` under example output dir with explicit `authorityBoundary` on every record. Agent golden path example should chain: hosted admission → workflow handle → x402 proposal readback cross-ref (`x402OutputPath` pattern line 22). + +--- + +## Shared Patterns + +### Non-authority boundary object + +**Source:** `src/surfaces/service-workflow-admission/index.ts` (`serviceWorkflowAuthorityBoundary`) +**Apply to:** All agent-lane docs, CLI outputs, projections, recipe sequencer steps + +```typescript +export const serviceWorkflowAuthorityBoundary = { + createsAuthority: false, + createsPolicyDecision: false, + createsGreenlight: false, + performsGatewayCheck: false, + performsMutation: false, + permitsMutation: false, + exportsReceipt: false, + mintsTerminalCertificate: false, + freshActionContractRequired: true, +} as const; +``` + +### Gateway-before-mutation adapter spine + +**Source:** `src/adapters/auth-md/gateway.ts` (`runAuthMdProtectedApiCallGateway`) +**Apply to:** All family adapters and HTTP transport profile wrappers + +```typescript +const gatewayCheck = await input.protocol.gatewayCheck({ actionContractId, greenlightId, observedParameters, surfaceOperationRef }); +const verifiedGate = verifiedGatewayCheckFromResult(gatewayCheck); +if (!verifiedGate) { + return { outcome: gatewayCheck.gateAttempt.gateDecision === "refused" ? "gateway_check_refused" : "gateway_check_not_authoritative", ... }; +} +// only after verifiedGate: surface mutation + reconcileSurfaceOperation +``` + +### Role-scoped SDK custody + +**Source:** `src/sdk/surface-clients/transport.ts` +**Apply to:** All Tier-1 recipe steps — one credential role per client, no cross-role bundling + +```typescript +this.transport = new RoleScopedTransport(baseUrl, { ...options, role: "control_plane" }, fetchImpl); +// PolicyClient / InstallClient / ControlPlaneClient → control_plane +// RuntimeClient → runtime_evidence +// GatewayClient → gateway_custody +``` + +### Architecture test repo walk + +**Source:** `test/architecture/workflow-admission-boundary.test.ts` (`walkTs`, forbidden roots) +**Apply to:** Bypass enforcement (D-24), claim-boundary doc tests, scaffold conformance + +```typescript +for (const root of forbiddenAuthorityRoots) { + for (const file of walkTs(root)) { + const text = readFileSync(file, "utf8"); + // assert invariant + } +} +expect(violations.sort()).toEqual([]); +``` + +### CLI diagnostic output envelope + +**Source:** `src/cli/output.ts` (via quickstart/simulate) +**Apply to:** doctor, simulate, quickstart, recipe sequencer + +```typescript +return cliOutput({ + command: "...", + plane: "operator", + ok: boolean, + reasonCodes: [...], + evidenceKind: "cli_diagnostic", + warnings: ["... non-authority ..."], + result: { authorityCreated: false, greenlightCreated: false, gatewayCheckPerformed: false, ... }, +}); +``` + +--- + +## No Analog Found + +| File | Role | Data Flow | Reason | +|------|------|-----------|--------| +| `src/adapters/http-transport-profile/` (shared REST canonicalizer) | service | transform | No standalone generic HTTP profile module yet; auth-md is closest family prototype (D-10) | +| Conformance-gated **service scaffold** (every route adapter-wrapped) | test | batch | Bypass tests exist per adapter (`bypass-probes.ts`) but no generic service route inventory scaffold | +| `src/sdk/recipe/` unified sequencer | utility | batch | x402 quickstart orchestrates CLI only; no SDK-level multi-client recipe module | +| RFC 9457 Problem Details HTTP mapper | middleware | request-response | `transition-error-envelope` has remediation URLs; no separate `application/problem+json` handler yet | +| Product doc export aliases (`StandingBounds`, `DelegatedMandate`) | config | transform | Explicitly deferred in CONTEXT (schema names unchanged) | + +--- + +## Metadata + +**Analog search scope:** `docs/internal/`, `src/adapters/`, `src/cli/`, `src/sdk/surface-clients/`, `src/http/errors/`, `src/protocol/foundation/`, `src/protocol/navigation/`, `src/surfaces/`, `src/install/`, `test/architecture/`, `examples/service-workflow-admission/` +**Files scanned:** ~45 +**Pattern extraction date:** 2026-05-28 diff --git a/.planning/phases/05-product-coherence/05-KEEL-AUDIT.md b/.planning/phases/05-product-coherence/05-KEEL-AUDIT.md new file mode 100644 index 0000000..df16e60 --- /dev/null +++ b/.planning/phases/05-product-coherence/05-KEEL-AUDIT.md @@ -0,0 +1,102 @@ +# Phase 05 — Keel Integrity Audit + +> **Purpose (coherence invariant #6):** every claimed invariant has a *confirmed +> structural enforcement site* or an *honest proof-gap label*. No advisory claim +> is allowed where a structural site exists. Each row carries a `file:line` +> citation (D-70) and a D-63 enforcement label drawn from: +> `structural` · `architecture-test` · `runtime-test` · `advisory` · `proof-gap`. + +- **Phase:** 05-product-coherence +- **Closes:** D1 (custody), D3 (test promotion), D4 (sequence matrix), D5 (agent-origin graph) +- **Lands after:** 05-13 (custody must precede promotion — D-65) +- **Citations verified against tree at:** `feat(05-14)` matrix/promotion commit `f7fd1d6` + +Enforcement-label legend: + +| Label | Meaning | +|-------|---------| +| `structural` | The type system / kernel transition guard makes the violation unrepresentable or refused before consequence. | +| `architecture-test` | A `test/architecture/` guard pins the invariant; regression fails CI even if the structural site is reachable. | +| `runtime-test` | Behaviour pinned by a non-architecture test (adapter/protocol/integration). | +| `advisory` | Documentation / audit artifact only — no executable guard. | +| `proof-gap` | The invariant is *not* fully structurally enforced; the gap is recorded honestly rather than smoothed over. | + +--- + +## Table A — AGENTS.md core invariants (10) + +| # | Invariant | Enforcement site (`file:line`) | Label | Pinning test | +|---|-----------|--------------------------------|-------|--------------| +| 1 | An operating envelope authorizes *attempts*, not mutations. | `src/protocol/areas/action-attempt-lifecycle/matrix.ts:157-162` — `registerOperatingEnvelope:recorded` / `:idempotent` / `:conflict` lifecycle entries register bounds evidence, never mutation authority. | structural | `test/architecture/claim-boundary.test.ts` | +| 2 | Vague intent is not an operating envelope. | `src/protocol/areas/intent-compilation/candidate-decision.ts:67` — `deriveUncertaintyMarkers` pushes `unknown_operating_envelope` when no envelope is bound; `deriveCatalogAndEnvelopeReasonCodes` → `deriveEnvelopeReasonCodes` (`:165-185`) refuses actor/action/gateway/resource mismatch, revocation, or expiry on a bound envelope. | structural | `test/protocol/kernel-compilation-contract.test.ts` | +| 3 | Generated code is not an action contract. | `src/protocol/areas/intent-compilation/candidate-decision.ts:207-210` — `isAgentOriginCompilation` forces a generated-execution-graph ref even with no `runtimeExecution` (D-66 adjudication #4); `src/protocol/areas/action-attempt-lifecycle/matrix.ts:209` — unsafe generated-graph evidence terminates as refusal/proof gap *before* contract. | structural | `test/architecture/agent-origin-graph-required.test.ts` | +| 4 | A rendered plan is not permission. | `src/protocol/evidence-projections/schemas.ts:389` — `authorityCreatedByReadback: z.literal(false)` on readback projections. | structural | `test/protocol/evidence-projections/readback-spine.test.ts` | +| 5 | An action contract is a proposed commitment, not execution authority. | `src/protocol/areas/gateway-gate/transitions.ts:87-103` — `gatewayCheck` derives a constraint evaluation + commit plan from contract + greenlight + policy records before any commit. | structural | `test/architecture/http-handler-mutation-gating.test.ts` | +| 6 | A greenlight authorizes only one exact gateway-checked mutation attempt. | `src/protocol/areas/gateway-gate/transitions.ts:74,84` — `idempotencyLedgerEntry` + `GreenlightConsumption` single-use binding; `src/protocol/areas/gateway-gate/replay-refusal/index.ts:25` — `commitReplayRefusal` refuses the consumed replay with `already_consumed`. | structural | `test/architecture/gateway-invariant-replay.test.ts` (05-14 D3 promotion) | +| 7 | The gateway check is the enforcement point before consequence. | `src/adapters/auth-md/gateway.ts:191` — `verifiedGatewayCheckFromResult(gatewayCheck)` gate before provider I/O; `src/adapters/x402-payment/wallet-gateway.ts:143` — `assertGatewayHeldSigningCommand` refuses signing without a passed `VerifiedGatewayCheck` (custody landed 05-13). | structural | `test/adapters/auth-md-gateway.test.ts`, `test/architecture/x402-gateway-credential-custody.test.ts`, `test/architecture/gateway-invariant-signer-custody.test.ts` | +| 8 | Receipt evidence must distinguish gateway check from downstream execution. | `src/protocol/areas/action-attempt-lifecycle/matrix.ts:116` — "missing downstream response records proof gap instead of downstream success". | structural | `test/protocol/evidence-projections/readback-spine.test.ts` | +| 9 | Isolation state must be checked before future greenlights and gateway checks. | `src/protocol/areas/gateway-gate/transitions.ts:143-144` — `store.listIsolationStates([...isolationScopeRefsForContract(contract), ...])` evaluated inside the gate. | structural | `test/architecture/gateway-invariant-replay.test.ts`, `test/protocol/kernel-conflict-isolation.test.ts` | +| 10 | Missing evidence must be recorded as a proof gap, not smoothed over. | `src/protocol/areas/recovery/terminal/terminal-conflicts.ts:27-29,62` — `buildRecoveryTerminalConflictProofGap` + commit with `reasonCode: "recovery_terminal_conflict"`. | structural | `test/architecture/claim-boundary.test.ts` | + +--- + +## Table B — Phase 05 coherence invariants (7) + +| # | Coherence invariant | Evidence (`file:line` / plan) | Label | Verdict | +|---|---------------------|-------------------------------|-------|---------| +| 1 | Exact, policy-evaluated, gateway-checked contract before any consequential mutation. | `src/protocol/areas/gateway-gate/transitions.ts:87-103` (commit plan gated on records). | structural | PASS | +| 2 | One greenlight = one exact mutation attempt. | `src/protocol/areas/gateway-gate/transitions.ts:74,84` + `replay-refusal/index.ts:25`. | structural + architecture-test | PASS | +| 3 | The gateway check is the enforcement point. | `src/adapters/x402-payment/wallet-gateway.ts:143` (signer custody); `src/adapters/auth-md/gateway.ts:191` (provider-I/O gate). | structural | PASS (post-05-13) | +| 4 | Receipts separate gateway check from downstream execution. | `src/protocol/areas/action-attempt-lifecycle/matrix.ts:116`. | structural | PASS | +| 5 | Every persona uses the same live-fetch evidence spine (CLI/SDK/MCP). | `src/sdk/surface-clients/evidence-client.ts` (`getOperationReadbackProjection`); `src/cli/evidence/fetch.ts`; `src/mcp/resources.ts`. | architecture-test | PASS — pinned by `test/cli/cli-evidence-fetch.test.ts`, `test/sdk/evidence-client-fetch.test.ts` (05-06) | +| 6 | Every claimed invariant has a confirmed structural site (no advisory where structural exists). | This artifact (Table A) + `test/architecture/gateway-invariant-signer-custody.test.ts:1` (promotion gated on 05-13 structure per D-65). | advisory + architecture-test | PASS | +| 7 | Narrative aligns with the category claim (no passport / authority / payment / approval headline drift). | `test/architecture/canonical-doc-forbidden-copy.test.ts:1`; `test/architecture/claim-boundary.test.ts:144` — `/certificate is terminal evidence, not permission/i` over RAW canonical sources (regression fixed 05-10). | architecture-test | PASS | + +--- + +## D2 custody — before / after (adjudication R3 narrative) + +| Window | State of "the gateway check is the enforcement point" at the x402 signer | Label | +|--------|--------------------------------------------------------------------------|-------| +| Pre-05-13 | The signer accepted a `VerifiedGatewayCheck`-shaped command but custody was **label-only** — a raw caller-supplied `gatewayCredentialRefId` could reach `signPayment`. The invariant was an **advisory** claim with no structural refusal. | proof-gap (historical) | +| Post-05-13 | `src/adapters/x402-payment/wallet-gateway.ts:143` `assertGatewayHeldSigningCommand` structurally refuses unless the command carries a passed gate **and** gateway-resolved, redacted credential-resolution evidence bound to the same `gateAttemptId`. Promotion test `test/architecture/gateway-invariant-signer-custody.test.ts` cannot pass on a pre-05-13 tree. | structural | + +This is the single before/after that motivated D-65's "promote only after the +structural site exists" rule: the architecture test was **deliberately withheld** +until 05-13 landed, so the suite never advertised a guard that the code could not +yet honour. + +--- + +## Honest proof gaps (coherence invariant #10 applied to the audit itself) + +1. **HTTP transition sequence matrix is an ordering/drift guard, not a second + policy engine.** `src/http/admission/transition-sequence-matrix.ts` documents + the canonical prerequisite producer per route and fails app construction on + matrix/registry drift (coverage + integrity + acyclicity), but it does **not** + independently re-reject an out-of-order request at the app layer — per-request + rejection of a transition whose prerequisite record is missing is enforced + *elsewhere*, structurally, by the route registry's `recordScope` resolvers and + the kernel transition guards (e.g. `gatewayCheck` requires a proposed + contract). Labelling the matrix itself as a per-request enforcement point would + be doc theatre; it is honestly an **architecture-test + drift guard** layered + over the existing structural enforcement. + - Site: `src/http/admission/transition-sequence-matrix.ts:1`; guard wired at + `src/http/app.ts` (`assertTransitionSequenceMatrixCoverage()`). + - Pinned by: `test/architecture/http-transition-sequence-matrix.test.ts`. + +2. **Plan citation correction (D-70 honesty):** the 05-14 plan cited the auth-md + gate at `src/adapters/auth-md/gateway.ts:131-132`; the actual gate call is at + `src/adapters/auth-md/gateway.ts:191` (`verifiedGatewayCheckFromResult`). The + invariant holds; the line reference is corrected here rather than copied + forward unchecked. + +--- + +## Automated suite backing this audit + +- `bun test test/architecture/agent-origin-graph-required.test.ts` +- `bun test test/architecture/http-transition-sequence-matrix.test.ts` +- `bun test test/architecture/gateway-invariant-replay.test.ts test/architecture/gateway-invariant-params-mismatch.test.ts test/architecture/gateway-invariant-signer-custody.test.ts` +- `bun test test/architecture/x402-gateway-credential-custody.test.ts` (05-13 custody) +- `bun test test/architecture/claim-boundary.test.ts test/architecture/canonical-doc-forbidden-copy.test.ts` (narrative / category claim) diff --git a/.planning/phases/05-product-coherence/05-REVIEW-FIX.md b/.planning/phases/05-product-coherence/05-REVIEW-FIX.md new file mode 100644 index 0000000..48b80e1 --- /dev/null +++ b/.planning/phases/05-product-coherence/05-REVIEW-FIX.md @@ -0,0 +1,41 @@ +--- +phase: 05-product-coherence +fixed_at: 2026-05-29T00:00:00Z +review_path: .planning/phases/05-product-coherence/05-REVIEW.md +iteration: 1 +findings_in_scope: 2 +fixed: 2 +skipped: 0 +status: all_fixed +--- + +# Phase 05: Code Review Fix Report + +**Fixed at:** 2026-05-29 +**Source review:** `.planning/phases/05-product-coherence/05-REVIEW.md` +**Iteration:** 1 + +**Summary:** +- Findings in scope: 2 (HR-01, MR-01 — same hunk) +- Fixed: 2 +- Skipped: 0 + +## Fixed Issues + +### HR-01: MCP maps intent-compilation refusals to proof_gap + +**Files modified:** `src/protocol/foundation/failure-class/index.ts`, `test/protocol/failure-class-taxonomy.test.ts` +**Commit:** `e60fc87` +**Applied fix:** Removed hand-maintained MCP override block; `classifyFailureClassFromReasonCode` resolves registered codes via `failureClassFromReasonCodeMetadata` before unregistered prefix fallbacks. Registry `kind: "refusal"` → `protected_action_refusal`. + +### MR-01: mcp_candidate_digest_missing forced to proof_gap + +**Files modified:** `src/protocol/foundation/failure-class/index.ts`, `test/protocol/failure-class-taxonomy.test.ts` +**Commit:** `e60fc87` +**Applied fix:** Same registry-first path; `transition_error` → `internal`. + +--- + +_Fixed: 2026-05-29_ +_Fixer: Claude (gsd-code-fixer)_ +_Iteration: 1_ diff --git a/.planning/phases/05-product-coherence/05-REVIEW.md b/.planning/phases/05-product-coherence/05-REVIEW.md new file mode 100644 index 0000000..2e40db5 --- /dev/null +++ b/.planning/phases/05-product-coherence/05-REVIEW.md @@ -0,0 +1,243 @@ +--- +phase: 05-product-coherence +reviewed: 2026-05-29T00:00:00Z +depth: deep +files_reviewed: 63 +files_reviewed_list: + - src/adapters/auth-md/gateway.ts + - src/adapters/auth-md/profiles.ts + - src/adapters/x402-payment/wallet-gateway.ts + - src/cli/command-manifest.ts + - src/cli/evidence/fetch.ts + - src/cli/evidence/operation-readback-view.ts + - src/cli/main.ts + - src/hosted-admission/hosted-admission-config.ts + - src/hosted-admission/hosted-caller-identity.ts + - src/hosted-admission/hosted-verifier-adapter.ts + - src/hosted-admission/index.ts + - src/hosted-admission/roles.ts + - src/http/admission/hosted-admission-config.ts + - src/http/admission/hosted-caller-identity.ts + - src/http/admission/hosted-verifier-adapter.ts + - src/http/admission/transition-sequence-matrix.ts + - src/http/app.ts + - src/http/errors/codes.ts + - src/http/handlers/evidence-read.ts + - src/http/mutation-route-manifest.ts + - src/http/routes/evidence-read-route-registry.ts + - src/index.ts + - src/mcp/reference-transcript-fixtures.ts + - src/mcp/resources.ts + - src/protocol/areas/intent-compilation/candidate-decision.ts + - src/protocol/evidence-projections/index.ts + - src/protocol/evidence-projections/projections.ts + - src/protocol/evidence-projections/schemas.ts + - src/protocol/evidence-projections/store-reader.ts + - src/sdk/index.ts + - src/sdk/surface-clients/evidence-client.ts + - src/surfaces/boundary-manifest.ts + - src/surfaces/proof-packets/index.ts + - src/surfaces/proof-packets/per-customer-bypass-scaffold/index.ts + - src/surfaces/proof-packets/product-completion-contract/index.ts + - src/surfaces/proof-packets/product-completion.ts + - test/adapters/x402-wallet-gateway.test.ts + - test/architecture/agent-origin-graph-required.test.ts + - test/architecture/canonical-doc-forbidden-copy.test.ts + - test/architecture/claim-boundary.test.ts + - test/architecture/cli-command-posture.test.ts + - test/architecture/cli-non-authority-copy.test.ts + - test/architecture/custody-matrix-parity.test.ts + - test/architecture/gateway-invariant-params-mismatch.test.ts + - test/architecture/gateway-invariant-replay.test.ts + - test/architecture/gateway-invariant-signer-custody.test.ts + - test/architecture/hosted-admission-reexport-only.test.ts + - test/architecture/http-handler-mutation-gating.test.ts + - test/architecture/http-profile-adapter-conformance.test.ts + - test/architecture/http-transition-sequence-matrix.test.ts + - test/architecture/operator-product-completion-contract.test.ts + - test/architecture/planning-scratch-quarantine.test.ts + - test/architecture/product-completion-parity.test.ts + - test/architecture/proof-packets.test.ts + - test/architecture/root-exports.test.ts + - test/architecture/x402-gateway-credential-custody.test.ts + - test/cli/cli-evidence-fetch.test.ts + - test/cli/cli-evidence.test.ts + - test/mcp/mcp-resource-redaction.test.ts + - test/protocol/evidence-projections/readback-spine.test.ts + - test/sdk/evidence-client-fetch.test.ts + - test/support/http-protocol-fixtures.ts + - test/support/operation-readback-fixture.ts +findings: + critical: 0 + warning: 4 + info: 3 + total: 7 +status: issues_found +verdict: SHIP-WITH-FIXES +--- + +# Phase 05: Product Coherence — Code Review Report + +**Reviewed:** 2026-05-29 +**Depth:** deep (cross-layer taxonomy, gateway custody, export boundaries, readback spine) +**Diff scope:** `74ff1f1..aef9478` (`*.ts` under `src/`, `test/`) +**Branch:** `phase-05-product-coherence` @ `aef9478` +**Status:** issues_found +**Verdict:** **SHIP-WITH-FIXES** + +## Summary + +Phase 05 delivers coherent surface scrubbing, export-boundary hardening, readback spine parity (CLI/SDK/MCP/HTTP), and a **structural** x402 Mechanism A custody lift (`assertGatewayHeldSigningCommand` at both gateway runner and official signing surface). HTTP transition error envelopes, role-scoped SDK clients, and kernel replay guards align with classifier doctrine on the **HTTP transition path**. + +The blocking-quality gap is **MCP failure-class taxonomy**: intent-compilation refusals are hard-mapped to `proof_gap`, contradicting the reason-code registry and the phase’s own doctrine (“refusals ≠ missing evidence”). No recurrence of historical **F-01** (raw signing bypass via root exports) or **F-02** (treating the sequence matrix as a per-request gate) was found; both are explicitly guarded in code and architecture tests. + +**Tests run (literal):** + +```text +bun test test/architecture/{claim-boundary,x402-gateway-credential-custody,http-transition-sequence-matrix,http-handler-mutation-gating,root-exports,product-completion-parity}.test.ts +→ 30 pass, 0 fail + +bun test test/protocol/failure-class-taxonomy.test.ts test/http/transition-error-failure-class.test.ts test/sdk/role-clients-failure-class.test.ts test/adapters/x402-wallet-gateway.test.ts +→ 40 pass, 0 fail +``` + +## Prior finding recurrence + +| Id | Topic | Recurs? | Evidence | +|----|--------|---------|----------| +| **F-01** | Raw SDK / root export bypass of gateway-held signing | **No (x402)** | `runX402WalletGateway` / `experimentalRunX402WalletGateway` off root; `assertGatewayHeldSigningCommand` at `wallet-gateway.ts:143-187`, `:301`, `:375`; architecture pins in `gateway-invariant-signer-custody.test.ts`. Root still exports `HandshakeClient` for protocol transitions — intentional integrator path; signing custody remains adapter-gated. | +| **F-02** | HTTP sequence matrix mistaken for per-request enforcement | **No** | `transition-sequence-matrix.ts:4-15` documents drift guard only; per-request ordering enforced by `recordScope` resolvers + kernel guards; `http-transition-sequence-matrix.test.ts` pins construction-time coverage, not request routing. | + +## Narrative Findings (AI reviewer) + +### HIGH + +#### HR-01: MCP maps intent-compilation **refusals** to `proof_gap` + +**Status:** **RESOLVED** @ `e60fc87` (2026-05-29) + +**File:** `src/protocol/foundation/failure-class/index.ts:132-143` +**Registry:** `src/protocol/foundation/reason-codes.ts:90` (`kind: "refusal"`) +**Call site:** `src/mcp/x402-proposal.ts:529-542`, `:16-27` + +**Issue:** `classifyFailureClassFromReasonCode` short-circuited before metadata lookup and returned `proof_gap` for `mcp_candidate_not_contractable`, even though the reason code is registered as a **refusal**. When MCP proposal compilation fails with no finer-grained codes, `mcpTaxonomyOutcome` embedded `taxonomy:failureClass/proof_gap` and set MCP `failureClass` accordingly. + +**Adversarial agent behavior:** An agent receiving `outcome: "refused"` with `failureClass: proof_gap` on a candidate overreach (e.g. unwrapped consequential tool) will treat the outcome as “gather more evidence / read_evidence” instead of “stop / recraft_request”, potentially looping proposals or escalating proof-gap workflows for a hard policy refusal. + +**Fix applied:** Removed hand-maintained MCP override block; `classifyFailureClassFromReasonCode` now resolves registered codes via `failureClassFromReasonCodeMetadata` (registry `kind: "refusal"` → `protected_action_refusal`) before unregistered prefix fallbacks. Parity test `maps every registry refusal kind to protected_action_refusal (never proof_gap)` in `test/protocol/failure-class-taxonomy.test.ts`. + +--- + +### MEDIUM + +#### MR-01: `mcp_candidate_digest_missing` forced to `proof_gap` (should be `internal`) + +**Status:** **RESOLVED** @ `e60fc87` (same hunk as HR-01) + +**File:** `src/protocol/foundation/failure-class/index.ts:132-143` +**Registry:** `src/protocol/foundation/reason-codes.ts:104` (`kind: "transition_error"`) + +**Issue:** Same early return mapped a transition/digest integrity error to `proof_gap`. HTTP classifiers would surface `internal` for this code shape. + +**Adversarial behavior:** Agents conflate digest integrity failures with evidentiary gaps, wasting readback/evidence cycles on a non-recoverable proposal bug. + +**Fix applied:** Registry-first classification; `transition_error` kind → `internal` via `failureClassFromReasonCodeMetadata`. Covered by `classifies MCP candidate digest integrity errors as internal` in `test/protocol/failure-class-taxonomy.test.ts`. + +--- + +#### MR-02: SDK HTTP-status fallback collapses `409` subtypes + +**Status:** **Deferred (non-blocking)** — accepted for Phase 05 close-out + +**File:** `src/protocol/foundation/failure-class/index.ts:55-61` +**Consumers:** `src/sdk/surface-clients/transport.ts:76-87`, `src/sdk/client.ts:328-339` + +**Issue:** When the error body is empty or non-JSON, `failureClassFromHttpStatus(409)` always yields `protected_action_refusal`, losing `replay_refusal` and `stale_admission` distinctions that structured envelopes preserve (`transition-error-failure-class.test.ts`). + +**Adversarial behavior:** Upstream proxy strips JSON → agent retries a consumed greenlight or stale hosted identity as a generic refusal, causing duplicate gateway attempts or wrong repair playbook (`explainHandshakeError` / `sdk/repair.ts`). + +**Minimal fix:** Document as accepted degradation **or** add optional `x-handshake-failure-class` header on HTTP errors for status-only fallbacks; at minimum extend `role-clients-failure-class.test.ts` with a comment/assertion that replay vs refusal collapse is intentional. + +--- + +#### MR-03: auth.md gateway lacks structural credential-resolution binding at execute boundary + +**Status:** **Deferred (non-blocking)** — accepted for Phase 05 close-out + +**File:** `src/adapters/auth-md/gateway.ts:251-265` (cf. `src/adapters/x402-payment/wallet-gateway.ts:143-187`, `:301`, `:375`) + +**Issue:** D-64 Mechanism A is fully structural for x402 (`assertGatewayHeldSigningCommand`). auth.md checks profile conformance and records resolution evidence but does **not** assert gate-bound, redacted, `used_by_gateway` evidence immediately before `executeProtectedApiCall`. A custom `AuthMdProtectedApiCallSurface` could ignore `command.credentialResolutionEvidence` and use caller-held material. + +**Adversarial behavior:** Integrator implements surface that reads env var tokens while still passing gateway check — protocol records resolution evidence but mutation uses raw credentials, undermining “gateway-held custody” narrative for the second adapter family. + +**Minimal fix:** Extract shared `assertGatewayHeldExecutionCommand` (gate + resolution evidence bindings) and call from auth.md gateway before I/O; add architecture test analogous to `x402-gateway-credential-custody.test.ts`. + +--- + +#### MR-04: x402 gateway swallows custody/signing errors into generic failed outcome + +**Status:** **Deferred (non-blocking)** — accepted for Phase 05 close-out + +**File:** `src/adapters/x402-payment/wallet-gateway.ts:332-357` + +**Issue:** Bare `catch` maps `assertGatewayHeldSigningCommand` throws and signing failures alike to `payment_signature_failed` with digest-only diagnostics — no distinct reason code or refusal class in the adapter result. + +**Adversarial behavior:** Operator/automation cannot distinguish custody violation from downstream signing failure; may retry signing path instead of fixing gate/evidence binding. + +**Minimal fix:** Branch on custody error message prefix (`x402 gateway-held custody refused signing`) to return a refused-shaped outcome or attach structured `reasonCode` before reconciliation. + +--- + +### LOW + +#### LR-01: Operation readback default status over-fallback to `policy_refused` + +**File:** `src/protocol/evidence-projections/projections.ts:865-887` + +**Issue:** After explicit branches, unmatched envelope states fall through to `"policy_refused"`. Early lifecycle projections with incomplete policy/gateway fields may read as policy refusal rather than a neutral/pending status. + +**Adversarial behavior:** Support tooling mis-prioritizes “recraft_request” for contracts still progressing through compilation. + +**Minimal fix:** Add explicit branch for “no policy decision yet” or default to a non-refusal pending status; extend `readback-spine.test.ts`. + +--- + +#### LR-02: Sequence matrix omits `evaluatePolicy` as documented prerequisite of `gatewayCheck` + +**File:** `src/http/admission/transition-sequence-matrix.ts:44-49` + +**Issue:** Matrix lists `gatewayCheck → [proposeActionContract]` only. Greenlight creation flows through `evaluatePolicy`; matrix is documentation-only (not F-02), but operator docs may under-specify the policy step. + +**Minimal fix:** Add comment or secondary prerequisite note that greenlight records imply `evaluatePolicy` (kernel enforces via greenlight load in `gateway-gate/transitions.ts:115-125`). + +--- + +#### LR-03: `failureClassFromHttpStatus(418)` → `proof_gap` for unknown 4xx + +**File:** `src/protocol/foundation/failure-class/index.ts:60` (pinned in `failure-class-taxonomy.test.ts:73`) + +**Issue:** Any unknown client error status in 4xx band becomes `proof_gap` in SDK fallback — acceptable for resilience but can mislabel future 4xx refusal codes until registry updated. + +**Minimal fix:** None required for ship; consider defaulting unknown 4xx to `protected_action_refusal` per `classifyFailureClassFromProtocolError` line 122 parity. + +--- + +## What passed (no finding) + +- **x402 Mechanism A (D-64):** Structural, not label-only — gate + redacted `used_by_gateway` resolution evidence required before `signPayment`; enforced in runner and official surface. +- **One greenlight / replay:** Architecture promotion in `gateway-invariant-replay.test.ts`; adapter replay test in x402 wallet suite. +- **HTTP handler lane:** Read-only handlers; mutation manifest parity; no direct mutation in `src/http/handlers/*`. +- **Claim-boundary / export hygiene:** Root curated exports; gateway runners and adapter packs off root; MCP off root; CLI avoids `HandshakeClient`. +- **HTTP/MCP/SDK taxonomy (transition path):** Policy refusals map to `protected_action_refusal` + 409; proof gaps to 422; replay to `replay_refusal`; ingress codes stay `internal` with explicit HTTP status (`transition-error-failure-class.test.ts`). +- **Candidate envelope refusals (D-66):** `candidate-decision.ts:195-207` closes agent-origin graph hole without misusing `proof_gap`. +- **Hosted admission:** Re-export-only HTTP shims; readiness readback does not masquerade as clearance. + +## Recommended ship gate + +**HR-01** and **MR-01** resolved @ `e60fc87`. **MR-02**, **MR-03**, **MR-04** deferred as non-blocking parity hardening (recorded in `CONCERNS.md`). Phase 05 classifier doctrine is complete across HTTP/MCP/SDK for refusal vs proof_gap separation. + +--- + +_Reviewed: 2026-05-29_ +_Reviewer: Claude (gsd-code-reviewer)_ +_Depth: deep_ diff --git a/.planning/phases/05-product-coherence/05-VERIFICATION.md b/.planning/phases/05-product-coherence/05-VERIFICATION.md new file mode 100644 index 0000000..275a61d --- /dev/null +++ b/.planning/phases/05-product-coherence/05-VERIFICATION.md @@ -0,0 +1,195 @@ +--- +phase: 05-product-coherence +verified: 2026-05-29T15:30:00Z +status: passed +score: 13/13 +overrides_applied: 0 +health: + tsc: "0 errors (npx tsc --noEmit)" + bun_test: "849 pass / 3 fail (852 total)" + acceptable_failures: + - "repo naming posture > keeps workspace metadata junk out of active repo surfaces" + - "repo naming posture > keeps deleted scratch documents out of the active tree" + - "manifest coverage > maps each product surface export to a manifest surface with matching sourceRoots" + gating_operator: "10/10" + gating_full: "15/15" +gaps: [] +deferred: + - truth: "Whole-repo manifest coverage maps every export surface" + addressed_in: "Pre-Phase-04 baseline; acceptable residual" + evidence: "test/architecture/manifest-coverage.test.ts still fails for ./hosted-admission and ./surfaces/service-workflow-admission; Phase 04 VERIFICATION documented as pre-existing, not Phase 05 regression" +--- + +# Phase 05: Product Coherence Verification Report + +**Phase Goal:** Synthesis pass turning the post-Phase-04 spine into a coherent product — surface scrub (Bucket B), narrative polish honoring D-59 *reconstructable clearance before consequence*, keel-integrity audit (Bucket D), and Phase-04 deferred lane (Bucket A). + +**Verified:** 2026-05-29T15:30:00Z @ `6e23848` (`phase-05-product-coherence`) +**Status:** passed +**Re-verification:** Close-out reconciliation appended below (keel Table A row 2 citation + health re-run) + +## Goal Achievement + +### Observable Truths + +| # | Truth | Status | Evidence | +|---|-------|--------|----------| +| 1 | Phase-04 deferred lane shipped (mutation manifest, HTTP profile, dual-enforcement inventory, runbooks, D-25 scaffolds) | ✓ VERIFIED | `src/http/mutation-route-manifest.ts:1-20`; `test/adapters/http-profile-canonicalization.test.ts`; `test/architecture/dual-enforcement-posture.test.ts`; `docs/internal/service-operator-runbook.md`, `host-operator-runbook.md`; `src/surfaces/proof-packets/per-customer-bypass-scaffold/index.ts:32` | +| 2 | Live-fetch evidence spine parity (CLI/SDK/MCP → `OperationReadbackProjection`) | ✓ VERIFIED | `src/sdk/surface-clients/evidence-client.ts:47`; `src/cli/evidence/fetch.ts:53`; `src/mcp/resources.ts:140`; `test/sdk/evidence-client-fetch.test.ts`, `test/cli/cli-evidence-fetch.test.ts` | +| 3 | One-import agent ergonomics (root re-export) | ✓ VERIFIED | `src/index.ts:52-63` re-exports `EvidenceClient` and role clients from `sdk/surface-clients` | +| 4 | Readback spine includes compilation stages + correlation (D-57/D-58) | ✓ VERIFIED | `test/protocol/evidence-projections/readback-spine.test.ts`; `src/protocol/evidence-projections/schemas.ts:389` (`authorityCreatedByReadback: z.literal(false)`) | +| 5 | Category claim D-59 in canonical docs + forbidden-copy lint | ✓ VERIFIED | `README.md:15`; `test/architecture/claim-boundary.test.ts:186-191`; `test/architecture/canonical-doc-forbidden-copy.test.ts` | +| 6 | Mechanism A — gateway-held x402 credential custody (structural) | ✓ VERIFIED | `assertGatewayHeldSigningCommand` at `src/adapters/x402-payment/wallet-gateway.ts:143-187`; invoked before `signPayment` at `:301`; tests `test/architecture/x402-gateway-credential-custody.test.ts`, `gateway-invariant-signer-custody.test.ts` | +| 7 | D-66 agent-origin graph required at candidate-decision | ✓ VERIFIED | `requiresMissingGeneratedExecutionGraphRefusal` + push at `candidate-decision.ts:38-39,195-214`; `test/architecture/agent-origin-graph-required.test.ts` | +| 8 | Keel audit artifact with structural/architecture-test labels | ✓ VERIFIED | `05-KEEL-AUDIT.md` present with 10+7 rows; Table A row 2 cites `candidate-decision.ts:67` (`unknown_operating_envelope`) | +| 9 | HTTP transition sequence matrix (D4) + gateway invariant promotion (D3) | ✓ VERIFIED | `src/http/admission/transition-sequence-matrix.ts:74-122`; wired at `src/http/app.ts:34`; architecture tests pass; honestly scoped as drift guard not second policy engine | +| 10 | Concierge scaffold quarantined under `.planning/macro/` (D-62) | ✓ VERIFIED | `.planning/macro/concierge-demand-test-scaffold.md`; `test/architecture/planning-scratch-quarantine.test.ts` | +| 11 | No new kernel transition semantics (D-50 synthesis) | ✓ VERIFIED | Phase changes are admission docs, readback, adapters, tests — no new transition routes beyond Phase 04 registry | +| 12 | Phase 04 hard gate honored | ✓ VERIFIED | `04-VERIFICATION.md` `status: passed`; Phase 05 execution artifacts present on branch | +| 13 | Independent health gates green (modulo acceptable residuals) | ✓ VERIFIED | See health block in frontmatter | + +**Score:** 13/13 truths verified + +### 13-Entry Coherence-Invariant Checklist (KEEL audit) + +The audit documents **Table A (10 AGENTS.md invariants)** plus **Table B (7 phase coherence invariants)**. Deduplicating Table B rows 1–4 (restated core four) yields **13 unique checklist entries** (10 kernel + 3 phase-specific: live-fetch spine, structural-site audit, narrative category claim). + +Spot-check of every Table A/B `file:line` citation: + +| Row | Invariant (abbrev.) | Citation check | Label honest? | +|-----|---------------------|----------------|---------------| +| A1 | Envelope authorizes attempts, not mutations | `matrix.ts:157-164` — `catalogRecorded` bounds evidence | ✓ structural | +| A2 | Vague intent ≠ operating envelope | `candidate-decision.ts:67`, `:165-185` | ✓ structural — `unknown_operating_envelope` + `deriveEnvelopeReasonCodes` | +| A3 | Generated code ≠ action contract | `candidate-decision.ts:207-210`, `matrix.ts:209` | ✓ structural | +| A4 | Rendered plan ≠ permission | `schemas.ts:389` `authorityCreatedByReadback: false` | ✓ structural | +| A5 | Contract is proposal, not authority | `gateway-gate/transitions.ts:87-103` | ✓ structural | +| A6 | One greenlight, one attempt | `transitions.ts:74,84,229`; `replay-refusal/index.ts:25,142` | ✓ structural | +| A7 | Gateway check = enforcement point | `auth-md/gateway.ts:191`; `wallet-gateway.ts:143,301` | ✓ structural | +| A8 | Receipt vs downstream separation | `matrix.ts:116` missing_downstream_response | ✓ structural | +| A9 | Isolation before greenlight/gateway | `transitions.ts:143-144` | ✓ structural | +| A10 | Proof gaps recorded honestly | `terminal-conflicts.ts:27-29,62` | ✓ structural | +| B1–4 | Core four (coherence restatement) | Same sites as A5,A6,A7,A8 | ✓ | +| B5 | Live-fetch spine | evidence-client / CLI / MCP | ✓ architecture-test | +| B6 | Structural site per claim | This artifact + promotion tests | ✓ advisory + architecture-test (honest) | +| B7 | Narrative category claim | `canonical-doc-forbidden-copy.test.ts`, `claim-boundary.test.ts:144` | ✓ architecture-test | + +**D-63 enforcement labels:** No row labels `structural` where only docs exist. Table B row 6 correctly uses `advisory + architecture-test`. HTTP sequence matrix honestly documented as drift guard (`05-KEEL-AUDIT.md` proof-gap section) — not editorial theatre. + +### Mechanism A (D-64 custody) — structural proof + +```143:187:src/adapters/x402-payment/wallet-gateway.ts +export function assertGatewayHeldSigningCommand(command: X402PaymentSignatureCommand): void { + const refuse = (reasonCode: string, detail: string): never => { + throw new Error(`x402 gateway-held custody refused signing (${reasonCode}): ${detail}`); + }; + // ... gate status, field binding, credential resolution evidence checks ... +} +``` + +Called immediately before signing at line 301. Architecture tests refuse raw caller-supplied credential paths. **Not editorial-only.** + +### D-66 generated-execution-graph — structural proof + +```38:40:src/protocol/areas/intent-compilation/candidate-decision.ts + if (requiresMissingGeneratedExecutionGraphRefusal(context)) { + overreachReasonCodes.push("generated_execution_graph_missing"); + } +``` + +Agent-origin signal at `isAgentOriginCompilation` (`:210-214`). Pinned by `test/architecture/agent-origin-graph-required.test.ts` (3 cases, all pass). + +### Required Artifacts + +| Artifact | Expected | Status | Details | +|----------|----------|--------|---------| +| `05-KEEL-AUDIT.md` | 13-entry checklist + D-63 labels | ✓ VERIFIED | Present; row A2 cites envelope refusal at `:67` | +| `src/http/mutation-route-manifest.ts` | Phase-04 D-24 deferred lane | ✓ VERIFIED | Lines 1-20 document Phase 05 plan 05-01 landing | +| `src/http/admission/transition-sequence-matrix.ts` | D4 sequence matrix | ✓ VERIFIED | 29 routes, construction guard | +| `src/adapters/x402-payment/wallet-gateway.ts` | D-64 custody | ✓ VERIFIED | Structural assert before sign | +| Narrative / lint tests | D-59, D-60 | ✓ VERIFIED | claim-boundary + forbidden-copy | + +### Key Link Verification + +| From | To | Via | Status | +|------|-----|-----|--------| +| `wallet-gateway.ts` signing path | `assertGatewayHeldSigningCommand` | call at :301 before `signPayment` | ✓ WIRED | +| `candidate-decision.ts` | `compileIntent` refusal | `deriveCandidateDecision` → rejected status | ✓ WIRED | +| `EvidenceClient` | HTTP readback | `getOperationReadbackProjection` canonical path | ✓ WIRED | +| `app.ts` | sequence matrix | `assertTransitionSequenceMatrixCoverage()` at :34 | ✓ WIRED | +| KEEL audit row A2 | envelope enforcement | `candidate-decision.ts:67` | ✓ WIRED | + +### Behavioral Spot-Checks + +| Behavior | Command | Result | Status | +|----------|---------|--------|--------| +| Agent-origin graph refusal | `bun test test/architecture/agent-origin-graph-required.test.ts` | 3/3 pass | ✓ PASS | +| x402 custody structural | `bun test test/architecture/x402-gateway-credential-custody.test.ts` | pass | ✓ PASS | +| Signer custody promotion (D-65) | `bun test test/architecture/gateway-invariant-signer-custody.test.ts` | 3/3 pass | ✓ PASS | +| HTTP sequence matrix | `bun test test/architecture/http-transition-sequence-matrix.test.ts` | pass | ✓ PASS | +| Category claim lint | `bun test test/architecture/claim-boundary.test.ts test/architecture/canonical-doc-forbidden-copy.test.ts` | pass | ✓ PASS | + +### Probe Execution + +Step 7c: SKIPPED — no `scripts/*/tests/probe-*.sh` declared for this phase. + +### Requirements Coverage (D-50…D-71, sampled) + +| Decision | Status | Evidence | +|----------|--------|----------| +| D-50 synthesis not new mechanism | ✓ | No new kernel transitions; mutation manifest inventories existing routes | +| D-55 live evidence spine | ✓ | evidence-client + CLI + MCP tests | +| D-59 category claim | ✓ | README + claim-boundary required string | +| D-60 forbidden-copy structural | ✓ | canonical-doc-forbidden-copy.test.ts | +| D-63 keel audit | ✓ | Artifact exists; Table A row 2 citation corrected at close-out | +| D-64 Mechanism A custody | ✓ | wallet-gateway structural assert | +| D-65 arch test after structural lift | ✓ | gateway-invariant-signer-custody promoted post-05-13 | +| D-66 agent-origin graph | ✓ | candidate-decision + architecture test | +| D-70 citations required | ✓ | Table A/B spot-check accurate after row A2 fix | + +### Anti-Patterns Found + +| File | Pattern | Severity | Impact | +|------|---------|----------|--------| +| Phase-modified sources (sampled) | No TBD/FIXME in wallet-gateway, candidate-decision, transition-sequence-matrix | — | Clean | + +### Human Verification Required + +None blocking. Optional: read `docs/internal/golden-paths/*.md` for persona flow quality (grep/lint cannot judge prose clarity). + +### Gaps Summary + +Phase 05 **did deliver product coherence** in code and tests: deferred lane landed, surfaces unify on the evidence spine, narrative is lint-guarded, x402 custody and agent-origin graph are **structurally** enforced (not advisory), and the keel audit exists with honest proof-gap disclosure for the HTTP sequence matrix. Close-out corrected the sole audit citation gap (Table A row 2 → `candidate-decision.ts:67`). + +Acceptable test residuals (846/849) match Phase 04 baseline — not new Phase 05 regressions. + +--- + +## Close-out reconciliation + +**When:** 2026-05-29 (local Phase 04+05 close-out; no push/PR/npm publish) +**Base:** `e60fc87` on `phase-05-product-coherence` + +**Fixes applied:** + +- `05-KEEL-AUDIT.md` Table A row 2 retargeted from `candidate-decision.ts:39` (`generated_execution_graph_missing`, D-66) to `candidate-decision.ts:67` (`unknown_operating_envelope`) plus `deriveEnvelopeReasonCodes` at `:165-185`. Row 3 remains the agent-origin graph site; rows are not redundant. +- **05-REVIEW HR-01 + MR-01** resolved @ `e60fc87`: registry-first `FailureClass` derivation in `classifyFailureClassFromReasonCode` (`src/protocol/foundation/failure-class/index.ts:132-143`); parity tests in `test/protocol/failure-class-taxonomy.test.ts`. + +**Deferred (non-blocking, recorded in `CONCERNS.md`):** MR-02 (SDK 409 fallback), MR-03 (auth.md custody binding), MR-04 (x402 gateway catch collapse). + +**Health re-run at close-out:** + +| Gate | Result | +|------|--------| +| `npx tsc --noEmit` | 0 errors | +| `bun test` | 849 pass / 3 fail (852 total) — only `repo naming posture` (2) + `manifest coverage` (1) | +| `check-service-agent-gating-phase --tier operator` | 10/10 | +| `check-service-agent-gating-phase --tier full` | 15/15 | + +**05-REVIEW.md:** Complete — **SHIP-WITH-FIXES**, HR-01 resolved, 3 non-blocking MRs deferred. Review no longer provisional. + +**Remote ship:** Deferred — gh CLI absent + npm 401 per operator instruction. + +--- + +_Verified: 2026-05-29T15:30:00Z_ +_Verifier: gsd-verifier (independent codebase read + health re-run)_ diff --git a/.planning/tier2/00-canon-alignment.md b/.planning/tier2/00-canon-alignment.md deleted file mode 100644 index 0e46cb1..0000000 --- a/.planning/tier2/00-canon-alignment.md +++ /dev/null @@ -1,127 +0,0 @@ -# Canon Alignment - -Status: planning scratch, revised 2026-05-19. - -## Invariant at stake - -Tier 2 must extend the protocol kernel without changing the primitive. It must -not smuggle hosted claims, provider claims, or broad x402 payment claims into a -self-hosted proof. - -## Canon facts from `/docs/internal` - -### Product kernel - -`docs/internal/decisions.md` defines the current product kernel as: - -```text -exact action contract --> exact policy decision --> one-use gateway-bound greenlight --> gateway check before mutation --> receipt, refusal, or proof gap -``` - -It also defines the first bought product as Handshake Protected Actions: an -integration kit and receipt experience for one coding-agent workflow executing -one protected production-adjacent action through gateway-checked action -contracts. - -### Hosted boundary - -`docs/internal/decisions.md` says HTTP admission and caller custody may model -deployment-mode custody and caller roles, but they do not prove hosted -operation, production org auth, provider enforcement, or customer gateway -installation. - -A hosted claim requires: - -- a real deployment boundary; -- a credential custody model; -- a customer or provider gateway check; -- receipts that distinguish gateway check evidence from downstream execution - evidence. - -### Extension boundary - -`docs/internal/protocol-kernel-architecture.md` defines the forward extension -path: - -- self-hosted operation adds installable protected-action loops around the - kernel; -- hosted operation adds policy management, receipt retention, search, rollout, - audit, and recovery operations around the same kernel; -- bilateral ecosystem operation may add negotiation and linked agreements, but - every obligation still becomes its own action contract, policy decision, - greenlight, gateway check, and receipt/refusal/proof-gap chain. - -### Gateway policy lifecycle - -The same architecture doc says self-hosted installs can use local versioned -gateway policy, and hosted operation can distribute hosted versioned policy to -gateways. Enforcement remains at the gateway in both cases. - -### Evidence boundary - -`docs/internal/protocol-notes.md` requires receipts to distinguish: - -- proposal evidence; -- policy decision evidence; -- gateway check evidence; -- mutation attempt evidence; -- downstream finality evidence; -- proof gaps. - -Missing or ambiguous evidence is `ProofGap`, not success. - -## Correction to the first draft - -The first draft over-indexed on local product parts. That is not enough. - -The corrected design starts from a tier ladder: - -```text -Tier 1: protocol kernel proves the authority state machine -Tier 2: self-hosted Protected Actions proves one installed customer-owned path -Tier 3: hosted operation manages policy, retention, audit, rollout, and recovery -Tier 4: provider/customer gateway integrations make enforcement native at the - protected system boundary -``` - -The x402 example is useful only because wallet signing gives a clean mutation -boundary. It is not the product category. - -## Design constraints - -Tier 2 must preserve these constraints: - -- The agent may propose. It cannot authorize. -- The customer-owned gateway holds or controls signing authority. -- Policy is versioned before action time. -- The contract pins x402 evidence and gateway policy version. -- The greenlight is exact, one-use, gateway-bound, and expires. -- The gateway checks pinned and current policy, contract digest, params digest, - idempotency, isolation, and protected path posture before signing. -- The receipt can later move into Tier 3 retention/search without changing its - evidentiary meaning. -- Tier 4 provider work must make the gateway check native or provider-certified; - it cannot be a later observer. - -## Non-claims - -Tier 2 must not claim: - -- hosted operation; -- provider-side enforcement; -- generic x402 payment control; -- universal agent governance; -- wallet custody product; -- settlement finality; -- downstream business success; -- control over raw sibling tools or credentials outside the installed path. - -## Smallest next mechanism - -Define a migration-ready `x402_payment.exact` protected action family whose -records are already suitable for future hosted policy distribution and -provider-gateway attestation. diff --git a/.planning/tier2/01-source-study.md b/.planning/tier2/01-source-study.md deleted file mode 100644 index 185e427..0000000 --- a/.planning/tier2/01-source-study.md +++ /dev/null @@ -1,157 +0,0 @@ -# Source Study - -Status: planning scratch, revised 2026-05-19. - -## Invariant at stake - -Source evidence must separate what x402 proves from what Handshake proves. -x402 can prove payment-protocol facts. Handshake must prove principal authority -over a generated agent's consequential payment attempt. - -## Internal source anchors - -### `docs/internal/protocol-definition.md` - -Authority exists only when: - -- runtime or generated-execution evidence produced the candidate; -- the candidate matched catalog, envelope, and gateway records; -- the candidate was canonicalized into an exact `ActionContract`; -- policy greenlit that exact contract; -- the `Greenlight` is unexpired, unconsumed, and `maxUses: 1`; -- no active `IsolationState` blocks policy or gateway execution; -- the gateway owns or controls the mutation credential; -- the gateway checks the exact greenlight before mutation. - -For x402, the mutation credential is wallet signing authority. - -### `docs/internal/protocol-kernel-architecture.md` - -The kernel already has the required object chain: - -```text -ToolCapability -ActionType -GatewayRegistryEntry -OperatingEnvelope -RuntimeExecution -GeneratedExecutionGraph -IntentCompilationRecord -CandidateAction -ActionContract -PolicyDecision -Greenlight -GatewayCheckAttempt -MutationAttempt -Receipt -Refusal -ProofGap -IsolationState -RecoveryRecommendation -``` - -Tier 2 should map x402 into this chain instead of adding a new protocol core. - -### `docs/internal/protocol-layman.md` - -The plain-language guide gives the product translation Tier 2 should preserve: - -```text -one exact work order -one decision -one-use pass -one gateway check -one receipt, refusal, or proof gap -``` - -For x402: - -```text -one exact payment contract -one decision -one-use greenlight -one wallet gateway check -one receipt, refusal, or proof gap -``` - -### `docs/internal/decisions.md` - -The first bought product is Protected Actions: one workflow, one protected -production-adjacent action class, one gateway check, one policy file, one -receipt timeline. - -That implies Tier 2 x402 should design for a buying path, not just a demo path. - -## X402 primary-source facts - -Primary sources: - -- x402 HTTP 402 docs: - -- x402 buyer quickstart: - -- x402 facilitator docs: - -- x402 V1 to V2 migration guide: - -- x402 GitHub repository: - - -### Payment flow - -x402 V2 uses: - -- `PAYMENT-REQUIRED`: server to client, base64 `PaymentRequired`; -- `PAYMENT-SIGNATURE`: client to server, base64 `PaymentPayload`; -- `PAYMENT-RESPONSE`: server to client, base64 settlement response. - -The buyer receives a 402, selects accepted payment details, creates and signs a -payment payload, retries the request with `PAYMENT-SIGNATURE`, and receives -resource/settlement evidence through the server response. - -Handshake's authority boundary is before `PAYMENT-SIGNATURE` exists. - -### Buyer SDK pressure - -The buyer quickstart shows private-key-backed signers loaded from environment -variables such as `EVM_PRIVATE_KEY` and clients that automatically retry paid -requests. That is correct x402 ergonomics, but it is the danger case for -Handshake: generated code can make a paid request look like an ordinary HTTP -call. - -Tier 2 must invert that path. Generated code may produce a candidate. Only the -customer-owned gateway may create the payment signature. - -### Facilitator boundary - -The facilitator verifies and settles payments for servers and does not hold -buyer funds. Facilitator responses are downstream evidence. They do not decide -whether the principal authorized the agent to sign. - -### Version drift - -x402 V2 changed headers and network identifiers. Contracts must pin x402 -version and header evidence rather than letting the gateway infer compatibility -at signing time. - -## Design conclusion - -x402 is a strong Tier 2 proof because the mutation is crisp: - -```text -PAYMENT-SIGNATURE created by wallet authority -``` - -But x402 should not determine the Handshake architecture. The architecture is: - -```text -protected action authority chain now -hosted operation around the same chain later -provider gateway attestation around the same chain after that -``` - -## Smallest next mechanism - -Map `PAYMENT-REQUIRED` into `ActionContract.parameters` and make -`PAYMENT-SIGNATURE` creation a `GatewayCheckAttempt` outcome, never a runtime -helper outcome. diff --git a/.planning/tier2/02-users-and-tier-pathway.md b/.planning/tier2/02-users-and-tier-pathway.md deleted file mode 100644 index 5c7aaa5..0000000 --- a/.planning/tier2/02-users-and-tier-pathway.md +++ /dev/null @@ -1,258 +0,0 @@ -# Users And Tier Pathway - -Status: planning scratch, revised 2026-05-19. - -## Invariant at stake - -User-type design cannot become persona theatre. Each user type must map to a -real authority, evidence, adoption, or recovery job in the protocol chain. - -## User types - -### 1. Agent workflow owner - -Who: engineer or team lead letting a coding agent perform useful work. - -Job: get agent productivity without handing the agent mutation authority. - -Needs: - -- a way for generated work to produce exact candidates; -- fast local feedback when a candidate is refused; -- proof that a successful action used the gateway path; -- no requirement to understand every protocol object on day one. - -Tier implication: - -- Tier 2 must feel like an installable protected-action loop. -- Tier 3 can centralize policy and receipts for multiple workflows. -- Tier 4 matters when their provider or platform can enforce natively. - -### 2. Protected path owner - -Who: engineer, platform owner, security owner, or wallet owner who controls the -credential or mutation path. - -Job: ensure the agent cannot mutate outside declared bounds. - -Needs: - -- custody posture: who holds the credential; -- gateway policy version; -- exact contract fields; -- replay and drift refusal; -- isolation after divergence. - -Tier implication: - -- Tier 2 must keep credential authority outside the agent. -- Tier 3 must manage policy rollout without broadening authority. -- Tier 4 must make provider-side enforcement real, not advisory. - -### 3. Policy owner - -Who: person or team responsible for deciding which exact actions may proceed. - -Job: turn operating limits into machine-checkable decisions. - -Needs: - -- versioned policy packs; -- deterministic evaluation; -- refusal reasons; -- review hooks tied to exact contract digests; -- budget windows treated as attempt bounds, not permission. - -Tier implication: - -- Tier 2 uses local versioned policy. -- Tier 3 hosts policy management and distribution. -- Tier 4 requires policy contracts the provider gateway can verify or honor. - -### 4. Reviewer or auditor - -Who: operator, security reviewer, compliance reviewer, incident responder, or -future maintainer reconstructing what happened. - -Job: determine what was controlled, what was observed, and what is unknown. - -Needs: - -- receipt timeline; -- refusal history; -- proof gaps; -- gateway check evidence; -- downstream finality evidence; -- links between related obligations. - -Tier implication: - -- Tier 2 must produce local reconstruction truth. -- Tier 3 adds retention, search, audit, and recovery workflows. -- Tier 4 adds provider attestations or native evidence. - -### 5. Provider partner - -Who: wallet provider, deployment provider, package registry, CI provider, cloud -provider, data API provider, or agent runtime vendor. - -Job: make Handshake enforcement native enough that customers do not have to rely -on wrappers or logs. - -Needs: - -- stable contract and gateway check semantics; -- versioned gateway policy contract; -- conformance expectations; -- evidence exchange format; -- clear non-claim boundaries. - -Tier implication: - -- Tier 2 should expose the shape providers will later need. -- Tier 3 can operate policy and evidence across orgs. -- Tier 4 is reached only when the provider/customer gateway can block mutation - before consequence. - -### 6. Resource seller in the x402 example - -Who: x402 seller, data/API provider, or facilitator-adjacent service. - -Job: publish payment requirements and fulfill paid resources. - -Needs: - -- no dependency on Handshake to sell through x402; -- clear buyer-side evidence requirements; -- optional signed offer/receipt support treated as evidence; -- no assumption that seller approval equals principal consent. - -Tier implication: - -- Tier 2 buyer-side proof should not require seller cooperation beyond standard - x402. -- Tier 4 may later support provider-native receipt or offer attestation, but it - still cannot authorize the buyer's principal. - -## Tier ladder - -### Tier 1: protocol kernel - -User promise: - -```text -There is a coherent authority state machine. -``` - -What exists: - -- exact contracts; -- policy decisions; -- one-use greenlights; -- gateway checks; -- receipts/refusals/proof gaps; -- isolation and recovery primitives. - -What it cannot claim: - -- installed customer path; -- hosted operation; -- provider enforcement. - -### Tier 2: self-hosted Protected Actions - -User promise: - -```text -This installed customer-owned path is gateway-checked. -``` - -For x402: - -```text -The agent can propose a paid request. -The customer-owned wallet gateway creates PAYMENT-SIGNATURE only after exact -greenlight verification. -``` - -Tier 2 must produce objects that Tier 3 can host later: - -- versioned policy pack; -- gateway registry entry; -- protected path posture; -- receipts and proof gaps; -- recovery recommendations; -- conformance results. - -### Tier 3: hosted operation - -User promise: - -```text -Handshake can operate policy, evidence, audit, rollout, and recovery across -installed protected paths. -``` - -Tier 3 adds: - -- hosted policy management; -- policy distribution to gateways; -- gateway enrollment and health; -- receipt retention and search; -- audit workflows; -- recovery workflows; -- rollout controls; -- org-level installation posture. - -Tier 3 must not move enforcement away from the gateway. Hosted policy is not a -mutation credential. - -### Tier 4: provider-integrated enforcement - -User promise: - -```text -The protected system's own gateway or provider-certified boundary can enforce -Handshake-compatible checks before mutation. -``` - -Tier 4 adds: - -- provider/customer gateway contract; -- native or certified pre-mutation check; -- provider evidence attestation; -- conformance profile; -- bilateral or ecosystem records when multiple principals coordinate. - -Tier 4 is not "more connectors." It is a stronger enforcement location. - -## X402 ladder - -```text -Tier 2: - customer-owned wallet gateway signs after local policy greenlight - -Tier 3: - hosted Handshake manages wallet-gateway policy, receipts, rollout, recovery, - and audit across teams - -Tier 4: - wallet provider, x402 client provider, or payment infrastructure provider - implements or certifies the gateway check before signing -``` - -## Design requirements by user type - -| User type | Tier 2 proof | Tier 3 growth | Tier 4 endpoint | -| --- | --- | --- | --- | -| Agent workflow owner | agent cannot spend directly | many workflows managed | provider runtime cannot bypass | -| Protected path owner | gateway owns signer | policy rollout and health | native provider enforcement | -| Policy owner | local deterministic policy | hosted policy distribution | provider-verifiable policy contract | -| Reviewer/auditor | local receipt timeline | retained/searchable evidence | provider attestation | -| Provider partner | clear gateway semantics | operational integration | certified enforcement | -| x402 seller | standard x402 compatibility | richer evidence intake | signed offers/receipts as evidence | - -## Smallest next mechanism - -Design Tier 2 records so every object has a Tier 3 owner and a Tier 4 -attestation path before source implementation begins. diff --git a/.planning/tier2/03-x402-architecture.md b/.planning/tier2/03-x402-architecture.md deleted file mode 100644 index 0facd48..0000000 --- a/.planning/tier2/03-x402-architecture.md +++ /dev/null @@ -1,205 +0,0 @@ -# X402 Architecture - -Status: planning scratch, revised 2026-05-19. - -## Invariant at stake - -The x402 transaction is valid Tier 2 only if the wallet gateway is the first -component that can create `PAYMENT-SIGNATURE`. If generated code can sign, the -architecture is advisory, not Handshake. - -## Role model - -```text -principal - owns intent and operating envelope - -agent runtime - generates execution evidence and proposes payment candidate - -policy owner - defines versioned local policy in Tier 2 - defines hosted policy in Tier 3 - -wallet gateway owner - owns or controls signing authority - -x402 seller - returns PAYMENT-REQUIRED and fulfills resource if payment is accepted - -facilitator - verifies/settles x402 payment for the seller when used -``` - -Authority stays with the principal's policy and wallet gateway. The seller and -facilitator provide payment-protocol evidence, not principal authority. - -## Kernel mapping - -| Kernel object | X402 mapping | Tier 3/4 continuity | -| --- | --- | --- | -| `ToolCapability` | generated request capability and raw x402/wallet reachability posture | hosted install inventory; provider runtime claims | -| `ActionType` | `x402_payment.exact` | stable action family for policy and provider profiles | -| `GatewayRegistryEntry` | customer-owned wallet gateway, custody mode, policy version | hosted gateway enrollment; provider gateway registration | -| `OperatingEnvelope` | agent, runtime, allowed resource, network, asset, gateway, budget bounds | hosted policy pack and org rollout | -| `RuntimeExecution` | generated request attempt and 402 discovery evidence | retained execution evidence | -| `GeneratedExecutionGraph` | graph node showing paid request proposal, no signer node | hosted replay and review | -| `IntentCompilationRecord` | conversion of vague intent into candidate payment | compiler quality and refusal analytics | -| `CandidateAction` | proposed exact x402 payment | candidate review and policy evaluation | -| `ActionContract` | canonical x402 V2 payment contract | stable evidence object across tiers | -| `PolicyDecision` | deterministic local/hosted decision | hosted policy distribution | -| `Greenlight` | one-use wallet-gateway-bound pass | provider-verifiable authority token | -| `GatewayCheckAttempt` | pre-signature wallet verification | provider/customer enforcement evidence | -| `MutationAttempt` | payment signature creation and paid retry | downstream operation reconciliation | -| `Receipt` | reconstructed chain and x402 evidence | retention, search, audit | -| `Refusal` | no authority/no signature evidence | policy tuning and recovery | -| `ProofGap` | missing settlement/receipt/finality/idempotency evidence | recovery and audit queue | -| `IsolationState` | future block after signer exposure or divergence | org-level containment | - -## Contract shape - -The first implementation should use generic `ActionContract.parameters`, not a -new protocol primitive. - -```yaml -actionType: x402_payment.exact -x402Version: 2 -request: - method: GET - url: https://seller.example/data - headersDigest: sha256:... - bodyDigest: null -paymentRequired: - rawHeaderDigest: sha256:... - decodedDigest: sha256:... - selectedPaymentDetailsDigest: sha256:... - scheme: exact - network: eip155:84532 - asset: usdc - maxAmountRequired: "1000" - payTo: "0x..." - resource: https://seller.example/data - facilitatorUrl: https://... - timeoutSeconds: 60 -extensions: - paymentIdentifier: - required: true - valueDigest: sha256:... - signedOffer: - posture: optional_evidence - offerDigest: sha256:... -gateway: - gatewayId: gateway_wallet_local_... - policyVersion: x402-policy-v1 - custodyMode: customer_owned - authorityHolder: wallet_gateway -idempotency: - key: x402-attempt-... - retryScopeDigest: sha256:... -evidence: - requirePaymentResponse: true - requireSettlementEvidence: true - signedReceipt: optional_evidence -``` - -Important: `maxAmountRequired` is x402 terminology. In the `exact` scheme, the -contract still represents one fixed payment requirement selected before signing. - -## Authority sequence - -```mermaid -sequenceDiagram - participant A as Agent runtime - participant K as Handshake kernel - participant P as Policy - participant G as Wallet gateway - participant S as x402 seller - participant F as Facilitator - - A->>S: request paid resource without payment - S-->>A: 402 + PAYMENT-REQUIRED - A->>K: record runtime evidence and candidate - K->>K: canonicalize ActionContract - K->>P: evaluate exact contract - P-->>K: Greenlight or Refusal - K-->>G: one-use gateway-bound greenlight - G->>K: verify contract, policy, idempotency, isolation - G->>S: retry with PAYMENT-SIGNATURE only if verified - S->>F: verify/settle when facilitator is used - F-->>S: verification/settlement evidence - S-->>G: resource or 402 + PAYMENT-RESPONSE when available - G->>K: record mutation attempt, receipt, refusal, or proof gap -``` - -## Tier 2 requirements - -Tier 2 is acceptable only when it proves: - -- generated code cannot access the signer in the protected path; -- candidate payment is exact and canonicalized; -- policy can refuse before authority exists; -- greenlight is one-use, gateway-bound, and consumed; -- wallet gateway signs only after the exact check; -- replay, mismatch, drift, and isolation refuse before signature; -- receipt distinguishes gateway check from x402 settlement/resource evidence; -- raw sibling authority is reported as unsafe posture, not silently ignored. - -## Tier 3 migration requirements - -The Tier 2 architecture must leave these migration seams intact: - -- policy pack can move from local file to hosted versioned distribution; -- receipt file can move to hosted retention without changing meaning; -- gateway registration can move to hosted enrollment without moving signing - authority into the agent; -- refusal/proof-gap records can move into hosted audit and recovery queues; -- install posture can become org-level health without claiming universal - enforcement. - -Tier 3 adds operation around the same chain. It must not create a hosted bypass -around the gateway. - -## Tier 4 migration requirements - -The Tier 4 path is provider-native or provider-certified enforcement. - -For x402 this could mean: - -- wallet provider implements the Handshake-compatible gateway check before - signing; -- x402 client provider offers a mode where payment signing calls require a - verified Handshake greenlight; -- payment infrastructure provider emits attestable evidence for settlement and - signed receipt support; -- agent runtime provider blocks raw signer access and exposes generated - execution evidence suitable for Handshake. - -Tier 4 is reached only when the provider or customer gateway can block mutation. -If it only logs after signing, it is not Tier 4. - -## Architecture decisions - -### Decision 1: x402 is a proof lens, not the product category - -Keep x402 because the signature boundary is concrete. Do not turn Tier 2 into a -payment product. - -### Decision 2: buyer-side first - -The first proof is buyer-side because the authority question is principal spend. -Seller middleware and facilitator behavior are downstream evidence. - -### Decision 3: exact scheme first - -Start with x402 V2 `exact`. Treat `upto` as a future hostile fixture because the -seller can determine actual usage after signature. - -### Decision 4: policy before operation, operation before ecosystem - -Tier 2 proves local policy and gateway enforcement. Tier 3 operates it across -orgs. Tier 4 moves enforcement into provider/customer boundaries. - -## Smallest next mechanism - -Build a fake-signing wallet gateway fixture whose records are shaped exactly as -Tier 3 hosted retention and Tier 4 provider attestation would need them. diff --git a/.planning/tier2/04-spec-and-doubt-review.md b/.planning/tier2/04-spec-and-doubt-review.md deleted file mode 100644 index 4c5c52d..0000000 --- a/.planning/tier2/04-spec-and-doubt-review.md +++ /dev/null @@ -1,195 +0,0 @@ -# Spec And Doubt Review - -Status: planning scratch, revised 2026-05-19. - -## Invariant at stake - -The design must be strong enough that a Tier 2 proof can grow into hosted and -provider-integrated Handshake without renaming local demo artifacts into product -truth. - -## Spec - -### Objective - -Design the Tier 2 x402 protected spend proof as the first self-hosted instance -of Handshake Protected Actions. - -Success means: - -- one coding-agent workflow can propose an exact x402 payment; -- the wallet gateway, not the agent, holds signing authority; -- policy can greenlight/refuse the exact payment; -- the gateway creates `PAYMENT-SIGNATURE` only after exact one-use verification; -- the resulting records are suitable for Tier 3 hosted operation and Tier 4 - provider-gateway integration. - -### Commands - -No source implementation in this packet. When implementation begins, repo canon -requires: - -```bash -npm run check:types -npm run lint -npm run test -git diff --check -``` - -Full gate: - -```bash -npm run check:repo -``` - -### Future source ownership - -Do not implement directly from this scratch packet without a follow-up source -plan. - -Expected ownership if implemented: - -- `src/runtime/x402-payment`: generated-execution evidence and candidate - proposal only; -- `src/adapters/x402-wallet-gateway`: reference wallet gateway fixture that - signs only after verified gateway check; -- `src/conformance/x402-payment`: hostile checks for replay, drift, raw signer - exposure, and proof gaps; -- `test/runtime`, `test/adapters`, `test/conformance`: focused evidence tests. - -### Code style - -Use protocol nouns that describe authority: - -```ts -recordX402PaymentCandidate(...) -proposeX402PaymentContract(...) -evaluateX402PaymentPolicy(...) -recordWalletGatewayCheck(...) -recordX402PaymentReceipt(...) -``` - -Avoid names that imply more than mechanism: - -```text -safePayment -trustedAgentPayment -approvedSpend -secureX402Fetch -proveSettlement -``` - -### Testing strategy - -The first behavioral proof should use deterministic fake signing before real -funds. - -Required hostile checks: - -- no greenlight -> no payment signature; -- wrong contract digest -> no payment signature; -- wrong gateway -> no payment signature; -- expired greenlight -> no payment signature; -- replayed greenlight -> no second signature; -- changed `PAYMENT-REQUIRED` -> no payment signature; -- active isolation -> no payment signature; -- raw signer visible to agent -> unsafe posture and refusal/quarantine; -- missing `PAYMENT-RESPONSE` -> proof gap, not success; -- `upto` offered -> refusal until final amount evidence is designed. - -### Boundaries - -Always: - -- preserve exact contract binding; -- keep signer authority out of generated code; -- record refusals and proof gaps as product outcomes; -- design records for Tier 3 retention and Tier 4 attestation. - -Ask first: - -- adding x402 dependencies; -- adding source paths; -- moving scratch planning into canon; -- running real testnet/mainnet payment flows. - -Never: - -- give generated code private keys; -- infer authority from x402 seller/facilitator evidence; -- claim hosted operation without deployment/custody/gateway proof; -- claim provider enforcement without provider/customer pre-mutation check. - -## Doubt review - -This is a degraded in-session adversarial pass, not a fresh-context or -cross-model review. Subagents and external model CLIs were not invoked in this -turn. - -### Claim: "Tier 2 x402 creates a path to Tier 3/4." - -Issue: only true if Tier 2 records already carry policy version, gateway -identity, custody mode, contract digest, idempotency posture, receipt evidence, -proof gaps, and install posture. - -Resolution: revised architecture makes Tier 3/4 continuity a design requirement, -not a follow-up. - -### Claim: "User types are addressed." - -Issue: generic personas would be theatre. User types must map to authority jobs. - -Resolution: user types are defined by protocol responsibility: workflow owner, -protected path owner, policy owner, auditor, provider partner, and x402 seller. - -### Claim: "The x402 buyer flow is enough." - -Issue: official x402 buyer docs optimize for automatic payment after 402. That -is the exact bypass risk for generated code. - -Resolution: the buyer flow is used as threat pressure. Handshake inverts it: -generated code proposes; wallet gateway signs after exact check. - -### Claim: "Tier 3 is just hosted UI." - -Issue: that repeats the prior misalignment. Hosted operation is not presentation. - -Resolution: Tier 3 is policy management, distribution, receipt retention, -search, rollout, audit, and recovery around the same authority chain. - -### Claim: "Tier 4 is more integrations." - -Issue: more integrations can still be advisory. - -Resolution: Tier 4 requires provider/customer gateway enforcement before -mutation or provider-native evidence compatible with the gateway chain. - -## Design verdict - -Keep: - -- x402 buyer-side exact payment as first proof lens; -- wallet gateway as authority holder; -- local versioned policy in Tier 2; -- Tier 3 hosted operation around the same chain; -- Tier 4 provider/customer gateway enforcement as the end state. - -Cut: - -- local adapter as product center; -- payment-product language; -- seller/facilitator ambitions; -- generic "agent commerce"; -- broad "x402 protection" claims. - -Redesign: - -- records must be migration-ready from the first Tier 2 fixture; -- user types must be responsibility types, not marketing personas; -- receipt structure must serve future retention/search/audit without changing - evidence meaning. - -## Smallest next mechanism - -Before source implementation, write the `x402_payment.exact` record contract and -conformance checklist as a Tier 2 -> Tier 3 -> Tier 4 compatibility matrix. diff --git a/.planning/tier2/README.md b/.planning/tier2/README.md deleted file mode 100644 index 7344b1e..0000000 --- a/.planning/tier2/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# Tier 2 Protocol Usability And Clearing-House Research Packet - -Status: planning scratch, revised 2026-05-21 after gsd-map-codebase refresh. - -This packet records the current Tier 2/Tier 3 architecture thinking around -protocol-facing usability and the longer clearing-house thesis. It is scratch, -not repo canon. - -The important correction is that no adapter family defines the protocol shape. -`x402_payment.exact`, preview deploy, package install, and repo write are proof -profiles or reference protected action families. The product center remains a -protected action path for automated decision-making: - -```text -observed consequential attempt --> exact action contract --> policy decision --> one-use gateway-bound greenlight --> gateway check before mutation --> receipt, refusal, proof gap, isolation, or recovery evidence -``` - -The clearing-house thesis extends that same loop into a future evidence layer: - -```text -protected action path --> gateway-checked authority evidence --> local terminal AuthorityCertificate evidence --> hosted evidence navigation and policy operation --> cross-org verification and ecosystem clearing -``` - -Doctrine realignment (autoreason pass_02): [tiered-product-doctrine.md](../strategy/tiered-product-doctrine.md) v0.3.1 — protocol remains Layer 8 authority proof; adapter profiles do not become the product center. - -Crypto / signing (autoreason pass_03): [authority-certificate-foundation.md](../strategy/authority-certificate-foundation.md) — Ed25519 over `signingInput`; local `AuthorityCertificate` minting and offline pinned-key verification are now landed source behavior. Older docs **06–09** target language is historical planning context only. Do not reschedule K-D9-K-D12 as unfinished local foundation work, and do not convert local certificate verification into hosted trust, provider custody, marketplace certification, or cross-org clearing. - -Files under `.planning/` are scratch. They are not active repo canon. - -## Invariant at stake - -Tier 2 must prove the same authority chain that future hosted and -provider-integrated Handshake must preserve: - -```text -generated execution evidence --> exact action contract --> policy decision --> one-use gateway-bound greenlight --> gateway check before mutation --> receipt, refusal, proof gap, isolation, or recovery evidence -``` - -If Tier 2 only proves a local wrapper, it does not create a credible path to -Tier 3 or Tier 4. - -## Packet - -- `00-canon-alignment.md`: early canon alignment and non-claim boundaries. -- `01-source-study.md`: early source study; useful but x402-centered. -- `02-users-and-tier-pathway.md`: early Tier 2 -> Tier 3 -> Tier 4 pathway. -- `03-x402-architecture.md`: x402 adapter-family study; treat as example only. -- `04-spec-and-doubt-review.md`: early adversarial review and concerns. -- `05-t2-t3-cli-mcp-sdk-architecture-map.md`: self-hosted/hosted activation - map across CLI, MCP, SDK, gateway, and evidence surfaces. -- `06-policy-agent-management-interface-map.md`: current consolidated map for - protocol-facing metadata, challenges, requests, and evidence projections. -- `07-agentic-economy-clearing-house-research.md`: current consolidated - clearing-house research and kernel-now/kernel-needed map. -- `surfaces/`: Tier 2 activation **constitution** (P1–P12 -> MCP/CLI rules) plus - **doc 10 Agent Proof Slice** (Tier 2 activation proof over the landed authority - kernel, with x402 as the worked proof profile, hostile traces, and the current - product-level regression). Not implementation; preserves runtime - ingress as proposal evidence and keeps policy/gateway authority out of the - agent surface. - -## Current Kernel - -The current source kernel already supports the hard local primitive: - -```text -RuntimeExecution / GeneratedExecutionGraph / ToolCallDraft --> IntentCompilationRecord / CandidateAction --> ActionContract --> PolicyDecision --> one-use Greenlight or Refusal --> GatewayCheck --> MutationAttempt / Receipt / Refusal / ProofGap --> reconciliation, recovery, isolation, and redacted evidence projections -``` - -That is enough to prove local authority mechanics. It is not enough to claim a -clearing house. - -## What The Kernel Needs Next For The Vision - -The next required layer is not a new authority primitive. It is a projection and -usability layer that preserves the existing primitive: - -- `ProtectedActionMetadata`: what an automated client may propose, not - permission. -- `ProtectedActionChallenge`: structured refusal/proof-gap navigation, not - negotiation. -- `ProtectedActionRequest`: an external proposal shape that compiles into - runtime evidence and candidate action. -- `AgentTransactionEnvelope`: a redacted evidence projection/export, not - authority. -- Generic protected-path health and receipt timeline across action families, not - package-install-only diagnostics. -- Real runtime adapters, real bypass probes, and customer/provider gateway - custody before installed-path claims. -- Hosted policy management, retention, search, alerts, audit exports, and - reader authorization only in Tier 3. -- Cross-org verification, conformance marks, external verifier signatures, and - ecosystem clearing only in Tier 4. - -## Current APS proof - -`test/product/agent-proof-slice.test.ts` now proves that Tier 2 activation can -sit on the existing adapter framework without adding a protocol primitive: - -```text -generated runtime dispatch --> adapter-specific proposal helper --> generic kernel authority chain --> adapter-owned gateway check --> receipt, refusal, or proof gap --> redacted agent transaction envelope --> terminal AuthorityCertificate -``` - -x402 is the worked proof profile; package install is the non-x402 parity check. -The envelope is read-only, redacted, and unable to mint policy decisions, -greenlights, gateway checks, receipts, exports, certificates, or mutations. -The x402 lane is the official buyer-side `exact` path only: gateway-held -`PaymentPayload` / `PAYMENT-SIGNATURE` creation after `VerifiedGatewayCheck`, -with per-call spend authority and explicit cut lines around hosted/provider -custody, facilitator/seller operation, spend-window ledgers, certification, and -cross-org trust. - -## Smallest next mechanism - -Wrap the product proof in a first-protected-action walkthrough that shows the -same evidence refs without introducing CLI/MCP/hosted clearing-house surface -area. diff --git a/.planning/tier2/surfaces/10-agent-proof-slice.md b/.planning/tier2/surfaces/10-agent-proof-slice.md deleted file mode 100644 index 7b2b526..0000000 --- a/.planning/tier2/surfaces/10-agent-proof-slice.md +++ /dev/null @@ -1,519 +0,0 @@ -# Agent Proof Slice (APS) - Tier 2 Activation Proof - -Status: planning scratch, rewritten 2026-05-20. -Audience: Tier 2 implementers, runtime/gateway integrators, plan-devex-review, -plan-eng-review. -Source anchors: `AGENTS.md`, `README.md`, -`docs/internal/protocol-definition.md`, -`docs/internal/protocol-kernel-architecture.md`, -`.planning/tier2/README.md`, -`.planning/tier2/surfaces/00-surface-design-principles.md`, -`.planning/tier2/surfaces/04-v1-inventory.md`, -`.planning/tier2/06-policy-agent-management-interface-map.md`, -`.planning/codebase/CONCERNS.md`. - -This file is scratch. It is not repo canon, not a public roadmap, and not an -implementation claim. - -## Invariant at stake - -APS must prove that an automated runtime can propose consequential work without -receiving mutation authority, and that the protected gateway remains the only -place where consequence can happen. - -If APS turns into "agent payments", "approval UX", "observability", or a nice -x402 demo, it violates the product kernel. The primitive is still: - -```text -observed generated execution --> exact action contract --> policy decision --> one-use gateway-bound greenlight or refusal --> gateway check before mutation --> receipt, refusal, proof gap, isolation, or recovery evidence -``` - -## Rewrite verdict - -The previous APS draft treated x402 as the Tier 1 product proof and carried -stale blockers around route custody, invented proof scripts, and a package -install comparison that no longer matches the current kernel. Cut that framing. - -APS is now a Tier 2 activation slice over the landed local authority kernel. -x402 remains the worked proof profile because paid HTTP stresses wallet custody, -exact parameter binding, replay, downstream uncertainty, and evidence -reconstruction. It does not define the product. - -## APS thesis - -An agent runtime should be able to: - -1. Observe generated orchestration that attempts a consequential action. -2. Reduce that attempt to a catalog-bound, exact proposed action contract. -3. Receive either a contract handle or a structured refusal/challenge. -4. Hold no install authority, policy authority, gateway authority, wallet key, - mutation credential, or greenlight minting capability. -5. Read redacted evidence after policy/gateway activity. -6. Reconstruct whether the chain ended in receipt, refusal, proof gap, - isolation, or recovery. - -That is enough for a first developer-facing proof. It is not enough to claim -hosted operation, cross-org clearing, broad MCP safety, or an agentic economy -clearing house. - -## APS is not - -- Not a generic x402 payment SDK. -- Not a wallet-hosting product. -- Not an approval screen. -- Not a hosted verifier. -- Not MCP productization. -- Not a CLI product. -- Not package-install certification. -- Not a conformance mark. -- Not a claim that all agent actions are controlled. -- Not a claim that downstream business success is proven. - -## Why x402 remains the worked proof profile - -| Proof profile | Why it belongs | What it does not prove | -| --- | --- | --- | -| `x402_payment.exact` | Exercises money movement, wallet-signature custody, exact paid-HTTP parameters, replay, and downstream proof gaps. | General product scope, hosted wallet custody, session/day spend-window ledgers, provider trust, or universal payment safety. | -| `package_install.npm` | Exercises package-manager bypass, material evidence, lifecycle risk, and supply-chain regression. | Payment semantics, wallet custody, or paid-HTTP proof. | -| preview deploy / repo write | Future reference profiles for cloud/repo mutation paths. | Nothing until an installed gateway path exists. | - -x402 is the best local APS profile because payment consequence is obvious and -gateway custody is testable. It must remain a proof profile, not the product -center. - -## Current architecture snapshot - -The old APS draft had several blockers that are now false. Current source state: - -- Protocol version is `0.2.4`. -- `/v0.2/action-contracts` requires `runtime_evidence` custody. -- Runtime execution, generated graph, tool-call draft, and intent compilation - routes require `runtime_evidence` custody. -- Policy decisions, isolation, breaker decisions, recovery records, and receipt - exports are `control_plane` custody. -- Bypass probes, protected-path posture, gateway checks, and downstream - reconciliation are `gateway_custody`. -- Review artifacts and review decisions are `review_custody`. -- Evidence projections are readable by `review_custody` and `runtime_evidence`; - reads are redacted diagnostics, not authority. -- `ProtectedActionMetadata`, `ProtectedActionRequest`, - `ProtectedActionChallenge`, and `ProtectedActionEvidenceProjection` exist as - non-authority representation schemas. -- Runtime ingress supports wrapped/raw/ambiguous package-install and x402 - dispatch observations. -- The local x402 D1/HTTP proof profile covers proposal, policy, gateway check, - wallet signature after admission, replay refusal, parameter mismatch refusal, - and proof gap recording. -- `AuthorityCertificate` exists as a local terminal-evidence export. It is not - hosted trust, JWKS, revocation, provider custody, or cross-org clearing. - -## Custody matrix - -| Surface | Current custody holder | APS rule | -| --- | --- | --- | -| Tool/action/gateway catalog registration | `control_plane` | Operator/setup only. Never agent-facing authority. | -| Operating envelope registration | `control_plane` | Authorizes attempts, not mutation. | -| Runtime execution evidence | `runtime_evidence` | Agent/runtime may record what generated code attempted. | -| Generated execution graph | `runtime_evidence` | Evidence only; not permission. | -| Tool-call draft creation/transition | `runtime_evidence` | Captures generated dispatch state before contract. | -| Intent compilation | `runtime_evidence` | Emits candidate/refusal boundary; never permission. | -| Action contract proposal | `runtime_evidence` | Produces proposed exact contract; never greenlight. | -| Policy decision / greenlight | `control_plane` | Machine decision layer; greenlight is one-use and gateway-bound. | -| Review artifact / review decision | `review_custody` | Human review evidence bound to exact digests; never gateway authority. | -| Bypass probe / path posture | `gateway_custody` | Gateway-owned protected-path evidence. | -| Gateway check | `gateway_custody` | Final enforcement point before mutation. | -| Surface operation reconciliation | `gateway_custody` | Downstream observation only; no fresh authority. | -| Evidence projection reads | `review_custody` or `runtime_evidence` | Redacted reconstruction only. | - -An APS agent must not be able to call install, policy, greenlight, gateway -check, reconcile, isolation, or receipt-export transitions. - -## The APS happy path - -```text -operator/control_plane: - register tool catalog, action catalog, gateway registry, envelope - -gateway/gateway_custody: - record bypass probes and protected-path posture - -runtime/runtime_evidence: - observe generated x402 dispatch block - create runtime execution evidence - create generated execution graph - create/finalize tool-call draft - compile intent - propose action contract - -control_plane: - evaluate policy - record one-use greenlight or refusal - -gateway/gateway_custody: - verify exact greenlight binding - only then create wallet payment signature / mutation attempt - emit receipt or proof gap - reconcile downstream state if available - -runtime or reviewer: - read redacted evidence projections - optionally verify a local terminal AuthorityCertificate -``` - -The magical developer moment is not "the payment succeeds". It is seeing that -the agent can propose a paid action and read evidence, but the wallet signature -only appears after gateway admission against the exact contract. - -## Developer target - -Primary persona: runtime or gateway engineer integrating Handshake into an -engineering-agent stack. - -Their job is not to become a Handshake protocol expert. Their job is: - -```text -wrap one consequential path --> observe generated dispatch --> propose exact contract --> let policy/gateway own authority --> read reconstructable evidence -``` - -APS is successful when this engineer can explain four things without reading -internal state-machine code: - -1. What generated action was attempted. -2. Why the runtime could propose but not execute. -3. Where the gateway enforced exact authority. -4. What evidence survives if the action is refused, replayed, mismatched, or - downstream proof is missing. - -Target time-to-first-hard-proof for a future public flow: under 10 minutes from -clone/install to a local x402 contract, refusal/proof-gap, receipt timeline, and -terminal evidence verification. The current repo has tests and source APIs, not -yet that public developer command. - -## Public APS shape - -APS should expose four safe surfaces over the current kernel. - -| Surface | Purpose | Non-authority rule | -| --- | --- | --- | -| `ProtectedActionMetadata` | Tell an automated client what it may propose and what evidence/policy shape applies. | Must include `authorityCreated: false`, no greenlight, no gateway check, no mutation. | -| `ProtectedActionRequest` | External proposal envelope that compiles into runtime evidence and candidate action. | Must not bypass intent compilation or canonicalization. | -| `ProtectedActionChallenge` | Structured refusal/proof-gap navigation. | Must not negotiate authority or hide mutation ambiguity. | -| `ProtectedActionEvidenceProjection` / agent transaction envelope | Redacted reconstruction of graph, contract, receipt, idempotency, posture, and proof gaps. | Must never include raw internal records, mutation commands, secrets, or fresh authority. | - -`AuthorityCertificate` can be shown as an optional terminal evidence export once -there is a terminal receipt/refusal/proof-gap/isolation/recovery state. It must -not become a cross-org trust claim in APS. - -## Canonical local x402 request shape - -The APS x402 request should be a representation over the current adapter input, -not a new authority primitive: - -```json -{ - "schemaVersion": "0.2.4", - "tenantId": "tenant_demo", - "organizationId": "org_demo", - "createdAt": "2026-05-20T00:00:00.000Z", - "requestId": "req_x402_demo", - "metadataRef": "pam_x402_demo", - "principalIntentRef": "intent_upgrade_staging", - "generatedCodeOrSpecRef": "codeblock_x402_001", - "runtimeExecutionId": "runexec_001", - "generatedExecutionGraphId": "graph_001", - "generatedExecutionNodeId": "node_001", - "toolCallDraftId": "draft_001", - "actionClass": "x402_payment.exact", - "resourceRef": "x402:https://api.example.test/paid-report:base-sepolia:0xpayee", - "parameters": { - "endpointUrl": "https://api.example.test/paid-report", - "payee": "0xpayee", - "network": "base-sepolia", - "token": "USDC", - "atomicAmount": "1000", - "paymentRequirementsDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "facilitatorRef": "facilitator:local" - }, - "nonSecretParamsSummary": { - "endpointUrl": "https://api.example.test/paid-report", - "payee": "0xpayee", - "network": "base-sepolia", - "token": "USDC", - "atomicAmount": "1000", - "paymentRequirementsDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "facilitatorRef": "facilitator:local" - }, - "secretRefs": {}, - "idempotencyKey": "x402-payment:demo", - "evidenceRefs": ["evidence:x402-payment-required:aaaaaaaaaaaaaaaa"], - "requestedAt": "2026-05-20T00:00:00.000Z", - "authorityCreated": false, - "greenlightRef": null, - "gatewayCheckRef": null, - "mutationAttemptRef": null -} -``` - -The corresponding runtime dispatch observation is narrower and belongs to -runtime ingress: - -```json -{ - "principalIntentRef": "intent_upgrade_staging", - "generatedCodeOrSpecRef": "codeblock_x402_001", - "dispatchBoundaryRef": "runtime-adapter:demo", - "graphNonce": "nonce-demo-001", - "truncationStatus": "complete", - "unobservedRegionRefs": [], - "dispatches": [ - { - "dispatchKind": "wrapped_x402_payment", - "dispatchRef": "dispatch_x402_001", - "generatedCodeOrSpecRef": "codeblock_x402_001", - "dynamicToolConstructionDetected": false, - "lateBoundParameterRefs": [], - "retryOfDispatchRef": null, - "branchRef": null, - "loopIteration": null, - "endpointUrl": "https://api.example.test/paid-report", - "payee": "0xpayee", - "network": "base-sepolia", - "token": "USDC", - "atomicAmount": "1000", - "paymentRequirementsDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "facilitatorRef": "facilitator:local", - "evidenceRefs": ["evidence:x402-payment-required:aaaaaaaaaaaaaaaa"] - } - ], - "evidenceRefs": ["evidence:runtime-transcript:demo"] -} -``` - -These shapes can propose. They cannot evaluate policy, mint a greenlight, run a -gateway check, sign a payment, or mutate a protected surface. - -## Challenge shape - -APS must make refusal and proof gap first-class. Example: - -```json -{ - "schemaVersion": "0.2.4", - "tenantId": "tenant_demo", - "organizationId": "org_demo", - "createdAt": "2026-05-20T00:00:00.000Z", - "challengeId": "challenge_x402_amount_bound", - "phase": "compilation", - "actionContractRef": null, - "refusedObjectRef": "dispatch_x402_001", - "proofGapRef": null, - "reasonCode": "x402_amount_exceeds_call_bound", - "retryability": "terminal", - "commitState": "not_started", - "mutationAttempted": false, - "rawInternalRecordIncluded": false, - "evidenceRefs": ["evidence:x402-payment-required:aaaaaaaaaaaaaaaa"], - "nextStepKind": "recraft_request", - "authorityCreated": false, - "greenlightRef": null, - "gatewayCheckRef": null, - "mutationAttemptRef": null -} -``` - -If downstream payment confirmation is missing after a gateway-admitted attempt, -the challenge/projection must say proof gap. It must not imply downstream -business success. - -## Hostile trace catalog - -APS must preserve these hostile cases as product-facing evidence, even if the -implementation uses existing tests underneath. - -| Case | Required APS outcome | Current anchor | -| --- | --- | --- | -| Agent tries to propose with `control_plane` token | Rejected as wrong custody; proposal is runtime evidence only. | `test/http/http.test.ts` | -| Agent tries to call policy/gateway routes | Rejected as wrong custody. | `test/http/http.test.ts` | -| Wrapped x402 call within bound | Produces runtime evidence and proposed contract only. | `test/runtime/runtime-ingress.test.ts` | -| x402 amount above `maxAtomicAmountPerCall` | Candidate refusal/challenge, no contract. | `src/adapters/x402-payment/action-proposal.ts` | -| Raw sibling x402 payment path | Refusal/challenge or bypass evidence, no greenlight. | `test/runtime/runtime-ingress.test.ts` | -| Ambiguous x402 dispatch | Refusal/challenge, no greenlight. | `test/runtime/runtime-ingress.test.ts` | -| Dynamic tool construction / late-bound parameter refs | Captured as uncertainty; must not silently contract. | `src/runtime/ingress/index.ts` | -| Gateway receives mismatched params | Refusal before wallet signature. | `test/integration/x402-d1-http.test.ts` | -| Greenlight replay | Rejected; no second mutation. | `test/integration/x402-d1-http.test.ts` | -| Downstream proof missing | Proof gap, not receipt theatre. | `test/integration/x402-d1-http.test.ts` | -| Evidence read attempts to expose internals | Redacted projection only. | `test/protocol/representation-contract.test.ts` | -| Terminal evidence certificate tampered | Verification fails. | `test/protocol/authority-certificate.test.ts` | - -## Plan-eng review - -Brutal verdict: keep the slice and narrow the claim. The product-level proof now -exists; the next work is a walkthrough over that proof before any CLI/MCP -surface. - -Execution concerns: - -- Do not build a new control plane for APS. -- Do not add a second x402 adapter path. -- Do not invent `prove:*` scripts that create new authority. A wrapper may only - run or explain the existing product proof. -- Do not expose policy, gateway, install, receipt export, or internal store - APIs to the agent. -- Do not let `ProtectedActionRequest` bypass runtime evidence or intent - compilation. -- Do not let evidence projection reads become raw record reads. -- Do not claim session/day/review spend-window enforcement. Current local - x402 bounds prove atomic amount per call. -- Do not claim hosted gateway custody, provider custody, JWKS, revocation, or - cross-org clearing. - -Completed implementation path: - -1. `test/product/agent-proof-slice.test.ts` stitches x402 runtime ingress, - proposal, policy, gateway, evidence projection, and terminal certificate - verification. -2. Runtime custody can propose and read redacted evidence only. -3. Gateway, policy, wallet, and certificate authority remain outside runtime - custody. -4. Mismatch, replay, raw sibling dispatch, and proof gap produce refusal, - challenge, or evidence, not fake receipts. -5. The next implementation surface may wrap that proof for developer - understanding, but it must not create a new mutation path. - -## Plan-devex review - -Brutal verdict: APS is understandable only if the first developer experience is -"watch authority stay out of the runtime", not "make an x402 payment". - -Developer-facing assets should be ordered like this: - -1. Existing source-owned product regression. -2. One-page local proof walkthrough over that regression. -3. One minimal read-only command wrapping that regression. -4. Optional MCP/SDK convenience after the proof is already stable. - -The first screen or walkthrough must show: - -- observed generated dispatch; -- exact action contract digest; -- policy outcome; -- gateway check outcome; -- payment signature or refusal/proof gap; -- redacted evidence projection; -- terminal certificate verification if terminal evidence exists. - -The walkthrough must not hide: - -- which custody role made each transition; -- that the agent never receives wallet/gateway authority; -- that evidence reads are not execution authority; -- that x402 is only the worked proof profile; -- that hosted/cross-org claims are future. - -## Acceptance tests - -The APS implementation should not duplicate every low-level invariant. It should -compose the source-owned tests into one product story. - -| Layer | Existing proof | APS status | -| --- | --- | --- | -| Route custody | `test/http/http.test.ts` | Covered for role boundaries; APS product proof additionally asserts runtime cannot use authority. | -| Runtime ingress | `test/runtime/runtime-ingress.test.ts` | Covered directly and composed through product proof. | -| x402 D1/HTTP | `test/integration/x402-d1-http.test.ts` | Covered directly; product proof shows signer evidence only after gateway check. | -| Representation | `test/protocol/representation-contract.test.ts` | Covered as non-authority shape; product proof uses redacted envelope projection. | -| Authority certificate | `test/protocol/authority-certificate.test.ts` | Covered directly and composed through product proof as local terminal evidence only. | -| Adapter-backed APS | `test/product/agent-proof-slice.test.ts` | Current product proof: x402 plus package-install parity share the same generic authority/evidence spine. | -| Claim boundary | `test/architecture/claim-boundary.test.ts` | Covered for local/per-call x402 and non-hosted, non-provider, non-cross-org language. | - -## Evidence requirements - -APS remains green only while the product-level proof leaves these reconstructable -references: - -- runtime execution id; -- generated execution graph id; -- tool-call draft id; -- intent compilation id; -- candidate action id or refusal/challenge id; -- action contract id when proposed; -- policy decision id; -- greenlight id only when policy admits; -- gateway check id only when gateway attempts; -- mutation attempt id only when mutation is attempted; -- receipt id when evidence is sufficient; -- proof gap id when evidence is missing or downstream state is ambiguous; -- terminal certificate id only for terminal evidence exports. - -Any missing link is either a refusal or a proof gap. It is not a TODO comment in -the receipt. - -## Product non-claims - -APS must explicitly refuse these claims: - -- "Handshake secures x402 payments" - false. It proves one local protected x402 - path. -- "Handshake is agent auth" - false. It separates principal authority, runtime - evidence, policy, and gateway custody. -- "The agent approved a payment" - false. The agent proposed an exact action; - policy and gateway admitted or refused it. -- "The receipt proves the business outcome" - false unless downstream evidence - exists and is bound. -- "The review screen authorized execution" - false unless it is bound to exact - contract/policy digests and the gateway enforces the greenlight. -- "The certificate proves ecosystem trust" - false in APS. Local terminal - certificate verification is not hosted trust or cross-org clearing. - -## Future surfaces after APS - -Only after the product-level APS proof remains green: - -- SDK wrapper for `ProtectedActionMetadata`, `ProtectedActionRequest`, - `ProtectedActionChallenge`, and redacted evidence projections. -- MCP read/propose surface that follows the v1 inventory and excludes install, - policy, gateway, and mutation tools. -- CLI wrapper for the local proof flow. -- Generic transaction-envelope projection across x402 and package-install. -- Hosted evidence navigation in Tier 3. -- Cross-org verification and clearing-house trust in Tier 4. - -## Current product proof - -`test/product/agent-proof-slice.test.ts` now proves the adapter-backed APS spine: - -```text -generated runtime dispatch --> adapter-specific proposal helper --> generic kernel authority chain --> adapter-owned gateway check --> receipt / refusal / proof gap --> redacted agent transaction envelope projection --> terminal AuthorityCertificate -``` - -The test keeps x402 as the worked proof profile, verifies raw bypass, -parameter-mismatch, replay, and proof-gap branches, and includes package-install -parity to prevent the product proof from becoming payment-specific. - -## Smallest next mechanism - -Add a first-protected-action walkthrough that wraps the product proof without -creating new authority surface: - -```text -run the APS product proof -inspect the generated dispatch, contract, gateway check, envelope, and certificate refs -show that runtime custody could propose/read evidence but could not install, policy, gateway, sign, mutate, or export -``` - -Do that before building any APS CLI, MCP surface, dashboard, hosted verifier, or -clearing-house language. diff --git a/.prettierignore b/.prettierignore index 346a145..8cd760e 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,4 @@ examples/x402-protected-spend/output examples/mcp-reference-transcript/output examples/self-hosted-activation/output examples/x402-protected-tool-profiles/output +examples/service-workflow-admission/output diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fdb583..b26c1fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,52 @@ public artifact repository. It does not claim hosted operation, provider custody, settlement finality, marketplace certification, MCP Registry discoverability, or Handshake authority from publication alone. +## 0.2.8 - 2026-05-29 + +### Added + +- Service-agent gating phase: operator and full tier architecture gates, + `check:service-agent-gating-phase` scripts, service-operator golden path and + bootstrap examples, dual-enforcement posture tests, and HTTP mutation-route + manifest gating. +- FailureClass taxonomy with registry-first derivation across HTTP transitions, + SDK role clients, and MCP failure surfaces. +- x402 gateway-held credential custody (Mechanism A): signer unreachable without + passed gateway check and gateway-resolved redacted evidence. +- Product coherence phase: unified readback spine, intent-compilation projection + rows, forbidden-copy lint, keel-integrity audit, and claim-boundary fixes + across CLI, SDK, and MCP surfaces. +- Service-operator and host-operator runbooks, integrator parity docs, and + persona golden paths under internal docs. + +### Changed + +- Renamed service-agent integration vocabulary to service-operator where + product surfaces describe Branch A bootstrap and maintenance flows. +- Root SDK re-export of role clients for one-import agent ergonomics without a + factory wrapper. +- Product launch gate and proof-packet fixtures track `0.2.8` as the current + package surface after Phase 04+05 land. + +### Boundary Notes + +- This release does not broaden authority. The public package remains proposal, + evidence, conformance, SDK, CLI, and local MCP distribution only. +- Service-agent gating proves structural dual enforcement and FailureClass + parity; it does not claim hosted operation, provider custody, or universal + agent governance. +- MCP Registry discoverability remains a proof gap until registry acceptance + and lookup are verified. +- Public npm availability does not create authority. + +### Release State + +- `ready_to_publish`: verified locally by repo gates and package projection. +- `actually_published`: pending npm trusted-publish workflow, npm registry + readback, registry signature metadata, provenance publication, and clean + installed-artifact smoke for `0.2.8`. +- `registry_discoverable`: pending MCP Registry acceptance and lookup. + ## 0.2.7 - 2026-05-25 ### Changed diff --git a/README.md b/README.md index a4737a7..5fd9d51 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Handshake Protocol Kernel +> **Doc type:** Explanation + Handshake is protected action infrastructure for automated decision making. This package is the installable protocol kernel, CLI, SDK, and local MCP proposal/evidence server for reducing one consequential automated action to an @@ -7,19 +9,39 @@ exact contract before mutation. Vague intent and generated code are not authority. A protected path requires an exact action contract, policy decision, one-use greenlight or refusal, gateway check before mutation, and receipt, refusal, replay refusal, proof gap, or -optional terminal AuthorityCertificate. Certificate is terminal evidence, not -permission. +optional terminal AuthorityCertificate. +Certificate is terminal evidence, not permission. -Category: protected actions for automated decision making; certificate is terminal evidence, not permission. +Category: protected actions for automated decision making, framed as **reconstructable clearance before consequence**. A service must be able to reconstruct clearance evidence before treating downstream consequence as proof. Certificates are terminal evidence, not permission. Core terms: a `cleared protected-action event` is one terminal event with -reconstructable evidence; the `protocol kernel` is the state machine and schema -set; a `product surface` is CLI, MCP, SDK, docs, demo, or service readback that -exposes proposal/evidence without creating authority. Public npm availability +reconstructable evidence; the `protocol kernel` is the only authority state +machine and schema set; a `product surface` is a projection/readback surface +such as CLI, MCP, docs, demo, or service readback that exposes +proposal/evidence without creating authority. Role-scoped protocol transition +clients, such as SDK policy or gateway clients, transport specific kernel +transitions under custody; they are not product authority surfaces. Public npm availability does not create authority. MCP Registry discoverability remains a proof gap until registry acceptance and lookup are verified. -Package: `handshake-protocol-kernel@0.2.7`. MCP name: +First-use product projection/readback surfaces should teach the service workflow as: + +```text +Present evidence bundle (readback only) +-> ServiceWorkflowAdmission (mapping only) +-> ServiceWorkflowHandle (correlation only) +-> Request reconstructable clearance for one protected action +-> Read outcome evidence +``` + +`ServiceWorkflowAdmission` means service-side accepted/refused/stale/proof-gap +mapping, not policy. `ServiceWorkflowHandle` means correlation and readback +context only, not permission. Each protected action still requires a fresh exact +action contract, policy decision, one-use greenlight or refusal, and gateway +check before mutation. Presentation bundles are evidence for readback — they do +not grant clearance by themselves. + +Package: `handshake-protocol-kernel@0.2.8`. MCP name: `io.github.CreasyBear/handshake-protocol-kernel`. Runtime: Node.js `>=20`. License: Apache-2.0. Published package repository form: package artifact repository, not source mirror. The published package repo contains package artifacts and trusted-publish @@ -45,6 +67,11 @@ handshake install health --cwd . handshake-mcp ``` +In service-workflow terms, these CLI commands prepare local/readiness evidence +before any fresh `ServiceWorkflowAdmission`, `ServiceWorkflowHandle`, or +Request Clearance; they do not create admission, handle, clearance, or outcome +authority. + These commands do not create policy decisions, greenlights, gateway checks, payment material, mutations, receipts, or certificates. They establish local proposal readiness only. @@ -75,7 +102,8 @@ and redacted evidence readback. The package root still exposes the lower-level `HandshakeClient`, but first-slice activation should teach role-scoped clients first. `InstallClient` performs one server-side setup commit, not hosted installation authority. `PolicyClient.evaluatePolicy()` evaluates one exact -action contract; it cannot perform the gateway check or mutate. +action contract through the protocol authority spine; it is not a product +surface, cannot perform the gateway check, and cannot mutate. Use `adapter-sdk` for third-party protected-action adapter packs and install-proposal shape review. It is definition-only: not an install client, not @@ -99,7 +127,20 @@ it uses real local MCP stdio proposal/evidence proof; `npm run demo:aps` writes `examples/x402-protected-spend/output/latest.md` and is not hosted operation, not broad x402 compatibility; `npm run demo:adapter-sdk` writes `examples/external-adapter-sdk/output/latest.md` and is not policy evaluation, -not gateway check, not mutation. +not gateway check, not mutation; +`npm run demo:service-workflow-admission` writes +`examples/service-workflow-admission/output/latest.md` and is admission readback +plus handle context only, not clearance or authority. + +Hosted admission lock: this service workflow simplification is not a +hosted-operation go-ahead. Hosted product work may consume projection/readback +surfaces only after the pre-hosted service workflow gates have source-owned +proof or explicit proof-gap posture. If hosted work needs hosted operation, +provider custody, +settlement/finality, marketplace or certification, cross-org trust, aggregate +spend enforcement, hosted org auth, retention/search, or new kernel exports, +route it to a separate hosted workspace or a new pre-hosted kernel task. Do not +expand protocol kernel exports for hosted needs without fresh proof gates. No adapter family defines the protocol. This package is not broad x402 compatibility, not live provider custody, hosted mutation authority, production @@ -113,11 +154,11 @@ payment-budget management is intentionally outside the current remit. Trusted Publishing: MCP Registry discoverability is now the remaining distribution launch blocker. -`0.2.7` npm availability is verified by registry readback, npm signature +`0.2.8` npm availability is verified by registry readback, npm signature metadata, GitHub Actions provenance publication, and clean installed-artifact smoke. Public npm availability still does not create authority. -Trusted Publishing workflow input: `expected_version = 0.2.7`. Release proof +Trusted Publishing workflow input: `expected_version = 0.2.8`. Release proof states: `ready_to_publish` means package shape and local gates passed; `actually_published` means npm publish and installed-artifact readback passed for the exact version; `registry_discoverable` means MCP Registry acceptance and diff --git a/STRUCTURE.md b/STRUCTURE.md index 3dc2a10..28c0ee8 100644 --- a/STRUCTURE.md +++ b/STRUCTURE.md @@ -6,9 +6,15 @@ Last structural audit: 2026-05-19. ## Product And Protocol Boundary -The protocol kernel is the source-owned state machine and schemas for exact contracts, policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, isolation, and terminal certificates. +The protocol kernel is the source-owned authority state machine and schemas for exact contracts, policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, isolation, and terminal certificates. -Product surfaces are the CLI, MCP, SDK, docs, demos, and service-facing readbacks that expose proposal/evidence/readback without creating authority. A cleared protected-action event is a specific terminal Handshake event with reconstructable evidence. The certificate is terminal evidence, not permission. +Product surfaces are projection/readback surfaces such as CLI, MCP, docs, +demos, and service-facing readbacks that expose proposal/evidence/readback +without creating authority. Role-scoped protocol transition clients, including +SDK policy and gateway clients, transport specific kernel transitions under +custody; they are not product authority surfaces. A cleared protected-action +event is a specific terminal Handshake event with reconstructable evidence. The +certificate is terminal evidence, not permission. Public npm availability does not create authority, and MCP Registry discoverability remains a proof gap until verified. `.planning/codebase/*` can inform source-map work, but tracked source, canonical docs, and current tests win when facts disagree. @@ -21,26 +27,26 @@ required quality/package/full-repo gates. ## Ownership Rules -| Path | Owns | Must Not Own | -| --------------------- | -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -| `src/protocol/` | Protocol primitives, state transitions, canonicalization, events, store port, navigation, public schemas and inputs. | HTTP transport, storage implementations, runtime wrappers, gateway fixtures, client ergonomics, hosted operation. | -| `src/http/` | Hono/Worker app, admission, route metadata, handlers, OpenAPI, HTTP errors, store resolution. | Protocol meaning, policy interpretation, mutation authority. | -| `src/runtime/` | Generated-execution evidence and action proposal helpers. | Policy decisions, greenlights, gateway checks, receipts, mutation attempts. | -| `src/adapter-sdk/` | Public adapter authoring definitions, install compiler contract refs, and install-proposal shape reports. | Runtime ingress registration, gateway binding, policy evaluation, credential custody, receipt export, mutation. | -| `src/adapters/` | Reference adapter profiles and gateway fixtures; mutation fixtures run only after a verified gateway check. | Storage internals, runtime authority, provider-side claims, identity-provider claims. | -| `src/conformance/` | Reference checks for protocol and gateway posture. | Hosted operation, standards claims, provider certification, mutation attempts. | -| `src/storage/` | Atomic record commits, stream offsets, D1, memory fixtures, KV cache plumbing. | Protocol meaning, route handling, SDK behavior. | -| `src/sdk/` | Typed client calls and response parsing. | Authority inference, mutation, storage, runtime wrappers. | -| `src/cli/` | Local command manifests, APS evidence rendering, conformance status, and certificate verification wrappers. | Process startup, policy evaluation, gateway checks, mutation commands, raw records, or credential custody. | -| `src/mcp/` | Model-facing proposal/evidence schemas, resource mappings, and pure runtime-client proposal bridge. | Process startup, policy evaluation, gateway checks, mutation commands, raw records, or credential custody. | -| `src/surfaces/` | Source-owned boundary manifests and shared non-authority outcomes for non-kernel product surfaces. | Protocol meaning, policy interpretation, route behavior, gateway authority, or public product claims. | -| `src/index.ts` | Curated package export surface. | Internal kernel/store objects or compatibility shims. | -| `src/experimental.ts` | Explicit reference adapter profile and gateway fixture exports. | Stable public API claims, provider enforcement claims, or standards certification claims. | -| `src/worker.ts` | Cloudflare Worker entrypoint wiring. | Protocol meaning, route behavior, or deployment policy. | -| `bin/` | Thin Node executable wrappers for bundled CLI and MCP package entrypoints. | Source logic, authority behavior, gateway custody, or mutation execution. | -| `server.json` | MCP Registry metadata for the local stdio proposal/evidence server. | Product claims, hosted operation, package publication proof, or protocol semantics. | -| `migrations/` | Canonical D1 schema for protocol storage. | Runtime behavior or product documentation. | -| `wrangler.toml` | Worker binding and deployment configuration. | Product claims or protocol semantics. | +| Path | Owns | Must Not Own | +| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `src/protocol/` | Protocol primitives, state transitions, canonicalization, events, store port, navigation, public schemas and inputs. | HTTP transport, storage implementations, runtime wrappers, gateway fixtures, client ergonomics, hosted operation. | +| `src/http/` | Hono/Worker app, admission, route metadata, handlers, OpenAPI, HTTP errors, store resolution. | Protocol meaning, policy interpretation, mutation authority. | +| `src/runtime/` | Generated-execution evidence and action proposal helpers. | Policy decisions, greenlights, gateway checks, receipts, mutation attempts. | +| `src/adapter-sdk/` | Public adapter authoring definitions, install compiler contract refs, and install-proposal shape reports. | Runtime ingress registration, gateway binding, policy evaluation, credential custody, receipt export, mutation. | +| `src/adapters/` | Reference adapter profiles and gateway fixtures; mutation fixtures run only after a verified gateway check. | Storage internals, runtime authority, provider-side claims, identity-provider claims. | +| `src/conformance/` | Reference checks for protocol and gateway posture. | Hosted operation, standards claims, provider certification, mutation attempts. | +| `src/storage/` | Atomic record commits, stream offsets, D1, memory fixtures, KV cache plumbing. | Protocol meaning, route handling, SDK behavior. | +| `src/sdk/` | Typed client calls and response parsing. | Authority inference, mutation, storage, runtime wrappers. | +| `src/cli/` | Local command manifests, APS evidence rendering, conformance status, and certificate verification wrappers. | Process startup, policy evaluation, gateway checks, mutation commands, raw records, or credential custody. | +| `src/mcp/` | Model-facing proposal/evidence schemas, resource mappings, and pure runtime-client proposal bridge. | Process startup, policy evaluation, gateway checks, mutation commands, raw records, or credential custody. | +| `src/surfaces/` | Source-owned boundary manifests, service workflow projection maps, and shared non-authority outcomes for product projection/readback surfaces. | Protocol meaning, policy interpretation, route behavior, gateway authority, reusable auth, or public product claims. | +| `src/index.ts` | Curated package export surface. | Internal kernel/store objects or compatibility shims. | +| `src/experimental.ts` | Explicit reference adapter profile and gateway fixture exports. | Stable public API claims, provider enforcement claims, or standards certification claims. | +| `src/worker.ts` | Cloudflare Worker entrypoint wiring. | Protocol meaning, route behavior, or deployment policy. | +| `bin/` | Thin Node executable wrappers for bundled CLI and MCP package entrypoints. | Source logic, authority behavior, gateway custody, or mutation execution. | +| `server.json` | MCP Registry metadata for the local stdio proposal/evidence server. | Product claims, hosted operation, package publication proof, or protocol semantics. | +| `migrations/` | Canonical D1 schema for protocol storage. | Runtime behavior or product documentation. | +| `wrangler.toml` | Worker binding and deployment configuration. | Product claims or protocol semantics. | ## Current Tree @@ -100,6 +106,7 @@ src/ surfaces/ boundary-manifest.ts outcome.ts + service-workflow-admission/ index.ts experimental.ts worker.ts @@ -186,6 +193,7 @@ docs/internal/protocol-kernel-architecture.md docs/internal/protocol-layman.md docs/internal/protocol-notes.md docs/internal/release-admin-runbook.md +docs/internal/service-workflow-story.md ``` Long planning reports, source studies, and historical prompts belong outside the active repo tree or under `docs/internal/archive` only when there is a reason to retain provenance. diff --git a/docs/internal/decisions.md b/docs/internal/decisions.md index faa892d..e039916 100644 --- a/docs/internal/decisions.md +++ b/docs/internal/decisions.md @@ -16,6 +16,7 @@ docs/internal/protocol-definition.md docs/internal/protocol-kernel-architecture.md docs/internal/protocol-layman.md docs/internal/protocol-notes.md +docs/internal/service-workflow-story.md ``` `.planning/` is scratch. Long plans, source studies, public-facing product docs, and historical prompts are not active repo truth. @@ -38,21 +39,51 @@ The category is protected actions for automated decision making. Builder-buyer product language centers on a cleared protected-action event: one specific terminal Handshake event with reconstructable evidence that a service can accept, refuse, or treat as a proof gap. +**Category claim (D-59):** *reconstructable clearance before consequence* — services must reconstruct clearance evidence before treating downstream consequence as proof. This is not an approval workflow, agent-permissions product, or audit-trail substitute. + +## Phase 05 product coherence (shipped) + +Accepted on branch `phase-05-product-coherence` (local close-out 2026-05-29). Phase 05 is a synthesis pass — not a new protocol mechanism layer. + +- **D-50:** Phase 05 unifies product surfaces and narrative; it does not add kernel transition semantics or new wedges. +- **D-51:** Comprehensive delivery scale (~14 plans) for scrub, polish, and keel integrity — not an MVP cut. +- **D-52:** Phase 05 execution required Phase 04 verification `status: passed` as a hard gate. +- **D-53:** Carry-forward integrity for the Phase-04 deferred lane (mutation manifest, HTTP profile conformance, dual-enforcement inventory, operator runbooks, D-25 scaffolds). +- **D-54:** D-25 per-customer bypass scaffolds remain honestly incomplete — no inflated claims for un-onboarded customers. +- **D-55:** CLI, SDK, and MCP evidence readback routes through the same live-fetch spine (`OperationReadbackProjection` keyed by `actionContractId`). +- **D-56:** One-import agent ergonomics via root re-export of role clients from `src/index.ts` (no `createHandshakeClients()` factory). +- **D-57:** Intent-compilation stages appear in the readback spine as non-authority projection rows (`createsAuthority: false`). +- **D-58:** Correlation index is read-only evidence keyed by `actionContractId`; it does not create authority. +- **D-60:** Forbidden-copy lint is structural: canonical docs and CLI copy must not leak category-drift vocabulary without explicit negation or non-authority windows. +- **D-61:** Diataxis coverage labels apply to internal docs; Phase 05 adds persona golden paths, not a full doc rewrite mandate. +- **D-62:** Concierge demand-test scaffold lives only under `.planning/macro/` — quarantined from package scripts, exports, and CI. +- **D-63:** Keel-integrity audit (`05-KEEL-AUDIT.md`) records each claimed invariant with a structural site, architecture-test pin, or honest proof-gap label (D-70). +- **D-64:** Mechanism A — x402 gateway-held credential custody (see section below); signer unreachable without passed gate + gateway-resolved redacted evidence. +- **D-65:** Gateway invariant architecture tests promote only after the structural custody site exists (05-13 before 05-14 promotion). +- **D-66:** Agent-origin compilations require a generated execution graph refusal at `candidate-decision.ts` before contract authority is implied. +- **D-67:** Phase 05 does not replace Phase 04; it depends on Phase 04 landing first. +- **D-68:** Phase 05 does not add new wedge families or new kernel transitions. +- **D-69:** Narrative polish must not soften the category claim or reintroduce passport/approval/HITL framing in headlines. +- **D-70:** Keel audit rows require `file:line` citations; mis-mapped citations are proof-gap honesty failures, not enforcement failures. +- **D-71:** Hosted-admission consolidation remains re-export-only polish — no hosted workspace promotion from Phase 05. + Shared product/protocol vocabulary: -- `protocol kernel`: the source-owned state machine and schemas for exact contracts, policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, isolation, and terminal certificates. -- `product surface`: CLI, MCP, SDK, docs, demo, or service-facing readback surfaces that expose proposal/evidence/readback without creating authority. +- `protocol kernel`: the source-owned authority state machine and schemas for exact contracts, policy decisions, one-use greenlights, gateway checks, receipts, refusals, proof gaps, isolation, and terminal certificates. +- `product surface`: projection/readback surfaces such as CLI, MCP, docs, demos, or service-facing readbacks that expose proposal/evidence/readback without creating authority. +- `role-scoped protocol transition client`: an SDK or HTTP client that transports a specific kernel transition under custody. It is not a product authority surface and does not make product nouns authoritative. +- `ServiceWorkflowAdmission` and `ServiceWorkflowHandle`: non-authority product-surface records for presented evidence, service-side admission status, correlation, and readback context. They do not create identity, policy decisions, greenlights, gateway checks, mutations, receipts, certificates, reusable auth, signer use, or spend approval; each protected action still requires a fresh exact action contract. - `AuthorityCertificate`: verifiable terminal evidence for one event. The certificate is terminal evidence, not permission, identity, settlement, hosted trust, or reusable auth. - Distribution is separate from authority. Public npm availability does not create authority, and MCP Registry discoverability remains a proof gap until verified. The current kernel centers on protected action control: ```text -exact action contract +CandidateAction / exact action contract -> exact policy decision --> one-use gateway-bound greenlight +-> one-use gateway-bound greenlight or refusal -> gateway check before mutation --> receipt, refusal, or proof gap +-> receipt, refusal, replay refusal, proof gap, or optional terminal certificate ``` The first official wedge is one buyer-side `x402_payment.exact` per-call @@ -191,20 +222,29 @@ adjacency to the protocol. Current ledger: -| Surface or claim | Current status | Boundary | -| ---------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------- | -| `x402_payment.exact` per-call path | locally proven for self-hosted package | Exact contract, policy, one-use greenlight, gateway check, receipt/readback. | -| Hosted operation | proof gap | Requires deployed tenant boundary, hosted custody, retention, and ops evidence. | -| Provider/customer gateway custody | proof gap beyond local/reference proof | Requires external custody proof, signer lease/rotation/revocation, and monitoring evidence. | -| Settlement/finality | proof gap | Downstream payment observation is not settlement finality. | -| Facilitator operation | outside current claim | First wedge consumes x402 evidence; it does not operate a facilitator. | -| Seller middleware | outside current claim | First wedge is buyer-side only. | -| Marketplace or certification | proof gap | Requires separate listing, rating, dispute, and trust evidence model. | -| Cross-org trust | proof gap | Local terminal certificates and pinned keys do not create portable trust. | -| Broad x402 compatibility | cut line | Only one buyer-side `exact` per-call path is admitted. | -| Aggregate spend enforcement | proof gap | Requires a policy-time and gateway-time aggregate ledger. | -| MCP Registry discoverability | proof gap until verified | Public npm availability and `server.json` metadata are distribution facts only. | -| Host-wide containment | cut line | Host profiles and raw sibling probes record posture, not native containment. | +| Surface or claim | Current status | configuredBy | Boundary | +| --- | --- | --- | --- | +| Gateway registry entry | locally proven (x402 triplet) | service_operator | Service catalog/install owns registry binding before host attestation. | +| Gateway credential custody | proof gap beyond local/reference | service_operator | External signer lease/rotation evidence required for production claims. | +| Adapter mutation enforcement | locally proven on x402 wedge | service_operator | Handler must call `adapter.run*Gateway` before downstream effect. | +| Trusted binding digests | locally proven (doctor attestation) | host_operator | Host doctor emits attestation evidence only — not identity or gateway ownership. | +| MCP proposal wiring | locally proven (reference MCP) | shared | Host runtime wiring + service registry digests must both be fresh. | +| Policy pack baseline | shared | shared | Service registers pack; host consumes policy version digests in bindings. | +| Hosted admission verifier | proof gap until deployed | service_operator | Tenant boundary + verifier config evidence required for hosted claims. | +| `x402_payment.exact` per-call path | locally proven for self-hosted package | service_operator | Exact contract, policy, one-use greenlight, gateway check, receipt/readback. | +| Hosted operation | proof gap | service_operator | Requires deployed tenant boundary, hosted custody, retention, and ops evidence. | +| Provider/customer gateway custody | proof gap beyond local/reference proof | service_operator | Requires external custody proof, signer lease/rotation/revocation, and monitoring evidence. | +| Settlement/finality | proof gap | service_operator | Downstream payment observation is not settlement finality. | +| Facilitator operation | outside current claim | — | First wedge consumes x402 evidence; it does not operate a facilitator. | +| Seller middleware | outside current claim | — | First wedge is buyer-side only. | +| Marketplace or certification | proof gap | — | Requires separate listing, rating, dispute, and trust evidence model. | +| Cross-org trust | proof gap | — | Local terminal certificates and pinned keys do not create portable trust. | +| Broad x402 compatibility | cut line | — | Only one buyer-side `exact` per-call path is admitted. | +| Aggregate spend enforcement | proof gap | service_operator | Requires a policy-time and gateway-time aggregate ledger. | +| MCP Registry discoverability | proof gap until verified | shared | Public npm availability and `server.json` metadata are distribution facts only. | +| Host-wide containment | cut line | host_operator | Host profiles and raw sibling probes record posture, not native containment. | + +Standalone operator runbooks (`service-operator-runbook.md`, `host-operator-runbook.md`) are deferred post-execute; bilateral order lives in golden path docs for phase 04. Expansion admission requires a proposed second action family to name, in source and tests, all of the following before it can be called execution-ready: @@ -227,6 +267,120 @@ repo write, CI/deploy, cloud configuration, database/data-plane, marketplace, agent-management, or other protected actions remain proof contexts rather than execution-ready product surfaces. +## Hosted Admission Lock + +Accepted: pre-hosted product simplification is not a hosted-operation +go-ahead. + +Hosted product work may consume or extend the service workflow surface only +after the pre-hosted service workflow gates have source-owned proof or +explicitly accepted proof-gap posture. The current completed gates prove +non-authority admission/handle schema, active surface alignment, local example +readback, generated-agent misuse refusal, and one fresh `x402_payment.exact` +fixture gate. They do not prove hosted operation, provider/customer custody, +settlement/finality, marketplace or certification, cross-org trust, aggregate +spend enforcement, hosted org auth, retention/search, or hosted mutation +authority. + +If hosted work needs hosted operation, tenant/org auth, hosted custody, retention, +search, marketplace/certification, cross-org trust, aggregate spend, or new +protocol-kernel exports, route that work to a separate hosted workspace or a +new pre-hosted kernel task with its own generated execution shape, protected +action path, gateway authority holder, credential holder, bypass posture, +evidence path, proof-gap model, non-claims, and `npm run check:repo` proof. +That follow-on work must carry fresh proof gates. + +This checkout must not expand protocol kernel exports for hosted needs merely +because the service workflow product surface is now simpler. + +## Clerk-For-Agents Dual Enforcement + +Accepted: service-operator and agent-host integrations must treat **admission** +and **gateway check** as separate enforcement layers. Ingress middleware that +identifies callers and scopes transitions is not Handshake by itself. + +Request chain (Clerk-for-agents framing): + +```text +Request + -> http/admission (middleware: identity + transition scope) + -> kernel transitions (compile, propose, policy, gatewayCheck evidence) + -> service app handler (adapter.run*Gateway before mutation) + -> downstream effect +``` + +Per D-00: admission or ingress alone is advisory, not Handshake. Only an +adapter-wrapped `run*Gateway` (or equivalent gateway check) immediately before +protected mutation is enforcement. + +Per D-12: external PEP layers (Envoy, Kong, OPA, or similar) may sit in front as +deployment glue. Handshake still requires adapter-side observed-parameter +re-check against the exact greenlight before consequence. External PEP does not +replace the gateway check or create ambient mutation authority. + +The first runnable clearance wedge remains buyer-side `x402_payment.exact` +per-call protected action. Dual enforcement applies to any protected surface, +not payment-only integrations. + +### Product-completion gate `dual_enforcement_posture` (D-53) + +The `dual_enforcement_posture` gate in `src/surfaces/proof-packets/product-completion-contract.ts` +projects **incomplete** until structural architecture evidence exists: passing +`test/architecture/dual-enforcement-posture.test.ts` (Phase-04 plan **04-01**) and +mutation-manifest inventory at `src/http/mutation-route-manifest.ts` (Phase-05 plan **05-01**). +Admission middleware identifies callers and scopes transitions; it does **not** +authorize protected mutation. Admission alone is advisory — only adapter-wrapped +`run*Gateway` immediately before consequence is Handshake enforcement. + +## x402 Gateway-Held Credential Custody (Mechanism A) + +Accepted: the x402 payment signer holds **gateway-held credential custody**. The +signer is structurally unreachable without a passed `VerifiedGatewayCheck` and +gate-bound, redacted credential-resolution evidence. This is enforcement, not a +comment or naming posture. + +Mechanism A is enforced by `assertGatewayHeldSigningCommand` in +`src/adapters/x402-payment/wallet-gateway.ts`. It runs at two boundaries before +any signature: + +- the orchestration entry `runX402WalletGateway`, immediately before + `surface.signPayment`; and +- the official signing surface entry `createOfficialExactX402SigningSurface`'s + `signPayment`, so an integrator that constructs the official surface directly + still cannot bypass the check. + +The guard refuses unless the `X402PaymentSignatureCommand` carries: + +- `verifiedGate.gatewayCheckStatus === "passed"` with non-empty + `gateAttemptId` and `mutationAttemptId` (a forged or unfilled gate is refused); + and +- `credentialResolutionEvidence` that is gateway-resolved — `resultClass === + "used_by_gateway"`, `credentialMaterialIncluded === false`, + `redactionStatus === "redacted"` — and bound to the same gate by matching + `gateAttemptId`, `actionContractId`, and `greenlightId`. + +Raw caller-supplied credential references therefore cannot reach the signer: +only redacted refs that the gateway resolved against the verified gate are +admitted, and the emitted `credentialMaterialPosture: "gateway_held_redacted"` +is a structurally enforced invariant rather than a label. Bypass via a raw x402 +SDK outside the host-trusted path remains a **proof gap**, not enforcement — it +does not run this guard and produces no Handshake clearance evidence. + +This invariant is pinned by `test/architecture/x402-gateway-credential-custody.test.ts`, +promoted from adapter runtime patterns in the same landing per the +architecture-promotion rule (an architecture-level test is admitted only for a +structurally enforced invariant, never an advisory one). + +**Integrator migration note:** `X402PaymentSignatureCommand` is unchanged — the +guard is additive and ABI-stable (no shape change, no new required field beyond +the already-present `verifiedGate` and `credentialResolutionEvidence`). +Integrators that route through `runX402WalletGateway` or the official signing +surface need no code change. Integrators that previously constructed signing +commands by hand must supply a real passed `VerifiedGatewayCheck` and +gateway-resolved redacted resolution evidence bound to that gate; hand-rolled +commands with empty gate ids, unbound evidence, or +`credentialMaterialIncluded: true` now refuse before signing. + ## Market And Expansion Scoring Boundary Accepted: market scoring is strategy input, not enforcement proof. A wedge can @@ -353,7 +507,7 @@ through Handshake. Do not claim live paid execution, settlement finality, provider custody, or buyer-side production readiness from a 402 challenge alone. -Package provenance is now satisfied for `0.2.7` by the public artifact +Package provenance is now satisfied for `0.2.8` by the public artifact repository's trusted-publish workflow. The successful run published `handshake-protocol-kernel@0.2.7`, recorded npm registry integrity and signature metadata, produced GitHub Actions provenance, and passed clean @@ -369,7 +523,7 @@ This checkout is an internal TypeScript protocol kernel. It should not carry lon Accepted: the active repo canon is compact and internal. -Former ADR, plan, product, protocol, business, reference, audit, and spec subtrees are no longer active repo truth. Durable decisions move into this file only when they protect implementation boundaries. Protocol definition lives in `docs/internal/protocol-definition.md`. Kernel architecture and schema mapping live in `docs/internal/protocol-kernel-architecture.md`. Plain-English translation lives in `docs/internal/protocol-layman.md`. Compact implementation notes live in `docs/internal/protocol-notes.md`. Planning, marketing, source studies, and historical prompts belong outside the active repo tree. +Former ADR, plan, product, protocol, business, reference, audit, and spec subtrees are no longer active repo truth. Durable decisions move into this file only when they protect implementation boundaries. Protocol definition lives in `docs/internal/protocol-definition.md`. Kernel architecture and schema mapping live in `docs/internal/protocol-kernel-architecture.md`. Plain-English translation lives in `docs/internal/protocol-layman.md`. Compact implementation notes live in `docs/internal/protocol-notes.md`. The service workflow story lives in `docs/internal/service-workflow-story.md` as a product-surface translation only; it does not create authority. Planning, marketing, source studies, and historical prompts belong outside the active repo tree. ## Structural Decision @@ -522,6 +676,20 @@ marketplace certification, or host-wide containment. Readiness rows must remain `pre_contract`; `trusted_gateway_ready` means ready for the runtime facade, not authorized to mutate. +### Production acceptance custody matrix (configured-by) + +| Responsibility | configuredBy | Surface owner | Notes | +| --- | --- | --- | --- | +| gateway registry entry | service_operator | InstallClient / bootstrap | Atomic triplet; orphan without gateway refuses | +| gateway credential custody | service_operator | GatewayClient / wallet adapter | Signer held at gateway, not agent-exposed | +| adapter mutation enforcement | service_operator | Family adapters + handlers | `run*Gateway` before downstream mutation (D-24) | +| trusted binding digests | host_operator | `handshake host doctor` | Attestation evidence only (D-23) | +| MCP proposal wiring | shared | MCP x402 proposal bridge | Parity with HTTP `failureClass`; no authority | +| policy pack baseline | service_operator | PolicyClient / bootstrap | Exact policy per action family | +| hosted admission verifier | shared | HTTP admission + service workflow | Ingress identifies callers; not mutation authority | + +Do not claim hosted marketplace trust, cross-org federation, or registry discoverability as phase-04 proof. + The `./sdk/role-clients` subpath now includes a role-scoped `ControlPlaneClient` for delegated-authority lifecycle management. It accepts one control-plane credential and can register delegated authority refs or record diff --git a/docs/internal/developer-experience-index.md b/docs/internal/developer-experience-index.md new file mode 100644 index 0000000..4d5dd3c --- /dev/null +++ b/docs/internal/developer-experience-index.md @@ -0,0 +1,69 @@ +# Developer Experience Index + +> **Doc type:** Reference + +Single entry for operator onboarding. Service API gating is the primary buyer +path; host-operator commands apply only when you operate MCP/runtime binding. + +## Start Here — Persona golden paths + +| Persona | Golden path | Boundary | +| ------- | ----------- | -------- | +| Agent / integrator | [golden-paths/agent-golden-path.md](./golden-paths/agent-golden-path.md) | Root import, compile→contract spine, `handshake evidence fetch` | +| Service operator | [golden-paths/service-operator-golden-path.md](./golden-paths/service-operator-golden-path.md) | Dual enforcement, bootstrap, links service runbook | +| Auditor / reviewer | [golden-paths/auditor-golden-path.md](./golden-paths/auditor-golden-path.md) | Readback + correlation index; proof-gap honesty | + +Legacy long-form operator narrative (Step 3 fork): + +→ [service-operator-golden-path.md](./service-operator-golden-path.md) + +## Operator runbooks (maintenance) + +| Doc | Boundary | +| --- | -------- | +| [service-operator-runbook.md](./service-operator-runbook.md) | Service API lane: dual enforcement, mutation manifest, completion gates | +| [host-operator-runbook.md](./host-operator-runbook.md) | Host lane: doctor/quickstart/simulate; non-authority only | + +## Service operator commands (first) + +| Command | Purpose | +| ------- | ------- | +| [service-operator-golden-path.md](./service-operator-golden-path.md) | Primary TTHW narrative | +| `npm run demo:service-workflow-admission` | Canonical service-side admission demo | +| `handshake service bootstrap` | Atomic x402 catalog install (control-plane) | + +Operator-visible HTTP failures (`failureClass`, status discipline, safe retry): +see the failure table in [service-operator-golden-path.md](./service-operator-golden-path.md#operator-visible-failures). + +Vocabulary: [service-workflow-story.md](./service-workflow-story.md) + +## Host operator commands (only if you operate the host) + +| Command | Purpose | +| ------- | ------- | +| [host-golden-paths-and-trace-guidance.md](./host-golden-paths-and-trace-guidance.md) | MCP/runtime host path | +| `handshake host doctor` | Host readiness attestation (non-authority) | +| `handshake quickstart x402` | Runnable x402 proposal spine | +| `handshake simulate x402-payment` | Simulated clearance readback | +| `handshake quickstart agent-spine` | Optional recommended sequencer (plan 04) | + +Host branch is required only when you operate MCP/runtime binding — not for +every service operator. + +## Agent SDK quick import (one-import ergonomics, D-56) + +```typescript +import { PolicyClient, EvidenceClient, explainHandshakeError } from "handshake-protocol-kernel"; +``` + +For precision or smaller bundles, use the subpath: `handshake-protocol-kernel/sdk/role-clients`. + +## Advanced (not first session) + +- [integrator-parity-transitions.md](./integrator-parity-transitions.md) — integrator parity transition appendix; defer until after golden path + +## Canonical internal docs + +- [decisions.md](./decisions.md) — product and protocol boundaries +- [protocol-layman.md](./protocol-layman.md) — plain-English protocol guide +- [protocol-notes.md](./protocol-notes.md) — compact implementation notes diff --git a/docs/internal/golden-paths/agent-golden-path.md b/docs/internal/golden-paths/agent-golden-path.md new file mode 100644 index 0000000..dde7bf7 --- /dev/null +++ b/docs/internal/golden-paths/agent-golden-path.md @@ -0,0 +1,45 @@ +# Agent Golden Path + +> **Doc type:** How-to + +Agent hosts and integrators run the authority spine without treating readback as +permission. Handshake is **reconstructable clearance before consequence** — not +agent auth, tracing, or an approval workflow. + +## One-import ergonomics (D-56) + +```typescript +import { PolicyClient, GatewayClient, EvidenceClient } from "handshake-protocol-kernel"; +``` + +For smaller bundles: `handshake-protocol-kernel/sdk/role-clients`. + +## Authority spine (labels only) + +```text +Standing Bounds → Delegated Mandate (when required) +→ Intent compilation (readback stage; non-authority) +→ Candidate action (readback stage; non-authority) +→ Compile → Work Order → Policy → Greenlight or refusal +→ Gateway check before mutation → Outcome +``` + +Intent compilation and candidate-action stages appear in operation readback only. +They do not create greenlights or gateway passes. + +## Runnable readback + +After you have an `actionContractId`: + +```bash +handshake evidence fetch --contract-id --base-url https://your-handshake-host +``` + +Uses the canonical HTTP readback route +`/v0.2/evidence/operations/:actionContractId/readback`. Readback does not issue +clearance. + +## Next docs + +- [protocol-layman.md](../protocol-layman.md) — plain-English spine +- [integrator-parity-transitions.md](../integrator-parity-transitions.md) — integrator parity appendix diff --git a/docs/internal/golden-paths/auditor-golden-path.md b/docs/internal/golden-paths/auditor-golden-path.md new file mode 100644 index 0000000..6465ae7 --- /dev/null +++ b/docs/internal/golden-paths/auditor-golden-path.md @@ -0,0 +1,46 @@ +# Auditor Golden Path + +> **Doc type:** How-to + +Auditors and reviewers reconstruct what happened on a protected action without +treating readback surfaces as authority. Category claim: +**reconstructable clearance before consequence**. + +## Readback + correlation (read-only) + +For a known `actionContractId`: + +| Surface | HTTP route (evidence read roles) | +| ------- | -------------------------------- | +| Operation readback | `GET /v0.2/evidence/operations/:actionContractId/readback` | +| Correlation index | `GET /v0.2/evidence/operations/:actionContractId/correlation` | + +SDK: `EvidenceClient.getOperationReadbackProjection` and +`EvidenceClient.getOperationCorrelationIndex`. + +MCP: `handshake://evidence/operations/{id}/readback` and +`handshake://evidence/operations/{id}/correlation`. + +CLI: + +```bash +handshake evidence fetch --contract-id +``` + +## Proof-gap-as-refusal pattern + +When policy or gateway evidence is missing, treat the terminal posture as +**proof gap** or **refusal** — not as proof that downstream execution succeeded. +Gateway admission evidence is separate from downstream business outcome. + +## Non-claims + +- Readback does not issue greenlights. +- Correlation index links existing refs; it does not create authority. +- Compilation stages in readback (`intent_compilation`, `candidate_action`) are + provenance labels only. + +## Related docs + +- [protocol-layman.md](../protocol-layman.md) +- [service-workflow-story.md](../service-workflow-story.md) — Passport negation table diff --git a/docs/internal/golden-paths/service-operator-golden-path.md b/docs/internal/golden-paths/service-operator-golden-path.md new file mode 100644 index 0000000..721d0fc --- /dev/null +++ b/docs/internal/golden-paths/service-operator-golden-path.md @@ -0,0 +1,43 @@ +# Service Operator Golden Path + +> **Doc type:** How-to + +Service operators integrate Handshake on the API lane: dual enforcement (admission +middleware **and** gateway-before-mutation in handlers) plus honest product +completion gates. + +## Start here + +Primary narrative: [service-operator-golden-path.md](../service-operator-golden-path.md) + +Maintenance runbook: [service-operator-runbook.md](../service-operator-runbook.md) +(Phase 05 A4 — dual enforcement checklist, mutation manifest, `dual_enforcement_posture`) + +## Dual enforcement (non-negotiable) + +```text +http/admission (identity + transition scope) + + +adapter.run*Gateway before mutation (handler enforcement) +``` + +Admission alone does not authorize mutation. See `src/http/mutation-route-manifest.ts`. + +## Bootstrap commands + +```bash +handshake service bootstrap --cwd . +handshake host doctor # only when you also operate the host lane +``` + +## Evidence readback for operators + +```bash +handshake evidence fetch --contract-id +``` + +## Host lane (optional branch) + +If you operate MCP/runtime binding, continue in +[host-operator-runbook.md](../host-operator-runbook.md) and +[host-golden-paths-and-trace-guidance.md](../host-golden-paths-and-trace-guidance.md). diff --git a/docs/internal/host-golden-paths-and-trace-guidance.md b/docs/internal/host-golden-paths-and-trace-guidance.md new file mode 100644 index 0000000..b43f0cf --- /dev/null +++ b/docs/internal/host-golden-paths-and-trace-guidance.md @@ -0,0 +1,62 @@ +# Host golden paths and trace guidance + +Host-operator TTHW for MCP/runtime custody. Product vocabulary only — no authority +is created by doctor, quickstart, or simulate commands. + +## Service operator prerequisite (D-22) + +Before host attestation, the service side must register the gateway registry and +catalog triplet for the protected endpoint family. Complete Branch A bootstrap +first: + +- [service-operator-golden-path.md](./service-operator-golden-path.md) (Branch A) +- `handshake service bootstrap` or `examples/service-operator-bootstrap/run.ts` + +Host doctor attestation binds to those registry digests; it does not substitute +for service install. The host lane **does not own gateway registry** — registry +and gateway credential custody remain service-operator responsibilities (D-21). + +## Bilateral setup order (host lane, D-22) + +After service bootstrap completes: + +1. `handshake host doctor` — binding digest attestation (non-authority). +2. `handshake quickstart x402` — local probe and readiness scaffolding. +3. `handshake simulate x402-payment` — non-authority simulation output. + +Optional: `handshake quickstart agent-spine` (same three steps). Trusted binding +digests must match current service registry; stale digests fail closed. + +## Canonical host commands (primary) + +Run these discrete commands in order: + +```bash +handshake host doctor +handshake quickstart x402 +handshake simulate x402-payment +``` + +Each command returns `authorityCreated: false`, `greenlightCreated: false`, +`gatewayCheckPerformed: false`, and `mutationAttempted: false`. + +## Recommended convenience (optional) + +```bash +handshake quickstart agent-spine +``` + +Equivalent to the three canonical commands above. Not required for operator +product completion or service-only operators. + +## Doctor attestation (D-23) + +`handshake host doctor` emits `attestationDigest` and `bindingDigestInputs` as +evidence for binding checks. It is not a parallel identity system, hosted trust +anchor, or gateway readiness certification. + +## Trace guidance + +- Correlate host steps with service admission readback using workflow handles only. +- Simulation output is non-authority scaffolding — not a gateway check or mutation. +- Fresh clearance still requires a new exact action contract per call. diff --git a/docs/internal/host-operator-runbook.md b/docs/internal/host-operator-runbook.md new file mode 100644 index 0000000..b041a47 --- /dev/null +++ b/docs/internal/host-operator-runbook.md @@ -0,0 +1,48 @@ +# Host Operator Runbook + +Doc type: How-to + +Companion maintenance guide for Branch B host operators (Phase-04 plan `04-10`, D-22). +Host commands are non-authority scaffolding — they do not create ServiceWorkflowAdmission, +ServiceWorkflowHandle, clearance, policy decisions, greenlights, gateway checks, or mutations. + +## Start Here + +1. Complete service Branch A bootstrap first ([service-operator-golden-path.md](./service-operator-golden-path.md)). +2. Read [host-golden-paths-and-trace-guidance.md](./host-golden-paths-and-trace-guidance.md) for bilateral order. +3. Use this runbook when changing host doctor, quickstart, or simulate flows. + +## Canonical host commands + +```bash +handshake host doctor +handshake quickstart x402 +handshake simulate x402-payment +``` + +Optional sequencer: + +```bash +handshake quickstart agent-spine +``` + +Each command returns `authorityCreated: false`, `greenlightCreated: false`, +`gatewayCheckPerformed: false`, and `mutationAttempted: false`. + +## MCP / runtime custody notes + +- Host doctor emits binding digests for attestation — not a trust anchor. +- Quickstart and simulate are local scaffolding; they are not gateway checks. +- Registry and gateway credential custody remain service-operator responsibilities (D-21). + +## Trace guidance + +- Correlate host steps with service admission readback using workflow handles only. +- Fresh clearance still requires a new exact action contract per protected call. +- Stale registry digests fail closed against current service bootstrap. + +## Non-claims + +- Handshake does not create native host certification or live host config mutation. +- Host doctor does not substitute for service gateway registry install. +- Simulation output is not downstream business finality. diff --git a/docs/internal/integrator-parity-transitions.md b/docs/internal/integrator-parity-transitions.md new file mode 100644 index 0000000..3cfb6e2 --- /dev/null +++ b/docs/internal/integrator-parity-transitions.md @@ -0,0 +1,47 @@ +# Integrator parity transitions (appendix) + +> **Do not read in your first 30 minutes.** Service operators should follow [service-operator-golden-path.md](./service-operator-golden-path.md) Branch A first. Host operators use [host-golden-paths-and-trace-guidance.md](./host-golden-paths-and-trace-guidance.md). + +Integrator parity transitions are the bounded HTTP/SDK surface for integrators wiring Handshake into a service. They record evidence and clearance steps only — no bundled execute shortcut. + +## Progressive onboarding + +1. **Catalog triplet** — register `ToolCapability`, `ActionType`, `GatewayRegistryEntry`, and `OperatingEnvelope` (control plane). +2. **Atomic install** — `registerInstallProposalCompiledRecords` refuses orphan catalogs without a gateway registry entry ([service-operator-bootstrap](../../examples/service-operator-bootstrap/) recipe). +3. **Compile and propose** — `compileIntent` then `proposeActionContract` on runtime evidence role. +4. **Policy** — `evaluatePolicy` returns one-use greenlight or refusal (control plane). +5. **Gateway** — `gatewayCheck` then optional `reconcileSurfaceOperation` (gateway custody). + +Host doctor, quickstart x402, and simulate are **not** integrator parity kernel transitions — see the host golden path fork. + +## Integrator parity transition table + +| transitionId | phase | HTTP | SDK client + method | caller role | authority boundary | runnable in phase 04? | +| --- | --- | --- | --- | --- | --- | --- | +| registerToolCapability | catalog | POST /v0.2/catalog/tool-capabilities | ControlPlaneClient.registerToolCapability | control_plane | catalog availability only | yes | +| registerActionType | catalog | POST /v0.2/catalog/action-types | ControlPlaneClient.registerActionType | control_plane | catalog availability only | yes | +| registerGatewayRegistryEntry | catalog | POST /v0.2/catalog/gateways | ControlPlaneClient.registerGatewayRegistryEntry | control_plane | catalog availability only | yes | +| registerOperatingEnvelope | catalog | POST /v0.2/envelopes | ControlPlaneClient.registerOperatingEnvelope | control_plane | catalog availability only | yes | +| registerInstallProposalCompiledRecords | install_setup | POST /v0.2/install-proposals/compiled-records | InstallClient.registerInstallProposalCompiledRecords | control_plane | install setup evidence only | yes | +| registerDelegatedAuthorityRef | delegated_authority | POST /v0.2/delegated-authority-refs | ControlPlaneClient.registerDelegatedAuthorityRef | control_plane | delegated authority evidence only | yes | +| compileIntent | intent_compilation | POST /v0.2/intent-compilations | RuntimeClient.compileIntent | runtime_evidence | candidate evidence only | yes | +| proposeActionContract | action_contract | POST /v0.2/action-contracts | RuntimeClient.proposeActionContract | runtime_evidence | exact contract proposal only | yes | +| evaluatePolicy | policy | POST /v0.2/policy-decisions | PolicyClient.evaluatePolicy | control_plane | policy decision / greenlight only | yes | +| gatewayCheck | gateway | POST /v0.2/gateway-check-attempts | GatewayClient.gatewayCheck | gateway_custody | gateway check before mutation | yes (x402 wedge only) | +| reconcileSurfaceOperation | operation_lifecycle | POST /v0.2/surface-operation-reconciliations | GatewayClient.reconcileSurfaceOperation | gateway_custody | downstream observation only | yes (x402 wedge only) | + +**Proof-gap families (not runnable in phase 04):** auth.md and package-install adapter families have `runnable: false` — see [service-operator-golden-path.md](./service-operator-golden-path.md#proof-gap-list-not-runnable-in-phase-04). Only x402 install/clearance paths are honestly runnable. + +## Install triplet + HTTP profile + +Atomic install requires **ToolCapability**, **ActionType**, and **GatewayRegistryEntry** together. Orphan catalogs (capability/action without gateway) must refuse at install compile. Shared transport canonicalization lives in `src/adapters/http-profile/` (used by family adapters such as auth-md and x402). + +Runnable x402 triplet reference: [examples/service-operator-bootstrap/](../../examples/service-operator-bootstrap/). + +## Extended transitions (reference only) + +Negotiation sessions, recovery terminal conflict resolution, bypass probes, authority certificates, review artifacts, and generated execution graph transitions remain available on the HTTP surface but are **not** integrator parity requirements for phase 04 operator TTHW. + +## SDK walkthrough recipe + +See `test/sdk/role-clients-walkthrough.test.ts` for a mocked composition: InstallClient → ControlPlaneClient (delegated mandate) → RuntimeClient propose path → PolicyClient → GatewayClient, with distinct role credentials and idempotency keys per attempt. diff --git a/docs/internal/protocol-layman.md b/docs/internal/protocol-layman.md index 1981fc0..4048112 100644 --- a/docs/internal/protocol-layman.md +++ b/docs/internal/protocol-layman.md @@ -1,5 +1,7 @@ # Plain-English Protocol Guide +> **Doc type:** Explanation + Last plain-language protocol audit: 2026-05-21. This document translates `docs/internal/protocol-definition.md` and @@ -19,9 +21,11 @@ Handshake says: > exact work order, check that exact work order, make the real gate check the > pass before anything changes, and keep a record of what happened. -For a builder-buyer, the product outcome is a cleared protected-action event: a -specific terminal Handshake event with reconstructable evidence that a service -can accept, refuse, or treat as a proof gap. +For a builder-buyer, the category claim is **reconstructable clearance before +consequence**: a service must reconstruct clearance evidence before treating +downstream consequence as proof. The product outcome is a cleared protected-action +event — one specific terminal Handshake event with reconstructable evidence that +a service can accept, refuse, or treat as a proof gap. The protocol kernel is the source-owned machinery that records the exact work order, decision, pass, gate check, receipt/refusal/proof gap, and optional @@ -29,6 +33,62 @@ certificate. A product surface is the CLI, MCP, SDK, docs, demo, or service-facing readback that exposes proposal and evidence without creating authority. +## The Service Workflow Surface + +The simple service-facing story is: + +```text +Present evidence bundle (readback only) +-> ServiceWorkflowAdmission (mapping only) +-> ServiceWorkflowHandle (correlation only) +-> Request reconstructable clearance +-> Read outcome evidence +``` + +That story hides protocol detail from the user. It does not hide authority. + +`ServiceWorkflowAdmission` is the service's accepted, refused, stale, or +proof-gap mapping of that presented evidence. It is not a policy decision, +greenlight, gateway check, receipt, certificate, or mutation permission. + +`ServiceWorkflowHandle` is a workflow context reference the agent can carry for +correlation and readback. It is not a badge, bearer token, retry permission, +x402 payment approval, auth.md credential, gateway pass, or receipt export. + +The surface may carry these IDs: + +```text +passportPackageDigest +passportPresentationId +admissionId +serviceWorkflowHandleId +serviceWorkflowHandleDigest +``` + +Those IDs help reconstruct which bundle was shown and which workflow context was +used. They do not authorize action. Every protected action still starts with a +fresh exact work order. + +## The Agent Lane (Short Chain) + +For agent hosts and integrators, the same authority spine uses product vocabulary +without renaming schema exports: + +```text +Standing Bounds -> Delegated Mandate -> Compile -> Work Order -> Clearance -> Outcome +``` + +| Plain word | Protocol object | Does not mean permission because… | +| ----------------- | --------------------------------------------- | ---------------------------------------------------------------------- | +| Standing Bounds | `OperatingEnvelope` | It bounds attempt classes; policy and gateway still decide each event. | +| Delegated Mandate | `DelegatedAuthorityRef` | It records mandate evidence; it is not a greenlight or gateway pass. | +| Compile | `IntentCompilationRecord` / `CandidateAction` | It proposes; it does not authorize mutation. | +| Work Order | `ActionContract` | It is an exact commitment awaiting policy and gateway check. | +| Clearance | Policy + one-use greenlight + gateway check | Admission or middleware identity alone is not Handshake. | +| Outcome | Receipt / refusal / proof gap | It records what happened; it is not reusable auth. | + +Admission identifies callers. Only an adapter-wrapped gateway check before mutation is enforcement. Ingress-only posture is advisory, not Handshake. + ## The Work Order A vague request is not enough. diff --git a/docs/internal/protocol-notes.md b/docs/internal/protocol-notes.md index 6d7b0bc..e2f78b1 100644 --- a/docs/internal/protocol-notes.md +++ b/docs/internal/protocol-notes.md @@ -15,16 +15,43 @@ Handshake's category is protected actions for automated decision making. - Product language centers on the cleared protected-action event: one terminal Handshake event with reconstructable evidence that a service can accept, refuse, or treat as a proof gap. -- The protocol kernel is the source-owned state machine and schema set for exact - contracts, policy decisions, one-use greenlights, gateway checks, receipts, - refusals, proof gaps, isolation, and terminal certificates. -- A product surface is CLI, MCP, SDK, docs, demo, or service-facing readback that - exposes proposal/evidence/readback without creating authority. +- The protocol kernel is the source-owned authority state machine and schema + set for exact contracts, policy decisions, one-use greenlights, gateway + checks, receipts, refusals, proof gaps, isolation, and terminal certificates. +- A product surface is a projection/readback surface such as CLI, MCP, docs, + demo, or service-facing readback that exposes proposal/evidence/readback + without creating authority. +- Role-scoped protocol transition clients, including SDK policy and gateway + clients, transport specific kernel transitions under custody. They are not + product authority surfaces and do not make product nouns authoritative. +- The service workflow story is a projection/readback translation only: + `Passport -> ServiceWorkflowAdmission -> ServiceWorkflowHandle -> fresh +protected-action clearance -> terminal outcome`. Passport, admission, and + handle records are evidence/readback context; they are not identity, policy, + greenlight, gateway check, mutation permission, receipt export, terminal + certificate, or reusable auth. +- `PrincipalAgentLink` and `ServiceWorkflowContextRefs` are product projection + contracts, not protocol authority primitives. They may provide setup evidence + and proposal metadata, but they cannot approve spend, widen an envelope, + satisfy delegated authority, perform a gateway check, or replace a fresh + exact action contract. - The certificate is terminal evidence, not permission, identity, settlement, hosted trust, or reusable auth. - Public npm availability does not create authority. MCP Registry discoverability remains a proof gap until registry acceptance and lookup are verified. +- Hosted admission lock: service workflow simplification is not a + hosted-operation go-ahead. Hosted work may consume the surface only after the + pre-hosted service workflow gates have source-owned proof or proof-gap + posture. Hosted operation, provider custody, settlement/finality, marketplace + or certification, cross-org trust, aggregate spend enforcement, hosted org + auth, retention/search, or new kernel exports require a separate hosted + workspace or a new pre-hosted kernel task with fresh proof gates. +- Clerk-for-agents dual enforcement: admission identifies callers at the HTTP + middleware layer; adapter `run*Gateway` before mutation is the route-handler + enforcement point. Ingress-only posture is advisory, not Handshake. External + PEP (Envoy/Kong/OPA) is deployment glue only — adapter-side re-check against + the exact greenlight is still required. ## Required Separation @@ -115,6 +142,11 @@ Protocol areas may depend on foundation/events/context/store and other area publ - `catalog-envelope`: declared tool, action, gateway, and envelope records; catalog presence is not authorization. Envelopes may carry provider-neutral participant identity bindings, but those bindings are evidence-only links to the opaque principal/agent refs. - `delegated-authority`: redacted principal/agent/runtime/envelope/gateway scoped attempt-authority refs; registering a ref records bounds and evidence expectations only, and creates no policy decision, greenlight, gateway check, mutation authority, or receipt. Revocation and expiry are separate status-transition evidence that creates `authority_ref` isolation without mutating the original ref. - `credential-custody`: opaque gateway credential refs, redacted gateway custody proof packets, and post-gate resolution evidence; no provider clients or secret retrieval API. + Customer or provider gateway custody claims require official external + verification, current custody and resolver posture, time-bounded lease or + rotation evidence, attestation evidence, redaction success, and no raw + credential or payment material. Fixture-local custody remains local proof and + cannot satisfy `customer_gateway_evidence`. - `runtime-evidence`: generated execution evidence; evidence can propose but cannot authorize. - `generated-execution-graph`: normalized generated-code/spec evidence and action candidates. - `tool-call-draft`: opened, streaming, finalized, invalid, or abandoned generated tool-call input state. diff --git a/docs/internal/service-operator-golden-path.md b/docs/internal/service-operator-golden-path.md new file mode 100644 index 0000000..cd971c8 --- /dev/null +++ b/docs/internal/service-operator-golden-path.md @@ -0,0 +1,204 @@ +# Service Operator Golden Path + +Primary time-to-first-value (TTHW) for operators integrating Handshake on a +service API or agent host. This doc is product vocabulary and runnable spine +narrative only — it does not create authority. + +## Section 0 — Unified Operator Journey + +### 1. What Handshake is + +Handshake is protected action infrastructure for automated decision making. +It helps a service accept, refuse, and reconstruct a cleared protected-action +event: one terminal Handshake event with reconstructable evidence. + +Handshake is not agent auth, tracing, approvals, or compliance theatre. Every +consequential automated action becomes an exact action contract, receives policy +evaluation, passes a gateway check before mutation, and leaves a receipt, +refusal, or proof gap. + +### 2. Dual enforcement + +Two layers must both be true before a protected mutation is Handshake-enforced: + +```text +http/admission (middleware: identity + transition scope) + + +adapter.run*Gateway before mutation (route handler enforcement) +``` + +Ingress or admission alone is advisory, not Handshake. See +[decisions.md](./decisions.md) (Clerk-for-agents dual enforcement). + +### 3. Step 3 — Choose your custody role (fork) + +**Branch A — I operate the service API** (default; continue below) + +**Branch B — I operate the agent host (MCP/runtime)** → see +[host-golden-paths-and-trace-guidance.md](./host-golden-paths-and-trace-guidance.md). +Canonical host commands: `handshake host doctor`, `handshake quickstart x402`, +`handshake simulate x402-payment`. Optional convenience: +`handshake quickstart agent-spine` (recommended sequencer; not required for +service-only operators). + +--- + +## Branch A — Service Operator Path + +### Product chain (agent lane) + +```text +Standing Bounds → Delegated Mandate (when required) → Compile → Work Order → Clearance → Outcome +``` + +Schema-native mapping lives in [service-workflow-story.md](./service-workflow-story.md). + +### Progressive onboarding (default) + +Register the **catalog triplet** per endpoint family first: + +- `ToolCapability` +- `ActionType` +- `GatewayRegistryEntry` + +Then bind per-instance `OperatingEnvelope`, policy pack, and optional +`DelegatedAuthorityRef` at delegation or admission time. See plan 03 bootstrap +for atomic install. + +### Regulated exception (not default) + +Full day-one `OperatingEnvelope` plus policy pack for every agent is reserved +for **fixed-tenant / regulated** services only — not the default multi-agent +hosted path. + +| Posture | Default multi-agent hosted | Fixed-tenant / regulated | +| -------------------- | -------------------------- | ------------------------ | +| Catalog triplet | Required per family | Required per family | +| Day-one full envelope| No — per-instance bounds | Yes — standing bounds upfront | +| Delegated mandate | Per spend/delegation event | May be pre-provisioned | +| Proof expectation | x402 runnable wedge | Same; extra audit rows | + +### Atomic bootstrap (D-08) + +Register the x402 catalog triplet atomically via control-plane +`InstallClient.registerInstallProposalCompiledRecords` (control_plane credential +required on live workers): + +```bash +bun run examples/service-operator-bootstrap/run.ts +handshake service bootstrap +``` + +Optional input fixture path: + +```bash +handshake service bootstrap ./my-x402-install-input.json +``` + +**Success** (`outcome: compiled_records_registered`): `recordRefs` include +`toolCapabilityId`, `actionTypeId`, `gatewayRegistryEntryId`, `operatingEnvelopeId`, +plus `policyPackRef` / `policyPackVersion`. Authority flags remain false. + +**Refusal** (`outcome: install_proposal_refused`): `reasonCodes` explain compile or +setup refusal; no orphan catalog writes. + +Inspect artifact: `examples/service-operator-bootstrap/output/latest.json` + +Product tests: `test/product/service-operator-bootstrap.test.ts` + +### Bilateral setup order (D-22) + +Service operator lane runs first on Branch A: + +1. Register catalog triplet → atomic bootstrap (`handshake service bootstrap` or `examples/service-operator-bootstrap/run.ts`) +2. Confirm gateway registry readiness and policy pack refs in bootstrap output +3. Wire hosted admission verifier claims before exposing mutation routes +4. Bind each consequential handler to `adapter.run*Gateway` before downstream effect + +Host lane runs after registry digests exist: + +- `handshake host doctor` for binding attestation (non-authority) +- `handshake quickstart x402` / `handshake simulate x402-payment` for clearance rehearsal +- Optional: `handshake quickstart agent-spine` (recommended, not mandatory for operator sign-off) + +Stale gateway registry or policy pack drift blocks downstream host attestation. Use the [failure table](#operator-visible-failures) — do not retry clearance refusals as OAuth refresh. + +### Runnable clearance wedge (x402 only) + +Only **buyer-side `x402_payment.exact` per-call** is runnable in this phase. +auth.md, package-install, and registry discoverability remain proof-gap prose. + +### End-to-end service flow + +```text +verify caller → admission/handle → clearance (x402) → readback +``` + +1. **Verify caller** — present passport evidence; service returns admission (non-authority). +2. **Admission/handle** — carry workflow context for correlation only. +3. **Clearance** — fresh exact `ActionContract` → policy → one-use greenlight → gateway check. +4. **Readback** — receipt, refusal, or proof gap; admission readback is not a receipt. + +### Canon demo: service workflow admission + +```bash +npm run demo:service-workflow-admission +``` + +Inspect outputs: + +```text +examples/service-workflow-admission/output/latest.json +examples/service-workflow-admission/output/latest.md +``` + +In `latest.json`, confirm `authorityBoundary` flags: + +```text +createsAuthority: false +createsGreenlight: false +performsGatewayCheck: false +freshActionContractRequired: true +``` + +Follow the embedded x402 clearance cross-ref to +`examples/x402-protected-spend/output/latest.json` for the fresh protected-action +path (`ActionContract → PolicyDecision → Greenlight → GatewayCheck`). + +The demo proves admission/handle projection only until you wire your own gateway +adapter on Branch A routes. Product test anchor: +`test/product/service-workflow-admission.test.ts`. + +### Proof-gap list (not runnable in phase 04) + +| Family | Runnable in phase 04? | proofGaps (summary) | What to use instead | +| --- | --- | --- | --- | +| auth.md protected API | false | live gateway, admission packet, provider custody | x402 wedge + `src/adapters/http-profile/` module (plan 08); external-adapter-sdk checklist | +| package install | false | live gateway, composite admission, material evidence | x402 install triplet pattern via `handshake service bootstrap` | +| MCP Registry discoverability | false | registry acceptance, lookup proof | local MCP doctor only; npm publish is distribution not authority | + +Do not treat quickstart-shaped stub directories as clearance paths. The only runnable +clearance wedge in phase 04 is buyer-side `x402_payment.exact` per call. + +Forbidden operator language: "run the auth.md quickstart", "bootstrap package install clearance". + +### Operator-visible failures + +_Table filled by plan 05 (`failureClass` × HTTP status × safe retry × forbidden actions)._ + +| failureClass | HTTP | Safe retry? | Forbidden actions | What to run next | +| ------------ | ---- | ----------- | ----------------- | ---------------- | +| auth | 401 / 403 | No — fix bearer/custody token | Retry as OAuth refresh for clearance refusals | Re-run with correct role token; `handshake host doctor` on host lane | +| hosted_admission | 403 | No — fix hosted identity/config | Treat as mutation authority | Refresh hosted verifier claims; check [hosted readiness](/v0.2/hosted/readiness) readback | +| protected_action_refusal | 409 | No — craft new exact contract | Reuse greenlight or widen scope silently | SDK: new `proposeActionContract` + policy path; never refresh OAuth | +| proof_gap | 422 | After evidence repair only | Assume downstream success without receipt | SDK: resolve proof gap or read evidence projection; do not retry same mutation | +| replay_refusal | 409 | No — new idempotency key | Replay same greenlight | New contract + greenlight; inspect receipt `greenlightConsumptionStatus` | +| stale_admission | 409 | After re-admission | Continue with stale hosted identity | Re-issue hosted caller identity; check freshness window | + +OAuth BCP: clearance refusals (`protected_action_refusal`, `replay_refusal`, `proof_gap`) must **not** be retried as credential refresh. Read dedicated routes may return **200** with claim/readiness status; mutation refusals never masquerade as auth **403**. + +### Advanced (not first 30 minutes) + +- [integrator-parity-transitions.md](./integrator-parity-transitions.md) — integrator parity appendix +- [service-workflow-story.md](./service-workflow-story.md) — plain-language vocabulary +- [decisions.md](./decisions.md) — custody and expansion ledger diff --git a/docs/internal/service-operator-runbook.md b/docs/internal/service-operator-runbook.md new file mode 100644 index 0000000..11c4200 --- /dev/null +++ b/docs/internal/service-operator-runbook.md @@ -0,0 +1,58 @@ +# Service Operator Runbook + +Doc type: How-to + +Companion maintenance guide for Branch A service operators (Phase-04 plan `04-02`, D-22). +This runbook does not create authority, greenlights, gateway checks, or mutations. + +## Start Here + +1. Complete [service-operator-golden-path.md](./service-operator-golden-path.md) once. +2. Keep [service-workflow-story.md](./service-workflow-story.md) vocabulary when writing tickets. +3. Use this runbook when changing HTTP routes, adapter gateway enforcement, or product-completion gates. + +## Dual-enforcement checklist + +Before any protected mutation ships: + +- HTTP admission must scope the caller and transition (middleware). +- The adapter path must run a gateway check before mutation I/O. +- Admission success alone does **not** authorize mutation (see AGENTS.md). + +```text +http/admission (identity + transition scope) + + +adapter.run*Gateway before mutation (route handler enforcement) +``` + +## Mutation manifest maintenance + +Frozen POST inventory lives in `src/http/mutation-route-manifest.ts` (Phase-05 plan `05-01`). +When adding or renaming transition routes: + +1. Update `src/http/routes/transition-route-registry.ts` first. +2. Mirror the row in `mutation-route-manifest.ts` with `requiresAdapterGatewayCheck: true`. +3. Run `bun test test/architecture/http-handler-mutation-gating.test.ts`. + +Do not treat manifest rows as new surface families — `src/surfaces/boundary-manifest.ts` owns surface ownership. + +## Product-completion gate + +`dual_enforcement_posture` in product-completion readback audits structural dual enforcement. +Keep gate evidence honest: incomplete until architecture tests prove adapter + admission coupling. + +## Failure escalation + +| Symptom | Likely layer | Next step | +| ------- | ------------ | --------- | +| 401/403 on transition | Admission / custody | Verify role credential and transition scope | +| 409 policy_refused | Policy | Read refusal projection; do not retry same contract | +| 409 gateway_refused | Gateway check | Inspect gate attempt evidence before mutation | +| 422 proof_gap | Evidence gap | File proof gap; no silent retry | +| Protected mutation without gate | Adapter bypass | Fix adapter — admission cannot substitute | + +## Non-claims + +- Service workflow admission readback is not receipt evidence. +- This runbook does not certify marketplace readiness or cross-org trust. +- Manifest maintenance does not add POST routes by itself. diff --git a/docs/internal/service-workflow-story.md b/docs/internal/service-workflow-story.md new file mode 100644 index 0000000..7643751 --- /dev/null +++ b/docs/internal/service-workflow-story.md @@ -0,0 +1,176 @@ +# Service Workflow Story + +> **Doc type:** Reference + +This story is a product projection/readback surface over the existing protocol +authority spine. It makes the first-use path easier to understand, but it does +not create a new authority primitive or a peer product truth lane. + +## Passport is not permission (D-59) + +**Passport is not a passport for permission.** **Passport is not permission.** +**Show Passport is not authorization.** A +presented evidence bundle helps a service map admission and readback; it does +not substitute for policy evaluation, a one-use greenlight, or a gateway check +before mutation. See [decisions.md](./decisions.md) for the category claim +*reconstructable clearance before consequence*. + +## Plain Flow + +```text +Agent shows Passport +-> Service returns ServiceWorkflowAdmission +-> Agent carries ServiceWorkflowHandle +-> Agent requests Clearance for one protected action +-> Handshake records Outcome +``` + +The plain words map to the protocol this way: + +| Plain word | Meaning | Not allowed to mean | +| ------------------------ | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | +| Passport | Evidence package the agent presents. | Identity, trust, permission, spend approval, signer access, or reusable auth. | +| ServiceWorkflowAdmission | Service-side accepted, refused, stale, or proof-gap mapping of presented evidence. | Policy decision, greenlight, gateway check, receipt, certificate, or mutation permission. | +| ServiceWorkflowHandle | Non-authority workflow context reference for later proposals and readback. | Badge-as-bearer-token, tool permission, retry permission, x402 payment approval, auth.md credential, or gateway pass. | +| Clearance | Fresh exact protected-action path for one event. | Workflow-level permission. | +| Outcome | Receipt, refusal, replay refusal, proof gap, or terminal certificate after the event path. | Downstream business success or future permission. | + +## Non-Authority IDs + +The service workflow surface may carry these correlation and reconstruction +fields: + +```text +passportPackageDigest +passportPresentationId +admissionId +serviceWorkflowHandleId +serviceWorkflowHandleDigest +``` + +These fields identify what was presented, how the service handled it, and which +workflow context the agent is carrying. They do not create authority. Every +surface that exposes them must make the boundary explicit: + +```text +createsAuthority: false +createsPolicyDecision: false +createsGreenlight: false +performsGatewayCheck: false +permitsMutation: false +exportsReceipt: false +mintsTerminalCertificate: false +freshActionContractRequired: true +``` + +The source contract for carrying those five fields is +`ServiceWorkflowContextRefsSchema`. MCP may accept that object as proposal +metadata for one fresh x402 contract. SDK, HTTP, runtime, package-root, and +protocol-public surfaces must not accept that schema as permission or as an +authority shortcut unless a separate package-surface decision and proof gate +are opened. + +`PrincipalAgentLink` is also evidence-only. It may help a hosted service record +which principal scoped which agent for a tenant, organization, project, or +workspace. It is not a bearer credential, reusable auth, spend approval, policy +decision, greenlight, gateway check, receipt, or envelope-widening authority. + +## Protected Action Boundary + +A service can admit standing evidence into a workflow context. That is still +before protected action clearance. + +Every consequential event still needs: + +```text +CandidateAction +-> ActionContract +-> PolicyDecision +-> one-use Greenlight or Refusal +-> GatewayCheck before mutation +-> Receipt / Refusal / ReplayRefusal / ProofGap / AuthorityCertificate +``` + +If the gateway cannot enforce the exact greenlight before consequence, the path +is advisory, not Handshake. + +## Agent Lane (Parallel Projection) + +The **Agent lane** is a product vocabulary chain for agent hosts and integrators. +It maps plain words to schema-native protocol objects. Schema export names stay +unchanged; this section is additive cross-link only — it does not replace the +canonical state path in `protocol-definition.md`. + +```text +Standing Bounds +-> Delegated Mandate (when required) +-> Compile +-> Work Order +-> Clearance +-> Outcome +``` + +| Agent lane term | Schema-native object | Does not mean | +| ----------------- | --------------------------------------------- | ----------------------------------------------------------------------------- | +| Standing Bounds | `OperatingEnvelope` | Permission, mutation authority, or a reusable pass for future actions. | +| Delegated Mandate | `DelegatedAuthorityRef` | Greenlight, gateway check, spend approval, or signer access. | +| Compile | `IntentCompilationRecord` / `CandidateAction` | Policy decision, authority, or an executable contract. | +| Work Order | `ActionContract` | Ambient permission, plan approval, or a batch of unrelated mutations. | +| Clearance | Policy decision + one-use greenlight + gateway check before mutation | Admission alone, workflow handle carry-forward, or ingress middleware theatre. | +| Outcome | Receipt / refusal / proof gap / replay refusal / terminal certificate | Downstream business success or permission for the next action. | + +Every agent-lane projection that exposes workflow or compilation context must +carry the same non-authority boundary as the service workflow surface: + +```text +createsAuthority: false +createsPolicyDecision: false +createsGreenlight: false +performsGatewayCheck: false +permitsMutation: false +exportsReceipt: false +mintsTerminalCertificate: false +freshActionContractRequired: true +``` + +`OperatingEnvelope` is class-level attempt bounds, not permission (D-01). +`DelegatedAuthorityRef` is episodic mandate evidence, not a greenlight (D-02). +Compile output proposes candidates only (D-03). `ActionContract` is an exact +commitment, not execution authority (D-04). Clearance requires a gateway check +before mutation — admission or handle carry-forward alone is advisory, not +Handshake (D-00). + +## Recovery States + +| State | Meaning | Safe next move | +| -------------------- | ----------------------------------------------------------- | -------------------------------------------------------------- | +| `accepted` | The service recognizes the evidence for workflow context. | Create a fresh protected-action request when action is needed. | +| `refused` | The service rejects the evidence. | Replace evidence or abandon the workflow. | +| `stale` | A digest, expiry, metadata, or readiness reference drifted. | Reload current evidence. | +| `proof_gap` | The service cannot establish the claim. | Gather proof or keep the workflow blocked. | +| `quarantined` | Evidence or posture is unsafe. | Stop and isolate future attempts. | +| `clearance_required` | The handle exists, but event authority does not. | Create a fresh exact action contract candidate. | + +Refusal, proof gap, replay refusal, and support-bundle generation are not retry +permission. A new protected action requires a new exact contract. + +## Forbidden Shortcuts + +- Do not pass a workflow handle to a protected tool as permission. +- Do not put raw credentials, bearer tokens, private keys, x402 + `PaymentPayload`, or `PAYMENT-SIGNATURE` into Passport, Admission, or Handle. +- Do not treat an admission report as a receipt. +- Do not turn an `AuthorityCertificate` into a passport or badge. +- Do not let a rendered review summary substitute for the exact action contract. +- Do not claim hosted operation, provider custody, settlement finality, + marketplace trust, broad runtime containment, or cross-org trust from this + surface. +- Do not claim customer gateway custody from local fixture evidence. + `customer_gateway_evidence` requires official external verification, current + custody and resolver posture, lease/rotation or equivalent time-bounded + evidence, attestation evidence, redaction success, and no raw payment or + credential material. + +## Operator maintenance + +For day-two service API changes (mutation manifest, dual-enforcement checks, product-completion gates), use [service-operator-runbook.md](./service-operator-runbook.md). Host-side maintenance stays in [host-operator-runbook.md](./host-operator-runbook.md). diff --git a/examples/a2a-negotiated-x402-room/README.md b/examples/a2a-negotiated-x402-room/README.md new file mode 100644 index 0000000..01ed0ba --- /dev/null +++ b/examples/a2a-negotiated-x402-room/README.md @@ -0,0 +1,23 @@ +# A2A Negotiated x402 Room + +This local reference room exercises one buyer/seller negotiation over a single buyer-side `x402_payment.exact` protected action. + +The accepted agreement and obligation binding are evidence only. The policy greenlight is created only after the exact `ActionContract` is bound to the active agreement obligation, and the payment signer is invoked only after a passed gateway check. + +Generate the product readback: + +```sh +bun examples/a2a-negotiated-x402-room/generate.ts +``` + +Expected outputs: + +- `latest.json`: full support packet plus product readback. +- `latest.md`: customer/operator readback. +- `agent-handoff.md`: agent-executable handoff with source boundary, stop conditions, eval path, and non-claims. + +Evaluation: + +- `evaluation.md`: DX, AX, CX, CSO, and product scorecard for this local/reference slice. + +This example is local/reference evidence only. It does not claim marketplace operation, legal contract formation, escrow, settlement finality, reputation, cross-org trust, provider custody, reusable authority, or native-host containment. diff --git a/examples/a2a-negotiated-x402-room/agent-handoff.md b/examples/a2a-negotiated-x402-room/agent-handoff.md new file mode 100644 index 0000000..cb97a7c --- /dev/null +++ b/examples/a2a-negotiated-x402-room/agent-handoff.md @@ -0,0 +1,57 @@ +# Agent Handoff + +## Objective + +Inspect A2A protected-action readback for act_00000000-0000-4000-8000-000000000008 without creating authority. + +## Runtime Profile + +codex, mcp, x402, generic + +## Source Boundary + +- Use this readback packet as evidence only. +- Do not infer authority from an accepted agreement. +- Bind future mutations to a fresh exact ActionContract and gateway check. + +## Tool Contract + +- Read support packet fields and public readback fields. +- Do not request raw payment payloads, payment signatures, or credential material. +- Do not call signer or mutation tools unless a verified gateway check is present. + +## Protected-Action Boundary + +Agreement acceptance created authority: false +Gateway check remains final enforcement point: true +Downstream finality: unknown + +## Stop Conditions + +- Stop on missing obligation binding. +- Stop on agreement, params, selected payment requirement, endpoint, amount, or counterparty drift. +- Stop on readback assembly failure. +- Record downstream unknown as a proof gap or next action, not success. + +## Evaluation Path + +- bun test test/product/a2a-negotiated-x402-room.test.ts +- bun examples/a2a-negotiated-x402-room/generate.ts +- npm run quality:claims +- npm run quality:architecture + +## Non-Claims + +- marketplace operation (marketplace_operation) +- legal contract formation (legal_contract_formation) +- escrow (escrow) +- settlement finality (settlement_finality) +- reputation (reputation) +- cross-org trust (cross_org_trust) +- provider custody (provider_custody) +- reusable authority (reusable_authority) +- native host containment (native_host_containment) + +## Next Agent Step + +Resolve or preserve proof gaps before claiming success. diff --git a/examples/a2a-negotiated-x402-room/evaluation.md b/examples/a2a-negotiated-x402-room/evaluation.md new file mode 100644 index 0000000..81d2c53 --- /dev/null +++ b/examples/a2a-negotiated-x402-room/evaluation.md @@ -0,0 +1,55 @@ +# A2A Negotiated x402 Room Evaluation + +Scope: this scorecard evaluates the local/reference A2A negotiated x402 readback path only. It does not evaluate a production marketplace, live provider custody, legal agreement formation, settlement finality, or host-native containment (`native_host_containment`). + +## Scores + +| Lens | Score | Evidence | Remaining gap | +| ---- | -----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | +| DX | 9.1/10 | A developer can run `bun examples/a2a-negotiated-x402-room/generate.ts` and inspect `latest.json`, `latest.md`, and `agent-handoff.md` without importing test fixtures. | Fresh package-install walkthrough is not yet a separate published-package onboarding proof. | +| AX | 9.2/10 | `agent-handoff.md` gives runtime profile, source boundary, tool contract, protected-action boundary, stop conditions, eval path, next step, and machine-readable non-claims. | Host-specific generated-code containment remains a separate blocked proof. | +| CX | 9.1/10 | `latest.md` separates agreement evidence, obligation binding, one-use greenlight, gateway check, downstream unknown, proof gap, and redacted payment material. | There is no production customer UI or live external receipt finality proof in this slice. | + +## Ten-Star Ambition + +A ten-star version of this surface means a developer, agent, or operator can reconstruct the protected-action chain without reading internal source, guessing authority semantics, or trusting prose. + +- DX: one command produces a support packet, customer readback, and agent handoff with stable file names. +- DX: public package import posture exposes readback helpers without exposing kernel, signer, gateway, or mutation authority. +- DX: failure modes are named as proof gaps, refusals, or blocked evidence instead of generic demo failures. +- AX: the next agent receives source boundaries, allowed reads, forbidden material, stop conditions, and eval commands. +- AX: agreement acceptance is explicitly non-authority, so a generated program cannot treat negotiation as permission. +- AX: retries require a fresh exact contract and gateway check, not reuse of a greenlight. +- CX: the operator sees what was negotiated, what exact action was bound, what the policy greenlit, and what the gateway checked. +- CX: downstream uncertainty is visible as unknown/proof-gap evidence, not smoothed into success. +- CSO: raw payment payloads, signatures, and credential material are absent from readback outputs. +- Product: all non-claims stay visible: marketplace operation, legal contract formation, escrow, settlement finality, reputation, cross-org trust, provider custody, reusable authority, and native host containment (`native_host_containment`). + +## CSO And Product Review + +Threat: agreement acceptance is confused with authority. +Mechanism: `authorityBoundary.agreementAcceptanceCreatedAuthority` is false, the product readback repeats the boundary, and policy/gateway events remain separate. + +Threat: the readback leaks payment or credential material. +Mechanism: outputs include redaction posture and product tests reject `PAYMENT-SIGNATURE`, payment payload digests, and credential material. + +Threat: replay turns one greenlight into ambient authority. +Mechanism: the local room records a refused replay, customer readback says not to retry with the same greenlight, and tests assert the signer count stays at one. + +Threat: a public helper becomes an authority surface. +Mechanism: the public readback subpath projects support-packet evidence only and exports no `HandshakeKernel`, policy client, gateway checker, signer, or mutation runner. + +Threat: product language overclaims external operation. +Mechanism: the example and generated readbacks state local/reference scope and preserve non-claims for marketplace operation, legal contract formation, escrow, settlement finality, reputation, cross-org trust, provider custody, reusable authority, and native host containment (`native_host_containment`). + +## Validation Evidence + +- `bun examples/a2a-negotiated-x402-room/generate.ts` +- `bun test test/product/a2a-negotiated-x402-room.test.ts` +- `npm run quality:claims` +- `npm run quality:architecture` +- `npm run check:repo` + +## Brutal Verdict + +Keep, but keep it narrow. This slice is a product-grade readback and handoff path for one local/reference negotiated x402 protected action. It is not marketplace operation, not legal contract formation, not settlement finality, not provider custody, not reusable authority, and not native-host containment. diff --git a/examples/a2a-negotiated-x402-room/generate.ts b/examples/a2a-negotiated-x402-room/generate.ts new file mode 100644 index 0000000..9e77d2b --- /dev/null +++ b/examples/a2a-negotiated-x402-room/generate.ts @@ -0,0 +1,69 @@ +import { mkdir } from "node:fs/promises"; +import { dirname, join } from "node:path"; +import { format } from "prettier"; +import { + projectA2ANegotiationProductReadback, + renderA2ANegotiationAgentHandoff, + renderA2ANegotiationCustomerReadback, +} from "../../src/surfaces/a2a-negotiation-readback"; +import { localReferenceGeneratedAt, runNegotiatedX402Room } from "./local-reference-room"; + +const outputPath = join(import.meta.dir, "latest.json"); +const markdownOutputPath = join(import.meta.dir, "latest.md"); +const agentHandoffOutputPath = join(import.meta.dir, "agent-handoff.md"); + +export async function buildA2ANegotiatedX402RoomOutput() { + const room = await runNegotiatedX402Room(); + const productReadback = projectA2ANegotiationProductReadback(room.supportPacket); + return { + generatedAt: localReferenceGeneratedAt, + fixtureKind: "a2a_negotiated_x402_room", + contract: { + actionContractId: room.contract.actionContractId, + actionContractDigest: room.contract.actionContractDigest, + paramsDigest: room.contract.paramsDigest, + actionClass: room.contract.actionClass, + resourceRef: room.contract.resourceRef, + clearingEvidenceRefs: room.contract.clearingEvidenceRefs, + }, + authorityBoundary: { + acceptedAgreementCreatedPolicyDecision: false, + acceptedAgreementCreatedGreenlight: false, + acceptedAgreementPerformedGatewayCheck: false, + acceptedAgreementAttemptedMutation: false, + signerInvokedBeforeGatewayCheck: false, + gatewayCheckRemainsFinalEnforcementPoint: true, + }, + policy: { + decision: room.policy.decision.decision, + decisionReasonCode: room.policy.decision.decisionReasonCode, + greenlightId: room.greenlight.greenlightId, + greenlightMaxUses: room.greenlight.maxUses, + }, + gateway: { + firstOutcome: room.gatewayResult.outcome, + firstGateDecision: room.gatewayResult.gatewayCheck.gateAttempt.gateDecision, + firstMutationAttempted: room.gatewayResult.gatewayCheck.mutationAttempt !== null, + replayOutcome: room.replay.outcome, + replayReasonCode: room.replay.gatewayCheck.gateAttempt.gateDecisionReasonCode, + signerInvocationCount: room.surface.signatureCount(), + }, + supportPacket: room.supportPacket, + productReadback, + }; +} + +export async function writeA2ANegotiatedX402RoomOutput() { + const output = await buildA2ANegotiatedX402RoomOutput(); + const customerReadback = renderA2ANegotiationCustomerReadback(output.productReadback); + const agentHandoff = renderA2ANegotiationAgentHandoff(output.productReadback); + await mkdir(dirname(outputPath), { recursive: true }); + await Bun.write(outputPath, await format(JSON.stringify(output), { parser: "json" })); + await Bun.write(markdownOutputPath, await format(customerReadback, { parser: "markdown" })); + await Bun.write(agentHandoffOutputPath, await format(agentHandoff, { parser: "markdown" })); + return outputPath; +} + +if (import.meta.main) { + console.log(await writeA2ANegotiatedX402RoomOutput()); +} diff --git a/examples/a2a-negotiated-x402-room/latest.json b/examples/a2a-negotiated-x402-room/latest.json new file mode 100644 index 0000000..74893df --- /dev/null +++ b/examples/a2a-negotiated-x402-room/latest.json @@ -0,0 +1,211 @@ +{ + "generatedAt": "2026-05-26T00:00:00.000Z", + "fixtureKind": "a2a_negotiated_x402_room", + "contract": { + "actionContractId": "act_00000000-0000-4000-8000-000000000008", + "actionContractDigest": "sha256:c3d84e6eb55bf70b9b6dcbb432fdfe8731fe8e25e15f5f35b6b4c4fb3cc75c14", + "paramsDigest": "sha256:a00d76dbe83b6608ca9a779042166aed82bb6a30e0b6600a1c7b1737eec4493b", + "actionClass": "x402_payment.exact", + "resourceRef": "x402:base-sepolia:0xpayee:https://api.example.com/mcp/premium-context", + "clearingEvidenceRefs": { + "obligationRef": "obligation:x402-exact-call", + "counterpartyRef": "agent:seller" + } + }, + "authorityBoundary": { + "acceptedAgreementCreatedPolicyDecision": false, + "acceptedAgreementCreatedGreenlight": false, + "acceptedAgreementPerformedGatewayCheck": false, + "acceptedAgreementAttemptedMutation": false, + "signerInvokedBeforeGatewayCheck": false, + "gatewayCheckRemainsFinalEnforcementPoint": true + }, + "policy": { + "decision": "greenlight", + "decisionReasonCode": "policy_passed", + "greenlightId": "grn_00000000-0000-4000-8000-000000000020", + "greenlightMaxUses": 1 + }, + "gateway": { + "firstOutcome": "payment_signature_proof_gap", + "firstGateDecision": "passed", + "firstMutationAttempted": true, + "replayOutcome": "gateway_check_refused", + "replayReasonCode": "already_consumed", + "signerInvocationCount": 1 + }, + "supportPacket": { + "packetKind": "a2a_negotiation_support_packet", + "actionContractId": "act_00000000-0000-4000-8000-000000000008", + "actionContractDigest": "sha256:c3d84e6eb55bf70b9b6dcbb432fdfe8731fe8e25e15f5f35b6b4c4fb3cc75c14", + "paramsDigest": "sha256:a00d76dbe83b6608ca9a779042166aed82bb6a30e0b6600a1c7b1737eec4493b", + "actionClass": "x402_payment.exact", + "resourceRef": "x402:base-sepolia:0xpayee:https://api.example.com/mcp/premium-context", + "agreement": { + "linkedAgreementId": "linked_agreement_demo", + "agreementDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "agreementStatus": "active", + "obligationRef": "obligation:x402-exact-call", + "counterpartyRef": "agent:seller", + "evidencePosture": "local_evidence_only" + }, + "obligationBinding": { + "agreementObligationBindingId": "agreement_obligation_binding_demo", + "obligationRef": "obligation:x402-exact-call", + "actionContractDigest": "sha256:c3d84e6eb55bf70b9b6dcbb432fdfe8731fe8e25e15f5f35b6b4c4fb3cc75c14", + "paramsDigest": "sha256:a00d76dbe83b6608ca9a779042166aed82bb6a30e0b6600a1c7b1737eec4493b", + "counterpartyRef": "agent:seller" + }, + "negotiation": { + "negotiationSessionId": "negotiation_session_demo", + "acceptedOfferVersionId": "offer_version_1", + "acceptedNegotiationDecisionId": "negotiation_decision_accept_v1", + "acceptedOfferContentDigest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "partyRefs": ["agent:buyer", "agent:seller"] + }, + "lifecycle": { + "assemblyStatus": "assembled", + "assemblyReasonCode": null, + "assemblyReason": null, + "policyDecisionId": "pol_00000000-0000-4000-8000-00000000001f", + "policyDecision": "greenlight", + "greenlightId": "grn_00000000-0000-4000-8000-000000000020", + "gatewayCheckAttemptId": "gat_00000000-0000-4000-8000-00000000004a", + "mutationAttemptId": "mut_00000000-0000-4000-8000-00000000002d", + "receiptId": "rcp_00000000-0000-4000-8000-00000000004b", + "downstreamFinalityStatus": "unknown", + "proofGapIds": ["gap_00000000-0000-4000-8000-000000000040"], + "refusalIds": ["ref_5e2f7ad3fd8fa3f6bf9fb415b10b5485025435321ab3cc1c"] + }, + "authorityBoundary": { + "agreementAcceptanceCreatedAuthority": false, + "obligationBindingCreatedAuthority": false, + "policyMayCreateOneUseGreenlight": true, + "gatewayCheckRemainsFinalEnforcementPoint": true, + "downstreamSuccessClaimedByAgreement": false + }, + "redaction": { + "rawTranscriptIncluded": false, + "rawOfferTermsIncluded": false, + "paymentPayloadIncluded": false, + "paymentSignatureIncluded": false, + "credentialMaterialIncluded": false + } + }, + "productReadback": { + "readbackKind": "a2a_negotiation_product_readback", + "schemaVersion": "a2a.negotiation.readback.v1", + "status": "gateway_checked_downstream_unknown", + "actionContractId": "act_00000000-0000-4000-8000-000000000008", + "actionContractDigest": "sha256:c3d84e6eb55bf70b9b6dcbb432fdfe8731fe8e25e15f5f35b6b4c4fb3cc75c14", + "paramsDigest": "sha256:a00d76dbe83b6608ca9a779042166aed82bb6a30e0b6600a1c7b1737eec4493b", + "actionClass": "x402_payment.exact", + "resourceRef": "x402:base-sepolia:0xpayee:https://api.example.com/mcp/premium-context", + "negotiatedEvidence": { + "linkedAgreementId": "linked_agreement_demo", + "agreementStatus": "active", + "obligationRef": "obligation:x402-exact-call", + "counterpartyRef": "agent:seller", + "evidencePosture": "local_evidence_only" + }, + "protectedAction": { + "policyDecisionId": "pol_00000000-0000-4000-8000-00000000001f", + "policyDecision": "greenlight", + "greenlightId": "grn_00000000-0000-4000-8000-000000000020", + "gatewayCheckAttemptId": "gat_00000000-0000-4000-8000-00000000004a", + "mutationAttemptId": "mut_00000000-0000-4000-8000-00000000002d", + "receiptId": "rcp_00000000-0000-4000-8000-00000000004b", + "downstreamFinalityStatus": "unknown" + }, + "developerExperience": { + "targetTimeToHelloWorldMinutes": 5, + "runCommand": "bun examples/a2a-negotiated-x402-room/generate.ts", + "expectedOutputFiles": ["latest.json", "latest.md", "agent-handoff.md"], + "inspectFirst": [ + "authorityBoundary.agreementAcceptanceCreatedAuthority", + "protectedAction.gatewayCheckAttemptId", + "protectedAction.downstreamFinalityStatus", + "customerExperience.nextActions" + ], + "failureModes": [ + "missing agreement obligation binding becomes a proof gap", + "stale negotiation evidence is refused before greenlight", + "changed payment parameters are refused at the gateway before signer use", + "downstream finality unknown remains unknown, not success" + ] + }, + "agentExperience": { + "runtimeProfiles": ["codex", "mcp", "x402", "generic"], + "sourceBoundary": [ + "Use this readback packet as evidence only.", + "Do not infer authority from an accepted agreement.", + "Bind future mutations to a fresh exact ActionContract and gateway check." + ], + "toolContract": [ + "Read support packet fields and public readback fields.", + "Do not request raw payment payloads, payment signatures, or credential material.", + "Do not call signer or mutation tools unless a verified gateway check is present." + ], + "stopConditions": [ + "Stop on missing obligation binding.", + "Stop on agreement, params, selected payment requirement, endpoint, amount, or counterparty drift.", + "Stop on readback assembly failure.", + "Record downstream unknown as a proof gap or next action, not success." + ], + "recoveryPath": [ + "Re-run the readback generator to refresh local evidence.", + "Inspect proofGapIds and refusalIds before retrying.", + "Create a new exact ActionContract for any new mutation attempt." + ], + "evalPath": [ + "bun test test/product/a2a-negotiated-x402-room.test.ts", + "bun examples/a2a-negotiated-x402-room/generate.ts", + "npm run quality:claims", + "npm run quality:architecture" + ] + }, + "customerExperience": { + "headline": "A negotiated agreement was linked to one exact protected action; authority came only from policy and gateway checks.", + "verified": [ + "Agreement evidence linked_agreement_demo is recorded with status active.", + "Obligation binding agreement_obligation_binding_demo pins the exact action contract digest.", + "Policy created one-use greenlight grn_00000000-0000-4000-8000-000000000020.", + "Gateway check gat_00000000-0000-4000-8000-00000000004a is recorded before mutation evidence." + ], + "unknown": [ + "Downstream business finality is unknown.", + "Proof gaps remain: gap_00000000-0000-4000-8000-000000000040.", + "Payment signature material is redacted from the readback." + ], + "nextActions": [ + "Resolve or preserve proof gaps before claiming success.", + "Do not retry payment with the same greenlight." + ] + }, + "authorityBoundary": { + "agreementAcceptanceCreatedAuthority": false, + "obligationBindingCreatedAuthority": false, + "policyMayCreateOneUseGreenlight": true, + "gatewayCheckRemainsFinalEnforcementPoint": true, + "downstreamSuccessClaimedByAgreement": false + }, + "redaction": { + "rawTranscriptIncluded": false, + "rawOfferTermsIncluded": false, + "paymentPayloadIncluded": false, + "paymentSignatureIncluded": false, + "credentialMaterialIncluded": false + }, + "nonClaims": [ + "marketplace_operation", + "legal_contract_formation", + "escrow", + "settlement_finality", + "reputation", + "cross_org_trust", + "provider_custody", + "reusable_authority", + "native_host_containment" + ] + } +} diff --git a/examples/a2a-negotiated-x402-room/latest.md b/examples/a2a-negotiated-x402-room/latest.md new file mode 100644 index 0000000..c4933ad --- /dev/null +++ b/examples/a2a-negotiated-x402-room/latest.md @@ -0,0 +1,33 @@ +# A2A Negotiated Protected Action Readback + +A negotiated agreement was linked to one exact protected action; authority came only from policy and gateway checks. + +## Verified + +- Agreement evidence linked_agreement_demo is recorded with status active. +- Obligation binding agreement_obligation_binding_demo pins the exact action contract digest. +- Policy created one-use greenlight grn_00000000-0000-4000-8000-000000000020. +- Gateway check gat_00000000-0000-4000-8000-00000000004a is recorded before mutation evidence. + +## Unknown + +- Downstream business finality is unknown. +- Proof gaps remain: gap_00000000-0000-4000-8000-000000000040. +- Payment signature material is redacted from the readback. + +## Next Actions + +- Resolve or preserve proof gaps before claiming success. +- Do not retry payment with the same greenlight. + +## Non-Claims + +- marketplace operation (marketplace_operation) +- legal contract formation (legal_contract_formation) +- escrow (escrow) +- settlement finality (settlement_finality) +- reputation (reputation) +- cross-org trust (cross_org_trust) +- provider custody (provider_custody) +- reusable authority (reusable_authority) +- native host containment (native_host_containment) diff --git a/examples/a2a-negotiated-x402-room/local-reference-records.ts b/examples/a2a-negotiated-x402-room/local-reference-records.ts new file mode 100644 index 0000000..ae5cbee --- /dev/null +++ b/examples/a2a-negotiated-x402-room/local-reference-records.ts @@ -0,0 +1,174 @@ +import type { ActionContract } from "../../src/protocol/areas/action-contract"; +import type { + AgreementObligationBinding, + LinkedAgreement, + NegotiationDecision, + NegotiationOffer, + NegotiationSession, +} from "../../src/protocol/areas/negotiation"; +import { PROTOCOL_VERSION } from "../../src/protocol/public/schemas"; + +export const negotiationDigest = `sha256:${"a".repeat(64)}` as const; +const obligationDigest = `sha256:${"b".repeat(64)}` as const; +const createdAt = "2026-05-26T00:00:00.000Z"; + +export function futureIso(): string { + return "2026-06-26T00:00:00.000Z"; +} + +export function negotiationSession(overrides: Partial = {}): NegotiationSession { + return { + schemaVersion: PROTOCOL_VERSION, + tenantId: "tenant_demo", + organizationId: "org_demo", + createdAt, + negotiationSessionId: "negotiation_session_demo", + negotiationSessionDigest: negotiationDigest, + subjectResourceRef: "resource:x402:premium-context", + subjectProtectedActionContextRefs: ["candidate_action:candidate_demo"], + runtimePosture: "declared_runtime_context", + parties: [ + { + partyId: "party_buyer", + partyRole: "initiator", + agentRef: "agent:buyer", + organizationRef: "org:buyer", + runtimeRef: "runtime:codex", + endpointRef: null, + identityProofPosture: "host_verified_ref", + identityEvidenceRefs: ["identity-evidence:buyer"], + identityProofDigest: negotiationDigest, + proofGapRefs: [], + }, + { + partyId: "party_seller", + partyRole: "counterparty", + agentRef: "agent:seller", + organizationRef: "org:seller", + runtimeRef: "runtime:a2a", + endpointRef: "https://seller-agent.example.test", + identityProofPosture: "proof_gap_recorded", + identityEvidenceRefs: [], + identityProofDigest: null, + proofGapRefs: ["proof_gap:seller_identity"], + }, + ], + generatedCodeOrSpecRefs: ["generated_graph:x402-a2a-negotiation"], + declaredAssumptions: ["seller endpoint was imported from runtime evidence"], + uncertaintyMarkers: ["seller identity remains imported local evidence"], + externalProtocolEvidenceRefs: [], + clearingEvidenceRefs: { correlationRef: "a2a:task:x402-negotiation" }, + expiresAt: futureIso(), + ...overrides, + }; +} + +export function negotiationOffer(overrides: Partial = {}): NegotiationOffer { + return { + schemaVersion: PROTOCOL_VERSION, + tenantId: "tenant_demo", + organizationId: "org_demo", + createdAt, + negotiationOfferId: "negotiation_offer_v1", + negotiationSessionId: "negotiation_session_demo", + offerVersionId: "offer_version_1", + offerSequence: 1, + offeredByPartyId: "party_buyer", + previousOfferVersionId: null, + supersedesOfferVersionId: null, + offerContentDigest: negotiationDigest, + offerObjectRefs: ["object:x402-offer:v1"], + offerContentRefs: ["content:x402-offer:v1"], + proofGapRefs: [], + externalProtocolEvidenceRefs: [], + generatedCodeOrSpecRefs: ["generated_graph:x402-a2a-negotiation"], + declaredAssumptions: [], + uncertaintyMarkers: [], + clearingEvidenceRefs: { obligationRef: "obligation:x402-exact-call" }, + expiresAt: futureIso(), + ...overrides, + }; +} + +export function negotiationDecision(overrides: Partial = {}): NegotiationDecision { + return { + schemaVersion: PROTOCOL_VERSION, + tenantId: "tenant_demo", + organizationId: "org_demo", + createdAt, + negotiationDecisionId: "negotiation_decision_accept_v1", + negotiationSessionId: "negotiation_session_demo", + decidedOfferVersionId: "offer_version_1", + decidedOfferSequence: 1, + decidedByPartyId: "party_seller", + decision: "accept", + reasonCodes: ["offer_terms_accepted"], + evidenceRefs: ["evidence:decision:accept"], + proofGapRefs: [], + counterOfferVersionId: null, + decisionDigest: negotiationDigest, + ...overrides, + }; +} + +export function linkedAgreement(overrides: Partial = {}): LinkedAgreement { + return { + schemaVersion: PROTOCOL_VERSION, + tenantId: "tenant_demo", + organizationId: "org_demo", + createdAt, + linkedAgreementId: "linked_agreement_demo", + negotiationSessionId: "negotiation_session_demo", + acceptedNegotiationDecisionId: "negotiation_decision_accept_v1", + acceptedOfferVersionId: "offer_version_1", + acceptedOfferSequence: 1, + acceptedOfferContentDigest: negotiationDigest, + acceptedByPartyId: "party_seller", + counterpartyRef: "agent:seller", + agreementDigest: negotiationDigest, + agreementObjectRefs: ["object:x402-agreement:v1"], + agreementContentRefs: ["content:x402-agreement:v1"], + proofGapRefs: [], + agreementEvidencePosture: "local_evidence_only", + clearingEvidenceRefs: { obligationRef: "obligation:x402-exact-call", counterpartyRef: "agent:seller" }, + externalProtocolEvidenceRefs: [], + expiresAt: futureIso(), + ...overrides, + }; +} + +export function agreementBindingForContract( + contract: ActionContract, + overrides: Partial = {}, +): AgreementObligationBinding { + return { + schemaVersion: PROTOCOL_VERSION, + tenantId: contract.tenantId, + organizationId: contract.organizationId, + createdAt, + agreementObligationBindingId: "agreement_obligation_binding_demo", + linkedAgreementId: "linked_agreement_demo", + negotiationSessionId: "negotiation_session_demo", + obligationRef: "obligation:x402-exact-call", + obligationDigest, + actionContractId: contract.actionContractId, + actionContractDigest: contract.actionContractDigest, + paramsDigest: contract.paramsDigest, + actionTypeId: contract.actionTypeId, + actionClass: contract.actionClass, + resourceRef: contract.resourceRef, + counterpartyRef: "agent:seller", + maxUses: 1, + bindingPosture: "local_evidence_only", + localProtectedActionEvidenceRefs: [ + { + refKind: "action_contract", + ref: `action_contract:${contract.actionContractId}`, + digest: contract.actionContractDigest, + }, + ], + evidenceRefs: ["evidence:agreement-obligation-binding"], + proofGapRefs: [], + ...overrides, + }; +} diff --git a/examples/a2a-negotiated-x402-room/local-reference-room.ts b/examples/a2a-negotiated-x402-room/local-reference-room.ts new file mode 100644 index 0000000..6cbdf56 --- /dev/null +++ b/examples/a2a-negotiated-x402-room/local-reference-room.ts @@ -0,0 +1,390 @@ +import { + buildX402DelegatedSpendAuthorityRefInput, + buildX402WalletGatewayCredentialRefInput, + compileX402InstallProposal, + type X402InstallProposal, + type X402InstallProposalInput, + x402DelegatedSpendAuthorityBindingFor, + x402WalletGatewayCredentialBindingFor, +} from "../../src/adapters/x402-payment/install-proposal"; +import { requireInstallProposalGatewayRegistryEntry } from "../../src/install/install-proposal"; +import { proposeX402PaymentActionContract } from "../../src/adapters/x402-payment/action-proposal"; +import { + runX402WalletGateway, + type X402PaymentParameters, + type X402PaymentSignatureCommand, +} from "../../src/adapters/x402-payment/wallet-gateway"; +import { buildA2ANegotiationSupportPacket } from "../../src/surfaces/a2a-negotiation-support"; +import type { ActionContract } from "../../src/protocol/areas/action-contract"; +import type { GatewayCredentialRef } from "../../src/protocol/areas/credential-custody"; +import type { DelegatedAuthorityRef } from "../../src/protocol/areas/delegated-authority"; +import { digestCanonical } from "../../src/protocol/foundation/canonical"; +import { nowIso, withProtocolIdSource } from "../../src/protocol/foundation/ids"; +import { HandshakeKernel } from "../../src/protocol/kernel"; +import { requiredGatewayCheckedBypassProbeKinds } from "../../src/protocol/public/schemas"; +import { InMemoryProtocolStore } from "../../src/storage/memory"; +import { + agreementBindingForContract, + futureIso, + linkedAgreement, + negotiationDecision, + negotiationDigest, + negotiationOffer, + negotiationSession, +} from "./local-reference-records"; + +const digest = `sha256:${"c".repeat(64)}` as const; +const selectedPaymentRequirementDigest = `sha256:${"b".repeat(64)}` as const; +const obligationRef = "obligation:x402-exact-call"; +const counterpartyRef = "agent:seller"; +export const localReferenceGeneratedAt = "2026-05-26T00:00:00.000Z"; + +const x402CredentialRefs = new WeakMap(); +const x402AuthorityRefs = new WeakMap(); + +export async function createNegotiatedX402Greenlight() { + return withLocalReferenceProtocolIds(createNegotiatedX402GreenlightUnchecked); +} + +async function createNegotiatedX402GreenlightUnchecked() { + const store = new InMemoryProtocolStore(); + const kernel = new HandshakeKernel(store); + const proposal = await compileX402InstallProposal(validInstallInput()); + const records = requireCompiledRecords(proposal); + const gatewayRegistryEntry = requireInstallProposalGatewayRegistryEntry(records.gatewayRegistryEntry); + await kernel.putCatalogObject({ objectType: "tool_capability", payload: records.toolCapability }); + await kernel.putCatalogObject({ objectType: "action_type", payload: records.actionType }); + await kernel.putCatalogObject({ objectType: "gateway_registry_entry", payload: gatewayRegistryEntry }); + await kernel.putCatalogObject({ objectType: "operating_envelope", payload: records.operatingEnvelope }); + await registerX402WalletCredentialRef(kernel, proposal, records); + await registerX402DelegatedAuthorityRef(kernel, proposal, records); + + const runtimeResult = await proposeX402PaymentActionContract( + kernel, + x402RuntimeConfig(proposal, records, "run_x402_a2a_negotiation"), + { + principalIntentRef: "intent:a2a negotiated paid context", + generatedCodeOrSpecRef: "code:x402-a2a-fetch-wrapper", + endpointUrl: proposal.endpointEvidence.endpointUrl, + payee: proposal.endpointEvidence.payee, + network: proposal.endpointEvidence.network, + token: proposal.endpointEvidence.token, + atomicAmount: "2500", + paymentRequirementsDigest: proposal.endpointEvidence.paymentRequirementsDigest, + selectedPaymentRequirementIndex: 0, + selectedPaymentRequirementDigest, + paymentRequiredEvidenceRef: "evidence:x402-payment-required:a2a-room", + clearingEvidenceRefs: { obligationRef, counterpartyRef }, + }, + ); + if (runtimeResult.outcome !== "action_contract_proposed") throw new Error("expected x402 action contract"); + + await recordNegotiatedX402Agreement(kernel, proposal, runtimeResult.actionContract); + await recordGatewayCheckedPosture(kernel, proposal, records); + const policy = await kernel.evaluatePolicy({ + actionContractId: runtimeResult.actionContract.actionContractId, + envelopeId: records.operatingEnvelope.envelopeId, + signingSecret: "test-secret", + }); + if (!policy.greenlight) throw new Error(`expected x402 greenlight, got ${policy.decision.decisionReasonCode}`); + const surface = fakeSigningSurface("unknown"); + return { + store, + kernel, + proposal, + records, + contract: runtimeResult.actionContract, + greenlight: policy.greenlight, + policy, + surface, + }; +} + +export async function runNegotiatedX402Room() { + return withLocalReferenceProtocolIds(async () => { + const fixture = await createNegotiatedX402GreenlightUnchecked(); + const gatewayResult = await runX402WalletGateway({ + protocol: fixture.kernel, + surface: fixture.surface, + actionContractId: fixture.contract.actionContractId, + greenlightId: fixture.greenlight.greenlightId, + observedParameters: fixture.contract.parameters as X402PaymentParameters, + surfaceOperationRef: "surface-op:x402-a2a:first", + }); + const replay = await runX402WalletGateway({ + protocol: fixture.kernel, + surface: fixture.surface, + actionContractId: fixture.contract.actionContractId, + greenlightId: fixture.greenlight.greenlightId, + observedParameters: fixture.contract.parameters as X402PaymentParameters, + surfaceOperationRef: "surface-op:x402-a2a:replay", + }); + const supportPacket = await buildA2ANegotiationSupportPacket(fixture.store, fixture.contract.actionContractId); + return { ...fixture, gatewayResult, replay, supportPacket }; + }); +} + +export function changedAmountParameters(parameters: X402PaymentParameters): X402PaymentParameters { + return { ...parameters, atomicAmount: "2501" }; +} + +export function changedEndpointParameters(parameters: X402PaymentParameters): X402PaymentParameters { + return { + ...parameters, + endpointUrl: "https://api.example.com/mcp/other-premium-context", + intendedRequestUrl: "https://api.example.com/mcp/other-premium-context", + }; +} + +export function changedSelectedPaymentRequirementParameters(parameters: X402PaymentParameters): X402PaymentParameters { + return { + ...parameters, + selectedPaymentRequirementDigest: `sha256:${"d".repeat(64)}`, + }; +} + +export function fakeSigningSurface(downstreamPaymentStatus: "succeeded" | "unknown") { + let signatures = 0; + const commands: X402PaymentSignatureCommand[] = []; + return { + signatureCount: () => signatures, + signedCommands: () => commands, + async signPayment(command: X402PaymentSignatureCommand) { + signatures += 1; + commands.push(command); + const paymentSignature = `PAYMENT-SIGNATURE:fake:${command.verifiedGate.gateAttemptId}:${command.parameters.paymentRequirementsDigest.slice( + "sha256:".length, + "sha256:".length + 16, + )}`; + const paymentSignatureDigest = await digestCanonical({ paymentSignature }); + return { + evidenceRef: `evidence:x402-a2a-payment-signature:${command.verifiedGate.gateAttemptId}`, + surfaceOperationRef: command.verifiedGate.surfaceOperationRef, + paymentSignatureHeaderName: "PAYMENT-SIGNATURE" as const, + paymentSignatureHeaderRef: `credential:x402-a2a-local-fixture-signature:${command.verifiedGate.gateAttemptId}`, + paymentSignatureDigest, + paymentPayloadShape: "local_fixture_payment_signature" as const, + credentialMaterialPosture: "local_fixture" as const, + downstreamPaymentStatus, + paymentResponseEvidenceRef: + downstreamPaymentStatus === "succeeded" + ? `evidence:x402-a2a-payment-response:${command.verifiedGate.gateAttemptId}` + : null, + providerRequestRef: `provider-request:x402-a2a:${command.verifiedGate.gateAttemptId}`, + providerOperationRef: `provider-operation:x402-a2a:${command.verifiedGate.gateAttemptId}`, + }; + }, + }; +} + +async function recordNegotiatedX402Agreement( + kernel: HandshakeKernel, + proposal: X402InstallProposal, + contract: ActionContract, +) { + await kernel.recordNegotiationSession( + negotiationSession({ + negotiationSessionDigest: negotiationDigest, + subjectResourceRef: proposal.resourceRef, + clearingEvidenceRefs: { correlationRef: "a2a:task:x402-negotiation" }, + }), + ); + await kernel.recordNegotiationOffer( + negotiationOffer({ + offerObjectRefs: ["object:x402-offer:v1"], + offerContentRefs: ["content:x402-offer:v1"], + clearingEvidenceRefs: { obligationRef }, + }), + ); + await kernel.recordNegotiationDecision(negotiationDecision()); + await kernel.recordLinkedAgreement( + linkedAgreement({ + agreementObjectRefs: ["object:x402-agreement:v1"], + agreementContentRefs: ["content:x402-agreement:v1"], + clearingEvidenceRefs: { obligationRef, counterpartyRef }, + counterpartyRef, + }), + ); + await kernel.recordAgreementObligationBinding( + agreementBindingForContract(contract, { + obligationRef, + counterpartyRef, + resourceRef: contract.resourceRef, + }), + ); +} + +async function recordGatewayCheckedPosture( + kernel: HandshakeKernel, + proposal: X402InstallProposal, + records: NonNullable, +) { + const gatewayRegistryEntry = requireInstallProposalGatewayRegistryEntry(records.gatewayRegistryEntry); + const bypassProbeIds: string[] = []; + for (const probeKind of requiredGatewayCheckedBypassProbeKinds) { + const probe = await kernel.createBypassProbe({ + tenantId: proposal.tenantId, + organizationId: proposal.organizationId, + runtimeAdapterId: records.toolCapability.runtimeAdapterId, + gatewayId: gatewayRegistryEntry.gatewayId, + actionClass: "x402_payment.exact", + resourceRef: proposal.resourceRef, + protectedSurfaceKind: "x402_payment", + probeKind, + probeOutcome: "passed", + sourceAuthority: "gateway_probe", + reasonCodes: ["x402_probe_passed"], + evidenceRefs: [`evidence:x402-probe:${probeKind}`], + expiresAt: futureIso(), + }); + bypassProbeIds.push(probe.bypassProbeId); + } + await kernel.createProtectedPathPosture({ + tenantId: proposal.tenantId, + organizationId: proposal.organizationId, + runtimeAdapterId: records.toolCapability.runtimeAdapterId, + gatewayId: gatewayRegistryEntry.gatewayId, + actionClass: "x402_payment.exact", + resourceRef: proposal.resourceRef, + protectedSurfaceKind: "x402_payment", + postureState: "gateway_checked", + credentialCustodyStatus: "fixture_gateway_held", + rawSiblingToolStatus: "blocked", + sourceAuthority: "gateway_probe", + reasonCodes: ["x402_gateway_checked"], + evidenceRefs: ["evidence:x402-probes"], + bypassProbeIds, + expiresAt: futureIso(), + }); +} + +async function registerX402WalletCredentialRef( + kernel: HandshakeKernel, + proposal: X402InstallProposal, + records: NonNullable, +): Promise { + const credentialRef = await kernel.registerGatewayCredentialRef( + await buildX402WalletGatewayCredentialRefInput(proposal, records), + ); + x402CredentialRefs.set(proposal, credentialRef); + return credentialRef; +} + +async function registerX402DelegatedAuthorityRef( + kernel: HandshakeKernel, + proposal: X402InstallProposal, + records: NonNullable, +): Promise { + const authorityRef = await kernel.registerDelegatedAuthorityRef( + await buildX402DelegatedSpendAuthorityRefInput(proposal, records), + ); + x402AuthorityRefs.set(proposal, authorityRef); + return authorityRef; +} + +function requireCompiledRecords(proposal: X402InstallProposal): NonNullable { + if (!proposal.compiledRecords) throw new Error("expected installable x402 proposal"); + return proposal.compiledRecords; +} + +function x402RuntimeConfig( + proposal: X402InstallProposal, + records: NonNullable, + runId: string, +) { + const credentialRef = x402CredentialRefs.get(proposal); + if (!credentialRef) throw new Error("expected registered x402 wallet credential ref"); + const authorityRef = x402AuthorityRefs.get(proposal); + if (!authorityRef) throw new Error("expected registered x402 delegated authority ref"); + const gatewayRegistryEntry = requireInstallProposalGatewayRegistryEntry(records.gatewayRegistryEntry); + return { + tenantId: proposal.tenantId, + organizationId: proposal.organizationId, + principalId: records.operatingEnvelope.principalId, + agentId: records.operatingEnvelope.agentId, + runId, + runtimeAdapterId: records.toolCapability.runtimeAdapterId, + operatingEnvelopeId: records.operatingEnvelope.envelopeId, + toolCatalogRef: `${records.toolCapability.toolCatalogId}@${records.toolCapability.toolCatalogVersion}`, + actionCatalogRef: `${records.actionType.actionCatalogId}@${records.actionType.actionCatalogVersion}`, + gatewayRegistryRef: `gateway_registry@${gatewayRegistryEntry.gatewayRegistryVersion}`, + gatewayReadinessRef: "handshake://local/x402/a2a-gateway-readiness.json", + gatewayReadinessDigest: digest, + policyVersionRef: `${proposal.policyPackRef}@${proposal.policyPackVersion}`, + policyVersionDigest: digest, + toolCapabilityId: records.toolCapability.toolCapabilityId, + actionTypeId: records.actionType.actionTypeId, + gatewayRegistryEntryId: gatewayRegistryEntry.gatewayRegistryEntryId, + gatewayId: gatewayRegistryEntry.gatewayId, + gatewayCredentialBinding: x402WalletGatewayCredentialBindingFor(credentialRef), + delegatedAuthorityBinding: x402DelegatedSpendAuthorityBindingFor(authorityRef), + maxAtomicAmountPerCall: proposal.spendBounds.maxAtomicAmountPerCall, + contractExpiresAt: futureIso(), + signingSecret: "test-secret", + }; +} + +function validInstallInput(): X402InstallProposalInput { + const issuedAt = nowIso(); + return { + tenantId: "tenant_demo", + organizationId: "org_demo", + createdAt: issuedAt, + endpointEvidence: { + endpointUrl: "https://api.example.com/mcp/premium-context", + payee: "0xpayee", + network: "base-sepolia", + token: "USDC", + maxAtomicAmount: "2500", + paymentRequirementsDigest: digest, + facilitatorRef: "facilitator:local", + evidenceRefs: ["evidence:x402-payment-required:a2a-room"], + }, + walletGatewayProfile: { + walletGatewayId: "wallet_gateway_local", + gatewayId: "gateway_x402_wallet", + signerCustodyStatus: "fixture_gateway_held", + signerRef: "secretref:local-fake-signer", + authorityHolderRef: "gateway-authority:x402-wallet", + supportedNetworks: ["base-sepolia"], + supportedTokens: ["USDC"], + }, + spendBounds: { + principalId: "principal_demo", + agentId: "agent_demo", + runtimeAdapterId: "runtime_codex", + objectiveRef: "intent:a2a negotiated paid context", + allowedDomains: ["api.example.com"], + allowedPayees: ["0xpayee"], + allowedNetworks: ["base-sepolia"], + allowedTokens: ["USDC"], + maxAtomicAmountPerCall: "2500", + maxAtomicAmountPerSession: "10000", + maxAtomicAmountPerDay: "20000", + reviewThresholdAtomicAmount: "5000", + issuedAt, + expiresAt: futureIso(), + }, + }; +} + +function withLocalReferenceProtocolIds(run: () => T): T { + let sequence = 0; + return withProtocolIdSource( + { + createId(prefix) { + sequence += 1; + return `${prefix}_${deterministicUuid(sequence)}`; + }, + nowIso() { + return localReferenceGeneratedAt; + }, + }, + run, + ); +} + +function deterministicUuid(sequence: number): string { + const tail = sequence.toString(16).padStart(12, "0"); + return `00000000-0000-4000-8000-${tail}`; +} diff --git a/examples/external-adapter-sdk/README.md b/examples/external-adapter-sdk/README.md index e27c3e5..63d1cd6 100644 --- a/examples/external-adapter-sdk/README.md +++ b/examples/external-adapter-sdk/README.md @@ -30,3 +30,20 @@ It is definition-only: not runtime ingress registration, not gateway binding, not policy evaluation, not greenlight issuance, not gateway check, not mutation, not receipt export, not provider custody, not marketplace certification, and not hosted operation. + +## Dual-enforcement checklist (D-00, D-12) + +Before shipping an external adapter integration: + +- [ ] Catalog triplet registered (`ToolCapability`, `ActionType`, `GatewayRegistryEntry`) +- [ ] Atomic install or compiled-records refusal on orphan catalog (D-08) +- [ ] Service HTTP handler calls `adapter.run*Gateway` before mutation +- [ ] Hosted admission configured for transition scope (advisory layer only) +- [ ] External PEP (if any) is glue only — adapter re-check required (D-12) +- [ ] Conformance probe registered (`ProtectedMutationAdapter`) +- [ ] Proof gaps documented honestly — do not fake `pack:check` green + +Admission alone is not Handshake enforcement. Every consequential attempt must reduce to an exact action contract, receive policy evaluation, and pass a gateway check before mutation. REST-like transports compose `HttpProtectedMutationProfileSchema` from `src/adapters/http-profile` (see [integrator-parity-transitions.md](../../docs/internal/integrator-parity-transitions.md)). + +Proof-gap families (auth.md, package-install, registry discoverability) are prose-only in phase 04 — x402 is the only runnable clearance wedge: +[service-operator-golden-path.md](../../docs/internal/service-operator-golden-path.md#proof-gap-list-not-runnable-in-phase-04). diff --git a/examples/service-operator-bootstrap/README.md b/examples/service-operator-bootstrap/README.md new file mode 100644 index 0000000..fdddd31 --- /dev/null +++ b/examples/service-operator-bootstrap/README.md @@ -0,0 +1,49 @@ +# Service operator bootstrap (x402 family) + +Atomic install recipe for the **x402_payment.exact** catalog triplet: compile an +install proposal, then register compiled records through the control-plane +`InstallClient` transition. This does not create greenlights, perform gateway +checks, or mutate protected surfaces. + +## Copy-paste + +```bash +bun run examples/service-operator-bootstrap/run.ts +``` + +```bash +handshake service bootstrap +``` + +Inspect evidence: + +```text +examples/service-operator-bootstrap/output/latest.json +``` + +## Success shape + +`outcome: "compiled_records_registered"` with `recordRefs` for tool capability, +action type, gateway registry entry, and operating envelope, plus +`policyPackRef` / `policyPackVersion`. + +## Refusal shape + +`outcome: "install_proposal_refused"` with `reasonCodes` (for example +`x402_wallet_signer_not_gateway_held` when gateway readiness is not fixture-held). +No orphan catalog rows are written on refusal. + +## Re-run / idempotency + +A second run with the same compiled digest reuses existing catalog rows +(`recordConflictMode: absent_or_same`) and does not silently duplicate gateway +registry entries. A conflicting digest for the same catalog id returns +`bootstrap_record_digest_conflict`. + +## Scope + +x402_payment.exact only. Other action families are refused at the CLI with +`service_bootstrap_x402_only`. + +See [service-operator-golden-path.md](../../docs/internal/service-operator-golden-path.md) +(Branch A — atomic bootstrap). diff --git a/examples/service-operator-bootstrap/latest.json b/examples/service-operator-bootstrap/latest.json new file mode 100644 index 0000000..eded989 --- /dev/null +++ b/examples/service-operator-bootstrap/latest.json @@ -0,0 +1,4 @@ +{ + "schemaVersion": "handshake.demo.service-operator-bootstrap.v1", + "note": "Run examples/service-operator-bootstrap/run.ts to regenerate this artifact." +} diff --git a/examples/service-operator-bootstrap/run.ts b/examples/service-operator-bootstrap/run.ts new file mode 100644 index 0000000..74ad9f2 --- /dev/null +++ b/examples/service-operator-bootstrap/run.ts @@ -0,0 +1,53 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { + defaultX402BootstrapInstallInput, + runServiceBootstrap, +} from "../../src/cli/service-operator/bootstrap"; + +const outputDir = new URL("./output/", import.meta.url); +const outputJsonPath = new URL("./output/latest.json", import.meta.url); +const goldenPathDoc = "docs/internal/service-operator-golden-path.md"; + +console.log("# Service Operator Bootstrap (x402 family only)\n"); +console.log(`Golden path: ${goldenPathDoc}`); +console.log("Scope: atomic catalog triplet via InstallClient — no authority.\n"); + +const installInput = defaultX402BootstrapInstallInput(); +const result = await runServiceBootstrap({ installInput }); + +const summary = { + schemaVersion: "handshake.demo.service-operator-bootstrap.v1", + generatedAt: new Date().toISOString(), + authorityBoundary: { + authorityCreated: false, + greenlightCreated: false, + gatewayCheckPerformed: false, + mutationAttempted: false, + }, + docs: { goldenPath: goldenPathDoc }, + install: { + outcome: result.outcome, + actionFamily: result.actionFamily, + installProposalId: result.installProposalId, + installDigest: result.installDigest, + reasonCodes: result.reasonCodes, + recordRefs: result.recordRefs, + policyPackRef: result.policyPackRef, + policyPackVersion: result.policyPackVersion, + }, + commands: { + example: "bun run examples/service-operator-bootstrap/run.ts", + cli: "handshake service bootstrap", + }, +}; + +await mkdir(outputDir, { recursive: true }); +await writeFile(outputJsonPath, `${JSON.stringify(summary, null, 2)}\n`, "utf8"); + +console.log(JSON.stringify(summary, null, 2)); +console.log(`\nWrote: ${fileURLToPath(outputJsonPath)}`); + +if (result.outcome !== "compiled_records_registered") { + process.exitCode = 1; +} diff --git a/examples/service-operator-golden-path/README.md b/examples/service-operator-golden-path/README.md new file mode 100644 index 0000000..bf2a38e --- /dev/null +++ b/examples/service-operator-golden-path/README.md @@ -0,0 +1,27 @@ +# Service Operator Golden Path Example + +Thin wrapper around the canonical service workflow admission demo. Source of +truth: [service-operator-golden-path.md](../../docs/internal/service-operator-golden-path.md). + +## Run + +```bash +bun run examples/service-operator-golden-path/run.ts +``` + +Or from repo root: + +```bash +npm run demo:service-operator-golden-path +``` + +(if wired in package.json — otherwise use `bun run` above) + +## What this does + +1. Prints links to golden path and developer experience index +2. Runs `npm run demo:service-workflow-admission` +3. Writes `output/latest.json` summary with `nextCommands` including future + `handshake service bootstrap` + +Non-authority only — no kernel transitions beyond the admission demo. diff --git a/examples/service-operator-golden-path/run.ts b/examples/service-operator-golden-path/run.ts new file mode 100644 index 0000000..364007b --- /dev/null +++ b/examples/service-operator-golden-path/run.ts @@ -0,0 +1,58 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import { spawn } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const repoRoot = fileURLToPath(new URL("../..", import.meta.url)); +const outputDir = new URL("./output/", import.meta.url); +const outputJsonPath = new URL("./output/latest.json", import.meta.url); + +const goldenPathDoc = "docs/internal/service-operator-golden-path.md"; +const devexIndexDoc = "docs/internal/developer-experience-index.md"; + +console.log("# Service Operator Golden Path Wrapper\n"); +console.log(`Start Here: ${goldenPathDoc}`); +console.log(`Developer index: ${devexIndexDoc}`); +console.log("\nRunning canonical admission demo...\n"); + +const demo = spawn("npm", ["run", "demo:service-workflow-admission"], { + cwd: repoRoot, + stdio: "inherit", + shell: true, +}); + +const exitCode: number = await new Promise((resolve, reject) => { + demo.on("error", reject); + demo.on("close", (code) => resolve(code ?? 1)); +}); + +if (exitCode !== 0) { + process.exit(exitCode); +} + +await mkdir(outputDir, { recursive: true }); + +const summary = { + schemaVersion: "handshake.demo.service-operator-golden-path.v1", + generatedAt: new Date().toISOString(), + authorityBoundary: { + createsAuthority: false, + permitsMutation: false, + freshActionContractRequired: true, + }, + docs: { + goldenPath: goldenPathDoc, + developerExperienceIndex: devexIndexDoc, + }, + canonicalDemo: { + command: "npm run demo:service-workflow-admission", + outputJson: "examples/service-workflow-admission/output/latest.json", + }, + nextCommands: [ + "npm run demo:service-workflow-admission", + "handshake service bootstrap --help", + "handshake host doctor", + ], +}; + +await writeFile(outputJsonPath, `${JSON.stringify(summary, null, 2)}\n`, "utf8"); +console.log(`\nWrote: ${fileURLToPath(outputJsonPath)}`); diff --git a/examples/service-workflow-admission/README.md b/examples/service-workflow-admission/README.md new file mode 100644 index 0000000..aac4146 --- /dev/null +++ b/examples/service-workflow-admission/README.md @@ -0,0 +1,59 @@ +# Service Workflow Admission Example + +Status: local/source-owned product-surface proof +Scope: one non-authority service workflow admission and handle, followed by one +fresh x402 protected-action clearance path composed from the existing APS demo. + +## Invariant At Stake + +Admission and handle records can help a service correlate evidence and readback. +They cannot become identity, permission, policy, greenlight, gateway check, +receipt evidence, signer access, payment approval, or reusable auth. + +## Run + +From the repo root: + +```bash +npm run demo:service-workflow-admission +``` + +The demo writes: + +```text +examples/service-workflow-admission/output/latest.md +examples/service-workflow-admission/output/latest.json +``` + +The demo also refreshes `examples/x402-protected-spend/output/latest.json` by +running `npm run demo:aps` internally, then reads only the redacted local APS +report fields needed to show that protected-action clearance is separate from +workflow admission. + +## What This Proves + +- `ServiceWorkflowAdmission` and `ServiceWorkflowHandle` parse through the + source-owned non-authority schemas. +- The five workflow IDs are correlation and reconstruction fields only. +- Admission readback is not receipt evidence. +- The workflow handle is not permission. +- x402 clearance appears only in the fresh protected-action path: + `ActionContract -> PolicyDecision -> one-use Greenlight -> GatewayCheck`. +- The generated-agent misuse posture lists loop/retry reuse, changed + parameters, dynamic tool construction, stale review, raw sibling bypass, + replay, and proof-gap cases as non-authority outcomes. +- auth.md is recorded as provenance or proof-gap posture only; it is not + composed with x402 spend into one fixture authority. + +## What This Does Not Prove + +- No hosted operation. +- No provider custody. +- No settlement finality. +- No broad x402 compatibility. +- No host-wide containment. +- No reusable passport authority. +- No handle-as-permission. +- No auth, policy, gateway admission, signer access, payment approval, receipt + evidence, or reusable clearance from admission or handle records. +- No composite auth.md plus x402 authority artifact. diff --git a/examples/service-workflow-admission/output/.gitignore b/examples/service-workflow-admission/output/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/examples/service-workflow-admission/output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/examples/service-workflow-admission/run.ts b/examples/service-workflow-admission/run.ts new file mode 100644 index 0000000..083ffaa --- /dev/null +++ b/examples/service-workflow-admission/run.ts @@ -0,0 +1,439 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { + ServiceWorkflowAdmissionSchema, + ServiceWorkflowHandleSchema, + serviceWorkflowAdmissionSchemaVersion, + serviceWorkflowNonAuthorityBoundary, +} from "../../src/surfaces/service-workflow-admission"; + +const repoRoot = fileURLToPath(new URL("../..", import.meta.url)); +const outputDir = new URL("./output/", import.meta.url); +const outputJsonPath = new URL("./output/latest.json", import.meta.url); +const outputMarkdownPath = new URL("./output/latest.md", import.meta.url); +const x402OutputPath = `${repoRoot}/examples/x402-protected-spend/output/latest.json`; + +const generatedAt = "2026-05-25T00:00:00.000Z"; +const digest = (char: string) => `sha256:${char.repeat(64)}` as const; +const authorityBoundary = serviceWorkflowNonAuthorityBoundary(); + +await runExistingX402Demo(); +const x402Output = asRecord(await Bun.file(x402OutputPath).json(), "x402 output"); +const x402Report = asRecord(x402Output.report, "x402 report"); +const protectedAction = asRecord(x402Report.protectedAction, "x402 protectedAction"); +const authorityPath = asRecord(x402Report.authorityPath, "x402 authorityPath"); +const actorsAndCustody = asRecord(x402Report.actorsAndCustody, "x402 actorsAndCustody"); +const evidencePosture = asRecord(x402Report.evidencePosture, "x402 evidencePosture"); +const challengePhaseEvidence = phaseEvidence(x402Output, "0_sandbox_payment_required_challenge"); +const runtimeProposalPhaseEvidence = phaseEvidence(x402Output, "2_runtime_proposal"); +const gatewaySignaturePhaseEvidence = phaseEvidence(x402Output, "4_gateway_admission_and_signature"); + +const workflowHandle = ServiceWorkflowHandleSchema.parse({ + schemaVersion: serviceWorkflowAdmissionSchemaVersion, + passportPackageDigest: digest("1"), + passportPresentationId: "passport-presentation:x402-demo-agent:001", + admissionId: "service-workflow-admission:x402-demo:001", + serviceWorkflowHandleId: "service-workflow-handle:x402-demo:001", + serviceWorkflowHandleDigest: digest("2"), + issuedAt: generatedAt, + expiresAt: "2026-05-25T01:00:00.000Z", + workflowBoundsDigest: digest("3"), + sourceAdmissionDigest: digest("4"), + runtimePostureDigest: digest("5"), + authorityBoundary, + nextProtectedActionRequirement: "fresh_action_contract_required", + allowedUse: "correlation_and_readback_context_only", +}); + +const admissionPacket = ServiceWorkflowAdmissionSchema.parse({ + schemaVersion: serviceWorkflowAdmissionSchemaVersion, + passportPackageDigest: workflowHandle.passportPackageDigest, + passportPresentationId: workflowHandle.passportPresentationId, + admissionId: workflowHandle.admissionId, + admissionDigest: workflowHandle.sourceAdmissionDigest, + serviceRef: "service:x402-demo-intake", + presentedAt: generatedAt, + evaluatedAt: "2026-05-25T00:00:01.000Z", + claimResults: [ + { + claimRef: "passport:evidence-bundle:x402-demo-agent", + claimDigest: workflowHandle.passportPackageDigest, + status: "accepted", + reasonCodes: ["standing_evidence_recognized_for_workflow_context"], + evidenceRefs: ["evidence:passport-package:x402-demo-agent"], + proofGapRefs: [], + }, + { + claimRef: "provider-custody:live-x402", + claimDigest: null, + status: "proof_gap", + reasonCodes: ["provider_custody_not_established_by_admission"], + evidenceRefs: [], + proofGapRefs: ["proof-gap:provider-custody-live-x402"], + }, + ], + runtimePosture: [ + { + runtimeRef: "runtime:codex-local", + hostProfileEvidenceRef: "host-profile:codex-local-x402", + rawSiblingBypassPostureRef: "bypass-posture:x402-raw-sibling", + nativeContainmentClaimed: false, + proofGapRefs: ["proof-gap:host-wide-containment"], + }, + ], + serviceWorkflowHandle: workflowHandle, + authorityBoundary, + nextActionRequirement: "fresh_action_contract_required", + clearanceBoundary: "fresh_action_contract_required_for_each_protected_action", + readbackBoundary: "admission_readback_is_not_receipt_evidence", +}); + +const output = { + schemaVersion: "handshake.demo.service-workflow-admission.v1", + generatedAt, + command: "npm run demo:service-workflow-admission", + invariant: + "Passport, admission, and handle records support correlation and readback only; fresh protected-action clearance carries authority.", + proofBoundary: "local_source_owned_product_surface", + outputFiles: { + markdown: "examples/service-workflow-admission/output/latest.md", + json: "examples/service-workflow-admission/output/latest.json", + composedProtectedActionJson: "examples/x402-protected-spend/output/latest.json", + }, + admissionPacket, + admissionReadback: { + readbackBoundary: admissionPacket.readbackBoundary, + admissionStatus: "accepted_with_proof_gap", + serviceWorkflowHandleId: workflowHandle.serviceWorkflowHandleId, + policyDecisionRef: null, + greenlightRef: null, + gatewayCheckRef: null, + mutationAttemptRef: null, + receiptRef: null, + authorityCertificateRef: null, + nextActionRequirement: "fresh_action_contract_required", + }, + workflowHandle, + freshClearanceRequest: { + actionClass: stringField(protectedAction, "actionClass"), + protectedSurfaceKind: stringField(protectedAction, "protectedSurfaceKind"), + resourceRef: stringField(protectedAction, "resourceRef"), + contextRefs: { + passportPackageDigest: workflowHandle.passportPackageDigest, + passportPresentationId: workflowHandle.passportPresentationId, + admissionId: workflowHandle.admissionId, + serviceWorkflowHandleId: workflowHandle.serviceWorkflowHandleId, + serviceWorkflowHandleDigest: workflowHandle.serviceWorkflowHandleDigest, + }, + contextAuthorityCreated: false, + freshActionContractRequired: true, + }, + freshClearanceAuthorityPath: { + actionClass: stringField(protectedAction, "actionClass"), + actionContractId: stringField(authorityPath, "actionContractId"), + policyDecisionId: stringField(authorityPath, "policyDecisionId"), + policyDecision: stringField(authorityPath, "policyDecision"), + greenlightId: stringField(authorityPath, "greenlightId"), + gateAttemptId: stringField(authorityPath, "gateAttemptId"), + gateDecision: stringField(authorityPath, "gateDecision"), + receiptId: stringField(authorityPath, "receiptId"), + changedParameterDecision: stringField(authorityPath, "changedParameterDecision"), + changedParameterReasonCode: stringField(authorityPath, "changedParameterReasonCode"), + replayDecision: stringField(authorityPath, "replayDecision"), + replayReasonCode: stringField(authorityPath, "replayReasonCode"), + }, + protectedActionFixtureGate: { + serviceWorkflowContextRole: "correlation_context_only", + contextAuthorityCreated: false, + freshActionContractRequired: true, + freshActionContractId: stringField(authorityPath, "actionContractId"), + policyDecisionId: stringField(authorityPath, "policyDecisionId"), + greenlightId: stringField(authorityPath, "greenlightId"), + gatewayCheckAttemptId: stringField(authorityPath, "gateAttemptId"), + receiptId: stringField(authorityPath, "receiptId"), + admissionReadbackReceiptRef: null, + paymentMaterialBoundary: { + admissionOrHandlePaymentMaterialIncluded: false, + runtimeCredentialMaterialVisible: stringField(runtimeProposalPhaseEvidence, "credentialMaterialVisibleToRuntime"), + signedRetryCountBeforeGateway: numberField(challengePhaseEvidence, "signedRetryCountBeforeGateway"), + signerInvocationBoundary: stringField(actorsAndCustody, "signerInvocationBoundary"), + paymentSignatureHeaderRef: nullableStringField(gatewaySignaturePhaseEvidence, "paymentSignatureHeaderRef"), + paymentPayloadRef: nullableStringField(gatewaySignaturePhaseEvidence, "paymentPayloadRef"), + paymentMaterialCreatedOnlyAfterVerifiedGatewayCheck: true, + }, + authMdBoundary: { + includedInFixture: false, + posture: "provenance_or_proof_gap_only", + compositeAuthorityCreated: false, + proofGapRef: "proof-gap:auth-md-not-composed-into-t2-04", + }, + }, + authMdPosture: { + includedInProtectedActionFixture: false, + authorityPosture: "provenance_or_proof_gap_only", + compositeAuthorityCreated: false, + separateProtectedActionRequired: + "auth_md_protected_api_call.exact_requires_fresh_action_contract_policy_greenlight_gateway_check", + proofGapRefs: ["proof-gap:auth-md-not-composed-into-t2-04"], + }, + evidenceSeparation: { + admissionEvidenceRefs: admissionPacket.claimResults.flatMap((claim) => claim.evidenceRefs), + admissionProofGapRefs: admissionPacket.claimResults.flatMap((claim) => claim.proofGapRefs), + protectedActionOutcomeRefs: stringArrayField(evidencePosture, "surfaceOperationEvidenceRefs"), + protectedActionProofGapRefs: stringArrayField(evidencePosture, "proofGapRefs"), + protectedActionRefusalRefs: stringArrayField(evidencePosture, "refusalRefs"), + }, + generatedAgentMisusePosture: [ + { + scenario: "handle_reuse_in_loop", + generatedShape: "agent loop carries the same service workflow handle into another x402 attempt", + expectedBoundary: "fresh_action_contract_required", + acceptedAsAuthority: false, + resultingPosture: "separate_action_contract_or_refusal_required", + }, + { + scenario: "retry_after_changed_parameters", + generatedShape: "agent retries with changed amount, endpoint, payee, or request body after the handle was issued", + expectedBoundary: "fresh_action_contract_required", + acceptedAsAuthority: false, + resultingPosture: "changed_parameter_refusal_or_new_exact_contract_required", + }, + { + scenario: "dynamic_tool_construction", + generatedShape: "agent constructs a protected tool name or x402 endpoint dynamically from handle context", + expectedBoundary: "runtime_refusal_or_proof_gap", + acceptedAsAuthority: false, + resultingPosture: "recraft_request_before_contract", + }, + { + scenario: "stale_rendered_review", + generatedShape: "agent acts from a rendered review whose underlying protected-action parameters drifted", + expectedBoundary: "fresh_action_contract_required", + acceptedAsAuthority: false, + resultingPosture: "stale_review_cannot_authorize_changed_parameters", + }, + { + scenario: "raw_sibling_x402_bypass", + generatedShape: "agent calls direct MCP, browser, network, or x402 payment route outside the gateway", + expectedBoundary: "bypass_evidence_only", + acceptedAsAuthority: false, + resultingPosture: "stop_or_isolate_until_recovered", + }, + { + scenario: "replay_after_greenlight", + generatedShape: "agent reuses a prior greenlight or payment attempt after the handle stays valid", + expectedBoundary: "one_use_greenlight_only", + acceptedAsAuthority: false, + resultingPosture: "replay_refusal", + }, + { + scenario: "admission_proof_gap", + generatedShape: "agent treats accepted admission with proof gaps as clearance", + expectedBoundary: "proof_gap_not_authority", + acceptedAsAuthority: false, + resultingPosture: "fresh_action_contract_required_after_gap_resolution_or_refusal", + }, + ], + authorityAudit: { + passportCreatedAuthority: false, + admissionCreatedAuthority: false, + handleCreatedAuthority: false, + readbackCreatedAuthority: false, + markdownCreatedAuthority: false, + freshClearanceRequiredForProtectedAction: true, + paymentMaterialInAdmissionOrHandle: false, + credentialMaterialInAdmissionOrHandle: false, + }, + nonClaims: [ + "hosted operation", + "provider custody", + "settlement finality", + "broad x402 compatibility", + "host-wide containment", + "reusable passport authority", + "handle-as-permission", + "receipt evidence from admission readback", + ], + proofGaps: [ + "provider_custody_not_established_by_admission", + "host_wide_containment_not_established_by_admission", + "downstream_finality_remains_x402_outcome_evidence_only", + ], + artifacts: [ + "docs/internal/service-workflow-story.md", + "src/surfaces/service-workflow-admission/index.ts", + "examples/x402-protected-spend/output/latest.json", + ], +} as const; + +const markdown = renderMarkdown(output); + +await mkdir(outputDir, { recursive: true }); +await writeFile(outputJsonPath, `${JSON.stringify(output, null, 2)}\n`); +await writeFile(outputMarkdownPath, markdown); + +console.log(markdown); +console.log("Wrote: examples/service-workflow-admission/output/latest.md"); +console.log("Wrote: examples/service-workflow-admission/output/latest.json"); + +async function runExistingX402Demo(): Promise { + const proc = Bun.spawn([process.execPath, "run", "./examples/x402-protected-spend/run.ts"], { + cwd: repoRoot, + stdout: "pipe", + stderr: "pipe", + }); + const stdoutPromise = proc.stdout ? new Response(proc.stdout).text() : Promise.resolve(""); + const stderrPromise = proc.stderr ? new Response(proc.stderr).text() : Promise.resolve(""); + const exitCode = await proc.exited; + const stdout = await stdoutPromise; + const stderr = await stderrPromise; + if (exitCode !== 0 || stderr !== "") { + throw new Error(`x402 protected-spend demo failed: exit=${exitCode} stdout=${stdout} stderr=${stderr}`); + } +} + +function asRecord(value: unknown, label: string): Record { + if (typeof value !== "object" || value === null || Array.isArray(value)) { + throw new Error(`${label} must be an object.`); + } + return value as Record; +} + +function stringField(record: Record, key: string): string { + const value = record[key]; + if (typeof value !== "string") throw new Error(`${key} must be a string.`); + return value; +} + +function stringArrayField(record: Record, key: string): string[] { + const value = record[key]; + if (!Array.isArray(value)) throw new Error(`${key} must be an array.`); + if (!value.every((entry) => typeof entry === "string")) throw new Error(`${key} must contain strings.`); + return value; +} + +function numberField(record: Record, key: string): number { + const value = record[key]; + if (typeof value !== "number") throw new Error(`${key} must be a number.`); + return value; +} + +function nullableStringField(record: Record, key: string): string | null { + const value = record[key]; + if (value === null) return null; + if (typeof value !== "string") throw new Error(`${key} must be a string or null.`); + return value; +} + +function phaseEvidence(report: Record, phaseName: string): Record { + const phases = report.phases; + if (!Array.isArray(phases)) throw new Error("x402 output phases must be an array."); + const phase = phases.find((entry) => asRecord(entry, "x402 phase").phase === phaseName); + if (!phase) throw new Error(`x402 phase not found: ${phaseName}`); + return asRecord(asRecord(phase, "x402 phase").evidence, `${phaseName} evidence`); +} + +function renderMarkdown(report: typeof output): string { + return `# Service Workflow Admission Example + +Generated: ${report.generatedAt} + +Command: \`${report.command}\` + +## Invariant + +${report.invariant} + +## Admission Evidence + +| Field | Value | +| --- | --- | +| Passport package digest | \`${report.admissionPacket.passportPackageDigest}\` | +| Passport presentation ID | \`${report.admissionPacket.passportPresentationId}\` | +| Admission ID | \`${report.admissionPacket.admissionId}\` | +| Admission status | \`${report.admissionReadback.admissionStatus}\` | +| Creates authority | \`${report.admissionPacket.authorityBoundary.createsAuthority}\` | +| Creates policy decision | \`${report.admissionPacket.authorityBoundary.createsPolicyDecision}\` | +| Performs gateway check | \`${report.admissionPacket.authorityBoundary.performsGatewayCheck}\` | + +## Workflow Handle + +| Field | Value | +| --- | --- | +| Handle ID | \`${report.workflowHandle.serviceWorkflowHandleId}\` | +| Handle digest | \`${report.workflowHandle.serviceWorkflowHandleDigest}\` | +| Allowed use | \`${report.workflowHandle.allowedUse}\` | +| Next protected action requirement | \`${report.workflowHandle.nextProtectedActionRequirement}\` | +| Is reusable auth | \`${report.workflowHandle.authorityBoundary.isReusableAuth}\` | + +## Readback Boundary + +Admission readback is not receipt evidence. The handle is not permission. The +readback carries no policy decision, greenlight, gateway check, mutation, +receipt, certificate, credential material, x402 \`PaymentPayload\`, or +\`PAYMENT-SIGNATURE\`. + +## Fresh Clearance Path + +| Field | Value | +| --- | --- | +| Action class | \`${report.freshClearanceAuthorityPath.actionClass}\` | +| Action contract | \`${report.freshClearanceAuthorityPath.actionContractId}\` | +| Policy decision | \`${report.freshClearanceAuthorityPath.policyDecision}\` | +| Gateway decision | \`${report.freshClearanceAuthorityPath.gateDecision}\` | +| Replay decision | \`${report.freshClearanceAuthorityPath.replayDecision}\` | +| Changed parameter decision | \`${report.freshClearanceAuthorityPath.changedParameterDecision}\` | + +x402 clearance comes only from fresh \`ActionContract -> PolicyDecision -> +one-use Greenlight -> GatewayCheck\`. The workflow handle contributes context +only. + +## Protected-Action Fixture Gate + +| Field | Value | +| --- | --- | +| Context role | \`${report.protectedActionFixtureGate.serviceWorkflowContextRole}\` | +| Fresh contract required | \`${report.protectedActionFixtureGate.freshActionContractRequired}\` | +| Gateway check attempt | \`${report.protectedActionFixtureGate.gatewayCheckAttemptId}\` | +| Runtime credential material visible | \`${report.protectedActionFixtureGate.paymentMaterialBoundary.runtimeCredentialMaterialVisible}\` | +| Signed retry count before gateway | \`${report.protectedActionFixtureGate.paymentMaterialBoundary.signedRetryCountBeforeGateway}\` | +| Signer boundary | \`${report.protectedActionFixtureGate.paymentMaterialBoundary.signerInvocationBoundary}\` | +| Payment material after gateway only | \`${report.protectedActionFixtureGate.paymentMaterialBoundary.paymentMaterialCreatedOnlyAfterVerifiedGatewayCheck}\` | +| auth.md composite authority created | \`${report.protectedActionFixtureGate.authMdBoundary.compositeAuthorityCreated}\` | +| auth.md posture | \`${report.authMdPosture.authorityPosture}\` | +| auth.md separate action required | \`${report.authMdPosture.separateProtectedActionRequired}\` | + +## Evidence Separation + +| Evidence class | Refs | +| --- | --- | +| Admission evidence | ${report.evidenceSeparation.admissionEvidenceRefs.map((ref) => `\`${ref}\``).join(", ") || "none"} | +| Admission proof gaps | ${report.evidenceSeparation.admissionProofGapRefs.map((ref) => `\`${ref}\``).join(", ") || "none"} | +| Protected-action outcome evidence | ${report.evidenceSeparation.protectedActionOutcomeRefs.map((ref) => `\`${ref}\``).join(", ")} | +| Protected-action proof gaps | ${report.evidenceSeparation.protectedActionProofGapRefs.map((ref) => `\`${ref}\``).join(", ") || "none"} | +| Protected-action refusals | ${report.evidenceSeparation.protectedActionRefusalRefs.map((ref) => `\`${ref}\``).join(", ")} | + +## Generated-Agent Misuse Posture + +| Scenario | Boundary | Authority accepted | Resulting posture | +| --- | --- | --- | --- | +${report.generatedAgentMisusePosture + .map( + (item) => + `| \`${item.scenario}\` | \`${item.expectedBoundary}\` | \`${item.acceptedAsAuthority}\` | \`${item.resultingPosture}\` |`, + ) + .join("\n")} + +## Non-Claims + +${report.nonClaims.map((claim) => `- ${claim}`).join("\n")} + +## Proof Gaps + +${report.proofGaps.map((gap) => `- ${gap}`).join("\n")} + +## Artifacts + +${report.artifacts.map((artifact) => `- \`${artifact}\``).join("\n")} +`; +} diff --git a/package.json b/package.json index a43a60b..5d9939c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "handshake-protocol-kernel", - "version": "0.2.7", + "version": "0.2.8", "description": "Protected action infrastructure for automated decision making: protocol kernel, CLI evidence views, and local MCP proposal/evidence server.", "license": "Apache-2.0", "mcpName": "io.github.CreasyBear/handshake-protocol-kernel", @@ -49,6 +49,11 @@ "import": "./dist/sdk/surface-clients/index.mjs", "default": "./dist/sdk/surface-clients/index.mjs" }, + "./surfaces/a2a-negotiation-readback": { + "types": "./dist/surfaces/a2a-negotiation-readback/index.d.ts", + "import": "./dist/surfaces/a2a-negotiation-readback/index.mjs", + "default": "./dist/surfaces/a2a-negotiation-readback/index.mjs" + }, "./cli": { "types": "./dist/cli/index.d.ts", "import": "./dist/cli/index.mjs", @@ -87,6 +92,8 @@ "test": "bun test", "demo:self-hosted": "bun run ./examples/self-hosted-activation/run.ts", "demo:aps": "bun run ./examples/x402-protected-spend/run.ts", + "demo:service-workflow-admission": "bun run ./examples/service-workflow-admission/run.ts", + "demo:service-operator-golden-path": "bun run ./examples/service-operator-golden-path/run.ts", "demo:adapter-sdk": "bun run ./examples/external-adapter-sdk/run.ts", "demo:x402-tool-profiles": "bun run ./examples/x402-protected-tool-profiles/run.ts", "demo:mcp-transcript": "bun run ./examples/mcp-reference-transcript/run.ts", @@ -98,6 +105,8 @@ "lint": "eslint src test --max-warnings=0", "check:types": "tsc --noEmit --pretty false", "pack:check": "npm run build && node scripts/check-package-surface.mjs && node scripts/check-published-entrypoints.mjs && node scripts/check-clean-installed-activation.mjs && node scripts/check-release-proof.mjs && node scripts/check-npm-maintainer-posture.mjs", + "check:service-agent-gating-phase": "node scripts/check-service-agent-gating-phase.mjs --tier operator", + "check:service-agent-gating-phase:full": "node scripts/check-service-agent-gating-phase.mjs --tier full", "check:repo": "npm run build && npm run check:types && npm run lint && npm run format:check && npm run test && npm run pack:check && git diff --check", "release:admin:check": "node scripts/check-release-admin.js", "release:admin:check:remote": "node scripts/check-release-admin.js --remote-readback", diff --git a/scripts/build-package-bundles.mjs b/scripts/build-package-bundles.mjs index c514442..232dec4 100644 --- a/scripts/build-package-bundles.mjs +++ b/scripts/build-package-bundles.mjs @@ -5,6 +5,7 @@ const bundles = [ ["./src/conformance/index.ts", "./dist/conformance/index.mjs"], ["./src/adapter-sdk/index.ts", "./dist/adapter-sdk/index.mjs"], ["./src/surfaces/index.ts", "./dist/surfaces/index.mjs"], + ["./src/surfaces/a2a-negotiation-readback/index.ts", "./dist/surfaces/a2a-negotiation-readback/index.mjs"], ["./src/runtime/index.ts", "./dist/runtime/index.mjs"], ["./src/sdk/surface-clients/index.ts", "./dist/sdk/surface-clients/index.mjs"], ["./src/cli/index.ts", "./dist/cli/index.mjs"], diff --git a/scripts/check-package-surface.mjs b/scripts/check-package-surface.mjs index ec57f2a..f138f3f 100644 --- a/scripts/check-package-surface.mjs +++ b/scripts/check-package-surface.mjs @@ -14,6 +14,7 @@ const requiredFiles = [ "dist/conformance/index.mjs", "dist/adapter-sdk/index.mjs", "dist/surfaces/index.mjs", + "dist/surfaces/a2a-negotiation-readback/index.mjs", "dist/runtime/index.mjs", "dist/sdk/surface-clients/index.mjs", "dist/cli/index.mjs", @@ -26,6 +27,7 @@ const requiredFiles = [ "dist/conformance/index.d.ts", "dist/adapter-sdk/index.d.ts", "dist/surfaces/index.d.ts", + "dist/surfaces/a2a-negotiation-readback/index.d.ts", "dist/runtime/index.d.ts", "dist/sdk/surface-clients/index.d.ts", "dist/cli/index.d.ts", diff --git a/scripts/check-product-completion.mjs b/scripts/check-product-completion.mjs new file mode 100644 index 0000000..ccb3b2c --- /dev/null +++ b/scripts/check-product-completion.mjs @@ -0,0 +1,115 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { pathToFileURL } from "node:url"; + +const repoRoot = process.cwd(); +const { + projectProductCompletionReadback, + PRODUCT_COMPLETION_READBACK_KIND, + PRODUCT_COMPLETION_STATUSES, + PRODUCT_COMPLETION_PACK_CHECK_EXPECT_STATUS, + assertProductCompletionGateIds, +} = await import(pathToFileURL(join(repoRoot, "dist/surfaces/index.mjs")).href); + +const args = process.argv.slice(2); +const expectedStatus = optionValue(args, "--expect-status") ?? PRODUCT_COMPLETION_PACK_CHECK_EXPECT_STATUS; +const printJson = args.includes("--json"); + +assert.equal( + ["completed", "closed_with_hard_blocks", "incomplete"].includes(expectedStatus), + true, + "--expect-status must be completed, closed_with_hard_blocks, or incomplete", +); + +const pkg = JSON.parse(readFileSync("package.json", "utf8")); +const proof = buildProductCompletionProof(pkg); + +assert.equal(proof.proofKind, PRODUCT_COMPLETION_READBACK_KIND, "proofKind must match projector contract"); +assert.equal( + PRODUCT_COMPLETION_STATUSES.includes(proof.status), + true, + `status must be one of ${PRODUCT_COMPLETION_STATUSES.join(", ")}`, +); +assertProductCompletionGateIds(proof.gates.map((gate) => gate.gateId)); + +const dualGate = proof.gates.find((gate) => gate.gateId === "dual_enforcement_posture"); +assert.equal(dualGate?.status, "incomplete", "dual_enforcement_posture must stay incomplete until structural evidence"); + +if (printJson) { + console.log(JSON.stringify(proof, null, 2)); +} else { + console.log(`Product completion is ${proof.status}.`); +} + +if (proof.status !== expectedStatus) { + console.error(`Expected product completion status ${expectedStatus}, got ${proof.status}.`); + process.exit(1); +} + +function buildProductCompletionProof(pkg) { + return projectProductCompletionReadback({ + generatedAt: new Date().toISOString(), + commandRefs: ["node scripts/check-product-completion.mjs"], + qualityGate: { + command: "npm run check:repo", + passed: false, + evidenceRef: "quality-gate:not-passed", + }, + gates: { + codexLocalHostActivation: { + status: "blocked", + artifactVersion: pkg.version ?? "0.0.0", + artifactSha256: null, + observesHostToolInvocation: false, + authorityCreated: false, + evidenceRefs: [], + }, + publicDistributionAndRegistry: { + status: "blocked", + localVersion: pkg.version ?? "0.0.0", + npmLatestVersion: null, + currentSurfacePublished: false, + mcpRegistryAccepted: false, + mcpRegistryDiscoverable: false, + provenanceAttempted: false, + provenanceSupported: null, + proofGapReasonCodes: ["npm_latest_readback_failed"], + evidenceRefs: [], + }, + customerGatewayLiveX402PaidProof: { + status: "blocked", + customerGatewayCustodyPresent: false, + livePaidRetryPerformed: false, + terminalReadbackPresent: false, + signerInvocationPosture: "not_observed", + proofGapReasonCodes: ["customer_gateway_custody_packet_absent"], + evidenceRefs: [], + }, + authMdX402AdmissionPacket: { + packetVersion: "v0", + packetProjectorPresent: false, + refusalFirstTestsPassed: false, + redactedReadbackTestsPassed: false, + createsAuthority: false, + evidenceRefs: [], + }, + dualEnforcementPosture: { + dualEnforcementPostureTestPassed: false, + mutationManifestGatingTestPassed: false, + evidenceRefs: ["evidence:test:dual-enforcement-posture:pending"], + }, + perCustomerBypassScaffold: { + customerOnboardingRef: null, + firstPartyDogfoodCustomerId: null, + evidenceRefs: [], + }, + }, + }); +} + +function optionValue(args, flag) { + const index = args.indexOf(flag); + if (index === -1) return null; + return args[index + 1] ?? null; +} diff --git a/scripts/check-published-entrypoints.mjs b/scripts/check-published-entrypoints.mjs index 9badaac..f139d17 100644 --- a/scripts/check-published-entrypoints.mjs +++ b/scripts/check-published-entrypoints.mjs @@ -22,6 +22,7 @@ const requiredPublishedFiles = [ "dist/adapter-sdk/index.mjs", "dist/cli/index.mjs", "dist/mcp/index.mjs", + "dist/surfaces/a2a-negotiation-readback/index.mjs", "dist/x402-protected-tool/index.mjs", "dist/bin/handshake.mjs", "dist/bin/handshake-mcp.mjs", @@ -54,6 +55,7 @@ assert.ok(cliOutput.nonClaims.includes("broad MCP/CLI/browser/shell/network cont await checkMcpStdioBin(); await checkRoleClientsSubpath(); +await checkA2ANegotiationReadbackSubpath(); await checkX402ProtectedToolSubpath(); async function checkRoleClientsSubpath() { @@ -74,6 +76,28 @@ async function checkRoleClientsSubpath() { assert.equal(/ReceiptExport|AuthorityCertificateMint|PaymentPayload/u.test(exportNames.join(" ")), false); } +async function checkA2ANegotiationReadbackSubpath() { + const readback = await import("handshake-protocol-kernel/surfaces/a2a-negotiation-readback"); + const exportNames = Object.keys(readback).sort(); + assert.deepEqual(exportNames, [ + "A2ANegotiationProductReadbackSchema", + "A2ANegotiationReadbackInputSchema", + "a2aNegotiationReadbackNonClaims", + "projectA2ANegotiationProductReadback", + "renderA2ANegotiationAgentHandoff", + "renderA2ANegotiationCustomerReadback", + ]); + assert.equal(typeof readback.projectA2ANegotiationProductReadback, "function"); + assert.equal(typeof readback.renderA2ANegotiationCustomerReadback, "function"); + assert.equal(typeof readback.renderA2ANegotiationAgentHandoff, "function"); + assert.equal("HandshakeKernel" in readback, false); + assert.equal("PolicyClient" in readback, false); + assert.equal( + /GatewayCheck|GreenlightSchema|PaymentPayload|PAYMENT-SIGNATURE|runX402WalletGateway/u.test(exportNames.join(" ")), + false, + ); +} + async function checkX402ProtectedToolSubpath() { const x402Tool = await import("handshake-protocol-kernel/x402-protected-tool"); assert.equal(x402Tool.X402_PROTECTED_TOOL_NAME, "handshake.actions.x402_payment.propose"); diff --git a/scripts/check-service-agent-gating-phase.mjs b/scripts/check-service-agent-gating-phase.mjs new file mode 100755 index 0000000..36cba2a --- /dev/null +++ b/scripts/check-service-agent-gating-phase.mjs @@ -0,0 +1,66 @@ +#!/usr/bin/env node +/** + * Phase 04 service-agent-gating gate (D-25). + * Does not assert blocked proof gates green; mutation-route manifest deferred in operator tier. + */ +import { existsSync } from "node:fs"; +import { spawnSync } from "node:child_process"; +import process from "node:process"; + +const args = process.argv.slice(2); +const tierIndex = args.indexOf("--tier"); +const tier = tierIndex >= 0 ? args[tierIndex + 1] : "operator"; + +if (tier !== "operator" && tier !== "full") { + console.error(`Unknown tier: ${tier}. Use --tier operator or --tier full.`); + process.exit(1); +} + +const operatorTests = [ + "test/architecture/operator-product-completion-contract.test.ts", + "test/architecture/dual-enforcement-posture.test.ts", + "test/http/transition-error-failure-class.test.ts", + "test/product/service-operator-bootstrap.test.ts", + "test/integration/service-operator-golden-path.test.ts", + "test/architecture/proof-gap-honesty.test.ts", + "test/architecture/custody-matrix-parity.test.ts", + "test/architecture/http-handler-mutation-gating.test.ts", + "test/sdk/role-clients-failure-class.test.ts", + "test/mcp/mcp-failure-class-parity.test.ts", +]; + +const fullOnlyTests = [ + "test/architecture/maintainer-product-completion-contract.test.ts", + "test/architecture/integrator-parity.test.ts", + "test/adapters/http-profile-canonicalization.test.ts", + "test/adapters/http-profile-orphan-catalog.test.ts", + "test/cli/cli-agent-spine-sequencer.test.ts", +]; + +const suite = tier === "full" ? [...operatorTests, ...fullOnlyTests] : operatorTests; + +function runTest(path) { + if (!existsSync(path)) { + console.error(`MISSING required test: ${path}`); + return { path, ok: false, skipped: false }; + } + const result = spawnSync("bun", ["test", path], { stdio: "inherit" }); + return { path, ok: result.status === 0, skipped: false }; +} + +console.log(`\n=== check-service-agent-gating-phase (${tier} tier) ===\n`); + +const results = suite.map(runTest); +const failed = results.filter((row) => !row.ok); + +console.log("\n--- summary ---"); +for (const row of results) { + console.log(`${row.ok ? "PASS" : "FAIL"} ${row.path}`); +} + +if (failed.length > 0) { + console.error(`\n${failed.length} check(s) failed for tier ${tier}.`); + process.exit(1); +} + +console.log(`\nAll ${results.length} checks passed for tier ${tier}.`); diff --git a/server.json b/server.json index 7428165..cabbd22 100644 --- a/server.json +++ b/server.json @@ -3,12 +3,12 @@ "name": "io.github.CreasyBear/handshake-protocol-kernel", "title": "Handshake Protocol Kernel", "description": "Local MCP stdio proposal/evidence server for Handshake x402 exact protected-spend candidate inspection. It does not issue policy decisions, greenlights, gateway checks, mutations, receipt exports, authority certificates, provider custody, hosted operation, or broad MCP protection.", - "version": "0.2.7", + "version": "0.2.8", "packages": [ { "registryType": "npm", "identifier": "handshake-protocol-kernel", - "version": "0.2.7", + "version": "0.2.8", "transport": { "type": "stdio" } diff --git a/src/adapters/auth-md/action-proposal.ts b/src/adapters/auth-md/action-proposal.ts index 745b5e7..57fed5b 100644 --- a/src/adapters/auth-md/action-proposal.ts +++ b/src/adapters/auth-md/action-proposal.ts @@ -8,6 +8,7 @@ import { CredentialCustodyStatusSchema } from "../../protocol/areas/catalog-enve import type { CompileIntentInput, IntentCompilationRecord } from "../../protocol/areas/intent-compilation"; import { digestCanonical } from "../../protocol/foundation/canonical"; import { DigestSchema, IdSchema, type JsonValue } from "../../protocol/foundation/schema-core"; +import { canonicalizeHttpProfile } from "../http-profile/canonicalize"; import { authMdGatewayCredentialBindingFor, authMdProtectedResourceRef } from "./profiles"; export const AUTH_MD_PROTECTED_API_CALL_PROFILE = "auth_md_protected_api_call.exact.v0"; @@ -219,6 +220,19 @@ async function buildAuthMdProtectedApiCallCompileIntentInputUnchecked( dynamicHostConstructionObserved: attempt.dynamicHostConstructionObserved, retryAuthorityReuseDetected: attempt.retryAuthorityReuseDetected, }) satisfies Record; + const refusalReasonCodes = authMdProtectedApiCallRefusalReasonCodes(attempt); + if (refusalReasonCodes.length === 0) { + canonicalizeHttpProfile({ + targetHttpMethod: parameters.targetHttpMethod, + endpointUrl: parameters.endpointUrl, + pathTemplate: parameters.pathTemplate, + requestBodyDigest: parameters.requestBodyDigest, + selectedHeadersDigest: parameters.selectedHeadersDigest, + dynamicEndpointConstructionObserved: parameters.dynamicEndpointConstructionObserved, + dynamicHostConstructionObserved: parameters.dynamicHostConstructionObserved, + retryAuthorityReuseDetected: parameters.retryAuthorityReuseDetected, + }); + } const idempotencyDigest = await digestCanonical({ profile: AUTH_MD_PROTECTED_API_CALL_PROFILE, protectedResource: attempt.protectedResource, diff --git a/src/adapters/auth-md/gateway.ts b/src/adapters/auth-md/gateway.ts index 9b175c0..3963490 100644 --- a/src/adapters/auth-md/gateway.ts +++ b/src/adapters/auth-md/gateway.ts @@ -17,12 +17,17 @@ import type { } from "../../protocol/areas/operation-lifecycle"; import { digestCanonical } from "../../protocol/foundation/canonical"; import { DigestSchema } from "../../protocol/foundation/schema-core"; +import { HandshakeProtocolError } from "../../protocol/foundation/errors"; import { authMdProtectedApiCallRefusalReasonCodes, AuthMdProtectedApiCallParametersSchema, type AuthMdProtectedApiCallParameters, } from "./action-proposal"; -import { assertNoLeakedAuthMdCredentialMaterial } from "./profiles"; +import { + assertNoLeakedAuthMdCredentialMaterial, + AuthMdProtectedApiCallAllowedHttpMethodSchema, + canonicalizeAuthMdProtectedApiCallExactTransport, +} from "./profiles"; export const AuthMdProtectedApiCallDownstreamStatusSchema = z.enum(["succeeded", "refused", "unknown"]); export type AuthMdProtectedApiCallDownstreamStatus = z.infer; @@ -42,6 +47,61 @@ export const AuthMdProtectedApiCallEvidenceSchema = z.strictObject({ }); export type AuthMdProtectedApiCallEvidence = z.infer; +export const AuthMdProfileConformanceReason = { + missingVerifiedGate: "auth_md_profile_missing_verified_gate", + paramsDigestDrift: "auth_md_profile_params_digest_drift", + leakedCredentialMaterial: "auth_md_profile_leaked_credential_material", +} as const; + +export type AuthMdProfileConformanceInput = { + verifiedGate?: VerifiedGatewayCheck; + parameters?: AuthMdProtectedApiCallParameters; + expectedActionContractId?: string; +}; + +export function assertAuthMdProfileConformance(input: AuthMdProfileConformanceInput): void { + if (!input.verifiedGate) { + throw new HandshakeProtocolError( + AuthMdProfileConformanceReason.missingVerifiedGate, + "auth.md profile conformance requires a verified gateway check before protected API call I/O", + 409, + ); + } + if ( + input.expectedActionContractId && + input.verifiedGate.actionContractId !== input.expectedActionContractId + ) { + throw new HandshakeProtocolError( + AuthMdProfileConformanceReason.paramsDigestDrift, + "auth.md observed parameters drift from verified greenlight action contract binding", + 409, + ); + } + if (input.parameters) { + try { + canonicalizeAuthMdProtectedApiCallExactTransport({ + targetHttpMethod: AuthMdProtectedApiCallAllowedHttpMethodSchema.parse( + input.parameters.targetHttpMethod.trim().toUpperCase(), + ), + endpointUrl: input.parameters.endpointUrl, + pathTemplate: input.parameters.pathTemplate, + requestBodyDigest: input.parameters.requestBodyDigest, + selectedHeadersDigest: input.parameters.selectedHeadersDigest, + dynamicEndpointConstructionObserved: input.parameters.dynamicEndpointConstructionObserved, + dynamicHostConstructionObserved: input.parameters.dynamicHostConstructionObserved, + retryAuthorityReuseDetected: input.parameters.retryAuthorityReuseDetected, + }); + } catch (error) { + throw new HandshakeProtocolError( + AuthMdProfileConformanceReason.paramsDigestDrift, + error instanceof Error ? error.message : "auth.md profile transport canonicalization failed", + 409, + ); + } + assertNoLeakedAuthMdCredentialMaterial(input.parameters); + } +} + export type AuthMdProtectedApiCallCommand = { verifiedGate: VerifiedGatewayCheck; parameters: AuthMdProtectedApiCallParameters; @@ -135,9 +195,40 @@ export async function runAuthMdProtectedApiCallGateway( return { outcome, gatewayCheck, credentialResolutionEvidence: null, reconciliation: null, apiCallEvidence: null }; } + const unsafeObservedReasons = authMdGatewayUnsafeObservedParameterReasons(observedParameters); + if (unsafeObservedReasons.length > 0) { + const failureEvidence = await redactedAuthMdFailureEvidence({ + surfaceOperationRef, + error: new HandshakeProtocolError( + unsafeObservedReasons[0] ?? "auth_md_gateway_observed_parameters_refused", + `auth.md gateway refused unsafe observed parameters: ${unsafeObservedReasons.join(",")}`, + 409, + { refusalRef: `refusal:auth-md-unsafe:${verifiedGate.gateAttemptId}` }, + ), + }); + const { reconciliation } = await input.protocol.reconcileSurfaceOperation({ + mutationAttemptId: verifiedGate.mutationAttemptId, + idempotencyKey: verifiedGate.idempotencyKey, + observedSurfaceOperationRef: surfaceOperationRef, + observedDownstreamStatus: "refused", + ...failureEvidence, + evidenceRefs: [ + ...(failureEvidence.evidenceRefs ?? []), + ...unsafeObservedReasons.map((reasonCode) => `reason_code:${reasonCode}`), + ], + resolvedProofGapIds: [], + }); + return { + outcome: "protected_api_call_failed", + gatewayCheck, + credentialResolutionEvidence: null, + reconciliation, + apiCallEvidence: null, + }; + } + let credentialResolutionEvidence: CredentialResolutionEvidence | null = null; try { - assertNoGatewayUnsafeObservedParameters(observedParameters); const providerRefs = providerRefsForGate(verifiedGate); credentialResolutionEvidence = await input.protocol.recordCredentialResolutionEvidence({ actionContractId: input.actionContractId, @@ -164,7 +255,11 @@ export async function runAuthMdProtectedApiCallGateway( credentialUseRef: `gateway-credential-use:auth-md:${verifiedGate.gateAttemptId}`, ...providerRefs, }; - assertNoLeakedAuthMdCredentialMaterial(command); + assertAuthMdProfileConformance({ + verifiedGate, + parameters: observedParameters, + expectedActionContractId: input.actionContractId, + }); const apiCallEvidence = AuthMdProtectedApiCallEvidenceSchema.parse( await input.surface.executeProtectedApiCall(command), ); @@ -222,8 +317,8 @@ export async function runAuthMdProtectedApiCallGateway( } } -function assertNoGatewayUnsafeObservedParameters(parameters: AuthMdProtectedApiCallParameters): void { - const reasons = authMdProtectedApiCallRefusalReasonCodes({ +function authMdGatewayUnsafeObservedParameterReasons(parameters: AuthMdProtectedApiCallParameters): string[] { + const reasons = [...authMdProtectedApiCallRefusalReasonCodes({ principalIntentRef: "gateway-observed:auth-md-protected-api-call", generatedCodeOrSpecRef: "gateway-observed:auth-md-protected-api-call", protectedResource: parameters.protectedResource, @@ -249,16 +344,14 @@ function assertNoGatewayUnsafeObservedParameters(parameters: AuthMdProtectedApiC dynamicEndpointConstructionObserved: parameters.dynamicEndpointConstructionObserved, dynamicHostConstructionObserved: parameters.dynamicHostConstructionObserved, retryAuthorityReuseDetected: parameters.retryAuthorityReuseDetected, - }); - if (reasons.length > 0) { - throw new Error(`auth.md gateway refused unsafe observed parameters: ${reasons.join(",")}`); - } + })]; if ( new URL(parameters.protectedResource).origin !== parameters.protectedResourceOrigin || new URL(parameters.endpointUrl).origin !== parameters.endpointOrigin ) { - throw new Error("auth.md gateway refused origin field drift in observed parameters"); + reasons.push("auth_md_protected_resource_origin_mismatch"); } + return reasons; } async function credentialResolutionRequestDigest( diff --git a/src/adapters/auth-md/profiles.ts b/src/adapters/auth-md/profiles.ts index cab4f90..857e9b0 100644 --- a/src/adapters/auth-md/profiles.ts +++ b/src/adapters/auth-md/profiles.ts @@ -4,9 +4,43 @@ import { type GatewayCredentialRef, type RegisterGatewayCredentialRefInput, } from "../../protocol/areas/credential-custody"; +import { canonicalizeHttpProfile } from "../http-profile/canonicalize"; import { digestCanonical } from "../../protocol/foundation/canonical"; import { DigestSchema, IdSchema, IsoDateSchema, type JsonValue } from "../../protocol/foundation/schema-core"; +/** Phase 04 plan `04-08` / D-11: shared HTTP transport canonicalization for auth.md exact profile. */ +export const AUTH_MD_PROTECTED_API_CALL_EXACT_PROFILE = "auth_md_protected_api_call.exact" as const; + +export const AuthMdProtectedApiCallAllowedHttpMethodSchema = z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]); +export type AuthMdProtectedApiCallAllowedHttpMethod = z.infer; + +export const AuthMdProtectedApiCallHeaderAllowlistSchema = z.array( + z.enum(["accept", "content-type", "authorization", "x-request-id", "x-idempotency-key"]), +); +export type AuthMdProtectedApiCallHeaderAllowlist = z.infer; + +export const AuthMdProtectedApiCallExactTransportSchema = z.strictObject({ + targetHttpMethod: AuthMdProtectedApiCallAllowedHttpMethodSchema, + endpointUrl: z.string().url(), + pathTemplate: z + .string() + .min(1) + .refine((value) => value.startsWith("/"), { message: "pathTemplate must start with /" }), + requestBodyDigest: DigestSchema.nullable().default(null), + selectedHeadersDigest: DigestSchema, + dynamicEndpointConstructionObserved: z.boolean().default(false), + dynamicHostConstructionObserved: z.boolean().default(false), + retryAuthorityReuseDetected: z.boolean().default(false), +}); + +export function canonicalizeAuthMdProtectedApiCallExactTransport( + input: z.input, +): z.infer { + const parsed = AuthMdProtectedApiCallExactTransportSchema.parse(input); + const canonical = canonicalizeHttpProfile(parsed); + return AuthMdProtectedApiCallExactTransportSchema.parse(canonical); +} + export const AUTH_MD_REGISTERED_CREDENTIAL_PROFILE = "auth_md_registered_credential.v0"; export const AUTH_MD_DISCOVERY_REDACTION_PROFILE = "auth-md-discovery:v0-redacted"; export const AUTH_MD_REGISTRATION_REDACTION_PROFILE = "auth-md-registration:v0-redacted"; diff --git a/src/adapters/http-profile/canonicalize.ts b/src/adapters/http-profile/canonicalize.ts new file mode 100644 index 0000000..34a5e3e --- /dev/null +++ b/src/adapters/http-profile/canonicalize.ts @@ -0,0 +1,20 @@ +import { z } from "zod"; +import { HttpProtectedMutationProfileSchema, type HttpProtectedMutationProfile } from "./schemas"; + +export function canonicalizeHttpProfile(input: HttpProtectedMutationProfile): HttpProtectedMutationProfile { + const parsed = HttpProtectedMutationProfileSchema.parse(input); + if (parsed.dynamicEndpointConstructionObserved || parsed.dynamicHostConstructionObserved) { + throw new z.ZodError([ + { + code: "custom", + message: "dynamic endpoint or host construction is not allowed on protected HTTP profiles", + path: ["dynamicEndpointConstructionObserved"], + }, + ]); + } + return { + ...parsed, + targetHttpMethod: parsed.targetHttpMethod.trim().toUpperCase(), + pathTemplate: parsed.pathTemplate.trim(), + }; +} diff --git a/src/adapters/http-profile/generic-gateway-skeleton.ts b/src/adapters/http-profile/generic-gateway-skeleton.ts new file mode 100644 index 0000000..a26acb8 --- /dev/null +++ b/src/adapters/http-profile/generic-gateway-skeleton.ts @@ -0,0 +1,24 @@ +import { z } from "zod"; +import { canonicalizeHttpProfile } from "./canonicalize"; +import { HttpProtectedMutationProfileSchema } from "./schemas"; + +export const GENERIC_HTTP_PROFILE_GATEWAY_POSTURE = "definition_only" as const; + +export type GenericHttpProfileGatewaySkeletonResult = { + posture: typeof GENERIC_HTTP_PROFILE_GATEWAY_POSTURE; + proofGapCode: "generic_http_profile_live_mutation_forbidden"; + message: string; +}; + +export function runGenericHttpProfileGatewaySkeleton( + input: unknown, +): GenericHttpProfileGatewaySkeletonResult { + const profile = canonicalizeHttpProfile(HttpProtectedMutationProfileSchema.parse(input)); + void profile; + return { + posture: GENERIC_HTTP_PROFILE_GATEWAY_POSTURE, + proofGapCode: "generic_http_profile_live_mutation_forbidden", + message: + "Generic HTTP profile skeleton validates transport shape only. Family adapters must perform gateway-checked mutation; external PEP is glue, not a substitute for adapter re-check.", + }; +} diff --git a/src/adapters/http-profile/index.ts b/src/adapters/http-profile/index.ts new file mode 100644 index 0000000..54d580e --- /dev/null +++ b/src/adapters/http-profile/index.ts @@ -0,0 +1,12 @@ +export { + canonicalizeHttpProfile, +} from "./canonicalize"; +export { + runGenericHttpProfileGatewaySkeleton, + GENERIC_HTTP_PROFILE_GATEWAY_POSTURE, + type GenericHttpProfileGatewaySkeletonResult, +} from "./generic-gateway-skeleton"; +export { + HttpProtectedMutationProfileSchema, + type HttpProtectedMutationProfile, +} from "./schemas"; diff --git a/src/adapters/http-profile/schemas.ts b/src/adapters/http-profile/schemas.ts new file mode 100644 index 0000000..5bebba5 --- /dev/null +++ b/src/adapters/http-profile/schemas.ts @@ -0,0 +1,15 @@ +import { z } from "zod"; +import { DigestSchema } from "../../protocol/foundation/schema-core"; + +export const HttpProtectedMutationProfileSchema = z.strictObject({ + targetHttpMethod: z.string().min(1), + endpointUrl: z.string().url(), + pathTemplate: z.string().min(1), + requestBodyDigest: DigestSchema.nullable().default(null), + selectedHeadersDigest: DigestSchema, + dynamicEndpointConstructionObserved: z.boolean().default(false), + dynamicHostConstructionObserved: z.boolean().default(false), + retryAuthorityReuseDetected: z.boolean().default(false), +}); + +export type HttpProtectedMutationProfile = z.infer; diff --git a/src/adapters/x402-payment/action-proposal.ts b/src/adapters/x402-payment/action-proposal.ts index a2bf6f1..c3596cf 100644 --- a/src/adapters/x402-payment/action-proposal.ts +++ b/src/adapters/x402-payment/action-proposal.ts @@ -4,7 +4,7 @@ import { DelegatedAuthorityBindingSchema } from "../../protocol/areas/delegated- import { GatewayCredentialBindingSchema } from "../../protocol/areas/credential-custody"; import type { CompileIntentInput, IntentCompilationRecord } from "../../protocol/areas/intent-compilation"; import { digestCanonical } from "../../protocol/foundation/canonical"; -import { DigestSchema } from "../../protocol/foundation/schema-core"; +import { ClearingEvidenceRefsSchema, DigestSchema } from "../../protocol/foundation/schema-core"; import { x402PaymentResourceRef } from "./install-proposal"; import type { X402PaymentRequiredEvidence } from "./upstream-evidence"; @@ -56,6 +56,7 @@ export const X402PaymentAttemptSchema = z.strictObject({ extensionKeys: z.array(z.string().min(1)).default([]), sequenceNumber: z.number().int().nonnegative().default(1), requiredPriorActionContractIds: z.array(z.string().min(1)).default([]), + clearingEvidenceRefs: ClearingEvidenceRefsSchema.default({}), }); export type X402PaymentAttempt = z.input; @@ -381,6 +382,7 @@ async function buildX402PaymentCompileIntentInputUnchecked( ...runtimeConfig.gatewayCredentialBinding.evidenceExpectationRefs, ...runtimeConfig.delegatedAuthorityBinding.evidenceExpectationRefs, ]), + clearingEvidenceRefs: attempt.clearingEvidenceRefs, bounds: { endpointDomain, payee: attempt.payee, diff --git a/src/adapters/x402-payment/install-proposal.ts b/src/adapters/x402-payment/install-proposal.ts index 131f53e..b347de6 100644 --- a/src/adapters/x402-payment/install-proposal.ts +++ b/src/adapters/x402-payment/install-proposal.ts @@ -12,6 +12,7 @@ import { import { InstallProposalCompiledKernelRecordsSchema, InstallProposalSchema, + requireInstallProposalGatewayRegistryEntry, type InstallProposalCompiledKernelRecords, } from "../../install/install-proposal"; import { ProtectedActionAdapterPackSchema } from "../../install/protected-action-adapter-pack"; @@ -199,6 +200,7 @@ export async function buildX402WalletGatewayCredentialRefInput( recordsValue: InstallProposalCompiledKernelRecords | null = proposal.compiledRecords, ): Promise { const records = requireCompiledRecords(recordsValue); + const gatewayRegistryEntry = requireInstallProposalGatewayRegistryEntry(records.gatewayRegistryEntry); const providerRegistryRef = `provider:x402-wallet-gateway:${proposal.walletGatewayProfile.walletGatewayId}`; const providerRegistryDigest = await digestCanonical({ walletGatewayId: proposal.walletGatewayProfile.walletGatewayId, @@ -215,12 +217,12 @@ export async function buildX402WalletGatewayCredentialRefInput( tenantId: proposal.tenantId, organizationId: proposal.organizationId, principalId: proposal.spendBounds.principalId, - gatewayId: records.gatewayRegistryEntry.gatewayId, - gatewayRegistryEntryId: records.gatewayRegistryEntry.gatewayRegistryEntryId, + gatewayId: gatewayRegistryEntry.gatewayId, + gatewayRegistryEntryId: gatewayRegistryEntry.gatewayRegistryEntryId, protectedSurfaceKind: "x402_payment", actionClasses: ["x402_payment.exact"], resourceRefs: [proposal.resourceRef], - resourceNamespaceRef: records.gatewayRegistryEntry.resourceNamespaceRef, + resourceNamespaceRef: gatewayRegistryEntry.resourceNamespaceRef, credentialKind: "x402_wallet_signer", custodyStatus: credentialCustodyStatusForWalletSigner(proposal.walletGatewayProfile.signerCustodyStatus), providerClass: "x402_wallet_gateway", @@ -255,6 +257,7 @@ export async function buildX402DelegatedSpendAuthorityRefInput( recordsValue: InstallProposalCompiledKernelRecords | null = proposal.compiledRecords, ): Promise { const records = requireCompiledRecords(recordsValue); + const gatewayRegistryEntry = requireInstallProposalGatewayRegistryEntry(records.gatewayRegistryEntry); return { tenantId: proposal.tenantId, organizationId: proposal.organizationId, @@ -262,8 +265,8 @@ export async function buildX402DelegatedSpendAuthorityRefInput( agentId: proposal.spendBounds.agentId, runtimeAdapterId: proposal.spendBounds.runtimeAdapterId, operatingEnvelopeId: records.operatingEnvelope.envelopeId, - gatewayId: records.gatewayRegistryEntry.gatewayId, - gatewayRegistryEntryId: records.gatewayRegistryEntry.gatewayRegistryEntryId, + gatewayId: gatewayRegistryEntry.gatewayId, + gatewayRegistryEntryId: gatewayRegistryEntry.gatewayRegistryEntryId, protectedSurfaceKind: "x402_payment", actionClasses: ["x402_payment.exact"], resourceRefs: [proposal.resourceRef], diff --git a/src/adapters/x402-payment/wallet-gateway.ts b/src/adapters/x402-payment/wallet-gateway.ts index ac3950a..d9b7367 100644 --- a/src/adapters/x402-payment/wallet-gateway.ts +++ b/src/adapters/x402-payment/wallet-gateway.ts @@ -129,6 +129,63 @@ export interface X402WalletSigningSurface { signPayment(command: X402PaymentSignatureCommand): Promise; } +/** + * D-64 Mechanism A — gateway-held credential custody (structural, not label-only). + * + * The x402 signer must never mint a payment signature unless the command carries a + * genuine {@link VerifiedGatewayCheck} AND gateway-resolved, redacted credential + * resolution evidence bound to that same gate attempt. This makes + * `credentialMaterialPosture: "gateway_held_redacted"` an enforced invariant rather + * than a label: a caller-only path holding a raw `gatewayCredentialRefId` cannot + * reach `signPayment` because it cannot produce gate-bound `used_by_gateway` + * resolution evidence. Throws on any custody violation. + */ +export function assertGatewayHeldSigningCommand(command: X402PaymentSignatureCommand): void { + const refuse = (reasonCode: string, detail: string): never => { + throw new Error(`x402 gateway-held custody refused signing (${reasonCode}): ${detail}`); + }; + + const gate = command.verifiedGate; + if (gate.gatewayCheckStatus !== "passed") { + refuse("gateway_check_not_authoritative", "verified gate status is not passed."); + } + const requiredGateIds: ReadonlyArray<[keyof VerifiedGatewayCheck, string]> = [ + ["gateAttemptId", gate.gateAttemptId], + ["mutationAttemptId", gate.mutationAttemptId], + ["surfaceOperationRef", gate.surfaceOperationRef], + ["actionContractId", gate.actionContractId], + ["greenlightId", gate.greenlightId], + ["gatewayId", gate.gatewayId], + ["idempotencyKey", gate.idempotencyKey], + ]; + for (const [field, value] of requiredGateIds) { + if (!value) refuse("gateway_check_not_authoritative", `verified gate ${String(field)} is empty.`); + } + + const evidence = command.credentialResolutionEvidence; + if (!evidence) { + refuse("credential_resolution_evidence_missing", "no gateway credential resolution evidence present."); + } + if (evidence.credentialMaterialIncluded !== false) { + refuse("credential_material_not_redacted", "resolution evidence must not include credential material."); + } + if (evidence.resultClass !== "used_by_gateway") { + refuse("credential_not_used_by_gateway", `resolution evidence resultClass is ${evidence.resultClass}.`); + } + if (evidence.redactionStatus !== "redacted") { + refuse("credential_resolution_not_redacted", `resolution evidence redactionStatus is ${evidence.redactionStatus}.`); + } + if (evidence.gateAttemptId !== gate.gateAttemptId) { + refuse("credential_resolution_gate_unbound", "resolution evidence is not bound to the verified gate attempt."); + } + if (evidence.actionContractId !== gate.actionContractId) { + refuse("credential_resolution_contract_unbound", "resolution evidence is not bound to the gate action contract."); + } + if (evidence.greenlightId !== gate.greenlightId) { + refuse("credential_resolution_greenlight_unbound", "resolution evidence is not bound to the gate greenlight."); + } +} + export type CreateOfficialExactX402SigningSurfaceInput = { signer: ClientEvmSigner; paymentRequired: unknown; @@ -234,13 +291,15 @@ export async function runX402WalletGateway(input: X402WalletGatewayInput): Promi `digest:${observedParameters.policyVersionDigest}`, ], }); - const signatureEvidence = await input.surface.signPayment({ + const signingCommand: X402PaymentSignatureCommand = { verifiedGate, parameters: observedParameters, credentialResolutionEvidence, credentialUseRef: `gateway-credential-use:x402:${verifiedGate.gateAttemptId}`, ...providerRefs, - }); + }; + assertGatewayHeldSigningCommand(signingCommand); + const signatureEvidence = await input.surface.signPayment(signingCommand); const evidenceRefs = [ signatureEvidence.evidenceRef, signatureEvidence.paymentSignatureHeaderRef, @@ -313,6 +372,7 @@ export function createOfficialExactX402SigningSurface( return { async signPayment(command: X402PaymentSignatureCommand): Promise { + assertGatewayHeldSigningCommand(command); const paymentIdentifierDigest = await verifyPaymentIdentifierBinding({ parameters: command.parameters, paymentIdentifier, diff --git a/src/cli/LANE.md b/src/cli/LANE.md index b8c9c17..0b3a425 100644 --- a/src/cli/LANE.md +++ b/src/cli/LANE.md @@ -12,6 +12,10 @@ The first CLI slice can inspect a local APS report, verify a supplied terminal c Let an operator or operator automation inspect local/reference evidence with machine-readable JSON while preserving custody separation from runtime, gateway, and protocol authority. +Service workflow evidence may be displayed as admission/readback context. A +`ServiceWorkflowHandle` never makes a CLI command agent-safe, retry-safe, or +authorized to run protected work. + ## Constraints and assumptions The CLI is not an agent hot path. Runtime proposal belongs to SDK/MCP, gateway checks belong to gateway custody, and policy decisions remain kernel/control-plane authority. First-slice CLI commands are evidence or posture commands only. @@ -51,3 +55,8 @@ Extract after command metadata, JSON envelope, redaction posture, evidence wrapp ## Scope boundary The CLI may render local evidence and verify supplied terminal certificates. It must not evaluate policy, mint greenlights, perform gateway checks, start protected mutation processes, export raw receipts, or infer authorization from command success. + +It must also not infer authorization from `Passport`, +`ServiceWorkflowAdmission`, or `ServiceWorkflowHandle` records. Those records +can help an operator find evidence and proof gaps; protected action clearance +still requires a fresh exact action contract. diff --git a/src/cli/command-manifest.ts b/src/cli/command-manifest.ts index c1525cf..51d2eb3 100644 --- a/src/cli/command-manifest.ts +++ b/src/cli/command-manifest.ts @@ -21,6 +21,9 @@ export type CliCommandManifestEntry = { readonly nonGoals: readonly string[]; }; +export const cliServiceWorkflowPosture = + "CLI surface only: local setup, readiness, and evidence readback; does not create ServiceWorkflowAdmission, ServiceWorkflowHandle, clearance, policy decision, greenlight, gateway check, mutation, receipt export, or certificate." as const; + const sharedNonGoals = [ "policy evaluation", "gateway check", @@ -28,6 +31,7 @@ const sharedNonGoals = [ "credential custody", "raw record access", "process startup", + "workflow handle authority", ] as const; export const cliCommandManifest = [ @@ -91,6 +95,24 @@ export const cliCommandManifest = [ redactionPosture: "redacted_projection_only", nonGoals: sharedNonGoals, }, + { + id: "evidence.fetch", + aliases: ["evidence fetch"], + status: "active", + plane: "evidence", + custodyRole: "review_custody", + routeFamilies: ["evidence_projection_read"], + filesystemReads: [ + "optional local .handshake/evidence/operations readback json when --cwd is set", + "HANDSHAKE_BASE_URL or --base-url HTTP evidence readback", + ], + filesystemWrites: [], + childProcessEnvInheritance: "none", + outputSchema: CLI_SCHEMA_VERSION, + agentSafe: true, + redactionPosture: "redacted_projection_only", + nonGoals: sharedNonGoals, + }, { id: "evidence.contract-view", aliases: ["evidence contract-view"], @@ -222,6 +244,77 @@ export const cliCommandManifest = [ redactionPosture: "redacted_projection_only", nonGoals: sharedNonGoals, }, + { + id: "host.doctor", + aliases: ["host doctor"], + status: "active", + plane: "operator", + custodyRole: "none", + routeFamilies: [], + filesystemReads: [".handshake/project.json", "external role credential profile"], + filesystemWrites: [], + childProcessEnvInheritance: "none", + outputSchema: CLI_SCHEMA_VERSION, + agentSafe: true, + redactionPosture: "manifest_only", + nonGoals: [...sharedNonGoals, "parallel identity system", "gateway readiness certification"], + }, + { + id: "quickstart.x402", + aliases: ["quickstart x402"], + status: "active", + plane: "operator", + custodyRole: "none", + routeFamilies: [], + filesystemReads: [".handshake/project.json", "optional x402 install input json path"], + filesystemWrites: [], + childProcessEnvInheritance: "none", + outputSchema: CLI_SCHEMA_VERSION, + agentSafe: false, + redactionPosture: "redacted_projection_only", + nonGoals: [...sharedNonGoals, "live control-plane registration", "signer use"], + }, + { + id: "quickstart.agent-spine", + aliases: ["quickstart agent-spine"], + status: "active", + plane: "operator", + custodyRole: "none", + routeFamilies: [], + filesystemReads: [".handshake/project.json"], + filesystemWrites: [], + childProcessEnvInheritance: "none", + outputSchema: CLI_SCHEMA_VERSION, + agentSafe: false, + redactionPosture: "redacted_projection_only", + nonGoals: [ + ...sharedNonGoals, + "bundled execute API", + "greenlight reuse", + "authority creation", + "live x402 operation beyond quickstart scope", + ], + }, + { + id: "simulate.x402-payment", + aliases: ["simulate x402-payment"], + status: "active", + plane: "operator", + custodyRole: "none", + routeFamilies: [], + filesystemReads: [".handshake/project.json"], + filesystemWrites: [], + childProcessEnvInheritance: "none", + outputSchema: CLI_SCHEMA_VERSION, + agentSafe: true, + redactionPosture: "redacted_projection_only", + nonGoals: [ + ...sharedNonGoals, + "live wallet operation", + "bundled execute API", + "greenlight reuse", + ], + }, { id: "conformance.x402-payment", aliases: ["conformance x402-payment"], @@ -237,6 +330,27 @@ export const cliCommandManifest = [ redactionPosture: "redacted_projection_only", nonGoals: [...sharedNonGoals, "broad x402 compatibility"], }, + { + id: "service.bootstrap", + aliases: ["service bootstrap"], + status: "active", + plane: "operator", + custodyRole: "none", + routeFamilies: ["install_health_read"], + filesystemReads: [".handshake/project.json", "optional x402 install input json path"], + filesystemWrites: [], + childProcessEnvInheritance: "none", + outputSchema: CLI_SCHEMA_VERSION, + agentSafe: false, + redactionPosture: "redacted_projection_only", + nonGoals: [ + ...sharedNonGoals, + "live wallet mutation", + "second action-family install", + "orphan catalog without compiled-records transition", + "signer use", + ], + }, ] as const satisfies readonly CliCommandManifestEntry[]; export function cliSchemaOutput() { @@ -249,5 +363,7 @@ export function cliSchemaOutput() { outputSchema: command.outputSchema, agentSafe: command.agentSafe, redactionPosture: command.redactionPosture, + nonGoals: command.nonGoals, + workflowPosture: cliServiceWorkflowPosture, })); } diff --git a/src/cli/evidence/fetch.ts b/src/cli/evidence/fetch.ts new file mode 100644 index 0000000..61db5d8 --- /dev/null +++ b/src/cli/evidence/fetch.ts @@ -0,0 +1,54 @@ +import { readFile } from "node:fs/promises"; +import { join } from "node:path"; +import { + OperationReadbackProjectionSchema, + type OperationReadbackProjection, +} from "../../protocol/evidence-projections/schemas"; +import { EvidenceClient } from "../../sdk/surface-clients/evidence-client"; +import { evidenceOperationReadbackCliView } from "./operation-readback-view"; +import { cliOutput } from "../output"; + +const DEFAULT_BASE_URL = "http://127.0.0.1:8787"; + +export type EvidenceFetchCommandInput = { + contractId: string; + baseUrl?: string; + cwd?: string; + roleCredential?: string; +}; + +export { evidenceOperationReadbackCliView }; + +export function evidenceOperationReadbackCommand(value: unknown) { + const projection = OperationReadbackProjectionSchema.parse(value); + const view = evidenceOperationReadbackCliView(projection); + return cliOutput({ + command: "evidence operation-readback", + plane: "evidence", + custodyRole: "review_custody", + nextAction: "read_evidence", + redactionProfileRef: projection.redactionProfileRef, + evidenceRefs: projection.evidenceRefs, + result: { projection, view }, + }); +} + +export async function evidenceFetchCommand(input: EvidenceFetchCommandInput) { + const projection = await resolveOperationReadbackProjection(input); + return evidenceOperationReadbackCommand(projection); +} + +async function resolveOperationReadbackProjection( + input: EvidenceFetchCommandInput, +): Promise { + if (input.cwd) { + const offlinePath = join(input.cwd, ".handshake", "evidence", "operations", `${input.contractId}.readback.json`); + const raw = await readFile(offlinePath, "utf8"); + return OperationReadbackProjectionSchema.parse(JSON.parse(raw)); + } + + const baseUrl = input.baseUrl ?? process.env.HANDSHAKE_BASE_URL ?? DEFAULT_BASE_URL; + const roleCredential = input.roleCredential ?? process.env.HANDSHAKE_REVIEW_CUSTODY_TOKEN ?? "review-custody-dev"; + const client = new EvidenceClient(baseUrl, { roleCredential, readRole: "review_custody" }); + return client.getOperationReadbackProjection(input.contractId); +} diff --git a/src/cli/evidence/operation-readback-view.ts b/src/cli/evidence/operation-readback-view.ts new file mode 100644 index 0000000..7c6aacd --- /dev/null +++ b/src/cli/evidence/operation-readback-view.ts @@ -0,0 +1,38 @@ +import type { OperationReadbackProjection } from "../../protocol/evidence-projections/schemas"; + +/** D-57: compilation stages are readback-only — never authority-bearing labels. */ +export const OPERATION_READBACK_STAGE_ORDER = [ + "intent_compilation", + "candidate_action", + "action_contract", + "policy_decision", + "greenlight", + "gateway_check", + "mutation_attempt", + "receipt", + "recovery", + "isolation", +] as const; + +export function evidenceOperationReadbackCliView(projection: OperationReadbackProjection) { + return { + schemaVersion: "handshake.cli.operation-readback-view.v1" as const, + viewBoundary: "redacted_cli_projection_view" as const, + title: `Operation ${projection.actionContractRef}`, + status: projection.operationStatus, + stage: projection.latestAuthoritativeStage, + nextMechanism: projection.nextMechanism, + stageOrder: OPERATION_READBACK_STAGE_ORDER, + correlationSummary: { + policyDecisionRef: projection.policyDecisionRef, + greenlightRef: projection.greenlightRef, + gateAttemptRef: projection.gateAttemptRef, + receiptRef: projection.receiptRef, + }, + nonClaims: [ + "Readback does not issue greenlights", + "Readback does not perform gateway checks", + "Compilation stages do not grant authority", + ], + }; +} diff --git a/src/cli/host/doctor.ts b/src/cli/host/doctor.ts new file mode 100644 index 0000000..dc843ea --- /dev/null +++ b/src/cli/host/doctor.ts @@ -0,0 +1,56 @@ +import { digestCanonical } from "../../protocol/foundation/canonical"; +import { doctorLocalProject } from "../local-project"; +import { cliNonClaims, cliOutput } from "../output"; + +export async function hostDoctorCommand(input: { cwd: string }) { + const local = await doctorLocalProject(input.cwd); + const attestationDigest = await digestCanonical({ + status: local.status, + reasonCodes: local.reasonCodes, + configRef: local.configRef, + workspaceRef: local.workspaceRef, + }); + + return cliOutput({ + command: "host doctor", + plane: "operator", + ok: local.status === "ready", + reasonCodes: local.reasonCodes, + nextAction: local.status === "ready" ? "read_result" : "fix_install", + retryability: local.status === "ready" ? "not_retryable" : "retryable_after_fix", + redactionProfileRef: "cli-host-doctor:v1-redacted", + nonClaims: [ + ...cliNonClaims, + "parallel identity system", + "hosted trust anchor", + "gateway readiness certification", + ], + warnings: [ + "Host doctor output is attestation evidence for binding digests only (D-23).", + "No ServiceWorkflowAdmission, greenlight, gateway check, or mutation was performed.", + "configMutationPerformedByDoctor: false", + ], + result: { + ...local, + evidenceKind: "cli_diagnostic" as const, + liveHostVerificationStatus: "not_performed" as const, + configMutationPerformedByDoctor: false, + attestationEvidence: { + bindingDigestRefs: { + configRef: local.configRef, + workspaceRef: local.workspaceRef, + trustBundleRef: local.trustBundleRef, + }, + policyVersionDigest: local.x402InstallRef, + gatewayReadinessDigest: local.x402GatewayReadinessRef, + }, + attestationEvidenceRef: `handshake://local/host-doctor/${attestationDigest.slice("sha256:".length, "sha256:".length + 16)}`, + attestationDigest, + bindingDigestInputs: { + configRef: local.configRef, + workspaceRef: local.workspaceRef, + trustBundleRef: local.trustBundleRef, + }, + }, + }); +} diff --git a/src/cli/index.ts b/src/cli/index.ts index 7ec9f16..17e87bc 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -10,6 +10,15 @@ export { installHealthProjectionCommand, } from "./projection-evidence"; export { runCliCommand } from "./main"; +export { + defaultX402BootstrapInstallInput, + runServiceBootstrap, + serviceBootstrapCommand, +} from "./service-operator/bootstrap"; +export { hostDoctorCommand } from "./host/doctor"; +export { runAgentSpineQuickstart } from "./quickstart/agent-spine"; +export { runX402Quickstart } from "./quickstart/x402"; +export { simulateX402PaymentCommand } from "./simulate/x402-payment"; export { CLI_SCHEMA_VERSION, cliOutput, cliNonClaims } from "./output"; export type { CliOutputEnvelope } from "./output"; export { supportBundleCommand } from "./support-bundle"; diff --git a/src/cli/main.ts b/src/cli/main.ts index 7457f33..3311638 100644 --- a/src/cli/main.ts +++ b/src/cli/main.ts @@ -4,6 +4,7 @@ import { verifyCertificateCommand } from "./certificate"; import { cliCommandManifest, cliSchemaOutput } from "./command-manifest"; import type { CliCommandPlane } from "./command-manifest"; import { doctorCommand, initCommand } from "./local-project/doctor"; +import { evidenceFetchCommand } from "./evidence/fetch"; import { evidenceContractViewCommand, evidenceReceiptTimelineCommand, @@ -11,6 +12,11 @@ import { } from "./projection-evidence"; import { cliOutput } from "./output"; import { supportBundleCommand } from "./support-bundle"; +import { hostDoctorCommand } from "./host/doctor"; +import { runAgentSpineQuickstart } from "./quickstart/agent-spine"; +import { runX402Quickstart } from "./quickstart/x402"; +import { serviceBootstrapCommand } from "./service-operator/bootstrap"; +import { simulateX402PaymentCommand } from "./simulate/x402-payment"; import { installHealthCommand, installX402PaymentCommand, @@ -64,6 +70,26 @@ export async function runCliCommand(argv: readonly string[]): Promise { nextAction: "fix_arguments", }); } + if (group === "evidence" && subcommand === "fetch") { + const contractId = optionValue(argv, "--contract-id"); + if (!contractId) { + return cliCommandErrorOutput({ + argv, + errorCode: "cli_required_argument_missing", + message: "evidence fetch requires --contract-id .", + nextAction: "fix_arguments", + }); + } + const baseUrl = optionValue(argv, "--base-url"); + const cwd = optionValue(argv, "--cwd"); + const roleCredential = optionValue(argv, "--role-credential"); + return evidenceFetchCommand({ + contractId, + ...(baseUrl ? { baseUrl } : {}), + ...(cwd ? { cwd } : {}), + ...(roleCredential ? { roleCredential } : {}), + }); + } if (group === "evidence" && subcommand === "contract-view" && maybePath) { return evidenceContractViewCommand(await readJsonFile(maybePath)); } @@ -174,6 +200,26 @@ export async function runCliCommand(argv: readonly string[]): Promise { nextAction: "fix_arguments", }); } + if (group === "service" && subcommand === "bootstrap") { + const inputPath = argv.find((part) => !part.startsWith("--") && part !== "service" && part !== "bootstrap"); + return serviceBootstrapCommand({ + installInput: inputPath ? await readJsonFile(inputPath) : undefined, + }); + } + const cwd = optionValue(argv, "--cwd") ?? process.cwd(); + if (group === "host" && subcommand === "doctor") { + return hostDoctorCommand({ cwd }); + } + if (group === "quickstart" && subcommand === "x402") { + const inputPath = argv.find((part) => !part.startsWith("--") && part !== "quickstart" && part !== "x402"); + return runX402Quickstart({ cwd, installInputPath: inputPath ?? null }); + } + if (group === "quickstart" && subcommand === "agent-spine") { + return runAgentSpineQuickstart({ cwd }); + } + if (group === "simulate" && subcommand === "x402-payment") { + return simulateX402PaymentCommand({ cwd }); + } return cliCommandErrorOutput({ argv, errorCode: "cli_command_unsupported", @@ -197,7 +243,10 @@ export function cliCommandErrorOutput(input: { retryability: "retryable_after_fix", commitState: "not_started", redactionProfileRef: "cli-error:v1-redacted", - warnings: ["Command failed before any authority, gateway check, signer use, or protected mutation."], + warnings: [ + "Command failed before any authority, gateway check, signer use, or protected mutation.", + "No ServiceWorkflowAdmission, ServiceWorkflowHandle, clearance, policy decision, greenlight, gateway check, signer use, or protected mutation was created.", + ], result: { errorCode: input.errorCode, message: input.message, diff --git a/src/cli/mcp/doctor.ts b/src/cli/mcp/doctor.ts new file mode 100644 index 0000000..39efa4a --- /dev/null +++ b/src/cli/mcp/doctor.ts @@ -0,0 +1,56 @@ +import { digestCanonical } from "../../protocol/foundation/canonical"; +import { doctorLocalProject } from "../local-project"; +import { cliNonClaims, cliOutput } from "../output"; + +export async function mcpDoctorCommand(input: { cwd: string }) { + const local = await doctorLocalProject(input.cwd); + const attestationDigest = await digestCanonical({ + status: local.status, + reasonCodes: local.reasonCodes, + configRef: local.configRef, + workspaceRef: local.workspaceRef, + }); + + return cliOutput({ + command: "mcp doctor", + plane: "operator", + ok: local.status === "ready", + reasonCodes: local.reasonCodes, + nextAction: local.status === "ready" ? "read_result" : "fix_install", + retryability: local.status === "ready" ? "not_retryable" : "retryable_after_fix", + redactionProfileRef: "cli-mcp-doctor:v1-redacted", + nonClaims: [ + ...cliNonClaims, + "parallel identity system", + "hosted trust anchor", + "gateway readiness certification", + ], + warnings: [ + "MCP doctor output is attestation evidence for binding digests only (D-23).", + "No ServiceWorkflowAdmission, greenlight, gateway check, or mutation was performed.", + "configMutationPerformedByDoctor: false", + ], + result: { + ...local, + evidenceKind: "cli_diagnostic" as const, + liveHostVerificationStatus: "not_performed" as const, + configMutationPerformedByDoctor: false, + attestationEvidence: { + bindingDigestRefs: { + configRef: local.configRef, + workspaceRef: local.workspaceRef, + trustBundleRef: local.trustBundleRef, + }, + policyVersionDigest: local.x402InstallRef, + gatewayReadinessDigest: local.x402GatewayReadinessRef, + }, + attestationEvidenceRef: `handshake://local/mcp-doctor/${attestationDigest.slice("sha256:".length, "sha256:".length + 16)}`, + attestationDigest, + bindingDigestInputs: { + configRef: local.configRef, + workspaceRef: local.workspaceRef, + trustBundleRef: local.trustBundleRef, + }, + }, + }); +} diff --git a/src/cli/output.ts b/src/cli/output.ts index 0ebdc0c..61862c9 100644 --- a/src/cli/output.ts +++ b/src/cli/output.ts @@ -10,6 +10,7 @@ export const cliNonClaims = [ "marketplace certification", "clearing-house readiness", "cross-org AuthorityCertificate trust", + "service workflow admission or handle authority", ] as const; export type CliPlane = "operator" | "evidence"; diff --git a/src/cli/quickstart/agent-spine.ts b/src/cli/quickstart/agent-spine.ts new file mode 100644 index 0000000..5134467 --- /dev/null +++ b/src/cli/quickstart/agent-spine.ts @@ -0,0 +1,81 @@ +import { hostDoctorCommand } from "../host/doctor"; +import { cliNonClaims, cliOutput } from "../output"; +import { simulateX402PaymentCommand } from "../simulate/x402-payment"; +import { runX402Quickstart, type QuickstartStepEnvelope } from "./x402"; + +export type AgentSpineStepEnvelope = QuickstartStepEnvelope; + +export async function runAgentSpineQuickstart(input: { cwd: string }) { + const doctorOutput = await hostDoctorCommand({ cwd: input.cwd }); + const steps: AgentSpineStepEnvelope[] = [ + stepEnvelope("host_doctor", "host doctor", doctorOutput), + ]; + + if (doctorOutput.ok) { + const x402Output = await runX402Quickstart({ cwd: input.cwd }); + const x402Steps = + x402Output.result && typeof x402Output.result === "object" && "steps" in x402Output.result + ? (x402Output.result as { steps: QuickstartStepEnvelope[] }).steps + : []; + for (const step of x402Steps) { + steps.push(step); + } + if (x402Output.ok) { + const simulateOutput = await simulateX402PaymentCommand({ cwd: input.cwd }); + steps.push(stepEnvelope("simulate_x402_payment", "simulate x402-payment", simulateOutput)); + } + } + + const ok = steps.every((step) => step.ok); + return cliOutput({ + command: "quickstart agent-spine", + plane: "operator", + ok, + reasonCodes: steps.flatMap((step) => step.reasonCodes), + nextAction: ok ? "read_result" : "fix_install", + retryability: ok ? "not_retryable" : "retryable_after_fix", + redactionProfileRef: "cli-quickstart-agent-spine:v1-redacted", + nonClaims: [ + ...cliNonClaims, + "bundled execute API", + "greenlight reuse", + "live wallet mutation", + "authority creation", + ], + warnings: [ + "Convenience sequencer only — equivalent to host doctor, quickstart x402, then simulate x402-payment in order.", + "No greenlight, gateway check, signer use, or protected mutation was performed.", + ], + result: { + recommendedConvenience: true, + canonicalDiscreteCommands: ["host doctor", "quickstart x402", "simulate x402-payment"], + steps, + }, + }); +} + +function stepEnvelope( + stepId: string, + command: string, + output: { + ok: boolean; + reasonCodes: readonly string[]; + evidenceRefs: readonly string[]; + authorityCreated: false; + greenlightCreated: false; + gatewayCheckPerformed: false; + mutationAttempted: false; + }, +): AgentSpineStepEnvelope { + return { + stepId, + command, + ok: output.ok, + reasonCodes: output.reasonCodes, + evidenceRefs: output.evidenceRefs, + authorityCreated: false, + greenlightCreated: false, + gatewayCheckPerformed: false, + mutationAttempted: false, + }; +} diff --git a/src/cli/quickstart/x402.ts b/src/cli/quickstart/x402.ts new file mode 100644 index 0000000..4876d69 --- /dev/null +++ b/src/cli/quickstart/x402.ts @@ -0,0 +1,80 @@ +import { defaultX402BootstrapInstallInput } from "../service-operator/bootstrap"; +import { installX402PaymentCommand, x402PaymentConformanceCommand } from "../x402"; +import { cliNonClaims, cliOutput } from "../output"; + +export type QuickstartStepEnvelope = { + stepId: string; + command: string; + ok: boolean; + reasonCodes: readonly string[]; + evidenceRefs: readonly string[]; + authorityCreated: false; + greenlightCreated: false; + gatewayCheckPerformed: false; + mutationAttempted: false; +}; + +function defaultConformancePosture() { + return { + signerCustodyStatus: "fixture_gateway_held" as const, + rawPrivateKeyEnvStatus: "absent" as const, + directCoreClientSigningStatus: "blocked" as const, + paidFetchClientStatus: "blocked" as const, + paidAxiosClientStatus: "blocked" as const, + rawPaymentSignatureHeaderStatus: "blocked" as const, + siblingX402WrapperStatus: "blocked" as const, + mcpDirectPaymentStatus: "blocked" as const, + tokenPassthroughStatus: "blocked" as const, + wrapperDriftStatus: "absent" as const, + failureClosedStatus: "passed" as const, + }; +} + +export async function runX402Quickstart(input: { cwd: string; installInputPath?: string | null }) { + const compileStep = await installX402PaymentCommand({ + cwd: input.cwd, + inputValue: defaultX402BootstrapInstallInput(), + recordLocal: false, + }); + const steps: QuickstartStepEnvelope[] = [ + stepEnvelope("compile_install_proposal", "install x402-payment", compileStep), + ]; + + const conformanceStep = await x402PaymentConformanceCommand(defaultConformancePosture()); + steps.push(stepEnvelope("conformance_posture", "conformance x402-payment", conformanceStep)); + + const ok = steps.every((step) => step.ok); + return cliOutput({ + command: "quickstart x402", + plane: "operator", + ok, + reasonCodes: steps.flatMap((step) => step.reasonCodes), + nextAction: ok ? "read_result" : "fix_install", + retryability: ok ? "not_retryable" : "retryable_after_fix", + redactionProfileRef: "cli-quickstart-x402:v1-redacted", + nonClaims: [...cliNonClaims, "live control-plane registration", "signer use"], + warnings: [ + "Quickstart compiles local x402 install posture and runs conformance classification.", + "No greenlight, gateway check, wallet mutation, or live registration was performed.", + ], + result: { steps }, + }); +} + +function stepEnvelope( + stepId: string, + command: string, + output: { ok: boolean; reasonCodes: readonly string[]; evidenceRefs: readonly string[] }, +): QuickstartStepEnvelope { + return { + stepId, + command, + ok: output.ok, + reasonCodes: output.reasonCodes, + evidenceRefs: output.evidenceRefs, + authorityCreated: false, + greenlightCreated: false, + gatewayCheckPerformed: false, + mutationAttempted: false, + }; +} diff --git a/src/cli/service-operator/bootstrap.ts b/src/cli/service-operator/bootstrap.ts new file mode 100644 index 0000000..097c682 --- /dev/null +++ b/src/cli/service-operator/bootstrap.ts @@ -0,0 +1,273 @@ +import { z } from "zod"; +import { + compileX402InstallProposal, + X402InstallProposalInputSchema, + type X402InstallProposal, + type X402InstallProposalInput, +} from "../../adapters/x402-payment/install-proposal"; +import type { InstallProposal } from "../../install"; +import { createApp, type WorkerBindings } from "../../http/app"; +import type { CallerAuthTokens } from "../../http/admission/caller-auth"; +import { nowIso } from "../../protocol/foundation/ids"; +import type { InstallSetupResult } from "../../protocol/public/schemas"; +import type { HandshakeFetch } from "../../sdk/client"; +import { InstallClient } from "../../sdk/surface-clients"; +import type { ProtocolStore } from "../../protocol/store/port"; +import { InMemoryProtocolStore } from "../../storage/memory"; +import { cliNonClaims, cliOutput } from "../output"; + +const X402_ACTION_FAMILY = "x402_payment.exact" as const; + +const ServiceBootstrapInputSchema = z.union([ + X402InstallProposalInputSchema, + z.strictObject({ + actionFamily: z.string().min(1).optional(), + installInput: X402InstallProposalInputSchema, + }), +]); + +export type ServiceBootstrapResult = { + outcome: InstallSetupResult["outcome"]; + actionFamily: string; + installProposalId: string; + installDigest: string; + reasonCodes: readonly string[]; + recordRefs: InstallSetupResult["recordRefs"]; + policyPackRef: string | null; + policyPackVersion: string | null; + authorityBoundary: { + authorityCreated: false; + greenlightCreated: false; + gatewayCheckPerformed: false; + mutationAttempted: false; + }; +}; + +type X402BootstrapInstallInputOverrides = Partial< + Omit +> & { + endpointEvidence?: Partial; + walletGatewayProfile?: Partial; + spendBounds?: Partial; +}; + +export function defaultX402BootstrapInstallInput( + overrides: X402BootstrapInstallInputOverrides = {}, +): X402InstallProposalInput { + const { endpointEvidence, walletGatewayProfile, spendBounds, ...restOverrides } = overrides; + const createdAt = restOverrides.createdAt ?? nowIso(); + const digest = `sha256:${"d".repeat(64)}` as const; + return { + tenantId: "tenant_demo", + organizationId: "org_demo", + createdAt, + endpointEvidence: { + endpointUrl: "https://api.example.com/mcp/premium-context", + payee: "0xpayee", + network: "base-sepolia", + token: "USDC", + maxAtomicAmount: "2500", + paymentRequirementsDigest: digest, + facilitatorRef: "facilitator:local", + evidenceRefs: ["evidence:x402-payment-required"], + ...endpointEvidence, + }, + walletGatewayProfile: { + walletGatewayId: "wallet_gateway_local", + gatewayId: "gateway_x402_wallet", + signerCustodyStatus: "fixture_gateway_held", + signerRef: "secretref:service-bootstrap-fixture-signer", + authorityHolderRef: "gateway-authority:x402-wallet", + supportedNetworks: ["base-sepolia"], + supportedTokens: ["USDC"], + ...walletGatewayProfile, + }, + spendBounds: { + principalId: "principal_demo", + agentId: "agent_demo", + runtimeAdapterId: "runtime_codex", + objectiveRef: "intent:service-operator-bootstrap", + allowedDomains: ["api.example.com"], + allowedPayees: ["0xpayee"], + allowedNetworks: ["base-sepolia"], + allowedTokens: ["USDC"], + maxAtomicAmountPerCall: "2500", + maxAtomicAmountPerSession: "10000", + maxAtomicAmountPerDay: "20000", + reviewThresholdAtomicAmount: "5000", + spendWindowEnforcementStatus: "not_enforced_local_metadata", + issuedAt: createdAt, + expiresAt: futureIsoFromNow(), + ...spendBounds, + }, + ...restOverrides, + }; +} + +export function installProposalFromX402(proposal: X402InstallProposal): InstallProposal { + return { + installProposalId: proposal.installProposalId, + schemaVersion: proposal.schemaVersion, + tenantId: proposal.tenantId, + organizationId: proposal.organizationId, + createdAt: proposal.createdAt, + adapterPackId: proposal.adapterPackId, + adapterPackVersion: proposal.adapterPackVersion, + actionFamily: proposal.actionFamily, + protectedSurfaceKind: proposal.protectedSurfaceKind, + resourceRef: proposal.resourceRef, + status: proposal.status, + humanSummary: proposal.humanSummary, + refusalReasonCodes: proposal.refusalReasonCodes, + compiledRecords: proposal.compiledRecords, + policyPackRef: proposal.policyPackRef, + policyPackVersion: proposal.policyPackVersion, + bypassProbePlan: proposal.bypassProbePlan, + receiptExpectationRefs: proposal.receiptExpectationRefs, + installDigest: proposal.installDigest, + }; +} + +export async function runServiceBootstrap(input: { + installInput: unknown; + store?: ProtocolStore; + callerAuthTokens?: CallerAuthTokens; +}): Promise { + const parsed = ServiceBootstrapInputSchema.parse(input.installInput); + const actionFamily = + "installInput" in parsed + ? (parsed.actionFamily ?? X402_ACTION_FAMILY) + : X402_ACTION_FAMILY; + if (actionFamily !== X402_ACTION_FAMILY) { + return refusedBootstrapResult({ + actionFamily, + installProposalId: "install_unsupported_family", + installDigest: `sha256:${"0".repeat(64)}`, + reasonCodes: ["service_bootstrap_x402_only"], + }); + } + + const installInput = "installInput" in parsed ? parsed.installInput : parsed; + const proposal = await compileX402InstallProposal(installInput); + const store = input.store ?? new InMemoryProtocolStore(); + const tokens = + input.callerAuthTokens ?? + ({ + control_plane: "service_bootstrap_control_plane", + runtime_evidence: "service_bootstrap_runtime_evidence", + gateway_custody: "service_bootstrap_gateway_custody", + review_custody: "service_bootstrap_review_custody", + } satisfies CallerAuthTokens); + + const installClient = installClientForStore(store, tokens); + const registration = await installClient.registerInstallProposalCompiledRecords( + installProposalFromX402(proposal), + ); + + return { + outcome: registration.outcome, + actionFamily: proposal.actionFamily, + installProposalId: proposal.installProposalId, + installDigest: proposal.installDigest, + reasonCodes: + registration.outcome === "install_proposal_refused" + ? registration.reasonCodes + : proposal.refusalReasonCodes, + recordRefs: registration.recordRefs, + policyPackRef: proposal.policyPackRef, + policyPackVersion: proposal.policyPackVersion, + authorityBoundary: { + authorityCreated: false, + greenlightCreated: false, + gatewayCheckPerformed: false, + mutationAttempted: false, + }, + }; +} + +export async function serviceBootstrapCommand(input: { installInput?: unknown }) { + const result = await runServiceBootstrap({ + installInput: input.installInput ?? defaultX402BootstrapInstallInput(), + }); + + return cliOutput({ + command: "service bootstrap", + plane: "operator", + ok: result.outcome === "compiled_records_registered", + reasonCodes: [...result.reasonCodes], + nextAction: result.outcome === "compiled_records_registered" ? "read_result" : "fix_install", + retryability: result.outcome === "compiled_records_registered" ? "not_retryable" : "retryable_after_fix", + redactionProfileRef: "cli-service-bootstrap:v1-redacted", + nonClaims: [ + ...cliNonClaims, + "live wallet mutation", + "second action-family install", + "orphan catalog without compiled-records transition", + ], + warnings: [ + "Service bootstrap registers compiled catalog records via control-plane InstallClient only.", + "No greenlight, gateway check, signer use, or protected mutation was performed.", + "x402_payment.exact is the only supported action family in phase 04.", + ], + result, + }); +} + +function workerBindingsFromTokens(tokens: CallerAuthTokens): WorkerBindings { + const env: WorkerBindings = {}; + if (tokens.control_plane !== undefined) env.HANDSHAKE_CONTROL_PLANE_TOKEN = tokens.control_plane; + if (tokens.runtime_evidence !== undefined) env.HANDSHAKE_RUNTIME_EVIDENCE_TOKEN = tokens.runtime_evidence; + if (tokens.gateway_custody !== undefined) env.HANDSHAKE_GATEWAY_CUSTODY_TOKEN = tokens.gateway_custody; + if (tokens.review_custody !== undefined) env.HANDSHAKE_REVIEW_CUSTODY_TOKEN = tokens.review_custody; + return env; +} + +function installClientForStore(store: ProtocolStore, tokens: CallerAuthTokens): InstallClient { + const controlPlaneToken = tokens.control_plane; + if (!controlPlaneToken) { + throw new Error("service bootstrap requires a control_plane caller auth token."); + } + const app = createApp({ store, callerAuthTokens: tokens }); + const env = workerBindingsFromTokens(tokens); + const fetchImpl: HandshakeFetch = async (requestInput, init) => { + const url = new URL(String(requestInput), "http://handshake.test"); + return app.request(`${url.pathname}${url.search}`, init, env); + }; + return new InstallClient( + "http://handshake.test", + { + roleCredential: controlPlaneToken, + requestIdentityFactory: () => "service-bootstrap-request", + originatingIdentity: "ref:cli/service-operator-bootstrap", + }, + fetchImpl, + ); +} + +function refusedBootstrapResult(input: { + actionFamily: string; + installProposalId: string; + installDigest: string; + reasonCodes: readonly string[]; +}): ServiceBootstrapResult { + return { + outcome: "install_proposal_refused", + actionFamily: input.actionFamily, + installProposalId: input.installProposalId, + installDigest: input.installDigest, + reasonCodes: input.reasonCodes, + recordRefs: null, + policyPackRef: null, + policyPackVersion: null, + authorityBoundary: { + authorityCreated: false, + greenlightCreated: false, + gatewayCheckPerformed: false, + mutationAttempted: false, + }, + }; +} + +function futureIsoFromNow(minutes = 10): string { + return new Date(Date.now() + minutes * 60_000).toISOString(); +} diff --git a/src/cli/simulate/x402-payment.ts b/src/cli/simulate/x402-payment.ts new file mode 100644 index 0000000..6c33458 --- /dev/null +++ b/src/cli/simulate/x402-payment.ts @@ -0,0 +1,30 @@ +import { cliNonClaims, cliOutput } from "../output"; + +export async function simulateX402PaymentCommand(input: { cwd: string }) { + return cliOutput({ + command: "simulate x402-payment", + plane: "operator", + ok: true, + reasonCodes: [], + nextAction: "read_result", + retryability: "not_retryable", + redactionProfileRef: "cli-simulate-x402:v1-redacted", + nonClaims: [ + ...cliNonClaims, + "live wallet operation", + "provider settlement", + "bundled execute API", + "greenlight reuse", + ], + warnings: [ + "Simulation is non-authority readback scaffolding only — not a gateway check or mutation.", + "No payment payload was created and no protected surface was mutated.", + ], + result: { + simulationKind: "x402_payment_exact_readback_scaffold", + cwd: input.cwd, + simulatedOutcome: "readback_preview_only", + clearanceChainPresent: false, + }, + }); +} diff --git a/src/cli/x402/index.ts b/src/cli/x402/index.ts index 6e1a684..baba77f 100644 --- a/src/cli/x402/index.ts +++ b/src/cli/x402/index.ts @@ -8,6 +8,7 @@ import { x402FirstWedgeUnsupportedSurfaces, type X402PaymentConformancePosture, } from "../../adapters/x402-payment/conformance"; +import { requireInstallProposalGatewayRegistryEntry } from "../../install/install-proposal"; import { compileX402InstallProposal, X402InstallProposalInputSchema, @@ -98,6 +99,7 @@ export async function installX402PaymentCommand(input: { cwd: string; inputValue evidenceRefs: [recordedRef].filter((ref): ref is string => typeof ref === "string"), warnings: [ "Compiled local x402 posture only; trusted readiness requires control-plane install registration and gateway posture evidence.", + "Trusted readiness is pre-contract service context only; it is not ServiceWorkflowAdmission, ServiceWorkflowHandle, policy, greenlight, gateway check, or mutation authority.", "No greenlight, signer use, gateway check, or mutation was performed.", ], result: { @@ -123,6 +125,7 @@ export async function probesX402PaymentCommand(input: { cwd: string; postureValu evidenceRefs: [recordedRef].filter((ref): ref is string => typeof ref === "string"), warnings: [ "Probe report classifies caller-supplied gateway posture evidence; it is not provider certification, authority, or execution proof.", + "Probe evidence is pre-contract service context only; it is not ServiceWorkflowAdmission, ServiceWorkflowHandle, policy, greenlight, gateway check, or mutation authority.", ], result: { ...report, @@ -154,6 +157,7 @@ export async function registerX402GatewayReadinessCommand(input: { ), warnings: [ "Trusted readiness binds pre-contract install, probe, gateway, policy, and credential posture only.", + "Trusted readiness is pre-contract service context only; it is not ServiceWorkflowAdmission, ServiceWorkflowHandle, policy, greenlight, gateway check, or mutation authority.", "No greenlight, signer use, gateway check, payment payload, or mutation was performed.", ], result: outcome.record @@ -315,12 +319,17 @@ async function buildLocalInstallRecord(input: { refusalReasonCodes: input.proposal.refusalReasonCodes, compiledRecordsIncluded: false, compiledRecordRefs: compiled - ? { - toolCapabilityRef: compiled.toolCapability.toolCapabilityId, - actionTypeRef: compiled.actionType.actionTypeId, - gatewayRegistryEntryRef: compiled.gatewayRegistryEntry.gatewayRegistryEntryId, - operatingEnvelopeRef: compiled.operatingEnvelope.envelopeId, - } + ? (() => { + const gatewayRegistryEntry = requireInstallProposalGatewayRegistryEntry( + compiled.gatewayRegistryEntry, + ); + return { + toolCapabilityRef: compiled.toolCapability.toolCapabilityId, + actionTypeRef: compiled.actionType.actionTypeId, + gatewayRegistryEntryRef: gatewayRegistryEntry.gatewayRegistryEntryId, + operatingEnvelopeRef: compiled.operatingEnvelope.envelopeId, + }; + })() : null, controlPlaneRegistrationRequired: true, controlPlaneRegistrationPerformed: false, diff --git a/src/hosted-admission/LANE.md b/src/hosted-admission/LANE.md new file mode 100644 index 0000000..d1daa77 --- /dev/null +++ b/src/hosted-admission/LANE.md @@ -0,0 +1,77 @@ +# Hosted Admission Lane + +## Authority owner + +Provider-neutral hosted caller evidence helpers and public package exports for +hosted admission integration. + +## Current proof claim + +This lane exposes redacted hosted caller, participant binding, verifier-adapter, +and hosted admission configuration contracts. It does not create protocol +authority, policy decisions, greenlights, gateway checks, payment material, +mutations, receipts, or terminal certificates. + +## Use cases + +Let a hosted workspace consume a narrow package subpath for Clerk, OAuth/OIDC, +service credential, or future provider verifier adapters without importing HTTP +internals or the broad package root. + +## Constraints and assumptions + +Provider SDKs, raw session tokens, private claims, service credentials, and +billing identifiers stay outside this package surface. Provider adapters verify +raw material server-side and return adapter-verified claims that this lane +normalizes into digest/ref evidence only. + +## Core components + +`index.ts` is a curated public face over hosted caller identity normalization, +provider verifier adapter claims, hosted admission config, and readiness +schemas. + +## Failure and scale posture + +If this lane exposes a policy client, gateway client, signer, payment payload, +raw record reader, mutation runner, or receipt export, hosted convenience has +escaped the evidence boundary. + +## Future package target + +Keep this as the only public hosted-admission package subpath unless a separate +package-surface decision proves a narrower follow-on export. + +## Allowed imports + +Hosted HTTP admission schemas and provider-neutral hosted verifier helpers. + +## Forbidden imports + +Protocol kernel internals, storage implementations, SDK role clients, runtime +ingress, MCP tools, gateway adapters, signer factories, provider SDKs, +credential resolvers, mutation runners, receipt export helpers, and raw record +handlers. + +## Guarding tests + +`test/architecture/root-exports.test.ts`, `test/architecture/package-surface.test.ts`, +`scripts/check-package-surface.mjs`, and `scripts/check-published-entrypoints.mjs`. + +## Public surface + +`handshake-protocol-kernel/hosted-admission` is a non-authority hosted +integration surface. The package root must not export these hosted admission +helpers. + +## Extraction trigger + +Extract only if a hosted workspace needs a smaller provider-specific adapter +package. Do not extract to add provider SDK lock-in. + +## Scope boundary + +This lane helps a service produce and validate redacted identity evidence before +kernel transitions. It must not approve spend, widen an operating envelope, +perform policy evaluation, issue greenlights, verify gateway checks, invoke +signers, manage payment, mutate, or claim hosted operation. diff --git a/src/hosted-admission/hosted-admission-config.ts b/src/hosted-admission/hosted-admission-config.ts new file mode 100644 index 0000000..6feb666 --- /dev/null +++ b/src/hosted-admission/hosted-admission-config.ts @@ -0,0 +1,339 @@ +import { z } from "zod"; +import { HandshakeProtocolError } from "../protocol/foundation/errors"; +import type { TransitionCallerRole } from "./roles"; +import type { TransitionCallerIdentity } from "./hosted-caller-identity"; + +export const HostedDeploymentModeSchema = z.enum(["local-dev", "test", "preview", "production"]); +export type HostedDeploymentMode = z.infer; + +export const HostedVerifierStrategySchema = z.enum([ + "local_test_verifier", + "clerk_session", + "oauth_oidc_jwks", + "cloudflare_access_jwt", + "pinned_jwks", + "custom_server_verifier", +]); +export type HostedVerifierStrategy = z.infer; + +export const HostedReadRoleSchema = z.enum(["viewer", "auditor", "operator", "rawEvidenceReader"]); +export type HostedReadRole = z.infer; + +export const HostedScopeSchema = z.enum([ + "evidence:redacted:read", + "evidence:raw:request", + "evidence:raw:read", + "evidence:export:create", + "evidence:retention:admin", + "hosted:readiness:read", +]); +export type HostedScope = z.infer; + +export const HostedTenantSourceSchema = z.enum(["verifier_claims", "route_scope_match", "static_test_scope"]); +export type HostedTenantSource = z.infer; + +export const HostedRawReadPostureSchema = z.enum(["unavailable", "disabled", "gated", "allowed"]); +export type HostedRawReadPosture = z.infer; + +export const HostedReadinessStateSchema = z.enum([ + "active", + "configured_but_unverified", + "missing", + "disabled", + "read_only", + "not_promoted", +]); +export type HostedReadinessState = z.infer; + +export const HostedRolePolicySchema = z.strictObject({ + admittedTransitionRoles: z + .array(z.enum(["control_plane", "runtime_evidence", "gateway_custody", "review_custody"])) + .min(1), +}); +export type HostedRolePolicy = z.infer; + +export const HostedReadEntitlementSchema = z.strictObject({ + allowedRoles: z.array(HostedReadRoleSchema).min(1), + requiredScopes: z.array(HostedScopeSchema).min(1), +}); +export type HostedReadEntitlement = z.infer; + +export const HostedStorageBindingPostureSchema = z.strictObject({ + bindingName: z.string().min(1).max(200), + required: z.boolean(), + authority: z.enum(["structured_evidence", "non_authoritative_cache"]), +}); +export type HostedStorageBindingPosture = z.infer; + +export const HostedAdmissionConfigSchema = z + .strictObject({ + deploymentMode: HostedDeploymentModeSchema, + verifierStrategy: HostedVerifierStrategySchema, + maxIdentityAgeSeconds: z.number().int().positive().max(86_400), + rolePolicy: HostedRolePolicySchema, + readPolicy: z.strictObject({ + redactedEvidence: HostedReadEntitlementSchema, + rawEvidence: HostedReadEntitlementSchema, + readiness: HostedReadEntitlementSchema, + }), + tenantSource: HostedTenantSourceSchema, + storage: z.strictObject({ + d1: HostedStorageBindingPostureSchema, + kv: HostedStorageBindingPostureSchema, + }), + secretNames: z.array(z.string().min(1).max(200)), + publicVarNames: z.array(z.string().min(1).max(200)), + rawReadPosture: HostedRawReadPostureSchema, + redactionProfileRefs: z.array(z.string().min(1).max(200)).min(1), + retentionPosture: z.enum(["not_configured", "declared_non_certified", "disabled"]), + exportPosture: z.enum(["disabled", "redacted_only", "not_configured"]), + readinessExpectations: z.array(z.string().min(1).max(500)).min(1), + }) + .superRefine((config, ctx) => { + if (!config.readPolicy.redactedEvidence.requiredScopes.includes("evidence:redacted:read")) { + ctx.addIssue({ + code: "custom", + path: ["readPolicy", "redactedEvidence", "requiredScopes"], + message: "Redacted evidence reads must require evidence:redacted:read.", + }); + } + if (!config.readPolicy.rawEvidence.requiredScopes.includes("evidence:raw:read")) { + ctx.addIssue({ + code: "custom", + path: ["readPolicy", "rawEvidence", "requiredScopes"], + message: "Raw evidence reads must require evidence:raw:read.", + }); + } + if (!config.readPolicy.rawEvidence.requiredScopes.includes("evidence:raw:request")) { + ctx.addIssue({ + code: "custom", + path: ["readPolicy", "rawEvidence", "requiredScopes"], + message: "Raw evidence reads must require evidence:raw:request.", + }); + } + if (!config.readPolicy.rawEvidence.allowedRoles.includes("rawEvidenceReader")) { + ctx.addIssue({ + code: "custom", + path: ["readPolicy", "rawEvidence", "allowedRoles"], + message: "Raw evidence reads must require rawEvidenceReader role.", + }); + } + if (!config.readPolicy.readiness.requiredScopes.includes("hosted:readiness:read")) { + ctx.addIssue({ + code: "custom", + path: ["readPolicy", "readiness", "requiredScopes"], + message: "Hosted readiness reads must require hosted:readiness:read.", + }); + } + if (config.storage.d1.authority !== "structured_evidence") { + ctx.addIssue({ + code: "custom", + path: ["storage", "d1", "authority"], + message: "Hosted protocol records must declare D1 as structured evidence authority.", + }); + } + if (config.storage.kv.authority !== "non_authoritative_cache") { + ctx.addIssue({ + code: "custom", + path: ["storage", "kv", "authority"], + message: "KV must be declared non-authoritative for hosted evidence.", + }); + } + if ( + (config.deploymentMode === "preview" || config.deploymentMode === "production") && + config.secretNames.length === 0 + ) { + ctx.addIssue({ + code: "custom", + path: ["secretNames"], + message: "Promoted hosted modes must declare required secret names.", + }); + } + }); + +export type HostedAdmissionConfig = z.infer; +export type HostedAdmissionConfigInput = z.input; + +export const HostedReadinessReportSchema = z.strictObject({ + configured: z.boolean(), + deploymentMode: HostedDeploymentModeSchema.nullable(), + readinessState: HostedReadinessStateSchema, + authorityClass: z.literal("hosted_admission_and_redacted_evidence_read_only"), + hostedMutationAuthorityCreated: z.literal(false), + paymentManagementCreated: z.literal(false), + settlementAuthorityCreated: z.literal(false), + providerCustodyCreated: z.literal(false), + verifier: z.strictObject({ + strategy: HostedVerifierStrategySchema.nullable(), + serverVerifierConfigured: z.boolean(), + maxIdentityAgeSeconds: z.number().int().positive().nullable(), + }), + roles: z.strictObject({ + admittedTransitionRoles: z.array( + z.enum(["control_plane", "runtime_evidence", "gateway_custody", "review_custody"]), + ), + redactedEvidenceRoles: z.array(HostedReadRoleSchema), + rawEvidenceRoles: z.array(HostedReadRoleSchema), + readinessRoles: z.array(HostedReadRoleSchema), + redactedEvidenceScopes: z.array(HostedScopeSchema), + rawEvidenceScopes: z.array(HostedScopeSchema), + readinessScopes: z.array(HostedScopeSchema), + }), + tenantSource: HostedTenantSourceSchema.nullable(), + storage: z.strictObject({ + d1: z.strictObject({ + bindingName: z.string().nullable(), + required: z.boolean(), + present: z.boolean(), + authority: z.enum(["structured_evidence", "missing"]), + environmentPosture: z.enum(["local_or_injected", "remote_required", "unknown"]), + schema: z.strictObject({ + checked: z.boolean(), + status: z.enum(["present", "missing", "not_checked", "error"]), + requiredTableRefs: z.array(z.string()), + missingTableRefs: z.array(z.string()), + }), + }), + kv: z.strictObject({ + bindingName: z.string().nullable(), + required: z.boolean(), + present: z.boolean(), + authority: z.literal("non_authoritative_cache"), + }), + }), + secrets: z.array( + z.strictObject({ + name: z.string(), + present: z.boolean(), + }), + ), + publicVars: z.array( + z.strictObject({ + name: z.string(), + present: z.boolean(), + }), + ), + rawReadPosture: HostedRawReadPostureSchema.nullable(), + redactionProfileRefs: z.array(z.string()), + retentionPosture: z.enum(["not_configured", "declared_non_certified", "disabled"]).nullable(), + exportPosture: z.enum(["disabled", "redacted_only", "not_configured"]).nullable(), + readinessExpectations: z.array(z.string()), + unsupportedCapabilities: z.array(z.string()), +}); +export type HostedReadinessReport = z.infer; + +export function requireHostedAdmissionConfig(config: HostedAdmissionConfigInput | undefined): HostedAdmissionConfig { + if (!config) { + throw new HandshakeProtocolError( + "hosted_admission_config_not_configured", + "Hosted admission requires explicit deployment-mode authority, storage, read, raw-read, and secret-name posture.", + 503, + { retryability: "terminal", commitState: "not_started" }, + ); + } + const parsed = HostedAdmissionConfigSchema.safeParse(config); + if (!parsed.success) { + throw new HandshakeProtocolError( + "hosted_admission_config_invalid", + "Hosted admission config did not satisfy the deployment-mode authority schema.", + 503, + { retryability: "terminal", commitState: "not_started" }, + ); + } + return parsed.data; +} + +export function parseOptionalHostedAdmissionConfig( + config: HostedAdmissionConfigInput | undefined, +): HostedAdmissionConfig | null { + if (!config) return null; + return requireHostedAdmissionConfig(config); +} + +export function assertHostedTransitionRolesConfigured( + config: HostedAdmissionConfig, + requiredRoles: readonly TransitionCallerRole[], +): void { + const missingRoles = requiredRoles.filter((role) => !config.rolePolicy.admittedTransitionRoles.includes(role)); + if (missingRoles.length > 0) { + throw new HandshakeProtocolError( + "hosted_transition_role_not_admitted", + `Hosted deployment config does not admit ${missingRoles.join(" or ")} transition custody.`, + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +export function assertHostedRedactedEvidenceEntitlement( + identity: TransitionCallerIdentity, + config: HostedAdmissionConfig, +): void { + assertHostedReadEntitlement(identity, config.readPolicy.redactedEvidence, "hosted_read_entitlement_forbidden"); +} + +export function assertHostedReadinessEntitlement( + identity: TransitionCallerIdentity, + config: HostedAdmissionConfig, +): void { + assertHostedReadEntitlement(identity, config.readPolicy.readiness, "hosted_readiness_entitlement_forbidden"); +} + +export function assertHostedRawEvidenceEntitlement( + identity: TransitionCallerIdentity, + config: HostedAdmissionConfig, + headers: Headers, + now: string, +): void { + if (config.rawReadPosture === "unavailable" || config.rawReadPosture === "disabled") { + throw new HandshakeProtocolError( + "hosted_raw_read_unavailable", + `Hosted raw evidence reads are ${config.rawReadPosture}.`, + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } + assertHostedReadEntitlement(identity, config.readPolicy.rawEvidence, "hosted_raw_read_entitlement_forbidden"); + const purpose = headers.get("x-handshake-raw-read-purpose")?.trim(); + const expiresAt = headers.get("x-handshake-raw-read-expires-at")?.trim(); + if (!purpose || !expiresAt) { + throw new HandshakeProtocolError( + "hosted_raw_read_purpose_required", + "Hosted raw evidence reads require explicit purpose and expiry headers.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } + const nowMs = Date.parse(now); + const expiresAtMs = Date.parse(expiresAt); + if ( + !Number.isFinite(nowMs) || + !Number.isFinite(expiresAtMs) || + expiresAtMs <= nowMs || + expiresAtMs > nowMs + 3_600_000 + ) { + throw new HandshakeProtocolError( + "hosted_raw_read_window_invalid", + "Hosted raw evidence read expiry must be parseable, future, and bounded to one hour.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +function assertHostedReadEntitlement( + identity: TransitionCallerIdentity, + entitlement: z.infer, + code: string, +): void { + const roleAllowed = identity.hostedRoles.some((role) => entitlement.allowedRoles.includes(role)); + const scopesAllowed = entitlement.requiredScopes.every((scope) => identity.hostedScopes.includes(scope)); + if (!roleAllowed || !scopesAllowed) { + throw new HandshakeProtocolError( + code, + "Hosted caller identity does not satisfy the configured read role/scope entitlement.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} diff --git a/src/hosted-admission/hosted-caller-identity.ts b/src/hosted-admission/hosted-caller-identity.ts new file mode 100644 index 0000000..de6d3f5 --- /dev/null +++ b/src/hosted-admission/hosted-caller-identity.ts @@ -0,0 +1,353 @@ +import { z } from "zod"; +import { digestCanonical } from "../protocol/foundation/canonical"; +import { HandshakeProtocolError } from "../protocol/foundation/errors"; +import { + DigestSchema, + IdSchema, + IsoDateSchema, + JsonValueSchema, + ParticipantIdentityBindingSchema, + type JsonValue, + type ParticipantIdentityBinding, +} from "../protocol/public/schemas"; +import type { TransitionRequestCallerEvidence } from "../protocol/context/request-contexts"; +import type { TransitionCallerRole } from "./roles"; +import { HostedReadRoleSchema, HostedScopeSchema } from "./hosted-admission-config"; + +export const HostedIdentityProviderKindSchema = z.enum([ + "clerk", + "oauth_oidc", + "cloudflare_access", + "custom_jwt", + "service_credential", + "test_fixture", + "other", +]); +export type HostedIdentityProviderKind = z.infer; + +export const HostedIdentityEvidenceInputSchema = z.strictObject({ + providerKind: HostedIdentityProviderKindSchema, + authProviderRef: z.string().min(1).max(500), + callerIdentityRef: z.string().min(1).max(500).nullable().default(null), + subjectRef: z.string().min(1).max(500).nullable().default(null), + subjectDigest: DigestSchema.nullable().default(null), + tenantId: IdSchema, + organizationId: IdSchema, + projectId: IdSchema.nullable().default(null), + workspaceId: IdSchema.nullable().default(null), + custodyRoles: z.array(z.enum(["control_plane", "runtime_evidence", "gateway_custody", "review_custody"])).min(1), + hostedRoles: z.array(HostedReadRoleSchema).default([]), + hostedScopes: z.array(HostedScopeSchema).default([]), + sessionRef: z.string().min(1).max(500).nullable().default(null), + sessionDigest: DigestSchema.nullable().default(null), + serviceCredentialRef: z.string().min(1).max(500).nullable().default(null), + serviceCredentialDigest: DigestSchema.nullable().default(null), + claims: JsonValueSchema.nullable().default(null), + claimsDigest: DigestSchema.nullable().default(null), + membershipRefs: z.array(z.string().min(1).max(500)).default([]), + evidenceRefs: z.array(z.string().min(1).max(500)).default([]), + issuedAt: IsoDateSchema, + expiresAt: IsoDateSchema, + revocationEpochRef: z.string().min(1).max(500), +}); +export type HostedIdentityEvidenceInput = z.input; +export type HostedIdentityEvidence = z.infer; + +export const TransitionCallerIdentitySchema = z + .strictObject({ + callerIdentityRef: z.string().min(1).max(500), + callerSubjectDigest: DigestSchema, + tenantId: IdSchema, + organizationId: IdSchema, + projectId: IdSchema.nullable().default(null), + workspaceId: IdSchema.nullable().default(null), + custodyRoles: z.array(z.enum(["control_plane", "runtime_evidence", "gateway_custody", "review_custody"])).min(1), + hostedRoles: z.array(HostedReadRoleSchema).default([]), + hostedScopes: z.array(HostedScopeSchema).default([]), + authProviderRef: z.string().min(1).max(500), + authSessionDigest: DigestSchema.nullable().default(null), + serviceCredentialDigest: DigestSchema.nullable().default(null), + issuedAt: IsoDateSchema, + expiresAt: IsoDateSchema, + revocationEpochRef: z.string().min(1).max(500), + claimsDigest: DigestSchema, + }) + .superRefine((identity, ctx) => { + const sourceCount = [identity.authSessionDigest, identity.serviceCredentialDigest].filter(Boolean).length; + if (sourceCount !== 1) { + ctx.addIssue({ + code: "custom", + path: ["authSessionDigest"], + message: "TransitionCallerIdentity must contain exactly one auth source digest.", + }); + } + }); + +export type TransitionCallerIdentity = z.infer; + +export const HostedParticipantIdentityBindingInputSchema = z.strictObject({ + participantRole: z.enum(["principal", "agent"]), + participantRef: IdSchema, + verificationEvidenceRef: z.string().min(1).max(500).nullable().default(null), + bindingEvidenceRef: z.string().min(1).max(500).nullable().default(null), +}); +export type HostedParticipantIdentityBindingInput = z.input; + +export type HostedCallerVerifierInput = { + headers: Headers; + method: string; + url: string; + requiredRole: TransitionCallerRole; + requiredRoles: readonly TransitionCallerRole[]; + routeId: string; + routePath: string; + now: string; +}; + +export type HostedCallerVerifier = { + verify(input: HostedCallerVerifierInput): Promise; +}; + +export type TransitionScope = { + tenantId: string; + organizationId: string; + projectId?: string | null; + workspaceId?: string | null; +}; + +export async function transitionCallerIdentityFromHostedEvidence( + value: HostedIdentityEvidenceInput, +): Promise { + const evidence = HostedIdentityEvidenceInputSchema.parse(value); + const callerSubjectDigest = + evidence.subjectDigest ?? + (evidence.subjectRef + ? await digestCanonical({ + providerKind: evidence.providerKind, + authProviderRef: evidence.authProviderRef, + subjectRef: evidence.subjectRef, + }) + : null); + if (!callerSubjectDigest) { + throw new HandshakeProtocolError( + "hosted_caller_identity_invalid", + "Hosted identity evidence requires either a subject digest or a subject ref that can be digested.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } + + const authSessionDigest = + evidence.sessionDigest ?? + (evidence.sessionRef + ? await digestCanonical({ + providerKind: evidence.providerKind, + authProviderRef: evidence.authProviderRef, + sessionRef: evidence.sessionRef, + }) + : null); + const serviceCredentialDigest = + evidence.serviceCredentialDigest ?? + (evidence.serviceCredentialRef + ? await digestCanonical({ + providerKind: evidence.providerKind, + authProviderRef: evidence.authProviderRef, + serviceCredentialRef: evidence.serviceCredentialRef, + }) + : null); + const claimsDigest = + evidence.claimsDigest ?? + (await digestCanonical({ + providerKind: evidence.providerKind, + authProviderRef: evidence.authProviderRef, + subjectDigest: callerSubjectDigest, + tenantId: evidence.tenantId, + organizationId: evidence.organizationId, + projectId: evidence.projectId, + workspaceId: evidence.workspaceId, + custodyRoles: evidence.custodyRoles, + hostedRoles: evidence.hostedRoles, + hostedScopes: evidence.hostedScopes, + membershipRefs: evidence.membershipRefs, + evidenceRefs: evidence.evidenceRefs, + claims: evidence.claims, + } satisfies JsonValue)); + const callerIdentityRef = + evidence.callerIdentityRef ?? + `hosted-identity:${evidence.providerKind}:${( + await digestCanonical({ + authProviderRef: evidence.authProviderRef, + subjectDigest: callerSubjectDigest, + tenantId: evidence.tenantId, + organizationId: evidence.organizationId, + projectId: evidence.projectId, + workspaceId: evidence.workspaceId, + }) + ).slice("sha256:".length, "sha256:".length + 16)}`; + + return parseHostedCallerIdentity({ + callerIdentityRef, + callerSubjectDigest, + tenantId: evidence.tenantId, + organizationId: evidence.organizationId, + projectId: evidence.projectId, + workspaceId: evidence.workspaceId, + custodyRoles: evidence.custodyRoles, + hostedRoles: evidence.hostedRoles, + hostedScopes: evidence.hostedScopes, + authProviderRef: evidence.authProviderRef, + authSessionDigest, + serviceCredentialDigest, + issuedAt: evidence.issuedAt, + expiresAt: evidence.expiresAt, + revocationEpochRef: evidence.revocationEpochRef, + claimsDigest, + }); +} + +export function participantIdentityBindingFromHostedCallerIdentity( + identityValue: TransitionCallerIdentity, + inputValue: HostedParticipantIdentityBindingInput, +): ParticipantIdentityBinding { + const identity = TransitionCallerIdentitySchema.parse(identityValue); + const input = HostedParticipantIdentityBindingInputSchema.parse(inputValue); + return ParticipantIdentityBindingSchema.parse({ + participantRole: input.participantRole, + participantRef: input.participantRef, + identityProviderRef: identity.authProviderRef, + subjectRef: null, + subjectDigest: identity.callerSubjectDigest, + claimsDigest: identity.claimsDigest, + verificationEvidenceRef: input.verificationEvidenceRef ?? identity.callerIdentityRef, + bindingEvidenceRef: input.bindingEvidenceRef, + issuedAt: identity.issuedAt, + expiresAt: identity.expiresAt, + authorityPosture: "evidence_only", + }); +} + +export function parseHostedCallerIdentity(value: unknown): TransitionCallerIdentity { + const parsed = TransitionCallerIdentitySchema.safeParse(value); + if (!parsed.success) { + const firstIssue = parsed.error.issues[0]?.message; + throw new HandshakeProtocolError( + "hosted_caller_identity_invalid", + firstIssue ?? "Hosted caller identity did not satisfy the transition admission schema.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } + return parsed.data; +} + +export function assertHostedCallerRole(identity: TransitionCallerIdentity, requiredRole: TransitionCallerRole): void { + if (!identity.custodyRoles.includes(requiredRole)) { + throw new HandshakeProtocolError( + "hosted_caller_role_forbidden", + `Hosted caller identity does not satisfy ${requiredRole} transition custody.`, + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +export function assertHostedCallerAnyRole( + identity: TransitionCallerIdentity, + requiredRoles: readonly TransitionCallerRole[], +): void { + if (!requiredRoles.some((role) => identity.custodyRoles.includes(role))) { + throw new HandshakeProtocolError( + "hosted_caller_role_forbidden", + `Hosted caller identity does not satisfy ${requiredRoles.join(" or ")} transition custody.`, + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +export function assertHostedCallerFresh( + identity: TransitionCallerIdentity, + now: string, + maxIdentityAgeSeconds?: number, +): void { + const issuedAt = Date.parse(identity.issuedAt); + const expiresAt = Date.parse(identity.expiresAt); + const nowMs = Date.parse(now); + if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || !Number.isFinite(nowMs)) { + throw new HandshakeProtocolError( + "hosted_caller_identity_invalid", + "Hosted caller identity timestamps are not parseable.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } + if (issuedAt > nowMs || expiresAt <= nowMs) { + throw new HandshakeProtocolError( + "hosted_caller_identity_expired", + "Hosted caller identity is not valid at the transition admission time.", + 412, + { retryability: "terminal", commitState: "not_started" }, + ); + } + if (maxIdentityAgeSeconds !== undefined && nowMs - issuedAt > maxIdentityAgeSeconds * 1000) { + throw new HandshakeProtocolError( + "hosted_caller_identity_stale", + "Hosted caller identity is older than the configured freshness window.", + 412, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +export function assertHostedCallerScope(identity: TransitionCallerIdentity, scope: TransitionScope): void { + if ( + identity.tenantId !== scope.tenantId || + identity.organizationId !== scope.organizationId || + (scope.projectId !== undefined && identity.projectId !== scope.projectId) || + (scope.workspaceId !== undefined && identity.workspaceId !== scope.workspaceId) + ) { + throw new HandshakeProtocolError( + "hosted_caller_scope_forbidden", + "Hosted caller identity cannot write transition records for the requested tenant/org/project/workspace scope.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +export async function transitionCallerEvidenceFromIdentity( + identity: TransitionCallerIdentity, +): Promise { + const callerIdentityClaimsDigest = await digestCanonical({ + callerIdentityRef: identity.callerIdentityRef, + callerSubjectDigest: identity.callerSubjectDigest, + tenantId: identity.tenantId, + organizationId: identity.organizationId, + projectId: identity.projectId, + workspaceId: identity.workspaceId, + custodyRoles: identity.custodyRoles, + hostedRoles: identity.hostedRoles, + hostedScopes: identity.hostedScopes, + authProviderRef: identity.authProviderRef, + authSessionDigest: identity.authSessionDigest, + serviceCredentialDigest: identity.serviceCredentialDigest, + issuedAt: identity.issuedAt, + expiresAt: identity.expiresAt, + revocationEpochRef: identity.revocationEpochRef, + claimsDigest: identity.claimsDigest, + } satisfies JsonValue); + + return { + callerIdentityRef: identity.callerIdentityRef, + callerSubjectDigest: identity.callerSubjectDigest, + callerTenantId: identity.tenantId, + callerOrganizationId: identity.organizationId, + callerIdentityClaimsDigest, + authProviderRef: identity.authProviderRef, + authSessionDigest: identity.authSessionDigest, + serviceCredentialDigest: identity.serviceCredentialDigest, + revocationEpochRef: identity.revocationEpochRef, + callerIdentityIssuedAt: identity.issuedAt, + callerIdentityExpiresAt: identity.expiresAt, + }; +} diff --git a/src/hosted-admission/hosted-verifier-adapter.ts b/src/hosted-admission/hosted-verifier-adapter.ts new file mode 100644 index 0000000..6227ee9 --- /dev/null +++ b/src/hosted-admission/hosted-verifier-adapter.ts @@ -0,0 +1,146 @@ +import { z } from "zod"; +import { HandshakeProtocolError } from "../protocol/foundation/errors"; +import { + HostedIdentityEvidenceInputSchema, + HostedIdentityProviderKindSchema, + transitionCallerIdentityFromHostedEvidence, + type HostedCallerVerifier, + type HostedCallerVerifierInput, + type HostedIdentityProviderKind, + type TransitionCallerIdentity, +} from "./hosted-caller-identity"; + +export const HostedProviderVerificationPostureSchema = z.enum([ + "provider_sdk_verified", + "provider_jwks_verified", + "provider_webhook_verified", + "service_credential_verified", + "fixture_verified", + "custom_verified", +]); +export type HostedProviderVerificationPosture = z.infer; + +export const HostedProviderMembershipPostureSchema = z.enum(["current", "missing", "revoked", "stale", "unknown"]); +export type HostedProviderMembershipPosture = z.infer; + +export const HostedVerifierAdapterClaimsSchema = HostedIdentityEvidenceInputSchema.extend({ + providerVerificationPosture: HostedProviderVerificationPostureSchema, + verificationEvidenceRefs: z.array(z.string().min(1).max(500)).min(1), + revocationEpochEvidenceRefs: z.array(z.string().min(1).max(500)).min(1), + activeOrganizationId: z.string().min(1).max(200).nullable().default(null), + requestedOrganizationId: z.string().min(1).max(200).nullable().default(null), + membershipPosture: HostedProviderMembershipPostureSchema.default("current"), + rawIdentityMaterialPersisted: z.literal(false), + identityProviderLockInCreated: z.literal(false), +}); +export type HostedVerifierAdapterClaims = z.infer; +export type HostedVerifierAdapterClaimsInput = z.input; + +export type HostedVerifierAdapter = { + readonly providerKind: HostedIdentityProviderKind; + verify(input: HostedCallerVerifierInput): Promise; +}; + +export type HostedVerifierAdapterOptions = { + readonly allowedProviderKinds?: readonly HostedIdentityProviderKind[]; + readonly requireActiveOrganization?: boolean; +}; + +export function createHostedCallerVerifierFromAdapter( + adapter: HostedVerifierAdapter, + options: HostedVerifierAdapterOptions = {}, +): HostedCallerVerifier { + return { + async verify(input) { + const claims = HostedVerifierAdapterClaimsSchema.parse(await adapter.verify(input)); + assertAdapterProviderMatches(adapter.providerKind, claims.providerKind); + assertProviderAllowed(claims, options.allowedProviderKinds); + assertActiveOrganization(claims, options.requireActiveOrganization ?? false); + assertMembershipCurrent(claims); + const identityEvidence = HostedIdentityEvidenceInputSchema.strip().parse({ + ...claims, + evidenceRefs: [ + ...claims.evidenceRefs, + ...claims.verificationEvidenceRefs, + ...claims.revocationEpochEvidenceRefs, + ], + }); + return transitionCallerIdentityFromHostedEvidence(identityEvidence); + }, + }; +} + +function assertAdapterProviderMatches( + adapterProviderKind: HostedIdentityProviderKind, + claimsProviderKind: HostedIdentityProviderKind, +): void { + if (adapterProviderKind !== claimsProviderKind) { + throw new HandshakeProtocolError( + "hosted_caller_provider_forbidden", + "Hosted caller verifier adapter returned claims for a different identity provider kind.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +export function isHostedIdentityProviderKind(value: string): value is HostedIdentityProviderKind { + return HostedIdentityProviderKindSchema.safeParse(value).success; +} + +function assertProviderAllowed( + claims: HostedVerifierAdapterClaims, + allowedProviderKinds: readonly HostedIdentityProviderKind[] | undefined, +): void { + if (adapterProviderMismatch(claims.providerKind, allowedProviderKinds)) { + throw new HandshakeProtocolError( + "hosted_caller_provider_forbidden", + "Hosted caller verifier returned an identity provider that is not admitted by this deployment.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +function adapterProviderMismatch( + providerKind: HostedIdentityProviderKind, + allowedProviderKinds: readonly HostedIdentityProviderKind[] | undefined, +): boolean { + return Boolean(allowedProviderKinds && !allowedProviderKinds.includes(providerKind)); +} + +function assertActiveOrganization(claims: HostedVerifierAdapterClaims, requireActiveOrganization: boolean): void { + if (requireActiveOrganization && !claims.activeOrganizationId) { + throw new HandshakeProtocolError( + "hosted_caller_active_org_required", + "Hosted caller verifier did not produce active organization evidence.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } + if ( + claims.activeOrganizationId && + claims.requestedOrganizationId && + claims.activeOrganizationId !== claims.requestedOrganizationId + ) { + throw new HandshakeProtocolError( + "hosted_caller_active_org_mismatch", + "Hosted caller active organization does not match the requested hosted organization scope.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +function assertMembershipCurrent(claims: HostedVerifierAdapterClaims): void { + if (claims.membershipPosture !== "current") { + throw new HandshakeProtocolError( + "hosted_caller_membership_not_current", + "Hosted caller membership evidence is missing, stale, revoked, or unknown.", + 403, + { retryability: "terminal", commitState: "not_started" }, + ); + } +} + +export type HostedVerifierAdapterResult = Promise; diff --git a/src/hosted-admission/index.ts b/src/hosted-admission/index.ts new file mode 100644 index 0000000..e35aee7 --- /dev/null +++ b/src/hosted-admission/index.ts @@ -0,0 +1,64 @@ +export { + HostedAdmissionConfigSchema, + HostedDeploymentModeSchema, + HostedRawReadPostureSchema, + HostedReadEntitlementSchema, + HostedReadRoleSchema, + HostedReadinessReportSchema, + HostedReadinessStateSchema, + HostedRolePolicySchema, + HostedScopeSchema, + HostedStorageBindingPostureSchema, + HostedTenantSourceSchema, + HostedVerifierStrategySchema, + type HostedAdmissionConfig, + type HostedAdmissionConfigInput, + type HostedDeploymentMode, + type HostedRawReadPosture, + type HostedReadEntitlement, + type HostedReadRole, + type HostedReadinessReport, + type HostedReadinessState, + type HostedRolePolicy, + type HostedScope, + type HostedStorageBindingPosture, + type HostedTenantSource, + type HostedVerifierStrategy, +} from "./hosted-admission-config"; +export { + HostedIdentityEvidenceInputSchema, + HostedIdentityProviderKindSchema, + HostedParticipantIdentityBindingInputSchema, + TransitionCallerIdentitySchema, + assertHostedCallerAnyRole, + assertHostedCallerFresh, + assertHostedCallerRole, + assertHostedCallerScope, + parseHostedCallerIdentity, + participantIdentityBindingFromHostedCallerIdentity, + transitionCallerEvidenceFromIdentity, + transitionCallerIdentityFromHostedEvidence, + type HostedCallerVerifier, + type HostedCallerVerifierInput, + type HostedIdentityEvidence, + type HostedIdentityEvidenceInput, + type HostedIdentityProviderKind, + type HostedParticipantIdentityBindingInput, + type TransitionCallerIdentity, + type TransitionScope, +} from "./hosted-caller-identity"; +export { + HostedProviderMembershipPostureSchema, + HostedProviderVerificationPostureSchema, + HostedVerifierAdapterClaimsSchema, + createHostedCallerVerifierFromAdapter, + isHostedIdentityProviderKind, + type HostedProviderMembershipPosture, + type HostedProviderVerificationPosture, + type HostedVerifierAdapter, + type HostedVerifierAdapterClaims, + type HostedVerifierAdapterClaimsInput, + type HostedVerifierAdapterOptions, + type HostedVerifierAdapterResult, +} from "./hosted-verifier-adapter"; +export type { TransitionCallerRole } from "./roles"; diff --git a/src/hosted-admission/roles.ts b/src/hosted-admission/roles.ts new file mode 100644 index 0000000..31077e1 --- /dev/null +++ b/src/hosted-admission/roles.ts @@ -0,0 +1 @@ +export type TransitionCallerRole = "control_plane" | "runtime_evidence" | "gateway_custody" | "review_custody"; diff --git a/src/http/admission/hosted-admission-config.ts b/src/http/admission/hosted-admission-config.ts index 28fd91e..05543c6 100644 --- a/src/http/admission/hosted-admission-config.ts +++ b/src/http/admission/hosted-admission-config.ts @@ -1,334 +1 @@ -import { z } from "zod"; -import { HandshakeProtocolError } from "../../protocol/foundation/errors"; -import type { TransitionCallerRole } from "./caller-auth"; -import type { TransitionCallerIdentity } from "./hosted-caller-identity"; - -export const HostedDeploymentModeSchema = z.enum(["local-dev", "test", "preview", "production"]); -export type HostedDeploymentMode = z.infer; - -export const HostedVerifierStrategySchema = z.enum([ - "local_test_verifier", - "cloudflare_access_jwt", - "pinned_jwks", - "custom_server_verifier", -]); -export type HostedVerifierStrategy = z.infer; - -export const HostedReadRoleSchema = z.enum(["viewer", "auditor", "operator", "rawEvidenceReader"]); -export type HostedReadRole = z.infer; - -export const HostedScopeSchema = z.enum([ - "evidence:redacted:read", - "evidence:raw:request", - "evidence:raw:read", - "evidence:export:create", - "evidence:retention:admin", - "hosted:readiness:read", -]); -export type HostedScope = z.infer; - -export const HostedTenantSourceSchema = z.enum(["verifier_claims", "route_scope_match", "static_test_scope"]); -export type HostedTenantSource = z.infer; - -export const HostedRawReadPostureSchema = z.enum(["unavailable", "disabled", "gated", "allowed"]); -export type HostedRawReadPosture = z.infer; - -export const HostedReadinessStateSchema = z.enum([ - "active", - "configured_but_unverified", - "missing", - "disabled", - "read_only", - "not_promoted", -]); -export type HostedReadinessState = z.infer; - -export const HostedRolePolicySchema = z.strictObject({ - admittedTransitionRoles: z - .array(z.enum(["control_plane", "runtime_evidence", "gateway_custody", "review_custody"])) - .min(1), -}); - -export const HostedReadEntitlementSchema = z.strictObject({ - allowedRoles: z.array(HostedReadRoleSchema).min(1), - requiredScopes: z.array(HostedScopeSchema).min(1), -}); - -export const HostedStorageBindingPostureSchema = z.strictObject({ - bindingName: z.string().min(1).max(200), - required: z.boolean(), - authority: z.enum(["structured_evidence", "non_authoritative_cache"]), -}); - -export const HostedAdmissionConfigSchema = z - .strictObject({ - deploymentMode: HostedDeploymentModeSchema, - verifierStrategy: HostedVerifierStrategySchema, - maxIdentityAgeSeconds: z.number().int().positive().max(86_400), - rolePolicy: HostedRolePolicySchema, - readPolicy: z.strictObject({ - redactedEvidence: HostedReadEntitlementSchema, - rawEvidence: HostedReadEntitlementSchema, - readiness: HostedReadEntitlementSchema, - }), - tenantSource: HostedTenantSourceSchema, - storage: z.strictObject({ - d1: HostedStorageBindingPostureSchema, - kv: HostedStorageBindingPostureSchema, - }), - secretNames: z.array(z.string().min(1).max(200)), - publicVarNames: z.array(z.string().min(1).max(200)), - rawReadPosture: HostedRawReadPostureSchema, - redactionProfileRefs: z.array(z.string().min(1).max(200)).min(1), - retentionPosture: z.enum(["not_configured", "declared_non_certified", "disabled"]), - exportPosture: z.enum(["disabled", "redacted_only", "not_configured"]), - readinessExpectations: z.array(z.string().min(1).max(500)).min(1), - }) - .superRefine((config, ctx) => { - if (!config.readPolicy.redactedEvidence.requiredScopes.includes("evidence:redacted:read")) { - ctx.addIssue({ - code: "custom", - path: ["readPolicy", "redactedEvidence", "requiredScopes"], - message: "Redacted evidence reads must require evidence:redacted:read.", - }); - } - if (!config.readPolicy.rawEvidence.requiredScopes.includes("evidence:raw:read")) { - ctx.addIssue({ - code: "custom", - path: ["readPolicy", "rawEvidence", "requiredScopes"], - message: "Raw evidence reads must require evidence:raw:read.", - }); - } - if (!config.readPolicy.rawEvidence.requiredScopes.includes("evidence:raw:request")) { - ctx.addIssue({ - code: "custom", - path: ["readPolicy", "rawEvidence", "requiredScopes"], - message: "Raw evidence reads must require evidence:raw:request.", - }); - } - if (!config.readPolicy.rawEvidence.allowedRoles.includes("rawEvidenceReader")) { - ctx.addIssue({ - code: "custom", - path: ["readPolicy", "rawEvidence", "allowedRoles"], - message: "Raw evidence reads must require rawEvidenceReader role.", - }); - } - if (!config.readPolicy.readiness.requiredScopes.includes("hosted:readiness:read")) { - ctx.addIssue({ - code: "custom", - path: ["readPolicy", "readiness", "requiredScopes"], - message: "Hosted readiness reads must require hosted:readiness:read.", - }); - } - if (config.storage.d1.authority !== "structured_evidence") { - ctx.addIssue({ - code: "custom", - path: ["storage", "d1", "authority"], - message: "Hosted protocol records must declare D1 as structured evidence authority.", - }); - } - if (config.storage.kv.authority !== "non_authoritative_cache") { - ctx.addIssue({ - code: "custom", - path: ["storage", "kv", "authority"], - message: "KV must be declared non-authoritative for hosted evidence.", - }); - } - if ( - (config.deploymentMode === "preview" || config.deploymentMode === "production") && - config.secretNames.length === 0 - ) { - ctx.addIssue({ - code: "custom", - path: ["secretNames"], - message: "Promoted hosted modes must declare required secret names.", - }); - } - }); - -export type HostedAdmissionConfig = z.infer; -export type HostedAdmissionConfigInput = z.input; - -export const HostedReadinessReportSchema = z.strictObject({ - configured: z.boolean(), - deploymentMode: HostedDeploymentModeSchema.nullable(), - readinessState: HostedReadinessStateSchema, - authorityClass: z.literal("hosted_admission_and_redacted_evidence_read_only"), - hostedMutationAuthorityCreated: z.literal(false), - paymentManagementCreated: z.literal(false), - settlementAuthorityCreated: z.literal(false), - providerCustodyCreated: z.literal(false), - verifier: z.strictObject({ - strategy: HostedVerifierStrategySchema.nullable(), - serverVerifierConfigured: z.boolean(), - maxIdentityAgeSeconds: z.number().int().positive().nullable(), - }), - roles: z.strictObject({ - admittedTransitionRoles: z.array( - z.enum(["control_plane", "runtime_evidence", "gateway_custody", "review_custody"]), - ), - redactedEvidenceRoles: z.array(HostedReadRoleSchema), - rawEvidenceRoles: z.array(HostedReadRoleSchema), - readinessRoles: z.array(HostedReadRoleSchema), - redactedEvidenceScopes: z.array(HostedScopeSchema), - rawEvidenceScopes: z.array(HostedScopeSchema), - readinessScopes: z.array(HostedScopeSchema), - }), - tenantSource: HostedTenantSourceSchema.nullable(), - storage: z.strictObject({ - d1: z.strictObject({ - bindingName: z.string().nullable(), - required: z.boolean(), - present: z.boolean(), - authority: z.enum(["structured_evidence", "missing"]), - environmentPosture: z.enum(["local_or_injected", "remote_required", "unknown"]), - schema: z.strictObject({ - checked: z.boolean(), - status: z.enum(["present", "missing", "not_checked", "error"]), - requiredTableRefs: z.array(z.string()), - missingTableRefs: z.array(z.string()), - }), - }), - kv: z.strictObject({ - bindingName: z.string().nullable(), - required: z.boolean(), - present: z.boolean(), - authority: z.literal("non_authoritative_cache"), - }), - }), - secrets: z.array( - z.strictObject({ - name: z.string(), - present: z.boolean(), - }), - ), - publicVars: z.array( - z.strictObject({ - name: z.string(), - present: z.boolean(), - }), - ), - rawReadPosture: HostedRawReadPostureSchema.nullable(), - redactionProfileRefs: z.array(z.string()), - retentionPosture: z.enum(["not_configured", "declared_non_certified", "disabled"]).nullable(), - exportPosture: z.enum(["disabled", "redacted_only", "not_configured"]).nullable(), - readinessExpectations: z.array(z.string()), - unsupportedCapabilities: z.array(z.string()), -}); -export type HostedReadinessReport = z.infer; - -export function requireHostedAdmissionConfig(config: HostedAdmissionConfigInput | undefined): HostedAdmissionConfig { - if (!config) { - throw new HandshakeProtocolError( - "hosted_admission_config_not_configured", - "Hosted admission requires explicit deployment-mode authority, storage, read, raw-read, and secret-name posture.", - 503, - { retryability: "terminal", commitState: "not_started" }, - ); - } - const parsed = HostedAdmissionConfigSchema.safeParse(config); - if (!parsed.success) { - throw new HandshakeProtocolError( - "hosted_admission_config_invalid", - "Hosted admission config did not satisfy the deployment-mode authority schema.", - 503, - { retryability: "terminal", commitState: "not_started" }, - ); - } - return parsed.data; -} - -export function parseOptionalHostedAdmissionConfig( - config: HostedAdmissionConfigInput | undefined, -): HostedAdmissionConfig | null { - if (!config) return null; - return requireHostedAdmissionConfig(config); -} - -export function assertHostedTransitionRolesConfigured( - config: HostedAdmissionConfig, - requiredRoles: readonly TransitionCallerRole[], -): void { - const missingRoles = requiredRoles.filter((role) => !config.rolePolicy.admittedTransitionRoles.includes(role)); - if (missingRoles.length > 0) { - throw new HandshakeProtocolError( - "hosted_transition_role_not_admitted", - `Hosted deployment config does not admit ${missingRoles.join(" or ")} transition custody.`, - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } -} - -export function assertHostedRedactedEvidenceEntitlement( - identity: TransitionCallerIdentity, - config: HostedAdmissionConfig, -): void { - assertHostedReadEntitlement(identity, config.readPolicy.redactedEvidence, "hosted_read_entitlement_forbidden"); -} - -export function assertHostedReadinessEntitlement( - identity: TransitionCallerIdentity, - config: HostedAdmissionConfig, -): void { - assertHostedReadEntitlement(identity, config.readPolicy.readiness, "hosted_readiness_entitlement_forbidden"); -} - -export function assertHostedRawEvidenceEntitlement( - identity: TransitionCallerIdentity, - config: HostedAdmissionConfig, - headers: Headers, - now: string, -): void { - if (config.rawReadPosture === "unavailable" || config.rawReadPosture === "disabled") { - throw new HandshakeProtocolError( - "hosted_raw_read_unavailable", - `Hosted raw evidence reads are ${config.rawReadPosture}.`, - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } - assertHostedReadEntitlement(identity, config.readPolicy.rawEvidence, "hosted_raw_read_entitlement_forbidden"); - const purpose = headers.get("x-handshake-raw-read-purpose")?.trim(); - const expiresAt = headers.get("x-handshake-raw-read-expires-at")?.trim(); - if (!purpose || !expiresAt) { - throw new HandshakeProtocolError( - "hosted_raw_read_purpose_required", - "Hosted raw evidence reads require explicit purpose and expiry headers.", - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } - const nowMs = Date.parse(now); - const expiresAtMs = Date.parse(expiresAt); - if ( - !Number.isFinite(nowMs) || - !Number.isFinite(expiresAtMs) || - expiresAtMs <= nowMs || - expiresAtMs > nowMs + 3_600_000 - ) { - throw new HandshakeProtocolError( - "hosted_raw_read_window_invalid", - "Hosted raw evidence read expiry must be parseable, future, and bounded to one hour.", - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } -} - -function assertHostedReadEntitlement( - identity: TransitionCallerIdentity, - entitlement: z.infer, - code: string, -): void { - const roleAllowed = identity.hostedRoles.some((role) => entitlement.allowedRoles.includes(role)); - const scopesAllowed = entitlement.requiredScopes.every((scope) => identity.hostedScopes.includes(scope)); - if (!roleAllowed || !scopesAllowed) { - throw new HandshakeProtocolError( - code, - "Hosted caller identity does not satisfy the configured read role/scope entitlement.", - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } -} +export * from "../../hosted-admission/hosted-admission-config"; diff --git a/src/http/admission/hosted-caller-identity.ts b/src/http/admission/hosted-caller-identity.ts index 5f4b5c3..7501e03 100644 --- a/src/http/admission/hosted-caller-identity.ts +++ b/src/http/admission/hosted-caller-identity.ts @@ -1,177 +1 @@ -import { z } from "zod"; -import { digestCanonical } from "../../protocol/foundation/canonical"; -import { HandshakeProtocolError } from "../../protocol/foundation/errors"; -import { DigestSchema, IdSchema, IsoDateSchema, type JsonValue } from "../../protocol/public/schemas"; -import type { TransitionRequestCallerEvidence } from "../../protocol/context/request-contexts"; -import type { TransitionCallerRole } from "./caller-auth"; -import { HostedReadRoleSchema, HostedScopeSchema } from "./hosted-admission-config"; - -export const TransitionCallerIdentitySchema = z - .strictObject({ - callerIdentityRef: z.string().min(1).max(500), - callerSubjectDigest: DigestSchema, - tenantId: IdSchema, - organizationId: IdSchema, - projectId: IdSchema.nullable().default(null), - custodyRoles: z.array(z.enum(["control_plane", "runtime_evidence", "gateway_custody", "review_custody"])).min(1), - hostedRoles: z.array(HostedReadRoleSchema).default([]), - hostedScopes: z.array(HostedScopeSchema).default([]), - authProviderRef: z.string().min(1).max(500), - authSessionDigest: DigestSchema.nullable().default(null), - serviceCredentialDigest: DigestSchema.nullable().default(null), - issuedAt: IsoDateSchema, - expiresAt: IsoDateSchema, - revocationEpochRef: z.string().min(1).max(500), - claimsDigest: DigestSchema, - }) - .superRefine((identity, ctx) => { - const sourceCount = [identity.authSessionDigest, identity.serviceCredentialDigest].filter(Boolean).length; - if (sourceCount !== 1) { - ctx.addIssue({ - code: "custom", - path: ["authSessionDigest"], - message: "TransitionCallerIdentity must contain exactly one auth source digest.", - }); - } - }); - -export type TransitionCallerIdentity = z.infer; - -export type HostedCallerVerifierInput = { - headers: Headers; - method: string; - url: string; - requiredRole: TransitionCallerRole; - requiredRoles: readonly TransitionCallerRole[]; - routeId: string; - routePath: string; - now: string; -}; - -export type HostedCallerVerifier = { - verify(input: HostedCallerVerifierInput): Promise; -}; - -export type TransitionScope = { - tenantId: string; - organizationId: string; -}; - -export function parseHostedCallerIdentity(value: unknown): TransitionCallerIdentity { - const parsed = TransitionCallerIdentitySchema.safeParse(value); - if (!parsed.success) { - throw new HandshakeProtocolError( - "hosted_caller_identity_invalid", - "Hosted caller identity did not satisfy the transition admission schema.", - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } - return parsed.data; -} - -export function assertHostedCallerRole(identity: TransitionCallerIdentity, requiredRole: TransitionCallerRole): void { - if (!identity.custodyRoles.includes(requiredRole)) { - throw new HandshakeProtocolError( - "hosted_caller_role_forbidden", - `Hosted caller identity does not satisfy ${requiredRole} transition custody.`, - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } -} - -export function assertHostedCallerAnyRole( - identity: TransitionCallerIdentity, - requiredRoles: readonly TransitionCallerRole[], -): void { - if (!requiredRoles.some((role) => identity.custodyRoles.includes(role))) { - throw new HandshakeProtocolError( - "hosted_caller_role_forbidden", - `Hosted caller identity does not satisfy ${requiredRoles.join(" or ")} transition custody.`, - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } -} - -export function assertHostedCallerFresh( - identity: TransitionCallerIdentity, - now: string, - maxIdentityAgeSeconds?: number, -): void { - const issuedAt = Date.parse(identity.issuedAt); - const expiresAt = Date.parse(identity.expiresAt); - const nowMs = Date.parse(now); - if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || !Number.isFinite(nowMs)) { - throw new HandshakeProtocolError( - "hosted_caller_identity_invalid", - "Hosted caller identity timestamps are not parseable.", - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } - if (issuedAt > nowMs || expiresAt <= nowMs) { - throw new HandshakeProtocolError( - "hosted_caller_identity_expired", - "Hosted caller identity is not valid at the transition admission time.", - 412, - { retryability: "terminal", commitState: "not_started" }, - ); - } - if (maxIdentityAgeSeconds !== undefined && nowMs - issuedAt > maxIdentityAgeSeconds * 1000) { - throw new HandshakeProtocolError( - "hosted_caller_identity_stale", - "Hosted caller identity is older than the configured freshness window.", - 412, - { retryability: "terminal", commitState: "not_started" }, - ); - } -} - -export function assertHostedCallerScope(identity: TransitionCallerIdentity, scope: TransitionScope): void { - if (identity.tenantId !== scope.tenantId || identity.organizationId !== scope.organizationId) { - throw new HandshakeProtocolError( - "hosted_caller_scope_forbidden", - "Hosted caller identity cannot write transition records for the requested tenant/org scope.", - 403, - { retryability: "terminal", commitState: "not_started" }, - ); - } -} - -export async function transitionCallerEvidenceFromIdentity( - identity: TransitionCallerIdentity, -): Promise { - const callerIdentityClaimsDigest = await digestCanonical({ - callerIdentityRef: identity.callerIdentityRef, - callerSubjectDigest: identity.callerSubjectDigest, - tenantId: identity.tenantId, - organizationId: identity.organizationId, - projectId: identity.projectId, - custodyRoles: identity.custodyRoles, - hostedRoles: identity.hostedRoles, - hostedScopes: identity.hostedScopes, - authProviderRef: identity.authProviderRef, - authSessionDigest: identity.authSessionDigest, - serviceCredentialDigest: identity.serviceCredentialDigest, - issuedAt: identity.issuedAt, - expiresAt: identity.expiresAt, - revocationEpochRef: identity.revocationEpochRef, - claimsDigest: identity.claimsDigest, - } satisfies JsonValue); - - return { - callerIdentityRef: identity.callerIdentityRef, - callerSubjectDigest: identity.callerSubjectDigest, - callerTenantId: identity.tenantId, - callerOrganizationId: identity.organizationId, - callerIdentityClaimsDigest, - authProviderRef: identity.authProviderRef, - authSessionDigest: identity.authSessionDigest, - serviceCredentialDigest: identity.serviceCredentialDigest, - revocationEpochRef: identity.revocationEpochRef, - callerIdentityIssuedAt: identity.issuedAt, - callerIdentityExpiresAt: identity.expiresAt, - }; -} +export * from "../../hosted-admission/hosted-caller-identity"; diff --git a/src/http/admission/hosted-verifier-adapter.ts b/src/http/admission/hosted-verifier-adapter.ts new file mode 100644 index 0000000..8f6adbb --- /dev/null +++ b/src/http/admission/hosted-verifier-adapter.ts @@ -0,0 +1 @@ +export * from "../../hosted-admission/hosted-verifier-adapter"; diff --git a/src/http/admission/transition-sequence-matrix.ts b/src/http/admission/transition-sequence-matrix.ts new file mode 100644 index 0000000..98821fd --- /dev/null +++ b/src/http/admission/transition-sequence-matrix.ts @@ -0,0 +1,122 @@ +import { transitionRouteDefinitions } from "../routes/transition-route-registry"; +import type { TransitionRouteId } from "../routes/transition-invokers"; + +// D4 (05-14): declared transition-sequence prerequisite matrix. +// +// This is an admission-layer ordering contract and drift guard, NOT a second +// policy engine. Per-request rejection of a transition whose prerequisite +// record is missing is already enforced structurally by the route registry's +// `recordScope` resolvers plus the kernel transition guards (e.g. +// `proposeActionContract` requires an `intent_compilation`, `gatewayCheck` +// requires an `action_contract`). This matrix documents the canonical +// prerequisite route(s) — the transition(s) that produce the record each route +// consumes — and `assertTransitionSequenceMatrixCoverage` fails app +// construction if the matrix drifts from the registered route set, mirroring +// `assertMutationRouteManifestParity`. +// +// Each value lists the route(s) whose output record a route's scope resolver +// directly references. Entry-point transitions (direct-body scope: catalog and +// envelope registrations, compilation, runtime-execution evidence, drafts, +// postures, isolation, breaker) have no prerequisite transition. +export const transitionSequenceMatrix: Record = { + // Entry points — direct-body scope, no prerequisite transition. + registerToolCapability: [], + registerActionType: [], + registerGatewayRegistryEntry: [], + registerOperatingEnvelope: [], + registerInstallProposalCompiledRecords: [], + registerGatewayCredentialRef: [], + registerDelegatedAuthorityRef: [], + compileIntent: [], + createRuntimeExecution: [], + proposeRuntimeIngressActionContracts: [], + createBypassProbe: [], + createToolCallDraft: [], + createProtectedPathPosture: [], + createIsolationState: [], + createBreakerDecision: [], + + // Record-scoped transitions — prerequisite = producer of the consumed record. + transitionDelegatedAuthorityStatus: ["registerDelegatedAuthorityRef"], + recordGatewayCustodyProofPacket: ["registerGatewayCredentialRef"], + transitionToolCallDraft: ["createToolCallDraft"], + proposeActionContract: ["compileIntent"], + recordCredentialResolutionEvidence: ["proposeActionContract"], + evaluatePolicy: ["proposeActionContract"], + createReviewArtifact: ["proposeActionContract"], + createReviewDecision: ["proposeActionContract"], + gatewayCheck: ["proposeActionContract"], + reconcileSurfaceOperation: ["gatewayCheck"], + createReceiptExport: ["gatewayCheck"], + createRecoveryRecommendation: ["gatewayCheck"], + transitionRecoveryRecommendationStatus: ["createRecoveryRecommendation"], + resolveRecoveryTerminalConflictProofGap: ["gatewayCheck"], +}; + +/** + * Returns the declared prerequisite transition routes for a route id. + */ +export function prerequisiteTransitionsFor(routeId: TransitionRouteId): readonly TransitionRouteId[] { + return transitionSequenceMatrix[routeId] ?? []; +} + +/** + * Construction-time structural guard (D4). Verifies the sequence matrix stays + * consistent with the registered transition route set: + * - every registered route has exactly one matrix entry (coverage), + * - every prerequisite references a registered route (referential integrity), + * - the prerequisite graph is acyclic (no transition depends on itself). + * + * This catches matrix/registry drift the moment a new transition route is added + * without a declared prerequisite, exactly like the mutation-route manifest + * parity check. It does not authorize or re-evaluate any request. + */ +export function assertTransitionSequenceMatrixCoverage(): void { + const registeredRouteIds = new Set(transitionRouteDefinitions.map((route) => route.routeId)); + const matrixRouteIds = new Set(Object.keys(transitionSequenceMatrix) as TransitionRouteId[]); + + // Construction-time developer drift guard (mirrors assertMutationRouteManifestParity): + // a violation here is a programming error caught at app construction, never a + // request-time protocol refusal — so it throws a plain Error, not a coded + // HandshakeProtocolError with a client-facing transition reason code. + for (const routeId of registeredRouteIds) { + if (!matrixRouteIds.has(routeId)) { + throw new Error(`Transition route ${routeId} has no declared sequence-matrix entry.`); + } + } + for (const routeId of matrixRouteIds) { + if (!registeredRouteIds.has(routeId)) { + throw new Error(`Sequence-matrix entry ${routeId} does not map to a registered transition route.`); + } + for (const prerequisite of transitionSequenceMatrix[routeId]) { + if (!registeredRouteIds.has(prerequisite)) { + throw new Error(`Sequence-matrix entry ${routeId} references unknown prerequisite ${prerequisite}.`); + } + } + } + assertAcyclicSequenceMatrix(); +} + +function assertAcyclicSequenceMatrix(): void { + const visiting = new Set(); + const settled = new Set(); + + const walk = (routeId: TransitionRouteId, trail: readonly TransitionRouteId[]): void => { + if (settled.has(routeId)) return; + if (visiting.has(routeId)) { + throw new Error( + `Transition sequence matrix has a prerequisite cycle: ${[...trail, routeId].join(" -> ")}.`, + ); + } + visiting.add(routeId); + for (const prerequisite of transitionSequenceMatrix[routeId] ?? []) { + walk(prerequisite, [...trail, routeId]); + } + visiting.delete(routeId); + settled.add(routeId); + }; + + for (const routeId of Object.keys(transitionSequenceMatrix) as TransitionRouteId[]) { + walk(routeId, []); + } +} diff --git a/src/http/app.ts b/src/http/app.ts index dfdcb62..6efd72c 100644 --- a/src/http/app.ts +++ b/src/http/app.ts @@ -26,7 +26,12 @@ import { } from "./admission/request-context"; import { transitionErrorResult, type TransitionErrorContext } from "./errors/transition-error-envelope"; import { transitionInvokers } from "./routes/transition-invokers"; +import { assertMutationRouteManifestParity } from "./mutation-route-manifest"; +import { assertTransitionSequenceMatrixCoverage } from "./admission/transition-sequence-matrix"; import { transitionRouteDefinitions, type TransitionRouteDefinition } from "./routes/transition-route-registry"; + +assertMutationRouteManifestParity(); +assertTransitionSequenceMatrixCoverage(); import { kernelFor, storeFor } from "./store/resolution"; import { hideReferenceScopeMismatch } from "./routes/transition-scope-resolvers"; diff --git a/src/http/errors/codes.ts b/src/http/errors/codes.ts index 2f42f9f..8068bc7 100644 --- a/src/http/errors/codes.ts +++ b/src/http/errors/codes.ts @@ -33,6 +33,10 @@ export const httpTransitionErrorCodes = [ code("hosted_caller_identity_revoked", "hosted_admission", "terminal", "not_started", true), code("hosted_caller_role_forbidden", "hosted_admission", "terminal", "not_started", true), code("hosted_caller_scope_forbidden", "hosted_admission", "terminal", "not_started", true), + code("hosted_caller_provider_forbidden", "hosted_admission", "terminal", "not_started", true), + code("hosted_caller_active_org_required", "hosted_admission", "terminal", "not_started", true), + code("hosted_caller_active_org_mismatch", "hosted_admission", "terminal", "not_started", true), + code("hosted_caller_membership_not_current", "hosted_admission", "terminal", "not_started", true), code("hosted_transition_role_not_admitted", "hosted_admission", "terminal", "not_started", true), code("hosted_read_entitlement_forbidden", "hosted_admission", "terminal", "not_started", true), code("hosted_readiness_entitlement_forbidden", "hosted_admission", "terminal", "not_started", true), @@ -57,6 +61,7 @@ export const httpTransitionErrorCodes = [ code("proof_gap_missing", "scope_resolution", "terminal", "not_started", true), code("invalid_protocol_object_type", "record_read", "terminal", "not_applicable", true), code("record_not_found", "record_read", "terminal", "not_applicable", true), + code("action_contract_missing", "record_read", "terminal", "not_applicable", true), code("durable_store_unavailable", "store_resolution", "retryable", "unknown", true), code("invalid_request", "error_envelope", "terminal", "not_started", true), code("internal_error", "error_envelope", "retryable", "unknown", false), diff --git a/src/http/errors/transition-error-envelope.ts b/src/http/errors/transition-error-envelope.ts index c42fab2..f8bd9d1 100644 --- a/src/http/errors/transition-error-envelope.ts +++ b/src/http/errors/transition-error-envelope.ts @@ -5,8 +5,16 @@ import { type TransitionCommitState, type TransitionErrorRetryability, } from "../../protocol/foundation/errors"; +import { problemTypeUriForCode } from "../../protocol/foundation/reason-code-remediation/index"; +import { + classifyFailureClassFromProtocolError, + FailureClassSchema, + type FailureClass, +} from "../../protocol/foundation/failure-class"; +import { resolveProtocolReasonCodeMetadata } from "../../protocol/foundation/reason-codes"; import { JsonValueSchema } from "../../protocol/public/schemas"; import type { TransitionCallerRole } from "../admission/caller-auth"; +import { httpTransitionErrorCodes } from "./codes"; export const TransitionErrorRetryabilitySchema = z.enum([ "retryable", @@ -24,6 +32,10 @@ export const TransitionCommitStateSchema = z.enum([ "not_applicable", ]); +export const TransitionFailureClassSchema = FailureClassSchema; + +export const TransitionFailurePhaseSchema = z.enum(["admission", "transition", "readback"]).nullable(); + export const TransitionErrorEnvelopeSchema = z.strictObject({ code: z.string(), message: z.string(), @@ -34,6 +46,9 @@ export const TransitionErrorEnvelopeSchema = z.strictObject({ requestIdentity: z.string().nullable(), proofRef: z.string().nullable(), refusalRef: z.string().nullable(), + failureClass: TransitionFailureClassSchema, + failurePhase: TransitionFailurePhaseSchema, + problemType: z.string().url().nullable(), issues: z.array(JsonValueSchema).optional(), }); @@ -41,6 +56,8 @@ export const TransitionErrorResponseSchema = z.strictObject({ error: TransitionErrorEnvelopeSchema, }); +export type TransitionFailureClass = FailureClass; +export type TransitionFailurePhase = z.infer; export type TransitionErrorEnvelope = z.infer; export type TransitionErrorResponseBody = z.infer; @@ -48,6 +65,7 @@ export type TransitionErrorContext = { transitionName?: string | null; callerCustodyRole?: TransitionCallerRole | null; requestIdentity?: string | null; + failurePhase?: TransitionFailurePhase; }; export type TransitionErrorResult = { @@ -56,7 +74,7 @@ export type TransitionErrorResult = { }; export function transitionErrorResult(error: unknown, context: TransitionErrorContext = {}): TransitionErrorResult { - const classification = classifyTransitionError(error); + const classification = classifyTransitionError(error, context); const body = TransitionErrorResponseSchema.parse({ error: { code: classification.code, @@ -68,6 +86,9 @@ export function transitionErrorResult(error: unknown, context: TransitionErrorCo requestIdentity: context.requestIdentity ?? null, proofRef: classification.proofRef, refusalRef: classification.refusalRef, + failureClass: classification.failureClass, + failurePhase: classification.failurePhase, + problemType: classification.problemType, ...(classification.issues ? { issues: classification.issues } : {}), }, }); @@ -78,6 +99,65 @@ export function transitionErrorBody(error: unknown, context: TransitionErrorCont return transitionErrorResult(error, context).body; } +export function httpStatusForFailureClass( + failureClass: TransitionFailureClass, + preferredStatus?: number, +): number { + const preferred = + preferredStatus && preferredStatus >= 400 && preferredStatus < 600 ? preferredStatus : undefined; + + switch (failureClass) { + case "auth": + if (preferred === 401 || preferred === 403 || preferred === 503) return preferred; + return 401; + case "hosted_admission": + if (preferred === 401 || preferred === 403 || preferred === 412 || preferred === 503) return preferred; + return 403; + case "stale_admission": + case "protected_action_refusal": + case "replay_refusal": + return 409; + case "proof_gap": + return 422; + case "internal": + return preferred ?? 500; + } +} + +function isStaleHostedAdmissionCode(code: string): boolean { + return code === "hosted_caller_identity_stale"; +} + +export function failureClassForProtocolError(error: HandshakeProtocolError): TransitionFailureClass { + const httpAdmission = httpTransitionErrorCodes.find((entry) => entry.code === error.code); + if (httpAdmission) { + if (httpAdmission.phase === "auth") return "auth"; + if (httpAdmission.phase === "hosted_admission") { + return isStaleHostedAdmissionCode(error.code) ? "stale_admission" : "hosted_admission"; + } + // Ingress/request-shaping HTTP codes (400/404/413, etc.) are not clearance refusals. + // Keep failureClass internal so httpStatusForFailureClass honors error.status. + return "internal"; + } + return classifyFailureClassFromProtocolError(error); +} + +export function failurePhaseForError( + code: string, + context: TransitionErrorContext, +): TransitionFailurePhase { + if (context.failurePhase) return context.failurePhase; + const httpAdmission = httpTransitionErrorCodes.find((entry) => entry.code === code); + if (httpAdmission?.phase === "auth" || httpAdmission?.phase === "hosted_admission") { + return "admission"; + } + if (code.startsWith("caller_auth_") || code.startsWith("hosted_")) return "admission"; + if (code.includes("readiness") || code.includes("read_entitlement")) return "readback"; + const metadata = resolveProtocolReasonCodeMetadata(code); + if (metadata?.phase === "catalog") return "readback"; + return "transition"; +} + type ClassifiedTransitionError = { code: string; message: string; @@ -86,10 +166,13 @@ type ClassifiedTransitionError = { commitState: TransitionCommitState; proofRef: string | null; refusalRef: string | null; + failureClass: TransitionFailureClass; + failurePhase: TransitionFailurePhase; + problemType: string | null; issues?: Array>; }; -function classifyTransitionError(error: unknown): ClassifiedTransitionError { +function classifyTransitionError(error: unknown, context: TransitionErrorContext): ClassifiedTransitionError { if (error instanceof z.ZodError) { return { code: "invalid_request", @@ -99,6 +182,9 @@ function classifyTransitionError(error: unknown): ClassifiedTransitionError { commitState: "not_started", proofRef: null, refusalRef: null, + failureClass: "internal", + failurePhase: failurePhaseForError("invalid_request", context), + problemType: problemTypeUriForCode("invalid_request"), issues: error.issues.map((issue) => ({ code: issue.code, message: issue.message, @@ -108,14 +194,19 @@ function classifyTransitionError(error: unknown): ClassifiedTransitionError { } if (error instanceof HandshakeProtocolError) { + const failureClass = failureClassForProtocolError(error); + const failurePhase = failurePhaseForError(error.code, context); return { code: error.code, message: error.message, - status: error.status, + status: httpStatusForFailureClass(failureClass, error.status), retryability: error.metadata.retryability ?? retryabilityForProtocolError(error), commitState: error.metadata.commitState ?? commitStateForProtocolError(error), proofRef: error.metadata.proofRef ?? null, refusalRef: error.metadata.refusalRef ?? null, + failureClass, + failurePhase, + problemType: problemTypeUriForCode(error.code), }; } @@ -127,6 +218,9 @@ function classifyTransitionError(error: unknown): ClassifiedTransitionError { commitState: "unknown", proofRef: null, refusalRef: null, + failureClass: "internal", + failurePhase: "transition", + problemType: null, }; } diff --git a/src/http/handlers/evidence-read.ts b/src/http/handlers/evidence-read.ts index 5a4e24b..5f1b12e 100644 --- a/src/http/handlers/evidence-read.ts +++ b/src/http/handlers/evidence-read.ts @@ -14,6 +14,8 @@ import { projectAgentTransactionEnvelope, projectContractEvidence, projectIdempotencyRecovery, + projectOperationCorrelationIndex, + projectOperationReadback, projectProtectedPathInstallHealth, projectReceiptTimeline, } from "../../protocol/evidence-projections"; @@ -116,6 +118,29 @@ export async function handleEvidenceRead( }), ); } + case "getOperationReadbackProjection": { + const actionContractId = c.req.param("actionContractId"); + if (!actionContractId) return recordNotFound(c, errorContext); + const contractRecord = await store.getRecord("action_contract", actionContractId); + if (!contractRecord || !callerCanReadRecord(admission.hostedIdentity, contractRecord)) { + return recordNotFound(c, errorContext); + } + const projection = await projectOperationReadback( + await assembleAgentTransactionEnvelopeInput(store, contractRecord.payload), + ); + return c.json(projection); + } + case "getOperationCorrelationIndex": { + const actionContractId = c.req.param("actionContractId"); + if (!actionContractId) return recordNotFound(c, errorContext); + const contractRecord = await store.getRecord("action_contract", actionContractId); + if (!contractRecord || !callerCanReadRecord(admission.hostedIdentity, contractRecord)) { + return recordNotFound(c, errorContext); + } + return c.json( + projectOperationCorrelationIndex(await assembleAgentTransactionEnvelopeInput(store, contractRecord.payload)), + ); + } case "getProtectedPathInstallHealthProjection": { const actionContractId = c.req.param("actionContractId"); if (!actionContractId) return recordNotFound(c, errorContext); diff --git a/src/http/mutation-route-manifest.ts b/src/http/mutation-route-manifest.ts new file mode 100644 index 0000000..46686da --- /dev/null +++ b/src/http/mutation-route-manifest.ts @@ -0,0 +1,82 @@ +/** + * Phase-04 plan 04-11 / D-24 deferred maintainer lane (Phase 05 plan 05-01). + * Frozen HTTP mutation inventory — separate from `boundary-manifest.ts` surface ownership (adjudication #7). + * Inventories existing POST transition routes only; does not add new paths (D-50). + */ + +import type { SurfaceRouteFamily } from "../surfaces/boundary-manifest"; +import { + transitionRouteDefinitions, + type TransitionRouteDefinition, +} from "./routes/transition-route-registry"; + +export type MutationRouteDefinition = { + readonly routeId: TransitionRouteDefinition["routeId"]; + readonly path: TransitionRouteDefinition["path"]; + readonly role: TransitionRouteDefinition["role"]; + readonly summary: TransitionRouteDefinition["summary"]; + readonly surfaceRouteFamily: SurfaceRouteFamily; + readonly requiresAdapterGatewayCheck: true; +}; + +const routeFamilyById: Record = { + registerToolCapability: "catalog_install_write", + registerActionType: "catalog_install_write", + registerGatewayRegistryEntry: "gateway_credential_write", + registerOperatingEnvelope: "catalog_install_write", + registerInstallProposalCompiledRecords: "catalog_install_write", + registerGatewayCredentialRef: "gateway_credential_write", + registerDelegatedAuthorityRef: "delegated_authority_write", + transitionDelegatedAuthorityStatus: "delegated_authority_write", + recordGatewayCustodyProofPacket: "gateway_credential_write", + recordCredentialResolutionEvidence: "gateway_credential_write", + compileIntent: "runtime_evidence_write", + createRuntimeExecution: "runtime_evidence_write", + proposeRuntimeIngressActionContracts: "runtime_ingress_proposal_write", + createBypassProbe: "bypass_probe_write", + createToolCallDraft: "tool_call_draft_write", + transitionToolCallDraft: "tool_call_draft_write", + createProtectedPathPosture: "protected_path_posture_write", + proposeActionContract: "action_contract_proposal_write", + evaluatePolicy: "policy_decision_write", + createReviewArtifact: "runtime_evidence_write", + createReviewDecision: "runtime_evidence_write", + gatewayCheck: "gateway_check_write", + reconcileSurfaceOperation: "surface_reconciliation_write", + createIsolationState: "isolation_write", + createBreakerDecision: "isolation_write", + createReceiptExport: "receipt_export_write", + createRecoveryRecommendation: "recovery_write", + transitionRecoveryRecommendationStatus: "recovery_write", + resolveRecoveryTerminalConflictProofGap: "recovery_write", +}; + +export const mutationRouteDefinitions = transitionRouteDefinitions.map((route) => ({ + routeId: route.routeId, + path: route.path, + role: route.role, + summary: route.summary, + surfaceRouteFamily: routeFamilyById[route.routeId], + requiresAdapterGatewayCheck: true as const, +})) satisfies readonly MutationRouteDefinition[]; + +export function assertMutationRouteManifestParity( + routes: readonly TransitionRouteDefinition[] = transitionRouteDefinitions, +): void { + const manifestPaths = new Set(mutationRouteDefinitions.map((row) => row.path)); + const transitionPaths = new Set(routes.map((row) => row.path)); + const missing = [...transitionPaths].filter((path) => !manifestPaths.has(path)).sort(); + const extra = [...manifestPaths].filter((path) => !transitionPaths.has(path)).sort(); + if (missing.length > 0 || extra.length > 0) { + throw new Error( + `mutation-route-manifest drift: missing=${missing.join(", ") || "none"} extra=${extra.join(", ") || "none"}`, + ); + } + if (mutationRouteDefinitions.length !== routes.length) { + throw new Error( + `mutation-route-manifest count drift: manifest=${mutationRouteDefinitions.length} transitions=${routes.length}`, + ); + } +} + +assertMutationRouteManifestParity(); diff --git a/src/http/openapi/index.ts b/src/http/openapi/index.ts index 9d9b2b1..56610cc 100644 --- a/src/http/openapi/index.ts +++ b/src/http/openapi/index.ts @@ -12,7 +12,10 @@ const HealthResponseSchema = z.strictObject({ version: z.literal(PROTOCOL_VERSION), }); -const errorResponse = jsonResponse("Protocol transition error", TransitionErrorResponseSchema); +const errorResponse = jsonResponse( + "Protocol transition error with failureClass (auth | hosted_admission | protected_action_refusal | proof_gap | replay_refusal | stale_admission | internal), failurePhase, and optional RFC 9457 problemType URI. Status discipline: auth 401/403, hosted_admission 403, clearance refusals/replay/stale 409, proof_gap 422.", + TransitionErrorResponseSchema, +); export const openApiDocument = { openapi: "3.1.0", @@ -79,6 +82,7 @@ function openApiPathFor(route: (typeof transitionRouteDefinitions)[number]) { "404": errorResponse, "409": errorResponse, "412": errorResponse, + "422": errorResponse, "500": errorResponse, "503": errorResponse, }, @@ -98,6 +102,8 @@ function openApiEvidenceReadPathFor(route: (typeof evidenceReadRouteDefinitions) "401": errorResponse, "403": errorResponse, "404": errorResponse, + "409": errorResponse, + "422": errorResponse, "500": errorResponse, "503": errorResponse, }, diff --git a/src/http/routes/evidence-read-route-registry.ts b/src/http/routes/evidence-read-route-registry.ts index f5f66ac..bb052c4 100644 --- a/src/http/routes/evidence-read-route-registry.ts +++ b/src/http/routes/evidence-read-route-registry.ts @@ -4,6 +4,8 @@ import { ContractEvidenceProjectionSchema, GeneratedGraphEvidenceProjectionSchema, IdempotencyRecoveryProjectionSchema, + OperationCorrelationIndexSchema, + OperationReadbackProjectionSchema, ProtectedPathInstallHealthProjectionSchema, ReceiptTimelineProjectionSchema, } from "../../protocol/public/schemas"; @@ -13,6 +15,8 @@ export type EvidenceReadRouteId = | "getGeneratedGraphEvidenceProjection" | "getContractEvidenceProjection" | "getAgentTransactionEnvelopeProjection" + | "getOperationReadbackProjection" + | "getOperationCorrelationIndex" | "getIdempotencyRecoveryProjection" | "getReceiptTimelineProjection" | "getProtectedPathInstallHealthProjection"; @@ -84,6 +88,38 @@ export const evidenceReadRouteDefinitions = [ }, ], }, + { + routeId: "getOperationReadbackProjection", + honoPath: "/v0.2/evidence/operations/:actionContractId/readback", + openApiPath: "/v0.2/evidence/operations/{actionContractId}/readback", + roles: evidenceReadRoles, + summary: "Read redacted operation readback for diagnostics only", + responseDescription: + "Operation readback projection with compilation provenance stages. Inspection evidence only; does not create authority or greenlights.", + responseSchema: OperationReadbackProjectionSchema, + pathParameters: [ + { + name: "actionContractId", + description: "Action contract identifier for operation readback assembly.", + }, + ], + }, + { + routeId: "getOperationCorrelationIndex", + honoPath: "/v0.2/evidence/operations/:actionContractId/correlation", + openApiPath: "/v0.2/evidence/operations/{actionContractId}/correlation", + roles: evidenceReadRoles, + summary: "Read linked operation correlation refs for diagnostics only", + responseDescription: + "Read-only correlation index over existing evidence refs. No mutation routes and no authority creation.", + responseSchema: OperationCorrelationIndexSchema, + pathParameters: [ + { + name: "actionContractId", + description: "Action contract identifier for correlation index assembly.", + }, + ], + }, { routeId: "getIdempotencyRecoveryProjection", honoPath: "/v0.2/evidence/idempotency-recovery/:actionContractId", diff --git a/src/index.ts b/src/index.ts index ba4c881..e0d7b83 100644 --- a/src/index.ts +++ b/src/index.ts @@ -47,4 +47,19 @@ export { } from "./protocol/areas/authority-certificate"; export * from "./protocol/public/inputs"; export * from "./protocol/public/schemas"; +export { + ControlPlaneClient, + EvidenceClient, + GatewayClient, + PolicyClient, + type ControlPlaneClientOptions, + type EvidenceClientOptions, + type EvidenceClientRole, + type GatewayClientCheckResult, + type GatewayClientOptions, + type GatewayClientReconciliationResult, + type PolicyClientEvaluationResult, + type PolicyClientOptions, +} from "./sdk/surface-clients/index"; +export { explainHandshakeError, type HandshakeErrorExplanation } from "./sdk/repair"; export { HandshakeClient, HandshakeClientError, type HandshakeClientOptions, type HandshakeFetch } from "./sdk/client"; diff --git a/src/install/install-proposal/index.ts b/src/install/install-proposal/index.ts index 7460766..0be5589 100644 --- a/src/install/install-proposal/index.ts +++ b/src/install/install-proposal/index.ts @@ -10,6 +10,7 @@ import { type ToolCapability, } from "../../protocol/areas/catalog-envelope"; import { BypassProbeKindSchema } from "../../protocol/areas/bypass-probe"; +import { HandshakeProtocolError } from "../../protocol/foundation/errors"; import { DigestSchema, IdSchema, IsoDateSchema, PROTOCOL_VERSION } from "../../protocol/foundation/schema-core"; export const InstallProposalBypassProbePlanItemSchema = z.strictObject({ @@ -22,16 +23,29 @@ export type InstallProposalBypassProbePlanItem = z.infer; -export function mcpToolResult(structuredContent: SurfaceOutcome, isError = false): McpToolResult { +export function mcpToolResult( + structuredContent: SurfaceOutcome, + isError = false, + failureClass?: FailureClass | null, +): McpToolResult { return McpToolResultSchema.parse({ structuredContent, + ...(failureClass !== undefined ? { failureClass } : {}), isError, content: [{ type: "text", text: JSON.stringify(structuredContent) }], }); @@ -37,7 +48,9 @@ export function mcpNonContractOutcome( input: SurfaceOutcomeBaseInput, isError = input.outcome !== "tools_list_changed", ) { - return mcpToolResult(surfaceOutcomeBase(input), isError); + const reasonCodes = input.reasonCodes ?? []; + const failureClass = classifyFailureClassFromReasonCodes(reasonCodes); + return mcpToolResult(surfaceOutcomeBase(input), isError, failureClass); } export function mcpActionContractProposedOutcome( diff --git a/src/mcp/reference-transcript-fixtures.ts b/src/mcp/reference-transcript-fixtures.ts index 5624129..90c4be6 100644 --- a/src/mcp/reference-transcript-fixtures.ts +++ b/src/mcp/reference-transcript-fixtures.ts @@ -151,6 +151,20 @@ export function referenceEvidenceClient(): McpEvidenceResourceClient { redactionProfileRef: "reference-transcript-redacted", }; }, + async getOperationReadbackProjection(actionContractId: string) { + return { + projection: "operation_readback", + actionContractId, + redactionProfileRef: "reference-transcript-redacted", + }; + }, + async getOperationCorrelationIndex(actionContractId: string) { + return { + projection: "operation_correlation", + actionContractId, + redactionProfileRef: "reference-transcript-redacted", + }; + }, async getReceiptTimelineProjection(receiptId: string) { return { projection: "receipt_timeline", diff --git a/src/mcp/reference-transcript.ts b/src/mcp/reference-transcript.ts index 7ba9e43..f920284 100644 --- a/src/mcp/reference-transcript.ts +++ b/src/mcp/reference-transcript.ts @@ -234,7 +234,8 @@ export async function buildMcpX402ReferenceTranscript(): Promise ref.startsWith("handshake://")) ?? ""; const installHealthRead = installHealthUri ? await readMcpResource(installHealthUri, evidenceClient) : null; const offlineRuntime = referenceRuntimeClient(); diff --git a/src/mcp/resources.ts b/src/mcp/resources.ts index e724fdf..bd67c15 100644 --- a/src/mcp/resources.ts +++ b/src/mcp/resources.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { digestMcp, type McpJsonValue } from "./digest"; import { MCP_SCHEMA_VERSION } from "./output"; +import { mcpServiceWorkflowBoundary } from "./catalog"; export const McpResourceReadSchema = z.strictObject({ schemaVersion: z.literal(MCP_SCHEMA_VERSION), @@ -23,6 +24,8 @@ export type McpResourceRead = z.infer; export type McpEvidenceResourceClient = { getContractEvidenceProjection(actionContractId: string): Promise; getAgentTransactionEnvelopeProjection(actionContractId: string): Promise; + getOperationReadbackProjection(actionContractId: string): Promise; + getOperationCorrelationIndex(actionContractId: string): Promise; getReceiptTimelineProjection(receiptId: string): Promise; getIdempotencyRecoveryProjection(actionContractId: string): Promise; getProtectedPathInstallHealthProjection(actionContractId: string): Promise; @@ -55,6 +58,8 @@ type ParsedMcpResourceUri = | { kind: "metadata"; actionClass: string } | { kind: "challenge"; challengeId: string } | { kind: "contract"; actionContractId: string } + | { kind: "operationReadback"; actionContractId: string } + | { kind: "operationCorrelation"; actionContractId: string } | { kind: "envelope"; actionContractId: string } | { kind: "receiptTimeline"; receiptId: string } | { kind: "idempotency"; actionContractId: string } @@ -74,6 +79,22 @@ export function parseMcpResourceUri(uri: string): ParsedMcpResourceUri { if (parsed.hostname === "evidence" && segments[0] === "contracts" && segments[1]) { return { kind: "contract", actionContractId: segments[1] }; } + if ( + parsed.hostname === "evidence" && + segments[0] === "operations" && + segments[1] && + segments[2] === "readback" + ) { + return { kind: "operationReadback", actionContractId: segments[1] }; + } + if ( + parsed.hostname === "evidence" && + segments[0] === "operations" && + segments[1] && + segments[2] === "correlation" + ) { + return { kind: "operationCorrelation", actionContractId: segments[1] }; + } if (parsed.hostname === "evidence" && segments[0] === "envelopes" && segments[1]) { return { kind: "envelope", actionContractId: segments[1] }; } @@ -102,6 +123,7 @@ async function readPayload(parsed: ParsedMcpResourceUri, evidenceClient: McpEvid resourceVersion: "mcp-metadata.v1", actionClass: parsed.actionClass, proposalTool: "handshake.actions.x402_payment.propose", + serviceWorkflowBoundary: mcpServiceWorkflowBoundary, authorityCreated: false, gatewayCheckPerformed: false, mutationAttempted: false, @@ -114,6 +136,10 @@ async function readPayload(parsed: ParsedMcpResourceUri, evidenceClient: McpEvid }; case "contract": return evidenceClient.getContractEvidenceProjection(parsed.actionContractId); + case "operationReadback": + return evidenceClient.getOperationReadbackProjection(parsed.actionContractId); + case "operationCorrelation": + return evidenceClient.getOperationCorrelationIndex(parsed.actionContractId); case "envelope": return evidenceClient.getAgentTransactionEnvelopeProjection(parsed.actionContractId); case "receiptTimeline": diff --git a/src/mcp/x402-proposal.ts b/src/mcp/x402-proposal.ts index b77d401..efc2e9e 100644 --- a/src/mcp/x402-proposal.ts +++ b/src/mcp/x402-proposal.ts @@ -1,8 +1,32 @@ import { z } from "zod"; import type { RuntimeClient } from "../sdk/surface-clients"; +import { + ServiceWorkflowContextRefsSchema, + serviceWorkflowContextCorrelationRef, + serviceWorkflowContextEvidenceRefs, +} from "../surfaces/service-workflow-admission"; +import { + classifyFailureClassFromReasonCodes, + mcpFailureClassEvidenceRef, +} from "../protocol/foundation/failure-class"; +import type { SurfaceOutcomeBaseInput } from "../surfaces/outcome"; import { mcpActionContractProposedOutcome, mcpNonContractOutcome, mcpToolResult, type McpToolResult } from "./output"; import { digestMcp, type McpJsonValue } from "./digest"; +function mcpTaxonomyOutcome( + input: SurfaceOutcomeBaseInput & { reasonCodes: string[] }, + isError = input.outcome !== "tools_list_changed", +): McpToolResult { + const failureClass = classifyFailureClassFromReasonCodes(input.reasonCodes); + return mcpNonContractOutcome( + { + ...input, + evidenceRefs: [mcpFailureClassEvidenceRef(failureClass), ...(input.evidenceRefs ?? [])], + }, + isError, + ); +} + const DigestSchema = z.string().regex(/^sha256:[a-f0-9]{64}$/); const AtomicAmountSchema = z .string() @@ -102,6 +126,7 @@ export const McpX402PaymentProposalInputSchema = z.strictObject({ retryDetected: z.boolean().default(false), branchDetected: z.boolean().default(false), correlationRef: McpRefSchema.nullable().default(null), + serviceWorkflowContextRefs: ServiceWorkflowContextRefsSchema.optional(), }); export type McpX402PaymentProposalInput = z.input; @@ -143,7 +168,7 @@ export async function proposeMcpX402Payment( ): Promise { const parsed = McpX402PaymentProposalInputSchema.safeParse(inputValue); if (!parsed.success) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "tool_execution_error", phase: "tool_execution", reasonCodes: ["mcp_input_schema_invalid"], @@ -156,7 +181,7 @@ export async function proposeMcpX402Payment( const idempotencyKey = await deriveMcpX402IdempotencyKey(input, trustedBinding.binding); if (options.toolsListChanged) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "tools_list_changed", phase: "freshness", reasonCodes: ["mcp_tools_list_changed"], @@ -170,7 +195,7 @@ export async function proposeMcpX402Payment( } if (options.currentMetadataDigest && options.currentMetadataDigest !== input.metadataDigest) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "metadata_stale", phase: "freshness", reasonCodes: ["mcp_metadata_digest_stale"], @@ -184,7 +209,7 @@ export async function proposeMcpX402Payment( } if ((options.installPosture ?? "ready") !== "ready") { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "install_not_ready", phase: "readiness", reasonCodes: [`mcp_install_${options.installPosture ?? "unknown"}`], @@ -198,7 +223,7 @@ export async function proposeMcpX402Payment( } if (!trustedBinding.binding) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "install_not_ready", phase: "readiness", reasonCodes: trustedBinding.reasonCodes, @@ -212,7 +237,7 @@ export async function proposeMcpX402Payment( } if ((options.gatewayPosture ?? "online") === "offline") { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "gateway_offline", phase: "readiness", reasonCodes: ["mcp_gateway_offline"], @@ -227,7 +252,7 @@ export async function proposeMcpX402Payment( } if ((options.gatewayPosture ?? "online") === "unknown") { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "tool_execution_error", phase: "tool_execution", reasonCodes: ["mcp_gateway_posture_unknown"], @@ -240,7 +265,7 @@ export async function proposeMcpX402Payment( } if (compareAtomic(input.atomicAmount, trustedBinding.binding.trustedMaxAtomicAmountPerCall) > 0) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "refused", phase: "proposal", reasonCodes: ["x402_amount_exceeds_call_bound"], @@ -255,7 +280,7 @@ export async function proposeMcpX402Payment( const postureRefusalReasonCodes = mcpX402PostureRefusalReasonCodes(input); if (postureRefusalReasonCodes.length > 0) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "refused", phase: "proposal", reasonCodes: postureRefusalReasonCodes, @@ -275,7 +300,7 @@ export async function proposeMcpX402Payment( const code = errorCode(error); const transitionEvidence = errorTransitionEvidence(error, input.paymentRequiredEvidenceRef); if (code === "already_consumed" || code === "idempotency_duplicate_authority") { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "replay_refused", phase: "replay", reasonCodes: [code], @@ -292,7 +317,7 @@ export async function proposeMcpX402Payment( } if (code === "idempotency_key_params_mismatch") { const committedEvidence = transitionEvidence.proofRef !== null || transitionEvidence.refusalRef !== null; - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "refused", phase: "proposal", reasonCodes: [code], @@ -308,7 +333,7 @@ export async function proposeMcpX402Payment( }); } if (transitionEvidence.proofRef !== null) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "proof_gap", phase: "evidence", reasonCodes: [code], @@ -323,7 +348,7 @@ export async function proposeMcpX402Payment( }); } if (transitionEvidence.refusalRef !== null) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "refused", phase: "proposal", reasonCodes: [code], @@ -337,7 +362,7 @@ export async function proposeMcpX402Payment( refusalRef: transitionEvidence.refusalRef, }); } - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "tool_execution_error", phase: "tool_execution", reasonCodes: [code], @@ -366,6 +391,7 @@ async function proposeContract( input.paymentRequiredEvidenceRef, trustedBinding.gatewayReadinessRef, trustedBinding.policyVersionRef, + ...serviceWorkflowEvidenceRefs(input), ...delegatedAuthorityEvidenceRefs(input), ]); const executionBlockDigest = await digestMcp({ @@ -380,6 +406,7 @@ async function proposeContract( providerEnvironmentRef: input.providerEnvironmentRef, selectedPaymentRequirementIndex: input.selectedPaymentRequirementIndex, selectedPaymentRequirementDigest: input.selectedPaymentRequirementDigest, + serviceWorkflowContextRefs: input.serviceWorkflowContextRefs ?? null, gatewayReadinessDigest: trustedBinding.gatewayReadinessDigest, policyVersionDigest: trustedBinding.policyVersionDigest, }); @@ -476,7 +503,7 @@ async function proposeContract( purposeCode: "x402_paid_request", expectedSideEffectCodes: ["x402_payment_signature_created"], evidenceRefs, - clearingEvidenceRefs: input.correlationRef ? { correlationRef: input.correlationRef } : {}, + clearingEvidenceRefs: clearingEvidenceRefs(input), bounds: { endpointDomain: new URL(input.endpointUrl).hostname, payee: input.payee, @@ -500,7 +527,7 @@ async function proposeContract( ...intentCompilation.candidateAction.refusalReasonCodes, ]; if (intentCompilation.candidateAction.candidateStatus !== "contractable" || refusalReasonCodes.length > 0) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "refused", phase: "proposal", reasonCodes: refusalReasonCodes.length > 0 ? refusalReasonCodes : ["mcp_candidate_not_contractable"], @@ -517,7 +544,7 @@ async function proposeContract( const candidateDigest = intentCompilation.candidateAction.candidateDigest; if (!candidateDigest) { - return mcpNonContractOutcome({ + return mcpTaxonomyOutcome({ outcome: "refused", phase: "proposal", reasonCodes: ["mcp_candidate_digest_missing"], @@ -580,6 +607,18 @@ async function proposeContract( ); } +function serviceWorkflowEvidenceRefs(input: ParsedMcpX402PaymentProposalInput): string[] { + return input.serviceWorkflowContextRefs ? serviceWorkflowContextEvidenceRefs(input.serviceWorkflowContextRefs) : []; +} + +function clearingEvidenceRefs(input: ParsedMcpX402PaymentProposalInput): { correlationRef?: string } { + if (input.correlationRef) return { correlationRef: input.correlationRef }; + if (input.serviceWorkflowContextRefs) { + return { correlationRef: serviceWorkflowContextCorrelationRef(input.serviceWorkflowContextRefs) }; + } + return {}; +} + async function deriveMcpX402IdempotencyKey( input: ParsedMcpX402PaymentProposalInput, trustedBinding: McpTrustedProposalBinding | null, @@ -612,6 +651,7 @@ async function deriveMcpX402IdempotencyKey( paymentRequirementsDigest: input.paymentRequirementsDigest, selectedPaymentRequirementIndex: input.selectedPaymentRequirementIndex, selectedPaymentRequirementDigest: input.selectedPaymentRequirementDigest, + serviceWorkflowContextRefs: input.serviceWorkflowContextRefs ?? null, delegatedAuthorityRefId: input.delegatedAuthorityBinding.delegatedAuthorityRefId, delegatedAuthorityRefDigest: input.delegatedAuthorityBinding.delegatedAuthorityRefDigest, delegatedAuthorityPolicyPackRef: input.delegatedAuthorityBinding.policyPackRef, diff --git a/src/protocol/areas/action-attempt-lifecycle/matrix.ts b/src/protocol/areas/action-attempt-lifecycle/matrix.ts index 04f09db..ca49aac 100644 --- a/src/protocol/areas/action-attempt-lifecycle/matrix.ts +++ b/src/protocol/areas/action-attempt-lifecycle/matrix.ts @@ -37,6 +37,20 @@ const catalogRecorded = { terminalOutcome: "evidence_only", } as const; +const negotiationRecorded = { + phase: "negotiation", + state: "negotiation_recorded", + authorityEffect: "evidence_only", + terminalOutcome: "open", +} as const; + +const negotiationConflict = { + phase: "negotiation", + state: "negotiation_conflict", + authorityEffect: "none", + terminalOutcome: "proof_gap", +} as const; + export const actionAttemptHostileTraceMatrix: Record = { unknown_consequential_tool: entry( { @@ -357,6 +371,54 @@ export const actionAttemptLifecycleMatrix: Partial