@arnilo/prism 0.2.5 → 0.2.7

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.
@@ -4,7 +4,7 @@
4
4
 
5
5
  Prism is published as **50 publishable manifests**: the root `@arnilo/prism` core package plus **49 workspace packages** — 14 provider adapters, 9 `prism-*` family/profile packages, and 26 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 50th manifest is the 0.1.6 plan 018 optional `@arnilo/prism-document-reader` package (bounded PDF/Office literal-text extraction for the coding read tool; ships only because its `doc-reader` closeout is demanded — a deferred closeout keeps the graph at 49). This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
6
6
 
7
- Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism@0.2.5` peer; profiles are pure manifests. Installation activates no provider, listener, database, browser, credential, or tool capability.
7
+ Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism@0.2.7` peer; profiles are pure manifests. Installation activates no provider, listener, database, browser, credential, or tool capability.
8
8
 
9
9
  Current **50** publishable manifests (root + 49 workspace packages):
10
10
 
@@ -94,7 +94,7 @@ A packed tarball contains only public compiled output and release files:
94
94
  - Code packages ship `README.md`, `LICENSE`, and `CHANGELOG.md`; family/profile packages ship `README.md` and `CHANGELOG.md`.
95
95
  - The core tarball additionally ships the full `docs/` directory (the docs hub) and `templates/init/` used by `prism init`.
96
96
  - `dist/cli.js` and the `bin` link in core.
97
- - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.2.5.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.2.5.tgz` / `arnilo-prism-compaction-<name>-0.2.5.tgz` / `arnilo-prism-coding-agent-0.2.5.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.2.5.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
97
+ - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.2.7.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.2.7.tgz` / `arnilo-prism-compaction-<name>-0.2.7.tgz` / `arnilo-prism-coding-agent-0.2.7.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.2.7.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
98
98
 
99
99
  Excluded from every tarball by `files` negation:
100
100
 
@@ -303,6 +303,77 @@ npm run release:publish -- --version 0.2.4 --dry-run --allow-dirty --allow-untag
303
303
 
304
304
  Protected evidence (never a passing skip): the durable state-concurrency legs (Postgres `prism_phase24_*` schemas — `npm run test:postgres` under `PRISM_TEST_POSTGRES_URL`; absent credentials record **blocked** per the release skip manifest), the phase24 package-truth conformance over built dist + packed tarballs, and the live canaries (provider OIDC/OPA, MCP, A2A, Brave — always `protected` rows in the manifest, never `pass`). The release skip manifest names every skip class with its required env; missing protected evidence records 0.2.4 as **blocked**, never a passing skip.
305
305
 
