@arnilo/prism 0.7.0 → 0.9.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 +73 -0
- package/README.md +12 -11
- package/dist/agent-approval.d.ts +15 -2
- package/dist/agent-approval.js +5 -1
- package/dist/agent-event-source.d.ts +9 -1
- package/dist/agent-event-source.js +10 -3
- package/dist/agent-loops.js +7 -4
- package/dist/agent-run-lifecycle.d.ts +15 -1
- package/dist/agent-run-lifecycle.js +91 -10
- package/dist/agent-run-state.d.ts +34 -2
- package/dist/agent-run-state.js +68 -6
- package/dist/agent-session/helpers.js +20 -1
- package/dist/agent-session/session/assemble.js +250 -27
- package/dist/agent-session/session/persist.d.ts +27 -0
- package/dist/agent-session/session/persist.js +94 -12
- package/dist/agent-session/session/provider-round.d.ts +14 -4
- package/dist/agent-session/session/provider-round.js +197 -25
- package/dist/agent-session/session/tool-round.js +24 -2
- package/dist/agent-session/session/types.d.ts +36 -2
- package/dist/agent-session/session.d.ts +40 -4
- package/dist/agent-session/session.js +78 -5
- package/dist/attention-compiler.d.ts +51 -2
- package/dist/attention-compiler.js +282 -21
- package/dist/cache-helpers.d.ts +4 -2
- package/dist/cache-helpers.js +8 -6
- package/dist/checkpoint-restore.d.ts +45 -0
- package/dist/checkpoint-restore.js +54 -0
- package/dist/checkpoints.js +7 -11
- package/dist/context-budget.d.ts +2 -1
- package/dist/context-budget.js +24 -2
- package/dist/contracts-core/agent.d.ts +30 -0
- package/dist/contracts-core/attention.d.ts +95 -0
- package/dist/contracts-core/content.d.ts +15 -0
- package/dist/contracts-core/guardrail-packs.d.ts +41 -0
- package/dist/contracts-core/guardrail-packs.js +2 -0
- package/dist/contracts-core/loop.d.ts +42 -0
- package/dist/contracts-core/provider.d.ts +25 -0
- package/dist/contracts-core/run-limits.d.ts +21 -0
- package/dist/contracts-core/session.d.ts +23 -5
- package/dist/contracts-core/session.js +21 -2
- package/dist/contracts-core/usage.d.ts +40 -0
- package/dist/contracts-core/usage.js +8 -0
- package/dist/contracts-core.d.ts +2 -0
- package/dist/contracts-core.js +2 -0
- package/dist/contracts-protocol.d.ts +90 -4
- package/dist/contracts-run-state.d.ts +82 -6
- package/dist/evidence-grounding.d.ts +29 -0
- package/dist/evidence-grounding.js +162 -0
- package/dist/guardrail-packs/coding-standard.d.ts +3 -0
- package/dist/guardrail-packs/coding-standard.js +63 -0
- package/dist/guardrail-packs/destructive-commands.d.ts +3 -0
- package/dist/guardrail-packs/destructive-commands.js +46 -0
- package/dist/guardrail-packs/errors.d.ts +7 -0
- package/dist/guardrail-packs/errors.js +9 -0
- package/dist/guardrail-packs/index.d.ts +4 -0
- package/dist/guardrail-packs/index.js +15 -0
- package/dist/guardrail-packs/secrets-hygiene.d.ts +3 -0
- package/dist/guardrail-packs/secrets-hygiene.js +23 -0
- package/dist/guardrail-packs/types.d.ts +16 -0
- package/dist/guardrail-packs/types.js +2 -0
- package/dist/guardrail-packs/validation-respect.d.ts +3 -0
- package/dist/guardrail-packs/validation-respect.js +53 -0
- package/dist/guardrails.d.ts +20 -1
- package/dist/guardrails.js +268 -0
- package/dist/host-composition.d.ts +13 -0
- package/dist/host-composition.js +33 -2
- package/dist/index.d.ts +19 -10
- package/dist/index.js +11 -6
- package/dist/input.d.ts +8 -1
- package/dist/input.js +68 -6
- package/dist/middleware.d.ts +37 -2
- package/dist/middleware.js +41 -0
- package/dist/node/session-store-jsonl.js +18 -3
- package/dist/observability.js +6 -0
- package/dist/provider-events.d.ts +11 -3
- package/dist/provider-events.js +62 -4
- package/dist/providers/openai-compatible.js +6 -3
- package/dist/providers/transport.d.ts +3 -1
- package/dist/providers/transport.js +36 -0
- package/dist/redaction.js +18 -2
- package/dist/run-bundle.d.ts +89 -0
- package/dist/run-bundle.js +150 -0
- package/dist/run-limits.d.ts +11 -1
- package/dist/run-limits.js +46 -0
- package/dist/session-stores.d.ts +12 -1
- package/dist/session-stores.js +21 -4
- package/dist/testing/agent-event-source-conformance.js +41 -2
- package/dist/testing/prefix-stability-conformance.d.ts +30 -0
- package/dist/testing/prefix-stability-conformance.js +104 -0
- package/dist/testing/session-store-conformance.d.ts +3 -2
- package/dist/testing/session-store-conformance.js +48 -0
- package/dist/testing/state-concurrency-conformance.js +5 -12
- package/dist/tools.d.ts +5 -0
- package/dist/tools.js +11 -3
- package/dist/usage-estimation.d.ts +29 -0
- package/dist/usage-estimation.js +79 -0
- package/docs/ag-ui.md +5 -0
- package/docs/agent-events.md +68 -1
- package/docs/agent-loops.md +33 -0
- package/docs/agent-session-runtime.md +5 -3
- package/docs/attention-compiler.md +89 -8
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-security.md +1 -0
- package/docs/coding-tools.md +0 -1
- package/docs/compaction-and-retry.md +1 -1
- package/docs/compaction-observational-memory.md +34 -7
- package/docs/connected-apps.md +116 -0
- package/docs/context-and-skills.md +13 -0
- package/docs/core.md +1 -1
- package/docs/diagrams.md +6 -6
- package/docs/document-reader.md +9 -9
- package/docs/documents.md +32 -11
- package/docs/durable-runs.md +129 -0
- package/docs/embeddings.md +5 -0
- package/docs/enterprise-postgres-state.md +4 -0
- package/docs/evaluations.md +5 -0
- package/docs/execution-timeline.md +84 -1
- package/docs/guardrails.md +71 -2
- package/docs/history/079-messaging-primitive-review.md +391 -0
- package/docs/history/080-messaging-followon-primitive-review.md +234 -0
- package/docs/history/081-connected-apps-primitive-review.md +74 -0
- package/docs/history/083-prism-work-primitive-review.md +84 -0
- package/docs/history/084-primitive-review.md +96 -0
- package/docs/history/085-honesty-and-cut-primitive-review.md +91 -0
- package/docs/history/README.md +5 -0
- package/docs/history/release-handoffs.md +38 -0
- package/docs/host-compositions.md +8 -6
- package/docs/host-security.md +2 -2
- package/docs/index.md +66 -29
- package/docs/input-and-prompt-assembly.md +3 -3
- package/docs/knowledge-sync.md +4 -0
- package/docs/live-testing.md +5 -3
- package/docs/mcp-tools.md +1 -0
- package/docs/messaging-channel-operations.md +166 -0
- package/docs/messaging-channels.md +150 -0
- package/docs/middleware-hooks.md +38 -2
- package/docs/migrate-to-0.8.md +124 -0
- package/docs/migrate-to-0.9.md +210 -0
- package/docs/migration.md +43 -0
- package/docs/model-registry.md +12 -2
- package/docs/multi-agent-patterns.md +25 -2
- package/docs/node-jsonl-session-store.md +7 -1
- package/docs/observability.md +7 -3
- package/docs/openapi-tools.md +1 -1
- package/docs/operations.md +1 -3
- package/docs/options-index.md +36 -3
- package/docs/peer-dependencies.md +6 -6
- package/docs/policy-and-audit.md +13 -1
- package/docs/postgres-persistence.md +1 -1
- package/docs/prefix-stability-conformance.md +93 -0
- package/docs/provider-caching.md +4 -4
- package/docs/provider-conformance.md +16 -0
- package/docs/provider-layer.md +2 -2
- package/docs/provider-packages.md +20 -20
- package/docs/providers/neuralwatt.md +5 -1
- package/docs/public-contracts.md +2 -2
- package/docs/rag.md +102 -4
- package/docs/release-and-install.md +55 -47
- package/docs/run-bundle.md +92 -0
- package/docs/runs-and-usage.md +57 -6
- package/docs/scoped-agent-memory.md +262 -0
- package/docs/server.md +2 -0
- package/docs/session-store-conformance.md +1 -2
- package/docs/session-stores.md +17 -17
- package/docs/sheets.md +9 -9
- package/docs/signal-channel.md +112 -0
- package/docs/speech.md +5 -1
- package/docs/sqlite-persistence.md +1 -1
- package/docs/supervisors.md +32 -12
- package/docs/telegram-channel.md +157 -0
- package/docs/testing.md +2 -2
- package/docs/tools.md +17 -0
- package/docs/wiki.md +1 -1
- package/docs/work-artifacts-and-review.md +1 -1
- package/docs/work-connectors.md +9 -9
- package/docs/work-sandbox.md +115 -0
- package/docs/work-tools.md +38 -16
- package/docs/workflows.md +5 -0
- package/package.json +9 -3
- package/templates/business-worker/manifest.json +2 -1
- package/templates/business-worker/src/agent.ts.tmpl +1 -1
- package/templates/business-worker/src/tests/agent.test.ts.tmpl +1 -1
|
@@ -25,26 +25,26 @@ Do not use provider packages as a package manager, credential store, env loader,
|
|
|
25
25
|
|
|
26
26
|
| adapter package | version |
|
|
27
27
|
| --- | --- |
|
|
28
|
-
| `@arnilo/prism-providers/ai-sdk` | 0.
|
|
29
|
-
| `@arnilo/prism-providers/alibaba` | 0.
|
|
30
|
-
| `@arnilo/prism-providers/anthropic` | 0.
|
|
31
|
-
| `@arnilo/prism-providers/azure` | 0.
|
|
32
|
-
| `@arnilo/prism-providers/bedrock` | 0.
|
|
33
|
-
| `@arnilo/prism-providers/clinepass` | 0.
|
|
34
|
-
| `@arnilo/prism-providers/commandcode` | 0.
|
|
35
|
-
| `@arnilo/prism-providers/deepseek` | 0.
|
|
36
|
-
| `@arnilo/prism-providers/google` | 0.
|
|
37
|
-
| `@arnilo/prism-providers/hyper` | 0.
|
|
38
|
-
| `@arnilo/prism-providers/kimi` | 0.
|
|
39
|
-
| `@arnilo/prism-providers/model-discovery` | 0.
|
|
40
|
-
| `@arnilo/prism-providers/neuralwatt` | 0.
|
|
41
|
-
| `@arnilo/prism-providers/ollama` | 0.
|
|
42
|
-
| `@arnilo/prism-providers/openai` | 0.
|
|
43
|
-
| `@arnilo/prism-providers/opencode-go` | 0.
|
|
44
|
-
| `@arnilo/prism-providers/openrouter` | 0.
|
|
45
|
-
| `@arnilo/prism-providers/vertex` | 0.
|
|
46
|
-
| `@arnilo/prism-providers/xai` | 0.
|
|
47
|
-
| `@arnilo/prism-providers/zai` | 0.
|
|
28
|
+
| `@arnilo/prism-providers/ai-sdk` | 0.9.0 |
|
|
29
|
+
| `@arnilo/prism-providers/alibaba` | 0.9.0 |
|
|
30
|
+
| `@arnilo/prism-providers/anthropic` | 0.9.0 |
|
|
31
|
+
| `@arnilo/prism-providers/azure` | 0.9.0 |
|
|
32
|
+
| `@arnilo/prism-providers/bedrock` | 0.9.0 |
|
|
33
|
+
| `@arnilo/prism-providers/clinepass` | 0.9.0 |
|
|
34
|
+
| `@arnilo/prism-providers/commandcode` | 0.9.0 |
|
|
35
|
+
| `@arnilo/prism-providers/deepseek` | 0.9.0 |
|
|
36
|
+
| `@arnilo/prism-providers/google` | 0.9.0 |
|
|
37
|
+
| `@arnilo/prism-providers/hyper` | 0.9.0 |
|
|
38
|
+
| `@arnilo/prism-providers/kimi` | 0.9.0 |
|
|
39
|
+
| `@arnilo/prism-providers/model-discovery` | 0.9.0 |
|
|
40
|
+
| `@arnilo/prism-providers/neuralwatt` | 0.9.0 |
|
|
41
|
+
| `@arnilo/prism-providers/ollama` | 0.9.0 |
|
|
42
|
+
| `@arnilo/prism-providers/openai` | 0.9.0 |
|
|
43
|
+
| `@arnilo/prism-providers/opencode-go` | 0.9.0 |
|
|
44
|
+
| `@arnilo/prism-providers/openrouter` | 0.9.0 |
|
|
45
|
+
| `@arnilo/prism-providers/vertex` | 0.9.0 |
|
|
46
|
+
| `@arnilo/prism-providers/xai` | 0.9.0 |
|
|
47
|
+
| `@arnilo/prism-providers/zai` | 0.9.0 |
|
|
48
48
|
<!-- generated:package-truth:providers end -->
|
|
49
49
|
|
|
50
50
|
|
|
@@ -95,7 +95,7 @@ after resolved fields so per-call values and overrides win.
|
|
|
95
95
|
| --- | --- |
|
|
96
96
|
| Provider stream | Prism text, thinking (`delta.reasoning_content` → `providerThinkingDelta`), tool-call delta/final, `usage`, `done`, redacted `error` with HTTP-status `code` for retry classification. |
|
|
97
97
|
| Block preservation | Text, thinking, assistant `tool_call` → `tool_calls`, `tool_result` → role `tool` messages, images when `capabilities.input` includes `"image"`. |
|
|
98
|
-
| Model catalog | Featured aliases declare provider id, display name, context limit, text/image input support, tools, reasoning/fast variants, streaming, implicit cache,
|
|
98
|
+
| Model catalog | Featured aliases declare provider id, display name, context limit, text/image input support, tools, reasoning/fast variants, streaming, implicit cache, NeuralWatt JSON-mode compat metadata where documented, and conformance-derived `toolCallStrictness: "strict"`. |
|
|
99
99
|
| Pricing | Static aliases do not guess rates. Exact per-alias input/output/cache-read prices are advertised by NeuralWatt's `/v1/models` response and mapped by `listNeuralWattModels()` when present. |
|
|
100
100
|
| SSE comments | `: energy` / `: cost` comment lines are parsed by `neuralWattEventsWithTelemetry()` into `neuralwatt:telemetry` events; the standard `neuralWattEvents()` stream (used by `generate()`) tolerates them without spurious events. |
|
|
101
101
|
| `[DONE]` | Terminates the stream; final `providerDone(usage)` always emitted on a clean stream. |
|
|
@@ -292,6 +292,10 @@ prior tool turns through a multi-turn loop:
|
|
|
292
292
|
the stringified `tool_result` — matching the OpenAI requirement that a tool result
|
|
293
293
|
follows the call that produced it. `tool_result` blocks must appear in `role: "tool"
|
|
294
294
|
messages; `tool_call` blocks must be the only content on their assistant message.
|
|
295
|
+
- **Catalog evidence.** Curated aliases carry `capabilities.toolCallStrictness: "strict"`
|
|
296
|
+
because the network-free conformance fixtures cover parallel indexed calls,
|
|
297
|
+
schema-shaped arguments, and empty `{}` arguments. This is adapter evidence, not a
|
|
298
|
+
provider SLA: hosts still validate every call. See [tool-call coverage](../_evidence/toolcall-coverage-2026-09-17.md).
|
|
295
299
|
|
|
296
300
|
### Energy and cost telemetry
|
|
297
301
|
|
package/docs/public-contracts.md
CHANGED
|
@@ -154,10 +154,10 @@ Important request shapes:
|
|
|
154
154
|
| `PersistenceQuery` | Common pagination controls: `cursor?`, `limit?`, `order?: "asc" \| "desc"`. |
|
|
155
155
|
| `OwnershipScope` | Multi-tenant scope: `tenantId?`, `accountId?`, `userId?`. Included in records and queries. |
|
|
156
156
|
| `SessionRecord` / `SessionQuery` | Stored session and query filters (parent, agent definition, retention policy, timestamps, ownership). `SessionRecord.version` (with `appendSession` `expectedVersion`) is the optimistic metadata CAS: 0 = create-only, N = exact-version update; mismatch throws `SessionMetadataConflictError` (`metadata_conflict`). |
|
|
157
|
-
| `SessionIndex` / `SessionSearchQuery` / `SessionSearchHit` | Bounded optional session search seam (`search` / `SessionStore.searchSessions?`). Filters: workspace (`metadata.workspaceRoot`), time, provider/model, label/summary, optional FTS `query`, ownership. Hits return `sessionId` + optional `leafId` for resume
|
|
157
|
+
| `SessionIndex` / `SessionSearchQuery` / `SessionSearchHit` | Bounded optional session search seam (`search` / `SessionStore.searchSessions?`). Filters: workspace (`metadata.workspaceRoot`), time, provider/model, label/summary, entry-kind (`kind`, e.g. annotation search), optional FTS `query`, ownership. Hits return `sessionId` + optional `leafId` for resume, and on a text match the matched entry pointer (`entryId`, `runId`, 1-based `turn`, store `score`) with a bounded matched-text `snippet`; never credentials. Caps via `resolveSessionSearchQuery` / `DEFAULT_*` / `HARD_MAX_*` session-search constants. SQLite/Postgres index (FTS5 / `tsvector`); memory and JSONL scan linearly. |
|
|
158
158
|
| `contextBudget` / `getContextBudgetReport` / `ContextBudgetError` | Opt-in assembler budget on `AssembleProviderInputOptions`; deterministic eviction; omission report in `ProviderRequest.metadata` (kinds/ids/sizes only). |
|
|
159
159
|
| `AgentSession.steer` / `SteerOptions` / pending-steer caps | Mid-run enqueue into active run; optional `softInterrupt`; default 8 msgs / 64 KiB UTF-8. |
|
|
160
|
-
| `SessionSearchUnsupportedError` / `sessionSearchMode` | Memory opt-out
|
|
160
|
+
| `SessionSearchUnsupportedError` / `sessionSearchMode` | Memory opt-out (`sessionSearchMode: "unsupported"`); typed throw (not empty success). Memory linear caps are host-overridable via `CreateMemorySessionStoreOptions.search`; the JSONL store searches linearly with the contract default caps. |
|
|
161
161
|
| `BranchRecord` / `BranchQuery` | Branch handle/leaf pointer and query filters (session, name, parent branch, leaf presence). |
|
|
162
162
|
| `SessionEntryQuery` | Paginated entry filters: `sessionId`, `runId`, `parentId`, `leafId`, `kind`, timestamp range, ownership. |
|
|
163
163
|
| `RunRecord` / `RunQuery` | Stored run and filters: session, branch, status, timestamps, ownership. |
|
package/docs/rag.md
CHANGED
|
@@ -28,6 +28,10 @@ Document lifecycle:
|
|
|
28
28
|
| `deleteSource({ sourceId, store, scope })` | Deletes only matching IDs under exact tenant/resource/corpus scope. |
|
|
29
29
|
| `replaceDocument({ uri, loader, parser, store, scope, ... })` | Loads through a host seam, parses, chunks, and atomically replaces. `sourceId` is required unless loader supplies one. |
|
|
30
30
|
| `syncKnowledge({ connector, checkpoints, checkpoint, store, embedder, scope })` | Paged connector import; cursor CAS only after each committed page. See [Knowledge synchronization](knowledge-sync.md). |
|
|
31
|
+
| `createDeletionPropagator({ scope, vectorStore, authorization })` | Privileged deletion orchestration: lineage-closed tombstone set + registered handlers. See [Deletion propagation](#deletion-propagation). |
|
|
32
|
+
| `createRagDeletionHandler({ store, scope, statusStore? })` | The RAG layer's propagation handler: removes a deleted source's chunk rows and ingestion status. |
|
|
33
|
+
| `createLocalReranker({ model?, runtime?, … })` | Zero-service default reranker: in-process cross-encoder behind the `LocalRerankRuntime` seam. See [Local reranker](#local-reranker). |
|
|
34
|
+
| `resolveReranker(config)` | Declarative reranker config (`kind: "local" \| "tei" \| "openai-compatible" \| "voyage" \| "fake" \| "none"`) → `Reranker`. |
|
|
31
35
|
| `createGoogleDriveConnector({ tokenProvider, resolveAccess })` | Drive `files.list` + `changes.list` connector. Host maps permissions; watch payloads are not authorization. |
|
|
32
36
|
| `DocumentLoader` / `Parser` | Small host-replaceable seams. `@arnilo/prism-memory/rag/loaders` and `/rag/parsers` export reference adapters. |
|
|
33
37
|
| `textParser` / `markdownParser` / `htmlParser` / `pdfParser` | UTF-8 text, Markdown, script/style-stripping HTML, and uncompressed-text PDF parsers. |
|
|
@@ -83,6 +87,98 @@ Default/hard ceilings include 1,000/16,384 chunk characters, 100/4,096 overlap,
|
|
|
83
87
|
}
|
|
84
88
|
```
|
|
85
89
|
|
|
90
|
+
## Deletion propagation
|
|
91
|
+
|
|
92
|
+
`deleteSource()` removes one source's chunk rows. Derived artifacts (summaries, observational-memory entries, compiled wiki pages, host projections) are not chunk rows, so they need an explicit, privileged propagation pass:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { createDeletionPropagator, createMemoryVectorStore } from "@arnilo/prism-memory";
|
|
96
|
+
import { createRagDeletionHandler } from "@arnilo/prism-memory/rag";
|
|
97
|
+
import { createWikiDeletionHandler } from "@arnilo/prism-memory/wiki";
|
|
98
|
+
|
|
99
|
+
const store = createMemoryVectorStore();
|
|
100
|
+
const propagator = createDeletionPropagator({
|
|
101
|
+
scope: { tenantId: "t1", resourceId: "docs", threadId: "handbook" },
|
|
102
|
+
vectorStore: store,
|
|
103
|
+
authorization: { tenantId: "t1", principalId: "p1", groupIds: ["eng"] }, // host-verified; ACL-store grants are enforced here
|
|
104
|
+
});
|
|
105
|
+
propagator.register(createRagDeletionHandler({ store, scope: ragScope }));
|
|
106
|
+
propagator.register(createWikiDeletionHandler({ workspaceRoot }));
|
|
107
|
+
|
|
108
|
+
const result = await propagator.propagate("doc:erp-lead");
|
|
109
|
+
// { sourceId, ids, tombstoned, layers: { rag: 4, wiki: 1 }, batched: true }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- `propagate(sourceId)` expands the source through `_lineage.sourceIds` (`collectInvalidationIds`, depth 8) into a closed id set, tombstones **all** of it with reason `forgotten` inside one store transaction, then runs every registered handler with `{ sourceId, ids, scope, signal }`. Handlers return how many artifacts they removed (reported per `kind` in `layers`).
|
|
113
|
+
- Tombstones, not deletions, for derived rows: rows stay for explainability (`recall({ explain: true })` reports the invalidation), and lineage links never dangle. Handlers own physical removal (chunk rows, files, ledger entries).
|
|
114
|
+
- Retrieval is belt-and-suspenders: `retrieveContext()` reads per-scope invalidations before assembly and drops any candidate whose record id, `_lineage.sourceIds`, or `_rag.sourceId` is tombstoned — so a delete that lands after the query legs read rows still returns zero hits.
|
|
115
|
+
- `HARD_PROPAGATION_EDGES` (4,096) is the one-pass privileged ceiling; over it the whole delete rejects (fail-closed), never a half-tombstoned document. Each store `invalidate` call carries at most `HARD_INVALIDATION_BATCH` (64) entries.
|
|
116
|
+
- Deletion is privileged: `authorization` is required, tenant-checked, and enforced through the store's existing `checkSourceAccess` ACL when the store declares `authorization: "acl"` (missing grant → `MemoryScopeError` before anything is written). Retrieval paths never construct a propagator.
|
|
117
|
+
|
|
118
|
+
## Grant recheck and re-pointing
|
|
119
|
+
|
|
120
|
+
Retrieval never trusts a grant snapshot. `retrieveContext()` re-asks the store for **each distinct source** it is about to inject, on both sides of the reranker:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const result = await retrieveContext("approval policy", {
|
|
124
|
+
embedder,
|
|
125
|
+
store,
|
|
126
|
+
scope,
|
|
127
|
+
authorization: hostVerifiedPrincipal, // every query re-reads the live grant
|
|
128
|
+
onAccessDenied: (denial) => audit.write({ kind: "rag.acl_denied", ...denial }),
|
|
129
|
+
});
|
|
130
|
+
// mid-turn revoke → the source is gone from this and every later result
|
|
131
|
+
await store.setSourceAccess(thread, [{ sourceId: "doc:payroll", principalIds: [], accessVersion: 2 }]);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- Candidate pre-filter and, when a reranker ran, a fresh post-rerank gate (`createAccessRecheck()`, one instance per query). The post-rerank gate re-reads on purpose: a grant revoked *while the reranker was running* must not leak its text into the prompt.
|
|
135
|
+
- Cost is per source, not per hit: 200 candidates over 50 sources cost 50 lookups per gate, not 200. The in-memory hook does that inside the 5ms budget for 50 sources; a PostgreSQL store pays one indexed `checkSourceAccess` per source per gate.
|
|
136
|
+
- Fail closed, never silently: an absent/revoked/version-mismatched grant and a **thrown** store error both withhold the hits, and every withheld source is reported once through `onAccessDenied` as `{ sourceId, scope, reason: "no_grant" | "check_failed", hits, error? }` (`error` is redacted and capped at 256 chars). The query still completes with the remaining hits. Abort still aborts — it is not reclassified as a denial.
|
|
137
|
+
- There is no per-request off switch: passing `authorization` is what turns the gate on, and the only knob is the audit sink. A store that declares `authorization: "acl"` without `checkSourceAccess` fails closed before ranking.
|
|
138
|
+
- The store's own query/lexical predicate remains the first line of defense (unauthorized text never leaves the store); the boundary recheck also covers stores whose query leg ignores grants, and revokes that land after the query legs have read.
|
|
139
|
+
|
|
140
|
+
When a source's grant identity moves (`doc:a` → `doc:b`, a document re-filed under a new source id), `repointSource()` makes the derived artifacts follow **without re-embedding**:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { repointSource } from "@arnilo/prism-memory";
|
|
144
|
+
import { createWikiRepointHandler } from "@arnilo/prism-memory/wiki";
|
|
145
|
+
|
|
146
|
+
const moved = await repointSource({
|
|
147
|
+
scope: { tenantId: "t1", resourceId: "docs", threadId: "handbook" },
|
|
148
|
+
vectorStore: store,
|
|
149
|
+
from: "doc:a",
|
|
150
|
+
to: "doc:b",
|
|
151
|
+
authorization: hostVerifiedPrincipal, // must admit BOTH ids on an ACL store
|
|
152
|
+
handlers: [createWikiRepointHandler({ workspaceRoot })],
|
|
153
|
+
});
|
|
154
|
+
// { from, to, movedChunks, rewrittenEdges, layers: { wiki: 1 }, batched: true }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- Chunk rows keep their text, embeddings, offsets, and generation: the row id (`doc:a#0001` → `doc:b#0001`), `_rag.sourceId`, and `_rag.citationId` are rewritten, old ids are deleted, and the whole move lands in one store transaction (`batched: true`) or not at all.
|
|
158
|
+
- Lineage edges (`_lineage.sourceIds`) on derived rows move from `from` to `to` in the same pass, so `createDeletionPropagator()` stays correct afterwards: deleting `doc:b` still tombstones the derived rows, deleting `doc:a` no longer touches them.
|
|
159
|
+
- Privileged like deletion propagation: on a store that declares `authorization: "acl"` the caller must pass an `authorization` that admits **both** the source and the destination, and re-point never creates or copies grants — grant the destination first or the move fails closed. `HARD_REPOINT_RECORDS` (4,096) bounds one pass; over the cap nothing moves.
|
|
160
|
+
- Row ids that already exist at the destination (other than rows of the moved source) abort the move instead of overwriting (`MemoryValidationError`).
|
|
161
|
+
- `createWikiRepointHandler()` moves the wiki projection: manifest `rawSources`/`anchors`, the `sourceFileHashes` entry, every page that names the old path, the index pages, and a `Repointed` log line — no recompilation. `pathsFor(sourceId → paths)` maps ids to paths when they differ.
|
|
162
|
+
- Observational memory: `listInvalidatedIds(vectorStore, scope)` returns the ids a scope currently withholds (`corrected` sources stay) — pass them as `invalidatedIds` to `buildObservationalMemoryProjection()` / recall so already-emitted blocks that rest on a revoked source go stale on the next build instead of being re-injected.
|
|
163
|
+
|
|
164
|
+
## Local reranker
|
|
165
|
+
|
|
166
|
+
The default reranker runs in-process — no service, no credential, no per-query egress:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { createHashEmbedder, createMemoryVectorStore } from "@arnilo/prism-memory";
|
|
170
|
+
import { resolveReranker, retrieveContext } from "@arnilo/prism-memory/rag";
|
|
171
|
+
|
|
172
|
+
const reranker = resolveReranker({ kind: "local" }); // Xenova/bge-reranker-base via transformers.js
|
|
173
|
+
const result = await retrieveContext("How do approvals work?", { embedder, store, scope, reranker });
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- `resolveReranker({ kind: "local" })` is the zero-config path. The model runtime is a host seam exactly like `Embedder`: `createLocalReranker({ model?, runtime?, onLoad?, cacheDir?, dtype?, device?, allowRemoteModels? })`. Pass `runtime: { load(model) → { id, score({ query, documents, signal }) } }` to inject a runtime the host already owns (transformers.js, onnxruntime-node, llama.cpp). With no `runtime`, the built-in loader resolves `@huggingface/transformers` at first use — the package declares no inference dependency (no new dependency name in any manifest) and nothing resolves it at build/install time.
|
|
177
|
+
- Sizing trade-off: model download is one-time and host-cached, per-query latency is CPU-bound and grows with candidates × tokens. A bge-reranker-base class model (≈1.1 GB fp32 / ≈280 MB int8, `dtype: "q8"`) reranks top-50 in tens to low hundreds of ms on CPU dev hardware — measure it with your own runtime and weight cache, then keep `topK`/`queryCandidates` near what recall actually needs; the package guarantees the plumbing (one lazy load, one batched score call per rerank), not the model's speed. The hosted/TEI adapters stay for scale (higher throughput, no local RAM, no download).
|
|
178
|
+
- Cheap by construction: the model loads lazily once per reranker instance, `score` is called once per rerank with every candidate (never one call per document), and `onLoad({ model, loadMs })` is the only opt-in observability — no document text is ever logged. Zero network after load; the built-in loader only touches the model registry at load time, and `allowRemoteModels: false` pins it to local files.
|
|
179
|
+
- Failure is loud: a missing runtime, an unreachable model, or a runtime that returns no per-document scores throws a redacted `RagValidationError` naming the model and the install path (`npm i @huggingface/transformers` or pass `{ runtime }`). There is deliberately **no** silent lexical fallback.
|
|
180
|
+
- `rerankHits` is unchanged and still owns the caps and the trust boundary: local scores reorder the same `RagHit` references (provenance/trust untouched), byte/ms/concurrency limits apply, and abort/timeout/malformed-score cases fail closed.
|
|
181
|
+
|
|
86
182
|
## Implementation example
|
|
87
183
|
|
|
88
184
|
```ts
|
|
@@ -159,11 +255,11 @@ const found = await retrieveContext("leave balance", {
|
|
|
159
255
|
|
|
160
256
|
- Supply any Phase 7-conforming embedder/vector store, including the in-memory reference or PostgreSQL/pgvector adapter.
|
|
161
257
|
- Metadata filtering is package-local after a bounded candidate query so existing vector contracts/adapters remain unchanged. Increase `queryCandidates` only when selective filters measurably need it. `filter` never grants document access.
|
|
162
|
-
- Document ACL is opt-in via `authorization` on `retrieveContext` / `store.query` / `store.lexicalQuery`. Reference memory and PostgreSQL adapters declare `authorization: "acl"` and apply principal/group predicates **before** top-K. `setSourceAccess` replaces grants per source (empty principal+group lists revoke). Access version is independent of embedding generation; an unresolved `accessVersion` denies. Missing grants deny. Stores that omit the capability throw rather than claim protection. Group lists cap at 32.
|
|
258
|
+
- Document ACL is opt-in via `authorization` on `retrieveContext` / `store.query` / `store.lexicalQuery`. Reference memory and PostgreSQL adapters declare `authorization: "acl"` and apply principal/group predicates **before** top-K. `setSourceAccess` replaces grants per source (empty principal+group lists revoke). Access version is independent of embedding generation; an unresolved `accessVersion` denies. Missing grants deny. Stores that omit the capability throw rather than claim protection. Group lists cap at 32. `onAccessDenied` observes the boundary recheck; it never disables it.
|
|
163
259
|
- `Reranker` is a host seam, not a provider integration. Return each redacted candidate ID exactly once; Prism retains canonical hit/provenance/trust fields and exposes `retrievalRank` for diagnostics. Add a hosted reranker only when a host owns its credentials, quota, and retry policy.
|
|
164
260
|
- `createTeiReranker({ baseUrl, model?, timeoutMs?, maxResponseBytes?, ssrf?, allowLoopback?, fetch? })` (`CreateTeiRerankerOptions`) adapts a Hugging Face TEI `POST <baseUrl>/rerank` endpoint (`{query, texts, raw_scores:false}` → `{results:[{index,score}]}`) into the `Reranker` seam. It returns a permutation-only reorder of the same hit objects, so provenance/trust move untouched. Response parsing is strict — short/duplicate/out-of-range indices, non-finite scores, HTTP errors, timeouts, and oversized bodies all fail closed; the `rerankHits` caps (`maxRerankBytes`, `maxRerankMs`, `rerankConcurrency`) still apply around it. The default transport is the core DNS-pinned `pinnedFetch` (redirect-free, byte-bounded to 65,536 by default); HTTPS is required unless `allowLoopback: true` (loopback dev/test) or the host supplies `ssrf`/`fetch` for cluster networking. The adapter validates URL shape only — SSRF policy enforcement stays host-side. No credentials are ever sent; there is no SaaS default URL.
|
|
165
261
|
- Hosted rerank adapters over the same seam (plan 062): `createOpenAiCompatibleReranker({ baseUrl, model?, apiKey?, timeoutMs?, maxResponseBytes?, ssrf?, allowLoopback?, fetch? })` speaks the OpenAI-compatible `POST <baseUrl>/rerank` route (`{model, query, documents}` → `{results:[{index,relevance_score}]}`; pass the version segment in `baseUrl`, e.g. `https://api.jina.ai/v1`), and `createVoyageReranker({ baseUrl, model?, apiKey, … })` adapts Voyage AI (`…/v1/rerank` → `{data:[{index,relevance_score}]}`; `apiKey` required). Both send one request per rerank — no adapter-side batching — never send `top_k` (the retrieval seam owns top-K), return the same permutation-only reorder, and fail closed on the same malformed-response/HTTP/timeout/byte-bound cases. `apiKey` rides as `Authorization: Bearer …` and is never logged; errors carry status/host only. No SaaS default URL — hosts own credentials, quota, and retry policy.
|
|
166
|
-
- `createFakeReranker()` is a network-free deterministic reranker (query-term-overlap scoring, stable ties) and `runRerankerConformance(createReranker)` is the shared network-free conformance for any `Reranker` implementation: empty input → `[]`, output is a permutation of the exact input references (provenance/trust untouched), repeated calls are deterministic.
|
|
262
|
+
- `createFakeReranker()` is a network-free deterministic reranker (query-term-overlap scoring, stable ties) and `runRerankerConformance(createReranker)` is the shared network-free conformance for any `Reranker` implementation: empty input → `[]`, output is a permutation of the exact input references (provenance/trust untouched), repeated calls are deterministic. `createLocalReranker()` passes the same conformance; `resolveReranker({ kind: "local" })` is the zero-service default, and no reranker ever constructs itself from retrieval options (host config only).
|
|
167
263
|
- Hybrid retrieval: pass `lexical: "fts"` (or `"bm25"` when the store supports it) to `retrieveContext()`; the two legs are fused with reciprocal-rank fusion (`fusion: "rrf"`, `rrfK` 60 default; the pure helper `fuseReciprocalRank()` returns `FusedCandidate[]` for custom orchestration). Stores advertise support via `lexicalModes?: readonly LexicalMode[]` and `tokenizeLexical()` is the shared tokenizer. Each hit's provenance `retrieval` field reports `vector`/`lexical`/`hybrid`; fusion internals expose `RetrievalLeg`.
|
|
168
264
|
- Multi-scope retrieve: `scopes: RagScope[]` searches each exact scope against that scope's current generation, then runs **one** RRF over the union and **one** rerank. The query is embedded once. `queryCandidates` is per scope. Duplicate scopes are dropped. `HARD_RETRIEVE_SCOPE_CAP` is 8.
|
|
169
265
|
- Embedder identity/drift guard: `Embedder.id` (memory contract) is stamped onto every vector record as `embedderId`. `retrieveContext()` fails closed with `ERR_PRISM_RAG_EMBEDDER_MISMATCH` when a stored record's `embedderId` or dimensions differ from the active embedder (for example after a model change) — re-index the source before retrieving. Legacy records without an `embedderId` also fail closed, naming the re-index path.
|
|
@@ -172,13 +268,14 @@ const found = await retrieveContext("leave balance", {
|
|
|
172
268
|
- `createRagContextProvider()` derives its query from latest user text by default; pass a fixed string or callback for host-controlled query generation.
|
|
173
269
|
- `createResourceDocumentLoader({ loader })` calls one host-owned `ResourceLoader`; it scans nothing and performs no filesystem or network I/O itself. Pass the host's permission/trust context to that loader.
|
|
174
270
|
- `createWebFetchDocumentLoader({ fetcher })` accepts an already-configured `@arnilo/prism-web-tools` fetch adapter. It never opens a socket, rejects file/local/private/IP-literal URLs, and carries normalized citation/trust metadata forward. The fetch adapter still owns DNS/SSRF policy.
|
|
175
|
-
- `pdfParser` is deliberately limited to bounded, uncompressed PDF text. Provide a host parser through `Parser` for compressed, scanned, or complex PDFs; do not silently index partial text. Hosts that need OCR wrap `createMistralOcrParser` from `@arnilo/prism-
|
|
271
|
+
- `pdfParser` is deliberately limited to bounded, uncompressed PDF text. Provide a host parser through `Parser` for compressed, scanned, or complex PDFs; do not silently index partial text. Hosts that need OCR wrap `createMistralOcrParser` from `@arnilo/prism-work/document-reader` — it is never the default parser and never runs unless the host passes it to `replaceDocument({ parser })`.
|
|
176
272
|
- Package is available directly or via the `@arnilo/prism-memory` family tarball; installation does not create an embedder, vector store, loader, parser, or context provider.
|
|
177
273
|
|
|
178
274
|
## Security and performance notes
|
|
179
275
|
|
|
180
276
|
- Every index/query includes exact tenant/resource/corpus scope; returned records are rechecked and malformed/foreign records fail closed. `retrieveContext` accepts `scope` or `scopes` (never both, never neither). Empty `scopes` is the host “no allowed corpora” path — no embed, no search, no rerank. A hit whose stored scope is not in the requested list fails closed. Generation filters stay per scope.
|
|
181
|
-
- When `authorization` is set, unauthorized text, titles, citations, counts, and reranker payloads never leave the store. Recheck runs after fusion (before rerank) and again after rerank before injection, so
|
|
277
|
+
- When `authorization` is set, unauthorized text, titles, citations, counts, and reranker payloads never leave the store. Recheck runs after fusion (before rerank) and again after rerank before injection, so a revoke that lands between those steps drops the candidate; the post-rerank gate deliberately re-reads the live grant instead of reusing the pre-filter decision, and both gates dedupe to one lookup per distinct source. A thrown grant lookup withholds the source and reports `reason: "check_failed"` rather than failing open or aborting the query. `authorization.tenantId` must match every retrieve scope.
|
|
278
|
+
- Re-pointing is the only path that can re-key a source's row ids; it is ACL-gated on both ends, transactional, capped, and refuses destination collisions. It changes identity metadata only — content, embeddings, provenance, and trust are copied verbatim, and no text is ever re-embedded or re-injected because of a move.
|
|
182
279
|
- Embedding identity is a privacy/consistency boundary: records from a different embedder (or dimension) never silently mingle with new ones — retrieval fails closed and names the re-index path. Generation pointers are scope-scoped: a pointer row belongs to exactly one scope, and visibility is computed inside the store (SQL), never by post-filtering in JS.
|
|
183
280
|
- Source IDs become citation/storage IDs and must be stable non-secret identifiers. Text and user metadata can be redacted before external embedding and persistence.
|
|
184
281
|
- Heading metadata is document text only — it passes through the existing `maxMetadataBytes` cap as chunk metadata; no new content path is introduced.
|
|
@@ -187,6 +284,7 @@ const found = await retrieveContext("leave balance", {
|
|
|
187
284
|
- Remote sources must pass existing resource/media trust, SSRF, MIME, and byte policies before their decoded text reaches this package.
|
|
188
285
|
- `replaceSource()` stages every bounded embedding before opening the store transaction. It requires a source-aware transactional store and fails closed rather than pretending generic upserts are atomic. `createMemoryVectorStore()` supplies the reference `getBySource()` / transaction capability; durable stores must implement equivalent exact-scope behavior.
|
|
189
286
|
- `deleteSource()` rechecks every returned record's tenant/resource/corpus and source metadata before delete. Same source IDs in another corpus remain untouched.
|
|
287
|
+
- Deletion propagation reuses the existing memory ACL (`checkSourceAccess` plus the caller's host-verified `authorization`) and rejects unprivileged callers before writing any tombstone; it is only reachable from the explicit `createDeletionPropagator()` seam, never from `retrieveContext()` or any `filter`/query option. The retrieval-side tombstone guard is an exclusion only — it grants nothing.
|
|
190
288
|
- Parsers enforce byte/page/time caps, abort before and after parsing, decode UTF-8 strictly, and strip HTML script/style content. Parsed and retrieved text remains untrusted inert context; it never gains tool authority.
|
|
191
289
|
- Rerankers receive redacted input under byte/time/concurrency caps. Timeout, abort, unknown/duplicate/missing IDs, oversized input, and reranker failures fail closed; returned objects cannot overwrite Prism provenance/trust fields. The TEI adapter adds fail-closed response parsing (permutation completeness, finite scores) and honors the 65,536-byte response ceiling; SSRF/URL policy is host-side (see Extension notes). The hosted OpenAI-compatible and Voyage adapters carry the same guarantees and add Bearer credentials that are never logged and error messages that never contain document text or the API key.
|
|
192
290
|
- Telemetry is a host-owned seam: `RagTelemetry` adapter (`createRagTelemetry()`) drops anything outside a fixed span-name set and `rag.*`-shaped attribute keys, so raw chunk text never reaches the tracer unless the host's own `attributeFilter` opts it in; when the seam is absent, instrumentation costs nothing.
|
|
@@ -5,27 +5,28 @@
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
Prism's current **0.
|
|
8
|
+
Prism's current **0.9.0** line has **11 publishable manifests**: the root `@arnilo/prism` core package plus **10 workspace packages** — **19 provider adapters** (19 provider adapter subpaths inside the `@arnilo/prism-providers` family), 4 `prism-*` family packages, and 6 capability packages. (Generated by `node scripts/package-truth.mjs` → `scripts/package-truth.json` — the manifest-derived single source for counts, provider membership, umbrella closures, and profile closures.) The last lockstep cut was 0.3.0; Decision B now publishes changed packages independently inside `^0.3.0` — the plan 039 changed-package cut moved root `@arnilo/prism` and every plan-035+ changed package to **0.3.1**, and the plan 050 changed-package cut moved root plus four changed packages to **0.3.2**; the plan 041-044 changed-package cut moves root to **0.3.3** with `@arnilo/prism-memory@0.3.2` (composite recall scoring), `@arnilo/prism-evals@0.3.1` (trace-to-dataset curation), the three session-store packages at **0.3.1** (run-ledger `promptVersion` provenance), and the initial `@arnilo/prism-prompts@0.0.1` (independent opt-in, outside `prism-all`); plan 054 consolidation then folded `@arnilo/prism-browser` and `@arnilo/prism-obscura` into the `@arnilo/prism-web-tools` family as `/browser` and `/obscura` subpaths, folded `@arnilo/prism-rag`, both compaction strategies, `@arnilo/prism-graft`, and `@arnilo/prism-wiki` into the `@arnilo/prism-memory` family as `/rag`, `/compaction/llm`, `/compaction/observational-memory`, `/graft`, and `/wiki` subpaths (deleting the `@arnilo/prism-compaction` profile), and folded all 17 `@arnilo/prism-provider-*` packages into the `@arnilo/prism-providers` family as `/<adapter>` subpaths (Azure/Bedrock/Vertex stop being special all-only manifests); independent publication continues inside `^0.3.0` ranges (which satisfy 0.3.1, 0.3.2, and 0.3.3). This page describes how they are packed, what each tarball contains, how to install them, the required non-optional **caret** `@arnilo/prism@^0.9.0` peer range, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](history/./0.1.0-readiness.md).
|
|
9
9
|
|
|
10
10
|
Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism` peer inside the Decision B window — the caret current spec is `@arnilo/prism@^0.3.3` and every declared window peer satisfies it: packages republishing in the plan 050 cut carry `^0.3.2`; the plan 039 set keeps `^0.3.1`; unchanged packages keep their `^0.3.0` peer; profiles are pure manifests. The plan 050 republished set declares the required `@arnilo/prism@^0.3.2` peer; the plan 041-044 republished set keeps its existing `^0.3.0` window peer; unchanged packages keep their prior window. Installation activates no provider, listener, database, browser, credential, or tool capability.
|
|
11
11
|
|
|
12
|
-
The **0.
|
|
12
|
+
The **0.9.0 lockstep cut** moved all **eleven** manifests together: the current declared peer is `@arnilo/prism@^0.9.0` on every package, and `release.mjs` lockstep mode fails closed on any internal range that merely satisfies the cut version instead of matching it. The **0.6.0, 0.7.0, and 0.8.0 lockstep cuts** each moved the then-current manifest set together. The independent-publication history above (0.3.x, 0.4.x, 0.5.x) describes how the line grew when packages moved separately.
|
|
13
13
|
|
|
14
14
|
<!-- generated:package-truth:inventory begin -->
|
|
15
|
-
**
|
|
15
|
+
**11 publishable manifests** — root `@arnilo/prism` plus 10 workspace packages (4 `prism-*` family packages, 6 capability packages). Generated by `node scripts/package-truth.mjs --emit-docs` — do not hand-edit.
|
|
16
16
|
|
|
17
17
|
| package | version | notes |
|
|
18
18
|
| --- | --- | --- |
|
|
19
|
-
| `@arnilo/prism` | 0.
|
|
20
|
-
| `@arnilo/prism-
|
|
21
|
-
| `@arnilo/prism-
|
|
22
|
-
| `@arnilo/prism-
|
|
23
|
-
| `@arnilo/prism-
|
|
24
|
-
| `@arnilo/prism-
|
|
25
|
-
| `@arnilo/prism-
|
|
26
|
-
| `@arnilo/prism-
|
|
27
|
-
| `@arnilo/prism-
|
|
28
|
-
| `@arnilo/prism-web-tools` | 0.
|
|
19
|
+
| `@arnilo/prism` | 0.9.0 | core — runtime, CLI/RPC, templates, docs |
|
|
20
|
+
| `@arnilo/prism-channels` | 0.9.0 | family — transport-neutral messaging runtime, durable journal, pairing and one-use approvals; official /telegram (private DMs, opt-in granted groups/topics) and experimental pinned signal-cli /signal |
|
|
21
|
+
| `@arnilo/prism-coding-tools` | 0.9.0 | family — /agent, /security, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
|
|
22
|
+
| `@arnilo/prism-core` | 0.9.0 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /validation subpaths |
|
|
23
|
+
| `@arnilo/prism-providers` | 0.9.0 | family — all provider adapters as `/<adapter>` subpaths |
|
|
24
|
+
| `@arnilo/prism-acp-agent` | 0.9.0 | capability — ACP adapter |
|
|
25
|
+
| `@arnilo/prism-ag-ui` | 0.9.0 | capability — AG-UI/A2A/A2UI adapter |
|
|
26
|
+
| `@arnilo/prism-mcp` | 0.9.0 | capability — MCP client/server/OAuth interop |
|
|
27
|
+
| `@arnilo/prism-memory` | 0.9.0 | capability — memory plus /rag, /compaction/*, /fabric, /graft, /wiki subpaths |
|
|
28
|
+
| `@arnilo/prism-web-tools` | 0.9.0 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
|
|
29
|
+
| `@arnilo/prism-work` | 0.9.0 | capability — /connectors, /documents, /sheets, /diagrams, /document-reader, /sandbox, /skills, /tools subpaths |
|
|
29
30
|
<!-- generated:package-truth:inventory end -->
|
|
30
31
|
|
|
31
32
|
|
|
@@ -34,30 +35,30 @@ The **0.6.0 and 0.7.0 lockstep cuts** each moved all ten manifests together: the
|
|
|
34
35
|
|
|
35
36
|
| adapter package | version |
|
|
36
37
|
| --- | --- |
|
|
37
|
-
| `@arnilo/prism-providers/ai-sdk` | 0.
|
|
38
|
-
| `@arnilo/prism-providers/alibaba` | 0.
|
|
39
|
-
| `@arnilo/prism-providers/anthropic` | 0.
|
|
40
|
-
| `@arnilo/prism-providers/azure` | 0.
|
|
41
|
-
| `@arnilo/prism-providers/bedrock` | 0.
|
|
42
|
-
| `@arnilo/prism-providers/clinepass` | 0.
|
|
43
|
-
| `@arnilo/prism-providers/commandcode` | 0.
|
|
44
|
-
| `@arnilo/prism-providers/deepseek` | 0.
|
|
45
|
-
| `@arnilo/prism-providers/google` | 0.
|
|
46
|
-
| `@arnilo/prism-providers/hyper` | 0.
|
|
47
|
-
| `@arnilo/prism-providers/kimi` | 0.
|
|
48
|
-
| `@arnilo/prism-providers/model-discovery` | 0.
|
|
49
|
-
| `@arnilo/prism-providers/neuralwatt` | 0.
|
|
50
|
-
| `@arnilo/prism-providers/ollama` | 0.
|
|
51
|
-
| `@arnilo/prism-providers/openai` | 0.
|
|
52
|
-
| `@arnilo/prism-providers/opencode-go` | 0.
|
|
53
|
-
| `@arnilo/prism-providers/openrouter` | 0.
|
|
54
|
-
| `@arnilo/prism-providers/vertex` | 0.
|
|
55
|
-
| `@arnilo/prism-providers/xai` | 0.
|
|
56
|
-
| `@arnilo/prism-providers/zai` | 0.
|
|
38
|
+
| `@arnilo/prism-providers/ai-sdk` | 0.9.0 |
|
|
39
|
+
| `@arnilo/prism-providers/alibaba` | 0.9.0 |
|
|
40
|
+
| `@arnilo/prism-providers/anthropic` | 0.9.0 |
|
|
41
|
+
| `@arnilo/prism-providers/azure` | 0.9.0 |
|
|
42
|
+
| `@arnilo/prism-providers/bedrock` | 0.9.0 |
|
|
43
|
+
| `@arnilo/prism-providers/clinepass` | 0.9.0 |
|
|
44
|
+
| `@arnilo/prism-providers/commandcode` | 0.9.0 |
|
|
45
|
+
| `@arnilo/prism-providers/deepseek` | 0.9.0 |
|
|
46
|
+
| `@arnilo/prism-providers/google` | 0.9.0 |
|
|
47
|
+
| `@arnilo/prism-providers/hyper` | 0.9.0 |
|
|
48
|
+
| `@arnilo/prism-providers/kimi` | 0.9.0 |
|
|
49
|
+
| `@arnilo/prism-providers/model-discovery` | 0.9.0 |
|
|
50
|
+
| `@arnilo/prism-providers/neuralwatt` | 0.9.0 |
|
|
51
|
+
| `@arnilo/prism-providers/ollama` | 0.9.0 |
|
|
52
|
+
| `@arnilo/prism-providers/openai` | 0.9.0 |
|
|
53
|
+
| `@arnilo/prism-providers/opencode-go` | 0.9.0 |
|
|
54
|
+
| `@arnilo/prism-providers/openrouter` | 0.9.0 |
|
|
55
|
+
| `@arnilo/prism-providers/vertex` | 0.9.0 |
|
|
56
|
+
| `@arnilo/prism-providers/xai` | 0.9.0 |
|
|
57
|
+
| `@arnilo/prism-providers/zai` | 0.9.0 |
|
|
57
58
|
<!-- generated:package-truth:providers end -->
|
|
58
59
|
|
|
59
60
|
|
|
60
|
-
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` is the unified provider family: all provider adapters ship as `dist/<adapter>` subpaths in one tarball (Azure/Bedrock/Vertex included), with the required `@arnilo/prism` peer as the only dependency and `@ai-sdk/provider` an optional peer of `/ai-sdk`. `@arnilo/prism-core` provides the unified runtime, sessions, governance, credentials, enterprise persistence, and
|
|
61
|
+
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` is the unified provider family: all provider adapters ship as `dist/<adapter>` subpaths in one tarball (Azure/Bedrock/Vertex included), with the required `@arnilo/prism` peer as the only dependency and `@ai-sdk/provider` an optional peer of `/ai-sdk`. `@arnilo/prism-core` provides the unified runtime, sessions, governance, credentials, and enterprise persistence family package. `@arnilo/prism-channels` provides the transport-neutral messaging runtime, durable journal and pairing surface; it has only the required `@arnilo/prism` peer, while its SQLite/PostgreSQL conformance drivers are development-only. `@arnilo/prism-web-tools` provides the unified web tools family: root Brave/Exa/Firecrawl research tools plus `/browser` (Playwright-peer gated) and `/obscura` (host-binary + MCP gated) subpaths. `@arnilo/prism-memory` provides the unified memory and context family: root working/vector memory plus `/rag` (with `/rag/loaders` and `/rag/parsers`), `/compaction/llm`, `/compaction/observational-memory`, `/graft` (`@nanonets/graft` optional-peer gated), and `/wiki` subpaths, including the `prism-wiki` bin and bundled skills. `@arnilo/prism-coding-tools/dev` ships the loopback dev inspector — the `prism-dev` bin, the `prism dev` CLI composition, and the `/dev/cli` export the core CLI delegates to for `prism dev` (plan 040 Tasks 4–5); dev tooling is developer-time only and must never be the production API boundary. `@arnilo/prism-core/governance/prompts` (plan 042) is the versioned prompt registry: an explicit host opt-in with no first-party package depending on it — unlike `@arnilo/prism-memory` (a family member) and `@arnilo/prism-core/governance/evals` (used by the promotion helper as an optional peer). `@arnilo/prism-work` is the unified work family: `/connectors`, `/documents`, `/sheets`, `/diagrams`, `/document-reader`, `/sandbox`, `/skills`, and `/tools` subpaths in one tarball. Office dependencies are exact-pinned; `/document-reader` keeps `mammoth` and `pdf-parse` optional and fail-closed, while `playwright-core` remains a devDependency for gated draw.io testing. Importing `/connectors` never evaluates document dependencies.
|
|
61
62
|
|
|
62
63
|
## When to use it
|
|
63
64
|
|
|
@@ -74,6 +75,7 @@ Consumers install the core package for the runtime and add first-party packages
|
|
|
74
75
|
| Install core only | `npm install @arnilo/prism` |
|
|
75
76
|
| Scaffold a minimal project | `npx --package @arnilo/prism prism init my-agent [--provider openai] [--template <name>] [--list-templates] [--with-workflows] [--with-evals]` |
|
|
76
77
|
| Install core runtime & persistence family | `npm install @arnilo/prism @arnilo/prism-core` |
|
|
78
|
+
| Install messaging channels | `npm install @arnilo/prism @arnilo/prism-channels` |
|
|
77
79
|
| Install core + all provider adapters | `npm install @arnilo/prism @arnilo/prism-providers` (import `@arnilo/prism-providers/<adapter>`) |
|
|
78
80
|
| Install minimal runtime (replaces `@arnilo/prism`) | `npm install @arnilo/prism @arnilo/prism-core @arnilo/prism-memory` |
|
|
79
81
|
| Install compaction strategies only | `npm install @arnilo/prism @arnilo/prism-memory` |
|
|
@@ -89,9 +91,11 @@ Consumers install the core package for the runtime and add first-party packages
|
|
|
89
91
|
| Install RAG retrieval (memory family `/rag`) | `npm install @arnilo/prism @arnilo/prism-memory` |
|
|
90
92
|
| Install the Wiki CLI and skills (memory family `/wiki`) | `npm install @arnilo/prism @arnilo/prism-memory` (`npx prism-wiki --help`) |
|
|
91
93
|
| Install the Graft context-graph bridge (`/graft`, host supplies the CLI) | `npm install @arnilo/prism @arnilo/prism-memory` (+ host-installed `@nanonets/graft`) |
|
|
92
|
-
| Install
|
|
93
|
-
| Install spreadsheet
|
|
94
|
-
| Install
|
|
94
|
+
| Install work connectors | `npm install @arnilo/prism @arnilo/prism-work` (import `@arnilo/prism-work/connectors`) |
|
|
95
|
+
| Install document/spreadsheet/presentation engine | `npm install @arnilo/prism @arnilo/prism-work` (import `@arnilo/prism-work/documents`) |
|
|
96
|
+
| Install spreadsheet and CSV data engine | `npm install @arnilo/prism @arnilo/prism-work` (import `@arnilo/prism-work/sheets`) |
|
|
97
|
+
| Install draw.io embed client & diagram engine | `npm install @arnilo/prism @arnilo/prism-work` (import `@arnilo/prism-work/diagrams`) |
|
|
98
|
+
| Install bounded document reader | `npm install @arnilo/prism @arnilo/prism-work` (optional `pdf-parse mammoth`; import `@arnilo/prism-work/document-reader`) |
|
|
95
99
|
| Build everything (core + workspaces) | `npm run build` |
|
|
96
100
|
| Delete all build output (explicit one-shot, see build notes) | `npm run clean` |
|
|
97
101
|
| Run the default (network-free) test suite | `npm test` |
|
|
@@ -121,6 +125,7 @@ Run `npm run clean` explicitly after deleting source files or switching branches
|
|
|
121
125
|
| `@arnilo/prism/testing/state-concurrency-conformance` | `dist/testing/state-concurrency-conformance.{js,d.ts}` |
|
|
122
126
|
| `@arnilo/prism/testing/session-store-conformance` | `dist/testing/session-store-conformance.{js,d.ts}` |
|
|
123
127
|
| `@arnilo/prism/testing/compaction-conformance` | `dist/testing/compaction-conformance.{js,d.ts}` |
|
|
128
|
+
| `@arnilo/prism/testing/prefix-stability-conformance` | `dist/testing/prefix-stability-conformance.{js,d.ts}` |
|
|
124
129
|
| `@arnilo/prism/testing/tool-conformance` | `dist/testing/tool-conformance.{js,d.ts}` |
|
|
125
130
|
| `@arnilo/prism/testing/tool-effect-store-conformance` | `dist/testing/tool-effect-store-conformance.{js,d.ts}` |
|
|
126
131
|
| `@arnilo/prism/testing/extension-conformance` | `dist/testing/extension-conformance.{js,d.ts}` |
|
|
@@ -145,7 +150,7 @@ A packed tarball contains only public compiled output and release files:
|
|
|
145
150
|
- Code packages ship `README.md`, `LICENSE`, and `CHANGELOG.md`; family/profile packages ship `README.md` and `CHANGELOG.md`.
|
|
146
151
|
- The core tarball additionally ships the full `docs/` directory (the docs hub), `templates/init/`, and the `templates/` gallery (e.g. `deep-research`) used by `prism init`.
|
|
147
152
|
- `dist/cli.js` and the `bin` link in core.
|
|
148
|
-
- **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.
|
|
153
|
+
- **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.9.0.tgz`; family packages produce `arnilo-prism-core-0.9.0.tgz`, `arnilo-prism-coding-tools-0.9.0.tgz`, `arnilo-prism-providers-0.9.0.tgz` (all 19 adapters inside), `arnilo-prism-channels-0.9.0.tgz`, `arnilo-prism-memory-0.9.0.tgz`, and `arnilo-prism-web-tools-0.9.0.tgz`; capability packages like `arnilo-prism-mcp-0.9.0.tgz` and `arnilo-prism-work-0.9.0.tgz` carry their own package version. Independent-package tags carry their own version. 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).
|
|
149
154
|
|
|
150
155
|
Excluded from every tarball by `files` negation:
|
|
151
156
|
|
|
@@ -246,13 +251,13 @@ Frozen by Phase 12 Task 0 in `scripts/phase12-freeze-manifest.json` (schema gate
|
|
|
246
251
|
|
|
247
252
|
| Runtime | Supported | Measured in CI |
|
|
248
253
|
| --- | --- | --- |
|
|
249
|
-
| Node | 22, 24 (`engines.node >=22`) | `verify` runs the full `sdk:ready` gate on Node 24; `node22-compat` builds and imports every public root `exports` target on Node 22. Node 20 support was dropped in 0.6.0 (`dev-006`; Node 20 reached upstream end-of-life 2026-04-30); 0.
|
|
254
|
+
| Node | 22, 24 (`engines.node >=22`) | `verify` runs the full `sdk:ready` gate on Node 24; `node22-compat` builds and imports every public root `exports` target on Node 22. Node 20 support was dropped in 0.6.0 (`dev-006`; Node 20 reached upstream end-of-life 2026-04-30); 0.9.0 keeps the same floor. |
|
|
250
255
|
| PostgreSQL | 16 (`pgvector/pgvector:pg16`) | `postgres-integration` service container |
|
|
251
256
|
|
|
252
257
|
## Extension and configuration notes
|
|
253
258
|
|
|
254
259
|
|
|
255
|
-
- **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional **caret** `@arnilo/prism@^0.
|
|
260
|
+
- **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional **caret** `@arnilo/prism@^0.9.0` peer (the lockstep 0.9.0 cut rewrote every internal range; the version-literal gate rejects a declared range that only satisfies the cut version) (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). **Peer-version policy (plan 030, Decision B — independent packages):** internal ranges stay inside the caret window of the cut they shipped in, so a package may patch independently while consumers remain on a compatible 0.x line. A package outside that window is refused by the release gate until the next coordinated peer bump. 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.
|
|
256
261
|
- **Public access.** All 56 manifests (root + 55 workspace packages: 49 code packages + 6 pure-manifest family/profile packages — the 10 `prism-*` family/profile set is the 6 pure-manifest profiles plus the 4 code packages `prism-caveman`, `prism-impeccable`, `prism-openapi-tools`, `prism-ponytail`) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
|
|
257
262
|
- **Shipped vs repository docs.** The npm tarball ships `docs/` pages linked from `docs/index.md` (public API, security, migration, providers, install). It excludes `docs/_evidence/` (per-phase evidence freezes, including `release-0.2.7-evidence.md`), `docs/release-*-evidence.md`, and `docs/api-page-template.md`. Those files remain in git for audit. `dist/__tests__` and `*.map` stay excluded.
|
|
258
263
|
- **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).
|
|
@@ -277,7 +282,8 @@ Frozen by Phase 12 Task 0 in `scripts/phase12-freeze-manifest.json` (schema gate
|
|
|
277
282
|
## Security and performance notes
|
|
278
283
|
|
|
279
284
|
|
|
280
|
-
- **Export-count budget.** `scripts/budget-gate.test.mjs` counts each publishable package's public exports (same name classes as `scripts/dead-exports.mjs`) and fails CI when any exceed the `exportCounts` ceilings in `scripts/budgets.json
|
|
285
|
+
- **Export-count budget.** `scripts/budget-gate.test.mjs` counts each publishable package's public exports (same name classes as `scripts/dead-exports.mjs`) and fails CI when any exceed the `exportCounts` ceilings in `scripts/budgets.json`; the failure names the package and the exact delta. Ceilings are the 0.9.0 pre-release baselines (plan 099 Task 0, measured 2026-09-19): `@arnilo/prism` 1445 and `@arnilo/prism-memory` 892, every other ceiling unchanged since its recorded rebaseline. Each raise carries its measured value and the plans that caused it, and `docs/_evidence/phase54-package-map.md` records the same per-package count in its Budget-Gated Exports column. Growth requires removing exports or rebaselining with a recorded reason.
|
|
286
|
+
- **Artifact diet.** The same gate re-packs the root tarball and fails if packed bytes, unpacked bytes, or file count exceed `scripts/budgets.json#root` + 5%; the 0.9.0 pre-release baselines are 1414295 packed / 4647338 unpacked / 533 files (measured 2026-09-19, plan 099 Task 0). Tests, fixtures, plans, scripts, `src/`, and `docs/_evidence/**` stay out of the pack (plan 026 rule), and every page linked from shipped `docs/index.md` must be present.
|
|
281
287
|
- **No secrets or fixtures in tarballs.** Tests, fixtures, `src/`, `plans/`, `.agents/`, `roadmap.md`, and `tsconfig` files are excluded. The `docs avoid real-looking secret examples` docs check and the packaging guard's deny list prevent secret-bearing fixtures from shipping.
|
|
282
288
|
- **Live tests stay opt-in.** The default `npm test` is network-free by construction and never sets these vars. Provider/compaction live gates stay credential-gated and are not set by default or during `sdk:ready`. The PostgreSQL adapter live matrix is the exception that runs in CI via the dedicated `postgres-integration` job (still skipped in the default suite).
|
|
283
289
|
- `PRISM_LIVE_PROVIDER_TESTS=1` — gates the eight provider packages' `src/__tests__/live.test.ts` (`@arnilo/prism-providers/anthropic`, `provider-google`, `provider-openai`, `provider-opencode-go`, `provider-openrouter`, `provider-zai`, `provider-kimi`, `provider-neuralwatt`). Each provider live test also requires its own API key env var and skips safely when it is missing:
|
|
@@ -288,6 +294,8 @@ Frozen by Phase 12 Task 0 in `scripts/phase12-freeze-manifest.json` (schema gate
|
|
|
288
294
|
- `NEURALWATT_API_KEY` for `@arnilo/prism-providers/neuralwatt`
|
|
289
295
|
- `OPENCODE_API_KEY` for `@arnilo/prism-providers/opencode-go`
|
|
290
296
|
- `PRISM_LIVE_WEB=1` — gates `@arnilo/prism-web-tools` restricted live tests; provider calls additionally require `PRISM_BRAVE_SEARCH_TOKEN`, `PRISM_EXA_API_KEY`, or `PRISM_FIRECRAWL_API_KEY`. Run `npm run test:live -w @arnilo/prism-web-tools`; default tests use injected fake fetch only.
|
|
297
|
+
- `PRISM_LIVE_TELEGRAM=1` — gates `@arnilo/prism-channels` Telegram live probe (`TELEGRAM_BOT_TOKEN`, optional chat id). Skips without credentials; never creates contacts or accounts. Run `npm run test:live -w @arnilo/prism-channels`.
|
|
298
|
+
- `PRISM_LIVE_SIGNAL=1` — gates `@arnilo/prism-channels` Signal live probe (`PRISM_LIVE_SIGNAL_SOCKET`, `PRISM_LIVE_SIGNAL_ACCOUNT`, `PRISM_LIVE_SIGNAL_TERMS_VERSION`, optional recipient UUID). Skips without credentials; never creates contacts or accounts.
|
|
291
299
|
- `PRISM_TEST_PLAYWRIGHT=1` or `PRISM_LIVE_PLAYWRIGHT=1` — gates `@arnilo/prism-web-tools/browser` protected Playwright adversarial matrix (`npm run test:live -w @arnilo/prism-web-tools/browser`). Host must supply a pinned Chromium binary via `playwright-core`. Default tests use fake Playwright APIs only; enabled but missing browser fails closed.
|
|
292
300
|
- `PRISM_TEST_DOCKER_SANDBOX=1` — gates `@arnilo/prism-coding-tools/security` protected Docker matrix. Requires host-preloaded digest-pinned `PRISM_TEST_DOCKER_IMAGE` and absolute `PRISM_TEST_DOCKER_BIN` (optional `PRISM_TEST_DOCKER_USER`). Prism never pulls/builds the image during default tests. Missing prerequisites fail closed when the gate is enabled; disabled gate skips safely.
|
|
293
301
|
- `PRISM_LIVE_CANARIES=1` — gates `scripts/live-canary.mjs`, used only by scheduled/manual `.github/workflows/live-canaries.yml` in protected `live-canaries` environment. It requires provider endpoint/key/model, MCP endpoint/token, A2A endpoint/token, and Brave token environment entries; performs four probes plus at most one MCP session DELETE; caps provider output at one token, each response at 64 KiB, each request at 15 seconds (30 seconds hard), and emits only aggregate kind/status/code/duration. Disabled gate skips before network; enabled but incomplete configuration fails closed.
|
|
@@ -299,7 +307,7 @@ Frozen by Phase 12 Task 0 in `scripts/phase12-freeze-manifest.json` (schema gate
|
|
|
299
307
|
- Provider live tests read the API key from the env only when both gates are set; the key is used as a bearer token and never logged. `assertNoSecretLeak` verifies the key value does not appear in any streamed event. The compaction placeholders still carry no real credentials.
|
|
300
308
|
- Enforced by `network-free-guard.test.ts` (default suite stays network-free) and by source-scanning meta-tests that assert each `live.test.ts` keeps its `skip:` guard.
|
|
301
309
|
- **Supply-chain workflows.** `.github/workflows/security.yml` runs CodeQL JavaScript/TypeScript SAST, PR-only dependency review, `npm audit`, SPDX 2.3 generation, exact license allow/deny policy, tracked-source plus unpacked-tarball credential-pattern scans, and seven-day SBOM retention. Dependabot opens bounded weekly npm and GitHub Actions updates. Every third-party action uses a full immutable revision; workflows never use `pull_request_target`. GitHub repository secret scanning/push protection and required-check branch rules remain repository settings because GitHub provides no equivalent checked-in workflow toggle; enable `security / codeql`, `security / supply-chain`, PR dependency review, and release checks on protected branches.
|
|
302
|
-
- **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`), plus Obscura (`PRISM_ENABLE_OBSCURA_GATE`, `PRISM_OBSCURA_BIN`) and draw.io (`PRISM_ENABLE_DRAWIO_GATE`, `PRISM_TEST_DRAWIO_URL`) legs whose suites live in `@arnilo/prism-web-tools` and `@arnilo/prism-
|
|
310
|
+
- **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`), plus Obscura (`PRISM_ENABLE_OBSCURA_GATE`, `PRISM_OBSCURA_BIN`) and draw.io (`PRISM_ENABLE_DRAWIO_GATE`, `PRISM_TEST_DRAWIO_URL`) legs whose suites live in `@arnilo/prism-web-tools` and `@arnilo/prism-work` — the draw.io leg runs through `scripts/live-matrix.mjs` with `PRISM_LIVE_FILTER=work/drawio-live`; it receives no provider/npm/OIDC secrets, and uploads only a redacted aggregate status artifact (7-day retention).
|
|
303
311
|
- **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.
|
|
304
312
|
- **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.
|
|
305
313
|
- **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 **and the `pg` peer is installed in that consumer**) → batched approval → OpenAPI side effect with idempotency → artifact upload + signed delivery, with policy-deny and hash-mismatch fail-closed injections. The durable leg is peer-gated and never assumed from the env alone: with `PRISM_TEST_POSTGRES_URL` ambient but `pg` unresolvable (the default, since `pg` is a peer of `@arnilo/prism-core` and the consumer installs only Prism tarballs), the fixture prints `SKIP durable postgres leg: …` and runs the memory event source instead of dying with `ERR_MODULE_NOT_FOUND`; the test reports that line as a TAP diagnostic and asserts it, so the skip can never be silent. Scope the env to the phase that needs it (`PRISM_TEST_POSTGRES_URL=… npm run test:postgres`, or `phase release:gate` in `.github/workflows/release.yml`) rather than exporting it globally. 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`).
|
|
@@ -333,10 +341,10 @@ Workspace coverage rows used to include the symlinked root core `dist/` (workspa
|
|
|
333
341
|
| Fact | Value |
|
|
334
342
|
| --- | --- |
|
|
335
343
|
| Workspace include filter | `--test-coverage-include=dist/**` per package (package-local denominator) |
|
|
336
|
-
| Workspace discovery | any `*.test.js` under `packages/<name>/dist/**`, nested layouts included (`@arnilo/prism-acp-agent` builds to `dist/src/__tests__`, `@arnilo/prism-
|
|
344
|
+
| Workspace discovery | any `*.test.js` under `packages/<name>/dist/**`, nested layouts included (`@arnilo/prism-acp-agent` builds to `dist/src/__tests__`, `@arnilo/prism-work` to `dist/<area>/__tests__`) — all 10 workspace packages are measured and artifact keys must match their live manifest names |
|
|
337
345
|
| Per-package gate | `lines >= threshold` from `scripts/coverage-thresholds.json` (recaptured 2026-09-11 = min of two back-to-back runs − 3pp; the two runs differed by ≤ 0.02pp); branches/functions recorded, not gated. `phase23-coverage` also fails when a row names a package that is not in the live workspace graph — retired rows must be pruned |
|
|
338
346
|
| Protected exceptions | `@arnilo/prism-core` only (durable postgres/NATS legs need `PRISM_TEST_POSTGRES_URL` / `PRISM_TEST_NATS_URL`); exempt from the gate and reported separately with the reason. Env- or capability-gated legs elsewhere (memory postgres, coding-tools native sandbox, provider live legs) skip as protected skips but their packages stay gated on the measured run |
|
|
339
|
-
| Artifact | `scripts/coverage-summary.json` (gitignored, CI-retained):
|
|
347
|
+
| Artifact | `scripts/coverage-summary.json` (gitignored, CI-retained): its package-key set must exactly equal live workspace `package.json` names; each row carries `lines`/`branches`/`functions`/`denominatorFiles`/`threshold`/`pass`/`protectedException` + `belowThreshold`; a row whose child failed additionally carries `status`/`exitCode`/`tail` (a redacted tail of the child's output) |
|
|
340
348
|
| Fail-closed | a non-protected package below its threshold, a suite failure, or a run producing no coverage data exits non-zero; a missing threshold entry is a config error |
|
|
341
349
|
| Overrides | `PRISM_COVERAGE_THRESHOLDS`, `PRISM_COVERAGE_ARTIFACT` (used by the gate regression) |
|
|
342
350
|
|
|
@@ -354,7 +362,7 @@ A new workspace package must add an evidence-based threshold entry (or a `protec
|
|
|
354
362
|
| `protected` | a documented, permitted gap with a reason (+ required env where applicable) | pass, always visible |
|
|
355
363
|
| `blocked` | a required release surface cannot be attested (required env absent, or evidence missing) | **fail closed** — `release.mjs gate` refuses to release |
|
|
356
364
|
|
|
357
|
-
Surfaces: core `npm test` (counts and the skip total come from the latest `phase*-baseline.json` `exitGate.counts` — currently 33 protected/live skips, a frozen floor), `security:threat-suites`, every workspace suite (evidence from `scripts/coverage-summary.json` of the same run; `protectedException` packages are named with their reason), `test:postgres` durable conformance (**required**: `PRISM_TEST_POSTGRES_URL` must be set when `release:gate` runs
|
|
365
|
+
Surfaces: core `npm test` (counts and the skip total come from the latest `phase*-baseline.json` `exitGate.counts` — currently 33 protected/live skips, a frozen floor), `security:threat-suites`, every workspace suite (evidence from `scripts/coverage-summary.json` of the same run; `protectedException` packages are named with their reason), `test:postgres` durable conformance (**required**: `PRISM_TEST_POSTGRES_URL` must be set when `release:gate` runs, and gitignored `scripts/postgres-evidence.json` must be written by a successful `npm run test:postgres` at the current `git rev-parse HEAD`; a phase baseline or stale evidence is blocked. The wrapper records only `gitHead`, capture time, and TAP counts — never a DSN. The release workflow's verify job declares the env on the `release:gate` phase only, so it never leaks into env-gated docs demos / durable integration suites of `npm test`; the `postgres-integration` job runs the suite against a real server; a local release must set it too), `test:nats` real JetStream legs (protected, 0.3.0), the `PRISM_LIVE_PROVIDER_TESTS` provider legs (protected, per package), and the four live canaries from `scripts/live-canary.mjs` (provider/MCP/A2A/web; run by the scheduled `live-canaries` workflow with real credentials — recorded `protected`, never `pass`). The manifest cross-references the latest baseline's `exitGate`/`protectedEvidence` so per-phase records stay the source of truth.
|
|
358
366
|
|
|
359
367
|
Override `PRISM_RELEASE_EVIDENCE` to redirect the manifest (used by the gate regression). The manifest is gitignored and CI-retained (`release-evidence` artifact). A release cannot ship with a required env absent and unexplained — the operator sees every blocked surface in the retained manifest.
|
|
360
368
|
|
|
@@ -442,7 +450,7 @@ Every release gate maps to an exact enforcement test or command, so the checklis
|
|
|
442
450
|
| Root SDK export surface freeze | `public-export-contract.test.ts` `root export surface is frozen` snapshots every value and type export of `src/index.ts` (107 value + 69 type) so any add/remove is a deliberate test update; `every frozen value export resolves at runtime` rebuilds `dist/index.js` and asserts each value export is present (catches build drift), and `every frozen type export appears in the built type declarations` asserts each type export is in `dist/index.d.ts`. |
|
|
443
451
|
| Examples compile and are listed; runnable demos execute | `npm run typecheck` runs `tsc -p examples --noEmit`; `docs.test.ts` checks every `examples/*.ts` file is listed in `examples/README.md`, then runs demos offline and scans output for secrets. |
|
|
444
452
|
| Examples run to completion with no secret leakage | `docs.test.ts` `examples_demos_run_to_completion_and_emit_no_secret` runs each demo (Node strips TypeScript types natively) with exit-0 and real-secret scans; `external_app_example_*` pins the DB-backed adapter reference exercising the `RunLedger`, branch-handle checkout, fork, and prior-run resume. |
|
|
445
|
-
| Tarball excludes built tests, source maps, and source | `packaging.test.ts` rejects `dist/__tests__/`, `*.map`, `src/`, `plans/`, and internal files; confirms every package ships README/changelog (and code packages ship LICENSE), core ships docs + CLI, and every export target exists. Profile manifests (`prism-base`/`prism-code`/`prism-sdk`/`prism-all`) are retired; hosts install explicit family packages. `@arnilo/prism-
|
|
453
|
+
| Tarball excludes built tests, source maps, and source | `packaging.test.ts` rejects `dist/__tests__/`, `*.map`, `src/`, `plans/`, and internal files; confirms every package ships README/changelog (and code packages ship LICENSE), core ships docs + CLI, and every export target exists. Profile manifests (`prism-base`/`prism-code`/`prism-sdk`/`prism-all`) are retired; hosts install explicit family packages. `@arnilo/prism-work` ships isolated `/connectors`, `/documents`, `/sheets`, `/diagrams`, and `/document-reader` subpaths. |
|
|
446
454
|
| NeuralWatt package/docs/examples release gate | `packaging.test.ts` pins `@arnilo/prism-providers/neuralwatt` package exports/type declarations and `@arnilo/prism-providers` family membership; `docs.test.ts` asserts `docs/index.md` links `providers/neuralwatt.md` and `provider-caching.md`, and that `examples/cache-aware-prompt-assembly.ts` plus `examples/neuralwatt-agent-run.ts` exist and are listed. |
|
|
447
455
|
| Enterprise PostgreSQL package/docs/example gate | Packaging/install/public-contract tests include `@arnilo/prism-core/enterprise/postgres`; `docs.test.ts` pins its API page, four-store migration/ownership/unknown-outcome/async-router guidance, and `examples/enterprise-postgres-state.ts`; `npm run test:postgres` exercises migration, restart, contention, and cleanup with an explicit database URL. |
|
|
448
456
|
| Version graph and resumable publication | `release.test.ts` covers exact package/lock/range validation, topological order, registry collisions, dry-run, interrupted reports/resume, clean tagged git state, provenance/public/tag arguments, and token-safe errors. `release:check` and `release:publish` derive the workspace graph without a manual package list. |
|
|
@@ -451,7 +459,7 @@ Every release gate maps to an exact enforcement test or command, so the checklis
|
|
|
451
459
|
| Legacy registry markers (plan 054 Task 7) | `scripts/phase54-legacy-registry.mjs --dry-run` verifies every retired name's final published version exists and `latest` is unchanged, and that each deprecation URL anchor exists in `docs/migrate-to-0.4.md`, without mutating the registry; `--apply --confirm` pre-flights all 54 entries and fails closed (zero mutations) on any mismatch, then idempotently adds the `legacy` dist-tag and `<0.4.0` deprecation warning (already-correct entries skipped; per-entry status in `release-artifacts/legacy-registry-plan.json` for safe resume). `packaging.test.ts` asserts the generated plan covers all 54 retired names with uniform messages and valid guide anchors; the offline fixture suite `scripts/phase54-legacy-registry.test.mjs` proves the dry-run/apply/resume behavior without network or tokens. |
|
|
452
460
|
| Formatting, linting, and coverage thresholds | `npm run lint` and `npm run format:check` run Biome (single root `biome.json`, workspaces inherit) and fail on any lint error or unformatted file; `npm run test:coverage` uses Node's built-in `--experimental-test-coverage` with enforced minimums (lines 60 / functions 70 / branches 75) and no third-party service. All three run inside `sdk:ready`. |
|
|
453
461
|
| Supply-chain and live-canary policy | `supply-chain-security.test.ts` verifies SPDX allow/deny behavior, bounded source/artifact secret detection, credential-free canary reports, timeout/redacted failures, immutable action revisions, no `pull_request_target`, protected live environment, attestation paths, and publish dependency on `supply-chain`; CI adds CodeQL and PR dependency review. |
|
|
454
|
-
| Release secret scan covers the tracked release set | `scripts/phase27-release.test.mjs` enumerates `git ls-files` (plus built `packages/prism-core/dist` when present) and passes that explicit list to the unchanged `scanSecrets` — the same tracked set CI scans (`git ls-files -z \| xargs -0 node scripts/scan-secrets.mjs` in `release.yml`/`security.yml`), so no untracked or gitignored working-tree file can fail the gate or mask a tracked finding; a bare `node scripts/scan-secrets.mjs <path>` still walks everything for pre-commit use, and the gate reports the mode, file count, and untracked-but-unignored findings as a note without failing on them. |
|
|
462
|
+
| Release secret scan covers the tracked release set | `scripts/phase27-release.test.mjs` enumerates `git ls-files` (plus built `packages/prism-core/dist` when present) and passes that explicit list to the unchanged `scanSecrets` — the same tracked set CI scans (`git ls-files -z \| xargs -0 node scripts/scan-secrets.mjs` in `release.yml`/`security.yml`), so no untracked or gitignored working-tree file can fail the gate or mask a tracked finding; a bare `node scripts/scan-secrets.mjs <path>` still walks everything for pre-commit use except the two local-only credential names `.gitignore` already excludes (`scripts/live.env`, `*.local.env`), and the gate reports the mode, file count, and untracked-but-unignored findings as a note without failing on them. |
|
|
455
463
|
| Workflow and script references resolve | `scripts/workflow-liveness.test.mjs` resolves every `-w <pkg>` / `--workspace <pkg>` target in `.github/workflows/*.yml` against the live workspace inventory and every named npm script against that package's manifest (root scripts included for a bare `npm run x`), resolves every `@arnilo/*` specifier in `scripts/**/*.mjs` against the live package and its `exports` subpaths, and rejects any `uses:` reference that is not a full 40-hex commit SHA — the drift class that left `sandbox-browser.yml` building four retired packages, `scripts/fixtures/phase26-coding-journey.mjs` packing `packages/coding-agent`/`-security` and `scripts/benchmark-scenarios/phase11-auth.mjs` importing `@arnilo/prism-openapi-tools`/`-server` after plan 054 folded them, with a positive control for each. |
|
|
456
464
|
| Network-free + offline test budget | `network-free-guard.test.ts` keeps the default suite network-free; budget pinned `< 60s` (measured baseline above). Install-smoke is offline (`--offline --no-audit --no-fund`, zero registry fetches). |
|
|
457
465
|
| Core security invariants reaffirmed | Runtime/docs tests hold the trust boundary: **no built-in app tools** (hosts register tools; the core ships only the mock provider and contract helpers), **no hidden provider/credential globals** (providers/credentials are host-owned `AgentConfig` fields, resolved via explicit `providerSource`/`CredentialResolver`), **no auto package discovery** (provider/tool/skill packages are opt-in and individually installed; contribution discovery is realpath-contained and emits inert envelopes the host registers), and **no secret persistence in core** (redaction applies before any `RunLedger`/`SessionStore` append; the ledger gate asserts each message event is written exactly once and redacted). |
|