@arnilo/prism 0.6.0 → 0.8.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.
Files changed (178) hide show
  1. package/CHANGELOG.md +79 -5
  2. package/README.md +12 -11
  3. package/dist/agent-approval.d.ts +4 -0
  4. package/dist/agent-approval.js +5 -1
  5. package/dist/agent-definitions.js +1 -0
  6. package/dist/agent-run-lifecycle.js +39 -4
  7. package/dist/agent-run-state.d.ts +18 -0
  8. package/dist/agent-run-state.js +39 -9
  9. package/dist/agent-session/helpers.js +6 -1
  10. package/dist/agent-session/session/assemble.js +159 -7
  11. package/dist/agent-session/session/persist.d.ts +16 -0
  12. package/dist/agent-session/session/persist.js +64 -4
  13. package/dist/agent-session/session/provider-round.d.ts +3 -3
  14. package/dist/agent-session/session/provider-round.js +12 -6
  15. package/dist/agent-session/session/tool-round.js +5 -1
  16. package/dist/agent-session/session/types.d.ts +22 -1
  17. package/dist/agent-session/session.d.ts +16 -0
  18. package/dist/agent-session/session.js +42 -3
  19. package/dist/artifacts.d.ts +39 -1
  20. package/dist/artifacts.js +73 -0
  21. package/dist/attention-compiler.d.ts +121 -0
  22. package/dist/attention-compiler.js +479 -0
  23. package/dist/checkpoints.js +7 -11
  24. package/dist/cli-init.js +20 -6
  25. package/dist/context-budget.d.ts +20 -1
  26. package/dist/context-budget.js +10 -1
  27. package/dist/contracts-core/agent.d.ts +7 -0
  28. package/dist/contracts-core/attention.d.ts +66 -0
  29. package/dist/contracts-core/attention.js +2 -0
  30. package/dist/contracts-core/compaction.d.ts +59 -0
  31. package/dist/contracts-core/compaction.js +77 -1
  32. package/dist/contracts-core/content.d.ts +5 -0
  33. package/dist/contracts-core/loop.d.ts +42 -0
  34. package/dist/contracts-core/provider.d.ts +4 -0
  35. package/dist/contracts-core/run-limits.d.ts +2 -0
  36. package/dist/contracts-core.d.ts +1 -0
  37. package/dist/contracts-core.js +1 -0
  38. package/dist/contracts-protocol.d.ts +44 -3
  39. package/dist/contracts-run-state.d.ts +32 -5
  40. package/dist/evidence-grounding.d.ts +29 -0
  41. package/dist/evidence-grounding.js +162 -0
  42. package/dist/host-composition.d.ts +91 -0
  43. package/dist/host-composition.js +279 -0
  44. package/dist/index.d.ts +13 -6
  45. package/dist/index.js +7 -4
  46. package/dist/input.d.ts +13 -1
  47. package/dist/input.js +40 -1
  48. package/dist/provider-events.d.ts +3 -1
  49. package/dist/provider-events.js +2 -2
  50. package/dist/providers/transport.d.ts +3 -1
  51. package/dist/providers/transport.js +36 -0
  52. package/dist/redaction.js +18 -2
  53. package/dist/run-bundle.d.ts +89 -0
  54. package/dist/run-bundle.js +149 -0
  55. package/dist/secure-agent.d.ts +2 -0
  56. package/dist/secure-agent.js +6 -1
  57. package/dist/testing/state-concurrency-conformance.js +5 -12
  58. package/dist/tool-result-fold.d.ts +12 -0
  59. package/dist/tool-result-fold.js +13 -6
  60. package/dist/tools.d.ts +10 -0
  61. package/dist/tools.js +41 -0
  62. package/docs/acp-agent.md +42 -11
  63. package/docs/acp.md +2 -1
  64. package/docs/ag-ui.md +10 -3
  65. package/docs/agent-definitions.md +9 -1
  66. package/docs/agent-events.md +4 -1
  67. package/docs/agent-loops.md +33 -0
  68. package/docs/agent-session-runtime.md +8 -7
  69. package/docs/attention-compiler.md +272 -0
  70. package/docs/cli-rpc.md +4 -2
  71. package/docs/coding-agent-tools.md +1 -1
  72. package/docs/coding-security.md +6 -3
  73. package/docs/coding-tools.md +0 -1
  74. package/docs/coding-workspaces.md +22 -0
  75. package/docs/compaction-and-retry.md +36 -4
  76. package/docs/compaction-observational-memory.md +63 -10
  77. package/docs/connected-apps.md +116 -0
  78. package/docs/context-and-skills.md +17 -2
  79. package/docs/conversations.md +1 -1
  80. package/docs/core.md +1 -1
  81. package/docs/dev-inspector.md +4 -0
  82. package/docs/device-adapters.md +1 -0
  83. package/docs/diagrams.md +6 -6
  84. package/docs/document-reader.md +18 -10
  85. package/docs/documents.md +40 -11
  86. package/docs/durable-runs.md +87 -0
  87. package/docs/enterprise-postgres-state.md +6 -2
  88. package/docs/evaluations.md +168 -4
  89. package/docs/execution-timeline.md +186 -0
  90. package/docs/guardrails.md +33 -0
  91. package/docs/history/0.7.0-primitive-review.md +254 -0
  92. package/docs/history/079-messaging-primitive-review.md +391 -0
  93. package/docs/history/080-messaging-followon-primitive-review.md +234 -0
  94. package/docs/history/081-connected-apps-primitive-review.md +74 -0
  95. package/docs/history/083-prism-work-primitive-review.md +84 -0
  96. package/docs/history/084-primitive-review.md +96 -0
  97. package/docs/history/085-honesty-and-cut-primitive-review.md +91 -0
  98. package/docs/history/README.md +5 -0
  99. package/docs/history/migration-0.0.md +2 -2
  100. package/docs/history/release-handoffs.md +75 -1
  101. package/docs/host-compositions.md +149 -0
  102. package/docs/host-security.md +2 -2
  103. package/docs/hosted-sandboxes.md +94 -0
  104. package/docs/index.md +82 -45
  105. package/docs/input-and-prompt-assembly.md +1 -0
  106. package/docs/knowledge-sync.md +84 -0
  107. package/docs/language-intelligence.md +1 -1
  108. package/docs/live-testing.md +8 -3
  109. package/docs/mcp-tools.md +3 -1
  110. package/docs/memory-fabric.md +416 -0
  111. package/docs/messaging-channel-operations.md +166 -0
  112. package/docs/messaging-channels.md +150 -0
  113. package/docs/migrate-to-0.5.md +1 -1
  114. package/docs/migrate-to-0.6.md +1 -0
  115. package/docs/migrate-to-0.7.md +345 -0
  116. package/docs/migrate-to-0.8.md +124 -0
  117. package/docs/migration.md +43 -1
  118. package/docs/model-registry.md +12 -2
  119. package/docs/model-routing.md +79 -4
  120. package/docs/multi-agent-patterns.md +20 -6
  121. package/docs/observability.md +52 -1
  122. package/docs/openapi-tools.md +1 -1
  123. package/docs/operations.md +14 -4
  124. package/docs/options-index.md +47 -3
  125. package/docs/peer-dependencies.md +12 -10
  126. package/docs/postgres-persistence.md +1 -1
  127. package/docs/process-sessions.md +3 -1
  128. package/docs/prompt-registry.md +1 -1
  129. package/docs/provider-caching.md +4 -2
  130. package/docs/provider-conformance.md +1 -1
  131. package/docs/provider-layer.md +2 -2
  132. package/docs/provider-packages.md +22 -22
  133. package/docs/providers/bedrock.md +71 -7
  134. package/docs/providers/neuralwatt.md +5 -1
  135. package/docs/providers/openai.md +1 -1
  136. package/docs/rag.md +24 -8
  137. package/docs/realtime-voice.md +87 -0
  138. package/docs/release-and-install.md +53 -45
  139. package/docs/run-bundle.md +92 -0
  140. package/docs/runs-and-usage.md +17 -2
  141. package/docs/server.md +7 -3
  142. package/docs/sheets.md +9 -9
  143. package/docs/signal-channel.md +112 -0
  144. package/docs/speech.md +7 -1
  145. package/docs/sqlite-persistence.md +1 -1
  146. package/docs/supervisors.md +33 -5
  147. package/docs/telegram-channel.md +157 -0
  148. package/docs/testing.md +2 -2
  149. package/docs/thinking-and-reasoning.md +3 -1
  150. package/docs/tools.md +6 -5
  151. package/docs/web-tools.md +2 -1
  152. package/docs/wiki.md +1 -1
  153. package/docs/work-artifacts-and-review.md +14 -4
  154. package/docs/work-connectors.md +12 -10
  155. package/docs/work-sandbox.md +115 -0
  156. package/docs/work-tools.md +50 -18
  157. package/docs/workflows.md +69 -1
  158. package/docs/working-and-semantic-memory.md +25 -14
  159. package/package.json +5 -3
  160. package/templates/README.md +2 -0
  161. package/templates/business-worker/README.md.tmpl +19 -0
  162. package/templates/business-worker/env.example.tmpl +1 -0
  163. package/templates/business-worker/gitignore.tmpl +11 -0
  164. package/templates/business-worker/manifest.json +12 -0
  165. package/templates/business-worker/package.json.tmpl +23 -0
  166. package/templates/business-worker/src/agent.ts.tmpl +92 -0
  167. package/templates/business-worker/src/index.ts.tmpl +13 -0
  168. package/templates/business-worker/src/tests/agent.test.ts.tmpl +77 -0
  169. package/templates/business-worker/tsconfig.json.tmpl +15 -0
  170. package/templates/personal-assistant/README.md.tmpl +18 -0
  171. package/templates/personal-assistant/env.example.tmpl +1 -0
  172. package/templates/personal-assistant/gitignore.tmpl +11 -0
  173. package/templates/personal-assistant/manifest.json +11 -0
  174. package/templates/personal-assistant/package.json.tmpl +23 -0
  175. package/templates/personal-assistant/src/agent.ts.tmpl +65 -0
  176. package/templates/personal-assistant/src/index.ts.tmpl +13 -0
  177. package/templates/personal-assistant/src/tests/agent.test.ts.tmpl +28 -0
  178. package/templates/personal-assistant/tsconfig.json.tmpl +15 -0