306
+ ## Protected coding journey (0.2.6, plan 026 Task 7)
307
+
308
+ The 0.2.6 protected release profile requires real end-to-end coding-agent evidence, never a passing skip. `scripts/phase26-coding-journey.test.mjs` packs the published packages into a fresh consumer, installs the pinned host browser, and runs `scripts/fixtures/phase26-coding-journey.mjs` against real host services: a real LLM provider call through the Prism `AIProvider` contract (host adapter module), a digest-pinned Docker sandbox (`PRISM_TEST_DOCKER_IMAGE` must be `name@sha256:...`), the durable worktree lifecycle over real Postgres checkpoints/leases, a provider-driven edit through ACP with policy approval, a named check with a host parser and `diagnosticDelta`, a patch review composed over the server `ArtifactService` (accepted then superseded), process recovery across replicas (attach-if-attested, never re-spawn), durable ACP cancellation (terminal-idempotent, never replays tools), real GitHub push + lookup-before-create PR + reconcile + cleanup, host Playwright browser inspection, and the host PTY adapter when in the frozen profile.
309
+
310
+ ```bash
311
+ # Full protected profile (all legs real):
312
+ PRISM_CODING_JOURNEY=1 \
313
+ PRISM_TEST_POSTGRES_URL=postgres://... \
314
+ PRISM_TEST_DOCKER_BIN=/usr/bin/docker \
315
+ PRISM_TEST_DOCKER_IMAGE=name@sha256:... \
316
+ PRISM_LIVE_PLAYWRIGHT=1 \
317
+ PRISM_CODING_FORGE_REPOSITORY=owner/repo \
318
+ PRISM_CODING_FORGE_TOKEN=ghp_... \
319
+ PRISM_CODING_PROVIDER=/abs/path/provider-adapter.mjs \
320
+ PRISM_TEST_PTY_BACKEND=/abs/path/pty-host.mjs \
321
+ node --test scripts/phase26-coding-journey.test.mjs
322
+ ```
323
+
324
+ Every side effect carries the run suffix and is cleaned up idempotently (PR closed, branch deleted, worktree removed, containers/children/browser context closed); unknown cleanup blocks the journey. The retained report `scripts/phase26-coding-journey-report.json` is regenerated on every real run — `journey.state` pass records the surface `pass` in release evidence; blocked/partial reports record `blocked` (fail closed); `not_run`/missing records are documented protected gaps (`requiredEnv PRISM_CODING_JOURNEY`). The CI profile runs in `.github/workflows/coding-journey.yml` (scheduled + dispatch; Postgres service, host Docker, pinned Chromium, provider + forge secrets from the `coding-journey` environment) and uploads the report artifact. Leak scans cover journey stdout/stderr and the report against every credential-looking env value — the report records env names only. Frozen ceilings: journey wall 20 min (hard 40 min), cleanup 5 min (hard 15 min).
325
+
326
+ ### 0.2.6 publish handoff (plan 026 Task 8)
327
+
328
+ **Decision: GO when the operator prerequisites below are recorded.** Release **0.2.6** (plan 026) is the fully-featured coding-agent-readiness cut on the 0.2.x review-remediation line. API surface **additive-only** (plain reviewed compat gate at 0.2.6: expected deltas are the version literal plus the Task 1–6 additive exports — PTY backend/handle types, indexed-search seam, workspace lifecycle, process/ACP recovery, review manifest + diagnostics; zero removals; baselines regenerated with `--update-baseline`, no `--allow-break`; freeze manifest `scripts/phase26-freeze-manifest.json` records per-task evidence tokens, state machines, caps, the demand registry, and deviations D-T3-1/D-T5-1/D-T7-1). Seven roadmap items, **no runtime contract change, additive migration**: (1) **host-selected PTY/interactive terminal backend** (`pty-backend`) — `createProcessSessions` gains an optional `ptyBackend` with explicit `capabilities.resize`; `pty: true` without a backend fails byte-compatibly with `ERR_PRISM_PROCESS_PTY_UNSUPPORTED` before spawn; bounded geometry/TERM/attach/resize-rate/metadata caps, generic backend errors that never leak backend text, NUL rejected as a policy error, backend loss surfaces as `unknown` with `exitCode: null`; the protected PTY leg (`scripts/phase26-pty-protected.test.mjs`, gated by `PRISM_TEST_PTY_BACKEND`) passed 4/4 against a real PTY host (python3 `pty.fork` + `TIOCSWINSZ`). (2) **scalable indexed code-search seam** (`indexed-search`) — `createIndexedRepositoryOperations` composes a host-owned incremental index with bounded literal search as the unchanged default; `indexed_literal`/`semantic` fail closed on stale/failed/unsupported/untrusted indexes (`ERR_PRISM_INDEX_*`), no silent semantic-to-literal downgrade, results labeled `untrusted_index`; 100k-entry benchmark p95 ≤ 250 ms, 1k-file update ≤ 1 s, heap ≤ 64 MiB. (3) **ownership-scoped multi-repository/worktree lifecycle** (`workspace-lifecycle`) — `createCodingWorkspaceLifecycle` over CheckpointStore CAS + LeaseStore fencing (`prism.coding-agent.workspace.v1`), locked worktrees with `prism-workspace:` reasons, credential-free remote fingerprints, idempotent create, verify revalidation, cleanup refusal matrix, `ERR_PRISM_WORKSPACE_*`; `GitOperations` gains worktree `lock`/`unlock` + `fingerprint()`. (4) **forge breadth demand-gated** (`forge-breadth`) — GitLab/Bitbucket stay **deferred** in the demand registry with no named consumer; no adapter source ships; activation requires a recorded named consumer/date/use case. (5) **durable ACP/live-task and managed-process recovery** (`durable-recovery`) — bounded process intent/metadata persisted before spawn (`prism.coding-agent.process.v1`), serialized per-record CAS transition writes, attach-if-attested `recover()` reporting `attached|terminal|unknown` with no fabricated exit code and no PID probing; per-record leases fence replicas (memory + real Postgres two-replica conformance 8/8); ACP `activeRun` refs (additive optional, 0.2.5 records stay readable) + `createAcpRunRecovery` status re-resolution and durable fence-checked cancellation (`prism.coding-agent.cancel.v1`) that never replays a pending/dispatched tool. (6) **bounded patch review and incremental diagnostics** (`review-diagnostics`) — `createCodingPatchReviewManifest` + `assertCodingPatchAccepted` (pending/accepted/rejected/superseded bound to digest + revision + identity, stale acceptance refused, never auto-applies/commits/pushes/merges) composed over the server `ArtifactService`; `normalizeDiagnostics`/`diagnosticDelta` with deterministic added/removed/unchanged deltas and host-supplied check parsers; opt-in LSP `syncDocument`/`diagnosticDelta` (monotonic versions, resultId reuse) — LSP stays strictly opt-in, nothing spawns from tool factories or agent assembly. (7) **protected real coding journey** (`coding-journey`) — `scripts/phase26-coding-journey.test.mjs` packs 10 packages into a fresh consumer and drives real host services (provider call, digest-pinned Docker sandbox, Postgres worktree lifecycle, provider-driven ACP edit with policy approval, named check + `diagnosticDelta`, patch review over the server artifact store, cross-replica process recovery, durable cancellation, real GitHub push/lookup-before-create PR/reconcile/cleanup, host Playwright inspection, host PTY adapter in the frozen profile) under frozen wall/cleanup ceilings with run-suffix side effects and per-step idempotent cleanup; missing credentials/services or skipped substeps record **blocked**, never a passing skip; the retained `scripts/phase26-coding-journey-report.json` (timings/states/ids only) gates release evidence (pass/blocked/protected). Release graph stays **50** publishable manifests at exact **0.2.6**; zero new runtime dependency names (core remains dependency-free); 43 code packages + 6 pure-manifest family/profile.
329
+
330
+ **Measured reductions and deltas (recorded in `scripts/phase26-baseline.json` `exitGate`).** New error families: `ERR_PRISM_PROCESS_PTY_*`, `ERR_PRISM_INDEX_*`, `ERR_PRISM_WORKSPACE_*`, `ERR_PRISM_RECOVERY_*`, `ERR_PRISM_REVIEW_*` — all additive, all fail closed. New protected env names (never values): `PRISM_TEST_PTY_BACKEND`, `PRISM_TEST_POSTGRES_URL`, `PRISM_TEST_DOCKER_BIN`, `PRISM_TEST_DOCKER_IMAGE`, `PRISM_LIVE_PLAYWRIGHT`, `PRISM_CODING_FORGE_REPOSITORY`, `PRISM_CODING_FORGE_TOKEN`, `PRISM_CODING_PROVIDER`, `PRISM_CODING_JOURNEY`. Coverage stayed above the recorded 0.2.5 floors. **Rollback notes.** Rollback = restore the 0.2.5 manifests/tag. Three new versioned checkpoint namespaces exist (`prism.coding-agent.process.v1`, `prism.coding-agent.workspace.v1`, `prism.coding-agent.cancel.v1`) plus the additive optional ACP `activeRun` ref; before downgrading, stop all 0.2.6 workers and mark active PTY/process/recovery records unknown (a crashed 0.2.6 replica that resumes on 0.2.5 fails closed — recovery never fabricates an exit code or re-spawns without host attestation). No 0.2.5 persisted shape changed, so an ordinary downgrade is store-safe; the added exports simply disappear.
331
+
332
+ ```bash
333
+ # Operator prerequisites recorded: clean tree at the v0.2.6 tag candidate, GPG key, npm OIDC publisher.
334
+ node scripts/release.mjs bump --from 0.2.5 --to 0.2.6 # already applied by Task 8; idempotent
335
+ npm test # core + workspace suites + all script gates (incl. phase26-freeze + phase26-index-benchmark)
336
+ npm run security:threat-suites # phase8-11 + phase20-25 public-entry conformance
337
+ PRISM_TEST_POSTGRES_URL=postgres://postgres:prism@127.0.0.1:54329/prism_test npm run test:postgres
338
+ node --test scripts/phase26-recovery-conformance.test.mjs # protected: memory + real Postgres two-replica recovery/workspace conformance
339
+ node --test scripts/phase26-pty-protected.test.mjs # protected: real PTY host (PRISM_TEST_PTY_BACKEND)
340
+ PRISM_TEST_POSTGRES_URL=postgres://postgres:prism@127.0.0.1:54329/prism_test npm run sdk:ready
341
+ node scripts/release.mjs gate --version 0.2.6 # plain reviewed gate at 0.2.6: version literal + additive exports only, 0 breaking deltas
342
+ npm run pack:dry-run # twice; diff reports — deterministic
343
+ npm audit --audit-level=moderate
344
+ npm run release:check -- --version 0.2.6 --report /tmp/prism-0.2.6-preflight.json
345
+ npm run release:publish -- --version 0.2.6 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.2.6-dry-run.json
346
+ # run the dry-run twice and diff the reports: deterministic, byte-identical
347
+ ```
348
+
349
+ Protected evidence (never a passing skip): the durable recovery/workspace conformance legs (real Postgres two-replica split-brain fence, cross-replica cancellation, terminal-before-recovery), the protected PTY leg (real PTY host adapter), the protected real coding journey (`scripts/phase26-coding-journey-report.json` — pass/blocked/protected, never a passing skip; runs in `.github/workflows/coding-journey.yml` with real provider/Docker/Playwright/GitHub/Postgres/PTY services), and the live canaries (provider OIDC/OPA, MCP, A2A, Brave — always `protected` rows in the manifest, never `pass`). The release skip manifest names every skip class with its required env; missing protected evidence records 0.2.6 as **blocked**, never a passing skip.
350
+
351
+ ### 0.2.7 publish handoff (plan 027 Task 10)
352
+
353
+ **Decision: GO when the operator prerequisites below are recorded.** Release **0.2.7** (plan 027) is the enterprise ERP production-readiness cut on the 0.2.x review-remediation line. API surface **additive-only** (plain reviewed compat gate at 0.2.7: expected deltas are the version literal plus the plan 027 additive exports — ERP outbox/inbox + dispatcher, saga engine, SoD approvals, audit export, field policy, ERP invariant evals; zero removals; baselines regenerated with `--update-baseline`, no `--allow-break`; freeze manifest `scripts/phase27-freeze-manifest.json` records per-task evidence tokens, state machines, caps, the demand registry, measured HA/DR/classification/journey numbers, and the explicit 0.3.0 blocker). Nine roadmap items, **no exactly-once claim, additive forward-only migrations**: (1) **transactional outbox/inbox** (`erp-messaging`, Task 1) — `ErpOutboxStore`/`ErpInboxStore` + bounded `ErpOutboxDispatcher` with claim-token CAS, `FOR UPDATE SKIP LOCKED`, `ON CONFLICT DO NOTHING` idempotent append, at-least-once delivery with explicit unknown-outcome, dead-letter/replay requiring verified tenant `AgentIdentity`; migration `004_erp_messaging` (`prism_erp_outbox`/`prism_erp_inbox`, 14+4 columns, 3 partial indexes). (2) **saga compensation and reconciliation** (`saga`, Task 2) — `defineSaga`/`runSaga`/`resumeSaga` over existing CheckpointStore + LeaseStore (`prism.workflow.saga`), reverse-order compensation, unknown-outcome detection, manual resolution requiring verified identity + bounded reason + audit ref, stable tenant-scoped operation keys, redacted snapshots, `MAX_SAGA_STEPS=100`. (3) **multi-party and separation-of-duties approvals** (`approvals`, Task 3) — `ApprovalStore` with role/quorum rules, requester/approver separation, any-party-veto rejection, delegated authority (max depth 8), expiry checked at every protected transition, atomic grant consumption in the host transaction, `policyRevision` pin denying on mismatch; migration `005_erp_approvals` (`prism_erp_approvals`, JSONB decisions, `FOR UPDATE` row lock). (4) **tamper-evident audit export** (`audit-export`, Task 4) — `createAuditExporter` with WORM-then-SIEM ordering, hash-chained record envelopes (genesis 0x64 zeros), `verifyAuditBatch` independent verification, `AuditCursorStore` CAS, SIEM best-effort pending replay (8-entry cap), legal-hold flag preservation, RFC 8785 canonical JSON for digests; Prism does not certify NIST/SIEM/WORM compliance programs. (5) **secret-manager adapters demand-gated** (Task 5) — Vault/AWS/Azure/GCP stay **deferred** behind the demand gate (no named consumer; no adapter ships; `scripts/phase27-demand-gate.mjs` enforces zero ambient discovery). (6) **HA registries and recovery** (`ha-dr`, Task 6) — two-replica drill on real Postgres proves failover within lease TTL+5s (measured 4100 ms vs 9000 ms ceiling), idempotent outbox re-append on uncertain-commit replay, stale fence/revision write rejection, exactly-one lease owner, tenant isolation fail-closed. (7) **backup, restore, and migration rollback evidence** (Task 7) — `pg_dump`/`pg_restore` custom-format backup (108,291 B / 122 ms / 382 ms restore), 0.2.6→0.2.7 migration forward+rollback rehearsed (5 migrations), PITR RPO 0 s / RTO 1 s (recovery 1163 ms); production rollback is roll-forward repair only (no down migrations). (8) **field-level data classification and redaction** (`field-policy`, Task 8) — `applyFieldPolicy`/`FieldPolicy`/`createProtectedFieldPolicy` at the redaction, audit-export, and OpenTelemetry seams; unknown-label deny-on-outbound fail-closed default, sparse-copy walker, measured overhead peak 99.8% of the redactor-walk baseline (cap 110%). (9) **ERP release journey** (`erp-evals`, Task 9) — `erpInvariantDataset` + `createErpInvariantScorers` (8 hard 0/1 gates consuming structured facts only) + `scripts/phase27-erp-journey.test.mjs` exercising identity/policy/budget/SoD-approval/outbox/saga-compensation/audit-export/legal-hold/classification/failover/restore end-to-end (4815 ms, all 8 invariants pass). Release graph stays **50** publishable manifests at exact **0.2.7**; zero new runtime dependency names (core remains dependency-free); 43 code packages + 6 pure-manifest family/profile.
354
+
355
+ **Measured reductions and deltas (recorded in `scripts/phase27-release-evidence.json`).** New error families: `ERR_PRISM_ENTERPRISE_POSTGRES_CONFLICT` (outbox), `ERR_PRISM_SAGA_*`, `ERR_PRISM_FIELD_POLICY` — all additive, all fail closed. New protected env names (never values): `PRISM_TEST_POSTGRES_URL` (HA/DR/journey), `PRISM_DR_TARGET_URL` + `PRISM_PITR_URL` (DR drill). Coverage stayed above the recorded floors (policy 92.66% vs 90.78% threshold, evals 91.75% vs 87.63%, core 91.09%). **Rollback notes.** Rollback = restore the 0.2.6 manifests/tag. The two new ERP migrations (`004_erp_messaging`, `005_erp_approvals`) are forward-only; before downgrading, stop all 0.2.7 workers (outbox dispatcher, saga engine, audit exporter) and drop the `prism_erp_outbox`/`prism_erp_inbox`/`prism_erp_approvals` tables (they hold no 0.2.6 data). No 0.2.6 persisted shape changed, so an ordinary downgrade is store-safe; the added exports and ERP tables simply disappear. **"ERP production ready" remains blocked until the 0.3.0 live-service matrix is recorded** — passing 0.2.7 gates unblocks the release cut, not the 0.3.0 live-service matrix.
356
+
357
+ ```bash
358
+ # Operator prerequisites recorded: clean tree at the v0.2.7 tag candidate, GPG key, npm OIDC publisher.
359
+ node scripts/release.mjs bump --from 0.2.6 --to 0.2.7 # already applied by Task 10; idempotent
360
+ npm test # core + workspace suites + all script gates (incl. phase27-freeze + phase27-release + phase27-ha/erp-journey protected legs)
361
+ npm run security:threat-suites # phase8-11 + phase20-26 public-entry conformance
362
+ PRISM_TEST_POSTGRES_URL=postgres://postgres:prism@127.0.0.1:54329/prism_test npm run test:postgres
363
+ node --test scripts/phase27-ha.test.mjs # protected: real Postgres two-replica failover drill
364
+ node --test scripts/phase27-dr.test.mjs # protected: backup/restore/PITR + 0.2.6->0.2.7 migration rehearsal (PRISM_DR_TARGET_URL + PRISM_PITR_URL)
365
+ node --test scripts/phase27-erp-journey.test.mjs # protected: ERP release journey (8 invariant scorers)
366
+ PRISM_TEST_POSTGRES_URL=postgres://postgres:prism@127.0.0.1:54329/prism_test npm run sdk:ready
367
+ node scripts/release.mjs gate --version 0.2.7 # plain reviewed gate at 0.2.7: version literal + additive exports only, 0 breaking deltas
368
+ npm run pack:dry-run # twice; diff reports — deterministic
369
+ npm audit --audit-level=moderate
370
+ npm run release:check -- --version 0.2.7 --report /tmp/prism-0.2.7-preflight.json
371
+ npm run release:publish -- --version 0.2.7 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.2.7-dry-run.json
372
+ # run the dry-run twice and diff the reports: deterministic, byte-identical
373
+ ```
374
+
375
+ Protected evidence (never a passing skip): the HA failover drill (real Postgres two-replica split-brain fence, idempotent outbox replay, stale-write rejection), the DR drill (pg_dump/restore + PITR + 0.2.6→0.2.7 migration rehearsal), the ERP release journey (`docs/_evidence/phase27-erp-journey.json` — 8 invariant scorers, pass/blocked/protected, never a passing skip), the protected Postgres enterprise-state legs, and the live canaries (provider OIDC/OPA, MCP, A2A, Brave — always `protected` rows in the manifest, never `pass`). The release skip manifest names every skip class with its required env; missing protected evidence records 0.2.7 as **blocked**, never a passing skip. The final evidence manifest `scripts/phase27-release-evidence.json` records commit, tool versions, test totals, coverage, timings, budgets, known limitations, and the explicit 0.3.0 blocker + pending operator sign-off.
376
+
306
377
  ### 0.2.5 publish handoff (plan 025 Task 6)
