pleach
ReferenceChangelog

@pleach/core changelog

Release history for @pleach/core — site-docs entries that materially touched the @pleach/core surface, newest-first. Canonical runtime history lives upstream.

This page collects the site-content changelog entries that materially touched the @pleach/core docs surface or named a @pleach/core symbol, subpath, or audit gate. It is not the runtime changelog — the canonical record of @pleach/core runtime behavior lives in the upstream package CHANGELOG.md and on npmjs.org/package/@pleach/core.

See the combined site changelog at /docs/changelog/combined for the chronological unified view across every SKU.

Unreleased

Added

  • Comparison adds a governance-control-plane / AI-gateway category. Frames @pleach/core against governed-proxy control planes (Portkey, Cloudflare AI Gateway, and the enterprise control planes above them) as altitude, not timing: a proxy governs the call at the HTTP boundary; core governs the agent's execution graph and writes the AuditableCall row to a database you own. Relatedly, Landscape row 1 now notes that proxy-advertised "tamper-evident audit trails" live on the vendor's side, not as a hash-chained row you own.

  • Five more @pleach/core public exports documented (720a6e8a3 / de4403b6a). Interrupts adds rewriteToolArguments — the natural-language → structured-args rewrite for approval-with-edit flows; it runs on the utility call class and never throws, resolving to the original arguments on every fallback path. Tools adds the standalone createDiscoverToolsTool / DISCOVER_TOOLS_TOOL_NAME factory for hand-rolled servers. Server adds createPluginToolRegistry — the getter-backed registry behind /tools and /tools/:name. Storage adds composeDurableStore (build a DurableStore from adapters you already hold) plus the optional blob member and createMemoryBlobStore / MemoryBlobStore. Adoption paths names the BrownfieldRuntimeMenu options type; Prompts names the optional PromptDescriptor ({ title?, summary? }) surfaced by runtime.prompts.describe(). Upstream trunk, not yet published to npm.

  • New Pricing math page. Documents the @pleach/core/pricing subpath — computeTurnCost, DEFAULT_PRICING_MATRIX, createPricingResolver, the OpenRouter fetch, and resolveCostEventUsd.

  • React lab component kit documented. The full @pleach/core/react/lab surface — PleachLab's composable panels plus useLatticeState / useEventLogCapture / useChannelSnapshot — with @pleach/core/react/lab named as the canonical subpath.

  • Three prompt- and context-management capabilities documented. Orchestrator middleware adds the optional summaryProvider field on SummarizationConfig — a callback supplying a higher-quality (e.g. LLM-generated) rolling summary in place of the default extractive char-slice summary, falling back to the extractive default when it returns an empty value or throws. Prompt builder adds the "Cache-stable prefix" section: the stability: "stable" | "volatile" tag on BudgetedSection and the stableBoundaryIndex field on ComposedPromptcomposeBudgetedPrompt hoists stable sections into a contiguous prefix (untagged input stays byte-identical) and reports where the volatile suffix begins, so a consumer places its provider cache_control breakpoint after included[stableBoundaryIndex - 1]. Prompts adds "Persisting an agent's role" — put durable persona in the core.role-template slot via replaceCore / prependPersona and tag it stability: "stable". Upstream trunk, not yet published to npm.

  • condenseTools.intentPriorityMap given its real type. Tools replaces the intentPriorityMap placeholder with Record<string, readonly string[]> — an intent name mapped to the tool names that keep their full schema when that intent is active. Upstream trunk, not yet published to npm.

  • condenseTools + the discovery meta-tool documented. Tools gains the createPleachRoute option that trims the tools[] array above a threshold — keeping maxSchemaTools full schemas and surfacing the rest as one-line names — plus the discovery meta-tool (metaToolName) the model calls to pull a dropped schema back. Distinct from the prompt-directive weakToolSchemaBudgetPlugin on the same page. Upstream trunk, not yet published to npm.

  • Model-pipeline surface documented — two new pages plus eight section additions. Model hooks documents the @pleach/core/hooks pre/post-model seam (PreModelHook, PostModelHook, ModelProfile + historyTrimmerHook, lazyModelDefaultsHook, toolCallValidatorHook, repetitionDetectorHook, wired via runtime.model.registerPreHook / registerPostHook). Orchestrator middleware documents @pleach/core/middleware (OrchestratorMiddleware, MiddlewareStack, ResultEvictionMiddleware, SummarizationMiddleware, LanguageModelMiddleware, CHARS_PER_TOKEN, wired via setOrchestratorMiddlewareInit). Both join Subpath exports under a new "Model pipeline" category with @pleach/core/synthesis (SynthesisEmitter, enrichOffloadedToolPreviews). Sections added: finalizeAnswer + the { banner } return on postSynthesisGuard (Plugin authoring); ProviderCatalogContract and the SLOW_COLD_START_PLANNER_FAMILIES / isSlowColdStartPlannerFamily gate (Providers); InterruptManager.requestApprovalWithId (Interrupts); runtime.abort(reason) / AbortCoordinator + TURN_ABORT_REASON (Session runtime); the durable subagent.tool_used audit row (Subagents); the harness_event_log_owner_select per-user RLS policy + harness_event_log_service_role write bypass (Multi-tenant); and MemoryStore as the config.store ship-a-default. Existing published @pleach/core surface; upstream trunk, not yet on npm.

  • Four runtime-behavior sections documented. Each mechanism shipped upstream but had no doc home. Tools gains weakToolSchemaBudgetPlugin (@pleach/core/prompts) plus createWeakToolSchemaPredicate (@pleach/core/modelfamily) — the proactive tool-call budget for weak-tool-schema families (google/deepseek/moonshot, defaults maxBatch: 4 / maxSameTool: 2), gated on PromptContext.family. Turn lifecycle documents the no-first-token dead-air hard-cut (reduceTurnDeadAir; upstream d062ab24d5). Providers documents the stalled-rung cascade pivot, classed SYSTEM_ABORT not USER_ABORT (upstream e1fa3f1487). Fabrication detection documents metadata.uncoveredPlanSteps and the honest "not dispatched" note (upstream bb0f995fce, ca9dc86644). All from published subpaths or documented runtime behavior; upstream tree 8f224cbf42 on trunk, not yet published to npm.

  • Standalone hosted-agent route family — createPleachRoutes, createPleachAgent, DurableStore, MemoryEventLog. @pleach/core now mounts the whole route family from one factory, not just the single execute leg. createPleachRoutes and the three-arm createPleachAgent({ context, tools, db }) façade (both @pleach/core/quickstart) mount sessions CRUD, execute+SSE, interrupts, checkpoints, rollback, events-recall, sync, and fork; createPleachAgent returns { fetch, nextRoutes(), nodeHttp(), store }. DurableStore + createMemoryDurableStore() (@pleach/core/store) unify storage, checkpointer, event-write, event-read, and recall behind one binding, and MemoryEventLog (@pleach/core/query) is the keyless in-memory recall ledger with an asQueryClient() shim — so recall works with no Supabase when db is omitted. createHarnessServer({ runtime, storage, checkpointer?, events? }) is the build-only auto-bind factory over the still- unpublished @pleach/core/server subpath. Known limitation: the default interrupt resolver binds a per-request in-process InterruptManager; a durable multi-request deployment supplies its own via createPleachRoutes(...).capabilities.interrupts. Landed across API routes, Server, Quickstart, Storage, and Query. Upstream: pleachtui Track A, @pleach/core@0.1.0 on trunk (Waves 0b34ab8742, 095d037933, add6562a15, 2b20c9c4be) — on trunk, not yet published to npm.

  • Runtime strategies documents the resolveCallReasoningEffort hook. A new per-call SessionRuntimeConfig strategy slot. The runtime consults it before every provider stream with the resolved { callClass, family, modelId }; the returned ReasoningEffort ("low" | "medium" | "high", "none" to disable the budget, undefined to leave it untouched) threads onto StreamChatOptions.reasoningEffort and the adapter lowers it to the provider request. Capability-gated — a model that doesn't advertise reasoning control ignores the field, so an unsupported model never 400s on the param. ReasoningEffort is opaque to core: the host owns the policy of which call class on which family to cap. Unset ⇒ no field attached, request byte-identical. Fail-soft — a throwing resolver is caught and treated as undefined. Added to the "Newer injection hooks" table plus a per-call cadence note.

  • Comparison gains a category for agent-memory & knowledge-graph substrates (a read-side category). Pins the read-vs-write delineation for @pleach/core: memory layers and knowledge-graph engines (Letta, Mem0, Zep) are a read substrate — the graph exists so the agent can query it to decide; @pleach/core is a write substrate — the ledger exists so every provider call is recorded, then read to account. Shared skeleton (append-only, content-addressed, causal chain, fork/replay); divergent object of record (the agent's knowledge/decisions vs. one provider call with model/tokens/cost). Compose-not-compete — a memory graph reads the same session the AuditableCall row writes.

Changed

  • Replay-determinism claims reconciled from "byte-identical" to "deterministic; divergence-detected." Determinism, Comparison, and Migrating from Anthropic Enterprise no longer claim a recorded turn re-generates a live model call byte-for-byte. Deterministic replay reproduces the recorded response, tool-call sequence, and terminal state, and names any drift with ReplayDivergenceError; a replay re-serves the recorded response, it does not re-run the provider. "Byte-identical" is kept only where it holds by construction — fold-based state hydration and deterministic channel reducers. Corrects a load-bearing over-claim; the property is reproducible control flow + attributable divergence, not byte-equality. Adds the serial-execution caveat to the replay claim: replay determinism holds only under serial graph execution (one node per superstep).

  • Reasoning-only recovery documented as default-on for the packaged surface. Providers already documented the opt-in SessionRuntime reasoningRecovery DI; it now records that createPleachRoute defaults it on (opt out with recoverReasoningOnly: false), so a reasoning model that emits only chain-of-thought gets one same-model re-elicitation instead of a false family-exhausted. Interrupts gains a pointer from "Cross-request approval" to the interruptResolver option (createInMemorySharedInterruptResolver() / a store-backed DurableInterruptResolver).

Fixed

  • Model-resolution matrix — Google's fast tier was stale. Model resolution matrix listed gemini-3-flash-preview for the Google converse and utility rungs; the live matrix resolves both to gemini-3.5-flash-lite. A reader who saw the old id would have keyed a fingerprint or cost estimate off a model that no longer fires.

  • Off-policy example term scrubbed from Prompts. Two gatedPrompt examples keyed on a "modal" tool; both now key on the neutral "sandbox" capability. Example-only — no API or claim change.

  • @pleach/core doc corrections from a ~200-commit upstream sweep. Graph node catalog: core registry corrected 44 → 43 — two domain plugin nodes were listed as core, and the core node syntheticExpansionDetector was missing. Config manifest: added a partial-coverage caveat (only the plugin surface is content-hashed today). Fabrication detection: documented the ~13-detector grounding/offloaded-data cohort the exports table omitted. Air-gapped deployment: corrected from "v2+ roadmap item" to the shipped fail-closed airGapped enforcement. Adoption paths: createBrownfieldRuntime (@pleach/core/runtime) is shipped, no longer "proposed."

  • Four broken root imports corrected to their real subpath. Five code blocks imported a symbol from @pleach/core that the root barrel does not re-export (verified against the package exports map): SupabaseAdapter / createSupabaseAdapter (Research agent) → @pleach/core/sessions; withTenantHeader (Multi-tenant SaaS agent) → @pleach/core/tenant; computeFingerprint (Testing) → @pleach/core/fingerprint; EventLogWriter (Event log and Recipes) → @pleach/core/eventLog. Each would fail to resolve on copy-paste; the subpaths are public per Subpath exports.

  • Two orphaned pages wired into the sidebarInstall (Get Started) and Cycle-break contract packages (Reference) existed but were reachable only by direct URL.

  • Adoption paths "Host adapters" card corrected — it promised "implement OrchestratorAdapter / StorageAdapter", but Host adapter documents the setHarnessModuleLoader module-loader seam. Reworded to match.

  • Stale AuditRecordVersion claim corrected — 1819. CI enforcement stated the locked row shape was "currently 18"; upstream shipped the additive bump to 19. A version claim is load-bearing — a reader who saw "18" needs this row to know it moved. The package's published value is the source of truth; this tracks the shipped bump.

  • Hash-chain verifier home corrected to @pleach/core/eventLog. Audit ledger (two spots) and Recipes said verifyChainForChat / generateProof "ship in @pleach/replay@0.1.0". They are defined in @pleach/core/eventLog; @pleach/replay consumes them. Corrected across Audit ledger (two spots), Recipes, Which SKU, and Regulated-domain agent; now consistent with Hash chain.

  • Error-code range corrected to 1xxx–11xxx. The authoritative band table in Error codes defines 10xxx (caller-auth) and 11xxx (runtime/infra). Stale 1xxx–9xxx (frontmatter + Troubleshooting ×2) and 1xxx–7xxx (Contributing, Stream events) summaries now match the table.

  • maxConcurrentSubagents clamp claim corrected. Research agent said a maxConcurrentSubagents above SUBAGENT_LIMITS.maxConcurrent is clamped to it. They are separate limits on separate paths (default 4 caps the SubagentManager; 3 caps the imperative spawn path), neither clamped to the other — now consistent with Subagents.

  • Unknown safety-policy ids now throw at construction — even with no plugins. Safety promises "Construction throws UnknownSafetyPolicyError if the config references an id no plugin registered — operator typos surface at boot, not on the first turn." Previously the enable/validate loop was gated behind the plugin block, so a plugin-less createPleachRuntime({ enabledSafetyPolicies: ["typo"] }) silently no-op'd the enable and the typo surfaced (or silently didn't) only at first turn. The enable loop now runs unconditionally (core SessionRuntime.ts); the register() loop stays plugin-gated, so a legitimately plugin-contributed id is registered before the enable finds it and valid constructions are unaffected. The impl now matches the documented guarantee.

  • The chronological error trail (errorCodesChronological) now captures every error class. A completed tool call carrying a structured _error_code (its status looks successful, so it tripped neither the failed-status nor the schema-validation branch) and a caught async-planner throw (AsyncPlannerHandler, previously console-only) now each persist an error.code row. A live turn with these errors previously persisted zero rows; the durable trail is now complete. (Direct-API tool errors were already covered by the host emit path.)

  • Core-concept doc snippets reconciled with shipped signatures (devharness FINDING 88, 91–93). Determinism — the ledger read used a non-existent ledger.list({ sessionId }); the real AuditableCallQuery read is async positional await ledger.getSession(sessionId) (core audit/ProviderDecisionLedger.ts), and the "distinguishes three operating contracts" line corrected to five (the RuntimeMode union — and the page's own table — lists five). OTel observabilityexecuteMessage is positional executeMessage(sessionId, "hello"), not the object form executeMessage({ sessionId, content }) (core SessionRuntime.ts). Stream events — the LangGraph "values" mapping used runtime.sessions.get(), which RuntimeSessionsFacet (core facets/sessions.ts) does not expose; corrected to runtime.sessions.resume(sessionId).

Added

  • Gate failures → fixes — the failure-string lookup. Maps each gate's verbatim, greppable failure string to its meaning and the fix doc — [graph-stages] Node "<name>" missing stageId in NODE_STAGE_MAP, [audit:c8-event-type-allowlist-coverage] FAIL, [auditable-call-version] FAIL rule 3, [audit:plugin-contract-completeness] FAIL, and others, all verified against scripts/audit/. The agent-facing close of the self-extension loop.

  • AuditRecordVersion corrected 1418 on CI enforcement to match the source (export type AuditRecordVersion = 18;) and the AuditableCall row.

  • Extending Pleach — the gate-paired authoring map. Pairs each extension point with the interface, the registration call, and the audit gate that fails if the addition is wrong — nodes (audit:graph-stages), event types via contributeEventTypes (audit:c8-union-member-has-producer

    • audit:c8-event-type-allowlist-coverage), scrubbers, plugin hooks (audit:plugin-contract-completeness), prompt blocks, and a custom audit field via pluginPayloads (audit:auditable-call — the structural column set is locked). Draws the host-extension vs upstream-contribution line, and adds an "Agent-driven self-extension" section: the gates as an autonomous write → audit:* → read-failure → fix loop, plus injecting the extension contract into the operating agent's prompt via contributeRuntimeAwarePrompts. Nodes, channels, and scrubbers gained a "What CI checks when you add one" footer linking into it.
  • createPleachRoute({ demo }) keyless first-run + demo-first pleach init scaffold documented. Getting started, Quickstart, and Install now lead the wizard path with a keyless demo: with no provider key, createPleachRoute({ demo: process.env.NODE_ENV !== "production" }) drives a real graph turn over canned model text and writes real AuditableCall rows, flagged x-pleach-mode: demo. A resolved <PROVIDER>_API_KEY always wins; demo never engages in a production build. The Next.js App Router scaffold adds an /audit view (app/audit/page.tsx + app/api/audit/route.ts) rendering the per-model-family rollup (family · rows · tokens · est. cost). The bare createPleachRoute() no-key contract is unchanged (HTTP 503).

  • engine/ superstep scheduler named as an architecture piece + facets.mdx synced to the shipped facet inventory (pkgclean 06 D7/D9). Architecture and Concept clusters now name the engine/ scheduler (SuperstepRunner + its primitives) as the deterministic superstep executor that runs the compiled graph. Facets gained the two shipped SessionRuntime accessors it omitted — runtime.observe and runtime.probes — plus the four per-stage graph introspection facets graph.anchor / graph.toolLoop / graph.synthesize / graph.postTurn.

  • @pleach/core/skills + @pleach/core/agents/types are real emitted subpaths. Skills updated to import SkillLoader, parseSkillFrontmatter, Skill, and SkillFrontmatter from the @pleach/core/skills barrel (the /loader, /parser, /types sub-subpaths do not exist); Agents prose corrected from "wildcard path" to a real emitted @pleach/core/agents/types subpath.

Changed

  • @pleach/core/internal/… subpaths retired from the public docs surface (pkgclean 06 D8). streamSingleTurn and Subpath exports no longer document @pleach/core/internal/strategies/streamSingleTurn/helpers (+ its four direct helper entries) or @pleach/core/internal/tools/execution/registryResolvedTools as stable public imports. The internal/ segment marks implementation details, not a supported API; the copy-paste helper-barrel import is removed and both paths moved to a "Not a public import surface" section with their public alternatives — ToolDefinition from @pleach/core/types/generic, and @pleach/core/tools/execution (which re-exports the resolved-tools registry functions). No package.json:exports change.

  • core.mdx stale numbers corrected. auditRecordVersion updated 13 → 18 (real value at AuditableCall.ts), and the HarnessPlugin plugin-hook count updated ~41 → 67 contributeX hooks (derived by grepping packages/core/src/plugins/types.ts).

Fixed

  • More SKU doc-page snippets reconciled with the shipped signatures (devharness FINDING 80–82). Fabrication detection — the custom-detector example used a non-existent ctx.toolArgs and returned {suspect, tier}; corrected to the real FabricationDetectorContext fields + the FabricationFinding shape ({detectorId, severity, reason, evidence?}), and the tier-routing bullet corrected (routing keys on the tool's safetyTier, not a finding's severity). Multi-tenantgetAggregateUsage is 3-positional ((client, store, filters)), has no groupBy: "tenantId" value (session/agent/model/tool/day/week), nests dates under dateRange, and requires userId (it's single-user scoped; tenant rollups use the raw SQL). Determinism — the fingerprint round-trip read a non-existent .fingerprint audit field (real: fingerprintComposite, a string) and compared a string to a Fingerprint object; corrected to a like-for-like comparison over a real FingerprintInput. These are the ctor-shape / call-arity / field-name classes the new audit:doc-import-resolution gate doesn't cover (import-resolution only).

  • Event-log read side documented as store-agnostic — eventReader / HarnessEventReader. Event-log projections said runtime.events.iterate / .fold read harness_event_log rows ordered by (chat_id, sequence_number) and became live "on the Supabase backend in PA-1 Phase A.2" — store-specific claims that no longer match the shipped surface. Corrected: both accessors delegate to a HarnessEventReader injected as the runtime's eventReader (the read-side counterpart to eventLogWriter), so the host casts its own store into the reader at construction and @pleach/core itself stays free of backing-store knowledge — Postgres, Supabase, SQLite/pglite, or an HTTP API back the same surface. iterate's options gain tenantId; the reader is required to read the durable log (no built-in reader, no implicit store fallback — a bare runtime yields nothing, matching the MemoryAdapter path) and throws a typed error at the call site when absent. New Backing the reader section shows the one-method contract yielding EventLogRow (the shape reconstructSessionState and the shipped projections fold). Session runtime config table gains eventLogWriter + eventReader rows; Storage grows the ci:devharness-sql value-prop battery from four durable properties to nine — adding the @pleach/observe postgres() destination, time-travel fork, SQL-queryable audit ledger (harness_auditable_calls), tamper-evident hash chain, and @pleach/replay deterministic replay over the injected reader.

  • SKU doc pages reconciled with the shipped import/construction surface (devharness FINDING 76–79). Four doc-site pages drifted from the (correct) package READMEs: Building a chat UI advertised a fabricated @pleach/react chat-hook API (useChat/HarnessProvider from the root, useInterruptDecision, useChatVercelCompat, sendMessage) — corrected to the real surface (useSessionRuntime/useSessionMessageStream/useInterruptUI from @pleach/react; useChatsubmit from @pleach/core/quickstart; HarnessProvider from @pleach/react/legacy/@pleach/core/react; useVercelAISDKCompat from @pleach/react/adapters/vercel-ai-sdk). LangChainLangChainProvider takes a POSITIONAL model arg and wires via the top-level provider: slot (not { model } / host.strategies.provider). Base tools — the scratchpad is per-SESSION (chatId-scoped, not per-turn), its param is operation (not op), and its value is a string. Coding agent — the four sandbox tools register via a contributeTools HarnessPlugin in plugins: (SessionRuntimeConfig has no tools/context field). A new packages/core/test/docImportSurface.smoke.test.mjs regression-locks the import-path half.

  • Observability + gateway-cost docs corrected to the shipped exporter/cost surface (devharness FINDING 73–75). @pleach/core ships no @opentelemetry/* dependency and never reads the global tracer provider — the documented NodeSDK + OTLP recipe captured zero pleach spans. OTel observability and Observability now show the real path: a host-supplied OtelExporter bridge injected via new SessionRuntime({ otelExporter }) (default is NoopOtelExporter, which drops spans). runtime.spans.snapshot() returns { inFlightCount, isShutdown } (exporter state) — to inspect emitted spans you wire a CapturingOtelExporter and read .captured (real fields startTimeNs/endTimeNs/ parentId). And Gateway cost events + the gateway OTel wiring: computeCost was reading tenantId/family/callClass/byokActive/ routingDecision off RouteChatCompletionOutput, which carries none of them (asTenantId(undefined) threw → zero CostEvents) — the example now reads only real output fields + host-supplied observation context, and flags that routeChatCompletion is currently a slice-2 stub (costUsd: 0).

  • Subagents + async-tasks docs reconciled with the host-completion-required reality (devharness FINDING 66–72). Bare @pleach/core's subagent surface is host-completion-required (the host supplies subagentExecutor / drives SubagentManager); the docs presented it as substrate-delivered. Corrected in Subagents: removed the fabricated spawnsSubagent: true auto-escalation flag; LightweightRuntime → the real LightweightSessionRuntime imported from @pleach/core/subagents (not root) with its real constructor; fetchWorkspaceContext/formatWorkspaceContextPrompt moved to the @pleach/core/subagents subpath; the concurrency model corrected (the runtime spawn path caps on the hard SUBAGENT_LIMITS constant and FAILS over-cap rather than queueing — the SubagentManager queue/DAG is host-driven); context.variables noted as currently inert; plus a host-completion caveat. And Async tasks: the async-task tool-loop bridge is not wired in bare core (ASYNC_TASK_BRIDGE_NOT_WIRED), and the "subagent"/"sandbox_exec" task executors are host/plugin-supplied (the in-tree SubagentTaskExecutor is server-only), not "in-tree defaults".

  • Abort + resume docs synced to the shipped runtime behavior (devharness FINDING 56 + 62). Aborting an in-flight turn now records outcome.status: "user-aborted" (not "aborted" / not lumped into provider-error) at BOTH the tool-loop decision call and the synthesis terminal, so cost rollups + compliance separate caller cancellation from provider failure — corrected across session lifecycle, SessionRuntime, turn lifecycle, and API routes. And resuming a session now describes the real three-layer rebuild: storage row → version-guarded checkpoint overlay (the crash-recovery path) → server-only event-log hydration of the ephemeral card-lifecycle state (interrupts/subagents/exports/user cards) onto a transient Session.hydratedHarnessState field — correcting the prior claim that hydrateFromEvents rebuilt messages/channel state.

  • Model-resolution-matrix path corrected — it is host-supplied, not a @pleach/core dir (pkgclean 06 D7). The docs cited the family-lock matrix at the fictional src/graph/modelfamily/ (family-lock) and @pleach/core/ai/modelFamily/matrix.ts (quickstart, provider detection) — neither path exists in the package. The (family × callClass) matrix table is host-supplied and reached through the AgentAdapter.resolveModel<C>() seam; the ProviderFamily set is now pointed at the real @pleach/core/modelfamily export. The routing-decision seam's Ivy-internal host path was removed from routing decisions.

  • Docs reconciled with the shipped @pleach/core runtime (value-prop-vs-impl audit, devharness FINDING 56–64). Corrected doc claims that diverged from the implementation:

    • Time travelfork sets parent_id: source.id (not null).
    • Checkpointing — checkpoints write at message/event boundaries (discriminated by CheckpointMetadata.source), not stamped with a per-stage stageId; SupabaseSaver durability is "replicated"; rollback writes source: "manual" + writes: ["rollback"]; the fork snippet takes a string newSessionId.
    • Session lifecycle — the checkpoint snapshot is authoritative on the live restore path; the event-log canonical reader is a flag-gated shadow today.
    • Sync — interactive conflict resolution (runtime.resolveConflict, the sync.conflict event, the 3xxx code range) is enterprise-tier/planned; open-core uses SyncCoordinator last-writer-wins-on-push with a free-text lastError.
    • Query — dropped the non-existent queryAuditableCalls; corrected getChatUsage / lookupModelCost / getSessionReview / getInterruptChain signatures + return shapes to the real @pleach/core/query surface.
    • Memory — the production extraction path is the graph node (createMemoryExtractionNode), not the memoryExtractionHook → queue pipeline; LearnedFact.source is a provenance string (+createdAt/lastConfirmedAt) on extractor facts, with the object form documented alongside.
    • Lineage — opt-in via config.lineageTracker; the runtime records the session node + a branched_from fork edge, the other relations are host-recorded; completeSession is host-called.

Added

  • Opt-in tool-event preview enrichment for the manifest projection. New runtimeQuirks.enrichToolEventPreviewsForReplay flag (default OFF) lets the host write compact args_preview (tool.started) + output_preview (tool.completed) onto tool events; chatManifestProjection folds them into richer manifest params/output, closing the projection's intentional lossiness vs. the live provider. The previews are scrub-allowlisted (the C8 redaction chain processes them). OFF by default preserves the arguments_hash-only privacy posture. This makes the projection canonical-capable; the projection-canonical flip itself stays gated. See Replay.
  • TimeTravel surfaces the chat manifest (StateSnapshot.manifest). getState / getStateHistory / fork / bulkUpdate now carry the chat-manifest ledger AS-OF a checkpoint, for inspection (it does not feed the next generation — that runs through rollbackToCheckpoint / resumeSession into the live provider). The snapshot rides the checkpoint metadata (round-tripped via SupabaseSaver.metadata_extra; Memory/IndexedDB ride free), mirroring the pendingTasks pattern. See Time travel.
  • ProviderFamilyExhaustedError promoted to the top-level @pleach/core surface. The provider-family cascade terminal (raised when every in-family rung is exhausted) + its isProviderFamilyExhaustedError guard are now public on @pleach/core — previously reachable only via the deep @pleach/core/graph/seams/providerExhaustion path. Catch + narrow it from the top-level import.
  • @pleach/core/cache — content-hash deriver. deriveContentHashKey, canonicalizeKeyInput, and ContentHashKeyInput now have their canonical home in @pleach/core/cache (relocated from @pleach/replay/cache, which re-exports them for back-compat). The move lets @pleach/core derive + stamp a cacheKey into tool.completed / turn.completed events without the forbidden core → replay import. See Subpath exports.
  • @pleach/core/manifest — reload-durability + the manifest as a projection. The chat-manifest ledger (the [Session Manifest] prompt block) now survives a process reload: SessionRuntime.saveSession stamps the live snapshot into the persisted session state and resumeSession rehydrates it (complementing the existing checkpoint rollback restore). New chatManifestProjection / foldChatManifest fold the manifest deterministically from the event log (tool.* / job.* / model.upgraded), replayable via runtime.events.fold and the @pleach/replay stepper — intentionally lossy vs. the live provider (the log carries hashes/sizes, not full params/output), measured by a flag-gated [UXParity:manifest-projection-divergence] shadow probe. See Subpath exports.
  • tool.completed / turn.completed — optional cacheKey payload slot. Lets a deterministic replay consult the provider cache on the row (consumed by @pleach/replay's ReplayHandle). Host- / createCacheMiddleware-populated; core does not derive it (the core → replay boundary forbids importing deriveContentHashKey). See Replay.

Added

  • CI enforcement of the audit contract — new Reference page indexing the audit-gate catalog by the auditability and replayability clause each gate enforces. Covers the @pleach/core event-log gates (audit:auditable-call, audit:auditable-call-soak, audit:event-log-manifest-hash-completeness, the three audit:config-manifest-* gates, audit:c8-event-type-allowlist-coverage, audit:c9-hash-chain-integrity) and the CI jobs that carry them (graphnoderef, local-clone, per-SKU consumer-rehearsal). Cross-linked from Audit gates.
  • Contribution namespaces — new page documenting the nine namespaces every HarnessPlugin contribution hook resolves to (prompts, stream, safety, audit, intent, tools, middleware, policy, lifecycle) — the canonical, audit:plugin-hook-category-assigned-gated contract layout, with representative hooks per namespace and the rolling-out typed namespaced authoring form. Plugin contract gains a cross-link; Authoring a HarnessPlugin reframes its informal 12-bucket grouping as the scan view of these nine canonical namespaces.
  • Config manifest — new page documenting the content-addressable substrate snapshot the runtime writes to harness_config_manifest: one row per distinct plugin/prompt/node/channel/filter set, keyed by a SHA-256 Merkle roll-up (pleach.manifest.v1 prefix, 0x1F separator, mirroring the hash chain's pleach.c9.v1 canonicalization). Per-surface child hashes, the nullable manifest_hash foreign reference on harness_event_log, reference-counted retention (default forever), full-snapshot storage, and the canonical replay/audit query shapes. Marked in-flight — table and event-log column land as additive schema files during rollout.
  • What Pleach writes to your database — new page mapping every @pleach/core table written to a buyer's database, what's default versus opt-in, and the destination-is-yours posture (no phone-home).
  • manifest_hash cross-references added to Event log (stamping section + EventLogRow field) and Schema (rolling-out harness_config_manifest section).
  • OrchestratorClient — new top-level page documenting the per-turn handle the runtime threads through the stream body. Lifted from app-side into the substrate; canonical import path is @pleach/core/runtime/orchestratorClient. Covers the six user-facing facets (config, history, context, tools, model, prompts) and the _internal.graph snapshot consumer code must not touch.
  • streamSingleTurn — new top-level page documenting the canonical per-turn body. Lifted into @pleach/core/strategies/streamSingleTurn/ with a stable helpers barrel re-exporting TurnAccumulator, ToolDefinition, OrchestratorMessage, and ProviderFallbackConfig.
  • Subpath exports — adds two rows to the Runtime + composition table: @pleach/core/runtime/orchestratorClient and @pleach/core/strategies/streamSingleTurn. Both are now named subpath exports rather than wildcard-only reachable.
  • Subpath exports → @pleach/core/quickstart — added under the Wire + tooling cluster. Lists the five LANDED deliverables — createPleachRoute (fetch-handler factory), useChat (Pleach-native React hook), <ChatBox /> (unstyled, accessible), defaultPlugin (empty baseline), providerDetection helpers + constants — plus the benchmark-adjacent createBenchmarkPlugin.
  • Attestation — new top-level page on the Ed25519-signed envelope substrate that sits on top of the hash chain. Documents the @pleach/core/attestation subpath (signer, verifier, key-store interface), the two stub production adapters (AWS KMS, Vault Transit), and the file-backed attestation/testing adapter.
  • Architecture § Boundary rules — adds a sixth row to the gate table: audit:domain-string-purity forbids domain-specific literals in packages/core/src/** across five pattern families. Pairs with the existing lint:harness-boundary row, which forbids domain imports — the new gate covers domain strings.
  • Core "What you get" — new bullet "Composes under an existing Enterprise contract" after the AuditableCall ledger bullet.

Changed

  • Family-lock page documents the host-internal planner carve-out. family-lock.mdx gains a "Host-internal planner calls" section. The lock governs seam calls — synthesize / converse / reasoning / utility on the provider seam — but a host's anchor-plan planner cold-start can run on a pinned host-configured model that never consults the (family x callClass) matrix, so it sits outside the lock by construction, not as a leak. The row is identifiable by stage: "anchor-plan", callClass: "utility", payload.kind: "planGeneration" and carries no fallbackStep / family-exhausted / providerCascade. Guidance: alert on any other non-locked-family row; allow this planner row.
  • The tool-loop decision call is utility-class on its own seam, not the synthesize seam (singleton-per-call-class, D-72). Five pages carried the prior claim that the synthesizer node and the tool-loop llmDecision node share one ProviderSeam<"synthesize"> identity (the old "D-35" statement). The tool-loop continuation decision — "call another tool or finish?" — now runs on a dedicated utility seam, so the synthesize cap is structural: the synthesizer (and the recovery path) are the only consumers of the synthesize seam, and the decision node can't reach the TurnSynthesizeCounter. Corrected in Seams (the singleton section + the LangGraph callout's ProviderSeam<"utility"> type), Graph, Graph node catalog (the llmDecision row's acceptsSeam converseutility, the Stage 2 intro, and the singleton-invariant wire-check), Call classes (the utility row + section now name the tool-loop decision as the canonical utility call), and Multi-synthesize. A reader on the old "shared seam" model would have mis-predicted which node bumps the synthesize counter.
  • Graph lattice docs synced to the current @pleach/core topology across eight pages. The NODE_STAGE_MAP registry is 43 names, not 48. ALLOWED_EDGE_PATTERNS carries nine rows and FORBIDDEN_EDGE_PATTERNS seven, not eight/eight — the tool-loop → post-turn recovery-dispatch edge moved from the forbidden table into the allowed table. Recovery shaping is no longer four synthesize-stage graph nodes (recovery, refusalHint, retryNarration, garbleRecovery) plus a recoveryDispatchPredicate derivation node and a shouldContinueWithGarbleRoute wrapper; it is four post-turn stream filters (refusalHintFilter 100, retryNarrationFilter 200, garbleRecoveryFilter 300, standardRecoveryFilter 400) dispatched via StreamObserverRegistry and locked by audit:recovery-dispatch-single-surface. synthesize is now a true singleton — only synthesizer. Touched Graph, Node catalog, Edge catalog, Nodes, Architecture, Ownership boundaries, Plugin contract, and Audit gates. Node catalog also gains a "How the substrate source is organized" section documenting the src/graph/ layout (nodes/ one-file-per-node, wiring/ registrars split by stage, the topology.ts lattice layer, concern-split seams/ / predicates/ / strategies/), with upstream-contributor steps pointing at the wiring/register<Stage>Nodes.ts registrar.
  • Config manifest foreign key corrected in Config manifest. The harness_event_log.manifest_hash reference is a real foreign key with ON DELETE SET NULL and a load-bearing DEFERRABLE INITIALLY DEFERRED clause, not gate-only as the page previously claimed. Added the reference_count column to the table DDL and cited the audit:config-manifest-fk-constraint-applied and audit:config-manifest-referential-integrity gates.
  • Schema description for @pleach/core amended to name the language-agnostic contract. The description field in the site's Organization + SoftwareApplication JSON-LD graph (inlined in <head> on every page) previously described @pleach/core only in TypeScript terms, contradicting both the marketing surface and the editorial position at /ai.txt. The description now names the wire shapes — HTTP+SSE, StreamEvent, AuditableCall, Checkpoint, version vector — as language-agnostic and clarifies that the npm package is the TypeScript reference distribution. programmingLanguage: ["TypeScript"] stays accurate — the npm package IS TypeScript; the language-agnosticism belongs to the contract, not the publishable artifact. See Language-agnostic contract for the full wire-shape inventory.
  • Cross-docs status-flip pass — rolling correction across ~55 docs pages tracking the alpha-ship of @pleach/compliance, @pleach/gateway, and @pleach/replay. Touched pages include Audit ledger, Event log, Subpath exports, Seams, Prompts, Prompt builder, and Session runtime.

Fixed

  • Family-lock lifetime claim corrected — the page stated "switching family means a new session." The runtime ships a sanctioned in-session re-lock path (sessions.updateProviderModel, emitting a session-lock-resynced event), so switching family is an explicit operation, not a new-session requirement. The lock's real invariant is no silent mid-turn widen, not lifetime immutability.
  • AuditableCall row AuditRecordVersion corrected 13 → 14 — both the literal description and the version-log range (v8 through v14) now match the upstream AUDIT_RECORD_VERSION_HISTORY, whose latest entry is to: 14 (Cluster C: additive rewriteStatus? + tokenCost.callClass).

2026-06-08 — chat-pipeline lift into @pleach/core

Foundational lift bringing OrchestratorClient and streamSingleTurn into the substrate. See the Unreleased section above for the Added/Changed entries. The Pre-Merge Gate audit:domain-string-purity landed alongside.

2026-06-08

Added

  • New page Runtime inspector documenting inspectRuntime() from @pleach/core/inspector — the typed read-only introspection surface, the InspectionReport / CapabilityReport / PluginReport / CapabilityDescriptor shapes, and the 38 known capabilities (29 modern + 9 deprecated).
  • definePleachPlugin() factory section in Plugin contract covering the 8-key PluginCapabilities cluster and the _raw escape hatch.
  • contributeFabricationGuard section documenting the typed FabricationGuardImpl hook (7 methods) that retires the orchestratorHotpath.fabricationGuard untyped-bag entry.
  • CreatePleachRuntimeConfig.host.{strategies, modules, raw} section in Host adapter with the 15-key HostExtensionBundle list and the host.modules list (eventLogWriter, store, interrupt).
  • C9 hash-chain probe section in Tamper-evident hash chain documenting [UXParity:c9-hash-chain-row-stamp] (PE-1) and [UXParity:c9-hash-chain-verify] (PE-2).
  • @pleach/core/inspector row in Subpath exports.

Changed

  • Packages table corrected to real published version — @pleach/core 1.1.0 (was largely stale "Reserved · placeholder" framing).

Fixed

  • Runtime inspector — replaced fictional RuntimeInspection / CapabilityState types with the real InspectionReport / CapabilityReport / PluginReport / CapabilityDescriptor. Corrected the status discriminator to "wired" | "deprecated-wired" | "unwired".
  • Plugin contractdefinePleachPlugin capability fields take values, not thunks. Corrected to the real 8 capability keys (prompts, runtimeAwarePrompts, safetyPolicies, fabricationDetectors, tools, streamObservers, intentToolMap, toolCouplingHints).
  • Host adapterhost.modules corrected to { eventLogWriter, store, interrupt }. host.strategies populated with the real 15-key HostExtensionBundle list.
  • Tamper-evident hash chain — subpath corrected from @pleach/core/event-log to @pleach/core/eventLog (camelCase is the real export).
  • Event-log projections — subpath corrected from @pleach/core/event-log/projections to @pleach/core/eventLog (projections export from the ./eventLog barrel; there is no /projections subpath).

On this page