@arnilo/prism 0.0.27 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,48 +1,56 @@
1
1
  # 0.1.0 / 1.0 Readiness Gates
2
2
 
3
- Status: **0.0.27** is the current release line (Phase 10 ACP coding-host interop); **1.0** readiness remains operator-gated, not automatic.
3
+ Status: **0.1.0** is the current release line (Phase 12 release-candidate hardening; plan 012); **1.0** readiness remains operator-gated, not automatic.
4
4
 
5
- This page distills runnable readiness gates into one command-per-gate table. The
6
- **Last evidence** column records the 2026-07-26 **0.0.16** baseline snapshot
7
- (Phase 11, Node v24.18.0, Linux x86_64). Treat it as historical floor evidence,
8
- not the current release tag. Re-run each gate on the target release tree before
9
- cutting 0.0.27 / 1.0. The decision to cut 1.0 stays with the operator after
10
- operator-gated legs run in a protected environment and Phase 12 demand evidence
11
- exists.
5
+ This page distills runnable readiness gates into one command-per-gate table.
6
+ The **Last evidence** column records the 0.1.0-tree snapshot (plan 012 Tasks
7
+ 0–7, Node v24.18.0, Linux x86_64) with the 2026-07-26 **0.0.16** values kept
8
+ as the historical floor where the baseline predates it. Re-run each gate on
9
+ the release tree before cutting 1.0. The decision to cut 1.0 stays with the
10
+ operator after operator-gated legs run in a protected environment and Phase
11
+ 12 demand evidence exists.
12
12
 
13
13
  Evidence trail: [`docs/review-coverage-2026-07-26-phase-11.md`](./review-coverage-2026-07-26-phase-11.md)
14
14
  (addenda 0–9), [`docs/release-and-install.md`](./release-and-install.md),
15
- [`docs/migration.md`](./migration.md), [`docs/performance.md`](./performance.md).
15
+ [`docs/migration.md`](./migration.md), [`docs/performance.md`](./performance.md),
16
+ [`docs/public-contracts.md`](./public-contracts.md) (frozen 0.1.x contract).
17
+ Historical release lines (0.0.16 floor → 0.0.27 Phase 10 ACP interop → 0.1.0)
18
+ keep their per-phase evidence in the pages above; this page records the 0.1.0 snapshot.
16
19
 
17
- ## Current line (0.0.27)
20
+ ## Current line (0.1.0)
18
21
 
19
22
  | Item | Status |
20
23
  |---|---|
21
- | Published graph | **48** publishable manifests at **0.0.27** (`docs/release-and-install.md`) |
22
- | Phase 10 ACP coding-host interop | Seam-based capability advertisement, session persistence, modes/config overlays, client fs/terminal adapters, MCP select gate, `CodingLifecycleEvent` → ACP updates, four-outcome approvals + elicitation, frozen caps |
23
- | Docs tripwires | `node --test dist/__tests__/docs.test.js` — migration section `0.0.26 → 0.0.27 ACP coding-host interop`; `docs/acp.md` reference |
24
- | Network-free Phase 10 evidence | `scripts/phase10-conformance.test.mjs`; `benchmark-0.0.27.json` under Task 0 p95 ceilings; freeze manifest matched by exports |
25
- | Protected database evidence (Phase 7) | `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres`; `benchmark-0.0.24.json` under prior ceilings |
26
- | Readiness table below | **0.0.16 measured values** remain historical network-free baseline; 0.0.27 Phase 10 evidence is recorded separately |
24
+ | Published graph | **48** publishable manifests at exact **0.1.0** (root + 48 workspace packages; `docs/release-and-install.md`) |
25
+ | Phase 12 RC hardening | Freeze manifest (`scripts/phase12-freeze-manifest.json`): no new packages/exports/migrations/dependencies, additive-only compat promise vs `scripts/compat-baseline`; compatibility/support matrix machine-checked (Node 20+24 measured, PostgreSQL 16, linux-x64, protocol SDK pins) |
26
+ | Upgrade path | `docs/migration.md` `0.0.28 → 0.1.0` (no migration) + full `0.0.17 → 0.1.0` upgrade matrix (compatible / tested migration / tested refusal per release line) |
27
+ | Packed-install e2e journeys | enterprise + coding journeys install the exact packed 0.1.0 manifest graph into fresh consumers (`scripts/e2e-*-journey.test.mjs`, in `npm test`) |
28
+ | Protected restart-recovery evidence | `npm run test:postgres` includes `scripts/phase12-restart-recovery.test.mjs` (multi-replica kill/resume, unknown-outcome window, DB restart during streaming, reconnect/contention p95 vs frozen ceilings) |
29
+ | Capacity envelopes | `scripts/benchmark-0.1.0.json` — 24 network-free + 16 protected p95 rows under the frozen 0.1.0 contract, re-gated on every `npm test` |
30
+ | Security policy | `npm audit --audit-level=moderate` enforced in workflows; named threat-suites leg (`npm run security:threat-suites`); supply-chain negative fixtures in `scripts/release-gate.test.mjs` |
31
+ | Docs freeze | every public page, package README, and changelog consistent with 0.1.0 behavior; tripwires green (121/121) |
32
+ | Readiness table below | **0.0.16 measured values** remain the historical network-free floor; 0.1.0 evidence is recorded per row |
27
33
 
28
34
  ## Gate table
29
35
 
30
- | Gate | Command | Last evidence (2026-07-26 baseline @ 0.0.16) | Owner |
36
+ | Gate | Command | Last evidence (0.1.0 tree; 0.0.16 floor where noted) | Owner |
31
37
  |---|---|---|---|
32
- | Full quality gate | `npm run sdk:ready` | RC=0: typecheck (+examples), lint 0, format clean, full test, coverage, pack, release:gate | CI |
33
- | Exact version graph | `node scripts/release.mjs check --version <v>` | pass at 0.0.16: exact versions/ranges/lockfile/access + registry-collision check, 44 manifests | CI + operator |
34
- | Frozen public API surface + compat gate | `node scripts/release.mjs gate` | 0 breaks / 0 errors vs checked-in baselines (`scripts/compat-baseline/`); only additive delta at 0.0.16 was `resolveRedactor` | CI |
35
- | Migration coverage + docs tripwires | `node --test dist/__tests__/docs.test.js` | 112/112 at 0.0.16; `docs/migration.md` sections tripwired per release | Maintainer |
36
- | Deterministic artifact budget | `node --test dist/__tests__/budget-gate.test.mjs` | root 579.2 kB / 2.1 MB / 270 files within +5% of baseline; startup 38 ms < 250 ms ceiling | CI (in `npm test`) |
37
- | Performance benchmark medians | `node scripts/benchmark-0.0.16.mjs` | 6 network-free scenarios within ±25%; 0 backpressure / 0 resource-limit signals | On-demand release evidence |
38
- | Secret scan | `node scripts/scan-secrets.mjs` | 3095 files / 0 findings | CI |
39
- | License / SBOM | `node scripts/verify-sbom.mjs` | 227 packages / 12 licenses, all allow-listed | CI |
40
- | Dependency audit | `npm audit --audit-level=high` | rc=0 (2 moderate, 0 high) at 0.0.16 | CI |
38
+ | Full quality gate | `npm run sdk:ready` | RC=0 at 0.1.0: typecheck (+examples), lint 0, format clean, full test, coverage, pack, release:gate (clean-checkout run is part of the operator release checklist) | CI |
39
+ | Exact version graph | `node scripts/release.mjs check --version 0.1.0` | pass at 0.1.0: exact versions/ranges/lockfile/access + registry-collision check, **49** manifests | CI + operator |
40
+ | Frozen public API surface + compat gate | `node scripts/release.mjs gate` | 0 breaks / 0 errors vs checked-in baselines (`scripts/compat-baseline/`); additive-only delta (empty at the 0.0.28 → 0.1.0 bump) | CI |
41
+ | Migration coverage + docs tripwires | `node --test dist/__tests__/docs.test.js` | 121/121 at 0.1.0; `docs/migration.md` sections tripwired per release line | Maintainer |
42
+ | Deterministic artifact budget | `node --test dist/__tests__/budget-gate.test.mjs` | root 713.5 kB packed / 2.1 MB unpacked / 295 files within +5% of the regenerated 0.1.0 baseline; startup < 250 ms | CI (in `npm test`) |
43
+ | **0.1.0 capacity envelope (frozen performance contract)** | `node --test scripts/benchmark-0.1.0.test.mjs` | **`scripts/benchmark-0.1.0.json`** re-gated on every `npm test`: 24 network-free p95 rows ≤ frozen ceilings, 16 protected PostgreSQL rows ≤ budgets.json ceilings (50/100 ms), startup 41.7 ms < 250 ms, root pack within ±5%; regenerate with `node scripts/benchmark-0.1.0.mjs --out scripts/benchmark-0.1.0.json` (+ `PRISM_TEST_POSTGRES_URL` for protected legs) | CI (in `npm test`) |
44
+ | Performance benchmark medians | `node scripts/benchmark-0.1.0.mjs --out scripts/benchmark-0.1.0.json` (+ `PRISM_TEST_POSTGRES_URL` for the 16 protected rows) | envelope re-recorded at 0.1.0 (see capacity-envelope row above); historical phase medians remain in `docs/performance.md` | On-demand release evidence |
45
+ | Secret scan | `node scripts/scan-secrets.mjs` | 0.1.0 tree: 0 findings (3,095-file 0.0.16 floor) | CI |
46
+ | License / SBOM | `node scripts/verify-sbom.mjs` | 0.1.0 tree: 317 locked packages, allow-listed licenses (227/12 at 0.0.16 floor) | CI |
47
+ | Dependency audit | `npm audit --audit-level=moderate` | rc=0 (0 moderate+, 2 moderate at 0.0.16 baseline); 0 vulns at every severity for the 0.1.0 tree | CI |
41
48
  | Whitespace hygiene | `git diff --check` | clean | CI |