307
378
 
308
379
  **Decision: GO when the operator prerequisites below are recorded.** Release **0.2.5** (plan 025) is the maintainability-and-bounded-performance cut on the 0.2.x review-remediation line. API surface **additive-only** (plain reviewed compat gate at 0.2.5: expected deltas are the version literal plus 105 additive internal-helper exports from the splits/dedup — 84 Task 1 cross-family helpers across `@arnilo/prism`/`prism-coding-agent`/`prism-workflows`/`prism-server`/`prism-ag-ui` and 21 `prism-session-store-codecs` helpers — zero removals; baselines regenerated with `--update-baseline`, no `--allow-break`; freeze manifest `scripts/phase25-freeze-manifest.json`). Internal-only refactoring and bounded-performance work, **no runtime contract change and no migration**: (1) **god-module splits, compat-preserving** — the six remaining implementation god-modules split along cohesive boundaries into internal family files behind preserved barrels (0.1.4 precedent): `src/contracts-core.ts` (1,719 L → 10 families, max 403 L), `src/agent-session.ts` (2,049 L → 4 modules; the 1,686-L `RuntimeAgentSession` class is kept intact — a single TS class cannot span files without exporting private methods, recorded reason), `packages/workflows/src/run.ts` (1,227 L → 6 families, max 417 L), `packages/server/src/handler.ts` (1,005 L → 8 families, max 444 L), `packages/coding-agent/src/repository.ts` (974 L → 7 families, max 299 L), `packages/ag-ui/src/acp/agent.ts` (836 L → 8 families, max 386 L). No `exports` map gained a subpath; `ponytail:` comments preserved verbatim; every package verified with **zero breaking compat deltas** (`scripts/phase25-compat-diff.mjs`). (2) **persistence-mechanics dedup** — 21 pure helpers (ownership scope/assertion, checkpoint stale/encode/decode, branch cursors, lifecycle quota/reason/page-limit, search metadata/clipping, deepFreeze/string-array/throwIfAborted, feedback row mapping) moved into the dependency-free `packages/session-store-codecs` (426 → 624 L, stdlib only, no SQL dialect leakage); the adapters shrank 273 lines total (postgres 1,104 → 1,041, sqlite 1,088 → 1,010); SQL fragments, DDL templates, and query execution stay per-adapter; no persisted-shape change; cross-store conformance proves identical semantics before/after. (3) **quadratic accumulation removed** — the per-push `Buffer.concat` loops in language framing (`LspFrameReader`) and tar parsing (`summarizeTarStream`) became chunk-array readers (two-phase header parse + offset-advance `drop`, `take`/`drop` sliding window); caps and fail-closed overflow behavior byte-identical; framing measured **~100–200× faster at N=4000 chunks** (1,298.4 ms → 11.2 ms) and tar linear at 8 MiB; CLI capture (`collectOutput`) audited — already linear since plan 020; the near-limit probe `scripts/phase25-bounded-accumulation.test.mjs` (10 tests) is wired into the npm test gate segment and asserts linear copying by byte-count instrumentation. (4) **dead-code cleanup, internal-only** — the 62 `dead-exports.mjs` candidates triaged into 2 removals (`PostgresPersistenceCloseOptions`, `SqlitePersistenceCloseOptions` — internal type aliases never re-exported from their adapter indexes) + 60 allow-listed with reasons in `docs/_evidence/phase25-dead-exports-triage.md` (37 test-used false positives, 20 dead-but-compat-tracked deferred to the 0.3.0 breaking cut, 3 public type aliases deferred); the named-internal audit (`agent-session`/`cache-telemetry`/`skill-load`) recorded as clean at 0.2.4; no public export removed, so **no `docs/migration.md` removal note is required** (this section records the no-runtime-contract-delta statement instead). (5) **coverage close, behavior-backed** — 76 focused regressions (approval 43 — the untested `agent-approval.ts` resolve/validate/pending paths; conversations 22 — cursor codec + thread projection; artifacts 6 — approval-state/checkpoint-key/error codes; tool-effect-store conformance 5 — violation throws + option defaults; compaction relies on its 17 existing package suites); core coverage rose **90.53/84.20/90.54 → 91.43/84.80/91.60** lines/branches/functions (gate 60/70/75; all 39 non-protected packages above their evidence thresholds). Release graph stays **50** publishable manifests at exact **0.2.5**; zero new runtime dependency names (core remains dependency-free); 43 code packages + 6 pure-manifest family/profile.
