@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.
- package/CHANGELOG.md +29 -0
- package/dist/artifacts.d.ts +54 -0
- package/dist/artifacts.js +20 -0
- package/dist/index.d.ts +15 -15
- package/dist/index.js +8 -8
- package/dist/tool-effects.js +18 -4
- package/dist/tool-result-fold.js +15 -3
- package/docs/0.1.0-readiness.md +108 -63
- package/docs/agent-identity.md +33 -0
- package/docs/credential-storage.md +2 -0
- package/docs/enterprise-postgres-state.md +1 -0
- package/docs/host-security.md +11 -2
- package/docs/index.md +10 -9
- package/docs/mcp-tools.md +37 -0
- package/docs/migration.md +37 -0
- package/docs/openapi-tools.md +56 -0
- package/docs/performance.md +99 -0
- package/docs/policy-and-audit.md +31 -0
- package/docs/public-contracts.md +47 -0
- package/docs/release-and-install.md +129 -14
- package/docs/tools.md +1 -0
- package/docs/work-artifacts-and-review.md +3 -1
- package/package.json +5 -4
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# OpenAPI tools adapter (`@arnilo/prism-openapi-tools`)
|
|
2
|
+
|
|
3
|
+
Optional `createOpenApiTools` compiles host-selected OpenAPI 3.1 operations into bounded Prism `ToolDefinition`s. Zero dependencies (native fetch + WebCrypto-free); the compile step is pure and separated from the runtime executor.
|
|
4
|
+
|
|
5
|
+
## When to use it
|
|
6
|
+
|
|
7
|
+
Hosts that already expose a JSON API with an OpenAPI 3.1 document and want the agent to call a **fixed, host-chosen subset** of it — never model-driven discovery, never a raw method/path passthrough. For vendor web search/extraction use `@arnilo/prism-web-tools`; for M365/GWS use `@arnilo/prism-work-tools`; this adapter is for arbitrary host APIs.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { createOpenApiTools } from "@arnilo/prism-openapi-tools";
|
|
13
|
+
|
|
14
|
+
const tools = createOpenApiTools({
|
|
15
|
+
document, // OpenAPI 3.1 document (JSON string or parsed object)
|
|
16
|
+
operations: ["getCustomer", "createCase"], // only these operationIds compile
|
|
17
|
+
server: "https://api.example.com/v1", // pinned base URL
|
|
18
|
+
credentials: async ({ operationId }) => ({
|
|
19
|
+
headers: { authorization: `Bearer ${await hostToken(operationId)}` },
|
|
20
|
+
}),
|
|
21
|
+
policy: ({ operationId, args }, context) => {
|
|
22
|
+
if (operationId === "createCase" && !context.identity) throw new Error("identity required");
|
|
23
|
+
},
|
|
24
|
+
redactor, // applied to response text before it enters the tool result
|
|
25
|
+
pagination: { pageParam: "page", pageSizeParam: "limit", pageSize: 50, nextPath: "next", itemsPath: "items" },
|
|
26
|
+
idempotencyKeyHeader: true, // forward the core Idempotency-Key on mutating requests
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Register the returned tools with `createToolRegistry` (or pass them to the MCP bridge); validate arguments with `createJsonSchemaToolArgumentValidator` as usual.
|
|
31
|
+
|
|
32
|
+
## Compile-time guarantees
|
|
33
|
+
|
|
34
|
+
- **Allow-list only**: operations not listed never compile; unknown ids throw `ERR_PRISM_OPENAPI_OPERATION_UNKNOWN`. No generic arbitrary-request escape hatch.
|
|
35
|
+
- **Origin pinned**: the `server` option is the only authority. Every document/path/operation `servers` entry must resolve to the pinned origin (relative URLs resolve against it), else `ERR_PRISM_OPENAPI_SERVER_DRIFT`. https only; http allowed only for loopback hosts.
|
|
36
|
+
- **Bounded schemas**: internal `$ref`s resolve into self-contained argument schemas (path + query + header + body in one object, `additionalProperties: false`). Cycles, depth (`maxSchemaDepth`), ref count (`maxRefs`), external refs, cookie parameters, non-JSON request bodies, and duplicate argument names all fail closed (`ERR_PRISM_OPENAPI_SCHEMA_BOUNDS`).
|
|
37
|
+
- **Effects**: GET/HEAD/OPTIONS/TRACE compile as `{ kind: "none", idempotency: "none" }`; POST/PUT/PATCH/DELETE as `{ kind: "external_mutation", idempotency: "required" }` — the core run loop gates approval ("Tool side effect requires approval") and deduplicates via the `ToolEffectStore` (mutating tools require a verified identity and an effect store at dispatch; retries never re-execute a completed effect). Optional `idempotencyKeyHeader: true` also forwards the core key as `Idempotency-Key` for APIs that honor it.
|
|
38
|
+
|
|
39
|
+
## Runtime guarantees
|
|
40
|
+
|
|
41
|
+
- Request body and response bounded (`maxBodyBytes`, `maxResponseBytes`); oversized responses fail closed (`ERR_PRISM_OPENAPI_RESPONSE_BOUNDS`).
|
|
42
|
+
- Retries only on transport errors and 5xx, bounded by `maxRetries` (default 0, hard 3); transport failures after exhaustion throw `ERR_PRISM_OPENAPI_RETRY_EXHAUSTED`; 4xx never retried.
|
|
43
|
+
- Optional cursor pagination applies only to operations whose compiled query parameters include `pageParam`; bounded by `maxPages` and `maxPaginationItems`.
|
|
44
|
+
- Credentials come only from the host `credentials` resolver (headers/query merged per call), never from the document or options; the optional `redactor` runs over response text before the result is built, so echoed secrets are stripped.
|
|
45
|
+
- Responses are untrusted data: results carry an "UNTRUSTED EXTERNAL API CONTENT" marker and `metadata.trust: "untrusted_external"`; redirects are never followed (`redirect: "manual"`); caller aborts propagate without retry.
|
|
46
|
+
|
|
47
|
+
## Limits
|
|
48
|
+
|
|
49
|
+
Defaults and hard caps (frozen in `scripts/phase11-freeze-manifest.json`): `maxDocumentBytes` 2 MiB/16 MiB, `maxOperations` 256/1024, `maxSchemaDepth` 32/128, `maxRefs` 1024/8192, `maxBodyBytes` 1 MiB/16 MiB, `maxResponseBytes` 1 MiB/16 MiB, `maxPages` 20/100, `maxPaginationItems` 1000/10000, `maxRetries` 0/3. Invalid limits throw `ERR_PRISM_OPENAPI_DOCUMENT_BOUNDS`.
|
|
50
|
+
|
|
51
|
+
## Related
|
|
52
|
+
|
|
53
|
+
- [Tools](tools.md): registry, dispatch, validation
|
|
54
|
+
- [Recoverable tool effects](tool-effects.md): approval + idempotency contracts
|
|
55
|
+
- [Host security guide](host-security.md): permission, trust, validation checklist
|
|
56
|
+
- Package README: [`@arnilo/prism-openapi-tools`](../packages/prism-openapi-tools/README.md)
|
package/docs/performance.md
CHANGED
|
@@ -6,6 +6,105 @@ Evaluation defaults are finite: 100 trace rows × 20 pages and 4 MiB aggregate t
|
|
|
6
6
|
|
|
7
7
|
This page states Prism runtime limits that keep slow consumers and long sessions from becoming unbounded memory or latency problems.
|
|
8
8
|
|
|
9
|
+
## Release 0.1.0 capacity envelopes (frozen performance contract)
|
|
10
|
+
|
|
11
|
+
`scripts/benchmark-0.1.0.mjs` composes the six phase benchmark scripts
|
|
12
|
+
(0.0.23–0.0.28) into one 0.1.0 capacity envelope; the merged evidence is
|
|
13
|
+
checked in as `scripts/benchmark-0.1.0.json` and re-gated on every `npm test`
|
|
14
|
+
by `scripts/benchmark-0.1.0.test.mjs` against the Task 0 freeze-manifest
|
|
15
|
+
capacity contract (`scripts/phase12-freeze-manifest.json`): a row that drifts
|
|
16
|
+
above its frozen p95 ceiling, a startup import above 250 ms, or a root pack
|
|
17
|
+
row beyond its ±5% diet tolerance fails the gate.
|
|
18
|
+
|
|
19
|
+
**Methodology.** Each leg is the same fixture as the phase benchmark that
|
|
20
|
+
introduced it (warmups and measured operations per leg are recorded in the
|
|
21
|
+
JSON `legs` array): in-process fakes and loopback fixture servers for the
|
|
22
|
+
network-free legs, disposable PostgreSQL 16 schema for the protected legs.
|
|
23
|
+
Measured on Node v24.18.0 / Linux x64 (local hardware; values are environment
|
|
24
|
+
evidence, not universal SLOs). Regenerate with:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
node scripts/benchmark-0.1.0.mjs --out scripts/benchmark-0.1.0.json
|
|
28
|
+
PRISM_TEST_POSTGRES_URL="postgresql://…" node scripts/benchmark-0.1.0.mjs --out scripts/benchmark-0.1.0.json # adds protected legs
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Pass/fail thresholds.** Network-free rows fail above the frozen ceiling in
|
|
32
|
+
the table below; protected PostgreSQL rows fail above their per-phase
|
|
33
|
+
budgets.json ceilings (50/100 ms per the approved budget contract); startup
|
|
34
|
+
import fails above `startupImportMsCeiling` (250 ms); root packed bytes and
|
|
35
|
+
file count fail above baseline × 1.05. Labels: **network-free** = runs in
|
|
36
|
+
`npm test` evidence, no network; **protected** = requires live PostgreSQL.
|
|
37
|
+
|
|
38
|
+
| Envelope | Recorded p95 ms | Ceiling ms | Source leg | Label |
|
|
39
|
+
| --- | ---: | ---: | --- | --- |
|
|
40
|
+
| oidcVerifyCacheHitMs | 0.151 | 5 | enterprise adapters (0.0.28) | network-free |
|
|
41
|
+
| oidcVerifyCacheMissMs | 0.351 | 100 | enterprise adapters (0.0.28) | network-free |
|
|
42
|
+
| policyDecisionMs | 0.052 | 100 | enterprise adapters (0.0.28) | network-free |
|
|
43
|
+
| mcpDiscoveryRoundTripMs | 1.563 | 250 | enterprise adapters (0.0.28) | network-free |
|
|
44
|
+
| mcpAuthHandshakeMs | 6.909 | 2,000 | enterprise adapters (0.0.28) | network-free |
|
|
45
|
+
| openapiToolCallMs | 0.011 | 1,000 | enterprise adapters (0.0.28) | network-free |
|
|
46
|
+
| artifactPut1MiBMs | 9.337 | 2,000 | enterprise adapters (0.0.28) | network-free |
|
|
47
|
+
| artifactPresignMs | 0.381 | 100 | enterprise adapters (0.0.28) | network-free |
|
|
48
|
+
| decisionApply | 4.484 | 5 | durable loops/HITL (0.0.25) | network-free |
|
|
49
|
+
| stickyMatch | 0.343 | 5 | durable loops/HITL (0.0.25) | network-free |
|
|
50
|
+
| snapshotCaptureRestore | 7.814 | 20 | durable loops/HITL (0.0.25) | network-free |
|
|
51
|
+
| a2uiPaint | 0.330 | 10 | durable loops/HITL (0.0.25) | network-free |
|
|
52
|
+
| enumerationList | 363.610 | 2,000 | coding/process/forge/egress (0.0.26) | network-free |
|
|
53
|
+
| processChunkPage | 0.048 | 10 | coding/process/forge/egress (0.0.26) | network-free |
|
|
54
|
+
| lspDiagnosticNormalize | 0.610 | 100 | coding/process/forge/egress (0.0.26) | network-free |
|
|
55
|
+
| forgePagination | 144.868 | 10,000 | coding/process/forge/egress (0.0.26) | network-free |
|
|
56
|
+
| proxyDownload | 86.879 | 30,000 | coding/process/forge/egress (0.0.26) | network-free |
|
|
57
|
+
| rendererStreamOps | 1.647 | 100 | coding/process/forge/egress (0.0.26) | network-free |
|
|
58
|
+
| agUiMapperSync | 33.059 | 100 | coding/process/forge/egress (0.0.26) | network-free |
|
|
59
|
+
| fsReadWriteRoundTripMs | 0.210 | 250 | ACP (0.0.27) | network-free |
|
|
60
|
+
| modeSwitchMs | 0.185 | 250 | ACP (0.0.27) | network-free |
|
|
61
|
+
| terminalChunkAckMs | 0.049 | 1,000 | ACP (0.0.27) | network-free |
|
|
62
|
+
| promptFirstUpdateMs | 0.082 | 2,000 | ACP (0.0.27) | network-free |
|
|
63
|
+
| promptEndMs | 0.094 | 30,000 | ACP (0.0.27) | network-free |
|
|
64
|
+
| policyAppend | 0.684 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
65
|
+
| policyQuery | 1.274 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
66
|
+
| evaluationAppend | 0.721 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
67
|
+
| evaluationQuery | 0.918 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
68
|
+
| workClaimComplete | 1.938 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
69
|
+
| workContention | 5.002 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
70
|
+
| routerRateContention | 17.582 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
71
|
+
| routerBudgetContention | 6.018 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
72
|
+
| routerCircuitContention | 27.098 | 50 | enterprise PostgreSQL (0.0.23) | protected |
|
|
73
|
+
| cleanupBatch | 3.509 | 100 | enterprise PostgreSQL (0.0.23) | protected |
|
|
74
|
+
| eventAppend | 1.553 | 50 | distributed events (0.0.24) | protected |
|
|
75
|
+
| eventPage | 3.187 | 50 | distributed events (0.0.24) | protected |
|
|
76
|
+
| effectClaimTransition | 2.642 | 50 | distributed events (0.0.24) | protected |
|
|
77
|
+
| eventCleanup | 1.255 | 100 | distributed events (0.0.24) | protected |
|
|
78
|
+
| effectCleanup | 3.174 | 100 | distributed events (0.0.24) | protected |
|
|
79
|
+
| reconnectCatchup | 8.374 | 100 | distributed events (0.0.24) | protected |
|
|
80
|
+
|
|
81
|
+
Install/startup rows (same helpers as the budget gate — no duplicate
|
|
82
|
+
measurement): startup import 41.7 ms (ceiling 250 ms); root packed 711,755
|
|
83
|
+
bytes vs baseline 678,541 (+5%, tolerance 5%); root file count 295 vs 293
|
|
84
|
+
(+5%). Storage-growth rows and query plans from the protected legs are in the
|
|
85
|
+
recorded JSON (`storageBeforeCleanup` / `storageAfterCleanup` per leg).
|
|
86
|
+
|
|
87
|
+
Conformance companions: `scripts/phase8–11-conformance.test.mjs` plus the
|
|
88
|
+
Task 3 packed-install journeys and Task 4 restart-recovery evidence (see
|
|
89
|
+
[`docs/0.1.0-readiness.md`](./0.1.0-readiness.md)).
|
|
90
|
+
|
|
91
|
+
## Release 0.0.28 enterprise auth, policy, MCP OAuth, API, and artifact adapters
|
|
92
|
+
|
|
93
|
+
`node scripts/benchmark-0.0.28.mjs` is network-free (in-process fake JWKS/OPA/API fetches plus loopback fixture servers for the authorization server, Prism MCP server, and S3-compatible object store). Checked `scripts/benchmark-0.0.28.json` (Node v24.18.0/Linux x64): 20 warmups, 100 measured ops per seam.
|
|
94
|
+
|
|
95
|
+
| Scenario | Recorded p95 ms | Ceiling |
|
|
96
|
+
| --- | ---: | ---: |
|
|
97
|
+
| OIDC verify (warm JWKS cache) | 0.178 | 5 |
|
|
98
|
+
| OIDC verify (TTL-expired JWKS refetch) | 0.366 | 100 |
|
|
99
|
+
| OPA policy decision (fake endpoint) | 0.063 | 100 |
|
|
100
|
+
| MCP OAuth discovery round trip | 2.196 | 250 |
|
|
101
|
+
| MCP OAuth interactive handshake (PKCE + token + authorized connect) | 6.359 | 2,000 |
|
|
102
|
+
| OpenAPI tool call (compiled operation, fake API) | 0.023 | 1,000 |
|
|
103
|
+
| Artifact 1 MiB body put (fake object store) | 11.810 | 2,000 |
|
|
104
|
+
| Artifact presign | 0.630 | 100 |
|
|
105
|
+
|
|
106
|
+
Conformance: `scripts/phase11-conformance.test.mjs` (5 network-free cases: composed OIDC → OPA ledger → MCP OAuth tool → OpenAPI side effect → artifact body + signed delivery, adapter-absent baseline, hostile origins and limit ladder, redaction sweep). Values are environment evidence, not universal SLOs.
|
|
107
|
+
|
|
9
108
|
## Release 0.0.25 durable loops and human-in-the-loop
|
|
10
109
|
|
|
11
110
|
`node scripts/benchmark-0.0.25.mjs` is network-free (in-memory checkpoint store). Checked `scripts/benchmark-0.0.25.json` (Node v24.18.0/Linux x64): 20 warmups, 100 measured ops, 32 pending decisions, ~250 KiB snapshot, 64 A2UI ops/message.
|
package/docs/policy-and-audit.md
CHANGED
|
@@ -117,6 +117,37 @@ Policy is optional. Hosts wire `record*` helpers or `evaluateAndAppend` at permi
|
|
|
117
117
|
- Evaluate/append are O(fields) and network-free in-package; remote WORM I/O stays in the host sink/adapter.
|
|
118
118
|
- Export never full-scans: page size is capped; raise hard caps only with Phase 8 freeze + tests + docs updates.
|
|
119
119
|
|
|
120
|
+
## OPA external policy adapter (`@arnilo/prism-policy/opa`, 0.0.28)
|
|
121
|
+
|
|
122
|
+
Optional `createOpaPolicyEvaluator` evaluates `PolicyEvaluateRequest`s against a host-pinned OPA REST endpoint (`POST /v1/data/<path>` with `{"input": <document>}`) and returns a core `PolicyEvaluator` for `evaluateAndAppend`. Native `fetch` only; no OPA SDK dependency.
|
|
123
|
+
|
|
124
|
+
| Option | Meaning |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `url` / `policyId` / `policyVersion` | Pinned decision URL + immutable ledger attribution |
|
|
127
|
+
| `mapInput` | Input builder (default: redacted actor refs — tenant/account/user/principal/sponsor/scopes + action + resource; never prompts, tool args, JWTs, or credentials; `context` omitted by design) |
|
|
128
|
+
| `mapDecision` | Decision mapper (default: boolean, `{allow}`, or `{outcome, reason?, evidenceRefs?, expiresAt?}`) |
|
|
129
|
+
| `onFailure` | `deny` (default) returns a recorded deny result on OPA failures; `escalate` rethrows the `PolicyError` |
|
|
130
|
+
| `requirePolicyVersion` | Sends `provenance=true` and requires a matching OPA bundle revision (stale/missing fails closed) |
|
|
131
|
+
| `timeoutMs` / `maxInputBytes` / `maxResponseBytes` / `maxRetries` | Bounded caps (2 s/30 s, 16/256 KiB, 64 KiB/1 MiB, 0/2 retries — only timeout/transport/5xx retried) |
|
|
132
|
+
| `redactor` | `SecretRedactor` applied to OPA-provided `reason`/`evidenceRefs` before they leave the adapter |
|
|
133
|
+
| `ssrf` | `SsrfPolicy` for the endpoint; denials surface `MediaContentError` (`ssrf_denied`) |
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import { createOpaPolicyEvaluator } from "@arnilo/prism-policy/opa";
|
|
137
|
+
import { createPostgresEnterpriseState } from "@arnilo/prism-enterprise-postgres";
|
|
138
|
+
import { evaluateAndAppend } from "@arnilo/prism-policy";
|
|
139
|
+
|
|
140
|
+
const evaluator = createOpaPolicyEvaluator({
|
|
141
|
+
url: "https://opa.internal:8181/v1/data/prism/allow",
|
|
142
|
+
policyId: "opa-prism",
|
|
143
|
+
policyVersion: "2026-08-01",
|
|
144
|
+
});
|
|
145
|
+
const state = await createPostgresEnterpriseState({ pool, schema: "prism" });
|
|
146
|
+
await evaluateAndAppend(request, { store: state.policy, evaluator, id: crypto.randomUUID() });
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Fail-closed codes: `ERR_PRISM_OPA_TIMEOUT`, `ERR_PRISM_OPA_TRANSPORT`, `ERR_PRISM_OPA_RESPONSE_PARSE`, `ERR_PRISM_OPA_RESPONSE_BOUNDS`, `ERR_PRISM_OPA_DECISION_MAPPING`, `ERR_PRISM_OPA_VERSION_MISMATCH`. Redirects are never followed; response bodies are read with a hard cap; caller aborts propagate (never converted to a policy outcome); timeout/parse/bounds/version failures record a deny row through `evaluateAndAppend`, so the durable Phase 6 ledger captures them unchanged.
|
|
150
|
+
|
|
120
151
|
## PostgreSQL enterprise state (0.0.23)
|
|
121
152
|
|
|
122
153
|
For durable multi-replica policy decisions, construct [`createPostgresEnterpriseState`](enterprise-postgres-state.md) and pass its `policy` store to the existing helpers. PostgreSQL keeps the same append/query contract, requires tenant scope and verified identity at append, binds owner data into opaque cursors, validates record bounds on read, and rejects duplicate ids. Memory and JSONL remain development/reference adapters, not production WORM or cross-replica stores.
|
package/docs/public-contracts.md
CHANGED
|
@@ -439,6 +439,53 @@ Phase 7 contracts: `AgentEventSource`, `ToolEffectDeclaration`/`ToolEffectStore`
|
|
|
439
439
|
- Use `unknown`/metadata fields for host data, but validate at trust boundaries before executing tools or loading resources.
|
|
440
440
|
- App-specific tool categories and business domains do not belong in public contracts.
|
|
441
441
|
|
|
442
|
+
## Frozen 0.1.x contract (plan 012 Task 7)
|
|
443
|
+
|
|
444
|
+
Release 0.1.0 freezes the public contract surface for the 0.1.x line. The
|
|
445
|
+
freeze is recorded in `scripts/phase12-freeze-manifest.json` and machine-checked
|
|
446
|
+
on every `npm test` by the release gates; this section states what is frozen.
|
|
447
|
+
|
|
448
|
+
**Declaration/exports surface.** Every publishable package's generated `.d.ts`
|
|
449
|
+
export surface is diffed against checked-in baselines in
|
|
450
|
+
`scripts/compat-baseline/` (one file per package, regenerated at 0.1.0). The
|
|
451
|
+
gate fails on any removed export or changed declaration and allows additive
|
|
452
|
+
exports only. **0.1.x patch promise:** additive-only declaration deltas vs the
|
|
453
|
+
0.1.0 baselines, enforced by `node scripts/release.mjs gate`; a genuine break
|
|
454
|
+
requires `--allow-break` plus a `docs/migration.md` entry naming the version.
|
|
455
|
+
|
|
456
|
+
**Events.** The `AgentEvent` union (`agent_*`/`artifact_*`/`tool_*` variants),
|
|
457
|
+
the durable `AgentEventRecord`/`DurableAgentEventRecord` shapes
|
|
458
|
+
(`turn_started`, `turn_finished`, `tool_execution_started`, `message_finished`;
|
|
459
|
+
run-scoped strictly increasing sequences; `redacted: true` on appends), and
|
|
460
|
+
`AgentEventSource` page/cursor semantics (opaque ownership-bound cursors,
|
|
461
|
+
terminal pages, at-least-once delivery) are frozen as shipped in 0.1.0. See
|
|
462
|
+
[docs/agent-events.md](agent-events.md).
|
|
463
|
+
|
|
464
|
+
**Protocol payloads.** AG-UI/A2UI surface state and operation payloads, ACP
|
|
465
|
+
(`@arnilo/prism-ag-ui/acp`) capability advertisement and session payloads,
|
|
466
|
+
MCP tool/resource/prompt payloads and OAuth discovery exchanges, A2A messages,
|
|
467
|
+
and provider request/response envelopes are frozen at the 0.1.0 pins recorded
|
|
468
|
+
in the freeze-manifest `support.protocol` table (`@agentclientprotocol/sdk`,
|
|
469
|
+
`@modelcontextprotocol/sdk`, A2A 1.0, AG-UI 0.4.x, OpenAPI 3.1 subset).
|
|
470
|
+
|
|
471
|
+
**Migration checksums.** The PostgreSQL persistence contract
|
|
472
|
+
(`createPersistenceMigrationContract`, 7 steps `001_init` …
|
|
473
|
+
`007_agent_event_retention_index`, sha256-checksummed rows in
|
|
474
|
+
`prism_migrations`) is frozen; `assertAppliedPersistenceMigrations` fails
|
|
475
|
+
closed on unknown history, incomplete legacy checksums, name mismatch, or
|
|
476
|
+
checksum mismatch. Enterprise state DDL (`enterprise-postgres`) is covered by
|
|
477
|
+
its own checksum contract. See [docs/database-persistence.md](database-persistence.md)
|
|
478
|
+
and [docs/migration.md](migration.md).
|
|
479
|
+
|
|
480
|
+
**Compatibility promise.** 0.1.x patch releases: additive exports only, no
|
|
481
|
+
schema migration steps, no default-behavior changes, no new runtime
|
|
482
|
+
dependencies, store compatibility maintained with 0.1.0 (persisted data
|
|
483
|
+
remains readable; no upgrade step required). 0.1.0 itself is store-compatible
|
|
484
|
+
with 0.0.28 (no migration) and the `0.0.17 → 0.1.0` upgrade matrix in
|
|
485
|
+
[docs/migration.md](migration.md) documents every intermediate line
|
|
486
|
+
(compatible / tested migration / tested refusal). The 1.x line may break the
|
|
487
|
+
0.1.x surface; any break ships with a migration-guide entry first.
|
|
488
|
+
|
|
442
489
|
## Related APIs
|
|
443
490
|
|
|
444
491
|
- [Input and prompt assembly](input-and-prompt-assembly.md): prompt template expansion and default input builder for strings, messages, history, attachments, resources, summaries, and tool results.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Prism is published as one core package, forty-one first-party capability packages, and six pure-manifest family/profile packages (**48** publishable manifests total). This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
|
|
6
6
|
|
|
7
|
-
Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism@0.0
|
|
7
|
+
Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism@0.1.0` peer; profiles are pure manifests. Installation activates no provider, listener, database, browser, credential, or tool capability.
|
|
8
8
|
|
|
9
9
|
Current **48** publishable manifests:
|
|
10
10
|
|
|
@@ -15,7 +15,7 @@ Current **48** publishable manifests:
|
|
|
15
15
|
`@arnilo/prism-provider-alibaba`, `@arnilo/prism-provider-anthropic`, `@arnilo/prism-provider-azure`, `@arnilo/prism-provider-bedrock`, `@arnilo/prism-provider-google`, `@arnilo/prism-provider-kimi`
|
|
16
16
|
`@arnilo/prism-provider-neuralwatt`, `@arnilo/prism-provider-ollama`, `@arnilo/prism-provider-openai`, `@arnilo/prism-provider-opencode-go`, `@arnilo/prism-provider-openrouter`, `@arnilo/prism-provider-vertex`
|
|
17
17
|
`@arnilo/prism-provider-zai`, `@arnilo/prism-rag`, `@arnilo/prism-server`, `@arnilo/prism-session-store-codecs`, `@arnilo/prism-session-store-nats`, `@arnilo/prism-session-store-postgres`, `@arnilo/prism-session-store-sqlite`
|
|
18
|
-
`@arnilo/prism-supervisor`, `@arnilo/prism-tool-validator-json-schema`, `@arnilo/prism-web-tools`, `@arnilo/prism-work-tools`, `@arnilo/prism-workflows`
|
|
18
|
+
`@arnilo/prism-openapi-tools`, `@arnilo/prism-supervisor`, `@arnilo/prism-tool-validator-json-schema`, `@arnilo/prism-web-tools`, `@arnilo/prism-work-tools`, `@arnilo/prism-workflows`
|
|
19
19
|
|
|
20
20
|
Core ships `dist`, docs, templates, and `CHANGELOG.md`; code packages ship compiled output, README, license, and changelog. Family/profile packages ship manifest, README, and changelog. `@arnilo/prism-providers` includes all eleven `@arnilo/prism-provider-*` packages.
|
|
21
21
|
|
|
@@ -45,9 +45,9 @@ Consumers install the core package for the runtime and add first-party packages
|
|
|
45
45
|
| Run the default (network-free) test suite | `npm test` |
|
|
46
46
|
| Dry-run pack core + every package | `npm run pack:dry-run` |
|
|
47
47
|
| Local mirror of the release verify gate | `npm run release:dry-run` |
|
|
48
|
-
| Validate clean tag/version/ranges and reject registry collisions | `npm run release:check -- --version 0.0
|
|
49
|
-
| Preview deterministic publish order | `npm run release:publish -- --version 0.0
|
|
50
|
-
| Resume interrupted tagged publication | `npm run release:publish -- --version 0.0
|
|
48
|
+
| Validate clean tag/version/ranges and reject registry collisions | `npm run release:check -- --version 0.1.0` |
|
|
49
|
+
| Preview deterministic publish order | `npm run release:publish -- --version 0.1.0 --dry-run --allow-dirty --allow-untagged` |
|
|
50
|
+
| Resume interrupted tagged publication | `npm run release:publish -- --version 0.1.0 --resume --report release-artifacts/publish-report.json` |
|
|
51
51
|
| Protected PostgreSQL enterprise suite | `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres` |
|
|
52
52
|
| Full SDK readiness gate (typecheck + offline tests + pack) | `npm run sdk:ready` |
|
|
53
53
|
|
|
@@ -87,7 +87,7 @@ A packed tarball contains only public compiled output and release files:
|
|
|
87
87
|
- Code packages ship `README.md`, `LICENSE`, and `CHANGELOG.md`; family/profile packages ship `README.md` and `CHANGELOG.md`.
|
|
88
88
|
- The core tarball additionally ships the full `docs/` directory (the docs hub) and `templates/init/` used by `prism init`.
|
|
89
89
|
- `dist/cli.js` and the `bin` link in core.
|
|
90
|
-
- **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.0.
|
|
90
|
+
- **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.1.0.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.1.0.tgz` / `arnilo-prism-compaction-<name>-0.1.0.tgz` / `arnilo-prism-coding-agent-0.1.0.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.1.0.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
|
|
91
91
|
|
|
92
92
|
Excluded from every tarball by `files` negation:
|
|
93
93
|
|
|
@@ -106,9 +106,9 @@ Excluded from every tarball by `files` negation:
|
|
|
106
106
|
"name": "host-app",
|
|
107
107
|
"type": "module",
|
|
108
108
|
"dependencies": {
|
|
109
|
-
"@arnilo/prism": "0.0
|
|
110
|
-
"@arnilo/prism-enterprise-postgres": "0.0
|
|
111
|
-
"@arnilo/prism-provider-openai": "0.0
|
|
109
|
+
"@arnilo/prism": "0.1.0",
|
|
110
|
+
"@arnilo/prism-enterprise-postgres": "0.1.0",
|
|
111
|
+
"@arnilo/prism-provider-openai": "0.1.0"
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
```
|
|
@@ -151,11 +151,11 @@ For SDK readiness, run the same one-command gate directly. It composes existing
|
|
|
151
151
|
npm run sdk:ready
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
Release publication derives all **48** manifests from the workspace once, validates exact `0.0
|
|
154
|
+
Release publication derives all **48** manifests from the workspace once, validates exact `0.1.0` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.1.0` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag, but does not publish.
|
|
155
155
|
|
|
156
156
|
```bash
|
|
157
|
-
npm run release:check -- --version 0.0
|
|
158
|
-
npm run release:publish -- --version 0.0
|
|
157
|
+
npm run release:check -- --version 0.1.0
|
|
158
|
+
npm run release:publish -- --version 0.1.0 --dry-run --allow-dirty --allow-untagged
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
`--allow-dirty` and `--allow-untagged` exist only for local preview; real publication and CI never pass them. npm registry calls occur only in these release preflight/publication commands, never build/test/package discovery.
|
|
@@ -168,7 +168,62 @@ PRISM_LIVE_PROVIDER_TESTS=1 npm run test --workspaces --if-present
|
|
|
168
168
|
|
|
169
169
|
### GitHub Actions pipeline (0.0.27+)
|
|
170
170
|
|
|
171
|
-
`.github/workflows/release.yml` is the single pipeline: **push to `main`** runs CI (`verify` = `npm run sdk:ready`, `node20-compat`, `postgres-integration`, `supply-chain`), **push of a `v*` tag** additionally runs `codeql-release` and the `publish` job (deterministic `release:publish` in dependency order with provenance attestation). `security.yml` adds CodeQL/dependency-review/SBOM on push and PR; `live-canaries.yml` and `sandbox-browser.yml` are scheduled. All actions are SHA-pinned (2026-08-06 fix: CodeQL pins were invalid 404 refs and `workflow_dispatch` was missing — re-verified every pin against its upstream repo). Prerequisites outside the repo: Actions enabled in repository settings, and the `NPM_TOKEN` secret (with `id-token: write` for provenance). To re-cut a tag after a fix commit, delete and recreate it (`git push origin :v0.0.
|
|
171
|
+
`.github/workflows/release.yml` is the single pipeline: **push to `main`** runs CI (`verify` = `npm run sdk:ready`, `node20-compat`, `postgres-integration`, `supply-chain`), **push of a `v*` tag** additionally runs `codeql-release` and the `publish` job (deterministic `release:publish` in dependency order with provenance attestation). `security.yml` adds CodeQL/dependency-review/SBOM on push and PR; `live-canaries.yml` and `sandbox-browser.yml` are scheduled. All actions are SHA-pinned (2026-08-06 fix: CodeQL pins were invalid 404 refs and `workflow_dispatch` was missing — re-verified every pin against its upstream repo). Prerequisites outside the repo: Actions enabled in repository settings, and the `NPM_TOKEN` secret (with `id-token: write` for provenance). To re-cut a tag after a fix commit, delete and recreate it (`git push origin :v0.0.28 && git push origin v0.0.28`) so the tag creation event fires.
|
|
172
|
+
|
|
173
|
+
### 0.1.0 publish handoff (plan 012 Task 7)
|
|
174
|
+
|
|
175
|
+
**Decision: GO when the operator prerequisites below are recorded.** Release **0.1.0** (Phase 12, plan 012) is the release-candidate hardening cut of the **0.0.28** graph: no new packages, public exports, schema migrations, or runtime dependencies (freeze manifest `scripts/phase12-freeze-manifest.json`). Publishable graph stays **48** manifests at exact **0.1.0**. Store compatibility with 0.0.28: **compatible, no migration** ([migration](migration.md) `0.0.28 → 0.1.0`); the full `0.0.17 → 0.1.0` upgrade matrix is in the same page. All evidence for the tree under publication is recorded in [0.1.0 readiness](0.1.0-readiness.md) (capacity envelopes, restart-recovery, e2e journeys, threat-suites leg, audit at moderate).
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# Operator prerequisites (each a named blocked gate — none may be skipped):
|
|
179
|
+
# 1. protected live-canary matrix green (live-canaries.yml, canary-report.json retained)
|
|
180
|
+
# 2. PostgreSQL + keychain protected suites green (test:postgres, keychain suite)
|
|
181
|
+
# 3. CodeQL SAST green on the release commit (security.yml / release.yml codeql-release)
|
|
182
|
+
# 4. npm OIDC trusted publishing identity authenticated (NPM_TOKEN with id-token, provenance)
|
|
183
|
+
|
|
184
|
+
git diff --check
|
|
185
|
+
npm ci
|
|
186
|
+
npm run sdk:ready # includes typecheck, lint, format, full test, coverage, pack, release:gate
|
|
187
|
+
npm run security:threat-suites
|
|
188
|
+
PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres # Phase 7 + Phase 12 restart-recovery
|
|
189
|
+
node --test scripts/benchmark-0.1.0.test.mjs # frozen 0.1.0 capacity envelope contract
|
|
190
|
+
node scripts/scan-secrets.mjs && node scripts/verify-sbom.mjs
|
|
191
|
+
npm audit --audit-level=moderate
|
|
192
|
+
npm run release:check -- --version 0.1.0 --report /tmp/prism-0.1.0-preflight.json
|
|
193
|
+
npm run release:publish -- --version 0.1.0 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.1.0-dry-run.json
|
|
194
|
+
# run the dry-run twice and diff the reports: deterministic, byte-identical
|
|
195
|
+
|
|
196
|
+
# Sign the release on the clean tagged tree (operator GPG key):
|
|
197
|
+
git tag -s v0.1.0 -m "Prism 0.1.0"
|
|
198
|
+
git verify-tag v0.1.0
|
|
199
|
+
git push origin v0.1.0 # tag push triggers release.yml publish job (provenance, attestations)
|
|
200
|
+
|
|
201
|
+
# Real publication never bypasses the gates: release.mjs refuses
|
|
202
|
+
# --allow-dirty/--allow-untagged without --dry-run.
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Rollback notes.** `release:publish --version 0.1.0 --resume --report release-artifacts/publish-report.json` resumes an interrupted publication and skips only registry versions whose internal dependency fingerprint matches the local manifest. A failed package aborts the run with its status written to the report; re-run after fixing the cause. npm cannot unpublish the `0.1.0` line after 72 hours — a post-publication defect ships as a `0.1.x` patch (additive-only compat promise, `release:gate` enforced), or as a documented break in the next line with a `docs/migration.md` entry. `0.1.0` is store-compatible with `0.0.28` in both directions (no migration ran), so an operator may defer adoption of `0.1.0` without a database rollback.
|
|
206
|
+
|
|
207
|
+
### 0.0.28 publish handoff (historical)
|
|
208
|
+
|
|
209
|
+
**Decision: GO after protected operator prerequisites below.** Release **0.0.28** (Phase 11, plan 011) ships the optional enterprise adapter seams: OIDC/JWKS identity verification (`@arnilo/prism-credentials-node/oidc`), OPA policy evaluation into the durable ledger (`@arnilo/prism-policy/opa`), MCP OAuth client/server support (`@arnilo/prism-mcp`), host-selected OpenAPI operations as effect-gated tools (`@arnilo/prism-openapi-tools`), and an S3-compatible artifact body store behind the new core body contract (`@arnilo/prism-server/artifact-bodies`). Every seam is opt-in and fail-closed; hosts that wire none keep exact prior behavior. Publishable graph stays **48** manifests. See [migration](migration.md) `0.0.27 → 0.0.28`.
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
git diff --check
|
|
213
|
+
npm ci
|
|
214
|
+
npm run sdk:ready
|
|
215
|
+
node --test scripts/phase11-conformance.test.mjs
|
|
216
|
+
node scripts/benchmark-0.0.28.mjs > scripts/benchmark-0.0.28.json
|
|
217
|
+
node --test scripts/budget-gate.test.mjs scripts/tooling-gate.test.mjs
|
|
218
|
+
node scripts/scan-secrets.mjs && node scripts/verify-sbom.mjs
|
|
219
|
+
npm audit --audit-level=moderate
|
|
220
|
+
npm run release:gate -- --version 0.0.28 --allow-break --allow-dirty --allow-untagged
|
|
221
|
+
npm run release:check -- --version 0.0.28 --allow-dirty --allow-untagged --report /tmp/prism-0.0.28-preflight.json
|
|
222
|
+
npm run release:publish -- --version 0.0.28 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.0.28-dry-run.json
|
|
223
|
+
git tag -s v0.0.28 -m "Prism 0.0.28"
|
|
224
|
+
git verify-tag v0.0.28
|
|
225
|
+
git push origin v0.0.28
|
|
226
|
+
```
|
|
172
227
|
|
|
173
228
|
### 0.0.27 publish handoff
|
|
174
229
|
|
|
@@ -260,6 +315,27 @@ git push origin v0.0.22
|
|
|
260
315
|
|
|
261
316
|
Release-specific migration detail lives in [migration](migration.md). The current handoff plus the retained protected matrix below supersede 0.0.16–0.0.21 command transcripts.
|
|
262
317
|
|
|
318
|
+
### Release-integrity evidence matrix (0.0.18 → 0.1.0)
|
|
319
|
+
|
|
320
|
+
Phase 12 Task 2 (plan 012) closes roadmap defect #4: every release from 0.0.18 onward has a signed tag or a **documented publication-evidence pointer**. Tags below were created as lightweight refs (no GPG signature was available in this environment); each release therefore carries a documented evidence pointer: the roadmap phase completion evidence, benchmark JSON, conformance suite, and/or migration section that records what shipped. The 0.1.0 cut requires the **signed** tag + provenance publication procedure (operator action, see [0.1.0 readiness](0.1.0-readiness.md) "Remaining for 1.0").
|
|
321
|
+
|
|
322
|
+
| Release | Tag | Evidence pointer |
|
|
323
|
+
| --- | --- | --- |
|
|
324
|
+
| 0.0.18 | `v0.0.18` (lightweight, at `f627752`) | Roadmap Phase 1 completion evidence; `docs/migration.md` `0.0.17 → 0.0.18`; docs tripwire Phase 1 |
|
|
325
|
+
| 0.0.19 | `v0.0.19` (lightweight, at `7574e50`) | Roadmap Phase 2 completion evidence; migration `0.0.18 → 0.0.19` |
|
|
326
|
+
| 0.0.20 | `v0.0.20` (lightweight, at `b2cdb2e`) | Roadmap Phase 3 completion evidence; migration `0.0.19 → 0.0.20` |
|
|
327
|
+
| 0.0.21 | **no tag** | Roadmap Phase 4 completion evidence (workspace 0.0.21 / 44 manifests, sdk:ready green); migration `0.0.20 → 0.0.21` |
|
|
328
|
+
| 0.0.22 | `v0.0.22` (lightweight, at `f9902ed`) | Roadmap Phase 5 completion evidence; 0.0.22 publish handoff above; migration `0.0.21 → 0.0.22` |
|
|
329
|
+
| 0.0.23 | `v0.0.23` (lightweight, at `1401b6b`) | Roadmap Phase 6 completion evidence; 0.0.23 publish handoff above; `scripts/benchmark-0.0.23.json`; migration `0.0.22 → 0.0.23` |
|
|
330
|
+
| 0.0.24 | `v0.0.24` (lightweight, at `55c4b0e`) | Roadmap Phase 7 completion evidence; 0.0.24 publish handoff above; `scripts/benchmark-0.0.24.json`; `scripts/phase7-conformance.test.mjs`; migration `0.0.23 → 0.0.24` |
|
|
331
|
+
| 0.0.25 | `v0.0.25` (lightweight, at `24d7ac0`) | Roadmap Phase 8 completion evidence; `scripts/benchmark-0.0.25.json`; `scripts/phase8-conformance.test.mjs`; migration `0.0.24 → 0.0.25` |
|
|
332
|
+
| 0.0.26 | `v0.0.26` (lightweight, at `77fac7e`) | Roadmap Phase 9 completion evidence; `scripts/benchmark-0.0.26.json`; `scripts/phase9-conformance.test.mjs`; migration `0.0.25 → 0.0.26` |
|
|
333
|
+
| 0.0.27 | `v0.0.27` (lightweight, at `9d49625`) | Roadmap Phase 10 completion evidence; `scripts/benchmark-0.0.27.json`; `scripts/phase10-conformance.test.mjs`; migration `0.0.26 → 0.0.27` |
|
|
334
|
+
| 0.0.28 | **no tag (HEAD is 0.0.28 scope)** | Roadmap Phase 11 completion evidence; 0.0.28 publish handoff above; `scripts/benchmark-0.0.28.json`; `scripts/phase11-conformance.test.mjs`; migration `0.0.27 → 0.0.28` |
|
|
335
|
+
| 0.1.0 | `v0.1.0` **signed** (operator action at publication) | Phase 12 plan 012 records; `node scripts/release.mjs publish --version 0.1.0 --dry-run --allow-untagged` semantics verified (dry-run proceeds untagged; real publication refuses `--allow-untagged`/`--allow-dirty`) |
|
|
336
|
+
|
|
337
|
+
Machine check: `git tag --points-at <commit>` and the roadmap phase completion blocks above are the evidence trail; `node scripts/release.mjs check --version 0.1.0` validates the exact version graph at bump time (plan 012 Task 7).
|
|
338
|
+
|
|
263
339
|
### 0.0.15 protected live-canary matrix
|
|
264
340
|
|
|
265
341
|
Default `npm test`, `npm run sdk:ready`, and `benchmark-0.0.15` are network-free. Run live rows only from a protected scheduled/release environment (or an explicitly authorized operator workstation); never place credentials in fixtures, benchmark JSON, pull-request jobs, or package scripts. Use least-privilege keys, one bounded request, and retain only redacted aggregate status. A blank **checked-in gate** means Prism deliberately has no generic credential fixture: host owns that provider/account compatibility probe.
|
|
@@ -286,9 +362,46 @@ The scheduled/manual `live-canaries` workflow uses protected environment `live-c
|
|
|
286
362
|
|
|
287
363
|
Older 0.0.10–0.0.15 handoffs are summarized in [migration](migration.md); historical 43-package evidence remains there. The publishable package catalog includes `@arnilo/prism-provider-alibaba`, `@arnilo/prism-provider-ollama`, and `@arnilo/prism-session-store-codecs`; current publication uses the 47-manifest handoff above.
|
|
288
364
|
|
|
365
|
+
## 0.1.x compatibility and support matrix
|
|
366
|
+
|
|
367
|
+
Frozen by Phase 12 Task 0 in `scripts/phase12-freeze-manifest.json` (schema gate `node --test scripts/phase12-freeze.test.mjs`; docs agreement tripwired in the docs test suite). Any change requires a recorded freeze deviation in plan 012.
|
|
368
|
+
|
|
369
|
+
### Supported and measured
|
|
370
|
+
|
|
371
|
+
| Dimension | Supported | Measured evidence |
|
|
372
|
+
| --- | --- | --- |
|
|
373
|
+
| Node | 20, 24 (`engines.node >=20`) | `release.yml`: `verify` runs SDK readiness on Node 24; `node20-compat` builds and imports every public root export on Node 20. Docs examples need Node >=22.6 native TypeScript stripping. Node 22 is engines-supported but not measured in CI at freeze. |
|
|
374
|
+
| PostgreSQL | 16 | `release.yml` `postgres-integration` job with image `pgvector/pgvector:pg16`; driver `pg@^8.22.0`; schema version 6. The pgvector extension is required only by the `@arnilo/prism-memory` path. Range claims beyond 16 need an added protected leg before they may be documented. |
|
|
375
|
+
| Platform | linux-x64 | Every CI leg runs on `ubuntu-latest` (x64). All other OS/arch combinations are untested: run `npm run sdk:ready` on the target platform before production adoption. |
|
|
376
|
+
| Providers | every published `@arnilo/prism-provider-*` plus the OpenAI-compatible transport | Per-package conformance suites in the default network-free `npm test`; live canaries stay credential-gated (`PRISM_LIVE_PROVIDER_TESTS=1`). |
|
|
377
|
+
| Protocol SDKs | exact pins below | MCP 38-test suite, AG-UI/ACP/A2A protocol conformance, NATS JetStream event-source conformance. |
|
|
378
|
+
|
|
379
|
+
| Package | Frozen pin |
|
|
380
|
+
| --- | --- |
|
|
381
|
+
| `@modelcontextprotocol/sdk` | `1.30.0` |
|
|
382
|
+
| `@agentclientprotocol/sdk` | `1.3.0` |
|
|
383
|
+
| `@ag-ui/core` | `0.0.57` |
|
|
384
|
+
| `@nats-io/jetstream` | `^3.4.0` |
|
|
385
|
+
| `@nats-io/transport-node` | `^3.4.0` |
|
|
386
|
+
|
|
387
|
+
### Unsupported combinations
|
|
388
|
+
|
|
389
|
+
- Node below 20 (engines floor).
|
|
390
|
+
- PostgreSQL server majors outside the supported list (only 16 measured at freeze).
|
|
391
|
+
- ACP v2 experimental APIs — stable v1 only.
|
|
392
|
+
- Cedar policy engine — OPA adapter only.
|
|
393
|
+
- Redis/Kafka queues or backplanes — PostgreSQL and NATS JetStream event sources only.
|
|
394
|
+
- Forges beyond GitHub.
|
|
395
|
+
- Object stores beyond the S3-compatible reference adapter.
|
|
396
|
+
- Remote-browser vendors, hosted cloud, Studio/control plane, and channel catalogs (Phase 13 demand-gated).
|
|
397
|
+
|
|
398
|
+
### Security-support boundary
|
|
399
|
+
|
|
400
|
+
Audit fixes, dependency updates, and security patches land only for the supported lines above. The 0.1.0 audit target is moderate-or-higher (`releasePolicy.auditLevelTarget` in the freeze manifest); since plan 012 Task 6 both `security.yml` and the `release.yml` supply-chain job enforce `npm audit --audit-level=moderate` (0 vulnerabilities at every severity recorded for the 0.1.0 tree). Unsupported combinations receive no fixes. Supply-chain gates are listed in [host security](host-security.md).
|
|
401
|
+
|
|
289
402
|
## Extension and configuration notes
|
|
290
403
|
|
|
291
|
-
- **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional `@arnilo/prism@0.0.
|
|
404
|
+
- **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional `@arnilo/prism@0.0.28` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). The range stays pinned to `0.0.28` for the current 0.x release and will widen to `^1.0.0` at the 1.x stable release. Inside the workspace each package also declares `"@arnilo/prism": "file:../.."` in `devDependencies` so `npm install` resolves the peer locally; that devDependency is stripped from consumer installs and is not a runtime dependency.
|
|
292
405
|
- **Public access.** All 48 manifests (42 code packages + 6 family/profile packages) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
|
|
293
406
|
- **Map retention knob.** Source maps are emitted locally but stripped from tarballs by `!dist/**/*.map`. Removing that `files` negation ships maps in releases (larger tarballs, better consumer stack traces).
|
|
294
407
|
- **Release workflow.** `.github/workflows/release.yml` has six jobs. `verify` runs network-free SDK readiness on Node 24; `node20-compat` builds/imports every public root `exports` default target on Node 20 for declared `engines.node >=20` (docs examples need Node >=22.6 native TypeScript stripping); `postgres-integration` uses `pgvector/pgvector:pg16`; `supply-chain` runs high-severity audit, SPDX/license policy, and tracked-source secret scanning; and tag-only `codeql-release` runs SAST. Tag-only `publish` needs all five gates, preserves clean exact-tag/version/topological publication, and alone receives `NPM_TOKEN`, `id-token: write`, and `attestations: write`. Before npm publish it packs all current tarballs, generates checksums plus SPDX, scans unpacked public artifacts, creates GitHub attestations for tarballs and SBOM, then retains artifacts for 30 days. Registry state remains the resumable journal. Local `npm run release:dry-run` remains network-free SDK readiness; local PostgreSQL coverage is `PRISM_TEST_POSTGRES_URL=... npm run test:postgres`.
|
|
@@ -319,6 +432,8 @@ Older 0.0.10–0.0.15 handoffs are summarized in [migration](migration.md); hist
|
|
|
319
432
|
- **Sandbox/browser protected workflow.** `.github/workflows/sandbox-browser.yml` is scheduled/manual only in protected `sandbox-browser` environment. It runs network-free adversarial eval fixtures by default, optionally enables digest-pinned Docker and Playwright gates via repository variables (`PRISM_TEST_DOCKER_IMAGE`, `PRISM_ENABLE_PLAYWRIGHT_GATE`), receives no provider/npm/OIDC secrets, and uploads only a redacted aggregate status artifact (7-day retention).
|
|
320
433
|
- **Release attestations.** Tag publication uses GitHub OIDC with only `contents: read`, `id-token: write`, and `attestations: write` at the publish job. `actions/attest-build-provenance` attests every `.tgz` and `sbom.spdx.json` before npm publication; npm still receives `--provenance`. Verify downloaded attestations with GitHub CLI and npm signatures on the release host.
|
|
321
434
|
- **Install smoke is offline.** The install-smoke test packs core + every package into a temp dir and installs tarballs with `--offline --no-audit --no-fund` into a fresh project. External dependencies are satisfied from the lockfile-backed npm cache prepared by `npm ci`; any attempted uncached registry fetch fails the gate.
|
|
435
|
+
- **Packed-install e2e journeys (plan 012 Task 3).** `scripts/e2e-enterprise-journey.test.mjs` and `scripts/e2e-coding-journey.test.mjs` pack the first-party packages for their journey, install the exact tarballs into a fresh consumer project, and run the journey script inside that consumer — public exports only, no workspace-relative resolution (asserted per run). The **enterprise journey** composes OIDC identity → OPA policy decision (durable ledger) → agent run with durable events (memory, or real PostgreSQL when `PRISM_TEST_POSTGRES_URL` is set) → batched approval → OpenAPI side effect with idempotency → artifact upload + signed delivery, with policy-deny and hash-mismatch fail-closed injections. The **coding journey** composes an 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 with idempotent PR creation, with execution-policy and read-before-write denial paths. Each fixture asserts the installed version matches the packed manifest graph and stays within the frozen `e2eJourneyFixtureMsCeiling` (120 s in `scripts/phase12-freeze-manifest.json`).
|
|
436
|
+
- **Protected restart-recovery leg (plan 012 Task 4).** `scripts/phase12-restart-recovery.test.mjs` (run by `npm run test:postgres` after the Phase 7 suite) spawns two real processes against one PostgreSQL schema: replica A runs a durable agent, suspends on a batched tool approval, appends durable events and is then SIGKILLed by the driver; replica B reconnects and resumes. Operators re-run the leg with `PRISM_TEST_POSTGRES_URL="postgresql://…" npm run test:postgres` against a disposable PostgreSQL 16 (e.g. `pgvector/pgvector:pg16`). Without the URL the gate records a named `BLOCKED GATE` failure instead of skipping. Reconnect p95 and 16-worker append contention p95 are asserted against the frozen `reconnectP95Ms` / `pointOpP95Ms` ceilings; set `PRISM_PHASE12_RECORD_EVIDENCE=1` to refresh the checked-in evidence file `scripts/phase12-restart-recovery.json`.
|
|
322
437
|
- **Offline test budget.** The default `npm test` (no `PRISM_LIVE_PROVIDER_TESTS`) is pinned at **< 60s on Node 20** with a measured local baseline of ~45s (build ~18s + network-free tests/workspace tests/packaging smoke ~27s). The full CI `sdk:ready` gate runs on Node 24 because docs tests execute `examples/*.ts` via native TypeScript stripping. `npm run sdk:ready` also runs typecheck and pack dry-run, so it is allowed to exceed the `npm test` budget while remaining network-free. The CI `sdk:ready` step has `timeout-minutes: 5` as a hang backstop; the separate Node 20 compatibility step has `timeout-minutes: 3`. The budget was raised from 30s after the default suite grew to include every first-party package, offline install smoke, packaging guards, docs examples, and workspace tests; optimize before raising it again.
|
|
323
438
|
|
|
324
439
|
### 0.0.12 release-candidate verification — 2026-07-22
|
package/docs/tools.md
CHANGED
|
@@ -257,6 +257,7 @@ createJsonSchemaToolArgumentValidator({
|
|
|
257
257
|
|
|
258
258
|
## Related APIs
|
|
259
259
|
|
|
260
|
+
- [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).
|
|
260
261
|
- [Agent/session runtime](agent-session-runtime.md): dispatches complete provider tool calls through the host-active tool harness and returns tool results on the next provider turn.
|
|
261
262
|
- [Public contracts](public-contracts.md): `ToolDefinition`, `ToolRegistry`, `ToolExecutionContext`, `ToolResult`, and tool `AgentEvent` contracts.
|
|
262
263
|
- [Contribution registries](contribution-registries.md): inert extension/package tool contribution storage.
|
|
@@ -79,6 +79,8 @@ export const handler = createArtifactHandler({ service: artifacts, authorize: ho
|
|
|
79
79
|
- Artifact records are versioned checkpoint values (namespace `prism.artifact`, key `threadId:artifactId`). The checkpoint `version` is the CAS counter for concurrent reviewers, distinct from revision numbers. Any `CheckpointStore` works; sqlite/postgres persistence already expose `.checkpoints`, so there is no separate artifact schema or migration.
|
|
80
80
|
- `createArtifactHandler` mounts attach/list/get/revise/compare/approve/reject/last-validated/delivery-link plus `GET /prism/artifacts/download?link=…`. Download verifies the link signature + expiry, then **reauthorizes** against the token's ownership (mismatch fails closed), and returns the authorized revision reference only — the host fetches the body.
|
|
81
81
|
- Delivery links are `base64url(payload).base64url(HMAC-SHA256)` over `{ artifactId, threadId, version, ownership, issuedAt, expiresAt }`; they are reauthorized per download and are not bearer secrets.
|
|
82
|
+
- **Blob storage (0.0.28)**: `createArtifactService` accepts an optional `bodies: ArtifactBodyStore` (core contract in `src/artifacts.ts`: `put`/`get`/`delete`/`presign` by opaque, ownership-scoped `ArtifactBodyRef`). When wired, `deliveryLink` resolves through `bodies.presign` and returns an additional `url` (bounded-TTL, single-object presigned URL) beside the signed link/token; revisions must carry a recorded `size` (optional on attach/revise) or delivery fails closed. The reference adapter is `@arnilo/prism-server/artifact-bodies` `createS3ArtifactBodyStore` (hand-rolled SigV4 over native fetch + WebCrypto, path-style, single-chunk PUT with verified `x-amz-content-sha256`; works with AWS S3, MinIO, Cloudflare R2). Hosts may substitute any store; the contract is storage-free in core.
|
|
83
|
+
- Body stores verify ownership on every operation, verify size/SHA-256/MIME on put and get (fail closed), refuse delete under legal hold (host `isHeld` callback), and are idempotent on delete (retention sweeps delete bodies with metadata). Credentials come only from the host resolver; bucket/path/key never appear in errors, telemetry, or artifact records (the object key is derived from the ref).
|
|
82
84
|
- Review loops driven by an agent consume the shared `RunLimits` at the host's agent layer; the artifact service itself is a passive, bounded record store.
|
|
83
85
|
|
|
84
86
|
## Security and performance notes
|
|
@@ -87,7 +89,7 @@ export const handler = createArtifactHandler({ service: artifacts, authorize: ho
|
|
|
87
89
|
- Concurrent reviewer conflicts resolve via checkpoint CAS (`expectedVersion`); the loser gets a retryable `conflict` and no approval is lost or duplicated. A throw before commit persists nothing, so failed updates roll back.
|
|
88
90
|
- Local filesystem paths are rejected in `uri`/citations (`file:`, absolute, or drive paths); records are redacted before persist and on response, so paths/secrets/document-private data never enter records, events, or exports.
|
|
89
91
|
- Frozen caps (default / hard): artifacts per thread 64/256; revisions per artifact 32/128; record 8/64 KiB; preview 16/64 KiB; citations 32/128 and 2/8 KiB each; MIME 128/512 B; hash 256/1 KiB; compare exactly 2 revisions; delivery TTL 5 min/24 h; delivery token 4/16 KiB. Raising the revision cap may require raising `recordBytes` (aggregate backstop).
|
|
90
|
-
- Compare is hash+metadata-bounded (hosts render content); no file bodies are persisted or transferred.
|
|
92
|
+
- Compare is hash+metadata-bounded (hosts render content); no file bodies are persisted or transferred. With a wired body store, bodies live in the host's object store and are streamed through the adapter (bounded by `maxBodyBytes` 64 MiB/512 MiB, concurrent transfers 4/16, presign TTL 10 min/24 h); object-store outages surface typed `ERR_PRISM_S3_*` / `ERR_PRISM_ARTIFACT_BODY_*` errors, never silent success.
|
|
91
93
|
|
|
92
94
|
## Related APIs
|
|
93
95
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arnilo/prism",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Agent harness for AI providers, agents, sessions, and tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -141,18 +141,19 @@
|
|
|
141
141
|
"clean": "rm -rf dist packages/*/dist",
|
|
142
142
|
"build": "npm run clean && npm run build:core && npm run build --workspaces --if-present",
|
|
143
143
|
"typecheck": "npm run build && npm run typecheck --workspaces --if-present && tsc -p examples --noEmit",
|
|
144
|
-
"test": "npm run build && node --test dist/__tests__/*.test.js && node --test scripts/release-gate.test.mjs scripts/tooling-gate.test.mjs scripts/budget-gate.test.mjs scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs && npm run test --workspaces --if-present",
|
|
144
|
+
"test": "npm run build && node --test dist/__tests__/*.test.js && node --test scripts/release-gate.test.mjs scripts/tooling-gate.test.mjs scripts/budget-gate.test.mjs scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs scripts/phase11-freeze.test.mjs scripts/phase12-freeze.test.mjs scripts/benchmark-0.1.0.test.mjs scripts/e2e-enterprise-journey.test.mjs scripts/e2e-coding-journey.test.mjs && npm run test --workspaces --if-present",
|
|
145
145
|
"test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=60 --test-coverage-functions=70 --test-coverage-branches=75 --test-coverage-exclude='**/__tests__/**' --test-coverage-exclude='**/node_modules/**' --test-coverage-exclude='**/scripts/**' --test-coverage-exclude='**/packages/**' --test-coverage-exclude='**/examples/**' dist/__tests__/*.test.js",
|
|
146
146
|
"lint": "biome lint .",
|
|
147
147
|
"format": "biome format --write .",
|
|
148
148
|
"format:check": "biome format .",
|
|
149
149
|
"pack:dry-run": "npm pack --dry-run && npm run pack:dry-run --workspaces --if-present",
|
|
150
|
-
"test:postgres": "node scripts/require-postgres-url.mjs && npm run test:postgres --workspace @arnilo/prism-session-store-postgres && npm run test:postgres --workspace @arnilo/prism-memory && npm run test:postgres --workspace @arnilo/prism-enterprise-postgres && node --test scripts/phase7-conformance.test.mjs",
|
|
150
|
+
"test:postgres": "node scripts/require-postgres-url.mjs && npm run test:postgres --workspace @arnilo/prism-session-store-postgres && npm run test:postgres --workspace @arnilo/prism-memory && npm run test:postgres --workspace @arnilo/prism-enterprise-postgres && node --test scripts/phase7-conformance.test.mjs scripts/phase12-restart-recovery.test.mjs",
|
|
151
151
|
"release:dry-run": "npm run sdk:ready",
|
|
152
152
|
"release:check": "node scripts/release.mjs check",
|
|
153
153
|
"release:publish": "node scripts/release.mjs publish",
|
|
154
154
|
"sdk:ready": "npm run typecheck && npm run lint && npm run format:check && npm test && npm run test:coverage && npm run pack:dry-run && npm run release:gate",
|
|
155
|
-
"release:gate": "node scripts/release.mjs gate"
|
|
155
|
+
"release:gate": "node scripts/release.mjs gate",
|
|
156
|
+
"security:threat-suites": "node --test scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs"
|
|
156
157
|
},
|
|
157
158
|
"devDependencies": {
|
|
158
159
|
"@biomejs/biome": "^2.5.5",
|