42
- | Publish order + tarball validation | `node scripts/release.mjs publish --version <v> --dry-run --allow-dirty --allow-untagged` | 44/44 packages `dry-run`, deterministic dependency order, no failures | Operator (dry-run), CI |
49
+ | Publish order + tarball validation | `node scripts/release.mjs publish --version 0.1.0 --dry-run --allow-dirty --allow-untagged` | 49/49 packages `dry-run` twice with byte-identical reports, deterministic dependency order, no failures (Task 7) | Operator (dry-run), CI |
43
50
  | Node 20 compatibility | CI `node20-compat` (build + public-import smoke) | all 21 root exports import cleanly on Node 20.20.2 | CI |
44
- | PostgreSQL suite | `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres` | 57 checks including enterprise migration/restart/contention/cleanup; operator-gated | Operator |
45
- | Keychain / live-provider suites | `npm run test:live` (protected) | **operator-gated** (requires credentials) | Operator |
51
+ | PostgreSQL suite | `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres` | 0.1.0: Phase 7 conformance + Phase 12 restart-recovery + 74 workspace checks green against PostgreSQL 16 (Task 4 recording, re-run green at 0.1.0 on 2026-08-09); operator-gated | Operator |
52
+ | Keychain suite | `PRISM_TEST_KEYCHAIN=1 npm test --workspace @arnilo/prism-credentials-node` (protected) | 28/28 green incl. native keychain round-trip against the OS secret-service backend (gnome-keyring, 2026-08-09) | Operator host |
53
+ | Live-provider suites | `npm run test:live` (protected) | **operator-gated** (requires credentials; `live-canaries.yml` blocked gate, `canary-report.json` retained) | Operator |
46
54
  | SAST | GitHub CodeQL | **operator-gated** (runs in CI workflow) | CI |
47
55
  | Signed, provenance publication | `npm run release:publish` (clean tagged tree, OIDC) | **operator-gated** (see "Remaining for 1.0") | Operator |
48
56
 
@@ -50,11 +58,14 @@ Evidence trail: [`docs/review-coverage-2026-07-26-phase-11.md`](./review-coverag
50
58
 
51
59
  The compat gate diffs every package's generated `.d.ts` export surface against
52
60
  checked-in baselines in `scripts/compat-baseline/` (one file per package,
53
- regenerated at 0.0.16). It fails on any **removed** export or changed
61
+ regenerated at 0.1.0). It fails on any **removed** export or changed
54
62
  declaration; additive exports are allowed. `scripts/release-gates.mjs` also
55
- enforces a tarball deny list (no `docs/review-coverage-*` in published
56
- artifacts) and exact version-range drift. A genuine break requires
57
- `--allow-break` **and** a `docs/migration.md` entry mentioning the version.
63
+ enforces a tarball deny list (no reviews/plans/maps/tests/binaries/credential
64
+ material in published artifacts) and exact version-range drift. A genuine break
65
+ requires `--allow-break` **and** a `docs/migration.md` entry mentioning the
66
+ version. The frozen 0.1.x contract (declaration/exports, events, protocol
67
+ payloads, migration checksums, patch-release compatibility promise) is
68
+ published in [docs/public-contracts.md](public-contracts.md).
58
69
 
59
70
  **Baseline maintenance:** `scripts/compat-baseline/` must stay committed.
60
71
  Regenerate only after review with `node scripts/release.mjs gate --update-baseline`,
@@ -75,26 +86,15 @@ durability, MCP SDK bump) — see `0.0.17 → 0.0.18 restore integrity`.
75
86
 
76
87
  Deterministic budgets (CI gate, `scripts/budget-gate.test.mjs`):
77
88
 
78
- | Metric | Baseline | Tolerance | 0.0.16 measured |
89
+ | Metric | Baseline | Tolerance | 0.1.0 measured |
79
90
  |---|---|---|---|
80
- | Root packed bytes | 575,680 | +5% | 579.2 kB (within) |
81
- | Root unpacked bytes | 2,043,402 | +5% | 2.1 MB (within) |
82
- | Root file count | 270 | +5% | 270 |
83
- | Cold-startup import | 38 ms | ceiling 250 ms | ~38 ms |
84
- | Aggregate packed (47 manifests, reference only) | 1,217,694 | +10% | remeasure for the 0.0.24 graph before release |
91
+ | Root packed bytes | 713,454 (regenerated 0.1.0, dev-001) | +5% | 713.5 kB (within) |
92
+ | Root unpacked bytes | 2,388,118 | +5% | within |
93
+ | Root file count | 293 (regenerated 0.1.0, dev-001) | +5% | 295 (within) |
94
+ | Cold-startup import | 41.7 ms | ceiling 250 ms | within |
85
95
 
86
- Benchmark medians (on-demand evidence, `scripts/benchmark-0.0.16.mjs`, ±25%):
87
-
88
- | Scenario | throughput/s | p50 ms | p95 ms |
89
- |---|---|---|---|
90
- | openai-hosted-continuation | 5,386.0 | 0.1317 | 0.2907 |
91
- | openai-realtime-envelope | 880.3 | 1.1293 | 1.2399 |
92
- | ai-sdk-v4-stream-mapping | 22,403.0 | 0.0230 | 0.0734 |
93
- | provider-package-metadata | 55,829.2 | 0.0065 | 0.0394 |
94
- | rag-parse-replace-rerank-retrieve | 4,800.3 | 0.1432 | 0.4064 |
95
- | memory-retention-export-rebuild | 8,763.2 | 0.0686 | 0.1892 |
96
-
97
- Baselines are a 2026-07-26 snapshot (`scripts/budgets.json`); raise them only
96
+ Baselines are the 0.1.0 snapshot (`scripts/budgets.json`, amended once by
97
+ freeze deviation dev-001 for the Task 1–5 evidence scripts); raise them only
98
98
  after a deliberate reviewed performance change.
99
99
 
100
100
  ## Live-suite matrix (operator-gated)
@@ -105,9 +105,45 @@ after a deliberate reviewed performance change.
105
105
  | Keychain credentials | protected live suite | OS keychain |
106
106
  | Provider live-canary (OpenAI/Anthropic/Google/Kimi/Ollama/…) | protected live-canary matrix | vendor credentials |
107
107
  | RAG / memory / workflows live journeys | protected live-canary matrix | vendor + DB credentials |
108
+ | Enterprise adapters live canary (Phase 11: real OIDC IdP/JWKS, real OPA endpoint, real MCP OAuth authorization server, S3-compatible object store) | protected live-canary matrix | IdP / policy / object-store credentials |
108
109
 
109
110
  These do not run on a contributor machine; their evidence is recorded in the