@@ -746,7 +817,7 @@ Audit fixes, dependency updates, and security patches land only for the supporte
746
817
 
747
818
  ## Extension and configuration notes
748
819
 
749
- - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional **exact** `@arnilo/prism@0.2.5` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). **Peer-version policy (plan 024, Decision A — exact pins):** the peer spec is the bare exact current version — no `~`/`^`/`>=` range, no `*` — for the whole 0.2.x line, and all `@arnilo/prism-*` packages move at the same version (the **atomic-upgrade rule**). A partial upgrade (e.g. `@arnilo/prism@0.2.5` installed with a package peering `@arnilo/prism@0.2.6`) is unsupported and fails clearly at install time with `ERESOLVE unable to resolve dependency tree` naming the conflicting peer — never a silent install of a pair that was never tested together. A third-party `@arnilo/prism-*` adapter declares the same exact peer on the documented current version; an unsupported mixture fails at install time, not at runtime. The range widens to `^1.0.0` at the 1.x stable release (the 1.0 readiness gates go operator-green on the 0.2.x line); rollback of a release moves the pins back atomically with the manifests/tag. 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.
820
+ - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional **exact** `@arnilo/prism@0.2.7` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). **Peer-version policy (plan 024, Decision A — exact pins):** the peer spec is the bare exact current version — no `~`/`^`/`>=` range, no `*` — for the whole 0.2.x line, and all `@arnilo/prism-*` packages move at the same version (the **atomic-upgrade rule**). A partial upgrade (e.g. `@arnilo/prism@0.2.7` installed with a package peering `@arnilo/prism@0.2.8`) is unsupported and fails clearly at install time with `ERESOLVE unable to resolve dependency tree` naming the conflicting peer — never a silent install of a pair that was never tested together. A third-party `@arnilo/prism-*` adapter declares the same exact peer on the documented current version; an unsupported mixture fails at install time, not at runtime. The range widens to `^1.0.0` at the 1.x stable release (the 1.0 readiness gates go operator-green on the 0.2.x line); rollback of a release moves the pins back atomically with the manifests/tag. 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.
750
821
  - **Public access.** All 50 manifests (root + 49 workspace packages: 43 code packages + 6 pure-manifest family/profile packages — the 9 `prism-*` family/profile set is the 6 pure-manifest profiles plus the 3 code packages `prism-caveman`, `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.
751
822
  - **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).
752
823
  - **Release workflow.** `.github/workflows/release.yml` has six jobs. `verify` runs network-free SDK readiness on Node 24; `node20-compat` builds/imports every public root `exports` default target on Node 20 for declared `engines.node >=20` (docs examples need Node >=22.6 native TypeScript stripping); `postgres-integration` uses `pgvector/pgvector:pg16`; `supply-chain` runs high-severity audit, SPDX/license policy, and tracked-source secret scanning; and tag-only `codeql-release` runs SAST. Tag-only `publish` needs all five gates, preserves clean exact-tag/version/topological publication, and alone receives `NPM_TOKEN`, `id-token: write`, and `attestations: write`. Before npm publish it packs all current tarballs, generates checksums plus SPDX, scans unpacked public artifacts, creates GitHub attestations for tarballs and SBOM, then retains artifacts for 30 days. Registry state remains the resumable journal. Local `npm run release:dry-run` remains network-free SDK readiness; local PostgreSQL coverage is `PRISM_TEST_POSTGRES_URL=... npm run test:postgres`.
@@ -91,6 +91,10 @@ export const handler = createArtifactHandler({ service: artifacts, authorize: ho
91
91
  - Frozen caps (default / hard): artifacts per thread 64/256; revisions per artifact 32/128; record 8/64 KiB; preview 16/64 KiB; citations 32/128 and 2/8 KiB each; MIME 128/512 B; hash 256/1 KiB; compare exactly 2 revisions; delivery TTL 5 min/24 h; delivery token 4/16 KiB. Raising the revision cap may require raising `recordBytes` (aggregate backstop).
92
92
  - Compare is hash+metadata-bounded (hosts render content); no file bodies are persisted or transferred. With a wired body store, bodies live in the host's object store and are streamed through the adapter (bounded by `maxBodyBytes` 64 MiB/512 MiB, concurrent transfers 4/16, presign TTL 10 min/24 h); object-store outages surface typed `ERR_PRISM_S3_*` / `ERR_PRISM_ARTIFACT_BODY_*` errors, never silent success.
93
93
 
94
+ ## Coding patch review composition (0.2.6, plan 026)
95
+
96
+ `@arnilo/prism-coding-agent` composes over this service for the coding patch review workflow: `createCodingPatchReviewManifest` builds a bounded manifest (repository/worktree identity, base/head, patch digest, changed paths, diffstat, check and diagnostic summaries) and returns a structural `ArtifactAttachInput` whose `preview.review` embeds the manifest and whose `hash` is the patch SHA-256; `assertCodingPatchAccepted` derives `pending|accepted|rejected|superseded` from the returned `ArtifactRecord` by binding to the exact artifact revision, digest, and identity — any patch/repository/worktree/base/head change supersedes a prior acceptance (a newer revision attached after approval makes the old acceptance stale and refused). Decisions never apply/commit/push/merge; the manifest never embeds a raw patch body. Full contract: [Coding review and diagnostics](coding-review-and-diagnostics.md).
97
+
94
98
  ## Related APIs
95
99
 
96
100
  - [Server](server.md): `createArtifactService` / `createArtifactHandler` mount alongside the Prism handler; ownership only from `authorize`.
package/docs/workflows.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- `@arnilo/prism-workflows` is an optional package for typed, bounded DAG orchestration over Prism sessions, tools, events, and persistence seams. Hosts define acyclic workflows with agent/function/tool/conditional/fan-out/join/nested-workflow nodes; the package runs a Kahn-style scheduler with a bounded worker pool, emits package-local `WorkflowEvent`s, checkpoints progress, and can coordinate queued runs across multiple host processes using durable leases and fencing.
5
+ `@arnilo/prism-workflows` is an optional package for typed, bounded DAG orchestration over Prism sessions, tools, events, and persistence seams. Hosts define acyclic workflows with agent/function/tool/conditional/fan-out/join/nested-workflow nodes; the package runs a Kahn-style scheduler with a bounded worker pool, emits package-local `WorkflowEvent`s, checkpoints progress, can coordinate queued runs across multiple host processes using durable leases and fencing, and can run bounded linear sagas with durable compensation.
6
6
 
7
7
  Primary exports:
8
8
 
@@ -17,6 +17,7 @@ Primary exports:
17
17
  | `getWorkflowRun` / `listWorkflowRuns` / `cancelWorkflowRun` | Status, paginated list, and cancel helpers |
18
18
  | `createWorkflowCommands` | Optional `CommandDefinition[]` for direct/background/replay/status/list/cancel/resume and, when selected, schedule control |
19
19
  | `enqueueWorkflow` / `startWorkflowBackground` / `createWorkflowCoordinator` | Persist queued work and atomically claim/renew/execute it across processes using `LeaseStore` |
20
+ | `defineSaga` / `runSaga` / `resumeSaga` | Bounded linear durable forward steps, reverse compensation, unknown-outcome reconciliation, lease fencing, and manual resolution over existing checkpoint/lease stores |
20
21
  | `createWorkflowSchedules` | Explicit ownership-scoped one-time/interval/host-calculated schedules over existing checkpoint/lease stores |
21
22
  | `createProactiveScheduleCapabilities` | Scoped, expiring, revocable capability tokens that enable proactive schedules; revocation stops firing fail-closed |
22
23
 
@@ -28,6 +29,8 @@ Use this package when a host needs multi-node dependency scheduling, conditional
28
29
 
29
30
  Use `createWorkflowCoordinator()` when multiple processes share SQLite/PostgreSQL persistence and must claim queued work exclusively. It is a database-backed coordinator, not a separate broker, DSL parser, provider abstraction, or terminal UI. Agent nodes call public `AgentSession.run()` only; tool nodes go through ordinary `ToolDefinition` dispatch and optional `ExecutionPolicy`.
30
31
 
32
+ Use `defineSaga`/`runSaga` for a linear business sequence whose remote effects need explicit reverse compensation. Sagas are not a second scheduler or rollback engine: hosts supply handlers, `WorkflowCheckpointAdapter` persists bounded state, and `LeaseStore` fences one owner at a time.
33
+
31
34
  ## Inputs / request
32
35
 
33
36
  `defineWorkflow({ id, revision, nodes, edges, limits? })`:
@@ -81,7 +84,11 @@ Every node receives bounded `ctx.state`, `ctx.stateVersion`, and async `ctx.upda
81
84
 
82
85
  `createWorkflowCoordinator({ coordinatorId, workflows, checkpoints, leases, ... })` polls queued/running checkpoints with bounded pages, atomically claims each run, renews its lease, and aborts/fences work after lease loss. Key controls: `leaseTtlMs` (default 30s), `renewalIntervalMs` (default TTL/3), `pollIntervalMs` (default 1s), `maxConcurrentRuns` (default 4), and `pageSize` (default 100, maximum 500).
83
86
 
84
- `createWorkflowSchedules({ store, leases, checkpoints, workflows, ownership, ownerId, calculators? })` is inert until its host calls `pollOnce()` or `run({ signal })`. Ownership requires `tenantId` plus `accountId` or `userId`. Methods are `create`, `get`, `list`, `pause`, `resume`, `trigger`, `delete`, `pollOnce`, and `run`. A record has one required `nextRunAt`, optional fixed `intervalMs` or registered `calculatorId` (never both), bounded input/metadata, status, version, and last-fire attribution. Manual trigger requires an idempotency key. Scheduled run IDs derive from schedule ID plus fire timestamp, so retry after enqueue-before-advance finds the same queued checkpoint instead of duplicating it. Defaults: page 100/hard 500, due claims 16/hard 256, input 256 KiB/hard 1 MiB, poll 1s, fire lease 30s.
87
+ `defineSaga({ id, revision, steps })` validates a bounded linear definition. Each step supplies `run`, `compensate`, and `reconcile`; handlers receive a stable tenant-scoped `operationId`, redacted bounded input/output, prior outputs, and an abort signal. `runSaga(definition, { checkpoints, leases, ownerId, tenantId, runId?, input?, maxAttempts?, leaseTtlMs?, redactor?, onEvent? })` stores a surrogate workflow checkpoint through `WorkflowCheckpointAdapter`, acquires a fenced `LeaseStore` lease, and advances one cursor at a time. `resumeSaga` takes over an expired run; it never replays durably succeeded steps. Forward or compensation handlers mark ambiguous failures with `unknown: true` (or `ERR_PRISM_SAGA_UNKNOWN`), and `reconcile` must return `succeeded`, `failed`, or `unknown` before retry.
88
+
89
+ Saga statuses are `running → completed`, `running → compensating → compensated`, or `manual_intervention`. Compensation visits only completed forward steps in reverse order. A manual resolution may set `completed` or `compensated` only with the current checkpoint version, active verified actor, bounded reason, and host audit reference; the reference is stored as provenance, not verified against the host audit system by Prism.
90
+
91
+ `createWorkflowSchedules({ store, leases, checkpoints, workflows, ownership, ownerId, calculators? })` is inert until its host calls `pollOnce()` or `run({ signal })`). Ownership requires `tenantId` plus `accountId` or `userId`. Methods are `create`, `get`, `list`, `pause`, `resume`, `trigger`, `delete`, `pollOnce`, and `run`. A record has one required `nextRunAt`, optional fixed `intervalMs` or registered `calculatorId` (never both), bounded input/metadata, status, version, and last-fire attribution. Manual trigger requires an idempotency key. Scheduled run IDs derive from schedule ID plus fire timestamp, so retry after enqueue-before-advance finds the same queued checkpoint instead of duplicating it. Defaults: page 100/hard 500, due claims 16/hard 256, input 256 KiB/hard 1 MiB, poll 1s, fire lease 30s.
85
92
 