@@ -0,0 +1,345 @@
1
+ # Migrate Prism 0.6 to 0.7
2
+
3
+ > **Status: 0.7.0** (Host Completeness, Evidence, and Capability Boundaries).
4
+
5
+ This document details migration steps, security tightenings, and compatibility notes for upgrading from Prism 0.6.0 to 0.7.0.
6
+
7
+ ---
8
+
9
+ ## Security Tightenings and Breaking Behavioral Changes
10
+
11
+ ### 1. ACP MCP Destination Matching (Trap A)
12
+
13
+ In Prism 0.6.0 and earlier, `@arnilo/prism-acp-agent` matched candidate MCP server URLs against `mcp.allow` using string prefix matching (`server.url.startsWith(entry)`). This permitted:
14
+ - **Origin lookalikes**: An allow entry for `https://mcp.example.com` inadvertently matched `https://mcp.example.com.attacker.invalid/mcp`.
15
+ - **Path prefix bleeding**: An allow entry for `https://mcp.example.com/mcp` matched sibling paths like `https://mcp.example.com/mcp-other`.
16
+
17
+ In Prism 0.7.0, destination matching strictly adheres to WHATWG URL origin and path-segment subtree standards:
18
+
19
+ - **Origin matching**: Normalizes scheme (`http:` / `https:`), hostname (case-insensitive, punycode IDN, IPv6 brackets), and effective port (default ports 80/443 normalized). Lookalike hosts are rejected.
20
+ - **Path-segment subtree matching**:
21
+ - Origin-level entries (e.g. `https://mcp.example.com` or `https://mcp.example.com/`) match any path under that exact origin.
22
+ - Path-scoped entries (e.g. `https://mcp.example.com/mcp` or `https://mcp.example.com/mcp/`) match `/mcp`, `/mcp/`, and `/mcp/sub`, but reject sibling prefixes such as `/mcp-other` or `/mcpextra`.
23
+ - **Configuration validation**:
24
+ - Every `mcp.allow` entry in `prism-acp-agent.json` must be `"stdio"` or a valid absolute `http:` or `https:` URL.
25
+ - Entries containing userinfo (`user:pass@`), query parameters (`?query`), fragment identifiers (`#hash`), or ambiguous encoded path characters (`%2e%2e`, `%2f`, `%5c`, `..`, backslashes) throw `ConfigError` during config parsing.
26
+ - **Candidate URL validation**: Candidate server URLs with embedded credentials or ambiguous encoded path forms fail closed at selection time.
27
+ - **Transports**: Unstable `acp` transport remains rejected. `stdio` servers require the explicit `"stdio"` marker in `mcp.allow`.
28
+
29
+ #### Migration Actions
30
+ - Review `mcp.allow` in `prism-acp-agent.json`: remove any query strings, hashes, or credentials from allow entries.
31
+ - If previously relying on prefix matching across sibling paths (e.g. relying on `/mcp` to match `/mcp-internal`), explicitly list both entries or use an origin-level entry.
32
+
33
+ ### 2. Model Router Facade Fail-Closed Governance (Trap B)
34
+
35
+ In Prism 0.6.0 and earlier, the synchronous `router.providerSource(model)` facade only checked allow-lists, residencies, and durable state presence. When configured with in-memory budgets (such as `maxCostUsd: 0` or positive limits), rate limits, circuit breakers, fallbacks, or selection policies, `router.providerSource(model)` returned an unwrapped provider and bypassed these governance controls without enforcement.
36
+
37
+ In Prism 0.7.0, `router.providerSource(model)` enforces fail-closed boundary safety:
38
+ - **Refuses unenforced governance**: If the router is configured with `budgets`, `rateLimit`, `circuit`, `fallbacks`, or `selection`, calling `providerSource(model)` throws `ModelRouterError` with stable code `ERR_PRISM_MODEL_ROUTER_ASYNC_REQUIRED`.
39
+ - **Refuses durable state**: If configured with `stateStore`, calling `providerSource(model)` throws `ERR_PRISM_MODEL_ROUTER_ASYNC_STATE`.
40
+ - **Runtime validation**: Untyped JavaScript callers passing malformed model arguments fail closed before resolver invocation with `ERR_PRISM_MODEL_ROUTER_VALIDATION`.
41
+ - **Resolver isolation**: The underlying `resolver` function is never called when `providerSource` refuses or denies a request.
42
+ - **Synchronous allow-list / residency support**: Simple allow-list-only and residency-only routers without async state or governance caps remain fully supported via `router.providerSource(model)`.
43
+
44
+ #### Migration Actions
45
+
46
+ Do not use `router.providerSource(model)` when governance (budgets, rate limits, circuit breaker, fallbacks, selection policies, or durable state) is configured. Replace calls with the asynchronous admission method `await router.resolve(...)`:
47
+
48
+ ```ts
49
+ // ❌ Bypasses governance in 0.6.0 / Refused in 0.7.0 (throws ERR_PRISM_MODEL_ROUTER_ASYNC_REQUIRED)
50
+ const provider = router.providerSource(model);
51
+
52
+ // ✅ Governed admission in 0.7.0
53
+ const { provider, model: selectedModel, providerRequestPolicy, budgetReservation } = await router.resolve({
54
+ model,
55
+ identity,
56
+ maxCostUsd: 0.25,
57
+ });
58
+
59
+ // Pass to agent
60
+ const agent = createAgent({
61
+ model: selectedModel,
62
+ provider,
63
+ providerRequestPolicies: [providerRequestPolicy],
64
+ });
65
+
66
+ // Commit actual usage after run
67
+ await router.recordUsage({
68
+ identity,
69
+ provider: provider.id,
70
+ model: selectedModel.model,
71
+ tokens: runTokens,
72
+ budgetReservation,
73
+ });
74
+ ```
75
+
76
+ To test whether a router configuration supports `providerSource` before calling it, use `isProviderSourceEligible(options)` or `assertProviderSourceEligible(options)` exported from `@arnilo/prism-core/governance/model-router`.
77
+
78
+ ### 3. ACP Real-Provider Launcher and Explicit Mock Mode (Trap C / R05)
79
+
80
+ In Prism 0.6.0 and earlier, `@arnilo/prism-acp-agent` silently defaulted to `createMockProvider()` when no provider was passed and no model was configured. Hosts deploying the ACP binary without explicit provider wiring ran mock sessions without warning or token generation (Trap C).
81
+
82
+ In Prism 0.7.0, `createSpawnableAgent` enforces fail-closed startup validation:
83
+
84
+ - **Explicit model required**: Config must specify a valid `model` (`{ "provider": "<name>", "model": "<id>" }`) unless a provider instance is passed via API options.
85
+ - **Credential reference required**: Real providers require `credentialRef` in the configuration. The secret value is resolved from `process.env[ref]` or an optional host `credentialResolver`. If missing or unresolvable, startup fails immediately with `ConfigError` (code `PRISM_ACP_AGENT_CONFIG`).
86
+ - **Provider matching & allow-list**: Only allow-listed first-party providers are supported (`openai`, `anthropic`, `google`, `deepseek`, `openrouter`, `ollama`, `xai`, `zai`, `alibaba`, `kimi`, `clinepass`, `commandcode`, `neuralwatt`, `opencode-go`, `hyper`, and `mock`). Unknown providers or mismatches between configured models and injected providers fail before startup.
87
+ - **Explicit mock mode**: Mock mode requires explicit configuration: `{ "model": { "provider": "mock", "model": "mock" } }` (or injected `provider.id === "mock"`). It stays 100% offline and requires no credentials.
88
+ - **Lazy provider loading**: First-party provider adapters are dynamically imported on demand on the first generation call; `@arnilo/prism-providers` is never loaded at root import or during mock runs.
89
+ - **Credential safety**: Secret values never enter config persistence, argv flags, stdout protocol streams, events, or model context. Identity records only the non-secret `credentialRef`.
90
+ - **Durable session reconstruction**: With SQLite persistence, per-session agents (including editor-backed filesystem sessions) are reconstructed across process restarts with their selected model and provider intact.
91
+
92
+ #### Migration Actions
93
+
94
+ - **For real-provider deployments**: Add `model` and `credentialRef` to `prism-acp-agent.json`:
95
+ ```json
96
+ {
97
+ "userId": "local",
98
+ "cwd": ".",
99
+ "model": { "provider": "openai", "model": "gpt-4o" },
100
+ "credentialRef": "OPENAI_API_KEY",
101
+ "sessionStore": { "type": "sqlite", "path": ".prism/sessions.db" }
102
+ }
103
+ ```
104
+ - **For offline testing / mock journeys**: Explicitly declare mock mode:
105
+ ```json
106
+ {
107
+ "userId": "local",
108
+ "cwd": ".",
109
+ "model": { "provider": "mock", "model": "mock" }
110
+ }
111
+ ```
112
+
113
+ ### 4. Aggregate Task/Tenant Accounting Across All Paid Work (R01)
114
+
115
+ In Prism 0.6.0, model-router budgets were strictly per-model and per-provider (`(provider, model)`). When complex tasks involved retries, model switches, delegated child tasks, embeddings, compactions, or paid tools, each model bucket maintained separate counters, allowing budget resets through model hopping or child delegation.
116
+
117
+ In Prism 0.7.0, router state introduces unified task-level aggregate accounting:
118
+
119
+ - **Task-scoped reservations & accounting**: Supplying `taskId` and `kind` (`"generation" | "embedding" | "compaction" | "tool"`) groups all paid work for a given task under a single shared atomic budget ceiling.
120
+ - **Attribution breakdown**: Calling `router.readBudget({ identity, taskId })` decomposes total utilization into typed attributions (`byModel`, `byKind`, `attributions`).
121
+ - **Strict hard-budget mode (`budgets.strict = true`)**: In strict hard-budget mode, requests lacking enforceable bounds or candidates lacking cost pricing are denied fail-closed with `ERR_PRISM_MODEL_ROUTER_BUDGET`.
122
+ - **Hold renewal (`renewBudget`)**: Long-running holds can be renewed via `router.renewBudget()` or `governedProvider.renewBudget()` before expiry; the hold's fencing token advances and previous fencing tokens are invalidated. Expired holds fail closed with `ERR_PRISM_MODEL_ROUTER_STATE`.
123
+ - **PostgreSQL schema migration `006_aggregate_budgets`**: Adds `task_id` and `attributions` columns to `prism_model_router_budgets` with partial index `prism_model_router_budgets_task_idx`.
124
+
125
+ #### Migration Actions
126
+
127
+ - **Durable PostgreSQL deployments**: Apply migration `006_aggregate_budgets` on startup via `createPostgresEnterpriseState()`. Existing rows automatically default `task_id` to empty string and `attributions` to `{}`.
128
+ - **Task/Job workflows**: Pass `taskId` to `router.resolve()`, `recordUsage()`, and `createGovernedProvider()` to prevent budget oversubscription across retries and child agents.
129
+ - **Budget enforcement**: Set `budgets.strict: true` when hard cost/token ceilings must be guaranteed against unmetered or unpriced providers.
130
+
131
+ ### 5. Durable Business-Action Draft Persistence and Resumption (R02)
132
+
133
+ In Prism 0.6.0, Microsoft 365 and Google Workspace connector mutation drafts were kept ephemerally in adapter memory. If an agent process restarted or if an asynchronous human approval took minutes or hours, drafts were lost, forcing re-creation of drafts from scratch without revision guarantees. Furthermore, modifying a draft did not systematically invalidate existing approvals.
134
+
135
+ In Prism 0.7.0, business-action drafts feature durable lifecycle tracking:
136
+
137
+ - **Checkpoint-backed draft store**: Adapters accept `checkpoints: CheckpointStore` (e.g. `createPostgresEnterpriseState({ pool }).checkpoints` or `createMemoryCheckpointStore()`) or a dedicated `draftStore: WorkDraftStore`. Drafts persist under namespace `prism.work.draft` and survive process restart.
138
+ - **Exact revision binding & payload digest**: Drafts start at `revision: 1` with a canonical SHA-256 `payloadDigest`. Approvals bind strictly to `{ draftId, revision, payloadDigest, identityKey, approvedAt, expiresAt, policyRevision }`.
139
+ - **Edits invalidate approval**: Updating draft payload or recipients increments `revision`, clears `approval`, and resets `status` to `pending_approval`.
140
+ - **Resuming approved revisions**: Tools (`m365_mail_draft_send`, `gws_mail_draft_send`, `m365_calendar_draft_add`, `gws_calendar_draft_add`) accept `{ draftId, revision }` without repeating the payload; the tool resumes the stored payload and executes after approval validation.
141
+ - **Fail-closed ambiguous failure handling**: Connector failures after dispatch mark both the idempotency record and the draft `unknown`. Automatic replays are rejected with `ERR_PRISM_WORK_IDEMPOTENCY_UNKNOWN` until operator reconciliation.
142
+
143
+ #### Migration Actions
144
+
145
+ - **For persistent workloads**: Pass `checkpoints` (and optionally `bodies: ArtifactBodyStore`) to `createMicrosoft365CliAdapter` and `createGoogleWorkspaceCliAdapter` so drafts survive process restart.
146
+ - **Approval systems**: Ensure approval decisions provide or verify `{ draftId, revision, payloadDigest }`.
147
+
148
+ ### 6. RAG document authorization (R04)
149
+
150
+ `retrieveContext` without `authorization` is unchanged. Passing `authorization` injects host-verified principal/group constraints into both vector and lexical legs **before** ranking, then rechecks before rerank and injection.
151
+
152
+ - `filter` is metadata equality only. It is not document ACL.
153
+ - Stores that do not declare `authorization: "acl"` throw rather than claim protection. In-memory and PostgreSQL adapters declare it (`setSourceAccess` / `checkSourceAccess`).
154
+ - Missing grants and unresolved `accessVersion` deny. Revoking a grant (empty principal+group lists, bumped version) hides the source on the next query without re-embedding.
155
+ - `authorization.tenantId` must match every retrieve scope.
156
+
157
+ #### Migration Actions
158
+
159
+ - Hosts that need per-document ACL pass `authorization` and call `setSourceAccess` for each source. Hosts that do not pass `authorization` keep today's retrieve behavior.
160
+ - Custom `VectorStore` implementations must implement query-time ACL and `checkSourceAccess` before advertising `authorization: "acl"`.
161
+
162
+ ### 7. Drive knowledge synchronization (R04)
163
+
164
+ Opt-in. `syncKnowledge` + `createGoogleDriveConnector` page Drive `files.list` / `changes.list` into existing `replaceSource` / `setSourceAccess`. Cursors live on the host `CheckpointStore` and advance only after a page commits. `changes.watch` payloads are not authorization.
165
+
166
+ #### Migration Actions
167
+
168
+ - Hosts that want incremental Drive RAG import wire a token provider (`drive.readonly`), `resolveAccess` for permissions, and a durable checkpoint key. Hosts that do not call `syncKnowledge` are unchanged.
169
+
170
+ ### 8. Hosted E2B sandbox (R03)
171
+
172
+ Opt-in. `createE2BSandbox` / `connectE2BSandbox` implement `DisposableSandbox` plus `pause`/`resume`. Docker and native adapters are unchanged. E2B `Sandbox.connect` auto-resumes paused VMs; Prism reconnects paused sandboxes **without** calling it unless the host calls `resume()` or passes `resume: true`. `lifecycle.autoResume` is always false. `pause({ keepMemory: false })` is filesystem-only: processes do not survive resume. A 503 pause refusal leaves the sandbox running. `close({ export })` is unsupported (pause is the snapshot).
173
+
174
+ Default capabilities do **not** claim Docker `network: none` / egress parity.
175
+
176
+ #### Migration Actions
177
+
178
+ - Hosts that want E2B install optional peer `e2b@2.49.1` (or inject `client`) and pass `apiKey` at the edge. Hosts that keep Docker/native are unchanged.
179
+
180
+ ### 9. Fair worker admission and operator routes (R06)
181
+
182
+ Opt-in. Existing `createWorkflowCoordinator` and `createPrismDrainController` stay the composition entry points. Optional `admission` adds cursor wrap, per-tenant/per-class claim caps, queue deadlines, and drain-aware claiming. `createPrismOperatorHandler` is a separate authorized handler for queue/suspended/failed/unknown inspect plus cancel/reconcile. Reconcile cannot mark unknown effects retryable. No new job broker.
183
+
184
+ #### Migration Actions
185
+
186
+ - Hosts that want fair multi-tenant workers set `admission` and mount `/ops`. Hosts that keep a single-tenant coordinator with default FIFO first-page polling are unchanged.
187
+
188
+ ### 10. Behavioral eval inspector wiring (R07)
189
+
190
+ Opt-in. Trajectory scorers, scenario runner, manifests, and `summarizeTimeline` stay in `@arnilo/prism-core/governance/evals` and `@arnilo/prism-core/governance/observability`. The dev inspector adds `GET /runs/:id/summary` and `POST /compare` that render those artifacts. Host-journey fixtures live in `examples/behavior-evaluation.ts`.
191
+
192
+ #### Migration Actions
193
+
194
+ - Hosts that want inspector quality/cost/latency compare wire `eventSource` + `resolveRun` and call `compareInspectorRuns` / `POST /compare`. Hosts that keep the previous inspector timeline-only UI are unchanged.
195
+
196
+ ### 11. Cross-layer memory lineage (R08)
197
+
198
+ Opt-in. `remember({ lineage: { sourceIds } })` stamps `metadata._lineage` (schema v1). `forget` / `setConsent(visible: false)` / `correct` write invalidation rows **before** body delete. Query/lexical legs exclude forgotten/revoked/held ids and any record listing them in `_lineage.sourceIds`. `correct` keeps the source (`reason: corrected`). `forget({ hold: true })` skips body delete. Missing `_lineage` is self-only. Parent-child `shareWith` is an explicit allow-list; siblings and expired grants fail closed. Observational projection/recall take `invalidatedIds`. `revokedIdsAbsent` is the 072 invariant body.
199
+
200
+ Custom `VectorStore` implementations that omit `lineage: "invalidation"` keep pre-0.7 forget-as-delete (dependents may leak). In-memory and PostgreSQL adapters declare it.
201
+
202
+ #### Migration Actions
203
+
204
+ - Hosts that want derived-context exclusion stamp `lineage` on writes and pass `authorization`/invalidation through recall. Hosts that do not stamp lineage keep self-only delete. Do not edit frozen `docs/migrate-to-0.6.md`.
205
+ - `setConsent(entryId, { visible: false })` marks `revoked` (not `legal_hold`), so recall excludes the record but a later `forget` still purges it; re-granting clears only a revoked mark and never resurrects a `corrected`/`forgotten` one. Use `forget({ ids, hold: true })` when you actually need retention.
206
+ - Observational recall keeps a reflection whose supporting observation was dropped by compaction and annotates it `(dropped)`; invalidation still wins, so a revoked observation id (or a revoked source of one) withholds the reflection with `reason: "revoked"`.
207
+
208
+ ### 12. Evidence-backed citations and document diffs (R10)
209
+
210
+ Additive. `ArtifactCitation` may include `sourceId` / `revision` / `contentHash` / `retrievedAt` / `excerpt` / `span` / `tenantId` / `support`. Approvals stamp `evidenceDigest`. `checkCitationIntegrity` fails closed on missing source, hash/span mismatch, revoked ACL, or tenant mismatch; `support` is ignored. `diffDocument` walks Document Model nodes with op/node caps (`truncated` instead of unbounded diff). `createCitationIntegrityScorer` is a 072 invariant: score 0 cannot be averaged away by a semantic judge.
211
+
212
+ #### Migration Actions
213
+
214
+ - Legacy uri/title/kind citations still attach. Evidence fields are optional until the host starts integrity checks.
215
+ - Structural Office review uses `diffDocument`; artifact `compare` remains hash+metadata.
216
+
217
+ ### 13. Import fidelity and optional OCR (R10)
218
+
219
+ Additive. `importDocument` returns `{ model, fidelity }` — ZIP-name report of dropped OOXML structures (macros, comments, media, …). `parseDocument` still returns the model only.
220
+
221
+ `createMistralOcrParser({ apiKey })` is a host-selected `DocumentParser`. Default `createDocumentReader()` still uses `pdf-parse` / `mammoth` only and does not call OCR. Inline data URLs; no Files API. `documentUrl` is SSRF-checked. `recordUsage` admits pages/bytes into Task 7 accounting.
222
+
223
+ #### Migration Actions
224
+
225
+ - Existing `parseDocument` callers are unchanged. Switch to `importDocument` when review UI must show lost structures.
226
+ - OCR is opt-in. Do not add the OCR parser to default `parsers`.
227
+
228
+ ### 14. Per-run tool narrowing (R11)
229
+
230
+ Additive. `RunOptions.toolNames` allow-lists registered tool names for one run. Omitted = full registry (0.6 behavior). Empty = no tools. Unknown names throw. Resume persists the grant and will not widen it. MCP `execute` fails closed when a refresh changes schema/effect or revokes the tool.
231
+
232
+ Still no `RunOptions.tools` or `RunOptions.toolFilter`.
233
+
234
+ #### Migration Actions
235
+
236
+ - Existing `session.run(input)` callers are unchanged.
237
+ - Pass `{ toolNames: ["web_search"] }` when a continuing session should see a subset.
238
+
239
+ ### 15. Governed realtime voice (R14)
240
+
241
+ Additive. `createRealtimeVoiceBridge` (`@arnilo/prism-core/runtime/realtime`) admits a voice device, dispatches host `function_call` items through the ordinary execute path, cancels queued calls on barge-in, and skips `seenCallIds` on reconnect. Transcripts are off by default; audio is never retained. `RealtimeEvent` may include `usage`. `RealtimeSession.completeTool` is optional. OpenAI Realtime advertises host tools via `session.update` and completes them with `function_call_output`.
242
+
243
+ #### Migration Actions
244
+
245
+ - Existing `createOpenAIRealtimeSession` callers that only send audio are unchanged.
246
+ - Wire `execute` through `dispatchToolCall` / durable approval. Session microphone consent is not tool approval.
247
+
248
+ ### 16. Eval primitives match their contracts (R07)
249
+
250
+ Additive. `runExperiment({ trials: N, seed })` re-runs each item N times (cap 16) and reports `sampleCount` / `standard_error`. `wrapAgentWithFailureInjection` honors `failStore` (fails on `run`), `denyTools`, and `unknownEffect`. Timeline collection no longer uses a 10ms drain. `validateEvalManifest` stays two-field; `validateReleaseEvalManifest` adds prompt/tools/model/policy binding.
251
+
252
+ #### Migration Actions
253
+
254
+ - Existing `validateEvalManifest({ runtimeRevision, datasetVersion })` callers are unchanged.
255
+ - Call `validateReleaseEvalManifest` when packing release evidence. Do not pass `expectedBehavior`, `failStoreAfterTurns`, `denyToolCalls`, or `uncertaintyMethod: "bootstrap"` — those were docs drift, not APIs.
256
+
257
+
258
+
259
+
260
+ ### 17. Native Bedrock Converse route (R12)
261
+
262
+ Additive. `@arnilo/prism-providers/bedrock` now ships a native route next to the OpenAI-compatible one: `createBedrockConverseProvider({ region, credential, stream })` runs `ConverseStream` (default) or one `Converse` call, and `createBedrockProviderPackage({ region, credential, api: "converse" })` registers it under the same `id`/model bindings. Prism messages map to `messages`/`system`/`inferenceConfig`/`toolConfig`, Prism media blocks map to `image`/`document` blocks, cache breakpoints map to `cachePoint` blocks, `options.structuredOutput` maps to `outputConfig.textFormat`, and Anthropic/OpenAI-family reasoning maps to `additionalModelRequestFields.thinking` / `.reasoning_effort`. Responses are decoded from the `application/vnd.amazon.eventstream` framing with bounded frame sizes and CRC validation, still with no AWS SDK dependency.
263
+
264
+ #### Migration Actions
265
+
266
+ - Nothing changes for existing `createBedrockProvider` / `createBedrockProviderPackage` hosts: the default route stays `compatible`.
267
+ - To move a provider id to Converse, set `api: "converse"` (and keep `stream: false` only if the deployment must avoid `InvokeModelWithResponseStream`). One provider id serves one route; register a second `id` if you need both.
268
+ - Model bindings that relied on OpenAI image parts must declare `capabilities.input` with `image`/`document` and use Prism media blocks; unsupported media types now refuse before the request instead of being dropped.
269
+ - Do not pass `cachePoint`, `toolConfig`, `outputConfig`, or `additionalModelRequestFields` through `compat`; use Prism cache breakpoints, `tools`, `structuredOutput`, and `compat.thinking`/`compat.reasoning_effort` (or `options.extra.additionalModelRequestFields` for model-specific fields).
270
+
271
+ ---
272
+
273
+ ## Opt-in additions (no behavior change until enabled)
274
+
275
+ ### 18. Attention compiler (R17, opt-in)
276
+
277
+ `createAttentionCompiler(options?, context?)` is a per-turn gate that measures the assembled input against a host ratio of the model input cap and rewrites nothing until that ratio is reached; over the ratio it mutates a **history clone** monotonically (oldest `thinking` blocks first, then oldest fold-eligible tool results), so prompt-cache prefixes survive and the session store, observational-memory ledger, and input history array are untouched. Still over after every eligible row → `AttentionBudgetError` instead of silent eviction.
278
+
279
+ #### Migration Actions
280
+
281
+ - Nothing changes by default: with `attentionCompiler` omitted, request bytes and the store are byte-identical to 0.6.0.
282
+ - Turn it on per agent (`AgentConfig.attentionCompiler`) or per run (`RunOptions.attentionCompiler`, which narrows, never widens: `false` disables for that run).
283
+ - Hosts that compact on overflow can drive compaction from the gate instead of guessing a token threshold with the host-programmable compaction trigger.
284
+ - Do not use it as a replacement for compaction or `applyContextBudget` eviction: compaction is the boundary operation that writes a summary.
285
+
286
+ `AgentDefinition.attentionCompiler` and the direct `assembleProviderInput` seam carry the same option shape; a definition sets it for every resolved config.
287
+
288
+ ### 19. Memory Fabric subpath (opt-in)
289
+
290
+ `@arnilo/prism-memory/fabric` adds typed notes over the stores a host already configured: `createMemoryFabric({ memory, observational?, linker?, ... })` writes `fact`, `procedure`, `file`, `working`, and `episode` notes through the existing working/vector stores, with links, validity windows, and time/tool recall.
291
+
292
+ #### Migration Actions
293
+
294
+ - Add the subpath import; no new package, provider, database, or mandatory dependency is introduced.
295
+ - The fabric is inert until `fabric.attach(session)`: importing the subpath starts no worker, no timer, and no process, and an unattached fabric enriches nothing.
296
+ - Episode notes (`kind: "episode"`) and `searchConversation` require an attached observational-memory session; without one they fail closed.
297
+ - Reserved keys: `metadata.fabric` on vector records and `_fabric.blocks` inside the working value. A host schema that validates working values must allow them; the host schema remains the last word on block content.
298
+ - Existing `createMemory` hosts keep working unchanged — the fabric writes through the same store, consent, redaction, and lineage paths.
299
+
300
+ ### 20. Work-scope memory index (R16, opt-in)
301
+
302
+ `createWorkScopeController({ session, appendEntry, secrets? })` appends `om.scope.*` entries to one observational-memory ledger and folds them with `foldWorkScopeMap()`; `projectWorkMemory(ledger, map, query)` filters observations/reflections to a host-selected working set and `withWorkScope(controller, spec, fn)` opens/enters/leaves around a callback.
303
+
304
+ #### Migration Actions
305
+
306
+ - Nothing changes without `om.scope.*` entries: the map has only its implicit `session` root, context renders the existing active pool, and the dropper keeps its 0.6.0 behavior.
307
+ - While any host scope exists, the runtime skips the observation dropper — the working set is now the projection, and the folded-payload byte cap stays a storage safety cap, not garbage collection.
308
+ - Bindings are exact ids (`om:<12-hex>` / `reflection:<12-hex>`); a reflection bound on a **closed** scope can graduate into durable semantic memory through the fabric's `remember({ kind: "fact" | "procedure", reflectionId })`.
309
+ - Caps fail closed: 256 scopes, depth/stack 8, 4,096 binds per scope, 512-character labels/kinds, ids `[A-Za-z0-9._:/-]{1,128}` without `..`.
310
+ - `recallObservationalMemory()` still reads the complete current branch by exact id — the projection never hides memory from exact-id recall.
311
+
312
+ ### 21. Host-owned subagent spawn (opt-in)
313
+
314
+ `createSupervisor({ ownership, children })` gains model-facing tools: `createSpawnAgentTool({ supervisor, name?, mode? })` returns a non-exclusive `spawn_agent` whose closed schema exposes only the host's allow-listed child IDs, `input`, an optional `threadId`, and `mode: "sync" | "async"`; `createWaitAgentTool` / `createCancelAgentTool` return `wait_agent` / `cancel_agent` for host-owned async handles. `delegateAsync()` returns `{ delegationId, status: "running" }` without waiting.
315
+
316
+ #### Migration Actions
317
+
318
+ - Nothing changes for existing `delegate()` callers; the tools are additive and opt-in.
319
+ - Advertised children come from the supervisor's own list — a model cannot name a child the host did not construct, cannot supply child tools, identity, scopes, or higher limits, and sees redacted results and error text only.
320
+ - Child identity narrows from the parent (`narrowIdentity` + `assertIdentityPropagation`): a delegated scope set must be non-empty, must not widen the parent's scopes, and must not extend the parent expiry.
321
+ - Async handles are **in-process**: ownership-scoped, bounded, cached terminal records retained only up to `limits.maxQueuedEvents`, and they do not survive a host restart. Parent-run abort propagates to running children.
322
+ - Install `createWorktreeChildFactory` (`@arnilo/prism-coding-tools/agent`) and pass its `after` as the supervisor terminal hook when parallel children would otherwise collide in one working tree; the child context then carries `cwd` pointing at its own linked worktree, and cleanup runs on every terminal outcome — including a child that suspended for approval and later resumes.
323
+ - `observeSupervisorLifecycle` (coding tools) bridges supervisor `delegation_*` events to redacted coding `subagent_started` / `subagent_stopped` lifecycle events (and AG-UI/ACP projections).
324
+
325
+ ## Upgrade steps
326
+
327
+ 1. Bump every `@arnilo/*` dependency and peer to `^0.7.0` (all ten manifests cut together; a range that only *satisfies* 0.7.0 is refused by the release gate). The published predecessor is 0.6.0.
328
+ 2. Read §1–§3 if you run the ACP agent (`mcp.allow` entries may need tightening) or call `router.providerSource()` with governance configured — those are the only hard refusals for an existing host.
329
+ 3. Re-check each §4–§17 item your host touches: they are behavioral tightenings inside existing surfaces (accounting, drafts, authorization, narrowing, fidelity), not new opt-ins.
330
+ 4. Adopt the opt-in additions only where they matter: §18 attention compiler, §19 memory fabric, §20 work scopes, §21 spawn tools.
331
+ 5. Build and run your suite. No persisted-data migration exists or is needed: the 0.7.0 additions write through existing stores (working/vector records, checkpoints, observational-memory entries) under the same schema, and stores still fail closed on unknown or newer schema versions rather than rewriting data.
332
+ 6. Optional: re-run `npm run release:gate` locally to reproduce the release evidence matrix.
333
+
334
+ ## Rollback
335
+
336
+ Pin the previous published line: `@arnilo/prism@0.6.0` (exact pins per package, plus each package's `0.6.0`). Nothing persisted under 0.7 is rewritten in place: the new subpaths and options are additive, and the fabric/scopes/spawn features write only new records through existing stores — a rolled-back 0.6.0 host keeps reading its data and simply stops seeing entries it never wrote. The refusal changes in §1–§3 are the only deltas a 0.6.0 host regains by rolling back (and it regains the unsafe prefix matching and facade bypass with them, so re-check anything relying on those).
337
+
338
+ Back up the session/checkpoint store before a rollback if the 0.7 host wrote fabric notes or scope entries you intend to keep: 0.6.0 code paths ignore them rather than deleting them, but only the 0.7 docs describe them.
339
+
340
+ ## Related APIs
341
+
342
+ - [Migration guide](migration.md): the era index of migration cuts with replacement tables and rollback notes.
343
+ - [Migrate Prism 0.5 to 0.6](migrate-to-0.6.md): Node 22 floor, folded 0.5.7 delta, third-party floors.
344
+ - [Release and install](release-and-install.md): packed surfaces, install rules, support matrix, and the offline test budget.
345
+ - [Memory fabric](memory-fabric.md), [Observational memory compaction](compaction-observational-memory.md), [Attention compiler](attention-compiler.md), [Supervisors](supervisors.md): owning pages for the opt-in additions above.
@@ -0,0 +1,124 @@
1
+ # Migrate Prism 0.7 to 0.8
2
+
3
+ > **Status: 0.8.0** (messaging channels, connected apps, work family, durable runs).
4
+
5
+ This document details migration steps, breaking import-map changes, and compatibility notes for upgrading from Prism 0.7.0 to 0.8.0.
6
+
7
+ ---
8
+
9
+ ## Security Tightenings and Breaking Behavioral Changes
10
+
11
+ ### 1. Work family package move (the only import-map break)
12
+
13
+ `@arnilo/prism-office` is removed with no pre-1.0 shim. Install `@arnilo/prism-work` next to `@arnilo/prism` and rewrite imports:
14
+
15
+ | Old import | Replacement |
16
+ | --- | --- |
17
+ | `@arnilo/prism-office/documents` | `@arnilo/prism-work/documents` |
18
+ | `@arnilo/prism-office/sheets` | `@arnilo/prism-work/sheets` |
19
+ | `@arnilo/prism-office/diagrams` | `@arnilo/prism-work/diagrams` |
20
+ | `@arnilo/prism-core/integrations/work` | `@arnilo/prism-work/connectors` |
21
+ | `@arnilo/prism-core/integrations/work/microsoft365` | `@arnilo/prism-work/connectors/microsoft365` |
22
+ | `@arnilo/prism-core/integrations/work/google-workspace` | `@arnilo/prism-work/connectors/google-workspace` |
23
+ | `@arnilo/prism-core/integrations/work/drafts` | `@arnilo/prism-work/connectors/drafts` |
24
+ | `@arnilo/prism-coding-tools/document-reader` | `@arnilo/prism-work/document-reader` |
25
+
26
+ `createReadTool({ documentReader })` is unchanged: pass a reader from the new subpath. Core keeps the durable adapter at `@arnilo/prism-core/enterprise/postgres` (`createPostgresEnterpriseState({ pool }).workIdempotency`) with type-only structural coupling.
27
+
28
+ **Match work-idempotency conflicts by `code`, not by error class.** Portable codes stay `ERR_PRISM_WORK_IDEMPOTENCY` and `ERR_PRISM_WORK_IDEMPOTENCY_CONFLICT`. `createMemoryIdempotencyStore()` throws `WorkToolError`; the PostgreSQL adapter throws `EnterprisePostgresError` because `@arnilo/prism-core` cannot depend on `@arnilo/prism-work` at runtime.
29
+
30
+ #### Migration Actions
31
+ - Replace every `@arnilo/prism-office` and `integrations/work` / coding-tools `document-reader` import with the table above.
32
+ - Catch work-idempotency by `error.code`.
33
+ - Install `@arnilo/prism-work@^0.8.0` (it is one of the eleven lockstep packages).
34
+
35
+ ### 2. Observational-memory workers stay tool-only
36
+
37
+ Workers (`observer` / `dropper` / `reflector`) keep only `tool_call` provider events. A text-only, thinking-only, or done-only turn is a **successful no-op**: no ledger write from that turn. Mixed text+tools keep the tools. Limit and unknown-tool failures throw `MemoryError` / `MemoryLimitError` (`code`), not an English-prefix match.
38
+
39
+ #### Migration Actions
40
+ - Do not expect assistant prose from a worker turn to become an observation.
41
+ - Catch worker-limit failures with `instanceof MemoryError` (or `MemoryLimitError`) / `error.code`, not message prefix.
42
+
43
+ ### 3. Channel lease release is fail-closed
44
+
45
+ `createMessagingRuntime` clears an in-memory route lease only after the lease store acknowledges `releaseLease`. A store throw increments `storageFailures`, leaves the token on the route, and retries on the next idle/`stop` path. TTL remains the cross-process backstop. An already-delivered reply is not rolled back.
46
+
47
+ #### Migration Actions
48
+ - Treat a failed release as “this process still holds the binding,” not as free.
49
+ - Do not log lease tokens.
50
+
51
+ ### 4. AG-UI input authority is opt-in server-side
52
+
53
+ `CreateAgUiHandlerOptions.inputPolicy.clientState: "ignore"` validates then discards client-supplied AG-UI state and tools before projection, and stops advertising client-provided tools. Default `"honor"` is byte-identical to 0.7.0.
54
+
55
+ #### Migration Actions
56
+ - Hosts that must not trust the browser for tools/state set `inputPolicy: { clientState: "ignore" }`.
57
+ - Leave the default if the 0.7.0 honor path is intended.
58
+
59
+ ### 5. Checkpoint foreign-scope reads no longer leak existence
60
+
61
+ A checkpoint or agent-run status load under a foreign ownership scope is a miss (or a generic CAS conflict), not a distinct “exists but not yours” error. `ERR_PRISM_AGENT_RUN_STATE` covers a missing run and a foreign-scope read.
62
+
63
+ #### Migration Actions
64
+ - Stop catching `Checkpoint ownership mismatch` (or equivalent) as an existence signal.
65
+
66
+ ---
67
+
68
+ ## Additive surfaces (inert unless wired)
69
+
70
+ ### 6. Messaging channels (`@arnilo/prism-channels`)
71
+
72
+ New eleventh publishable package. Transport-neutral runtime: deny-by-default sender authorization, owned session binding, serialized turns, current-run replies, one-use durable approvals, bounded attachment refs. Official Telegram adapter (private DMs; opt-in granted groups/topics; opt-in streaming drafts in private chats; bounded media; optional voice transcription/synthesis; opt-in notices to one already-bound pair). Experimental Signal adapter (pinned signal-cli, explicit policy gate, UUID DM filtering). See [messaging channels](messaging-channels.md), [Telegram](telegram-channel.md), [Signal](signal-channel.md), [operations](messaging-channel-operations.md).
73
+
74
+ #### Migration Actions
75
+ - Install `@arnilo/prism-channels@^0.8.0` only if the host wants a messaging ingress. Omitted, 0.7.0 hosts are unchanged.
76
+ - Host `authorize` stays deny-by-default. Group/topic traffic requires an explicit grant.
77
+
78
+ ### 7. Connected apps and work HTTP
79
+
80
+ Identity-bound MCP connected-app sessions admit host-selected transports and register prefixed tools. Google Workspace and Microsoft 365 HTTP adapters live under `@arnilo/prism-work/connectors`. Slack MCP wrap and Open Connector sidecar remain examples, not core. See [connected apps](connected-apps.md) and [work connectors](work-connectors.md).
81
+
82
+ #### Migration Actions
83
+ - Wire `connected-apps` only with a host allow-list. Do not add Open Connector / Klavis / Nango as Prism dependencies.
84
+
85
+ ### 8. Durable long runs
86
+
87
+ `AgentRunStateOptions.checkpointPolicy: "every-turn"` checkpoints at the provider-turn boundary. Host-only `decision: "continue"` resumes a crashed worker (never from AG-UI or the server boundary; rejected while an approval or ready tool call is pending). `RunOptions.turnPolicy` stops at a turn boundary with `stopReason: "host_policy"`. `snapshotRunBundle` returns a frozen redacted digest with zero store or network reads. `createClaimGroundingGuardrail` (stage `"output"`) blocks or flags numeric claims that no tool result or host evidence supports. `ErrorInfo.failureClass` types provider failures; `ModelCapabilities.toolCallStrictness` is advisory. See [durable runs](durable-runs.md), [run bundle](run-bundle.md), [guardrails](guardrails.md).
88
+
89
+ #### Migration Actions
90
+ - Omit `checkpointPolicy` / `turnPolicy` / the claim-grounding guardrail to keep 0.7.0 run behavior.
91
+ - `"continue"` is a host decision, not a client action.
92
+
93
+ ### 9. Work sandbox and vendored skills
94
+
95
+ `@arnilo/prism-work/sandbox` plus `createWorkComposition` run office/exec in an injected Docker sandbox; connectors stay on the host. The package ships `docx`, `xlsx`, `powerpoint`, `pdf` skills. See [work sandbox](work-sandbox.md) and [context and skills](context-and-skills.md).
96
+
97
+ ---
98
+
99
+ ## Operator / release honesty (not a host API break)
100
+
101
+ - `npm run test:postgres` writes gitignored `scripts/postgres-evidence.json` bound to `git rev-parse HEAD`. `release:gate` reports the Postgres surface as pass only when that evidence matches this tree. A stale phase baseline is **blocked**.
102
+ - Coverage artifact keys must equal live workspace package names (`@arnilo/prism-work`, not `@arnilo/prism-office`).
103
+
104
+ ## Upgrade steps
105
+
106
+ 1. Bump every `@arnilo/*` dependency and peer to `^0.8.0` (all **eleven** manifests cut together; a range that only *satisfies* 0.8.0 is refused by the release gate). The published predecessor is 0.7.0.
107
+ 2. If the host imported `@arnilo/prism-office` or `integrations/work` / coding-tools `document-reader`, apply §1 before building.
108
+ 3. Adopt §6–§9 only where the host wants channels, connected apps, durable-run checkpoints, or the work sandbox. Omitted, request bytes and tool lists stay 0.7.0.
109
+ 4. Re-read §2–§5 if the host runs observational-memory workers, messaging channels, AG-UI, or inspects checkpoint ownership errors.
110
+ 5. Build and run the host suite. No new session-store schema version ships in 0.8.0; channel journals and work HTTP state are new stores a 0.7.0 host never opened.
111
+ 6. Optional: `PRISM_TEST_POSTGRES_URL=… npm run test:postgres` then `npm run release:gate` to reproduce this-tree Postgres evidence.
112
+
113
+ ## Rollback
114
+
115
+ Pin the previous published line: `@arnilo/prism@0.7.0` and its siblings, exact pins per package. A 0.7.0 host does not load `@arnilo/prism-channels` or `@arnilo/prism-work`. Channel journal rows and work-package files written under 0.8.0 are invisible to 0.7.0, not rewritten. Session/checkpoint schema is unchanged across 0.7.0 → 0.8.0, so a pin rollback is store-safe for those adapters. Restore `@arnilo/prism-office` only from a 0.7.0 install — that package name is gone on 0.8.0.
116
+
117
+ Back up channel journals and work-sandbox volumes before a rollback if those 0.8.0 stores hold data you intend to keep.
118
+
119
+ ## Related APIs
120
+
121
+ - [Migration guide](migration.md): the era index of migration cuts with replacement tables and rollback notes.
122
+ - [Migrate Prism 0.6 to 0.7](migrate-to-0.7.md): ACP MCP allow-list, model-router facade refusals, host-completeness additions.
123
+ - [Release and install](release-and-install.md): packed surfaces, install rules, support matrix, and the offline test budget.
124
+ - [Messaging channels](messaging-channels.md), [Connected apps](connected-apps.md), [Work tools](work-tools.md), [Durable runs](durable-runs.md): owning pages for the 0.8.0 additions.
package/docs/migration.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Migration guide
2
2
 
3
+ ## 0.7.0 → 0.8.0 (messaging channels, connected apps, work family, durable runs)
4
+
5
+ **Prism 0.8.0 is a lockstep minor for all eleven publishable packages.** Node `>=22` stays the floor. The only import-map break is `@arnilo/prism-office` → `@arnilo/prism-work` (plus the work/document-reader subpath moves). A host that never imported those paths upgrades by moving every `@arnilo/*` dependency and peer to `^0.8.0`. The full guide — per-item actions, opt-in activation, and rollback — is [migrate-to-0.8.md](migrate-to-0.8.md).
6
+
7
+ What a 0.7.0 host must check before upgrading:
8
+
9
+ - **One import-map break.** Replace `@arnilo/prism-office/*`, `@arnilo/prism-core/integrations/work*`, and `@arnilo/prism-coding-tools/document-reader` with `@arnilo/prism-work` subpaths. Catch work-idempotency by `error.code`, not class. No pre-1.0 shim.
10
+ - **Eleventh package.** `@arnilo/prism-channels` is new and optional; omit it if the host has no messaging ingress.
11
+ - **Additive, inert by default:** connected-app MCP sessions, work HTTP adapters, turn-boundary checkpoints / `decision: "continue"`, turn-stop policy, run-bundle snapshots, claim-grounding guardrail, work sandbox/skills.
12
+ - **Behavioral pins inside existing surfaces:** observational-memory workers stay tool-only (text-only turns are successful no-ops); channel lease release clears in-memory state only after the store acknowledges; AG-UI `inputPolicy.clientState: "ignore"` is opt-in (default honor matches 0.7.0); a foreign checkpoint/run-status load is a miss, not an existence leak.
13
+
14
+ ## Next lockstep cut — work family package move
15
+
16
+ `@arnilo/prism-office` and the work/document-reader subpaths are removed with no pre-1.0 compatibility shim. Install `@arnilo/prism-work` with `@arnilo/prism` and update imports:
17
+
18
+ | Old import | Replacement |
19
+ | --- | --- |
20
+ | `@arnilo/prism-office/documents` | `@arnilo/prism-work/documents` |
21
+ | `@arnilo/prism-office/sheets` | `@arnilo/prism-work/sheets` |
22
+ | `@arnilo/prism-office/diagrams` | `@arnilo/prism-work/diagrams` |
23
+ | `@arnilo/prism-core/integrations/work` | `@arnilo/prism-work/connectors` |
24
+ | `@arnilo/prism-core/integrations/work/microsoft365` | `@arnilo/prism-work/connectors/microsoft365` |
25
+ | `@arnilo/prism-core/integrations/work/google-workspace` | `@arnilo/prism-work/connectors/google-workspace` |
26
+ | `@arnilo/prism-core/integrations/work/drafts` | `@arnilo/prism-work/connectors/drafts` |
27
+ | `@arnilo/prism-coding-tools/document-reader` | `@arnilo/prism-work/document-reader` |
28
+
29
+ The coding `createReadTool({ documentReader })` injection seam is unchanged; pass the reader created by the new subpath. Core keeps its durable adapter behind `createPostgresEnterpriseState({ pool }).workIdempotency` at `@arnilo/prism-core/enterprise/postgres` with type-only structural coupling.
30
+
31
+ **Match work-idempotency conflicts by `code`, not by error class.** The portable codes are unchanged across the move — `ERR_PRISM_WORK_IDEMPOTENCY` for a rejected claim/transition and `ERR_PRISM_WORK_IDEMPOTENCY_CONFLICT` for a lost race or stale claim token — and a host that catches them by `error.code` (the pattern `docs/work-tools.md` documents) needs no change. The *class* is adapter-specific: `createMemoryIdempotencyStore()` throws `WorkToolError` (an upstream `Error` subclass) while the PostgreSQL adapter throws `EnterprisePostgresError`, since `@arnilo/prism-core` cannot depend on `@arnilo/prism-work` at runtime. A pre-existing adapter that caught the old import path's error by `instanceof` must switch to `code` matching; `packages/prism-core/src/enterprise/postgres/__tests__/work-idempotency.integration.test.ts` runs both adapters through the same conflict scenarios and asserts the two agree.
32
+
33
+ ## 0.6.0 → 0.7.0 (host completeness, evidence, and capability boundaries)
34
+
35
+ **Prism 0.7.0 is a lockstep minor for all ten publishable packages.** Node `>=22` stays the floor; no import path was removed and no store schema changed, so a host that does not touch the ACP agent or the model-router facade upgrades by moving every `@arnilo/*` dependency and peer to `^0.7.0`. The full guide — per-item migration actions, opt-in activation, and rollback — is [migrate-to-0.7.md](migrate-to-0.7.md).
36
+
37
+ What a 0.6.0 host must check before upgrading:
38
+
39
+ - **Two hard refusals inside existing surfaces (the only host-breaking changes).** `@arnilo/prism-acp-agent` now matches `mcp.allow` destinations by WHATWG origin plus path-segment subtree (prefix lookalikes such as `https://mcp.example.com.attacker.invalid` no longer match, and allow entries with userinfo/query/fragment/ambiguous encodings fail `ConfigError` at parse time); `router.providerSource(model)` throws `ERR_PRISM_MODEL_ROUTER_ASYNC_REQUIRED` / `ERR_PRISM_MODEL_ROUTER_ASYNC_STATE` instead of silently bypassing budgets, rate limits, circuits, fallbacks, selection policies, or durable state — move those call sites to `await router.resolve(...)`. An ACP deployment without an explicit provider no longer silently runs `createMockProvider()`; mock mode is explicit.
40
+ - **Behavioral tightenings inside existing surfaces** (agent tool narrowing is monotonic per run, RAG queries are authorized in both legs, memory corrections/revocations propagate, import-fidelity reports replace silent drops, model-router/worker accounting is aggregated): these need a host read-through, not a code change.
41
+ - **Additive declarations only.** No export was removed in 0.7.0; the compat baselines were regenerated because existing declaration groups gained members (new fields on options/results and new subpath exports for the attention compiler, memory fabric, work scopes, and supervisor spawn tools).
42
+ - **Opt-in additions are inert by default**: attention compiler (`AgentConfig`/`RunOptions`), `@arnilo/prism-memory/fabric`, the observational-memory work-scope index, and the supervisor `spawn_agent`/`wait_agent`/`cancel_agent` tools. Omitted, request bytes, stores, and tool lists are unchanged.
43
+ - **Channel adapters (Telegram/Signal) are not in 0.7.0.**
44
+
3
45
  ## 0.5.6 → 0.6.0 (Node 22 floor; folds the never-published 0.5.7)
4
46
 
5
47
  **Prism 0.6.0 requires Node `>=22`.** Every publishable package declares `"engines": { "node": ">=22" }`; a Node 20 host gets an `EBADENGINE` warning from npm (a hard failure under `engine-strict`) and an unsupported runtime. Node 20 reached upstream end-of-life on 2026-04-30, so the 0.6.0 line moves to Node 22 (maintenance LTS to 2027-04-30) while Node 24 stays the CI default (active LTS to 2028-04-30). The full 0.5.6 → 0.6.0 guide — third-party floors, the removed office peer, the additive host knobs, and upgrade/rollback steps — lives in [migrate-to-0.6.md](migrate-to-0.6.md).
@@ -48,7 +90,7 @@ Stream tokens coalesce on persist (adjacent `text`/`thinking` deltas merge). Rep
48
90
  ## 0.5.0 → 0.5.1 (additive)
49
91
 
50
92
 
51
- Kernel constructs valid provider requests: session correlation, default cache breakpoints, and `thinkingLevel` on `AgentConfig` / `RunOptions`. Clay may drop host-only `createSessionCachePolicy`. OpenCode Go raw `generate` without `sessionId` throws `ProviderRequirementError` (`ERR_PRISM_PROVIDER_REQUIREMENT`) before fetch instead of an upstream 400. Observational memory uses derived `om:{session.id}`; LLM compaction uses the agent session id. See [migrate-to-0.5.md](migrate-to-0.5.md#8-provider-request-construction--additive-plan-066--051).
93
+ Kernel constructs valid provider requests: session correlation, default cache breakpoints, and `thinkingLevel` on `AgentConfig` / `RunOptions`. Hosts may drop a host-side `createSessionCachePolicy` overlay. OpenCode Go raw `generate` without `sessionId` throws `ProviderRequirementError` (`ERR_PRISM_PROVIDER_REQUIREMENT`) before fetch instead of an upstream 400. Observational memory uses derived `om:{session.id}`; LLM compaction uses the agent session id. See [migrate-to-0.5.md](migrate-to-0.5.md#8-provider-request-construction--additive-plan-066--051).
52
94
 
53
95
  ## What it does
54
96
 
@@ -36,7 +36,7 @@ import { createModelRegistry, type ModelConfig } from "@arnilo/prism";
36
36
  | --- | --- |
37
37
  | `provider` / `model` | Required registry key. |
38
38
  | `displayName` | Human-readable label. |
39
- | `capabilities` | Input/output modes (`text`, `image`, `audio`, `file`, `document`) plus reasoning/tools/streaming booleans and optional `structuredOutput` (`true` or `"json_schema"`) for native JSON-schema requests. |
39
+ | `capabilities` | Input/output modes (`text`, `image`, `audio`, `file`, `document`) plus reasoning/tools/streaming booleans, optional `structuredOutput` (`true` or `"json_schema"`) for native JSON-schema requests, and advisory `toolCallStrictness`. |
40
40
  | `limits` | Context and output-token limits (`ModelLimits`). |
41
41
  | `cost` | Input/output/cache read/cache write pricing. |
42
42
  | `cache` | Generic `ModelCacheCapabilities`. |
@@ -101,9 +101,19 @@ const registry = createModelRegistry([model], { duplicate: "error" });
101
101
  const resolved = registry.resolve("demo", "demo-large");
102
102
  ```
103
103
 
104
+ ## Tool-call reliability metadata
105
+
106
+ `ModelCapabilities.toolCallStrictness?: "strict" | "lenient" | "legacy"` is advisory evidence metadata for hosts pinning models. Omission means **unknown** and must never be inferred as `"strict"`; it changes neither tool disclosure, argument validation, parallel dispatch, retries, nor provider requests.
107
+
108
+ - `"strict"`: the provider catalog has a network-free conformance fixture covering parallel-call reconstruction, a schema-shaped argument object, and an empty `{}` argument object.
109
+ - `"lenient"`: a catalog has tested tool support but a known relaxed behavior; hosts should retain extra guardrails.
110
+ - `"legacy"`: a catalog has tested compatibility-only tool behavior; hosts should avoid relying on strict multi-call/schema semantics.
111
+
112
+ Current first-party evidence is generated at [tool-call coverage matrix](_evidence/toolcall-coverage-2026-09-17.md). Only NeuralWatt's curated catalog is stamped `"strict"`: its fixture checks all three behaviors. Every other first-party static catalog with `tools: true` is explicitly unstamped-unknown until it has that fixture coverage. Dynamic discovery records remain unknown because provider responses are untrusted catalog metadata. Hosts must still validate every tool argument against its schema.
113
+
104
114
  ## Extension and configuration notes
105
115
 
106
- Provider packages register models through `ProviderPackageAPI.registerModel(model)`. The extension kernel stores those records in the host-owned registries. Static package metadata is allowed; dynamic model discovery remains provider/host code outside Prism core.
116
+ Provider packages register models through `ProviderPackageAPI.registerModel(model). The extension kernel stores those records in the host-owned registries. Static package metadata is allowed; dynamic model discovery remains provider/host code outside Prism core.
107
117
 
108
118
  `ModelConfig.compat` remains for provider-owned inert JSON. Prefer typed fields (`capabilities`, `limits`, `cost`, `cache`) for generic behavior shared across providers.
109
119