110
- protected environment, never faked.
111
+ protected environment, never faked. Phase 11 live-endpoint evidence is a
112
+ **blocked release gate, not a passing skip**: `npm test` proves the seams
113
+ against network-free fake servers (`scripts/phase11-conformance.test.mjs`),
114
+ and the live matrix above stays blocked until the protected environment
115
+ records it.
116
+
117
+ ## Packed-install e2e journeys (plan 012 Task 3)
118
+
119
+ | Journey | Command | Environment |
120
+ |---|---|---|
121
+ | Enterprise: OIDC identity → OPA policy decision → agent run with durable events → batched approval → OpenAPI side effect with idempotency → artifact upload + signed delivery | `npm test` (scripts/e2e-enterprise-journey.test.mjs) | network-free (memory stores, loopback fake servers); PostgreSQL leg when `PRISM_TEST_POSTGRES_URL` is set |
122
+ | Coding: ACP editor session (init capability negotiation, session new + load/resume) → bounded coding tools (git-aware list/search, glob, read-before-write write, delete, move) → sandboxed process session → forge handoff | `npm test` (scripts/e2e-coding-journey.test.mjs) | network-free (fake GitHub + git runner) |
123
+
124
+ Both install the exact packed manifest graph into a fresh consumer (`npm pack`
125
+ tarballs, never workspace paths) and run the journey against only public
126
+ exports. Each fixture ends with a success marker (`ENTERPRISE JOURNEY OK` /
127
+ `CODING JOURNEY OK`) that the test asserts. Runtime is bounded by
128
+ `e2eJourneyFixtureMsCeiling` in `scripts/phase12-freeze-manifest.json` (120 s
129
+ per fixture).
130
+
131
+ ## Protected restart-recovery evidence (plan 012 Task 4)
132
+
133
+ | Leg | Command | Environment |
134
+ |---|---|---|
135
+ | Multi-replica kill/resume: replica A runs a durable agent (PostgreSQL checkpoints + durable events), suspends on a batched tool approval, and is SIGKILLed; replica B resumes with no event gap/duplicate, exactly-once durable tool effects, partial-approval re-suspend with CAS, and ownership rechecks | `npm run test:postgres` (scripts/phase12-restart-recovery.test.mjs) | live PostgreSQL 16 |
136
+ | Tool-effect unknown-outcome window: a dispatched-and-expired claim replays as `ERR_PRISM_TOOL_EFFECT_UNKNOWN` (reconciliation demanded), never a silent double-apply | `npm run test:postgres` (same suite) | live PostgreSQL 16 |
137
+ | Database restart during streaming: terminated LISTEN backend recovers by polling (missed event delivered, no gap) | `npm run test:postgres` (Phase 7 + Phase 12 legs) | live PostgreSQL 16 |
138
+ | Reconnect p95 + append contention p95 recorded against frozen ceilings (`reconnectP95Ms`, `pointOpP95Ms` in `scripts/phase12-freeze-manifest.json`) | `npm run test:postgres`; evidence in `scripts/phase12-restart-recovery.json` | live PostgreSQL 16 |
139
+
140
+ Missing `PRISM_TEST_POSTGRES_URL` is a **named, visible blocked gate**: `npm run
141
+ test:postgres` fails at `scripts/require-postgres-url.mjs`, and running the
142
+ suite directly records a `BLOCKED GATE` failure instead of a passing skip.
143
+ Durable ACP session registries and sandbox process sessions stay host-owned
144
+ by design (Prism provides the durable agent-run lifecycle underneath); the
145
+ coding journey and Phase 9/10 conformance suites cover their in-process
146
+ semantics, and the legs above prove the durable restart classes.
111
147
 
112
148
  ## Security matrix
113
149
 
@@ -115,30 +151,39 @@ protected environment, never faked.
115
151
  |---|---|---|
116
152
  | Secret scan | `node scripts/scan-secrets.mjs` | 3095 files / 0 findings |
117
153
  | License / SBOM | `node scripts/verify-sbom.mjs` | 227 packages / 12 licenses, allow-listed |
118
- | Dependency audit | `npm audit --audit-level=high` | 0 high (2 moderate) |
154
+ | Dependency audit | `npm audit --audit-level=moderate` | 0 high (2 moderate) at 0.0.16; **0 vulnerabilities at every severity for the 0.1.0 tree** (317 locked deps; MCP SDK 1.30.0 fix baseline) |
119
155
  | SAST | GitHub CodeQL workflow | CI-gated |
120
156
  | Sandbox / protocol / tenant threat suites | `npm test` (coding-security, MCP, policy, guardrail suites) | green at 0.0.16 |
157
+ | **0.1.0 threat-suites leg** | `npm run security:threat-suites` (Phase 8–11 conformance) + `npm run test:postgres` (Phase 7 tenant leg, blocked gate without URL) | 28/28 network-free at 0.1.0 recording |
158
+ | **Supply-chain negative fixtures** | `scripts/release-gate.test.mjs` | tampered tarball content, unexpected file types/credential material, and suppressed-provenance-in-CI all detected |
121
159
  | Signed deterministic publication | `release.mjs publish` on clean tagged tree | operator-gated |
122
160
 
123
161
  ## Remaining for 1.0 (operator / protected environment)
124
162
 
125
- Exact prerequisites that must be satisfied before cutting 1.0:
163
+ Exact prerequisites that must be satisfied before cutting 1.0 (the 0.1.0
164
+ publication itself is the same list minus the 1.0-specific items):
126
165
 
127
- 1. **Signed tag + commits:** create and sign `v0.1.0` (or `v1.0.0`) on a clean
128
- tree; `release.mjs publish` refuses real publication with `--allow-dirty`
129
- or `--allow-untagged`.
166
+ 1. **Signed tag + commits:** create and sign `v1.0.0` on a clean tree;
167
+ `release.mjs publish` refuses real publication with `--allow-dirty`
168
+ or `--allow-untagged` (verified: the 0.1.0 dry-run proceeds only with
169
+ both flags, the real run always refuses).
130
170
  2. **npm authentication + OIDC provenance/attestation:** publish with
131
- `--provenance` and `--access public` from the protected registry identity.
171
+ `--provenance` and `--access public` from the protected registry identity
172
+ (the 0.1.0 publication is the first exercise of this operator step;
173
+ `publishArgs` derives `--provenance` from `GITHUB_ACTIONS` and the
174
+ release workflow holds `id-token: write` + `attestations: write`).
132
175
  3. **Protected live-canary matrix green:** provider/RAG/memory/workflows live
133
- journeys pass with real credentials.
176
+ journeys pass with real credentials (`live-canaries.yml` — blocked gate,
177
+ never a silent skip).
134
178
  4. **PostgreSQL + keychain protected suites green.**
135
179
  5. **CodeQL SAST green** on the release commit.
136
- 6. **`scripts/compat-baseline/` committed** so CI's compat gate has a
137
- checked-in baseline.
180
+ 6. **`scripts/compat-baseline/` committed** (frozen 0.1.x baselines are
181
+ already checked in).
138
182
  7. **Phase 12 demand evidence** (below) recorded for any capability that 1.0
139
183
  is expected to anchor.
140
- 8. **0.0.19+ lifecycle gates green** on the release candidate (docs suite,
141
- MCP SDK advisory cleared, coding-tool durability fixes, layout/eviction defaults).
184
+ 8. **0.1.0 lifecycle gates green** on the release candidate (docs suite,
185
+ audit at moderate, coding-tool durability, layout/eviction defaults) —
186
+ recorded in this page at 0.1.0.
142
187
 
143
188
  ## Phase 12 demand-evidence entry criteria
144
189
 