86
93
  `createProactiveScheduleCapabilities({ schedules, store, ownership, ownerId, defaultTtlMs?, maxTtlMs?, onCapability? })` wraps a `WorkflowSchedules` facade in explicit user enablement. `enable({ workflowId, scope, actor, nextRunAt, intervalMs?|calculatorId?, input?, ttlMs? })` creates the schedule plus a scoped, expiring `ScheduleCapabilityToken` (default TTL 24h / hard 31d, record ≤ 16 KiB) stamped with redacted actor refs. `revoke(tokenId, actor)` marks the token revoked and pauses the underlying schedule so `pollOnce()` never fires it (fail-closed). `assertActive(tokenId)` is a fail-closed guard for manual trigger paths — it throws on missing/revoked/expired tokens. `onCapability` emits `capability_enabled` / `capability_revoked` / `capability_denied` events (redacted refs only) that hosts bridge to `@arnilo/prism-policy` for an auditable ledger. Tokens are ownership-scoped checkpoint records; no cron expression or secret is persisted.
87
94
 
@@ -99,6 +106,18 @@ Every node receives bounded `ctx.state`, `ctx.stateVersion`, and async `ctx.upda
99
106
  | `resume` | Attributable resume decision/input/version/time record |
100
107
  | `version` | Checkpoint CAS identity shown to reviewers and required on suspended resume |
101
108
 
109
+ `runSaga` / `resumeSaga` resolve to `SagaRunResult`:
110
+
111
+ | Field | Notes |
112
+ | --- | --- |
113
+ | `sagaId`, `runId`, `status` | `running`, `compensating`, `completed`, `compensated`, or `manual_intervention` |
114
+ | `version` | Checkpoint CAS version; required as `manualResolution.expectedVersion` |
115
+ | `completedStepIds` | Forward steps durably marked succeeded, in completion order |
116
+ | `compensatedStepIds` | Completed steps durably compensated; list follows original forward completion order |
117
+ | `manualResolution` | Redacted reason, audit reference, checkpoint revision, and verified actor reference when manually resolved |
118
+
119
+ Saga `onEvent` callbacks receive metadata-only `saga_transition` events with tenant/saga/run/step/status/phase/version; input, output, error bodies, and secrets are excluded.
120
+
102
121
  Schedule `onEvent` receives bounded-attribution `schedule_fired` or metadata-only `schedule_failed`; schedule input is never copied into these events.
103
122
 
104
123
  Package-local `WorkflowEvent` types: `workflow_started`, `workflow_suspended`, `workflow_resumed`, `workflow_finished`, `node_started`, `node_finished`, `node_failed`, `node_skipped`, `checkpoint_saved`, `agent_event` (wraps a redacted `AgentEvent`), `workflow_event_overflow`. Sequences are monotonic; drain/order is deterministic by `(sequence, nodeId)`.
@@ -142,7 +161,10 @@ import {
142
161
  enqueueWorkflow,
143
162
  createWorkflowCoordinator,
144
163
  createWorkflowSchedules,
164
+ defineSaga,
145
165
  replayWorkflow,
166
+ resumeSaga,
167
+ runSaga,
146
168
  workflowNode,
147
169
  suspend,
148
170
  } from "@arnilo/prism-workflows";
@@ -177,6 +199,26 @@ const workflow = defineWorkflow({
177
199
  const persistence = createSqlitePersistence({ filename: "prism.db" });
178
200
  const checkpoints = createWorkflowCheckpoints({ store: persistence.checkpoints });
179
201
 
202
+ const invoiceSaga = defineSaga({
203
+ id: "post-invoice",
204
+ revision: "1",
205
+ steps: [{
206
+ id: "reserve-budget",
207
+ run: ({ operationId, input }) => reserveBudget(input, operationId),
208
+ compensate: ({ operationId, output }) => releaseBudget(output, operationId),
209
+ reconcile: ({ operationId, phase }) => reconcileBudget(operationId, phase),
210
+ }],
211
+ });
212
+ const sagaResult = await runSaga(invoiceSaga, {
213
+ checkpoints,
214
+ leases: persistence.leases,
215
+ ownerId: process.env.HOSTNAME ?? "worker-1",
216
+ tenantId: "t1",
217
+ runId: "invoice-1",
218
+ input: { invoiceId: "inv-1" },
219
+ onEvent: (event) => sink.push(event),
220
+ });
221
+
180
222
  const queued = await enqueueWorkflow(workflow, { topic: "hooks" }, {
181
223
  checkpoints,
182
224
  ownership: { tenantId: "t1" },
@@ -261,12 +303,13 @@ runRpcServer({
261
303
  ## Extension and configuration notes
262
304
 
263
305
  - Workflow semantics stay in this optional package; generic checkpoint persistence and bounded event fan-in live in core.
264
- - `ProductionPersistenceStore.checkpoints` and `.leases` are optional generic capabilities. First-party SQLite/PostgreSQL adapters own `prism_checkpoints` / `prism_leases`; workflows only adapt them.
306
+ - `ProductionPersistenceStore.checkpoints` and `.leases` are optional generic capabilities. First-party SQLite/PostgreSQL adapters own `prism_checkpoints` / `prism_leases`; workflows only adapt them. Sagas use the same `WorkflowCheckpointAdapter` and `LeaseStore`; they add no SQL table or scheduler.
265
307
  - `createWorkflowEventBus()` delegates queueing, source fan-in, overflow, abort, and close behavior to core `createEventMultiplexer()`, including its single-consumer contract: a second concurrent `subscribe()` is rejected with `EventMultiplexerError` (`ERR_PRISM_EVENT_MULTIPLEXER_SINGLE_CONSUMER`) instead of silently splitting the stream.
266
308
  - The in-process active-run registry (`registerActiveWorkflowRun` / `getActiveWorkflowRun` / `abortActiveWorkflowRun`) is **non-durable, in-process only — it does not survive restart**; durable active-run recovery is a later milestone. It is bounded: every register sweeps aborted/leaked entries (runs whose promise never settled) and the registry fails closed at `MAX_ACTIVE_WORKFLOW_RUNS` (512) rather than evicting a live run; `sweepActiveWorkflowRuns()` is available for hosts. Cross-tenant lookups stay ownership-isolated.
267
309
  - `createWorkflowCommands()` is optional; hosts can drive `workflow.start` / `enqueue` / `replay` / `status` / `list` / `cancel` / `resume`. The six `schedule.*` commands appear only when a scoped `schedules` service is supplied.
268
310
  - Hosts may bridge `WorkflowEvent` into OpenTelemetry or custom sinks; there is no built-in TUI.
269
311
  - Agent exclusivity is per session: one active `run()` at a time, same as core.
312
+ - Saga definitions remain host code and only their revision, ordered step IDs, bounded JSON snapshots, cursors, attempt counters, and redacted error/provenance metadata are persisted. The surrogate workflow checkpoint namespace is private to the package.
270
313
 
271
314
  ## Security and performance notes
272
315
 
@@ -287,6 +330,8 @@ runRpcServer({
287
330
  - Proactive schedules require an explicit capability grant. Revocation pauses the schedule (never fired by `pollOnce`) and `assertActive` fails closed on missing/revoked/expired tokens; enable/revoke/deny events carry redacted actor refs for the host policy ledger. Capability TTL is capped (default 24h / hard 31d) and the token record is byte-bounded (≤ 16 KiB); tokens are ownership-scoped, so foreign access fails closed rather than leaking existence.
288
331
  - Scheduler stores O(nodes + active outputs + bounded state history); ready-node work uses indegree maps, not repeated full scans.
289
332
  - Lease acquisition is atomic; opaque tokens protect renew/release; monotonically increasing fencing tokens plus checkpoint compare-and-swap prevent expired workers from committing after takeover. Node functions must honor `ctx.signal` for prompt cooperative cancellation.
333
+ - Saga runs require `tenantId`; checkpoint keys and leases include tenant ownership. Every transition uses checkpoint CAS plus the current lease fence. Forward/compensation retries are capped at 3 by default / 10 hard; ambiguous outcomes require reconciliation and unresolved state becomes `manual_intervention`.
334
+ - Saga input, step outputs, and error text are byte-bounded and passed through the configured `SecretRedactor` before persistence or compensation. Manual resolution requires an active verified actor for the tenant, exact checkpoint version, bounded reason, and a non-empty host audit reference; Prism does not pretend to verify the external audit record.
290
335
 
291
336
  Use workflows for known, durable, replayable graphs. Use optional supervisor delegation only when child selection must be dynamic at runtime; do not replace deterministic nodes with model routing without a concrete need.
292
337
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Agent harness for AI providers, agents, sessions, and tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -147,7 +147,7 @@
147
147
  "build": "npm run build:core && npm run build --workspaces --if-present",
148
148
  "typecheck": "npm run build && npm run typecheck --workspaces --if-present && tsc -p examples --noEmit",
149
149
  "sweep:unused": "node scripts/sweep-unused.mjs --json",
150
- "test": "npm run build && node scripts/with-build-lock.mjs node --test dist/__tests__/*.test.js && node scripts/with-build-lock.mjs node --test scripts/release-gate.test.mjs scripts/tooling-gate.test.mjs scripts/budget-gate.test.mjs scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs scripts/phase11-freeze.test.mjs scripts/phase12-freeze.test.mjs scripts/phase13-freeze.test.mjs scripts/phase14-freeze.test.mjs scripts/phase15-freeze.test.mjs scripts/phase16-freeze.test.mjs scripts/phase17-freeze.test.mjs scripts/phase18-freeze.test.mjs scripts/phase19-freeze.test.mjs scripts/phase20-freeze.test.mjs scripts/phase21-freeze.test.mjs scripts/benchmark-0.1.0.test.mjs scripts/sweep-unused.test.mjs scripts/e2e-enterprise-journey.test.mjs scripts/e2e-coding-journey.test.mjs scripts/phase23-quality-gates.test.mjs scripts/phase24-truth.test.mjs scripts/phase25-bounded-accumulation.test.mjs && node --test scripts/phase23-build-race.test.mjs && npm run test --workspaces --if-present",
150
+ "test": "npm run build && node scripts/with-build-lock.mjs node --test dist/__tests__/*.test.js && node scripts/with-build-lock.mjs node --test scripts/release-gate.test.mjs scripts/tooling-gate.test.mjs scripts/budget-gate.test.mjs scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs scripts/phase11-freeze.test.mjs scripts/phase12-freeze.test.mjs scripts/phase13-freeze.test.mjs scripts/phase14-freeze.test.mjs scripts/phase15-freeze.test.mjs scripts/phase16-freeze.test.mjs scripts/phase17-freeze.test.mjs scripts/phase18-freeze.test.mjs scripts/phase19-freeze.test.mjs scripts/phase20-freeze.test.mjs scripts/phase21-freeze.test.mjs scripts/benchmark-0.1.0.test.mjs scripts/sweep-unused.test.mjs scripts/e2e-enterprise-journey.test.mjs scripts/e2e-coding-journey.test.mjs scripts/phase23-quality-gates.test.mjs scripts/phase24-truth.test.mjs scripts/phase25-bounded-accumulation.test.mjs scripts/phase26-freeze.test.mjs scripts/phase27-freeze.test.mjs scripts/phase27-ha.test.mjs scripts/phase27-erp-journey.test.mjs scripts/phase27-release.test.mjs scripts/phase26-index-benchmark.test.mjs && node --test scripts/phase23-build-race.test.mjs && npm run test --workspaces --if-present",
151
151
  "test:coverage": "node scripts/with-build-lock.mjs node --test --experimental-test-coverage --test-coverage-lines=60 --test-coverage-functions=70 --test-coverage-branches=75 --test-coverage-exclude='**/__tests__/**' --test-coverage-exclude='**/node_modules/**' --test-coverage-exclude='**/scripts/**' --test-coverage-exclude='**/packages/**' --test-coverage-exclude='**/examples/**' dist/__tests__/*.test.js && node scripts/with-build-lock.mjs node scripts/coverage-summary.mjs && node --test scripts/phase23-coverage.test.mjs && node --test scripts/phase23-skip-manifest.test.mjs",
152
152
  "coverage:summary": "node scripts/with-build-lock.mjs node scripts/coverage-summary.mjs",
153
153
  "lint": "biome lint . --reporter=sarif --reporter-file=scripts/lint-report.sarif",