@@ -87,6 +87,39 @@ await agent.createSession().run("Summarize inbox", {
87
87
 
88
88
  Server / MCP / A2A authorize callbacks may include the same `identity` beside `ownership`. Handlers assert activity and ownership match before admitting work.
89
89
 
90
+ ## OIDC/JWKS verifier adapter (`@arnilo/prism-credentials-node/oidc`)
91
+
92
+ Optional `createOidcIdentityVerifier` turns a pinned issuer/audience and pinned JWKS URL into a core `IdentityVerifier` — one bounded reference adapter for hosts that already authenticate callers with OIDC JWTs (Entra, Keycloak, Auth0, …). Native `fetch` + WebCrypto only; no JOSE dependency.
93
+
94
+ | Option | Meaning |
95
+ | --- | --- |
96
+ | `issuer` / `audience` | Exact `iss` and accepted `aud` value(s); anything else fails closed |
97
+ | `jwksUrl` | Host-pinned JWKS URL; SSRF-checked (`assertSsrfAllowedUrl`), never discovered at runtime, never followed through redirects |
98
+ | `mapClaims` | Bounded claims → `tenantId`, `principal`, `scopes`, optional account/user/sponsor/owner/refs/metadata |
99
+ | `algorithms` | `RS256`/`ES256` default; hosts may only narrow |
100
+ | `clockSkewMs` | Bounded `exp`/`nbf` slack (default 30 s) |
101
+ | `isRevoked` | Optional revocation callback; `true` or a thrown error fails closed |
102
+ | `limits` | Bounded JWKS/claims knobs; `identity` reuses core identity caps |
103
+
104
+ ```ts
105
+ import { createOidcIdentityVerifier } from "@arnilo/prism-credentials-node/oidc";
106
+
107
+ const verifier = createOidcIdentityVerifier({
108
+ issuer: "https://id.example.com/tenant",
109
+ audience: "prism-api",
110
+ jwksUrl: "https://id.example.com/tenant/.well-known/jwks.json",
111
+ mapClaims: (claims) => ({
112
+ tenantId: String(claims.tid),
113
+ principal: { kind: "user", id: String(claims.sub) },
114
+ scopes: Array.isArray(claims.scp) ? claims.scp.map(String) : [],
115
+ }),
116
+ });
117
+
118
+ const identity = await verifier.verify({ token }); // -> AgentIdentity (verified: true)
119
+ ```
120
+
121
+ Fail-closed reasons (`IdentityError.reason`): `ERR_PRISM_OIDC_ISSUER_MISMATCH`, `AUDIENCE_MISMATCH`, `ALGORITHM`, `SIGNATURE`, `EXPIRED`, `NOT_YET_VALID`, `JWKS_FETCH`, `JWKS_KEY_MISSING`, `JWKS_PARSE`, `CLAIMS_BOUNDS`, `REVOKED`, `TENANT_MAPPING`. JWKS is cached (bounded entries/TTL, single-flight refetch, one bounded refetch on unknown `kid`); a parse/bounds failure on refresh fails closed while a transport failure keeps serving the last valid keys. SSRF denials surface the core `MediaContentError` (`ssrf_denied`). Tokens/claims never appear in errors, logs, or telemetry.
122
+
90
123
  ## Extension and configuration notes
91
124
 
92
125
  Identity is optional. Hosts that only set `ownership` keep prior behavior. When identity is present, run start and tool dispatch assert it before side effects. Workflows forward `RunWorkflowOptions.identity` into agent nodes. Credential values stay behind `CredentialResolver` keys listed in `credentialRefs`.
@@ -17,6 +17,8 @@ Factories:
17
17
  - `createOAuthCredentialStoreAdapter(store)`
18
18
  - `rotateEncryptedCredentialStorePassphrase(options)`
19
19
 
20
+ The `@arnilo/prism-credentials-node/oidc` subpath adds the optional OIDC/JWKS identity verifier (`createOidcIdentityVerifier`) — pinned issuer/audience/JWKS verification over native `fetch` + WebCrypto (see [Agent identity](agent-identity.md)).
21
+
20
22
  Core `@arnilo/prism` remains storage-free. Hosts choose a backend explicitly at startup; there is no global credential singleton and no silent fallback from keychain to plaintext file storage.
21
23
 
22
24
  ## When to use it
@@ -155,6 +155,7 @@ export async function recordEnterpriseState(state: PostgresEnterpriseState) {
155
155
  - `createModelRouter({ resolver, stateStore: state.modelRouter })` keeps allow-list, residency, fallback, and diagnostics behavior in `@arnilo/prism-model-router`; this package only supplies durable state.
156
156
  - Policy/evaluation/query public contracts stay in their owning packages. This package exports only `createPostgresEnterpriseState`, its options/result types, and `EnterprisePostgresError`; it has no SQL, DDL, codec, queryable, or migration subpath.
157
157
  - The fixed schema has no generic key/value table and no background cleanup scheduler. Schedule `state.cleanup()` from an authorized host job, size its bounded batch for the deployment, and monitor unknown work rows for reconciliation. Run protected integration checks with `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres`; the command rejects an absent URL instead of silently skipping database coverage.
158
+ - The OPA adapter (`@arnilo/prism-policy/opa`, 0.0.28) records decisions into the same `state.policy` store unchanged via `evaluateAndAppend` — see [Policy and audit](policy-and-audit.md#opa-external-policy-adapter-arniloprism-policyopa-008).
158
159
  - Request-path state SQL uses `SELECT`, `INSERT`, `UPDATE`, and `DELETE` on the six state tables. The open/migration lifecycle additionally needs schema/catalog/advisory-lock and DDL permissions. Use a deployment migration principal for that lifecycle and a least-privilege request role for request traffic; this release intentionally does not ship a migration CLI or worker.
159
160
 
160
161
  ## Security and performance notes
@@ -34,7 +34,7 @@ Start from explicit host inputs. Do not let runtime code discover security state
34
34
  | Durable interruption | host checkpoint + session stores, exact ownership | `RunOptions.runState`, `resumeAgentRun()`, `createAgentRunLifecycle()`, `createSecureAgent()` |
35
35
  | Extensions | explicit package imports only | `createExtensionKernel`, `ExtensionAPI` |
36
36
  | Remote agent/workflow API | host authentication + ownership mapping | `@arnilo/prism-server`, `createPrismHandler()` |
37
- | Authenticated identity | host `IdentityVerifier` → verified `AgentIdentity` | [Agent identity](agent-identity.md), `assertIdentityActive`, `narrowIdentity` |
37
+ | Authenticated identity | host `IdentityVerifier` → verified `AgentIdentity`; optional OIDC/JWKS reference adapter (`@arnilo/prism-credentials-node/oidc`, pinned issuer/audience/JWKS, fail closed) | [Agent identity](agent-identity.md), `assertIdentityActive`, `narrowIdentity` |
38
38
  | Policy decision audit | optional redacted ledger + host WORM sink | [Policy and audit](policy-and-audit.md), `@arnilo/prism-policy` |
39
39
  | Durable enterprise state | host PostgreSQL pool, TLS, exact owner/principal projection, migration/runtime database roles, backup and explicit cleanup schedule | [Enterprise PostgreSQL state](enterprise-postgres-state.md), `@arnilo/prism-enterprise-postgres` |
40
40
  | MCP server exposure | host MCP auth + selected capability list | `createPrismMcpServer()`, `createPrismMcpWebHandler()` |
@@ -146,7 +146,7 @@ Wire those values where they matter: provider adapters receive the resolved cred
146
146
  - AG-UI fields stay untrusted after schema validation. `input.project` returns host-selected messages/handoffs only; never merge state/tools/context/props into ownership, identity, permissions, provider options, or media policy. Apply Prism media SSRF/MIME bounds before resolution; output projectors are bounded allow-lists; interrupt edits deny rather than mutate persisted calls.
147
147
  - AG-UI MCP Apps requires negotiated `mcpApps`, exact proxy origin/auth, owned-run context, approval, one bridge, separate-origin sandbox (`allow-scripts allow-same-origin`), and no-wider CSP. Never execute HTML in host origin or retry a UI mutation; Task 4 adds recovery.
148
148
  - AG-UI A2A requires exact-origin verified client, host-owned task selection/correlation, explicit data/tool/A2UI projection, and reauthorized follow/cancel.
149
- - `@arnilo/prism-server` exposes no agent/workflow by default and requires `authorize()` for every matched operation. Derive complete tenant/account/user ownership from validated host identity, never request JSON. Workflow active identity and cancellation compare exact ownership; a tenant-only scope intentionally cannot cancel a checkpoint/run carrying account or user identity. The artifact review service (`createArtifactService`) requires authenticated identity + thread ownership on every attach/revise/compare/approve/reject/download, resolves concurrent reviewers via checkpoint CAS (no lost approvals), rejects local filesystem paths in `uri`/citations, redacts records before persist and on response, and serves downloads only through signed expiring links that are reauthorized against the token's ownership per request. Pass the current explicitly revised workflow definition so recursive hash mismatch fails before abort or durable mutation. Configure exact host/origin allow-lists where needed, wire redaction before execution, retain tool/workflow policy checks, and adapt the Web handler behind host TLS/rate limits. Disconnect abort is default; persistent reconnect/status belongs to durable workflow checkpoints, not an invented in-memory agent result cache.
149
+ - `@arnilo/prism-server` exposes no agent/workflow by default and requires `authorize()` for every matched operation. Derive complete tenant/account/user ownership from validated host identity, never request JSON. Workflow active identity and cancellation compare exact ownership; a tenant-only scope intentionally cannot cancel a checkpoint/run carrying account or user identity. The artifact review service (`createArtifactService`) requires authenticated identity + thread ownership on every attach/revise/compare/approve/reject/download, resolves concurrent reviewers via checkpoint CAS (no lost approvals), rejects local filesystem paths in `uri`/citations, redacts records before persist and on response, and serves downloads only through signed expiring links that are reauthorized against the token's ownership per request. When a blob store is wired (`bodies: ArtifactBodyStore`, 0.0.28), delivery links additionally resolve through `bodies.presign`; the reference `createS3ArtifactBodyStore` verifies ownership on every operation, verifies size/SHA-256/MIME on put and get (fail closed), refuses delete under legal hold (host `isHeld` callback), keeps credentials host-resolved, and never discloses bucket/path/key in errors, telemetry, or artifact records. Pass the current explicitly revised workflow definition so recursive hash mismatch fails before abort or durable mutation. Configure exact host/origin allow-lists where needed, wire redaction before execution, retain tool/workflow policy checks, and adapt the Web handler behind host TLS/rate limits. Disconnect abort is default; persistent reconnect/status belongs to durable workflow checkpoints, not an invented in-memory agent result cache.
150
150
  - Coding tools from `@arnilo/prism-coding-agent` accept an optional `ExecutionPolicy` checked inside each tool before side effects; shared policy propagation includes `createReadOnlyTools()`. They enforce finite text-scan/image/edit/write/shell limits, repository list/search depth/entry/match/scan/time caps, structured Git path/ref/message/output/patch/worktree caps, named-check concurrency/output caps, a 600-second default shell wall time, and a 64 MiB default total-output ceiling. Opt-in `createGitTools()` uses argument arrays with hooks/credential prompts/external diff disabled, requires host `commitIdentity` for commits, and never pushes or opens PRs. Successful truncated shell output leaves a host-owned exclusive `0600` temp file; delete `metadata.fullOutputPath` after use. Error/abort/timeout/overflow removes unpublished spills. Custom read/edit/shell/repository backends must honor supplied caps/signals. Use `@arnilo/prism-coding-security` for path roots, command rules, identity-scoped approval caching, required `workspaceMode` on `createSandboxCodingComposition()` / `createSandboxCodingTools()`, and the optional `createDockerSandbox()` reference adapter. **Host mode is never contained execution** (`containmentClaim: false`). Sandbox mode claims containment only when FS backends target the disposable tree; mixed wiring requires `allowMixedWorkspaceWiring` and still does not claim containment. Limits alone are not containment: construct the Docker adapter (absolute CLI, digest-pinned image, network none by default) or an equivalent host sandbox before treating coding execution as production-safe. Docker daemon/image trust, egress firewall/proxy, and artifact retention remain host-owned.
151
151
  - Allow-list egress (0.0.26, `@arnilo/prism-coding-security`): `createEgressPolicy()` is deny-all with exact host/port/protocol rules and frozen `npm-registry`/`github` presets; `createAllowListEgressProxy()` is an HTTP forward proxy + CONNECT tunnel that pins DNS answers and verifies the connected address (rebinding defense), denies private/link-local/metadata ranges unless a rule opts in, re-validates every redirect hop against policy, and cuts oversized/slow transfers at frozen byte/time caps. TLS passes through without interception. Every allow/deny writes an audit record with no secrets. The proxy is inert until `start()`; `reloadPolicy()` is the only rule change path. `composeEgressSandboxNetwork(proxy.attestation(), name)` records validated attestation as `prism.egress.*` container labels — evidence, not enforcement: the host must restrict the Docker network so the proxy is the only reachable path, and `denyDirectEgress: true` is a claim the host makes true by topology. The proxy is not a firewall and cannot stop a container whose network reaches the internet directly.
152
152
  - Optional `@arnilo/prism-browser` requires a host-supplied Playwright Browser (`playwright-core@1.61.0` peer). Import is inert. One non-persistent context belongs to one run; actions serialize; refs are snapshot-scoped; CSS/evaluate/CDP/persistent profiles are denied. Context routing + `serviceWorkers: "block"` deny file/data/blob/devtools/private/loopback by default and require contained-proxy attestation for external egress (Playwright routing is defense in depth, not DNS containment). Uploads are realpath-rooted; downloads quarantine with hash/MIME until host `approveRelease`; screenshots return bounded `ImageContent`. Observation vs mutation/high-impact actions map to `ExecutionPolicy`. Treat snapshot/page text as untrusted external content. Close contexts with `browser_close` or `manager.closeRun(runId)` on abort/terminal. Browser control endpoint, binary/image pin, and real egress firewall/proxy remain host-owned. Shared sandbox: `createSharedSandboxBrowserOptions()` + `assertBrowserSandboxNetwork()`.
@@ -202,6 +202,15 @@ PostgreSQL TLS/network policy, MCP endpoint trust/credentials and egress policy
202
202
  - Scheduled/manual canaries run only in protected `live-canaries` environment. Use dedicated read-only/low-quota credentials and provider account spend limits. Runner performs four probes, at most one MCP cleanup, one provider output token, one Brave result, 64-KiB responses, and finite timeouts; report excludes endpoints, headers, bodies, credentials, and MCP session IDs.
203
203
  - Scheduled/manual coding/browser containment checks run in protected `sandbox-browser` environment (`.github/workflows/sandbox-browser.yml`). They receive no provider/npm/OIDC secrets; Docker/Playwright enablement is variable-gated with host-preloaded digest-pinned images/binaries; uploads are redacted aggregate status only.
204
204
  - Live endpoint operators own TLS, egress allow-lists, account-dollar budget, cleanup beyond MCP session DELETE, and revocation. Failed canaries log only operation kind plus status/timeout; inspect provider-side audit logs for details.
205
+ - **Security-support boundary.** Audit fixes, dependency updates, and security patches land only for the supported Node/PostgreSQL/platform lines frozen in the 0.1.x compatibility matrix ([release and install](release-and-install.md), `scripts/phase12-freeze-manifest.json`). Unsupported combinations receive no fixes.
206
+
207
+ ### 0.1.0 security evidence (plan 012 Task 6)
208
+
209
+ - **Audit policy.** `npm audit --audit-level=moderate` is enforced in both `security.yml` and the `release.yml` supply-chain job (freeze-manifest `releasePolicy.auditLevelTarget`); recorded 0.1.0 tree: 0 vulnerabilities at every severity (317 locked dependencies, MCP SDK at the 1.30.0 fix baseline).
210
+ - **Named threat-suites leg.** `npm run security:threat-suites` aggregates the Phase 8–11 conformance suites (durable-loop/HITL approval, coding sandbox/egress/forge, ACP protocol, OIDC/OPA/MCP-OAuth/OpenAPI/artifact) into one named 0.1.0 security evidence leg — same scripts as `npm test`, no rewrite; the Phase 7 tenant-isolation suite is its protected counterpart under `npm run test:postgres` (missing `PRISM_TEST_POSTGRES_URL` is a named blocked gate).
211
+ - **Supply-chain negative fixtures.** `scripts/release-gate.test.mjs` verifies the tarball deny list rejects tampered content (plans/reviews/maps/tests), unexpected file types and credential material (native binaries, `.pem`/`.key`/`.p12`), and that a provenance flag suppressed in CI is detectable in the `release.mjs` publish dry-run arguments (`--provenance` mandatory under `GITHUB_ACTIONS`, never claimed on local OIDC-less publishes).
212
+ - **Mandatory gate stack.** CodeQL/SAST, PR dependency review (fail on high), secret scan (source + unpacked tarballs), SPDX SBOM + license policy, tarball allow/deny content checks, and provenance (npm OIDC + GitHub build attestations on tarballs and SBOM) all run in `security.yml`/`release.yml`; evidence for the 0.1.0 tree is recorded in [0.1.0 readiness](0.1.0-readiness.md).
213
+ - **Live canaries are blocked gates, not skips.** The `live-canaries` and `sandbox-browser` workflows always set their gate env (`PRISM_LIVE_CANARIES=1`), so absent credentials fail the job loudly with a named owner (the workflow + dispatching operator) and retained `canary-report.json` evidence; the local silent-skip path exists only when the gate env is not set.
205
214
 
206
215
  ## Distributed events and tool effects
207
216
 
package/docs/index.md CHANGED
@@ -6,8 +6,8 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
6
6
  - [Public contracts](public-contracts.md): type shapes for messages, agents, tools, stores, generic `CheckpointStore`, atomic `LeaseStore`, bounded `EventMultiplexer`, resources, credentials, and events.
7
7
 
8
8
  ## Identity and governance
9
- - [Agent identity](agent-identity.md): host-verified `Principal` / `AgentIdentity`, delegation narrowing, ownership projection, and redacted telemetry refs for enterprise runs/tools/MCP/A2A/workflows.
10
- - [Policy and audit](policy-and-audit.md): optional `@arnilo/prism-policy` decision ledger (allow/deny/modify/approval), evidence refs only, cursor-paginated WORM export, and durable PostgreSQL composition.
9
+ - [Agent identity](agent-identity.md): host-verified `Principal` / `AgentIdentity`, delegation narrowing, ownership projection, and redacted telemetry refs for enterprise runs/tools/MCP/A2A/workflows; optional OIDC/JWKS verifier adapter (`@arnilo/prism-credentials-node/oidc` — pinned issuer/audience/JWKS, bounded claims, fail closed).
10
+ - [Policy and audit](policy-and-audit.md): optional `@arnilo/prism-policy` decision ledger (allow/deny/modify/approval), evidence refs only, cursor-paginated WORM export, and durable PostgreSQL composition; 0.0.28 adds the OPA REST evaluator (`@arnilo/prism-policy/opa` — pinned SSRF-checked endpoint, redacted input, fail-closed deny, optional bundle-revision pin).
11
11
  - [Model routing](model-routing.md): optional `@arnilo/prism-model-router` allow-list/residency/budget/rate/circuit/fallback governance with redacted diagnostics; durable state requires awaited identity-scoped calls.
12
12
 
13
13
  ## Agent/session runtime
@@ -19,7 +19,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
19
19
  - [Observability](observability.md): OTel GenAI agent/provider/tool hierarchy, host context parenting, bounded trace linkage, safe evaluation events, controlled metrics, and exporter isolation.
20
20
  - [Evaluations](evaluations.md): deterministic and bounded trace/model-judge/pairwise scoring, CI thresholds, OTel trace-reference linkage, coding/browser adversarial fixtures, ID-only linkage to immutable owned run feedback, and optional durable PostgreSQL records.
21
21
  - [Runs and usage ledger](runs-and-usage.md): durable run/event/tool/usage persistence, optional bounded FIFO durability policies, session snapshot caching, and immutable run/trace feedback.
22
- - [Performance limits](performance.md): 0.0.26 coding-intelligence/process/forge/egress network-free evidence, 0.0.25 durable-loop/HITL/A2UI network-free evidence, 0.0.24 distributed event/effect PostgreSQL evidence, 0.0.23 enterprise state evidence, 0.0.15 network-free provider/RAG/memory benchmark evidence and frozen caps, bounded evaluation traces/judges/reports, and production sizing assumptions.
22
+ - [Performance limits](performance.md): **0.1.0 capacity envelopes** (frozen performance contract, 24 network-free + 16 protected p95 rows, startup/pack rows), 0.0.26 coding-intelligence/process/forge/egress network-free evidence, 0.0.25 durable-loop/HITL/A2UI network-free evidence, 0.0.24 distributed event/effect PostgreSQL evidence, 0.0.23 enterprise state evidence, 0.0.15 network-free provider/RAG/memory benchmark evidence and frozen caps, bounded evaluation traces/judges/reports, and production sizing assumptions.
23
23
  - [Structured output](structured-output.md): the `Artifact*` seam plus provider-native `StructuredOutputOptions` / `structuredOutputMode` for capable models.
24
24
 
25
25
  ## Compaction/session memory
@@ -29,13 +29,13 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
29
29
  - [Working and semantic memory](working-and-semantic-memory.md): optional `@arnilo/prism-memory` working-memory store, semantic recall, finite Embedder/VectorStore contracts, PostgreSQL/pgvector path, consent lifecycle, identity-bound redacted export, and resumable bounded rebuild.
30
30
  - [Session stores](session-stores.md): `SessionStore` contract, `SessionAppendOptions`, `SessionAppendConflictError`, branch handles, `readBranchPath`, optional bounded `searchSessions` / `SessionIndex` (memory linear|unsupported), and dev-vs-production branch reads — start here for session persistence.
31
31
  - [Conversations](conversations.md): durable user-scoped conversation threads (create/list/continue/branch/archive/export/delete) on session + event-ledger seams, thread-bound reconnectable replay, frozen caps, and legal-hold-aware deletion.
32
- - [Work artifacts and review](work-artifacts-and-review.md): durable artifact co-work review — authorized attach (MIME/hash/version, producer run, citations, preview metadata), revision compare, approve/reject with last-validated recovery, and authorized expiring delivery links; records persist as versioned checkpoints, never file bodies.
32
+ - [Work artifacts and review](work-artifacts-and-review.md): durable artifact co-work review — authorized attach (MIME/hash/version, producer run, citations, preview metadata), revision compare, approve/reject with last-validated recovery, and authorized expiring delivery links; records persist as versioned checkpoints, never file bodies. 0.0.28 adds the core `ArtifactBodyStore` contract (put/get/delete/presign by opaque ownership-scoped ref, hash/size/MIME verification, legal-hold-aware idempotent delete) and the reference `@arnilo/prism-server/artifact-bodies` S3-compatible adapter (hand-rolled SigV4, native fetch + WebCrypto, optional host KMS callback); delivery links resolve through `bodies.presign` when wired.
33
33
  - [Session stores and branching](session-stores-and-branching.md): detailed branch semantics and helper reference (kept for compatibility; links back to the canonical atomic append / branch-handle sections).
34
34
  - [Database persistence](database-persistence.md): production persistence contracts, shared checksummed migration/full-shape catalog primitives (`@arnilo/prism/testing/persistence-schema`), conditional append, indexes, `readBranchPath`, reference relational schema, retention/legal-hold/quota lifecycle (`lifecycle`), and NoSQL mapping.
35
35
  - [SQLite persistence](sqlite-persistence.md): optional `better-sqlite3` adapter with session/run storage, checkpoints/leases, feedback, FTS `searchSessions` (migration-v4), and transactionally verified/backfilled migration metadata.
36
36
  - [PostgreSQL persistence](postgres-persistence.md): optional pooled `pg` adapter with session/run/checkpoint/lease/feedback storage, FTS `searchSessions` (migration-v4), advisory-locked checksummed/full-shape migrations, and opt-in live conformance.
37
37
  - [Enterprise PostgreSQL state](enterprise-postgres-state.md): optional `@arnilo/prism-enterprise-postgres` composition for durable policy/evaluation/work-idempotency/model-router/`toolEffects` state, exact ownership, checksummed migrations, and explicit cleanup.
38
- - [Migration guide](migration.md): **0.0.27** ACP coding-host interop (capability advertise-when, session modes/config, MCP select, lifecycle events, elicitation); **0.0.26** coding intelligence, managed processes, forge, and safe egress; **0.0.25** durable custom loops and shared human-in-the-loop decisions; **0.0.24** distributed events and recoverable tool effects; **0.0.23** enterprise PostgreSQL state adapters (async router and work reconciliation); **0.0.22** third-party behavior integrations (Caveman, Ponytail); **0.0.21** coding-tool capability gaps (`outputMode`, glob, read-before-write, delete/move, aggregator 9/4); **0.0.20** progressive skill disclosure, empty registry default, `load_skill`, priority budget demotion, optional tool-result fold; **0.0.19** observational memory lifecycle; **0.0.15** OpenAI hosted tools/continuation/Realtime, exact AI SDK v4 matrix, RAG lifecycle/reranking/trust/status, and memory export/rebuild; **0.0.14** conversations, memory consent/lifecycle, artifact co-work review, AG-UI co-work events, scoped M365/GWS OAuth connectors, browser checkpoints, device contracts, and Alibaba/Ollama providers; plus prior release migrations.
38
+ - [Migration guide](migration.md): **0.0.28 → 0.1.0** release-candidate hardening (no migration); **0.0.17 → 0.1.0 upgrade matrix** (store compatibility per release line: compatible / tested migration / tested refusal, plus breaking-default callouts); **0.0.27** ACP coding-host interop (capability advertise-when, session modes/config, MCP select, lifecycle events, elicitation); **0.0.26** coding intelligence, managed processes, forge, and safe egress; **0.0.25** durable custom loops and shared human-in-the-loop decisions; **0.0.24** distributed events and recoverable tool effects; **0.0.23** enterprise PostgreSQL state adapters (async router and work reconciliation); **0.0.22** third-party behavior integrations (Caveman, Ponytail); **0.0.21** coding-tool capability gaps (`outputMode`, glob, read-before-write, delete/move, aggregator 9/4); **0.0.20** progressive skill disclosure, empty registry default, `load_skill`, priority budget demotion, optional tool-result fold; **0.0.19** observational memory lifecycle; **0.0.15** OpenAI hosted tools/continuation/Realtime, exact AI SDK v4 matrix, RAG lifecycle/reranking/trust/status, and memory export/rebuild; **0.0.14** conversations, memory consent/lifecycle, artifact co-work review, AG-UI co-work events, scoped M365/GWS OAuth connectors, browser checkpoints, device contracts, and Alibaba/Ollama providers; plus prior release migrations.
39
39
  - [Node JSONL session store](node-jsonl-session-store.md): development-only JSONL file adapter for single-process Node hosts; no cross-process safety; `searchSessions` throws `SessionSearchUnsupportedError`.
40
40
  - [Persistence, credentials, and multimodality primitives](persistence-credentials-multimodality-primitives.md): Plan 056 inventory — session/run-ledger/persistence contracts, credential/OAuth seams, content/resource/model capabilities, package dependency matrix, conformance matrix, and threat model for production adapters.
41
41
 
@@ -65,9 +65,10 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
65
65
  ## Tools
66
66
  - [Recoverable tool effects](tool-effects.md): optional effect declarations, `ToolEffectStore` claim/CAS, unknown reconciliation (not exactly-once), and adapter classifications.
67
67
  - [Tools](tools.md): register host-owned active tools with replace-or-error duplicate policy, apply exact allow/deny filtering, dispatch normal or opt-in bounded artifact-loop calls, and optionally bound untrusted JSON Schema compilation.
68
+ - [OpenAPI tools adapter](openapi-tools.md): optional `@arnilo/prism-openapi-tools` `createOpenApiTools` — compile host-selected OpenAPI 3.1 operationIds into bounded `ToolDefinition`s (allow-list only, pinned origin, resolved/bounded schemas, approval + effect-store idempotency on mutations, bounded body/response/retries/pagination, host credential resolver, untrusted output).
68
69
  - [Tool execution primitives](tool-execution-primitives.md): finite JSON Schema LRU validation, exclusive-aware bounded parallel dispatch, MCP bridge mapping, coding execution policy, and image-read bounds.
69
70
  - [Tool validator JSON Schema package](../packages/tool-validator-json-schema/README.md): optional `@arnilo/prism-tool-validator-json-schema` adapter for `tool.parameters`.
70
- - [MCP client bridge and server exposure](mcp-tools.md): SDK-1.29.0 bounded tools/resources/prompts, host-owned roots/sampling/elicitation, exact-origin DNS-pinned client transport, and principal-bound opt-in Streamable HTTP sessions.
71
+ - [MCP client bridge and server exposure](mcp-tools.md): SDK-1.30.0 bounded tools/resources/prompts, host-owned roots/sampling/elicitation, exact-origin DNS-pinned client transport, and principal-bound opt-in Streamable HTTP sessions. 0.0.28 adds MCP OAuth: `createMcpOAuthTransport`/`createMcpOAuthFetch`/`createMcpClientAuth` (RFC 9728/8414 discovery, PKCE, RFC 8707 audience binding, RFC 7009 revocation, host-owned bounded state) and server `protectedResource` metadata + `WWW-Authenticate` challenges.
71
72
  - [Web search, fetch, and extraction](web-tools.md): optional host-selected Brave/Exa discovery and Firecrawl Markdown/schema tools with native fetch, stable citations, late credentials, finite limits, and explicit untrusted-content boundaries.
72
73
  - [Work tools](work-tools.md): optional `@arnilo/prism-work-tools` identity-scoped M365 + GWS connectors (hard-coded CLI argv, draft-then-approve, state-machine idempotency, shared result shapes); 0.0.14 adds a late-bound per-identity `tokenProvider` (env-only, fail-closed).
73
74
  - [Work connectors](work-connectors.md): connector principles, capability gates, scoped OAuth establishment (0.0.14), and out-of-scope boundaries (Slack/Teams channels not shipped) for Microsoft 365 / Google Workspace.
@@ -108,10 +109,10 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
108
109
  - [Workflow/TUI scope](workflow-tui-primitives.md): records why 0.0.5 ships workflow APIs/RPC control but no interactive terminal UI.
109
110
 
110
111
  ## Security and credentials
111
- - [Host security guide](host-security.md): fail-closed checklist for supply-chain/attestation/canary isolation, bounded credentials, AG-UI/ACP/A2A/web remote boundaries, untrusted external content, settings, redaction, trust roots, workflow ownership, coding I/O, permissions, PostgreSQL TLS/roles/cleanup, persistence, extensions, and tool validation.
112
+ - [Host security guide](host-security.md): fail-closed checklist for supply-chain/attestation/canary isolation, bounded credentials, AG-UI/ACP/A2A/web remote boundaries, untrusted external content, settings, redaction, trust roots, workflow ownership, coding I/O, permissions, PostgreSQL TLS/roles/cleanup, persistence, extensions, and tool validation; **0.1.0 security evidence** (plan 012 Task 6): moderate audit policy, named threat-suites leg (`npm run security:threat-suites`), supply-chain negative fixtures, blocked-gate canary semantics.
112
113
  - [Security/auth/trust](settings-auth-trust-security.md): settings providers, credential helpers, trust/permission policies, redaction controls, host-owned settings/credentials wiring outside `AgentConfig`, and security-boundary hardening summary.
113
114
  - [Credentials and redaction](credentials-and-redaction.md): compose explicit credential resolver order, use caller-supplied env objects/OAuth refresh + revoke helpers, resolve credentials only at the provider edge, redact known secret values, and follow the provider-authorized subscription OAuth matrix.
114
- - [Credential storage](credential-storage.md): optional `@arnilo/prism-credentials-node` adapter with strict bounded AES-GCM envelopes, async finite scrypt, restrictive Unix files, abort-aware bounded system-keychain calls, optional host-KMS wrap (`encryptWithHostKms`), and 0.0.14 Microsoft 365 / Google Workspace OAuth providers (PKCE/device-code, least-privilege scope bundles, per-identity work-token bridge).
115
+ - [Credential storage](credential-storage.md): optional `@arnilo/prism-credentials-node` adapter with strict bounded AES-GCM envelopes, async finite scrypt, restrictive Unix files, abort-aware bounded system-keychain calls, optional host-KMS wrap (`encryptWithHostKms`), and 0.0.14 Microsoft 365 / Google Workspace OAuth providers (PKCE/device-code, least-privilege scope bundles, per-identity work-token bridge); `./oidc` subpath adds the OIDC/JWKS identity verifier.
115
116
 
116
117
  ## Testing and examples
117
118
  - Provider test doubles: `createMockProvider()` and provider event helpers are documented on the canonical Provider layer page above.
@@ -128,7 +129,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
128
129
  - [Ponytail behavior integration](ponytail.md): optional `@arnilo/prism-ponytail` — upstream Ponytail skills/commands, `ponytail-mode` injector, session `ponytail-mode` persistence; resolves peer `@dietrichgebert/ponytail` or `upstreamPath`; opt-in (not in code/sdk profiles).
129
130
 
130
131
  ## Release and install
131
- - [Release and install](release-and-install.md): current **0.0.24** 47-package graph (Phase 7 distributed events and tool effects; plan 007), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, protected PostgreSQL gate, pinned supply-chain gates, offline tests, the 0.0.15 provider/AI-SDK/RAG/memory protected live-canary matrix, and sandbox-browser Docker/Playwright gates.
132
+ - [Release and install](release-and-install.md): current **0.1.0** 48-package graph (Phase 12 release-candidate hardening; plan 012 — freeze manifest, compatibility matrix, upgrade matrix, packed-install e2e journeys, restart-recovery evidence, capacity envelopes, security policy), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, frozen 0.1.x compatibility and support matrix (Node/PostgreSQL/platform/provider/protocol pins and unsupported combinations, machine-checked against `scripts/phase12-freeze-manifest.json`), protected PostgreSQL gate, pinned supply-chain gates, offline tests, the 0.0.15 provider/AI-SDK/RAG/memory protected live-canary matrix, and sandbox-browser Docker/Playwright gates.
132
133
  - [0.1.0 / 1.0 readiness gates](0.1.0-readiness.md): command-per-gate 1.0 readiness table — frozen API surface + compat gate, migration/docs tripwires, budget table, live-suite matrix, security matrix, current-line status (**0.0.23** published target), signed-publication/live-canary prerequisites for 1.0, and Phase 12 demand-evidence entry criteria.
133
134
  - [Review coverage (2026-07-26 Phase 11)](review-coverage-2026-07-26-phase-11.md): Plan 079 evidence freeze — baseline size/startup/benchmark budgets, hotspot domain extraction table, confirmed duplication survivors (redactor/cleanJson/row-codecs/checkpoints/exec-runner/approval/ownership), profile adoption recommendations, and tarball artifact-diet findings for 0.0.16.
134
135
  - [Review coverage (2026-07-26 Phase 10)](review-coverage-2026-07-26-phase-10.md): Plan 078 evidence freeze — OpenAI hosted tools/continuation/realtime, AI SDK version matrix, remaining provider metadata parity, RAG replaceSource/loaders/parsers/reranker/provenance/ingestion-status, memory export/rebuild/conformance, and 0.0.15 (43 → 43 manifests; no new package) release gates.
package/docs/mcp-tools.md CHANGED
@@ -228,6 +228,43 @@ MCP output is untrusted. Register bridge tools through core dispatch with a `Sec
228
228
 
229
229
  Discovery validation is atomic: cursor/page/tool/name/description/schema failures reject `refresh()` and preserve the previous immutable tool-array reference. The bridge intentionally uses raw SDK `request()` for `tools/list` and `tools/call`; this avoids eager Ajv compilation/validation of untrusted remote output schemas. Host `ToolValidator` remains the argument-validation owner.
230
230
 
231
+ ## MCP OAuth (0.0.28)
232
+
233
+ Optional RFC 9728/8414 OAuth client and server wiring for Streamable HTTP transports.
234
+
235
+ **Client** — pass `auth` to the transport/bridge options:
236
+
237
+ ```ts
238
+ import { createMcpClientAuth } from "@arnilo/prism-mcp";
239
+
240
+ const auth = createMcpClientAuth(
241
+ {
242
+ state, // required persistence seam: load/save tokens, discovery, client info, code verifier
243
+ strategy: { kind: "static", clientId: "prism", clientSecret: "..." }, // or { kind: "dcr", clientMetadata }
244
+ redirectUri: "http://localhost:33418/callback",
245
+ onRedirectRequired: (url) => openBrowser(url), // interactive flows
246
+ },
247
+ { serverUrl: "https://mcp.example.com/api", fetch },
248
+ );
249
+ ```
250
+
251
+ The flow reuses the MCP SDK's `auth()` helper (401 → protected-resource metadata → RFC 8414 discovery → PKCE S256 → token exchange/refresh) wrapped in Prism policy: discovery URLs are SSRF-checked, https-only (loopback http opt-in), DNS-pinned, zero-redirect, and byte-bounded; RFC 8707 resource binding is enforced on every token request (`ERR_PRISM_MCP_OAUTH_AUDIENCE` on origin drift); issuer origin must match the discovered authorization server (`ERR_PRISM_MCP_OAUTH_ORIGIN`); bearer tokens are only ever attached to the allow-listed server origin. `McpClientAuthState` has no default implementation — production hosts back it with an encrypted/keychain store (refresh tokens must not live in plaintext persistence).
252
+
253
+ **Server** — advertise protected-resource metadata and challenge unauthenticated requests:
254
+
255
+ ```ts
256
+ const handler = await createPrismMcpWebHandler(factory, {
257
+ protectedResource: {
258
+ authorizationServers: ["https://as.example.com/"],
259
+ resource: "https://mcp.example.com/mcp", // required (RFC 9728)
260
+ scopesSupported: ["mcp"],
261
+ },
262
+ resolveIdentity, // host-owned token verification stays here
263
+ });
264
+ ```
265
+
266
+ The handler serves `GET /.well-known/oauth-protected-resource` and returns `401 WWW-Authenticate: Bearer resource_metadata="<origin>/.well-known/oauth-protected-resource"` on rejected requests. Token verification remains entirely host-owned via `resolveIdentity`; Prism only advertises and challenges.
267
+
231
268
  ## Vendor web MCP prototype boundary
232
269
 
233
270
  Official Exa/Firecrawl MCP servers may be tested only as explicit hardened prototypes: pin endpoint/origin/auth, inspect declared capabilities, allow-list individual tools/resources, retain all MCP bounds, and never expose generic remote passthrough. Production web research uses direct host-selected `@arnilo/prism-web-tools` adapters so provider choice, credentials, schema, and costs remain outside model control.
package/docs/migration.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # Migration guide
2
2
 
3
+ ## 0.0.28 → 0.1.0 release-candidate hardening (no migration)
4
+
5
+ Release **0.1.0** (Phase 12) is a release-candidate hardening cut of the **0.0.28** graph: no new packages, public exports, schema migrations, or runtime dependencies (frozen in `scripts/phase12-freeze-manifest.json`; deviations require a recorded plan 012 Task 0 entry). No persisted shape, event schema, or default behavior changed. **Store compatibility: compatible** — session-store and enterprise PostgreSQL schemas stay at the checksum-protected contract shipped in 0.0.24–0.0.28; no upgrade or rollback step exists for 0.0.28 → 0.1.0. No breaking defaults. 0.1.x patch releases promise additive-only declaration deltas vs `scripts/compat-baseline` (enforced by `node scripts/release.mjs gate`).
6
+
7
+ ## 0.0.17 → 0.1.0 upgrade matrix
8
+
9
+ | Release line | What changed | Store compatibility | Breaking defaults |
10
+ | --- | --- | --- | --- |
11
+ | 0.0.18 | `repo_search` literal-only, atomic write/edit, context-budget eviction, MCP SDK 1.30.0 | compatible (no persisted shape change) | default `inputLayout` → `cache_aware` |
12
+ | 0.0.19 | observational-memory lifecycle, nested OM settings | compatible (no persisted shape change) | none |
13
+ | 0.0.20 | skills progressive disclosure, `load_skill` | compatible (no persisted shape change) | `SkillRegistry` activates **zero** skills unless `activateAllSkills`; disclosure default `progressive` |
14
+ | 0.0.21 | coding-tool capability gaps (`outputMode`, `glob`, delete/move, read-before-write) | compatible (no persisted shape change) | none |
15
+ | 0.0.22 | Caveman/Ponytail behavior packages | compatible (no persisted shape change) | none |
16
+ | 0.0.23 | enterprise-postgres state adapters | **tested migration** (enterprise migration 001, checksum-protected, per-schema advisory lock) | none |
17
+ | 0.0.24 | durable `AgentEventSource`, `ToolEffectStore` | **tested migration** (session-store 006/007; enterprise 002; backup before upgrade) | none |
18
+ | 0.0.25 | durable custom loops, batched approvals | **tested refusal** — persisted 0.0.24 runs fail closed on 0.0.25 resume (fingerprint `{name, revision}`) | durable-loop fingerprint shape |
19
+ | 0.0.26 | coding intelligence, process sessions, forge, egress | compatible (no persisted shape change) | none |
20
+ | 0.0.27 | ACP coding-host interop | compatible (no persisted shape change) | none |
21
+ | 0.0.28 | OIDC/OPA/MCP-OAuth/OpenAPI/artifact adapters | compatible (no persisted shape change) | none |
22
+ | 0.1.0 | RC hardening | compatible (no migration) | none |
23
+
24
+ Verification: `PRISM_TEST_POSTGRES_URL=... npm run test:postgres` runs the disposable PostgreSQL suites including the upgrade-chain and refusal tests below; `node scripts/release.mjs gate` enforces the additive-only compat promise. Each release-line section below documents its changes in detail.
25
+
26
+ ## 0.0.27 → 0.0.28 enterprise auth, policy, MCP OAuth, API, and artifact adapters (additive)
27
+
28
+ Release **0.0.28** (Phase 11) adds five optional enterprise adapter seams: an OIDC/JWKS identity verifier, an OPA policy evaluator with durable ledger entries, MCP OAuth client/server support, host-selected OpenAPI operations compiled into effect-gated tools, and an S3-compatible artifact body store behind a new core body contract. Everything is **additive and opt-in** — hosts that wire none of it keep exact prior behavior (the Phase 11 conformance suite asserts the adapter-absent baseline). Publishable graph stays **48** manifests.
29
+
30
+ 1. **OIDC identity verifier is a new subpath.** `createOidcIdentityVerifier` from `@arnilo/prism-credentials-node/oidc` returns a core `IdentityVerifier`: RS256/ES256 over native WebCrypto, host-pinned JWKS URL with SSRF policy, one bounded refetch on unknown `kid`, fail-closed `IdentityError` reasons `ERR_PRISM_OIDC_*`. SSRF denials surface as the core `MediaContentError` (`ssrf_denied`), not as verification failures. The SDK never stores tokens; hosts map claims to `AgentIdentity` themselves.
31
+ 2. **OPA evaluator is a new subpath.** `createOpaPolicyEvaluator` from `@arnilo/prism-policy/opa` returns a core `PolicyEvaluator` for use with `createPolicyEvaluator`/`evaluateAndAppend` (the Phase 6 durable ledger). Timeouts and transport failures fail closed to `deny` by default (`onFailure: "escalate"` rethrows); the mapped input never carries prompts, tokens, or credentials; `requirePolicyVersion` pins the OPA bundle revision.
32
+ 3. **MCP OAuth client wiring is opt-in per transport.** `createMcpOAuthTransport`/`createMcpOAuthFetch` (from `@arnilo/prism-mcp`) add RFC 9728/8414 discovery, PKCE interactive flow, RFC 8707 resource-bound tokens, and RFC 7009 revocation over the existing pinned fetch policy. Hosts supply persistence through `McpClientAuthState` (tokens/discovery/client-information/code-verifier); refresh tokens belong in encrypted/keychain-backed stores. Transports without an `auth` option are unchanged.
33
+ 4. **`createPrismMcpWebHandler` takes a server factory and gains `protectedResource`.** The first argument now accepts `McpServer | (() => McpServer | Promise<McpServer>)`. Stateless operation **requires** a factory: the previous shared stateless transport threw `Stateless transport cannot be reused across requests` on the second request, so this is a correctness fix; stateful callers may keep passing an instance. The new `protectedResource` option serves RFC 9728 metadata at `/.well-known/oauth-protected-resource` and adds `WWW-Authenticate: Bearer resource_metadata=...` challenges to 401s; `resource` is required (fail closed at configuration time). Handlers without the option behave exactly as before.
34
+ 5. **OpenAPI tools are a new package.** `@arnilo/prism-openapi-tools` `createOpenApiTools({ document, operations, server, ... })` compiles only host-listed `operationId`s from an OpenAPI 3.1 document at setup time (never model-driven discovery): GET-family operations get `effect: { kind: "none" }`, mutation operations get `{ kind: "external_mutation", idempotency: "required" }` so the core run loop gates approval and idempotency; responses are bounded, redacted, and marked `trust: "untrusted_external"`; the server origin is pinned and drift fails closed.
35
+ 6. **Artifact bodies stay host-owned, with a new optional contract.** Core gains `ArtifactBodyStore`/`ArtifactBodyRef`/`ArtifactBodyStoreError` (types only, storage-free) and an optional `size` on `ArtifactRevision`. `createArtifactService` accepts an optional `bodies` store; `deliveryLink` then resolves a presigned `url` through `bodies.presign` and fails closed when the revision has no recorded size. `@arnilo/prism-server/artifact-bodies` ships the reference S3-compatible adapter (hand-rolled SigV4, optional host KMS callback, legal hold blocks delete). Services without a body store behave exactly as before (no `url` on delivery links).
36
+ 7. **No migration steps required.** No persisted shape, event schema, or default behavior changed; all seams are inert until configured. Errors: `ERR_PRISM_OIDC_*`, `ERR_PRISM_OPA_*`, `ERR_PRISM_MCP_OAUTH_*`, `ERR_PRISM_OPENAPI_*`, `ERR_PRISM_ARTIFACT_BODY_*`, `ERR_PRISM_S3_*`.
37
+
38
+ Conformance: `node --test scripts/phase11-conformance.test.mjs`; evidence: `scripts/benchmark-0.0.28.json`; freeze: `scripts/phase11-freeze-manifest.json`. Docs: [agent identity](agent-identity.md), [policy and audit](policy-and-audit.md), [MCP tools](mcp-tools.md), [OpenAPI tools](openapi-tools.md), [work artifacts and review](work-artifacts-and-review.md), [host security](host-security.md).
39
+
3
40
  ## 0.0.26 → 0.0.27 ACP coding-host interop (intentional advertise/surface changes)
4
41
 
5
42
  Release **0.0.27** (Phase 10) turns `@arnilo/prism-ag-ui/acp` from a text/tool/usage/approval glue layer into a full coding-host adapter over the Phase 8/9 primitives: host-seam capability advertisement, session persistence, modes and config options, client fs/terminal, MCP bridging behind a host gate, coding lifecycle events, and elicitation. ACP stays stable **v1** on `@agentclientprotocol/sdk@1.3.0`; UNSTABLE fields are never advertised or consumed. Publishable graph stays **48** manifests.