From 406508f42afb096262347565186d89e37015a29e Mon Sep 17 00:00:00 2001 From: SoulSpace Creator Date: Thu, 30 Jul 2026 12:44:28 +0800 Subject: [PATCH] feat(reasoning): implement provider-neutral invocation foundation --- ARCHITECTURE_DECISIONS.md | 8 + CHANGELOG.md | 6 + DOCUMENTATION_INDEX.md | 23 + README.md | 10 +- ...vidence_Finalization_Specification_v1.0.md | 46 + ...ing_Provider_Adapter_Specification_v1.0.md | 53 + ...Execution_Evidence_Ledger_Contract_v1.0.md | 50 + ...S_Milestone_13_Acceptance_Criteria_v1.0.md | 75 + ...ilestone_13_Codex_Execution_Prompt_v1.0.md | 1790 +++++++++ ...nderOS_Milestone_13_Package_README_v1.0.md | 73 + ..._Evidence_Foundation_Specification_v1.0.md | 81 + ...ilestone_13_Verification_Checklist_v1.0.md | 91 + ...esult_Integrity_Enforcement_Policy_v1.0.md | 51 + ...ral_Reasoning_Evaluation_Framework_v1.0.md | 78 + ...r_Neutral_Reasoning_Execution_Port_v1.0.md | 49 + ...r_Neutral_Reasoning_Input_Contract_v1.0.md | 52 + ...ecution_Policy_and_Budget_Contract_v1.0.md | 59 + ...and_Cancellation_Evidence_Contract_v1.0.md | 86 + ...out_and_Cancellation_Specification_v1.0.md | 63 + ...soning_Invocation_Request_Contract_v1.0.md | 42 + ...der_Capability_Descriptor_Contract_v1.0.md | 44 + ...Reasoning_Result_Envelope_Contract_v1.0.md | 55 + packages/knowledge-schema/README.md | 2 + .../src/durable-reasoning-ledger.ts | 963 +++++ packages/knowledge-schema/src/index.ts | 2 + packages/knowledge-schema/src/reasoning.ts | 1431 +++++++ .../tests/durable-reasoning-ledger.test.ts | 823 +++++ .../knowledge-schema/tests/reasoning.test.ts | 854 +++++ services/knowledge-engine/README.md | 32 + .../application/invoke-governed-reasoning.ts | 965 +++++ ...age-governed-reasoning-execution-ledger.ts | 552 +++ .../reasoning-execution-ledger-port.ts | 28 + .../application/reasoning-execution-port.ts | 50 + .../durable-reasoning-execution-ledger.ts | 661 ++++ .../knowledge-engine/src/domain/reasoning.ts | 1144 ++++++ services/knowledge-engine/src/index.ts | 70 + .../deterministic-fake-reasoning-provider.ts | 280 ++ ...e-governed-reasoning-execution-evidence.ts | 616 ++++ .../tests/fixtures/reasoning-evaluations.ts | 462 +++ .../tests/governed-reasoning.test.ts | 3278 +++++++++++++++++ .../tests/reasoning-evaluation-runner.ts | 1173 ++++++ .../tests/reasoning-fixtures.ts | 188 + 42 files changed, 16455 insertions(+), 4 deletions(-) create mode 100644 docs/milestones/milestone-13/FounderOS_Consumption_Evidence_Finalization_Specification_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Deterministic_Fake_Reasoning_Provider_Adapter_Specification_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Durable_Reasoning_Execution_Evidence_Ledger_Contract_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Milestone_13_Acceptance_Criteria_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Milestone_13_Codex_Execution_Prompt_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Milestone_13_Package_README_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Milestone_13_Provider_Neutral_Reasoning_Invocation_and_Result_Evidence_Foundation_Specification_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Milestone_13_Verification_Checklist_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_No_Provider_Bypass_and_Reasoning_Result_Integrity_Enforcement_Policy_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Evaluation_Framework_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Execution_Port_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Input_Contract_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Policy_and_Budget_Contract_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Receipt_Usage_Cost_Failure_and_Cancellation_Evidence_Contract_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Idempotency_Retry_Timeout_and_Cancellation_Specification_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Request_Contract_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Reasoning_Provider_Capability_Descriptor_Contract_v1.0.md create mode 100644 docs/milestones/milestone-13/FounderOS_Reasoning_Result_Envelope_Contract_v1.0.md create mode 100644 packages/knowledge-schema/src/durable-reasoning-ledger.ts create mode 100644 packages/knowledge-schema/src/reasoning.ts create mode 100644 packages/knowledge-schema/tests/durable-reasoning-ledger.test.ts create mode 100644 packages/knowledge-schema/tests/reasoning.test.ts create mode 100644 services/knowledge-engine/src/application/invoke-governed-reasoning.ts create mode 100644 services/knowledge-engine/src/application/manage-governed-reasoning-execution-ledger.ts create mode 100644 services/knowledge-engine/src/application/reasoning-execution-ledger-port.ts create mode 100644 services/knowledge-engine/src/application/reasoning-execution-port.ts create mode 100644 services/knowledge-engine/src/domain/durable-reasoning-execution-ledger.ts create mode 100644 services/knowledge-engine/src/domain/reasoning.ts create mode 100644 services/knowledge-engine/src/infrastructure/deterministic-fake-reasoning-provider.ts create mode 100644 services/knowledge-engine/src/infrastructure/local-file-governed-reasoning-execution-evidence.ts create mode 100644 services/knowledge-engine/tests/fixtures/reasoning-evaluations.ts create mode 100644 services/knowledge-engine/tests/governed-reasoning.test.ts create mode 100644 services/knowledge-engine/tests/reasoning-evaluation-runner.ts create mode 100644 services/knowledge-engine/tests/reasoning-fixtures.ts diff --git a/ARCHITECTURE_DECISIONS.md b/ARCHITECTURE_DECISIONS.md index 46250e8..699164a 100644 --- a/ARCHITECTURE_DECISIONS.md +++ b/ARCHITECTURE_DECISIONS.md @@ -131,6 +131,14 @@ This ledger records repository-level decisions. Feature-level decisions should m - **Decision:** Define strict, versioned, storage-independent Delivery Ledger records in `@founderos/knowledge-schema`, and keep verification, orchestration, canonical fingerprinting, replay, recovery, integrity checking, index rebuilding, and physical persistence in `@founderos/knowledge-engine`. Persist each original Delivery as one complete immutable committed transaction containing the exact verified Milestone 11 Request, Envelope, Acknowledgment, and Receipt plus permanent idempotency ownership. Persist every later Replay Attempt as a separate append-only audit event that references, but never rewrites, the original result. Chain authoritative events by explicit sequence and previous fingerprint. The local adapter stages and flushes a complete event, installs it atomically, then atomically advances a separately fingerprinted commit-head marker; only the marker-bounded prefix is committed. Derived lookups are non-authoritative, bounded, fingerprinted, and deterministically rebuildable. Expired idempotency keys remain permanently reserved in version `1.0`; expiration never erases authoritative evidence. - **Consequences:** Exact original results, single-delivery rules, idempotency ownership, replay history, and current validation evidence are recoverable and independently verifiable after restart. A crash before commit-head replacement leaves an ignored staging or uncommitted event; a crash after replacement requires the complete referenced event. The initial adapter assumes a cooperative local administrator, one explicit writer, atomic same-filesystem rename, and file flush support; it does not claim distributed writer safety, hostile privileged-filesystem resistance, network-filesystem consensus, coordinated rollback protection, or multi-region durability. Archival, destructive compaction, databases, distributed persistence, provider execution, authentication, authorization, agents, Hermes, and MCP remain deferred. +## ADR-0017: Invoke reasoning only from an exact durable Delivery transaction + +- **Status:** Accepted +- **Date:** 2026-07-29 +- **Context:** Milestones 10–12 create, deliver, and durably preserve governed Context Packages, but a reasoning executor must not turn those artifacts into an ungoverned provider call or lose the exact Delivery, Receipt, Consumer, Policy, Active Snapshot, and Registry bindings that made the context authoritative. +- **Decision:** Define strict, versioned, storage-independent Reasoning Invocation, provider-neutral Input and Capability Descriptor, Execution Policy, Attempt, Outcome, Result, Usage, Cost, Failure, Timeout, Cancellation, Consumption, and execution-ledger contracts in `@founderos/knowledge-schema`. `@founderos/knowledge-engine` exposes `invokeGovernedReasoning` as the public execution facade. It accepts only an exact Milestone 12 transaction identity and governed ledgers; recovers and independently verifies the durable Delivery transaction and all governed bindings before matching the verified Invocation against the fixed deterministic fake-provider Capability Descriptor. Provider-neutral character, attempt, and timeout budgets in the verified Execution Policy are authoritative. Invocation idempotency permanently owns one canonical request; retries produce sequential immutable Attempts and Outcomes, while explicit deadline and cancellation evidence control terminal classification. One independently verified Result and finalized Consumption Evidence are atomically committed as append-only execution evidence. No public path accepts raw knowledge, Query Results, unverified Delivery artifacts, hidden context, provider injection, or low-level execution-ledger writes. +- **Consequences:** Every finalized result has an independently verifiable chain from a committed Delivery through its exact Invocation, selected Capability, complete Attempt history, terminal evidence, Result, and finalized Consumption Evidence; identical finalized invocation replay returns that original result, while conflicting reuse or finalization fails. Milestone 13 instantiates only the deterministic fake provider: it makes no network or credential access and is not a real-provider integration. The local execution-evidence adapter is Git-ignored, cooperative, single-process, and same-filesystem only; its lock can require operator cleanup after a failed process and it provides neither distributed coordination nor hostile privileged-filesystem or coordinated-rollback protection. Automatic abandoned-invocation resume, real providers or provider selection, streaming, tools, Agents, Hermes, MCP, authentication, authorization, semantic retrieval, embeddings, ranking, knowledge graphs, databases, remote persistence, and UI remain deferred. + ## ADR template ```markdown diff --git a/CHANGELOG.md b/CHANGELOG.md index 832fdf9..3016e95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,3 +40,9 @@ All notable changes to FounderOS will be documented here. - Forty executable deterministic Milestone 11 evaluations plus contract, exact request/policy binding, trusted historical-prefix verification, authoritative artifact verification, freshness, capability, tamper, path and credential privacy, replay-attempt evidence, receipt, immutability, accessor-safety, and bypass tests. - Strict storage-independent Durable Context Delivery Ledger, immutable Request registration, permanent idempotency ownership, exact Delivery artifact wrapper, atomic transaction, Replay Attempt, expiration, recovery, integrity, and derived-index contracts. - A governed local file-backed Delivery Ledger with a fingerprinted commit-head commit point, single-writer protection, compare-and-swap head and ownership checks, restart recovery, exact original-result replay, current Policy and Freshness evidence, tamper-evident audit chaining, deterministic index rebuilding, crash-fault evaluation, and recursive filesystem-safety enforcement. +- Milestone 13 provider-neutral Reasoning Invocation contracts for governed Inputs, Capability Descriptors and compatibility, authoritative Execution Policies and character/attempt/timeout budgets, immutable Attempts and Outcomes, Result Envelopes, Usage/Cost/Failure/Timeout/Cancellation Evidence, finalized Consumption Evidence, permanent Invocation ownership, atomic finalization, and storage-independent append-only execution-evidence ledgers. +- A single governed invocation workflow that verifies one exact durable Milestone 12 Delivery transaction and its Context, Consumer, Policy, Freshness, Active Snapshot, and Registry bindings before deterministic capability matching, fake-provider execution, append-only Attempt evidence, independently verifiable Result construction, and Consumption finalization. +- The fixed deterministic fake provider, with explicit success, failure, retry, timeout, cancellation, overflow, malformed, contradictory, path-bearing, and credential-bearing evaluation modes; it has no production provider, network, credential, implicit-clock, randomness, Repository, tool, Agent, Hermes, or MCP dependency. +- A governed local file-backed execution-evidence adapter with expected-head checks, cooperative single-writer locking, fingerprinted atomic commit markers, restart recovery, fail-closed authoritative integrity verification, and non-authoritative rebuildable derived indexes. +- Sixty-three executable deterministic Milestone 13 evaluation definitions and focused no-provider-bypass, tamper, replay, recovery, capability, lifecycle, and adapter-safety tests. The full verification suite passes 719 tests in 37 files. +- Milestone 13 explicitly excludes real providers and provider selection, credentials, streaming, tools, Agents, Hermes, MCP, authentication, authorization, semantic retrieval, embeddings, ranking, knowledge graphs, databases, distributed or remote persistence, automatic abandoned-invocation resume, and UI. diff --git a/DOCUMENTATION_INDEX.md b/DOCUMENTATION_INDEX.md index d3868cd..dc95820 100644 --- a/DOCUMENTATION_INDEX.md +++ b/DOCUMENTATION_INDEX.md @@ -168,6 +168,29 @@ The documents below are the official FounderOS v1.0 bootstrap specification, org - [Milestone 12 Verification Checklist v1.0](./docs/milestones/milestone-12/FounderOS_Milestone_12_Verification_Checklist_v1.0.md) - [Milestone 12 Codex Execution Prompt v1.0](./docs/milestones/milestone-12/FounderOS_Milestone_12_Codex_Execution_Prompt_v1.0.md) +### Milestone 13 — Provider-Neutral Reasoning Invocation and Result Evidence Foundation + +Milestone 13 is implemented by storage-independent contracts in [`@founderos/knowledge-schema`](./packages/knowledge-schema/README.md) and the governed invocation facade, deterministic fake provider, and local append-only execution-evidence adapter in [`@founderos/knowledge-engine`](./services/knowledge-engine/README.md). It consumes an exact committed Milestone 12 Delivery transaction; it does not implement a production provider or a general reasoning runtime. + +- [Milestone 13 Package README v1.0](./docs/milestones/milestone-13/FounderOS_Milestone_13_Package_README_v1.0.md) +- [Provider-Neutral Reasoning Invocation and Result Evidence Foundation Specification v1.0](./docs/milestones/milestone-13/FounderOS_Milestone_13_Provider_Neutral_Reasoning_Invocation_and_Result_Evidence_Foundation_Specification_v1.0.md) +- [Reasoning Invocation Request Contract v1.0](./docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Request_Contract_v1.0.md) +- [Provider-Neutral Reasoning Input Contract v1.0](./docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Input_Contract_v1.0.md) +- [Reasoning Provider Capability Descriptor Contract v1.0](./docs/milestones/milestone-13/FounderOS_Reasoning_Provider_Capability_Descriptor_Contract_v1.0.md) +- [Reasoning Execution Policy and Budget Contract v1.0](./docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Policy_and_Budget_Contract_v1.0.md) +- [Provider-Neutral Reasoning Execution Port v1.0](./docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Execution_Port_v1.0.md) +- [Deterministic Fake Reasoning Provider Adapter Specification v1.0](./docs/milestones/milestone-13/FounderOS_Deterministic_Fake_Reasoning_Provider_Adapter_Specification_v1.0.md) +- [Reasoning Invocation Idempotency, Retry, Timeout, and Cancellation Specification v1.0](./docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Idempotency_Retry_Timeout_and_Cancellation_Specification_v1.0.md) +- [Reasoning Execution Receipt, Usage, Cost, Failure, and Cancellation Evidence Contract v1.0](./docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Receipt_Usage_Cost_Failure_and_Cancellation_Evidence_Contract_v1.0.md) +- [Reasoning Result Envelope Contract v1.0](./docs/milestones/milestone-13/FounderOS_Reasoning_Result_Envelope_Contract_v1.0.md) +- [Consumption Evidence Finalization Specification v1.0](./docs/milestones/milestone-13/FounderOS_Consumption_Evidence_Finalization_Specification_v1.0.md) +- [Durable Reasoning Execution Evidence Ledger Contract v1.0](./docs/milestones/milestone-13/FounderOS_Durable_Reasoning_Execution_Evidence_Ledger_Contract_v1.0.md) +- [No-Provider-Bypass and Reasoning Result Integrity Enforcement Policy v1.0](./docs/milestones/milestone-13/FounderOS_No_Provider_Bypass_and_Reasoning_Result_Integrity_Enforcement_Policy_v1.0.md) +- [Provider-Neutral Reasoning Evaluation Framework v1.0](./docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Evaluation_Framework_v1.0.md) +- [Milestone 13 Acceptance Criteria v1.0](./docs/milestones/milestone-13/FounderOS_Milestone_13_Acceptance_Criteria_v1.0.md) +- [Milestone 13 Verification Checklist v1.0](./docs/milestones/milestone-13/FounderOS_Milestone_13_Verification_Checklist_v1.0.md) +- [Milestone 13 Codex Execution Prompt v1.0](./docs/milestones/milestone-13/FounderOS_Milestone_13_Codex_Execution_Prompt_v1.0.md) + ## Repository governance - [Architecture decisions](./ARCHITECTURE_DECISIONS.md) diff --git a/README.md b/README.md index ae1f03c..9104871 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,14 @@ FounderOS is an AI-native operating system for founder decision-making, organizational memory, and governed AI-assisted execution. This repository is a documentation-first TypeScript monorepo. -The repository currently provides the governed KnowledgeOS schema, ingestion, migration, corpus-backed repository snapshots, deterministic comparison and governed change sets, human-controlled snapshot review, a local durable snapshot registry and activation audit trail, deterministic queries, governed context assembly, a provider-neutral governed Context Consumer delivery boundary, and a restart-safe local Context Delivery Ledger with durable idempotency and Replay Attempt evidence. It does **not** implement a general-purpose application database, distributed or remote persistence, automatic activation or synchronization, semantic retrieval, LLM execution, Hermes, an agent runtime, MCP connectors, or a user interface. +The repository currently provides the governed KnowledgeOS schema, ingestion, migration, corpus-backed repository snapshots, deterministic comparison and governed change sets, human-controlled snapshot review, a local durable snapshot registry and activation audit trail, deterministic queries, governed context assembly, a provider-neutral governed Context Consumer delivery boundary, and a restart-safe local Context Delivery Ledger with durable idempotency and Replay Attempt evidence. It does **not** implement a general-purpose application database, distributed or remote persistence, automatic activation or synchronization, semantic retrieval, real-provider or production-model execution, Hermes, an agent runtime, MCP connectors, or a user interface. ## Architecture at a glance FounderOS separates human interaction, intelligence, orchestration, knowledge and memory, integrations, and infrastructure. Knowledge is retrieved before important actions; reasoning is separate from execution; human approval remains authoritative for strategic, external, irreversible, and high-risk actions. +Milestone 13 also provides a governed provider-neutral reasoning boundary backed only by a deterministic fake provider and append-only execution evidence. It does not connect to or emulate a production model provider. + Repository dependencies must flow in one direction: ```text @@ -20,12 +22,12 @@ The official specifications are indexed in [DOCUMENTATION_INDEX.md](./DOCUMENTAT ## Implemented foundations -- [`@founderos/knowledge-schema`](./packages/knowledge-schema/README.md) provides strict runtime schemas and inferred TypeScript contracts for KnowledgeOS metadata, objects, migration, queries, repositories, lifecycle and durable registry evidence, governed context packages, Consumer delivery, and storage-independent durable Delivery Ledger records and results. -- [`@founderos/knowledge-engine`](./services/knowledge-engine/README.md) provides read-only ingestion, manifest-controlled Priority 1 corpus migration, corpus-backed repository initialization, deterministic snapshots and queries, governed lifecycle and durable activation, deterministic budget-bounded context assembly, fail-closed provider-neutral delivery, and a governed append-only Delivery Ledger with restart recovery, audit verification, and rebuildable derived indexes. +- [`@founderos/knowledge-schema`](./packages/knowledge-schema/README.md) provides strict runtime schemas and inferred TypeScript contracts for KnowledgeOS metadata, objects, migration, queries, repositories, lifecycle and durable registry evidence, governed context packages, Consumer delivery, and storage-independent durable Delivery and Reasoning Execution Ledger contracts and results. +- [`@founderos/knowledge-engine`](./services/knowledge-engine/README.md) provides read-only ingestion, manifest-controlled Priority 1 corpus migration, corpus-backed repository initialization, deterministic snapshots and queries, governed lifecycle and durable activation, deterministic budget-bounded context assembly, fail-closed provider-neutral delivery, governed append-only Delivery and Reasoning Execution ledgers, and deterministic fake-provider reasoning with independently verifiable result evidence. - [`specs/knowledge-templates`](./specs/knowledge-templates) provides valid Markdown templates for all seven KnowledgeOS object types. - [`knowledge/migration-manifest.yaml`](./knowledge/migration-manifest.yaml) binds the eight canonical FounderOS Priority 1 documents to reviewed object identities, logical destinations, metadata, and source hashes. -Automatic corpus refresh, vault watching, background synchronization or activation, database and distributed adapters, remote coordination and replication, semantic retrieval, embeddings, ranking, graph storage, LLM or agent execution, connectors, and interfaces remain unimplemented. Milestone 09 and 12 persistence is deliberately limited to explicit, Git-ignored, cooperative single-writer local runtimes; see the [knowledge-engine durability documentation](./services/knowledge-engine/README.md#milestone-12-durable-context-delivery-ledger) before operating them. +Automatic corpus refresh, vault watching, background synchronization or activation, database and distributed adapters, remote coordination and replication, semantic retrieval, embeddings, ranking, graph storage, real-provider or agent execution, connectors, and interfaces remain unimplemented. Milestone 09, 12, and 13 persistence is deliberately limited to explicit, Git-ignored, cooperative single-writer local runtimes; see the [Milestone 12](./services/knowledge-engine/README.md#milestone-12-durable-context-delivery-ledger) and [Milestone 13](./services/knowledge-engine/README.md#milestone-13-governed-reasoning-invocation) durability documentation before operating them. ## Repository layout diff --git a/docs/milestones/milestone-13/FounderOS_Consumption_Evidence_Finalization_Specification_v1.0.md b/docs/milestones/milestone-13/FounderOS_Consumption_Evidence_Finalization_Specification_v1.0.md new file mode 100644 index 0000000..2bd31c0 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Consumption_Evidence_Finalization_Specification_v1.0.md @@ -0,0 +1,46 @@ +# FounderOS Consumption Evidence Finalization Specification v1.0 + +## Purpose + +Define how Milestone 11 Consumption Evidence becomes complete after a governed Reasoning Invocation finishes. + +## Finalized Consumption Evidence + +The final record should bind: + +- Contract version +- Consumption ID +- Delivery Receipt ID and fingerprint +- Invocation Request ID and fingerprint +- Invocation idempotency key +- Provider Capability ID and fingerprint +- Final Result Envelope ID and fingerprint +- Final outcome +- Attempt history summary +- Started-at evidence +- Completed-at evidence +- Usage Evidence fingerprint +- Cost Evidence fingerprint +- Failure, Timeout, or Cancellation Evidence fingerprint when applicable +- Durable ledger transaction reference +- Canonical Consumption Evidence fingerprint + +## Finalization Rules + +- Consumption cannot finalize before a terminal Result Envelope exists. +- Exactly one final Consumption Evidence record exists per finalized Invocation. +- Identical finalization replay is idempotent. +- Conflicting finalization fails. +- Finalization never modifies the Delivery Envelope or Receipt. +- Attempt history remains separately auditable. +- Finalized evidence must be append-only when persisted. + +## Durable Binding + +Milestone 13 should extend the existing durable governance boundary using a storage-independent execution-evidence port or a compatible versioned extension to the Milestone 12 ledger. + +Do not expose arbitrary low-level record insertion. + +## Principle + +Consumption Evidence closes the governed chain from knowledge delivery to reasoning outcome. diff --git a/docs/milestones/milestone-13/FounderOS_Deterministic_Fake_Reasoning_Provider_Adapter_Specification_v1.0.md b/docs/milestones/milestone-13/FounderOS_Deterministic_Fake_Reasoning_Provider_Adapter_Specification_v1.0.md new file mode 100644 index 0000000..0fc0dc7 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Deterministic_Fake_Reasoning_Provider_Adapter_Specification_v1.0.md @@ -0,0 +1,53 @@ +# FounderOS Deterministic Fake Reasoning Provider Adapter Specification v1.0 + +## Purpose + +Define a deterministic adapter used to prove Reasoning Invocation, Result Evidence, retries, failures, timeouts, and cancellation without calling a real provider. + +## Required Behavior + +For identical: + +- Verified Invocation Request +- Delivery Envelope +- Capability Descriptor +- Execution Policy +- Attempt number +- Explicit evaluation time +- Configured fixture mode + +the fake provider must return byte-identical canonical output. + +## Fixture Modes + +The adapter should support deterministic modes such as: + +- Successful structured response +- Successful empty response +- Output-budget overflow +- Deterministic transient failure +- Deterministic permanent failure +- Timeout +- Cancellation before execution +- Cooperative cancellation +- Malformed provider outcome for verifier testing + +## Success Output + +A success result may deterministically derive content from: + +- Invocation Request fingerprint +- Context Package fingerprint +- Instruction fingerprints +- Fixture mode +- Attempt number + +It must not invent hidden knowledge or access repository state. + +## Failure Safety + +The adapter must not read environment credentials, call a network, use random numbers, or depend on wall-clock time. + +## Principle + +The fake provider proves execution governance and evidence integrity without pretending to be an intelligent production model. diff --git a/docs/milestones/milestone-13/FounderOS_Durable_Reasoning_Execution_Evidence_Ledger_Contract_v1.0.md b/docs/milestones/milestone-13/FounderOS_Durable_Reasoning_Execution_Evidence_Ledger_Contract_v1.0.md new file mode 100644 index 0000000..6bc71ef --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Durable_Reasoning_Execution_Evidence_Ledger_Contract_v1.0.md @@ -0,0 +1,50 @@ +# FounderOS Durable Reasoning Execution Evidence Ledger Contract v1.0 + +## Purpose + +Define the storage-independent append-only boundary for Invocation ownership, execution attempts, finalized Result Envelopes, and Consumption Evidence. + +## Ledger Responsibilities + +The ledger must support: + +- Registering Invocation idempotency ownership +- Reading Invocation ownership +- Appending immutable Execution Attempts +- Reading ordered Attempt history +- Finalizing one Invocation Result +- Reading the finalized Result Envelope +- Reading finalized Consumption Evidence +- Recovering execution state after restart +- Verifying execution-evidence integrity +- Rebuilding non-authoritative indexes + +## Authoritative Record Categories + +1. Invocation ownership record +2. Execution Attempt record +3. Attempt outcome evidence record +4. Finalized Result transaction record +5. Result Envelope record +6. Final Consumption Evidence record +7. Integrity checkpoint record + +## Required Invariants + +- One idempotency key owns one canonical Invocation. +- Attempt numbers are unique and sequential per Invocation. +- Every Attempt references the exact Invocation and Provider Capability. +- Exactly one finalized Result exists per finalized Invocation. +- Final Consumption Evidence references the finalized Result. +- Identical finalization is idempotent. +- Conflicting finalization fails. +- Authoritative records are immutable and append-only. +- Derived indexes are rebuildable and non-authoritative. + +## Storage Independence + +Shared contracts must not expose filesystem, SQL, database, provider, or model-specific concepts. + +## Principle + +Execution evidence must remain recoverable and auditable independently of the provider adapter that produced it. diff --git a/docs/milestones/milestone-13/FounderOS_Milestone_13_Acceptance_Criteria_v1.0.md b/docs/milestones/milestone-13/FounderOS_Milestone_13_Acceptance_Criteria_v1.0.md new file mode 100644 index 0000000..c1a3d69 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Milestone_13_Acceptance_Criteria_v1.0.md @@ -0,0 +1,75 @@ +# FounderOS Milestone 13 Acceptance Criteria v1.0 + +## Contract Criteria + +- [ ] Reasoning Invocation Request contract is implemented. +- [ ] Provider Capability Descriptor contract is implemented. +- [ ] Provider-neutral input contract is implemented. +- [ ] Execution Policy contract is implemented. +- [ ] Result Envelope and execution-evidence contracts are implemented. +- [ ] Consumption Evidence finalization contract is implemented. +- [ ] Unknown fields, unsupported versions, and forged fingerprints are rejected. +- [ ] Shared contracts remain provider, model, storage, and agent independent. + +## Delivery Binding Criteria + +- [ ] Every invocation binds to one verified Delivery Envelope and Receipt. +- [ ] Context Package, Active Snapshot, Registry, Consumer, and Policy bindings are preserved. +- [ ] Invocation without verified durable Delivery evidence fails. +- [ ] No raw knowledge or Query Result bypass exists. + +## Capability Criteria + +- [ ] Provider Capability matching is deterministic. +- [ ] Input and output limits are enforced. +- [ ] Timeout, retry, cancellation, and evidence compatibility are enforced. +- [ ] Capability mismatch fails before execution. +- [ ] Provider Capability substitution is detected. + +## Execution Criteria + +- [ ] A deterministic fake provider is implemented. +- [ ] No network or credential access occurs. +- [ ] Success, failure, timeout, and cancellation outcomes are distinct. +- [ ] Output budget is enforced. +- [ ] Malformed provider outcomes fail closed. + +## Idempotency and Retry Criteria + +- [ ] Invocation idempotency is enforced. +- [ ] Identical replay returns the original finalized result. +- [ ] Conflicting key reuse fails. +- [ ] Retry creates a new immutable attempt. +- [ ] Attempt limits are enforced. +- [ ] Prior attempt evidence is never rewritten. + +## Evidence Criteria + +- [ ] Execution Receipt verifies independently. +- [ ] Usage Evidence verifies independently. +- [ ] Cost Evidence status and amount semantics verify. +- [ ] Failure, Timeout, and Cancellation Evidence verify. +- [ ] Result Envelope verifies independently. +- [ ] Final Consumption Evidence closes the exact Delivery-to-Result chain. + +## Durability Criteria + +- [ ] Finalized execution evidence is append-only through a governed durable boundary. +- [ ] Finalization survives restart when persistence is implemented. +- [ ] Identical finalization replay is idempotent. +- [ ] Conflicting finalization fails. +- [ ] Low-level persistence bypass is not publicly exposed. + +## Regression Criteria + +- [ ] All Milestone 04–12 tests remain green. +- [ ] Milestone 11 and 12 no-context-bypass guarantees remain mandatory. +- [ ] New Milestone 13 tests pass. + +## Non-Goals + +Milestone 13 does not include real provider adapters, credentials, streaming, tool calling, Agent or Hermes runtime, MCP, authorization, semantic retrieval, embeddings, vector databases, ranking, knowledge graphs, or UI. + +## Definition of Done + +FounderOS can execute a governed provider-neutral Reasoning Invocation through a deterministic fake provider, produce and durably bind independently verifiable result evidence, and finalize Consumption Evidence without invoking a real model provider. diff --git a/docs/milestones/milestone-13/FounderOS_Milestone_13_Codex_Execution_Prompt_v1.0.md b/docs/milestones/milestone-13/FounderOS_Milestone_13_Codex_Execution_Prompt_v1.0.md new file mode 100644 index 0000000..9dce625 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Milestone_13_Codex_Execution_Prompt_v1.0.md @@ -0,0 +1,1790 @@ +# FounderOS Milestone 13 Codex Execution Prompt v1.0 + +## Role and Mission + +You are the lead engineer responsible for implementing **FounderOS Milestone 13 — Provider-Neutral Reasoning Invocation and Result Evidence Foundation**. + +Your responsibility is to implement this milestone completely, preserve every Milestone 04–12 governance and durability guarantee, verify the entire execution and evidence lifecycle, prepare the work for review, and return a formal completion report. + +Do not stop after analysis or planning. + +Do not declare completion unless: + +- Every required verification gate passes. +- Every prior milestone regression remains green. +- The final independent whole-branch review contains no unresolved Critical, Important, or Minor findings. + +Milestone 13 must not call a real LLM, reasoning provider, remote model API, local production model, Agent runtime, Hermes runtime, MCP integration, or external service. + +--- + +## 1. Repository Preparation + +Before modifying any file: + +1. Fetch the latest remote state. +2. Confirm Milestone 12 has been merged into the latest `main`. +3. Confirm the work is based on that merged state. +4. Create or switch to: + +```bash +codex/milestone-13 +``` + +5. Inspect: + +```bash +git status +git branch --show-current +git log --oneline --decorate -15 +git merge-base HEAD origin/main +git rev-parse origin/main +``` + +Preserve all legitimate work. + +Do not: + +- Reset unrelated changes +- Discard unrelated changes +- Rewrite unrelated history +- Amend another milestone's commit +- Delete or move user files +- Hide repository-state problems +- Commit generated runtime artifacts + +If unrelated changes exist: + +- Report them clearly. +- Isolate Milestone 13 safely. +- Continue only when the milestone changes can remain separate. + +Do not commit: + +- `.DS_Store` +- iCloud duplicate or conflict files +- Local Delivery Ledger runtime data +- Generated Invocation Requests +- Generated Result Envelopes +- Generated Execution Receipts +- Generated Consumption Evidence +- Fake-provider fixture output +- Lock files +- Staging files +- Temporary files +- Evaluation output +- Generated `dist/` directories +- Test artifacts +- Physical-path-bearing debug files +- Credentials, tokens, API keys, or secret-bearing files + +--- + +## 2. Required Reading + +Before implementation, read and follow: + +- `README.md` +- `AGENTS.md` +- `CONTRIBUTING.md` +- `ARCHITECTURE_DECISIONS.md` +- `DOCUMENTATION_INDEX.md` +- `CHANGELOG.md` +- `docs/reviews/REPOSITORY_AUDIT_v1.0.md` +- Every approved specification under `docs/milestones/milestone-04/` +- Every approved specification under `docs/milestones/milestone-05/` +- Every approved specification under `docs/milestones/milestone-06/` +- Every approved specification under `docs/milestones/milestone-07/` +- Every approved specification under `docs/milestones/milestone-08/` +- Every approved specification under `docs/milestones/milestone-09/` +- Every approved specification under `docs/milestones/milestone-10/` +- Every approved specification under `docs/milestones/milestone-11/` +- Every approved specification under `docs/milestones/milestone-12/` +- Every approved specification under `docs/milestones/milestone-13/` +- Current implementations under `packages/knowledge-schema/` +- Current implementations under `services/knowledge-engine/` + +Treat the approved Milestone 13 specification set as the implementation authority. + +Understand and preserve: + +- Milestone 04 migration and provenance authority +- Milestone 05 deterministic exact Query behavior +- Milestone 06 Repository and Candidate Source boundaries +- Milestone 07 Snapshot identity +- Milestone 08 lifecycle, comparison, approval, rejection, and activation governance +- Milestone 09 durable Snapshot Registry, audit chain, recovery, and integrity verification +- Milestone 10 governed Context Assembly, budgets, provenance, omission evidence, reproducibility, and package verification +- Milestone 11 Consumer identity, Capability matching, Policy Decision Evidence, Freshness, Delivery Envelope, Acknowledgment, Receipt, Replay Evidence, and no-context-bypass enforcement +- Milestone 12 durable Delivery Ledger, permanent idempotency ownership, atomic Delivery transactions, Replay Attempt records, restart recovery, audit-chain verification, bounded derived indexes, and filesystem safety + +Do not create competing systems for: + +- Query +- Repository +- Snapshot +- Registry +- Context Package +- Delivery Request +- Delivery Envelope +- Delivery Receipt +- Replay Evidence +- Durable Delivery Ledger +- Fingerprinting +- Canonical serialization +- Consumer identity +- Policy Evidence + +Extend the existing architecture. + +Preserve backward compatibility unless an approved Milestone 13 document explicitly requires a compatible, versioned extension. + +--- + +## 3. Milestone Objective + +Implement the first governed provider-neutral Reasoning Invocation boundary. + +The system must be able to: + +- Start from one exact durable Milestone 12 Delivery transaction. +- Verify its Delivery Envelope and Receipt. +- Construct and validate a Reasoning Invocation Request. +- Match the request against a Provider Capability Descriptor. +- Execute only through a provider-neutral port. +- Use only a deterministic fake provider in Milestone 13. +- Produce Success, Failure, Timeout, or Cancellation evidence. +- Enforce Invocation idempotency. +- Create immutable execution attempts. +- Apply verified retry policy. +- Enforce input, output, timeout, and attempt budgets. +- Produce an independently verifiable Reasoning Result Envelope. +- Produce Usage and Cost Evidence. +- Finalize Milestone 11 Consumption Evidence. +- Persist final execution evidence through a governed, storage-independent, append-only boundary. +- Recover or replay finalization deterministically where persistence is implemented. +- Preserve the complete chain back to the Active Snapshot and Context Package. + +The milestone must not execute a real production model. + +--- + +## 4. Target Architecture + +Implement this governed flow: + +```text +Durably Committed Delivery Transaction + | + v +Verified Delivery Envelope and Receipt + | + v +Reasoning Invocation Request + | + v +Provider Capability Matching + | + v +Execution Policy Validation + | + v +Invocation Idempotency Resolution + | + v +Provider-Neutral Execution Port + | + v +Deterministic Fake Provider + | + v +Execution Attempt Evidence + | + v +Reasoning Result Envelope + | + v +Finalized Consumption Evidence + | + v +Governed Append-Only Execution Evidence +``` + +Every result must remain traceable to: + +- Delivery transaction +- Delivery Envelope +- Delivery Receipt +- Consumer +- Context Package +- Active Snapshot +- Registry integrity evidence +- Policy Decision Evidence +- Invocation Request +- Provider Capability Descriptor +- Execution Policy +- Execution Attempt + +--- + +## 5. Package Ownership and Dependency Rules + +Maintain: + +```text +knowledge-engine -> knowledge-schema +``` + +### `@founderos/knowledge-schema` owns + +- Reasoning Invocation Request contracts +- Provider Capability Descriptor contracts +- Provider-neutral input contracts +- Execution Policy contracts +- Compatibility-result contracts +- Execution Attempt contracts +- Result Envelope contracts +- Execution Receipt contracts +- Usage Evidence contracts +- Cost Evidence contracts +- Failure Evidence contracts +- Timeout Evidence contracts +- Cancellation Evidence contracts +- Finalized Consumption Evidence contracts +- Invocation finalization contracts +- Stable statuses and reason codes +- Verification-result contracts +- Contract versions +- Runtime schemas +- Inferred TypeScript types + +### `@founderos/knowledge-engine` owns + +- Durable Delivery resolution +- Milestone 11 and 12 artifact verification +- Invocation validation and orchestration +- Provider Capability matching +- Execution Policy evaluation +- Invocation idempotency resolution +- Attempt lifecycle +- Retry, timeout, and cancellation handling +- Provider-neutral execution port +- Deterministic fake provider adapter +- Result Envelope construction +- Evidence generation +- Independent verification +- Consumption Evidence finalization +- Governed append-only execution-evidence persistence +- Recovery or finalization replay where applicable + +### Shared Contract Restrictions + +Shared contracts must not expose: + +- Vendor names +- Production model names +- Provider API payloads +- Chat-completions schemas +- Provider-specific roles +- Temperature, top-p, top-k, or vendor sampling controls +- Provider tokenizers +- API keys +- Credentials +- Network endpoints +- Filesystem paths +- SQL tables +- Database handles +- Agent runtime types +- Hermes types +- MCP types + +--- + +## 6. Implement the Reasoning Invocation Request + +Implement a strict, versioned Reasoning Invocation Request. + +It must bind: + +- Invocation Request ID +- Delivery transaction ID +- Delivery Envelope ID and fingerprint +- Delivery Receipt ID and fingerprint +- Context Package ID and fingerprint +- Active Snapshot binding +- Registry integrity binding +- Consumer ID and Descriptor fingerprint +- Policy Decision Evidence fingerprint +- Invocation purpose +- Provider Capability requirements +- Provider-neutral Reasoning Input +- Execution Policy +- Invocation idempotency key +- Request actor +- Request reason +- Requested-at evidence +- Canonical Invocation Request fingerprint + +Reject: + +- Unknown fields +- Unsupported versions +- Empty purpose +- Empty reason +- Invalid identifiers +- Invalid Delivery transaction +- Forged Envelope or Receipt binding +- Forged Context Package binding +- Consumer substitution +- Policy Evidence substitution +- Unsupported input content +- Contradictory Execution Policy +- Invalid idempotency key +- Physical paths +- Credential-bearing keys or values +- Accessor-backed input +- Noncanonical text +- Forged Invocation fingerprint + +The Invocation Request must not contain: + +- Provider credentials +- Real provider selection +- Production model ID +- Tool definitions +- Agent instructions +- Hidden knowledge +- Raw Knowledge Objects +- Full Query Results + +--- + +## 7. Verify Durable Delivery Before Invocation + +Before Invocation acceptance: + +1. Resolve the exact committed Milestone 12 Delivery transaction. +2. Verify the complete Delivery Ledger integrity required by the operation. +3. Verify Delivery Request registration. +4. Verify idempotency ownership. +5. Verify Delivery Envelope. +6. Verify Consumer Acknowledgment. +7. Verify Delivery Receipt. +8. Verify Context Package. +9. Verify Active Snapshot and Registry bindings. +10. Verify Consumer identity. +11. Verify Policy Decision Evidence. +12. Verify Freshness and historical delivery rules. +13. Verify no-context-bypass evidence. + +Fail closed on any mismatch. + +Do not allow a public Invocation API that accepts an arbitrary Envelope-like object and bypasses durable Delivery verification. + +--- + +## 8. Implement Provider-Neutral Reasoning Input + +Implement strict, versioned provider-neutral input contracts. + +Support stable Instruction Blocks such as: + +- System constraint +- Task instruction +- Context reference +- Output requirement +- Evaluation directive + +Each block must include: + +- Stable block ID +- Block type +- Canonical text +- Priority +- Source classification +- Block fingerprint + +The input must also include: + +- Exact Context Package reference +- Exact Delivery Envelope reference +- Output requirements +- Constraint blocks +- Evaluation metadata where applicable +- Canonical input fingerprint + +### Required Restrictions + +Do not use: + +- OpenAI-style message roles as the canonical shared contract +- Anthropic-specific content blocks +- Google-specific request structure +- Vendor model parameters +- Tool call payloads +- Hidden context +- Extra knowledge outside the Delivery Envelope + +Reject: + +- Duplicate block IDs +- Unsupported block types +- Noncanonical text +- Context reference mismatch +- Physical paths +- Credentials +- Accessor-backed blocks +- Forged block or input fingerprints + +--- + +## 9. Implement Provider Capability Descriptors + +Implement a strict, versioned Provider Capability Descriptor. + +It must support: + +- Provider Capability ID +- Provider class +- Accepted Invocation Request versions +- Accepted Delivery Envelope versions +- Accepted input content types +- Maximum input character count +- Maximum output character count +- Supported timeout range +- Supported cancellation modes +- Supported retry modes +- Supported deterministic execution mode +- Supported Usage Evidence +- Supported Cost Evidence +- Supported Failure Evidence +- Supported Result Envelope versions +- Descriptor fingerprint + +Initial provider-neutral classes may include: + +- `deterministic-fake-provider` +- `remote-reasoning-provider` +- `local-reasoning-provider` +- `evaluation-provider` + +Only `deterministic-fake-provider` may be instantiated in Milestone 13. + +Reject: + +- Unknown fields +- Unsupported versions +- Empty capability identity +- Duplicate accepted versions +- Non-positive limits +- Contradictory capabilities +- Provider-specific secret fields +- Vendor or production-model coupling +- Forged Descriptor fingerprints + +--- + +## 10. Implement Capability Matching + +Create a deterministic compatibility result between: + +- Invocation Request +- Provider-neutral input +- Execution Policy +- Provider Capability Descriptor + +Validate at least: + +- Invocation contract version +- Delivery Envelope version +- Input content types +- Input character count +- Output character limit +- Timeout range +- Cancellation mode +- Retry mode +- Deterministic-mode requirement +- Usage Evidence requirement +- Cost Evidence requirement +- Failure Evidence requirement +- Result Envelope version + +Return: + +- Compatible or incompatible status +- Stable ordered reason codes +- Exact mismatched fields +- Invocation Request fingerprint +- Provider Capability fingerprint +- Compatibility-result fingerprint + +Capability mismatch must fail before execution. + +Do not modify or downgrade the Invocation Request to create compatibility. + +--- + +## 11. Implement Execution Policy and Budgets + +Implement a strict, versioned Execution Policy. + +It must support: + +- Maximum input character count +- Maximum output character count +- Timeout duration +- Cancellation policy +- Retry policy +- Maximum attempt count +- Deterministic mode requirement +- Usage Evidence requirement +- Cost Evidence requirement +- Failure Evidence requirement +- Result persistence requirement +- Explicit evaluation timestamp +- Policy fingerprint + +### Authoritative Milestone 13 budgets + +Use: + +- Input characters +- Output characters +- Attempt count +- Timeout duration + +Do not require a provider-specific tokenizer. + +Optional estimated token-like units may exist only as evidence with a documented deterministic method. + +### Retry modes + +Support versioned modes such as: + +- `no-retry` +- `retry-deterministic-transient-failure` +- `retry-until-attempt-limit` +- `evaluation-only-retry` + +### Cancellation modes + +Support versioned modes such as: + +- `not-cancellable` +- `cancel-before-execution` +- `cooperative-cancellation` +- `deadline-cancellation` + +Reject contradictory limits and policies. + +--- + +## 12. Implement Invocation Idempotency + +Invocation idempotency must be explicit and governed. + +### Identical request + +Same Invocation idempotency key plus identical canonical Invocation Request: + +- Return the original finalized Result and Consumption Evidence. +- Do not execute a new fake-provider attempt after finalization. + +### Conflicting request + +Same Invocation idempotency key plus different canonical Invocation Request: + +- Fail closed. + +### In-progress request + +The system must explicitly classify an Invocation that is already in progress. + +Do not create two concurrent finalized owners of the same idempotency key. + +### Durable behavior + +Use a storage-independent execution-evidence port or a compatible versioned extension to the Milestone 12 ledger. + +Do not expose arbitrary record insertion. + +Persist or recover: + +- Invocation ownership +- Attempt history +- Finalized result identity +- Consumption Evidence identity + +The implementation may use the existing local durable pattern, but it must not couple shared contracts to filesystem concepts. + + +--- + +## 13. Implement Execution Attempt Lifecycle + +Every execution attempt must be immutable and independently identifiable. + +An Attempt must bind: + +- Execution Attempt ID +- Invocation Request ID and fingerprint +- Invocation idempotency key +- Provider Capability ID and fingerprint +- Execution Policy fingerprint +- Attempt number +- Previous Attempt ID when applicable +- Explicit started-at evidence +- Explicit deadline evidence when applicable +- Cancellation state +- Attempt fingerprint + +### Attempt ordering + +Attempt numbers must be: + +- Positive +- Sequential +- Unique within the Invocation +- Derived from authoritative attempt history + +Do not use wall-clock time as the ordering authority. + +### Attempt final states + +Each Attempt must terminate as exactly one of: + +- Succeeded +- Failed +- Timed out +- Cancelled + +Reject contradictory states. + +A retry creates a new Attempt. + +A retry must never rewrite or delete a prior Attempt. + +--- + +## 14. Implement the Provider-Neutral Execution Port + +Create a replaceable execution interface. + +The port accepts only: + +- Verified Invocation Request +- Verified Delivery bindings +- Verified Provider Capability Descriptor +- Verified Compatibility Result +- Verified Execution Policy +- Explicit Attempt identity +- Explicit evaluation timestamp +- Explicit cancellation signal abstraction +- Deterministic fixture configuration for the fake provider + +The port returns one provider-neutral outcome: + +- Success +- Failure +- Timeout +- Cancelled + +### Port restrictions + +The port must not: + +- Query KnowledgeOS +- Access the Repository +- Read corpus files +- Read raw Knowledge Objects +- Read full Query Results +- Modify the Context Package +- Add hidden context +- Select a real provider +- Read environment credentials +- Read API keys +- Call the network +- Perform tool calling +- Create Agent actions +- Invoke Hermes +- Invoke MCP + +Do not export infrastructure methods that allow a less-governed execution path. + +--- + +## 15. Implement the Deterministic Fake Provider + +Implement exactly one fake provider adapter. + +For identical: + +- Invocation Request +- Delivery Envelope +- Provider Capability Descriptor +- Execution Policy +- Attempt number +- Explicit evaluation time +- Fixture mode + +the adapter must return byte-identical canonical output. + +### Required deterministic modes + +Implement fixtures for at least: + +- Successful structured response +- Successful empty response +- Output-budget overflow +- Deterministic transient failure +- Deterministic permanent failure +- Timeout +- Cancellation before execution +- Cooperative cancellation +- Malformed success outcome +- Malformed failure outcome +- Contradictory outcome +- Physical-path-bearing outcome +- Credential-bearing outcome + +### Success content + +A success response may be deterministically derived from: + +- Invocation Request fingerprint +- Context Package fingerprint +- Instruction Block fingerprints +- Attempt number +- Fixture mode + +It must not invent or retrieve hidden organizational knowledge. + +### Forbidden fake-provider behavior + +Do not: + +- Access the internet +- Read environment credentials +- Use randomness +- Read implicit wall-clock time +- Read machine-specific paths +- Depend on checkout location +- Depend on map iteration order +- Depend on locale-sensitive sorting + +--- + +## 16. Implement Retry Semantics + +Retries are permitted only when authorized by the verified Execution Policy. + +A retry must: + +- Preserve the original Invocation Request +- Preserve the Delivery transaction binding +- Preserve the Delivery Envelope binding +- Preserve the Delivery Receipt binding +- Preserve the Context Package binding +- Preserve the Consumer binding +- Preserve Provider Capability requirements +- Increment the Attempt number +- Reference the previous Attempt +- Re-evaluate explicit timeout and cancellation state +- Produce new immutable Attempt Evidence + +### Transient failure + +A deterministic transient failure may be retried only when: + +- The Retry Policy permits it. +- The maximum Attempt count has not been reached. +- The Invocation is not cancelled. +- The deadline is not exceeded. + +### Permanent failure + +A permanent failure must not be retried unless an explicit evaluation-only policy permits a test-only Attempt. + +### Attempt exhaustion + +When the Attempt limit is reached: + +- Stop execution. +- Produce stable terminal Failure Evidence. +- Finalize the Invocation according to the approved policy. + +### Retry idempotency + +Retrying the same Attempt ID and same canonical Attempt request must return the original Attempt outcome. + +Conflicting reuse of an Attempt ID must fail. + +--- + +## 17. Implement Timeout Semantics + +All timeout logic must use: + +- Explicit timestamps +- Injected clock abstractions +- Deterministic fake-provider elapsed evidence + +Do not read current time inside pure domain logic. + +Timeout Evidence must bind: + +- Execution Attempt ID +- Configured timeout +- Attempt start evidence +- Deadline evidence +- Deterministic elapsed evidence +- Timeout phase +- Stable reason code +- Timeout Evidence fingerprint + +A timed-out Attempt must not contain contradictory success output. + +If retry is permitted: + +- Create a new Attempt. +- Preserve the timed-out Attempt evidence. +- Re-evaluate current deadline and cancellation state. + +--- + +## 18. Implement Cancellation Semantics + +Cancellation must be explicit and evidence-bearing. + +Support: + +- Cancellation before execution +- Cooperative cancellation during execution +- Deadline cancellation + +Cancellation Evidence must bind: + +- Invocation Request +- Execution Attempt +- Cancellation mode +- Cancellation phase +- Cancellation authority reference +- Requested-at evidence +- Observed-at evidence +- Stable reason codes +- Cancellation Evidence fingerprint + +A cancelled Attempt must: + +- Never be marked as successful +- Never produce contradictory output +- Remain immutable +- Remain in Attempt history + +Do not implement platform-specific process termination or remote-provider cancellation. + +--- + +## 19. Implement the Reasoning Result Envelope + +Implement a strict, versioned, immutable Result Envelope. + +It must include: + +- Result Envelope ID +- Invocation Request ID and fingerprint +- Invocation idempotency key +- Delivery transaction ID +- Delivery Envelope ID and fingerprint +- Delivery Receipt ID and fingerprint +- Context Package ID and fingerprint +- Consumer ID and Descriptor fingerprint +- Provider Capability ID and fingerprint +- Execution Policy fingerprint +- Execution Attempt ID +- Attempt number +- Outcome status +- Canonical output content +- Output content fingerprint +- Execution Receipt +- Usage Evidence +- Cost Evidence +- Failure Evidence when applicable +- Timeout Evidence when applicable +- Cancellation Evidence when applicable +- Completed-at evidence +- Canonical Result Envelope fingerprint + +### Outcome consistency + +#### Succeeded + +Must include: + +- Valid output content +- Output fingerprint +- Execution Receipt +- Usage Evidence +- Cost Evidence + +Must not include terminal Failure, Timeout, or Cancellation Evidence. + +#### Failed + +Must include Failure Evidence. + +Must not include contradictory successful output. + +#### Timed out + +Must include Timeout Evidence. + +Must not include contradictory successful output. + +#### Cancelled + +Must include Cancellation Evidence. + +Must not include contradictory successful output. + +### Output budget + +Enforce the maximum canonical output character count. + +Do not silently truncate provider output unless an approved versioned policy explicitly permits it. + +The default Milestone 13 behavior should be: + +```text +Output over budget -> fail closed with explicit evidence. +``` + +--- + +## 20. Implement Execution Receipt and Operational Evidence + +### Execution Receipt + +The Receipt must bind: + +- Execution Attempt ID +- Invocation Request ID and fingerprint +- Provider Capability ID and fingerprint +- Attempt number +- Started-at evidence +- Completed-at evidence +- Outcome +- Canonical Receipt fingerprint + +### Usage Evidence + +Include provider-neutral measures: + +- Input character count +- Output character count +- Instruction Block count +- Context Package object count +- Attempt number +- Duration evidence +- Optional deterministic estimated input units +- Optional deterministic estimated output units +- Usage Evidence fingerprint + +Do not claim real provider token counts. + +### Cost Evidence + +Support statuses such as: + +- Actual +- Estimated +- Unavailable +- Not applicable + +When amount is present, bind: + +- Currency code +- Amount in minor units +- Estimation method +- Pricing reference version +- Cost Evidence fingerprint + +The deterministic fake provider should use: + +- `not-applicable`, or +- Deterministic zero-cost evidence + +Do not introduce real provider pricing tables in Milestone 13. + +### Failure Evidence + +Bind: + +- Failure category +- Stable reason codes +- Retryable classification +- Sanitized failure detail +- Attempt number +- Failure Evidence fingerprint + +Do not expose: + +- Stack traces in public canonical evidence +- Physical paths +- Environment values +- Credentials +- Provider secrets + +--- + +## 21. Implement Independent Result Verification + +Implement pure verification for: + +- Invocation Request +- Provider-neutral input +- Provider Capability Descriptor +- Compatibility Result +- Execution Policy +- Execution Attempt +- Execution Receipt +- Usage Evidence +- Cost Evidence +- Failure Evidence +- Timeout Evidence +- Cancellation Evidence +- Result Envelope +- Final Consumption Evidence + +Verification must recompute: + +- Canonical fingerprints +- Character budgets +- Attempt ordering +- Outcome consistency +- Cross-artifact bindings +- Delivery transaction binding +- Context Package binding +- Provider Capability binding +- Execution Policy binding +- Finalization binding + +Detect and reject: + +- Delivery substitution +- Receipt substitution +- Context Package substitution +- Consumer substitution +- Provider Capability substitution +- Execution Policy substitution +- Attempt-number substitution +- Output mutation +- Usage mutation +- Cost mutation +- Failure mutation +- Timeout mutation +- Cancellation mutation +- Outcome contradiction +- Reordering +- Missing evidence +- Physical-path leakage +- Credential leakage +- Re-signed semantic substitutions + +Fail closed. + +Do not silently repair authoritative evidence. + +--- + +## 22. Finalize Consumption Evidence + +Extend the Milestone 11 Consumption Evidence placeholder into a finalized, strict, versioned record. + +It must bind: + +- Consumption ID +- Delivery Receipt ID and fingerprint +- Delivery transaction ID +- Invocation Request ID and fingerprint +- Invocation idempotency key +- Provider Capability ID and fingerprint +- Final Result Envelope ID and fingerprint +- Final outcome +- Attempt history summary +- Started-at evidence +- Completed-at evidence +- Usage Evidence fingerprint +- Cost Evidence fingerprint +- Failure, Timeout, or Cancellation Evidence fingerprint when applicable +- Durable execution-evidence transaction reference +- Canonical Consumption Evidence fingerprint + +### Finalization rules + +- Consumption cannot finalize before a terminal Result Envelope exists. +- Exactly one final Consumption Evidence record may own one finalized Invocation. +- Identical finalization retry returns the original finalized record. +- Conflicting finalization fails. +- Finalization never modifies Delivery artifacts. +- Finalization never rewrites Attempt history. +- Finalized evidence is append-only when persisted. + +--- + +## 23. Implement the Durable Execution-Evidence Boundary + +Implement a storage-independent port or compatible versioned extension to the Milestone 12 durable ledger. + +The governed persistence boundary must support: + +- Register Invocation ownership +- Append Execution Attempt +- Finalize Invocation Result +- Store Result Envelope +- Store finalized Consumption Evidence +- Resolve Invocation idempotency +- Read Attempt history +- Read finalized result +- Recover finalized state +- Verify execution-evidence integrity + +### Required durability behavior + +If persistence is implemented through a local adapter: + +- Use append-only authoritative records. +- Use explicit single-writer behavior. +- Use expected-head compare-and-swap. +- Use atomic committed transaction envelopes. +- Ignore staging and partial files during recovery. +- Keep derived indexes non-authoritative. +- Preserve physical-path and credential privacy. +- Reuse Milestone 09 and 12 safety patterns where appropriate. + +### Public API restriction + +Do not export low-level methods that allow: + +- Arbitrary Result insertion +- Arbitrary Consumption Evidence insertion +- Attempt history rewriting +- Invocation ownership reassignment +- Finalization without verification +- Deletion of authoritative evidence + +--- + +## 24. Preserve the No-Provider-Bypass Rule + +The public governed Invocation API must reject: + +- Raw Knowledge Objects +- Full Query Results +- Direct Repository access +- Direct corpus access +- Unverified Context Packages +- Unverified Delivery Envelopes +- Unverified Delivery Receipts +- Hidden context +- Provider-specific prompt injection +- Production model selection +- Credential-bearing input +- Physical paths +- Accessor-backed input +- Provider Capability substitution +- Execution Policy substitution +- Fake Result Envelope injection +- Result construction without an Attempt +- Evidence stripping +- Result mutation after finalization + +Every successful Result must have a complete chain: + +```text +Active Snapshot + -> +Context Package + -> +Delivery Envelope + -> +Delivery Receipt + -> +Invocation Request + -> +Provider Capability + -> +Execution Attempt + -> +Result Envelope + -> +Consumption Evidence +``` + +--- + +## 25. Add Deterministic Evaluation Fixtures + +Add executable evaluation scenarios covering at least: + +### Successful execution + +- Successful structured fake-provider response +- Successful empty response when policy permits +- Deterministic repeated execution +- Restart and finalized-result lookup when persistence is present + +### Delivery binding + +- Missing Delivery transaction +- Envelope substitution +- Receipt substitution +- Context Package substitution +- Consumer substitution +- Registry-binding substitution + +### Capability matching + +- Invocation version mismatch +- Delivery version mismatch +- Unsupported input content type +- Input budget mismatch +- Output budget mismatch +- Unsupported timeout +- Unsupported cancellation mode +- Unsupported retry mode +- Missing Usage Evidence capability +- Missing Cost Evidence capability +- Missing Failure Evidence capability + +### Idempotency + +- First Invocation ownership +- Identical finalized retry +- Conflicting key reuse +- In-progress duplicate request +- Conflicting finalization + +### Retry + +- Transient failure followed by success +- Permanent failure with no retry +- Attempt-limit exhaustion +- Identical Attempt retry +- Conflicting Attempt ID reuse + +### Timeout + +- Timeout without retry +- Timeout followed by permitted retry +- Contradictory success plus Timeout Evidence +- Deadline already expired + +### Cancellation + +- Cancel before execution +- Cooperative cancellation +- Deadline cancellation +- Contradictory success plus Cancellation Evidence + +### Evidence integrity + +- Output mutation +- Usage Evidence mutation +- Cost Evidence mutation +- Failure Evidence mutation +- Timeout Evidence mutation +- Cancellation Evidence mutation +- Execution Receipt mutation +- Result Envelope mutation +- Consumption Evidence mutation +- Re-signed semantic substitution + +### Fake-provider safety + +- Network access attempt +- Environment credential access attempt +- Randomness attempt +- Implicit wall-clock dependence +- Physical-path-bearing output +- Credential-bearing output +- Malformed outcome +- Contradictory outcome + +### No-provider-bypass + +- Raw Knowledge Object attempt +- Full Query Result attempt +- Hidden context injection +- Provider-specific payload injection +- Fake preconstructed Result attempt +- Low-level finalization bypass attempt + +Define expected: + +- Outcome status +- Stable reason codes +- Attempt count +- Attempt identities +- Result identity +- Usage and Cost Evidence +- Final Consumption Evidence +- Idempotency behavior +- Durability behavior +- Fingerprints + +--- + +## 26. Add Comprehensive Tests + +Add focused tests in these categories. + +### Contract tests + +- Strict validation +- Unknown-field rejection +- Unsupported versions +- Invalid identifiers +- Duplicate Instruction Block IDs +- Explicit-undefined rejection where required +- Accessor-safe validation +- Noncanonical text rejection +- Canonical normalization +- Fingerprint round trips +- Forged fingerprint rejection + +### Delivery-resolution tests + +- Exact durable Delivery lookup +- Ledger-integrity verification +- Envelope verification +- Receipt verification +- Context Package verification +- Consumer binding +- Policy binding +- Historical Delivery support where allowed +- Substitution rejection + +### Capability tests + +- Every supported compatibility field +- Exact boundary values +- Stable reason ordering +- No silent downgrade +- No silent input mutation +- No execution after incompatibility + +### Execution Policy tests + +- Input budget +- Output budget +- Timeout +- Attempt limits +- Retry modes +- Cancellation modes +- Evidence requirements +- Contradictory policy rejection + +### Fake-provider tests + +- Deterministic success +- Deterministic empty success +- Transient failure +- Permanent failure +- Timeout +- Cancellation +- Output overflow +- Malformed outcome +- Contradictory outcome +- No network +- No credentials +- No randomness +- No implicit time + +### Invocation idempotency tests + +- First ownership +- Identical finalized retry +- Conflicting request +- In-progress duplicate +- Restart recovery if persisted +- Conflicting finalization + +### Attempt and retry tests + +- Attempt creation +- Attempt ordering +- Prior-attempt binding +- Transient retry +- Attempt exhaustion +- Identical Attempt retry +- Conflicting Attempt reuse +- Prior Attempt immutability + +### Result and evidence tests + +- Success Result +- Failure Result +- Timeout Result +- Cancellation Result +- Outcome consistency +- Execution Receipt +- Usage Evidence +- Cost Evidence +- Failure Evidence +- Timeout Evidence +- Cancellation Evidence +- Output-budget enforcement +- Independent verification +- Tamper rejection + +### Consumption finalization tests + +- Valid finalization +- Finalization before terminal Result rejection +- Identical finalization replay +- Conflicting finalization +- Durable lookup +- Attempt-history summary +- Delivery-to-Result chain verification + +### No-provider-bypass tests + +- Raw Knowledge Object rejection +- Full Query Result rejection +- Direct Repository bypass rejection +- Unverified Delivery rejection +- Hidden context rejection +- Provider-specific payload rejection +- Result injection rejection +- Evidence stripping rejection +- Credential rejection +- Physical-path rejection + +### Regression tests + +- Keep all Milestone 04–12 tests green. +- Preserve Milestone 10 Context Package governance. +- Preserve Milestone 11 Delivery governance. +- Preserve Milestone 12 durable idempotency, replay, recovery, and audit-chain guarantees. + + +--- + +## 27. Architectural Constraints + +Do not implement: + +- OpenAI adapter +- Anthropic adapter +- Google adapter +- Local production-model adapter +- Any real provider adapter +- Provider credentials +- Secret management +- Provider API clients +- Network execution +- Streaming output +- Tool calling +- Function calling +- Agent runtime +- Hermes runtime +- MCP gateway +- Autonomous planning +- Authentication +- Authorization engine +- Semantic search +- Embeddings +- Vector databases +- Ranking +- Knowledge graphs +- UI +- Distributed execution coordination +- Distributed idempotency +- Multi-provider routing +- Provider failover +- Real provider pricing catalogs + +Do not add a framework or dependency unless the current Node.js and TypeScript platform cannot satisfy the approved deterministic contracts. + +If a dependency is unavoidable, first document: + +- Requirement +- Alternatives +- Security impact +- Determinism impact +- Durability impact +- Provider-neutrality impact +- Architecture decision + +in `ARCHITECTURE_DECISIONS.md`. + +--- + +## 28. Engineering Rules + +Follow: + +- Documentation first +- Architecture before code +- Strict TypeScript +- Existing naming conventions +- Existing package boundaries +- No reverse dependencies +- No unrelated refactoring +- No unsupported completion claims +- Defensive copying +- Immutable authoritative artifacts +- Accessor-safe raw validation +- Explicit time injection +- No implicit randomness +- Stable public errors +- No physical-path leakage +- No credential leakage +- Pure canonicalization, compatibility, budget, idempotency, attempt, and verification functions +- Tests for every behavior change + +Use: + +- OS temporary directories, or +- Explicit isolated test roots + +Do not write tests into the developer's real runtime ledger. + +Never modify canonical `docs/` or `knowledge/` sources. + +If the checkout is under an iCloud-managed directory: + +- Keep runtime and test fixtures outside file-provider-managed paths when possible. +- Do not rely on hydration timing for correctness. +- Do not commit hydrated duplicates or conflict files. + +--- + +## 29. Documentation Updates + +Update only documentation that reflects implemented behavior: + +- Root `README.md` +- `DOCUMENTATION_INDEX.md` +- `CHANGELOG.md` +- Relevant package READMEs +- Public exports +- `ARCHITECTURE_DECISIONS.md` + +Add an ADR documenting: + +- Provider-Neutral Reasoning Invocation boundary +- Exact durable Delivery binding +- Provider Capability Descriptor +- Provider-neutral input representation +- Execution Policy and authoritative budgets +- Deterministic fake provider +- Invocation idempotency +- Attempt lifecycle +- Retry, timeout, and cancellation semantics +- Result Envelope identity +- Usage and Cost Evidence +- Failure, Timeout, and Cancellation Evidence +- Consumption Evidence finalization +- Durable execution-evidence boundary +- No-provider-bypass rule +- Deferred real provider adapters +- Deferred streaming +- Deferred tool calling +- Deferred Agent, Hermes, and MCP +- Deferred authorization + +Do not document speculative production-provider behavior as implemented. + +--- + +## 30. Verification Gates + +Before completion, run: + +```bash +pnpm format:check +pnpm lint +pnpm build +pnpm typecheck +pnpm test +git diff --check +``` + +Run additional repository-defined checks if present. + +All Milestone 04–12 regressions and all new Milestone 13 tests must pass. + +Inspect: + +```bash +git status +``` + +Confirm: + +- Only intended Milestone 13 changes exist. +- No real provider credentials exist. +- No provider API configuration is staged. +- No generated Invocation Requests are staged. +- No generated Result Envelopes are staged. +- No generated Consumption Evidence is staged. +- No execution-ledger runtime records are staged. +- No fake-provider output is staged. +- No lock, staging, or temporary files are staged. +- `.DS_Store` is excluded. +- iCloud conflicts are excluded. +- Generated `dist/` directories are excluded. +- Physical-path-bearing debug files are excluded. +- Credential-bearing files are excluded. + +--- + +## 31. Independent Whole-Branch Review + +After all verification passes, perform an independent whole-branch review focused on: + +- Milestone 12 Delivery verification bypass +- Raw Knowledge Object bypass +- Full Query Result bypass +- Unverified Delivery Envelope acceptance +- Unverified Delivery Receipt acceptance +- Context Package substitution +- Consumer substitution +- Policy Evidence substitution +- Provider Capability substitution +- Execution Policy substitution +- Hidden context injection +- Provider-specific payload leakage +- Accidental real provider call +- Accidental network call +- Environment credential access +- Randomness +- Implicit wall-clock use +- Invocation idempotency conflict +- Duplicate finalized owner +- Attempt-number race +- Prior Attempt mutation +- Retry-policy bypass +- Attempt-limit bypass +- Timeout represented as success +- Cancellation represented as success +- Output-budget bypass +- Malformed fake-provider outcome acceptance +- Result Envelope forgery +- Usage Evidence forgery +- Cost Evidence forgery +- Failure Evidence forgery +- Consumption Evidence forgery +- Finalization before terminal Result +- Conflicting finalization +- Derived index treated as authoritative +- Authoritative corruption silently repaired +- Mutable aliasing across asynchronous boundaries +- Accessor execution +- Physical-path leakage +- Credential leakage +- Provider or model coupling +- Accidental Agent, Hermes, or MCP invocation + +Fix every Critical, Important, or Minor finding before declaring `GO`. + +Otherwise return `NOT READY` with exact unresolved findings. + +--- + +## 32. Commit and Pull Request Rules + +Prepare the result as commit-ready. + +Do not merge into `main`. + +If the user has not explicitly authorized commit and push: + +- Leave the changes uncommitted. +- Report that state. + +If explicitly authorized: + +1. Create one clean conventional milestone commit. +2. Push `codex/milestone-13`. +3. Prepare a Pull Request into `main`. +4. Do not merge locally. +5. Do not merge remotely. + +Never discard completed work. + +--- + +## 33. Completion Report + +Return a report titled: + +# FounderOS Milestone 13 Completion Report + +Include: + +1. Status: `GO` or `NOT READY` +2. Branch +3. Base branch +4. Worktree state +5. Commit state +6. Push state +7. Implementation summary +8. Exact Reasoning Invocation workflow +9. Exact Attempt and Retry workflow +10. Exact Consumption Evidence finalization workflow +11. All added files +12. All modified files +13. Tests added by category +14. Final total test count +15. Exact verification results +16. Durable Delivery-binding evidence +17. Provider Capability matching evidence +18. Provider-neutral input evidence +19. Execution Policy and budget evidence +20. Fake-provider determinism evidence +21. Invocation idempotency evidence +22. Attempt ordering and retry evidence +23. Timeout evidence +24. Cancellation evidence +25. Result Envelope evidence +26. Usage and Cost Evidence +27. Failure Evidence +28. Consumption Evidence finalization evidence +29. Durable execution-evidence and recovery evidence +30. Tamper and substitution rejection evidence +31. No-provider-bypass evidence +32. Architecture impact +33. Dependency direction +34. Known limitations +35. Deliberately deferred capabilities +36. Independent review findings +37. Recommended next milestone +38. Pull Request readiness + +--- + +## 34. GO Standard + +Milestone 13 may be reported as `GO` only when FounderOS can: + +- Resolve and verify one exact durable Milestone 12 Delivery transaction +- Verify its Envelope, Receipt, Context Package, Consumer, Policy, Active Snapshot, and Registry bindings +- Create a strict provider-neutral Reasoning Invocation Request +- Match it deterministically to a Provider Capability Descriptor +- Enforce provider-neutral input, output, timeout, retry, cancellation, and Attempt budgets +- Execute only through a deterministic fake provider +- Produce immutable Success, Failure, Timeout, or Cancellation Attempt evidence +- Enforce Invocation idempotency +- Preserve immutable ordered Attempt history +- Produce and independently verify a Reasoning Result Envelope +- Produce and independently verify Execution Receipt, Usage, Cost, Failure, Timeout, and Cancellation Evidence +- Finalize one exact Consumption Evidence record +- Persist or durably bind append-only execution evidence through a governed storage-independent boundary +- Reject partial, corrupt, substituted, contradictory, hidden, credential-bearing, physical-path-bearing, or forged artifacts +- Preserve all Milestone 10–12 no-bypass, durability, replay, and audit guarantees +- Complete the full workflow without invoking a real provider, network service, Agent, Hermes runtime, or MCP integration + +Prioritize traceability, deterministic execution evidence, provider neutrality, idempotency, attempt integrity, and result verification over production intelligence or provider integration. diff --git a/docs/milestones/milestone-13/FounderOS_Milestone_13_Package_README_v1.0.md b/docs/milestones/milestone-13/FounderOS_Milestone_13_Package_README_v1.0.md new file mode 100644 index 0000000..517ed41 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Milestone_13_Package_README_v1.0.md @@ -0,0 +1,73 @@ +# FounderOS Milestone 13 Package README v1.0 + +## Milestone + +**Milestone 13 — Provider-Neutral Reasoning Invocation and Result Evidence Foundation** + +## Purpose + +This package defines the first governed reasoning-execution boundary for FounderOS. + +Milestone 12 durably preserves governed Context Delivery, idempotency, replay, and receipt evidence. Milestone 13 introduces a provider-neutral Reasoning Invocation contract, Provider Capability matching, deterministic execution through a fake provider, immutable result evidence, usage and cost evidence, timeout and failure evidence, durable execution-evidence binding, and finalized Consumption Evidence. + +## Architectural Boundary + +```text +Durably Governed Delivery Envelope + | + v +Reasoning Invocation Request + | + v +Provider Capability Matching + | + v +Provider-Neutral Execution Port + | + v +Deterministic Fake Provider + | + v +Reasoning Result Envelope + | + v +Execution / Usage / Failure Evidence + | + v +Finalized Consumption Evidence +``` + +## Package Contents + +1. Milestone foundation specification +2. Reasoning Invocation Request contract +3. Provider Capability Descriptor contract +4. Provider-neutral Reasoning Input contract +5. Execution Policy and Budget contract +6. Provider-neutral Execution Port +7. Deterministic Fake Provider specification +8. Reasoning Result Envelope contract +9. Execution Receipt, Usage, Cost, Failure, Timeout, and Cancellation Evidence contract +10. Invocation Idempotency, Retry, Timeout, and Cancellation specification +11. Consumption Evidence Finalization specification +12. Durable Reasoning Execution Evidence Ledger contract +13. No-Provider-Bypass and Result Integrity policy +14. Provider-Neutral Reasoning Evaluation framework +15. Acceptance criteria +16. Verification checklist +17. Complete Codex execution prompt + +Including this README, the package contains 18 Markdown files. + +## Non-Goals + +This milestone does not: + +- Integrate OpenAI, Anthropic, Google, or any real provider +- Add provider credentials or secret management +- Add streaming or tool calling +- Run Agents or Hermes +- Add MCP integrations +- Implement authentication or authorization +- Add semantic retrieval, embeddings, vector databases, ranking, or knowledge graphs +- Add UI applications diff --git a/docs/milestones/milestone-13/FounderOS_Milestone_13_Provider_Neutral_Reasoning_Invocation_and_Result_Evidence_Foundation_Specification_v1.0.md b/docs/milestones/milestone-13/FounderOS_Milestone_13_Provider_Neutral_Reasoning_Invocation_and_Result_Evidence_Foundation_Specification_v1.0.md new file mode 100644 index 0000000..f6f3c0e --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Milestone_13_Provider_Neutral_Reasoning_Invocation_and_Result_Evidence_Foundation_Specification_v1.0.md @@ -0,0 +1,81 @@ +# FounderOS Milestone 13 Provider-Neutral Reasoning Invocation and Result Evidence Foundation Specification v1.0 + +## Purpose + +Define a governed, provider-neutral reasoning execution boundary that consumes a verified Milestone 11 Delivery Envelope and produces independently verifiable result evidence without integrating a real model provider. + +## Objective + +Create stable contracts and execution semantics for Reasoning Invocation Requests, Provider Capability matching, provider-neutral input representation, execution policy and limits, a deterministic fake provider, Result Envelopes, usage and cost evidence, failure and cancellation evidence, invocation idempotency, and finalized Consumption Evidence. + +## Architecture + +```text +Durable Delivery Receipt + | + v +Reasoning Invocation Request + | + v +Provider Capability Validation + | + v +Provider-Neutral Execution Port + | + v +Deterministic Fake Provider + | + v +Reasoning Result Envelope + | + v +Final Consumption Evidence +``` + +## In Scope + +- Strict versioned Reasoning Invocation Request +- Provider Capability Descriptor +- Provider-neutral message and content representation +- Execution policy, budget, timeout, and cancellation contracts +- Provider-neutral execution port +- Deterministic fake provider adapter +- Result Envelope +- Execution Receipt +- Usage, latency, and cost evidence +- Failure, timeout, cancellation, and retry evidence +- Invocation idempotency +- Exact Delivery Envelope and Receipt binding +- Finalized Consumption Evidence +- Durable append-only execution evidence through a compatible ledger boundary +- Independent verification +- Deterministic evaluation fixtures + +## Out of Scope + +- Real provider adapters +- API credentials or secret management +- Tool calling +- Streaming transport +- Agent or Hermes runtime +- MCP gateway +- Autonomous planning +- Authentication or authorization +- Semantic retrieval, embeddings, vector databases, ranking, knowledge graphs, or UI + +## Core Design Rules + +1. Every invocation binds to one exact verified Delivery Envelope and Receipt. +2. The execution port cannot access KnowledgeOS, the Repository, or raw Knowledge Objects. +3. Provider capability matching happens before execution. +4. Inputs are provider neutral and model neutral. +5. Invocation idempotency is explicit. +6. Fake-provider behavior is deterministic. +7. Result, Usage, Failure, Timeout, and Cancellation evidence is immutable and fingerprinted. +8. Consumption Evidence finalizes the exact invocation and result relationship. +9. No public API may bypass governed Delivery artifacts. +10. No real provider call occurs in Milestone 13. + +## Definition of Success + +FounderOS can deterministically execute a governed Reasoning Invocation through a fake provider, produce and independently verify a Result Envelope and final Consumption Evidence, and preserve all Delivery, Context, Policy, Freshness, Replay, and Idempotency bindings without integrating a real provider. diff --git a/docs/milestones/milestone-13/FounderOS_Milestone_13_Verification_Checklist_v1.0.md b/docs/milestones/milestone-13/FounderOS_Milestone_13_Verification_Checklist_v1.0.md new file mode 100644 index 0000000..ecdfae8 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Milestone_13_Verification_Checklist_v1.0.md @@ -0,0 +1,91 @@ +# FounderOS Milestone 13 Verification Checklist v1.0 + +## Repository Preconditions + +- [ ] Milestone 12 is merged into `main`. +- [ ] `codex/milestone-13` is based on current `origin/main`. +- [ ] The worktree contains no unrelated changes. + +## Contract Verification + +- [ ] Invocation, Capability, Input, Policy, Result, Evidence, and Consumption schemas validate strictly. +- [ ] Unknown fields and unsupported versions are rejected. +- [ ] Accessor-backed and noncanonical inputs are rejected. +- [ ] Canonical fingerprints independently recompute. +- [ ] Provider-specific fields are absent from shared contracts. + +## Delivery Binding Verification + +- [ ] Durable Delivery transaction verifies. +- [ ] Delivery Envelope and Receipt verify. +- [ ] Context Package and Consumer bindings are preserved. +- [ ] Invocation cannot use raw knowledge, Query Results, or hidden context. +- [ ] Substitution and re-signed semantic changes fail. + +## Capability and Policy Verification + +- [ ] Contract versions match. +- [ ] Content types match. +- [ ] Input and output limits match. +- [ ] Timeout, retry, cancellation, and evidence support match. +- [ ] Stable mismatch reasons are deterministic. +- [ ] Execution does not begin after capability failure. + +## Execution Verification + +- [ ] Fake-provider success is deterministic. +- [ ] Fake-provider failure is deterministic. +- [ ] Timeout and cancellation are deterministic. +- [ ] No network, environment credential, random, or implicit wall-clock dependency exists. +- [ ] Output budgets are enforced. +- [ ] Malformed outcomes fail closed. + +## Idempotency, Retry, and Attempt Verification + +- [ ] Identical invocation returns the original finalized result. +- [ ] Conflicting key reuse fails. +- [ ] Retries create distinct ordered attempts. +- [ ] Attempt limits are enforced. +- [ ] Previous attempts remain immutable. +- [ ] Finalization is idempotent. + +## Evidence Verification + +- [ ] Execution Receipt verifies. +- [ ] Usage Evidence verifies. +- [ ] Cost Evidence verifies. +- [ ] Failure Evidence verifies. +- [ ] Timeout Evidence verifies. +- [ ] Cancellation Evidence verifies. +- [ ] Result Envelope verifies. +- [ ] Consumption Evidence verifies. +- [ ] Tampering and reordering are detected. +- [ ] Physical paths, credentials, and provider secrets are absent. + +## Durability Verification + +- [ ] Execution Evidence uses a governed storage-independent port. +- [ ] Append-only finalization records survive restart where implemented. +- [ ] Derived state is non-authoritative. +- [ ] Authoritative corruption fails closed. +- [ ] No arbitrary record-insertion API is exported. + +## Regression Verification + +- [ ] All Milestone 04–12 tests remain green. +- [ ] New Milestone 13 tests pass. + +## Required Commands + +```bash +pnpm format:check +pnpm lint +pnpm build +pnpm typecheck +pnpm test +git diff --check +``` + +## Approval Rule + +Milestone 13 is `GO` only when Reasoning Invocation, provider capability matching, fake-provider execution, attempt lifecycle, result evidence, durable Consumption Evidence finalization, and no-provider-bypass guarantees are deterministic, independently verifiable, and fully compatible with prior milestones. diff --git a/docs/milestones/milestone-13/FounderOS_No_Provider_Bypass_and_Reasoning_Result_Integrity_Enforcement_Policy_v1.0.md b/docs/milestones/milestone-13/FounderOS_No_Provider_Bypass_and_Reasoning_Result_Integrity_Enforcement_Policy_v1.0.md new file mode 100644 index 0000000..6039583 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_No_Provider_Bypass_and_Reasoning_Result_Integrity_Enforcement_Policy_v1.0.md @@ -0,0 +1,51 @@ +# FounderOS No-Provider-Bypass and Reasoning Result Integrity Enforcement Policy v1.0 + +## Purpose + +Prevent reasoning execution from bypassing governed Delivery and Invocation boundaries. + +## Prohibited Public Paths + +Public APIs must not allow: + +- Invocation from raw Knowledge Objects +- Invocation from full Query Results +- Invocation from an unverified Context Package +- Invocation without a verified Delivery Envelope and Receipt +- Direct Repository or corpus access +- Hidden context injection +- Provider-specific prompt injection +- Provider capability substitution +- Execution Policy substitution +- Result Envelope construction without an execution attempt +- Usage or Cost Evidence forgery +- Result mutation after finalization +- Credential-bearing input +- Physical-path-bearing input + +## Required Verification + +Before execution: + +1. Verify durable Delivery and Receipt. +2. Verify Reasoning Invocation Request. +3. Verify provider-neutral input. +4. Verify Provider Capability Descriptor. +5. Verify capability compatibility. +6. Verify Execution Policy. +7. Verify Invocation idempotency state. +8. Create a governed execution attempt. + +After execution: + +1. Verify provider outcome. +2. Enforce output budget. +3. Generate Execution Receipt and evidence. +4. Generate Result Envelope. +5. Independently verify the Result Envelope. +6. Finalize Consumption Evidence. +7. Persist append-only execution evidence through the governed ledger boundary. + +## Principle + +No reasoning result may exist without a complete chain back to a verified governed Context Delivery. diff --git a/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Evaluation_Framework_v1.0.md b/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Evaluation_Framework_v1.0.md new file mode 100644 index 0000000..c553e97 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Evaluation_Framework_v1.0.md @@ -0,0 +1,78 @@ +# FounderOS Provider-Neutral Reasoning Evaluation Framework v1.0 + +## Purpose + +Define deterministic evaluation scenarios for provider-neutral Reasoning Invocation and Result Evidence. + +## Evaluation Dimensions + +### Binding Integrity + +- Invocation binds to exact Delivery Envelope and Receipt. +- Provider Capability and Execution Policy bind correctly. +- Result binds to exact Invocation and attempt. + +### Capability Compatibility + +- Supported input, output, timeout, cancellation, evidence, and version requirements pass. +- Incompatible requirements fail before execution. + +### Execution Outcomes + +- Success, failure, timeout, and cancellation are distinct. +- Contradictory evidence fails closed. +- Output budget is enforced. + +### Idempotency and Retry + +- Identical invocation returns the original finalized result. +- Conflicting idempotency reuse fails. +- Retry creates a new attempt and preserves prior evidence. +- Attempt limits are enforced. + +### Evidence + +- Usage and Cost Evidence verify. +- Failure, Timeout, and Cancellation Evidence verify. +- Final Consumption Evidence closes the chain. + +### Bypass Resistance + +- Raw knowledge, Query Results, hidden context, unverified Delivery artifacts, credentials, and physical paths are rejected. + +## Required Scenarios + +- Successful deterministic execution +- Identical repeat execution +- Conflicting invocation key +- Capability version mismatch +- Input budget mismatch +- Output budget mismatch +- Unsupported cancellation policy +- Unsupported retry policy +- Deterministic transient failure followed by retry success +- Permanent failure +- Timeout without retry +- Timeout followed by permitted retry +- Cancellation before execution +- Cooperative cancellation +- Attempt-limit exhaustion +- Malformed provider outcome +- Result output tampering +- Usage Evidence tampering +- Cost Evidence tampering +- Failure Evidence tampering +- Delivery Envelope substitution +- Receipt substitution +- Provider Capability substitution +- Execution Policy substitution +- Hidden context injection +- Credential leakage attempt +- Physical-path leakage attempt +- Final Consumption Evidence tampering +- Durable finalization replay +- Conflicting finalization + +## Principle + +Provider execution governance must be measurable before any production provider is connected. diff --git a/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Execution_Port_v1.0.md b/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Execution_Port_v1.0.md new file mode 100644 index 0000000..bac4dc5 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Execution_Port_v1.0.md @@ -0,0 +1,49 @@ +# FounderOS Provider-Neutral Reasoning Execution Port v1.0 + +## Purpose + +Define the replaceable boundary through which a governed Reasoning Invocation is executed. + +## Port Input + +The execution port accepts only: + +- Verified Reasoning Invocation Request +- Verified Delivery Envelope binding +- Verified Provider Capability Descriptor +- Verified compatibility result +- Explicit execution timestamp +- Explicit cancellation signal abstraction +- Explicit attempt number + +## Port Output + +The execution port returns one provider-neutral outcome: + +- Success +- Failure +- Timeout +- Cancelled + +Each outcome must include sufficient evidence for independent verification. + +## Port Must Not + +- Query KnowledgeOS +- Access the Repository +- Read raw Knowledge Objects +- Read full Query Results +- Change the Context Package +- Add hidden context +- Select a real provider +- Read credentials +- Perform tool calling +- Create Agent actions + +## Adapter Neutrality + +Milestone 13 implements only a deterministic fake provider behind this port. + +## Principle + +The execution port is a controlled reasoning boundary, not a gateway to organizational knowledge. diff --git a/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Input_Contract_v1.0.md b/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Input_Contract_v1.0.md new file mode 100644 index 0000000..7a66a33 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Provider_Neutral_Reasoning_Input_Contract_v1.0.md @@ -0,0 +1,52 @@ +# FounderOS Provider-Neutral Reasoning Input Contract v1.0 + +## Purpose + +Define a model-independent input representation for governed reasoning invocation. + +## Input Structure + +The initial input may contain: + +- Contract version +- Instruction blocks +- Context reference +- Output requirements +- Constraint blocks +- Evaluation metadata +- Canonical input fingerprint + +## Instruction Block + +An Instruction Block should include: + +- Stable block ID +- Block type +- Canonical text content +- Priority +- Source classification +- Fingerprint + +## Block Types + +Provider-neutral block types may include: + +- System constraint +- Task instruction +- Context reference +- Output requirement +- Evaluation directive + +Do not use provider-specific chat roles or message schemas. + +## Context Rule + +The input must reference the exact verified Context Package already embedded in the Delivery Envelope. It must not embed raw Knowledge Objects, full Query Results, or additional hidden context. + +## Validation Rules + +Reject unknown blocks, duplicate block IDs, physical paths, credentials, unsupported content types, noncanonical text, forged fingerprints, and any context not bound to the Delivery Envelope. + +## Principle + +The input contract expresses reasoning intent without becoming a vendor-specific prompt payload. diff --git a/docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Policy_and_Budget_Contract_v1.0.md b/docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Policy_and_Budget_Contract_v1.0.md new file mode 100644 index 0000000..b0dc6cb --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Policy_and_Budget_Contract_v1.0.md @@ -0,0 +1,59 @@ +# FounderOS Reasoning Execution Policy and Budget Contract v1.0 + +## Purpose + +Define provider-neutral execution limits and governance rules for a Reasoning Invocation. + +## Policy Fields + +- Contract version +- Maximum input character count +- Maximum output character count +- Timeout duration +- Cancellation policy +- Retry policy +- Maximum attempt count +- Deterministic mode requirement +- Usage Evidence requirement +- Cost Evidence requirement +- Failure Evidence requirement +- Result persistence requirement +- Explicit evaluation timestamp +- Canonical policy fingerprint + +## Budget Dimensions + +Milestone 13 authoritative budgets should use provider-neutral dimensions: + +- Input character count +- Output character count +- Attempt count +- Timeout duration + +Optional token or monetary estimates may be evidence only and must not become provider-specific enforcement authority. + +## Retry Policy + +Initial modes may include: + +- No retry +- Retry deterministic transient failure +- Retry until attempt limit +- Evaluation-only retry + +## Cancellation Policy + +Initial modes may include: + +- Not cancellable +- Cancel before execution +- Cooperative cancellation +- Deadline cancellation + +## Validation Rules + +Reject unknown fields, unsupported modes, non-positive limits, contradictory retry and cancellation rules, unsupported deterministic requirements, and forged policy fingerprints. + +## Principle + +Execution policy constrains the provider boundary without depending on vendor-specific controls. diff --git a/docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Receipt_Usage_Cost_Failure_and_Cancellation_Evidence_Contract_v1.0.md b/docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Receipt_Usage_Cost_Failure_and_Cancellation_Evidence_Contract_v1.0.md new file mode 100644 index 0000000..a4365fb --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Reasoning_Execution_Receipt_Usage_Cost_Failure_and_Cancellation_Evidence_Contract_v1.0.md @@ -0,0 +1,86 @@ +# FounderOS Reasoning Execution Receipt, Usage, Cost, Failure, and Cancellation Evidence Contract v1.0 + +## Purpose + +Define provider-neutral evidence for the execution of a Reasoning Invocation. + +## Execution Receipt + +The Execution Receipt should include: + +- Contract version +- Execution Attempt ID +- Invocation Request ID and fingerprint +- Provider Capability ID and fingerprint +- Attempt number +- Started-at evidence +- Completed-at evidence +- Outcome +- Canonical receipt fingerprint + +## Usage Evidence + +Usage Evidence may include: + +- Input character count +- Output character count +- Instruction block count +- Context Package object count +- Attempt count +- Duration evidence +- Optional estimated input units +- Optional estimated output units +- Canonical Usage Evidence fingerprint + +Provider-specific token accounting is deferred. + +## Cost Evidence + +Cost Evidence may include: + +- Evidence status +- Currency code when applicable +- Amount in minor units when applicable +- Estimation method +- Pricing reference version +- Whether the value is actual, estimated, unavailable, or not applicable +- Canonical Cost Evidence fingerprint + +The deterministic fake provider should normally return `not-applicable` or deterministic zero-cost evidence. + +## Failure Evidence + +Failure Evidence should include: + +- Failure category +- Stable reason codes +- Retryable classification +- Sanitized failure detail +- Attempt number +- Canonical Failure Evidence fingerprint + +## Timeout Evidence + +Timeout Evidence should include: + +- Configured timeout +- Deterministic elapsed evidence +- Timeout phase +- Stable reason code +- Canonical fingerprint + +## Cancellation Evidence + +Cancellation Evidence should include: + +- Cancellation mode +- Cancellation phase +- Cancellation authority reference +- Requested-at evidence +- Observed-at evidence +- Stable reason code +- Canonical fingerprint + +## Principle + +Operational evidence must explain the execution outcome without exposing provider secrets or implementation-specific diagnostics. diff --git a/docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Idempotency_Retry_Timeout_and_Cancellation_Specification_v1.0.md b/docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Idempotency_Retry_Timeout_and_Cancellation_Specification_v1.0.md new file mode 100644 index 0000000..06604b3 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Idempotency_Retry_Timeout_and_Cancellation_Specification_v1.0.md @@ -0,0 +1,63 @@ +# FounderOS Reasoning Invocation Idempotency, Retry, Timeout, and Cancellation Specification v1.0 + +## Purpose + +Define deterministic execution lifecycle controls for governed Reasoning Invocations. + +## Invocation Idempotency + +The same Invocation idempotency key and identical canonical request must resolve to the original finalized invocation result. + +Conflicting reuse of the same key with different canonical content must fail. + +## Attempt Identity + +Every execution attempt must have: + +- Stable Attempt ID +- Invocation Request fingerprint +- Attempt number +- Provider Capability fingerprint +- Execution Policy fingerprint +- Explicit start evidence +- Attempt fingerprint + +## Retry Rules + +Retries are permitted only by the verified Execution Policy. + +A retry must: + +- Preserve the original Invocation and Delivery bindings +- Increment attempt number deterministically +- Record the previous attempt +- Re-evaluate timeout and cancellation state +- Never change provider capability requirements silently + +## Timeout Rules + +Timeout logic must use injected time or deterministic fake-provider evidence. + +Timeout must produce a terminal attempt outcome unless the Retry Policy permits a new attempt. + +## Cancellation Rules + +Cancellation must be explicit, evidence-bearing, and bound to the Invocation. + +Cancellation may occur: + +- Before execution +- During cooperative execution +- At a deadline + +A cancelled attempt must never be represented as successful. + +## Finalization + +Only one finalized Invocation Result may own the Invocation idempotency key. + +Attempt history remains append-only. + +## Principle + +Retries create new attempts; they do not rewrite prior execution evidence. diff --git a/docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Request_Contract_v1.0.md b/docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Request_Contract_v1.0.md new file mode 100644 index 0000000..11ab3c7 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Reasoning_Invocation_Request_Contract_v1.0.md @@ -0,0 +1,42 @@ +# FounderOS Reasoning Invocation Request Contract v1.0 + +## Purpose + +Define the provider-neutral request to execute reasoning against one exact Governed Delivery Envelope. + +## Required Fields + +- Contract version +- Invocation Request ID +- Delivery Transaction ID +- Delivery Envelope ID and fingerprint +- Delivery Receipt ID and fingerprint +- Consumer ID and Descriptor fingerprint +- Invocation purpose +- Provider Capability requirements +- Provider-neutral reasoning input +- Execution Policy +- Invocation idempotency key +- Request actor +- Request reason +- Requested-at evidence +- Canonical request fingerprint + +## Required Bindings + +The request must bind to: + +- Exact Context Package fingerprint +- Exact Active Snapshot binding +- Exact Registry integrity binding +- Exact Policy Decision Evidence +- Exact Consumer identity +- Exact Delivery Receipt + +## Validation Rules + +Reject unknown fields, unsupported versions, empty purpose or reason, invalid IDs, forged Delivery or Receipt bindings, unsupported content types, contradictory Execution Policy, invalid timeout or budget values, duplicate idempotency identifiers, and forged request fingerprints. + +## Principle + +A Reasoning Invocation Request consumes a governed Delivery artifact; it never queries organizational knowledge directly. diff --git a/docs/milestones/milestone-13/FounderOS_Reasoning_Provider_Capability_Descriptor_Contract_v1.0.md b/docs/milestones/milestone-13/FounderOS_Reasoning_Provider_Capability_Descriptor_Contract_v1.0.md new file mode 100644 index 0000000..bf928df --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Reasoning_Provider_Capability_Descriptor_Contract_v1.0.md @@ -0,0 +1,44 @@ +# FounderOS Reasoning Provider Capability Descriptor Contract v1.0 + +## Purpose + +Define a provider-neutral description of what a reasoning executor can accept and produce. + +## Descriptor Fields + +- Contract version +- Provider Capability ID +- Provider class +- Accepted Invocation Request versions +- Accepted Delivery Envelope versions +- Accepted input content types +- Maximum input character count +- Maximum output character count +- Supported timeout range +- Supported cancellation behavior +- Supported retry behavior +- Supported deterministic execution mode +- Supported Usage Evidence +- Supported Cost Evidence +- Supported Failure Evidence +- Supported Result Envelope versions +- Descriptor fingerprint + +## Provider Classes + +Initial provider-neutral classes may include: + +- Deterministic fake provider +- Remote reasoning provider +- Local reasoning provider +- Evaluation provider + +These classes do not name a vendor or model. + +## Validation Rules + +Reject unknown fields, duplicate versions, non-positive limits, contradictory capabilities, unsupported combinations, empty capability identity, and forged fingerprints. + +## Principle + +Capability matching determines compatibility; it does not select a vendor or model. diff --git a/docs/milestones/milestone-13/FounderOS_Reasoning_Result_Envelope_Contract_v1.0.md b/docs/milestones/milestone-13/FounderOS_Reasoning_Result_Envelope_Contract_v1.0.md new file mode 100644 index 0000000..e60bb33 --- /dev/null +++ b/docs/milestones/milestone-13/FounderOS_Reasoning_Result_Envelope_Contract_v1.0.md @@ -0,0 +1,55 @@ +# FounderOS Reasoning Result Envelope Contract v1.0 + +## Purpose + +Define the immutable provider-neutral result of a governed Reasoning Invocation. + +## Result Envelope Fields + +- Contract version +- Result Envelope ID +- Invocation Request ID and fingerprint +- Delivery Transaction ID +- Delivery Envelope ID and fingerprint +- Delivery Receipt ID and fingerprint +- Provider Capability ID and fingerprint +- Execution Attempt ID +- Attempt number +- Outcome status +- Canonical output content +- Output content fingerprint +- Execution Receipt +- Usage Evidence +- Cost Evidence +- Failure, Timeout, or Cancellation Evidence when applicable +- Completed-at evidence +- Canonical Result Envelope fingerprint + +## Outcome Status + +Initial statuses: + +- Succeeded +- Failed +- Timed out +- Cancelled + +## Output Rules + +Successful output must: + +- Use provider-neutral content types +- Respect output budget +- Contain no hidden Context Package additions +- Contain no credentials or physical paths +- Be immutable and canonically serializable + +Non-success outcomes must not include contradictory successful output. + +## Verification + +Independent verification must recompute every nested fingerprint and validate all Delivery, Invocation, Provider Capability, attempt, output, and evidence bindings. + +## Principle + +A Result Envelope is the auditable output of one exact governed execution attempt. diff --git a/packages/knowledge-schema/README.md b/packages/knowledge-schema/README.md index 34e893c..ca941d7 100644 --- a/packages/knowledge-schema/README.md +++ b/packages/knowledge-schema/README.md @@ -38,6 +38,8 @@ Milestone 11 adds strict Consumer identity and capability, governed delivery req Milestone 12 adds strict, versioned, storage-independent contracts for immutable Delivery Request registration, permanent idempotency ownership, exact Milestone 11 artifact wrappers, atomic original Delivery transactions, separate Replay Attempts, expiration evidence, append-only audit events, deterministic Recovery and Integrity results, and rebuildable derived indexes. Every authoritative wrapper binds an explicit Ledger sequence and previous-audit fingerprint. Derived indexes declare the versioned `bounded-latest-v1` retention policy and an enforced positive entry capacity. Expired keys remain permanently reserved under `permanent-reservation-v1`. The shared `DurableContextDeliveryLedger` exposes governed reads, recovery, verification, and rebuild operations; it does not expose raw record append, filesystem, SQL, provider, prompt, model, agent, Hermes, or MCP concepts. +Milestone 13 adds strict, versioned, storage-independent contracts for provider-neutral Reasoning Inputs, Execution Policies and budgets, Provider Capability requirements and descriptors, compatibility evidence, governed Invocation Requests, immutable Attempts and Provider Outcomes, operational evidence, Result Envelopes, finalized Consumption Evidence, permanent Invocation ownership, atomic finalization, append-only execution-evidence Ledger events, deterministic Recovery and Integrity results, and rebuildable derived indexes. These shared contracts bind the existing Context Package, Delivery Envelope, Receipt, Consumer, Policy Decision, Active Snapshot, and Registry fingerprints without redefining Milestones 10–12. The package contains no Provider adapter, model payload, prompt role, credentials, network, filesystem, SQL, Agent, Hermes, MCP, or orchestration behavior. + ## Usage ```typescript diff --git a/packages/knowledge-schema/src/durable-reasoning-ledger.ts b/packages/knowledge-schema/src/durable-reasoning-ledger.ts new file mode 100644 index 0000000..e69f703 --- /dev/null +++ b/packages/knowledge-schema/src/durable-reasoning-ledger.ts @@ -0,0 +1,963 @@ +import { z } from "zod"; + +import { DurableCanonicalJsonValueSchema } from "./canonical-json.js"; +import { IsoTemporalSchema, Sha256DigestSchema } from "./primitives.js"; +import { + FinalizedReasoningConsumptionEvidenceSchema, + ReasoningExecutionAttemptSchema, + ReasoningIdentifierSchema as IdentifierSchema, + ReasoningInvocationIdempotencyKeySchema, + ReasoningInvocationRequestSchema, + ReasoningLogicalReferenceSchema, + ReasoningNonEmptyCanonicalTextSchema, + ReasoningProviderOutcomeSchema, + ReasoningResultEnvelopeSchema, + type FinalizedReasoningConsumptionEvidence, + type ReasoningExecutionAttempt, + type ReasoningInvocationRequest, + type ReasoningProviderOutcome, + type ReasoningResultEnvelope, +} from "./reasoning.js"; + +const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; + +export const ReasoningExecutionLedgerSequenceSchema = z + .number() + .int() + .positive() + .max(MAX_SAFE_INTEGER); +export const ReasoningExecutionLedgerCountSchema = z + .number() + .int() + .nonnegative() + .max(MAX_SAFE_INTEGER); +export const ReasoningExecutionPreviousAuditFingerprintSchema = z.union([ + z.literal("genesis"), + Sha256DigestSchema, +]); + +function requireChainPosition( + value: { ledgerSequence: number; previousAuditFingerprint: string }, + context: z.RefinementCtx, +): void { + if ((value.ledgerSequence === 1) !== (value.previousAuditFingerprint === "genesis")) { + context.addIssue({ + code: "custom", + message: "Only the first Execution Ledger event may link to genesis", + path: ["previousAuditFingerprint"], + }); + } +} + +function isSortedUnique(values: readonly string[]): boolean { + return values.every((value, index) => index === 0 || values[index - 1]! < value); +} + +function requireSortedUnique( + values: readonly string[], + context: z.RefinementCtx, + path: readonly PropertyKey[], + label: string, +): void { + if (!isSortedUnique(values)) { + context.addIssue({ + code: "custom", + message: `${label} must be unique and sorted`, + path: [...path], + }); + } +} + +const ReasoningExecutionChainFields = { + ledgerSequence: ReasoningExecutionLedgerSequenceSchema, + previousAuditFingerprint: ReasoningExecutionPreviousAuditFingerprintSchema, + committedAt: IsoTemporalSchema, +} as const; + +export const ReasoningExecutionLedgerHeadExpectationSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + ledgerSequence: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + auditFingerprint: z.union([z.literal("genesis"), Sha256DigestSchema]), + }) + .strict() + .superRefine((value, context) => { + if ((value.ledgerSequence === 0) !== (value.auditFingerprint === "genesis")) { + context.addIssue({ + code: "custom", + message: "Only an empty Execution Ledger head may use genesis", + path: ["auditFingerprint"], + }); + } + }), +); + +export const ReasoningInvocationOwnershipStatusSchema = z.enum(["in-progress", "finalized"]); +export const ReasoningInvocationOwnershipRecordSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + recordType: z.literal("invocation-ownership"), + ownershipId: IdentifierSchema, + invocationIdempotencyKey: ReasoningInvocationIdempotencyKeySchema, + invocationRequestId: IdentifierSchema, + invocationRequestFingerprint: Sha256DigestSchema, + ownershipStatus: z.literal("in-progress"), + ownershipSequence: ReasoningExecutionLedgerSequenceSchema, + createdAt: IsoTemporalSchema, + ...ReasoningExecutionChainFields, + ownershipFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireChainPosition(value, context); + if ( + value.ownershipSequence !== value.ledgerSequence || + value.createdAt !== value.committedAt + ) { + context.addIssue({ + code: "custom", + message: "Invocation ownership sequence and creation evidence must bind its Ledger event", + path: ["ownershipSequence"], + }); + } + }), +); + +export const DurableReasoningExecutionAttemptRecordSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + recordType: z.literal("execution-attempt"), + invocationRequestId: IdentifierSchema, + invocationRequestFingerprint: Sha256DigestSchema, + invocationIdempotencyKey: ReasoningInvocationIdempotencyKeySchema, + attempt: ReasoningExecutionAttemptSchema, + ...ReasoningExecutionChainFields, + recordFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireChainPosition(value, context); + if ( + value.invocationRequestId !== value.attempt.invocationRequestId || + value.invocationRequestFingerprint !== value.attempt.invocationRequestFingerprint || + value.invocationIdempotencyKey !== value.attempt.invocationIdempotencyKey || + value.committedAt !== value.attempt.startedAt + ) { + context.addIssue({ + code: "custom", + message: "Durable Attempt record must preserve exact Invocation and start bindings", + path: ["attempt"], + }); + } + }), +); + +export const DurableReasoningProviderOutcomeRecordSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + recordType: z.literal("provider-outcome"), + invocationRequestId: IdentifierSchema, + executionAttemptId: IdentifierSchema, + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + outcome: ReasoningProviderOutcomeSchema, + ...ReasoningExecutionChainFields, + recordFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireChainPosition(value, context); + if ( + value.invocationRequestId !== value.outcome.invocationRequestId || + value.executionAttemptId !== value.outcome.executionAttemptId || + value.attemptNumber !== value.outcome.attemptNumber || + value.committedAt !== value.outcome.completedAt + ) { + context.addIssue({ + code: "custom", + message: "Durable Provider Outcome record must preserve exact Attempt bindings", + path: ["outcome"], + }); + } + }), +); + +interface FinalizationBindingInput { + readonly transactionId: string; + readonly resultEnvelope: ReasoningResultEnvelope; + readonly consumptionEvidence: FinalizedReasoningConsumptionEvidence; + readonly completedAt: string; + readonly invocationIdempotencyKey?: string; + readonly invocationRequestId?: string; + readonly invocationRequestFingerprint?: string; +} + +function validateFinalizationBindings( + value: FinalizationBindingInput, + context: z.RefinementCtx, +): void { + const result = value.resultEnvelope; + const consumption = value.consumptionEvidence; + const finalAttempt = consumption.attemptHistorySummary.attempts.at(-1)!; + if ( + result.invocationIdempotencyKey !== consumption.invocationIdempotencyKey || + result.invocationRequestId !== consumption.invocationRequestId || + result.invocationRequestFingerprint !== consumption.invocationRequestFingerprint || + consumption.finalResultEnvelopeId !== result.resultEnvelopeId || + consumption.finalResultEnvelopeFingerprint !== result.resultEnvelopeFingerprint || + consumption.finalOutcome !== result.outcome || + consumption.deliveryReceiptId !== result.deliveryReceiptId || + consumption.deliveryReceiptFingerprint !== result.deliveryReceiptFingerprint || + consumption.deliveryTransactionId !== result.deliveryTransactionId || + consumption.providerCapabilityId !== result.providerCapabilityId || + consumption.providerCapabilityFingerprint !== result.providerCapabilityFingerprint || + consumption.usageEvidenceFingerprint !== result.usageEvidence.usageFingerprint || + consumption.costEvidenceFingerprint !== result.costEvidence.costFingerprint || + consumption.executionLedgerTransactionId !== value.transactionId || + finalAttempt.executionAttemptId !== result.executionAttemptId || + finalAttempt.attemptNumber !== result.attemptNumber || + finalAttempt.outcome !== result.outcome || + consumption.completedAt !== value.completedAt || + (value.invocationIdempotencyKey !== undefined && + (value.invocationIdempotencyKey !== result.invocationIdempotencyKey || + value.invocationIdempotencyKey !== consumption.invocationIdempotencyKey)) || + (value.invocationRequestId !== undefined && + (value.invocationRequestId !== result.invocationRequestId || + value.invocationRequestId !== consumption.invocationRequestId)) || + (value.invocationRequestFingerprint !== undefined && + (value.invocationRequestFingerprint !== result.invocationRequestFingerprint || + value.invocationRequestFingerprint !== consumption.invocationRequestFingerprint)) + ) { + context.addIssue({ + code: "custom", + message: "Finalization must atomically bind its Result and Consumption Evidence", + path: ["consumptionEvidence"], + }); + } + if ( + (result.outcome === "failed" && + consumption.finalOutcome === "failed" && + consumption.failureEvidenceFingerprint !== result.failureEvidence.failureFingerprint) || + (result.outcome === "timed-out" && + consumption.finalOutcome === "timed-out" && + consumption.timeoutEvidenceFingerprint !== result.timeoutEvidence.timeoutFingerprint) || + (result.outcome === "cancelled" && + consumption.finalOutcome === "cancelled" && + consumption.cancellationEvidenceFingerprint !== + result.cancellationEvidence.cancellationFingerprint) + ) { + context.addIssue({ + code: "custom", + message: "Finalized Consumption terminal evidence must bind the Result outcome", + path: ["consumptionEvidence", "finalOutcome"], + }); + } +} + +export const FinalizedReasoningInvocationTransactionSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + recordType: z.literal("finalized-invocation-transaction"), + transactionId: IdentifierSchema, + ownershipId: IdentifierSchema, + invocationIdempotencyKey: ReasoningInvocationIdempotencyKeySchema, + invocationRequestId: IdentifierSchema, + invocationRequestFingerprint: Sha256DigestSchema, + resultEnvelope: ReasoningResultEnvelopeSchema, + consumptionEvidence: FinalizedReasoningConsumptionEvidenceSchema, + ...ReasoningExecutionChainFields, + transactionFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireChainPosition(value, context); + validateFinalizationBindings( + { + ...value, + completedAt: value.committedAt, + }, + context, + ); + }), +); + +export const ReasoningExecutionIntegrityCheckpointRecordSchema = + DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + recordType: z.literal("integrity-checkpoint"), + checkpointId: IdentifierSchema, + verifiedThroughSequence: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + verifiedAuditFingerprint: z.union([z.literal("genesis"), Sha256DigestSchema]), + executionEvidenceFingerprint: Sha256DigestSchema, + ...ReasoningExecutionChainFields, + checkpointFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireChainPosition(value, context); + if ( + value.verifiedThroughSequence >= value.ledgerSequence || + (value.verifiedThroughSequence === 0) !== (value.verifiedAuditFingerprint === "genesis") + ) { + context.addIssue({ + code: "custom", + message: "Integrity checkpoint must verify a coherent prior Ledger head", + path: ["verifiedThroughSequence"], + }); + } + }), + ); + +export const ReasoningExecutionLedgerEventSchema = DurableCanonicalJsonValueSchema.pipe( + z + .discriminatedUnion("eventType", [ + z + .object({ + schemaVersion: z.literal("1.0"), + eventType: z.literal("invocation-ownership"), + ledgerSequence: ReasoningExecutionLedgerSequenceSchema, + previousAuditFingerprint: ReasoningExecutionPreviousAuditFingerprintSchema, + ownership: ReasoningInvocationOwnershipRecordSchema, + auditFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + eventType: z.literal("execution-attempt"), + ledgerSequence: ReasoningExecutionLedgerSequenceSchema, + previousAuditFingerprint: ReasoningExecutionPreviousAuditFingerprintSchema, + attemptRecord: DurableReasoningExecutionAttemptRecordSchema, + auditFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + eventType: z.literal("provider-outcome"), + ledgerSequence: ReasoningExecutionLedgerSequenceSchema, + previousAuditFingerprint: ReasoningExecutionPreviousAuditFingerprintSchema, + outcomeRecord: DurableReasoningProviderOutcomeRecordSchema, + auditFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + eventType: z.literal("invocation-finalization"), + ledgerSequence: ReasoningExecutionLedgerSequenceSchema, + previousAuditFingerprint: ReasoningExecutionPreviousAuditFingerprintSchema, + finalization: FinalizedReasoningInvocationTransactionSchema, + auditFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + eventType: z.literal("integrity-checkpoint"), + ledgerSequence: ReasoningExecutionLedgerSequenceSchema, + previousAuditFingerprint: ReasoningExecutionPreviousAuditFingerprintSchema, + checkpoint: ReasoningExecutionIntegrityCheckpointRecordSchema, + auditFingerprint: Sha256DigestSchema, + }) + .strict(), + ]) + .superRefine((value, context) => { + requireChainPosition(value, context); + const nested = + value.eventType === "invocation-ownership" + ? value.ownership + : value.eventType === "execution-attempt" + ? value.attemptRecord + : value.eventType === "provider-outcome" + ? value.outcomeRecord + : value.eventType === "invocation-finalization" + ? value.finalization + : value.checkpoint; + if ( + nested.ledgerSequence !== value.ledgerSequence || + nested.previousAuditFingerprint !== value.previousAuditFingerprint + ) { + context.addIssue({ + code: "custom", + message: "Execution Ledger event and authoritative record chain positions must agree", + path: ["ledgerSequence"], + }); + } + }), +); + +export const RegisterReasoningInvocationRequestSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + expectedLedgerHead: ReasoningExecutionLedgerHeadExpectationSchema, + expectedIdempotencyState: z.literal("unowned"), + invocationRequest: ReasoningInvocationRequestSchema, + registeredAt: IsoTemporalSchema, + }) + .strict(), +); + +export const AppendReasoningExecutionAttemptRequestSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + expectedLedgerHead: ReasoningExecutionLedgerHeadExpectationSchema, + ownershipId: IdentifierSchema, + expectedOwnershipStatus: z.literal("in-progress"), + expectedPriorAttemptCount: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + attempt: ReasoningExecutionAttemptSchema, + }) + .strict() + .refine((value) => value.attempt.attemptNumber === value.expectedPriorAttemptCount + 1, { + message: "Attempt number must follow the authoritative prior Attempt count", + path: ["attempt", "attemptNumber"], + }), +); + +export const AppendReasoningProviderOutcomeRequestSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + expectedLedgerHead: ReasoningExecutionLedgerHeadExpectationSchema, + ownershipId: IdentifierSchema, + expectedOwnershipStatus: z.literal("in-progress"), + attemptFingerprint: Sha256DigestSchema, + outcome: ReasoningProviderOutcomeSchema, + }) + .strict(), +); + +export const FinalizeReasoningInvocationRequestSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + expectedLedgerHead: ReasoningExecutionLedgerHeadExpectationSchema, + ownershipId: IdentifierSchema, + expectedOwnershipStatus: z.literal("in-progress"), + expectedAttemptCount: z.number().int().positive().max(MAX_SAFE_INTEGER), + transactionId: IdentifierSchema, + resultEnvelope: ReasoningResultEnvelopeSchema, + consumptionEvidence: FinalizedReasoningConsumptionEvidenceSchema, + finalizedAt: IsoTemporalSchema, + }) + .strict() + .superRefine((value, context) => { + validateFinalizationBindings( + { + transactionId: value.transactionId, + resultEnvelope: value.resultEnvelope, + consumptionEvidence: value.consumptionEvidence, + completedAt: value.finalizedAt, + }, + context, + ); + if ( + value.expectedAttemptCount !== value.resultEnvelope.attemptNumber || + value.expectedAttemptCount !== + value.consumptionEvidence.attemptHistorySummary.attemptCount || + value.transactionId !== value.consumptionEvidence.executionLedgerTransactionId || + value.finalizedAt !== value.resultEnvelope.completedAt || + value.finalizedAt !== value.consumptionEvidence.completedAt + ) { + context.addIssue({ + code: "custom", + message: "Finalization request must bind its terminal Attempt, transaction, and time", + path: ["expectedAttemptCount"], + }); + } + }), +); + +export const ReasoningInvocationOwnershipResolutionStatusSchema = z.enum([ + "conflict", + "identical-finalized", + "identical-in-progress", + "registered", +]); +export const ReasoningInvocationOwnershipReasonCodeSchema = z.enum([ + "idempotency_key_conflict", + "invocation_already_finalized", + "invocation_already_in_progress", + "invocation_registered", +]); +export const ReasoningInvocationOwnershipResolutionSchema = DurableCanonicalJsonValueSchema.pipe( + z + .discriminatedUnion("status", [ + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("registered"), + reasonCode: z.literal("invocation_registered"), + ownership: ReasoningInvocationOwnershipRecordSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("identical-in-progress"), + reasonCode: z.literal("invocation_already_in_progress"), + ownership: ReasoningInvocationOwnershipRecordSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("identical-finalized"), + reasonCode: z.literal("invocation_already_finalized"), + ownership: ReasoningInvocationOwnershipRecordSchema, + finalization: FinalizedReasoningInvocationTransactionSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("conflict"), + reasonCode: z.literal("idempotency_key_conflict"), + existingInvocationRequestId: IdentifierSchema, + existingInvocationRequestFingerprint: Sha256DigestSchema, + }) + .strict(), + ]) + .superRefine((value, context) => { + if ( + value.status === "identical-finalized" && + (value.ownership.ownershipId !== value.finalization.ownershipId || + value.ownership.invocationIdempotencyKey !== + value.finalization.invocationIdempotencyKey || + value.ownership.invocationRequestId !== value.finalization.invocationRequestId || + value.ownership.invocationRequestFingerprint !== + value.finalization.invocationRequestFingerprint) + ) { + context.addIssue({ + code: "custom", + message: "Identical finalized resolution must preserve exact Invocation ownership", + path: ["finalization"], + }); + } + }), +); + +export const ReasoningInvocationFinalizationStatusSchema = z.enum([ + "conflict", + "finalized", + "identical-finalization", +]); +export const ReasoningInvocationFinalizationResultSchema = DurableCanonicalJsonValueSchema.pipe( + z.discriminatedUnion("status", [ + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("finalized"), + finalization: FinalizedReasoningInvocationTransactionSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("identical-finalization"), + finalization: FinalizedReasoningInvocationTransactionSchema, + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("conflict"), + reasonCode: z.literal("conflicting_finalization"), + existingTransactionId: IdentifierSchema, + existingResultEnvelopeFingerprint: Sha256DigestSchema, + }) + .strict(), + ]), +); + +export const ReasoningExecutionLedgerIssueCodeSchema = z.enum([ + "attempt_binding_mismatch", + "attempt_order_invalid", + "audit_chain_broken", + "derived_index_invalid", + "derived_index_mismatch", + "derived_index_missing", + "finalization_conflict", + "finalization_incomplete", + "fingerprint_mismatch", + "invalid_raw_record", + "invocation_binding_mismatch", + "invocation_idempotency_conflict", + "orphan_attempt", + "orphan_outcome", + "outcome_binding_mismatch", + "resource_limit_exceeded", + "sequence_invalid", + "storage_failure", + "transaction_conflict", + "unsafe_content", + "unsupported_version", +]); +export const ReasoningExecutionLedgerIssueSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + code: ReasoningExecutionLedgerIssueCodeSchema, + logicalLocation: ReasoningLogicalReferenceSchema, + message: ReasoningNonEmptyCanonicalTextSchema, + }) + .strict(), +); + +export const DurableReasoningExecutionDerivedIndexSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + retentionPolicyVersion: z.literal("bounded-latest-v1"), + entryCapacity: z.number().int().positive().max(MAX_SAFE_INTEGER), + verifiedThroughSequence: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + verifiedAuditFingerprint: z.union([z.literal("genesis"), Sha256DigestSchema]), + invocationEntries: z.array( + z + .object({ + invocationIdempotencyKey: ReasoningInvocationIdempotencyKeySchema, + ownershipId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + invocationRequestFingerprint: Sha256DigestSchema, + status: ReasoningInvocationOwnershipStatusSchema, + finalizationTransactionId: IdentifierSchema.nullable(), + }) + .strict(), + ), + attemptEntries: z.array( + z + .object({ + executionAttemptId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + outcomeFingerprint: Sha256DigestSchema.nullable(), + }) + .strict(), + ), + resultEntries: z.array( + z + .object({ + invocationRequestId: IdentifierSchema, + resultEnvelopeId: IdentifierSchema, + resultEnvelopeFingerprint: Sha256DigestSchema, + consumptionId: IdentifierSchema, + }) + .strict(), + ), + indexFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + for (const [field, entries] of [ + ["invocationEntries", value.invocationEntries], + ["attemptEntries", value.attemptEntries], + ["resultEntries", value.resultEntries], + ] as const) { + if (entries.length > value.entryCapacity) { + context.addIssue({ + code: "custom", + message: "Derived index entries exceed the declared retention capacity", + path: [field], + }); + } + } + requireSortedUnique( + value.invocationEntries.map((entry) => entry.invocationIdempotencyKey), + context, + ["invocationEntries"], + "Invocation index keys", + ); + requireSortedUnique( + value.attemptEntries.map( + (entry) => + `${entry.invocationRequestId}\0${String(entry.attemptNumber).padStart(16, "0")}`, + ), + context, + ["attemptEntries"], + "Attempt index keys", + ); + requireSortedUnique( + value.resultEntries.map((entry) => entry.invocationRequestId), + context, + ["resultEntries"], + "Result index keys", + ); + if ( + (value.verifiedThroughSequence === 0) !== + (value.verifiedAuditFingerprint === "genesis") + ) { + context.addIssue({ + code: "custom", + message: "Derived index verification head must be coherent", + path: ["verifiedAuditFingerprint"], + }); + } + for (const [index, entry] of value.invocationEntries.entries()) { + if ((entry.status === "finalized") !== (entry.finalizationTransactionId !== null)) { + context.addIssue({ + code: "custom", + message: "Invocation index status and Finalization reference must agree", + path: ["invocationEntries", index, "status"], + }); + } + } + }), +); + +export const ReasoningExecutionDerivedIndexStatusSchema = z.enum([ + "current", + "invalid", + "missing", + "rebuilt", + "stale", +]); + +const RecoveryCounts = { + invocationOwnershipCount: ReasoningExecutionLedgerCountSchema, + executionAttemptCount: ReasoningExecutionLedgerCountSchema, + providerOutcomeCount: ReasoningExecutionLedgerCountSchema, + finalizedInvocationCount: ReasoningExecutionLedgerCountSchema, + finalizedConsumptionCount: ReasoningExecutionLedgerCountSchema, + integrityCheckpointCount: ReasoningExecutionLedgerCountSchema, + lastCommittedLedgerSequence: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + lastAuditFingerprint: z.union([z.literal("genesis"), Sha256DigestSchema]), + derivedIndexStatus: ReasoningExecutionDerivedIndexStatusSchema, +} as const; + +export const ReasoningExecutionLedgerRecoveryResultSchema = DurableCanonicalJsonValueSchema.pipe( + z + .discriminatedUnion("status", [ + z + .object({ + schemaVersion: z.literal("1.0"), + ledgerContractVersion: z.literal("1.0"), + status: z.literal("recovered"), + ...RecoveryCounts, + executionEvidenceFingerprint: Sha256DigestSchema, + errors: z.tuple([]), + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + ledgerContractVersion: z.literal("1.0"), + status: z.literal("failed"), + ...RecoveryCounts, + executionEvidenceFingerprint: z.null(), + errors: z.array(ReasoningExecutionLedgerIssueSchema).min(1), + }) + .strict(), + ]) + .superRefine((value, context) => { + if ( + (value.lastCommittedLedgerSequence === 0) !== + (value.lastAuditFingerprint === "genesis") + ) { + context.addIssue({ + code: "custom", + message: "Recovery Ledger sequence and audit head must agree", + path: ["lastAuditFingerprint"], + }); + } + const authoritativeEventCount = + value.invocationOwnershipCount + + value.executionAttemptCount + + value.providerOutcomeCount + + value.finalizedInvocationCount + + value.integrityCheckpointCount; + if ( + authoritativeEventCount !== value.lastCommittedLedgerSequence || + value.invocationOwnershipCount > value.lastCommittedLedgerSequence || + value.executionAttemptCount > value.lastCommittedLedgerSequence || + value.providerOutcomeCount > value.lastCommittedLedgerSequence || + value.finalizedInvocationCount > value.lastCommittedLedgerSequence || + value.finalizedConsumptionCount > value.lastCommittedLedgerSequence || + value.integrityCheckpointCount > value.lastCommittedLedgerSequence || + value.providerOutcomeCount > value.executionAttemptCount || + value.finalizedInvocationCount > value.invocationOwnershipCount || + value.finalizedInvocationCount > value.providerOutcomeCount || + value.finalizedInvocationCount !== value.finalizedConsumptionCount + ) { + context.addIssue({ + code: "custom", + message: "Recovery authoritative record counts are contradictory", + path: ["finalizedInvocationCount"], + }); + } + }), +); + +export const ReasoningExecutionLedgerIntegrityVerificationResultSchema = + DurableCanonicalJsonValueSchema.pipe( + z + .discriminatedUnion("status", [ + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("valid"), + verifiedEventCount: ReasoningExecutionLedgerCountSchema, + verifiedInvocationCount: ReasoningExecutionLedgerCountSchema, + verifiedAttemptCount: ReasoningExecutionLedgerCountSchema, + verifiedOutcomeCount: ReasoningExecutionLedgerCountSchema, + verifiedFinalizationCount: ReasoningExecutionLedgerCountSchema, + verifiedThroughSequence: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + lastAuditFingerprint: z.union([z.literal("genesis"), Sha256DigestSchema]), + executionEvidenceFingerprint: Sha256DigestSchema, + derivedIndexStatus: ReasoningExecutionDerivedIndexStatusSchema, + issues: z.tuple([]), + }) + .strict(), + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.literal("invalid"), + verifiedEventCount: ReasoningExecutionLedgerCountSchema, + verifiedInvocationCount: ReasoningExecutionLedgerCountSchema, + verifiedAttemptCount: ReasoningExecutionLedgerCountSchema, + verifiedOutcomeCount: ReasoningExecutionLedgerCountSchema, + verifiedFinalizationCount: ReasoningExecutionLedgerCountSchema, + verifiedThroughSequence: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + lastAuditFingerprint: z.union([z.literal("genesis"), Sha256DigestSchema]), + executionEvidenceFingerprint: z.null(), + derivedIndexStatus: ReasoningExecutionDerivedIndexStatusSchema, + issues: z.array(ReasoningExecutionLedgerIssueSchema).min(1), + }) + .strict(), + ]) + .superRefine((value, context) => { + const trackedEventCount = + value.verifiedInvocationCount + + value.verifiedAttemptCount + + value.verifiedOutcomeCount + + value.verifiedFinalizationCount; + if ( + value.verifiedEventCount !== value.verifiedThroughSequence || + trackedEventCount > value.verifiedEventCount || + (value.verifiedThroughSequence === 0) !== (value.lastAuditFingerprint === "genesis") || + value.verifiedInvocationCount > value.verifiedEventCount || + value.verifiedAttemptCount > value.verifiedEventCount || + value.verifiedOutcomeCount > value.verifiedEventCount || + value.verifiedFinalizationCount > value.verifiedEventCount || + value.verifiedOutcomeCount > value.verifiedAttemptCount || + value.verifiedFinalizationCount > value.verifiedInvocationCount || + value.verifiedFinalizationCount > value.verifiedOutcomeCount + ) { + context.addIssue({ + code: "custom", + message: "Integrity verification counts and verified Ledger head must agree", + path: ["verifiedThroughSequence"], + }); + } + }), + ); + +export const ReasoningExecutionLedgerDerivedIndexRebuildResultSchema = + DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: z.literal("1.0"), + status: z.enum(["failed", "rebuilt", "unchanged"]), + verifiedThroughSequence: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + indexFingerprint: Sha256DigestSchema.nullable(), + invocationEntryCount: ReasoningExecutionLedgerCountSchema, + attemptEntryCount: ReasoningExecutionLedgerCountSchema, + resultEntryCount: ReasoningExecutionLedgerCountSchema, + issues: z.array(ReasoningExecutionLedgerIssueSchema), + }) + .strict() + .superRefine((value, context) => { + if ( + (value.status === "failed" && + (value.indexFingerprint !== null || value.issues.length === 0)) || + (value.status !== "failed" && + (value.indexFingerprint === null || value.issues.length > 0)) + ) { + context.addIssue({ + code: "custom", + message: "Derived-index rebuild status, fingerprint, and issues must agree", + path: ["status"], + }); + } + }), + ); + +export type ReasoningExecutionLedgerHeadExpectation = z.infer< + typeof ReasoningExecutionLedgerHeadExpectationSchema +>; +export type ReasoningInvocationOwnershipRecord = z.infer< + typeof ReasoningInvocationOwnershipRecordSchema +>; +export type DurableReasoningExecutionAttemptRecord = z.infer< + typeof DurableReasoningExecutionAttemptRecordSchema +>; +export type DurableReasoningProviderOutcomeRecord = z.infer< + typeof DurableReasoningProviderOutcomeRecordSchema +>; +export type FinalizedReasoningInvocationTransaction = z.infer< + typeof FinalizedReasoningInvocationTransactionSchema +>; +export type ReasoningExecutionLedgerEvent = z.infer; +export type RegisterReasoningInvocationRequest = z.infer< + typeof RegisterReasoningInvocationRequestSchema +>; +export type AppendReasoningExecutionAttemptRequest = z.infer< + typeof AppendReasoningExecutionAttemptRequestSchema +>; +export type AppendReasoningProviderOutcomeRequest = z.infer< + typeof AppendReasoningProviderOutcomeRequestSchema +>; +export type FinalizeReasoningInvocationRequest = z.infer< + typeof FinalizeReasoningInvocationRequestSchema +>; +export type ReasoningInvocationOwnershipResolution = z.infer< + typeof ReasoningInvocationOwnershipResolutionSchema +>; +export type ReasoningInvocationFinalizationResult = z.infer< + typeof ReasoningInvocationFinalizationResultSchema +>; +export type DurableReasoningExecutionDerivedIndex = z.infer< + typeof DurableReasoningExecutionDerivedIndexSchema +>; +export type ReasoningExecutionLedgerRecoveryResult = z.infer< + typeof ReasoningExecutionLedgerRecoveryResultSchema +>; +export type ReasoningExecutionLedgerIntegrityVerificationResult = z.infer< + typeof ReasoningExecutionLedgerIntegrityVerificationResultSchema +>; +export type ReasoningExecutionLedgerDerivedIndexRebuildResult = z.infer< + typeof ReasoningExecutionLedgerDerivedIndexRebuildResultSchema +>; + +export interface DurableReasoningExecutionLedger { + registerInvocation( + request: RegisterReasoningInvocationRequest, + ): Promise; + appendExecutionAttempt( + request: AppendReasoningExecutionAttemptRequest, + ): Promise; + appendProviderOutcome( + request: AppendReasoningProviderOutcomeRequest, + ): Promise; + finalizeInvocation( + request: FinalizeReasoningInvocationRequest, + ): Promise; + resolveInvocationOwnership( + invocationIdempotencyKey: string, + ): Promise; + readInvocationRequest(invocationRequestId: string): Promise; + readAttemptHistory(invocationRequestId: string): Promise; + readProviderOutcome(executionAttemptId: string): Promise; + readFinalizedResult(invocationRequestId: string): Promise; + readFinalizedConsumptionEvidence( + invocationRequestId: string, + ): Promise; + recover(): Promise; + verifyIntegrity(): Promise; + rebuildDerivedIndexes(): Promise; +} diff --git a/packages/knowledge-schema/src/index.ts b/packages/knowledge-schema/src/index.ts index 1d2654c..cab67e9 100644 --- a/packages/knowledge-schema/src/index.ts +++ b/packages/knowledge-schema/src/index.ts @@ -4,6 +4,7 @@ export * from "./corpus.js"; export * from "./durable-registry.js"; export * from "./delivery.js"; export * from "./durable-delivery-ledger.js"; +export * from "./durable-reasoning-ledger.js"; export * from "./enums.js"; export * from "./metadata.js"; export * from "./migration.js"; @@ -12,5 +13,6 @@ export * from "./parse.js"; export * from "./primitives.js"; export * from "./query.js"; export * from "./query-result.js"; +export * from "./reasoning.js"; export * from "./repository.js"; export * from "./snapshot-lifecycle.js"; diff --git a/packages/knowledge-schema/src/reasoning.ts b/packages/knowledge-schema/src/reasoning.ts new file mode 100644 index 0000000..fb3a13e --- /dev/null +++ b/packages/knowledge-schema/src/reasoning.ts @@ -0,0 +1,1431 @@ +import { z } from "zod"; + +import { + DurableCanonicalJsonValueSchema, + type DurableCanonicalJsonValue, +} from "./canonical-json.js"; +import { + KnowledgeContextRegistryBindingSchema, + KnowledgeContextSnapshotBindingSchema, +} from "./context.js"; +import { ContextDeliveryRequestActorSchema } from "./delivery.js"; +import { + IdentifierSchema as BaseIdentifierSchema, + IsoTemporalSchema, + Sha256DigestSchema, +} from "./primitives.js"; + +const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; +const IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/u; +const LOGICAL_REFERENCE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/u; +const WINDOWS_PATH_PATTERN = /(?:[A-Za-z]:[\\/]|\\\\[^\\\s]+\\[^\\\s]+)/u; +const POSIX_PHYSICAL_PATH_PATTERN = + /(?:^|[\s([{'"=:;,])\/(?!\/)[^\s)\]}>'",;\\/]+(?:\/[^\s)\]}>'",;\\/]*)*/u; +const FILE_URI_PATTERN = /file:\/\//iu; +const CREDENTIAL_PATTERN = + /(?:api[_ -]?key|access[_ -]?token|authorization|bearer|password|private[_ -]?key|client[_ -]?secret)\s*[:=]\s*\S+/iu; +const CREDENTIAL_VALUE_PATTERN = + /(?:\b(?:sk|pk)_(?:live|test)_[A-Za-z0-9]+\b|\bgh[pousr]_[A-Za-z0-9]+\b|\bxox[baprs]-[A-Za-z0-9-]+\b|-----BEGIN [A-Z ]*PRIVATE KEY-----)/u; +const CREDENTIAL_KEY_PATTERN = + /(?:apikey|accesstoken|authorization|bearer|password|privatekey|clientsecret|credential|secret)/u; + +function hasLoneSurrogate(value: string): boolean { + for (let index = 0; index < value.length; index += 1) { + const code = value.charCodeAt(index); + if (code >= 0xd800 && code <= 0xdbff) { + const next = value.charCodeAt(index + 1); + if (next < 0xdc00 || next > 0xdfff) return true; + index += 1; + } else if (code >= 0xdc00 && code <= 0xdfff) { + return true; + } + } + return false; +} + +function isCanonicalText(value: string): boolean { + return ( + value === value.normalize("NFC") && + !value.includes("\r") && + !value.includes("\0") && + !hasLoneSurrogate(value) + ); +} + +function isSafeText(value: string): boolean { + return ( + isCanonicalText(value) && + !WINDOWS_PATH_PATTERN.test(value) && + !POSIX_PHYSICAL_PATH_PATTERN.test(value) && + !FILE_URI_PATTERN.test(value) && + !CREDENTIAL_PATTERN.test(value) && + !CREDENTIAL_VALUE_PATTERN.test(value) + ); +} + +function isSafeLogicalReference(value: string): boolean { + return ( + isCanonicalText(value) && + LOGICAL_REFERENCE_PATTERN.test(value) && + !value.startsWith("/") && + !value.startsWith("//") && + !value.includes("\\") && + !value.split("/").some((segment) => segment === "." || segment === "..") && + !/^[a-z][a-z0-9+.-]*:/iu.test(value) && + !FILE_URI_PATTERN.test(value) + ); +} + +function containsUnsafeString(value: DurableCanonicalJsonValue): boolean { + if (typeof value === "string") return !isSafeText(value); + if (Array.isArray(value)) return value.some(containsUnsafeString); + if (value !== null && typeof value === "object") { + return Object.entries(value).some(([key, nested]) => { + const normalizedKey = key + .normalize("NFC") + .toLowerCase() + .replace(/[^a-z0-9]/gu, ""); + return ( + !isSafeText(key) || + CREDENTIAL_KEY_PATTERN.test(normalizedKey) || + containsUnsafeString(nested) + ); + }); + } + return false; +} + +function isSortedUnique(values: readonly string[]): boolean { + return values.every((value, index) => index === 0 || values[index - 1]! < value); +} + +function requireSortedUnique( + values: readonly string[], + context: z.RefinementCtx, + path: readonly PropertyKey[], + label: string, +): void { + if (!isSortedUnique(values)) { + context.addIssue({ + code: "custom", + message: `${label} must be unique and sorted`, + path: [...path], + }); + } +} + +function compareTemporal(left: string, right: string): number { + return Date.parse(left) - Date.parse(right); +} + +export const ReasoningContractVersionSchema = z.literal("1.0"); +export const ReasoningIdentifierSchema = z + .string() + .refine((value) => value === value.trim(), "Identifiers cannot contain surrounding whitespace") + .pipe(BaseIdentifierSchema) + .refine( + (value) => /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u.test(value), + "Expected a canonical provider-neutral identifier", + ); +const IdentifierSchema = ReasoningIdentifierSchema; +export const ReasoningInvocationIdempotencyKeySchema = z + .string() + .regex(IDEMPOTENCY_KEY_PATTERN, "Invalid Reasoning Invocation idempotency key"); +export const ReasoningCanonicalTextSchema = z + .string() + .refine(isSafeText, "Expected canonical path-private and credential-private text"); +export const ReasoningNonEmptyCanonicalTextSchema = ReasoningCanonicalTextSchema.refine( + (value) => value.length > 0 && value.trim() === value, + "Expected non-empty canonical text without surrounding whitespace", +); +export const ReasoningLogicalReferenceSchema = z + .string() + .min(1) + .refine(isSafeLogicalReference, "Expected a path-private logical reference"); +export const ReasoningSafeCanonicalJsonValueSchema = DurableCanonicalJsonValueSchema.refine( + (value) => !containsUnsafeString(value), + "Canonical JSON cannot contain physical paths or credential-like material", +); + +export const ReasoningInstructionBlockTypeSchema = z.enum([ + "system-constraint", + "task-instruction", + "context-reference", + "output-requirement", + "evaluation-directive", +]); +export const ReasoningInstructionSourceClassificationSchema = z.enum([ + "governance-policy", + "request-author", + "delivered-context", + "evaluation-fixture", +]); +export const ReasoningInputContentTypeSchema = z.literal("provider-neutral-instruction-blocks-v1"); +export const ReasoningCapabilityInputContentTypeSchema = z.enum([ + "provider-neutral-instruction-blocks-v1", + "provider-neutral-instruction-blocks-v2", +]); +export const ReasoningCapabilityVersionSchema = z.enum(["1.0", "2.0"]); +export const ReasoningOutputContentTypeSchema = z.enum(["canonical-json", "canonical-text"]); + +export const ReasoningInstructionBlockSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + blockId: IdentifierSchema, + blockType: ReasoningInstructionBlockTypeSchema, + contentType: z.literal("canonical-text"), + text: ReasoningNonEmptyCanonicalTextSchema, + priority: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + sourceClassification: ReasoningInstructionSourceClassificationSchema, + blockFingerprint: Sha256DigestSchema, + }) + .strict(), +); + +export const ReasoningConstraintBlockSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + constraintId: IdentifierSchema, + text: ReasoningNonEmptyCanonicalTextSchema, + constraintFingerprint: Sha256DigestSchema, + }) + .strict(), +); + +export const ReasoningContextReferenceSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + contextPackageId: IdentifierSchema, + contextPackageFingerprint: Sha256DigestSchema, + deliveryEnvelopeId: IdentifierSchema, + deliveryEnvelopeFingerprint: Sha256DigestSchema, + }) + .strict(), +); + +export const ReasoningOutputRequirementsSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + contentType: ReasoningOutputContentTypeSchema, + maxCharacters: z.number().int().positive().max(MAX_SAFE_INTEGER), + requireNonEmpty: z.boolean(), + }) + .strict(), +); + +export const ReasoningEvaluationMetadataSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + evaluationId: IdentifierSchema, + evaluationReference: ReasoningLogicalReferenceSchema, + evaluatedAt: IsoTemporalSchema, + }) + .strict(), +); + +export const ProviderNeutralReasoningInputSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + contentType: ReasoningInputContentTypeSchema, + instructionBlocks: z.array(ReasoningInstructionBlockSchema).min(1), + contextReference: ReasoningContextReferenceSchema, + outputRequirements: ReasoningOutputRequirementsSchema, + constraintBlocks: z.array(ReasoningConstraintBlockSchema), + evaluationMetadata: ReasoningEvaluationMetadataSchema.optional(), + inputFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireSortedUnique( + value.instructionBlocks.map((block) => block.blockId), + context, + ["instructionBlocks"], + "Instruction Block IDs", + ); + requireSortedUnique( + value.constraintBlocks.map((block) => block.constraintId), + context, + ["constraintBlocks"], + "Constraint Block IDs", + ); + const contextBlocks = value.instructionBlocks.filter( + (block) => block.blockType === "context-reference", + ); + if (contextBlocks.length !== 1) { + context.addIssue({ + code: "custom", + message: "Reasoning input requires exactly one Context Reference Instruction Block", + path: ["instructionBlocks"], + }); + } + if (!value.instructionBlocks.some((block) => block.blockType === "task-instruction")) { + context.addIssue({ + code: "custom", + message: "Reasoning input requires at least one Task Instruction Block", + path: ["instructionBlocks"], + }); + } + if ( + value.instructionBlocks.some((block) => block.blockType === "evaluation-directive") !== + (value.evaluationMetadata !== undefined) + ) { + context.addIssue({ + code: "custom", + message: "Evaluation directives and Evaluation Metadata must be present together", + path: ["evaluationMetadata"], + }); + } + }), +); + +export const ReasoningRetryModeSchema = z.enum([ + "no-retry", + "retry-deterministic-transient-failure", + "retry-until-attempt-limit", + "evaluation-only-retry", +]); +export const ReasoningCancellationModeSchema = z.enum([ + "not-cancellable", + "cancel-before-execution", + "cooperative-cancellation", + "deadline-cancellation", +]); + +export const ReasoningExecutionPolicySchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + maxInputCharacters: z.number().int().positive().max(MAX_SAFE_INTEGER), + maxOutputCharacters: z.number().int().positive().max(MAX_SAFE_INTEGER), + timeoutMilliseconds: z.number().int().positive().max(MAX_SAFE_INTEGER), + cancellationMode: ReasoningCancellationModeSchema, + retryMode: ReasoningRetryModeSchema, + maxAttemptCount: z.number().int().positive().max(MAX_SAFE_INTEGER), + deterministicModeRequired: z.boolean(), + usageEvidenceRequired: z.boolean(), + costEvidenceRequired: z.boolean(), + failureEvidenceRequired: z.boolean(), + resultPersistenceRequired: z.boolean(), + evaluatedAt: IsoTemporalSchema, + policyFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + if ((value.retryMode === "no-retry") !== (value.maxAttemptCount === 1)) { + context.addIssue({ + code: "custom", + message: + "No-retry requires exactly one Attempt and multiple Attempts require a retry mode", + path: ["maxAttemptCount"], + }); + } + if ( + (value.retryMode === "retry-deterministic-transient-failure" || + value.retryMode === "evaluation-only-retry") && + !value.deterministicModeRequired + ) { + context.addIssue({ + code: "custom", + message: "Deterministic and evaluation retry modes require deterministic execution", + path: ["deterministicModeRequired"], + }); + } + if (!value.resultPersistenceRequired) { + context.addIssue({ + code: "custom", + message: "Milestone 13 requires finalized Result persistence", + path: ["resultPersistenceRequired"], + }); + } + }), +); + +export const ReasoningProviderClassSchema = z.enum([ + "deterministic-fake-provider", + "evaluation-provider", + "local-reasoning-provider", + "remote-reasoning-provider", +]); + +export const ReasoningProviderCapabilityRequirementsSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + acceptedProviderClasses: z.array(ReasoningProviderClassSchema).min(1), + requiredInputContentTypes: z.array(ReasoningInputContentTypeSchema).min(1), + requiredOutputContentType: ReasoningOutputContentTypeSchema, + deterministicModeRequired: z.boolean(), + usageEvidenceRequired: z.boolean(), + costEvidenceRequired: z.boolean(), + failureEvidenceRequired: z.boolean(), + resultEnvelopeVersion: ReasoningContractVersionSchema, + requirementsFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireSortedUnique( + value.acceptedProviderClasses, + context, + ["acceptedProviderClasses"], + "Accepted Provider classes", + ); + requireSortedUnique( + value.requiredInputContentTypes, + context, + ["requiredInputContentTypes"], + "Required input content types", + ); + }), +); + +export const ReasoningProviderCapabilityDescriptorSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + providerCapabilityId: IdentifierSchema, + providerClass: ReasoningProviderClassSchema, + acceptedInvocationRequestVersions: z.array(ReasoningCapabilityVersionSchema).min(1), + acceptedDeliveryEnvelopeVersions: z.array(ReasoningCapabilityVersionSchema).min(1), + acceptedInputContentTypes: z.array(ReasoningCapabilityInputContentTypeSchema).min(1), + acceptedOutputContentTypes: z.array(ReasoningOutputContentTypeSchema).min(1), + maxInputCharacters: z.number().int().positive().max(MAX_SAFE_INTEGER), + maxOutputCharacters: z.number().int().positive().max(MAX_SAFE_INTEGER), + minTimeoutMilliseconds: z.number().int().positive().max(MAX_SAFE_INTEGER), + maxTimeoutMilliseconds: z.number().int().positive().max(MAX_SAFE_INTEGER), + supportedCancellationModes: z.array(ReasoningCancellationModeSchema).min(1), + supportedRetryModes: z.array(ReasoningRetryModeSchema).min(1), + supportsDeterministicExecution: z.boolean(), + supportsUsageEvidence: z.boolean(), + supportsCostEvidence: z.boolean(), + supportsFailureEvidence: z.boolean(), + supportedResultEnvelopeVersions: z.array(ReasoningContractVersionSchema).min(1), + descriptorFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + for (const [field, values] of [ + ["acceptedInvocationRequestVersions", value.acceptedInvocationRequestVersions], + ["acceptedDeliveryEnvelopeVersions", value.acceptedDeliveryEnvelopeVersions], + ["acceptedInputContentTypes", value.acceptedInputContentTypes], + ["acceptedOutputContentTypes", value.acceptedOutputContentTypes], + ["supportedCancellationModes", value.supportedCancellationModes], + ["supportedRetryModes", value.supportedRetryModes], + ["supportedResultEnvelopeVersions", value.supportedResultEnvelopeVersions], + ] as const) { + requireSortedUnique(values, context, [field], field); + } + if (value.minTimeoutMilliseconds > value.maxTimeoutMilliseconds) { + context.addIssue({ + code: "custom", + message: "Supported timeout minimum cannot exceed the maximum", + path: ["minTimeoutMilliseconds"], + }); + } + if ( + (value.supportedRetryModes.includes("retry-deterministic-transient-failure") || + value.supportedRetryModes.includes("evaluation-only-retry")) && + !value.supportsDeterministicExecution + ) { + context.addIssue({ + code: "custom", + message: "Deterministic and evaluation retry support requires deterministic execution", + path: ["supportedRetryModes"], + }); + } + }), +); + +export const ReasoningCompatibilityStatusSchema = z.enum(["compatible", "incompatible"]); +export const ReasoningCompatibilityReasonCodeSchema = z.enum([ + "compatible", + "cancellation_mode_unsupported", + "cost_evidence_unsupported", + "delivery_envelope_version_unsupported", + "deterministic_mode_unsupported", + "failure_evidence_unsupported", + "input_budget_exceeded", + "input_content_type_unsupported", + "invocation_version_unsupported", + "output_budget_exceeded", + "output_content_type_unsupported", + "provider_class_unsupported", + "result_envelope_version_unsupported", + "retry_mode_unsupported", + "timeout_out_of_range", + "usage_evidence_unsupported", +]); +export const ReasoningCompatibilityMismatchFieldSchema = z.enum([ + "cancellationMode", + "costEvidenceRequired", + "deliveryEnvelopeVersion", + "deterministicModeRequired", + "failureEvidenceRequired", + "inputCharacters", + "inputContentType", + "invocationRequestVersion", + "maxOutputCharacters", + "outputContentType", + "providerClass", + "resultEnvelopeVersion", + "retryMode", + "timeoutMilliseconds", + "usageEvidenceRequired", +]); + +const COMPATIBILITY_REASON_FIELD = { + cancellation_mode_unsupported: "cancellationMode", + cost_evidence_unsupported: "costEvidenceRequired", + delivery_envelope_version_unsupported: "deliveryEnvelopeVersion", + deterministic_mode_unsupported: "deterministicModeRequired", + failure_evidence_unsupported: "failureEvidenceRequired", + input_budget_exceeded: "inputCharacters", + input_content_type_unsupported: "inputContentType", + invocation_version_unsupported: "invocationRequestVersion", + output_budget_exceeded: "maxOutputCharacters", + output_content_type_unsupported: "outputContentType", + provider_class_unsupported: "providerClass", + result_envelope_version_unsupported: "resultEnvelopeVersion", + retry_mode_unsupported: "retryMode", + timeout_out_of_range: "timeoutMilliseconds", + usage_evidence_unsupported: "usageEvidenceRequired", +} as const; + +export const ReasoningProviderCompatibilityResultSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + status: ReasoningCompatibilityStatusSchema, + reasonCodes: z.array(ReasoningCompatibilityReasonCodeSchema).min(1), + mismatchedFields: z.array(ReasoningCompatibilityMismatchFieldSchema), + invocationRequestFingerprint: Sha256DigestSchema, + reasoningInputFingerprint: Sha256DigestSchema, + executionPolicyFingerprint: Sha256DigestSchema, + providerCapabilityFingerprint: Sha256DigestSchema, + compatibilityFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireSortedUnique(value.reasonCodes, context, ["reasonCodes"], "Compatibility reasons"); + requireSortedUnique( + value.mismatchedFields, + context, + ["mismatchedFields"], + "Compatibility mismatch fields", + ); + if ( + value.status === "compatible" && + (value.reasonCodes.length !== 1 || + value.reasonCodes[0] !== "compatible" || + value.mismatchedFields.length !== 0) + ) { + context.addIssue({ + code: "custom", + message: "Compatible results require only the compatible reason and no mismatches", + path: ["status"], + }); + } + if ( + value.status === "incompatible" && + (value.reasonCodes.includes("compatible") || value.mismatchedFields.length === 0) + ) { + context.addIssue({ + code: "custom", + message: "Incompatible results require mismatch evidence and cannot be compatible", + path: ["status"], + }); + } + const expectedFields = value.reasonCodes + .filter((reason) => reason !== "compatible") + .map((reason) => COMPATIBILITY_REASON_FIELD[reason]) + .sort(); + if (JSON.stringify(expectedFields) !== JSON.stringify(value.mismatchedFields)) { + context.addIssue({ + code: "custom", + message: "Every Compatibility reason must bind its exact mismatched field", + path: ["mismatchedFields"], + }); + } + }), +); + +export const ReasoningInvocationRequestSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + invocationRequestId: IdentifierSchema, + deliveryTransactionId: IdentifierSchema, + deliveryEnvelopeVersion: z.literal("1.0"), + deliveryEnvelopeId: IdentifierSchema, + deliveryEnvelopeFingerprint: Sha256DigestSchema, + deliveryReceiptId: IdentifierSchema, + deliveryReceiptFingerprint: Sha256DigestSchema, + contextPackageId: IdentifierSchema, + contextPackageFingerprint: Sha256DigestSchema, + activeSnapshotBinding: KnowledgeContextSnapshotBindingSchema, + registryIntegrityBinding: KnowledgeContextRegistryBindingSchema, + consumerId: IdentifierSchema, + consumerDescriptorFingerprint: Sha256DigestSchema, + policyDecisionFingerprint: Sha256DigestSchema, + purpose: ReasoningNonEmptyCanonicalTextSchema, + capabilityRequirements: ReasoningProviderCapabilityRequirementsSchema, + reasoningInput: ProviderNeutralReasoningInputSchema, + executionPolicy: ReasoningExecutionPolicySchema, + idempotencyKey: ReasoningInvocationIdempotencyKeySchema, + requestActor: ContextDeliveryRequestActorSchema, + reason: ReasoningNonEmptyCanonicalTextSchema, + requestedAt: IsoTemporalSchema, + requestFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + const reference = value.reasoningInput.contextReference; + if ( + reference.contextPackageId !== value.contextPackageId || + reference.contextPackageFingerprint !== value.contextPackageFingerprint || + reference.deliveryEnvelopeId !== value.deliveryEnvelopeId || + reference.deliveryEnvelopeFingerprint !== value.deliveryEnvelopeFingerprint + ) { + context.addIssue({ + code: "custom", + message: "Reasoning Input must preserve the exact Delivery and Context Package bindings", + path: ["reasoningInput", "contextReference"], + }); + } + if ( + value.registryIntegrityBinding.recoveredActiveSnapshotId !== + value.activeSnapshotBinding.activeSnapshotId + ) { + context.addIssue({ + code: "custom", + message: "Registry and Active Snapshot bindings must agree", + path: ["registryIntegrityBinding", "recoveredActiveSnapshotId"], + }); + } + if ( + value.reasoningInput.outputRequirements.maxCharacters > + value.executionPolicy.maxOutputCharacters + ) { + context.addIssue({ + code: "custom", + message: "Input output requirements cannot exceed the Execution Policy budget", + path: ["reasoningInput", "outputRequirements", "maxCharacters"], + }); + } + const requirements = value.capabilityRequirements; + const policy = value.executionPolicy; + if ( + requirements.deterministicModeRequired !== policy.deterministicModeRequired || + requirements.usageEvidenceRequired !== policy.usageEvidenceRequired || + requirements.costEvidenceRequired !== policy.costEvidenceRequired || + requirements.failureEvidenceRequired !== policy.failureEvidenceRequired || + requirements.requiredOutputContentType !== + value.reasoningInput.outputRequirements.contentType + ) { + context.addIssue({ + code: "custom", + message: "Capability requirements, Reasoning Input, and Execution Policy must agree", + path: ["capabilityRequirements"], + }); + } + if ( + value.executionPolicy.evaluatedAt !== value.requestedAt || + (value.reasoningInput.evaluationMetadata !== undefined && + value.reasoningInput.evaluationMetadata.evaluatedAt !== value.requestedAt) + ) { + context.addIssue({ + code: "custom", + message: "Policy and evaluation timestamps must bind the Invocation timestamp", + path: ["requestedAt"], + }); + } + }), +); + +export const ReasoningCancellationStateSchema = z.enum([ + "not-requested", + "requested-before-execution", + "requested-cooperatively", + "requested-at-deadline", +]); +export const ReasoningOutcomeStatusSchema = z.enum([ + "succeeded", + "failed", + "timed-out", + "cancelled", +]); + +export const ReasoningExecutionAttemptSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + invocationRequestFingerprint: Sha256DigestSchema, + invocationIdempotencyKey: ReasoningInvocationIdempotencyKeySchema, + providerCapabilityId: IdentifierSchema, + providerCapabilityFingerprint: Sha256DigestSchema, + executionPolicyFingerprint: Sha256DigestSchema, + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + previousExecutionAttemptId: IdentifierSchema.optional(), + startedAt: IsoTemporalSchema, + deadlineAt: IsoTemporalSchema.optional(), + cancellationState: ReasoningCancellationStateSchema, + cancellationAuthorityReference: ReasoningLogicalReferenceSchema.optional(), + cancellationRequestedAt: IsoTemporalSchema.optional(), + cancellationObservedAt: IsoTemporalSchema.optional(), + attemptFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + if ((value.attemptNumber === 1) !== (value.previousExecutionAttemptId === undefined)) { + context.addIssue({ + code: "custom", + message: "Only the first Attempt may omit its previous Attempt binding", + path: ["previousExecutionAttemptId"], + }); + } + if ( + value.deadlineAt !== undefined && + compareTemporal(value.deadlineAt, value.startedAt) <= 0 + ) { + context.addIssue({ + code: "custom", + message: "Attempt deadline must be after its start", + path: ["deadlineAt"], + }); + } + const cancellationFields = [ + value.cancellationAuthorityReference, + value.cancellationRequestedAt, + value.cancellationObservedAt, + ]; + if ( + cancellationFields.every((field) => field === undefined) !== + (value.cancellationState === "not-requested") + ) { + context.addIssue({ + code: "custom", + message: + "Requested cancellation requires complete authority, request, and observation evidence", + path: ["cancellationAuthorityReference"], + }); + } + if ( + value.cancellationRequestedAt !== undefined && + value.cancellationObservedAt !== undefined && + compareTemporal(value.cancellationObservedAt, value.cancellationRequestedAt) < 0 + ) { + context.addIssue({ + code: "custom", + message: "Cancellation observation cannot precede its request", + path: ["cancellationObservedAt"], + }); + } + }), +); + +export const ReasoningFailureCategorySchema = z.enum([ + "attempt-limit-exhausted", + "capability", + "input-validation", + "output-validation", + "permanent-provider-failure", + "policy", + "transient-provider-failure", +]); +export const ReasoningFailureReasonCodeSchema = z.enum([ + "attempt_limit_exhausted", + "capability_mismatch", + "credential_material_rejected", + "invalid_provider_outcome", + "malformed_failure_outcome", + "malformed_success_outcome", + "output_budget_exceeded", + "permanent_provider_failure", + "physical_path_rejected", + "policy_rejected", + "transient_provider_failure", + "unsafe_output_rejected", +]); + +const FAILURE_CATEGORY_REASON_CODES = { + "attempt-limit-exhausted": ["attempt_limit_exhausted"], + capability: ["capability_mismatch"], + "input-validation": ["credential_material_rejected", "physical_path_rejected"], + "output-validation": [ + "credential_material_rejected", + "invalid_provider_outcome", + "malformed_failure_outcome", + "malformed_success_outcome", + "output_budget_exceeded", + "physical_path_rejected", + "unsafe_output_rejected", + ], + "permanent-provider-failure": ["permanent_provider_failure"], + policy: ["policy_rejected"], + "transient-provider-failure": ["transient_provider_failure"], +} as const; + +export const ReasoningFailureEvidenceSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + failureCategory: ReasoningFailureCategorySchema, + reasonCodes: z.array(ReasoningFailureReasonCodeSchema).min(1), + retryable: z.boolean(), + sanitizedDetail: ReasoningNonEmptyCanonicalTextSchema, + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + failureFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + requireSortedUnique(value.reasonCodes, context, ["reasonCodes"], "Failure reasons"); + const allowedReasons: readonly string[] = + FAILURE_CATEGORY_REASON_CODES[value.failureCategory]; + if (value.reasonCodes.some((reason) => !allowedReasons.includes(reason))) { + context.addIssue({ + code: "custom", + message: "Failure reason codes must be compatible with the Failure category", + path: ["reasonCodes"], + }); + } + if (value.retryable !== (value.failureCategory === "transient-provider-failure")) { + context.addIssue({ + code: "custom", + message: "Only transient Provider failures may be classified as retryable", + path: ["retryable"], + }); + } + }), +); + +export const ReasoningTimeoutPhaseSchema = z.enum([ + "before-execution", + "during-execution", + "provider-outcome-validation", +]); +export const ReasoningTimeoutReasonCodeSchema = z.enum([ + "execution_deadline_reached", + "execution_timeout", +]); +export const ReasoningTimeoutEvidenceSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + configuredTimeoutMilliseconds: z.number().int().positive().max(MAX_SAFE_INTEGER), + attemptStartedAt: IsoTemporalSchema, + deadlineAt: IsoTemporalSchema, + elapsedMilliseconds: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + timeoutPhase: ReasoningTimeoutPhaseSchema, + reasonCode: ReasoningTimeoutReasonCodeSchema, + timeoutFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + if (compareTemporal(value.deadlineAt, value.attemptStartedAt) <= 0) { + context.addIssue({ + code: "custom", + message: "Timeout deadline must be after Attempt start", + path: ["deadlineAt"], + }); + } + if ( + compareTemporal(value.deadlineAt, value.attemptStartedAt) !== + value.configuredTimeoutMilliseconds + ) { + context.addIssue({ + code: "custom", + message: "Timeout deadline must derive from the configured timeout", + path: ["deadlineAt"], + }); + } + if (value.elapsedMilliseconds < value.configuredTimeoutMilliseconds) { + context.addIssue({ + code: "custom", + message: "Timeout elapsed evidence must reach the configured timeout", + path: ["elapsedMilliseconds"], + }); + } + }), +); + +export const ReasoningCancellationPhaseSchema = z.enum([ + "before-execution", + "cooperative-execution", + "deadline", +]); +export const ReasoningCancellationReasonCodeSchema = z.enum([ + "cancelled_at_deadline", + "cancelled_before_execution", + "cancelled_cooperatively", +]); +export const ReasoningCancellationEvidenceSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + invocationRequestId: IdentifierSchema, + executionAttemptId: IdentifierSchema, + cancellationMode: ReasoningCancellationModeSchema, + cancellationPhase: ReasoningCancellationPhaseSchema, + cancellationAuthorityReference: ReasoningLogicalReferenceSchema, + requestedAt: IsoTemporalSchema, + observedAt: IsoTemporalSchema, + reasonCode: ReasoningCancellationReasonCodeSchema, + cancellationFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + const expected = { + "cancel-before-execution": { + phase: "before-execution", + reason: "cancelled_before_execution", + }, + "cooperative-cancellation": { + phase: "cooperative-execution", + reason: "cancelled_cooperatively", + }, + "deadline-cancellation": { phase: "deadline", reason: "cancelled_at_deadline" }, + } as const; + if (value.cancellationMode === "not-cancellable") { + context.addIssue({ + code: "custom", + message: "Not-cancellable policy cannot produce Cancellation Evidence", + path: ["cancellationMode"], + }); + } else { + const required = expected[value.cancellationMode]; + if (value.cancellationPhase !== required.phase || value.reasonCode !== required.reason) { + context.addIssue({ + code: "custom", + message: "Cancellation mode, phase, and reason must agree", + path: ["cancellationPhase"], + }); + } + } + if (compareTemporal(value.observedAt, value.requestedAt) < 0) { + context.addIssue({ + code: "custom", + message: "Cancellation observation cannot precede its request", + path: ["observedAt"], + }); + } + }), +); + +export const ReasoningOutputContentSchema = DurableCanonicalJsonValueSchema.pipe( + z.discriminatedUnion("contentType", [ + z + .object({ + contentType: z.literal("canonical-text"), + text: ReasoningCanonicalTextSchema, + }) + .strict(), + z + .object({ + contentType: z.literal("canonical-json"), + value: ReasoningSafeCanonicalJsonValueSchema, + }) + .strict(), + ]), +); + +export const ReasoningExecutionReceiptSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + invocationRequestFingerprint: Sha256DigestSchema, + providerCapabilityId: IdentifierSchema, + providerCapabilityFingerprint: Sha256DigestSchema, + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + startedAt: IsoTemporalSchema, + completedAt: IsoTemporalSchema, + outcome: ReasoningOutcomeStatusSchema, + receiptFingerprint: Sha256DigestSchema, + }) + .strict() + .refine((value) => compareTemporal(value.completedAt, value.startedAt) >= 0, { + message: "Execution Receipt completion cannot precede its start", + path: ["completedAt"], + }), +); + +export const ReasoningUsageEvidenceSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + inputCharacterCount: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + outputCharacterCount: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + instructionBlockCount: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + contextPackageObjectCount: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + durationMilliseconds: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + estimatedInputUnits: z.number().int().nonnegative().max(MAX_SAFE_INTEGER).optional(), + estimatedOutputUnits: z.number().int().nonnegative().max(MAX_SAFE_INTEGER).optional(), + estimationMethod: ReasoningLogicalReferenceSchema.optional(), + usageFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + const hasEstimates = + value.estimatedInputUnits !== undefined || value.estimatedOutputUnits !== undefined; + if (hasEstimates !== (value.estimationMethod !== undefined)) { + context.addIssue({ + code: "custom", + message: "Estimated units require an explicit deterministic estimation method", + path: ["estimationMethod"], + }); + } + }), +); + +export const ReasoningCostStatusSchema = z.enum([ + "actual", + "estimated", + "not-applicable", + "unavailable", +]); +export const ReasoningCostEvidenceSchema = DurableCanonicalJsonValueSchema.pipe( + z.discriminatedUnion("status", [ + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + status: z.enum(["actual", "estimated"]), + currencyCode: z.string().regex(/^[A-Z]{3}$/u), + amountMinorUnits: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + estimationMethod: ReasoningLogicalReferenceSchema, + pricingReferenceVersion: ReasoningLogicalReferenceSchema, + costFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + status: z.literal("unavailable"), + reasonCode: z.literal("cost_evidence_unavailable"), + costFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + status: z.literal("not-applicable"), + costFingerprint: Sha256DigestSchema, + }) + .strict(), + ]), +); + +const ProviderOutcomeBase = { + schemaVersion: ReasoningContractVersionSchema, + executionAttemptId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + completedAt: IsoTemporalSchema, +} as const; + +export const ReasoningProviderOutcomeSchema = DurableCanonicalJsonValueSchema.pipe( + z + .discriminatedUnion("status", [ + z + .object({ + ...ProviderOutcomeBase, + status: z.literal("succeeded"), + outputContent: ReasoningOutputContentSchema, + outputCharacterCount: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + outputContentFingerprint: Sha256DigestSchema, + outcomeFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + ...ProviderOutcomeBase, + status: z.literal("failed"), + failureEvidence: ReasoningFailureEvidenceSchema, + outcomeFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + ...ProviderOutcomeBase, + status: z.literal("timed-out"), + timeoutEvidence: ReasoningTimeoutEvidenceSchema, + outcomeFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + ...ProviderOutcomeBase, + status: z.literal("cancelled"), + cancellationEvidence: ReasoningCancellationEvidenceSchema, + outcomeFingerprint: Sha256DigestSchema, + }) + .strict(), + ]) + .superRefine((value, context) => { + const evidence = + value.status === "failed" + ? value.failureEvidence + : value.status === "timed-out" + ? value.timeoutEvidence + : value.status === "cancelled" + ? value.cancellationEvidence + : null; + if ( + evidence !== null && + (evidence.executionAttemptId !== value.executionAttemptId || + evidence.invocationRequestId !== value.invocationRequestId) + ) { + context.addIssue({ + code: "custom", + message: "Provider Outcome evidence must bind its Invocation and Attempt", + path: ["status"], + }); + } + if ( + value.status === "failed" && + value.failureEvidence.attemptNumber !== value.attemptNumber + ) { + context.addIssue({ + code: "custom", + message: "Failure Evidence must bind the Provider Outcome Attempt number", + path: ["failureEvidence", "attemptNumber"], + }); + } + }), +); + +const ReasoningResultBase = { + schemaVersion: ReasoningContractVersionSchema, + resultEnvelopeId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + invocationRequestFingerprint: Sha256DigestSchema, + invocationIdempotencyKey: ReasoningInvocationIdempotencyKeySchema, + deliveryTransactionId: IdentifierSchema, + deliveryEnvelopeId: IdentifierSchema, + deliveryEnvelopeFingerprint: Sha256DigestSchema, + deliveryReceiptId: IdentifierSchema, + deliveryReceiptFingerprint: Sha256DigestSchema, + contextPackageId: IdentifierSchema, + contextPackageFingerprint: Sha256DigestSchema, + consumerId: IdentifierSchema, + consumerDescriptorFingerprint: Sha256DigestSchema, + providerCapabilityId: IdentifierSchema, + providerCapabilityFingerprint: Sha256DigestSchema, + executionPolicyFingerprint: Sha256DigestSchema, + executionAttemptId: IdentifierSchema, + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + executionReceipt: ReasoningExecutionReceiptSchema, + usageEvidence: ReasoningUsageEvidenceSchema, + costEvidence: ReasoningCostEvidenceSchema, + completedAt: IsoTemporalSchema, + resultEnvelopeFingerprint: Sha256DigestSchema, +} as const; + +function validateResultBindings( + value: z.infer, + context: z.RefinementCtx, +): void { + if ( + value.executionReceipt.executionAttemptId !== value.executionAttemptId || + value.executionReceipt.invocationRequestId !== value.invocationRequestId || + value.executionReceipt.invocationRequestFingerprint !== value.invocationRequestFingerprint || + value.executionReceipt.providerCapabilityId !== value.providerCapabilityId || + value.executionReceipt.providerCapabilityFingerprint !== value.providerCapabilityFingerprint || + value.executionReceipt.attemptNumber !== value.attemptNumber || + value.executionReceipt.outcome !== value.outcome || + value.executionReceipt.completedAt !== value.completedAt || + value.usageEvidence.executionAttemptId !== value.executionAttemptId || + value.usageEvidence.attemptNumber !== value.attemptNumber || + value.costEvidence.executionAttemptId !== value.executionAttemptId + ) { + context.addIssue({ + code: "custom", + message: "Result Envelope operational evidence must preserve exact execution bindings", + path: ["executionReceipt"], + }); + } + const outcomeEvidence = + value.outcome === "failed" + ? value.failureEvidence + : value.outcome === "timed-out" + ? value.timeoutEvidence + : value.outcome === "cancelled" + ? value.cancellationEvidence + : null; + if ( + outcomeEvidence !== null && + (outcomeEvidence.executionAttemptId !== value.executionAttemptId || + outcomeEvidence.invocationRequestId !== value.invocationRequestId) + ) { + context.addIssue({ + code: "custom", + message: "Terminal outcome evidence must bind the Result Invocation and Attempt", + path: ["outcome"], + }); + } + if (value.outcome === "failed" && value.failureEvidence.attemptNumber !== value.attemptNumber) { + context.addIssue({ + code: "custom", + message: "Result Failure Evidence must bind the Result Attempt number", + path: ["failureEvidence", "attemptNumber"], + }); + } +} + +const ReasoningResultEnvelopeVariantSchema = z.discriminatedUnion("outcome", [ + z + .object({ + ...ReasoningResultBase, + outcome: z.literal("succeeded"), + outputContent: ReasoningOutputContentSchema, + outputCharacterCount: z.number().int().nonnegative().max(MAX_SAFE_INTEGER), + outputContentFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + ...ReasoningResultBase, + outcome: z.literal("failed"), + failureEvidence: ReasoningFailureEvidenceSchema, + }) + .strict(), + z + .object({ + ...ReasoningResultBase, + outcome: z.literal("timed-out"), + timeoutEvidence: ReasoningTimeoutEvidenceSchema, + }) + .strict(), + z + .object({ + ...ReasoningResultBase, + outcome: z.literal("cancelled"), + cancellationEvidence: ReasoningCancellationEvidenceSchema, + }) + .strict(), +]); + +export const ReasoningResultEnvelopeSchema = DurableCanonicalJsonValueSchema.pipe( + ReasoningResultEnvelopeVariantSchema.superRefine(validateResultBindings), +); + +export const ReasoningAttemptHistoryEntrySchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + executionAttemptId: IdentifierSchema, + attemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + outcome: ReasoningOutcomeStatusSchema, + attemptFingerprint: Sha256DigestSchema, + outcomeFingerprint: Sha256DigestSchema, + }) + .strict(), +); + +export const ReasoningAttemptHistorySummarySchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + attemptCount: z.number().int().positive().max(MAX_SAFE_INTEGER), + finalAttemptNumber: z.number().int().positive().max(MAX_SAFE_INTEGER), + finalOutcome: ReasoningOutcomeStatusSchema, + attempts: z.array(ReasoningAttemptHistoryEntrySchema).min(1), + historyFingerprint: Sha256DigestSchema, + }) + .strict() + .superRefine((value, context) => { + const sequential = value.attempts.every( + (attempt, index) => attempt.attemptNumber === index + 1, + ); + const finalAttempt = value.attempts.at(-1)!; + if ( + !sequential || + new Set(value.attempts.map((attempt) => attempt.executionAttemptId)).size !== + value.attempts.length || + value.attemptCount !== value.attempts.length || + value.finalAttemptNumber !== finalAttempt.attemptNumber || + value.finalOutcome !== finalAttempt.outcome + ) { + context.addIssue({ + code: "custom", + message: + "Attempt history must be unique, sequential, complete, and bind its final outcome", + path: ["attempts"], + }); + } + }), +); + +const FinalizedConsumptionBase = { + schemaVersion: ReasoningContractVersionSchema, + consumptionId: IdentifierSchema, + deliveryReceiptId: IdentifierSchema, + deliveryReceiptFingerprint: Sha256DigestSchema, + deliveryTransactionId: IdentifierSchema, + invocationRequestId: IdentifierSchema, + invocationRequestFingerprint: Sha256DigestSchema, + invocationIdempotencyKey: ReasoningInvocationIdempotencyKeySchema, + providerCapabilityId: IdentifierSchema, + providerCapabilityFingerprint: Sha256DigestSchema, + finalResultEnvelopeId: IdentifierSchema, + finalResultEnvelopeFingerprint: Sha256DigestSchema, + attemptHistorySummary: ReasoningAttemptHistorySummarySchema, + startedAt: IsoTemporalSchema, + completedAt: IsoTemporalSchema, + usageEvidenceFingerprint: Sha256DigestSchema, + costEvidenceFingerprint: Sha256DigestSchema, + executionLedgerTransactionId: IdentifierSchema, + consumptionFingerprint: Sha256DigestSchema, +} as const; + +export const FinalizedReasoningConsumptionEvidenceSchema = DurableCanonicalJsonValueSchema.pipe( + z + .discriminatedUnion("finalOutcome", [ + z.object({ ...FinalizedConsumptionBase, finalOutcome: z.literal("succeeded") }).strict(), + z + .object({ + ...FinalizedConsumptionBase, + finalOutcome: z.literal("failed"), + failureEvidenceFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + ...FinalizedConsumptionBase, + finalOutcome: z.literal("timed-out"), + timeoutEvidenceFingerprint: Sha256DigestSchema, + }) + .strict(), + z + .object({ + ...FinalizedConsumptionBase, + finalOutcome: z.literal("cancelled"), + cancellationEvidenceFingerprint: Sha256DigestSchema, + }) + .strict(), + ]) + .superRefine((value, context) => { + if ( + compareTemporal(value.completedAt, value.startedAt) < 0 || + value.attemptHistorySummary.finalOutcome !== value.finalOutcome + ) { + context.addIssue({ + code: "custom", + message: "Finalized Consumption timing and final Attempt outcome must agree", + path: ["finalOutcome"], + }); + } + }), +); + +export const ReasoningVerificationArtifactTypeSchema = z.enum([ + "cancellation-evidence", + "compatibility-result", + "cost-evidence", + "execution-attempt", + "execution-policy", + "execution-receipt", + "failure-evidence", + "finalized-consumption-evidence", + "invocation-request", + "provider-capability-descriptor", + "provider-outcome", + "reasoning-input", + "result-envelope", + "timeout-evidence", + "usage-evidence", +]); +export const ReasoningVerificationIssueCodeSchema = z.enum([ + "attempt_binding_mismatch", + "attempt_order_invalid", + "budget_exceeded", + "consumer_binding_mismatch", + "context_package_binding_mismatch", + "credential_material_detected", + "delivery_binding_mismatch", + "execution_policy_binding_mismatch", + "fingerprint_mismatch", + "invalid_artifact", + "noncanonical_value", + "outcome_contradiction", + "physical_path_detected", + "provider_capability_binding_mismatch", + "receipt_binding_mismatch", + "unsafe_content", +]); +export const ReasoningVerificationIssueSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + code: ReasoningVerificationIssueCodeSchema, + path: ReasoningLogicalReferenceSchema, + message: ReasoningNonEmptyCanonicalTextSchema, + }) + .strict(), +); +export const ReasoningArtifactVerificationResultSchema = DurableCanonicalJsonValueSchema.pipe( + z + .object({ + schemaVersion: ReasoningContractVersionSchema, + artifactType: ReasoningVerificationArtifactTypeSchema, + status: z.enum(["invalid", "valid"]), + fingerprint: Sha256DigestSchema.nullable(), + issues: z.array(ReasoningVerificationIssueSchema), + }) + .strict() + .superRefine((value, context) => { + if ( + (value.status === "valid") !== + (value.fingerprint !== null && value.issues.length === 0) + ) { + context.addIssue({ + code: "custom", + message: "Verification status, fingerprint, and issues must agree", + path: ["status"], + }); + } + const keys = value.issues.map((issue) => `${issue.code}\0${issue.path}\0${issue.message}`); + requireSortedUnique(keys, context, ["issues"], "Verification issues"); + }), +); + +export type ReasoningInstructionBlock = z.infer; +export type ReasoningConstraintBlock = z.infer; +export type ProviderNeutralReasoningInput = z.infer; +export type ReasoningExecutionPolicy = z.infer; +export type ReasoningProviderCapabilityRequirements = z.infer< + typeof ReasoningProviderCapabilityRequirementsSchema +>; +export type ReasoningProviderCapabilityDescriptor = z.infer< + typeof ReasoningProviderCapabilityDescriptorSchema +>; +export type ReasoningProviderCompatibilityResult = z.infer< + typeof ReasoningProviderCompatibilityResultSchema +>; +export type ReasoningInvocationRequest = z.infer; +export type ReasoningExecutionAttempt = z.infer; +export type ReasoningProviderOutcome = z.infer; +export type ReasoningExecutionReceipt = z.infer; +export type ReasoningUsageEvidence = z.infer; +export type ReasoningCostEvidence = z.infer; +export type ReasoningFailureEvidence = z.infer; +export type ReasoningTimeoutEvidence = z.infer; +export type ReasoningCancellationEvidence = z.infer; +export type ReasoningResultEnvelope = z.infer; +export type ReasoningAttemptHistorySummary = z.infer; +export type FinalizedReasoningConsumptionEvidence = z.infer< + typeof FinalizedReasoningConsumptionEvidenceSchema +>; +export type ReasoningArtifactVerificationResult = z.infer< + typeof ReasoningArtifactVerificationResultSchema +>; diff --git a/packages/knowledge-schema/tests/durable-reasoning-ledger.test.ts b/packages/knowledge-schema/tests/durable-reasoning-ledger.test.ts new file mode 100644 index 0000000..714e879 --- /dev/null +++ b/packages/knowledge-schema/tests/durable-reasoning-ledger.test.ts @@ -0,0 +1,823 @@ +import { describe, expect, it } from "vitest"; + +import { + AppendReasoningExecutionAttemptRequestSchema, + DurableReasoningExecutionAttemptRecordSchema, + DurableReasoningExecutionDerivedIndexSchema, + DurableReasoningProviderOutcomeRecordSchema, + FinalizeReasoningInvocationRequestSchema, + FinalizedReasoningInvocationTransactionSchema, + ReasoningExecutionLedgerDerivedIndexRebuildResultSchema, + ReasoningExecutionLedgerEventSchema, + ReasoningExecutionLedgerHeadExpectationSchema, + ReasoningExecutionLedgerIntegrityVerificationResultSchema, + ReasoningExecutionLedgerIssueCodeSchema, + ReasoningExecutionLedgerIssueSchema, + ReasoningExecutionLedgerRecoveryResultSchema, + ReasoningInvocationFinalizationResultSchema, + ReasoningInvocationOwnershipRecordSchema, + ReasoningInvocationOwnershipResolutionSchema, +} from "../src/index.js"; + +const digest = "a".repeat(64); +const timestamp = "2026-07-29T01:00:00.000Z"; +const completedAt = "2026-07-29T01:00:00.100Z"; + +function attempt() { + return { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + invocationIdempotencyKey: "reasoning:key:0001", + providerCapabilityId: "deterministic-evaluation-provider", + providerCapabilityFingerprint: digest, + executionPolicyFingerprint: digest, + attemptNumber: 1, + startedAt: timestamp, + deadlineAt: "2026-07-29T01:00:05.000Z", + cancellationState: "not-requested" as const, + attemptFingerprint: digest, + }; +} + +function providerOutcome() { + return { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + attemptNumber: 1, + completedAt, + status: "succeeded" as const, + outputContent: { contentType: "canonical-text" as const, text: "Governed evaluation." }, + outputCharacterCount: 20, + outputContentFingerprint: digest, + outcomeFingerprint: digest, + }; +} + +function ownership() { + return { + schemaVersion: "1.0" as const, + recordType: "invocation-ownership" as const, + ownershipId: "ownership-one", + invocationIdempotencyKey: "reasoning:key:0001", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + ownershipStatus: "in-progress" as const, + ownershipSequence: 1, + createdAt: timestamp, + ledgerSequence: 1, + previousAuditFingerprint: "genesis" as const, + committedAt: timestamp, + ownershipFingerprint: digest, + }; +} + +function successResult() { + return { + schemaVersion: "1.0" as const, + resultEnvelopeId: "result-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + invocationIdempotencyKey: "reasoning:key:0001", + deliveryTransactionId: "delivery-transaction-one", + deliveryEnvelopeId: "delivery-envelope", + deliveryEnvelopeFingerprint: digest, + deliveryReceiptId: "delivery-receipt", + deliveryReceiptFingerprint: digest, + contextPackageId: "context-package", + contextPackageFingerprint: digest, + consumerId: "consumer-one", + consumerDescriptorFingerprint: digest, + providerCapabilityId: "deterministic-evaluation-provider", + providerCapabilityFingerprint: digest, + executionPolicyFingerprint: digest, + executionAttemptId: "attempt-one", + attemptNumber: 1, + outcome: "succeeded" as const, + outputContent: { contentType: "canonical-text" as const, text: "Governed evaluation." }, + outputCharacterCount: 20, + outputContentFingerprint: digest, + executionReceipt: { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + providerCapabilityId: "deterministic-evaluation-provider", + providerCapabilityFingerprint: digest, + attemptNumber: 1, + startedAt: timestamp, + completedAt, + outcome: "succeeded" as const, + receiptFingerprint: digest, + }, + usageEvidence: { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + inputCharacterCount: 400, + outputCharacterCount: 20, + instructionBlockCount: 2, + contextPackageObjectCount: 3, + attemptNumber: 1, + durationMilliseconds: 100, + usageFingerprint: digest, + }, + costEvidence: { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + status: "not-applicable" as const, + costFingerprint: digest, + }, + completedAt, + resultEnvelopeFingerprint: digest, + }; +} + +function failureResult() { + const success = successResult(); + const { outputCharacterCount, outputContent, outputContentFingerprint, ...base } = success; + void outputCharacterCount; + void outputContent; + void outputContentFingerprint; + return { + ...base, + outcome: "failed" as const, + executionReceipt: { ...base.executionReceipt, outcome: "failed" as const }, + failureEvidence: { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + failureCategory: "permanent-provider-failure" as const, + reasonCodes: ["permanent_provider_failure" as const], + retryable: false, + sanitizedDetail: "Deterministic permanent failure fixture", + attemptNumber: 1, + failureFingerprint: digest, + }, + }; +} + +function consumption() { + return { + schemaVersion: "1.0" as const, + consumptionId: "consumption-one", + deliveryReceiptId: "delivery-receipt", + deliveryReceiptFingerprint: digest, + deliveryTransactionId: "delivery-transaction-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + invocationIdempotencyKey: "reasoning:key:0001", + providerCapabilityId: "deterministic-evaluation-provider", + providerCapabilityFingerprint: digest, + finalResultEnvelopeId: "result-one", + finalResultEnvelopeFingerprint: digest, + finalOutcome: "succeeded" as const, + attemptHistorySummary: { + attemptCount: 1, + finalAttemptNumber: 1, + finalOutcome: "succeeded" as const, + attempts: [ + { + executionAttemptId: "attempt-one", + attemptNumber: 1, + outcome: "succeeded" as const, + attemptFingerprint: digest, + outcomeFingerprint: digest, + }, + ], + historyFingerprint: digest, + }, + startedAt: timestamp, + completedAt, + usageEvidenceFingerprint: digest, + costEvidenceFingerprint: digest, + executionLedgerTransactionId: "finalization-one", + consumptionFingerprint: digest, + }; +} + +function failedConsumption() { + return { + ...consumption(), + finalOutcome: "failed" as const, + failureEvidenceFingerprint: digest, + attemptHistorySummary: { + ...consumption().attemptHistorySummary, + finalOutcome: "failed" as const, + attempts: [ + { + ...consumption().attemptHistorySummary.attempts[0], + outcome: "failed" as const, + }, + ], + }, + }; +} + +function finalization() { + return { + schemaVersion: "1.0" as const, + recordType: "finalized-invocation-transaction" as const, + transactionId: "finalization-one", + ownershipId: "ownership-one", + invocationIdempotencyKey: "reasoning:key:0001", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + resultEnvelope: successResult(), + consumptionEvidence: consumption(), + ledgerSequence: 4, + previousAuditFingerprint: digest, + committedAt: completedAt, + transactionFingerprint: digest, + }; +} + +function finalizationRequest() { + return { + schemaVersion: "1.0" as const, + expectedLedgerHead: { ledgerSequence: 3, auditFingerprint: digest }, + ownershipId: "ownership-one", + expectedOwnershipStatus: "in-progress" as const, + expectedAttemptCount: 1, + transactionId: "finalization-one", + resultEnvelope: successResult(), + consumptionEvidence: consumption(), + finalizedAt: completedAt, + }; +} + +describe("Durable Reasoning Execution Evidence Ledger contracts", () => { + it("accepts only coherent empty and non-empty expected heads", () => { + expect( + ReasoningExecutionLedgerHeadExpectationSchema.safeParse({ + ledgerSequence: 0, + auditFingerprint: "genesis", + }).success, + ).toBe(true); + expect( + ReasoningExecutionLedgerHeadExpectationSchema.safeParse({ + ledgerSequence: 1, + auditFingerprint: "genesis", + }).success, + ).toBe(false); + }); + + it("accepts immutable Invocation ownership and rejects forged chain positions", () => { + expect(ReasoningInvocationOwnershipRecordSchema.parse(ownership())).toEqual(ownership()); + expect( + ReasoningInvocationOwnershipRecordSchema.safeParse({ + ...ownership(), + ledgerSequence: 2, + }).success, + ).toBe(false); + expect( + ReasoningInvocationOwnershipRecordSchema.safeParse({ + ...ownership(), + ownershipStatus: "finalized", + }).success, + ).toBe(false); + }); + + it("binds durable Attempt and Provider Outcome wrappers to exact artifacts", () => { + const attemptRecord = { + schemaVersion: "1.0", + recordType: "execution-attempt", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + invocationIdempotencyKey: "reasoning:key:0001", + attempt: attempt(), + ledgerSequence: 2, + previousAuditFingerprint: digest, + committedAt: timestamp, + recordFingerprint: digest, + }; + const outcomeRecord = { + schemaVersion: "1.0", + recordType: "provider-outcome", + invocationRequestId: "invocation-one", + executionAttemptId: "attempt-one", + attemptNumber: 1, + outcome: providerOutcome(), + ledgerSequence: 3, + previousAuditFingerprint: digest, + committedAt: completedAt, + recordFingerprint: digest, + }; + expect(DurableReasoningExecutionAttemptRecordSchema.safeParse(attemptRecord).success).toBe( + true, + ); + expect(DurableReasoningProviderOutcomeRecordSchema.safeParse(outcomeRecord).success).toBe(true); + expect( + DurableReasoningExecutionAttemptRecordSchema.safeParse({ + ...attemptRecord, + invocationRequestId: "invocation-two", + }).success, + ).toBe(false); + expect( + DurableReasoningProviderOutcomeRecordSchema.safeParse({ + ...outcomeRecord, + attemptNumber: 2, + }).success, + ).toBe(false); + }); + + it("requires deterministic sequential Attempt append requests", () => { + const request = { + schemaVersion: "1.0", + expectedLedgerHead: { ledgerSequence: 1, auditFingerprint: digest }, + ownershipId: "ownership-one", + expectedOwnershipStatus: "in-progress", + expectedPriorAttemptCount: 0, + attempt: attempt(), + }; + expect(AppendReasoningExecutionAttemptRequestSchema.safeParse(request).success).toBe(true); + expect( + AppendReasoningExecutionAttemptRequestSchema.safeParse({ + ...request, + expectedPriorAttemptCount: 1, + }).success, + ).toBe(false); + }); + + it("accepts an atomic finalization and rejects Result or Consumption substitution", () => { + expect(FinalizedReasoningInvocationTransactionSchema.safeParse(finalization()).success).toBe( + true, + ); + expect( + FinalizedReasoningInvocationTransactionSchema.safeParse({ + ...finalization(), + consumptionEvidence: { + ...consumption(), + finalResultEnvelopeId: "result-two", + }, + }).success, + ).toBe(false); + expect( + FinalizedReasoningInvocationTransactionSchema.safeParse({ + ...finalization(), + resultEnvelope: { ...successResult(), deliveryReceiptId: "receipt-two" }, + }).success, + ).toBe(false); + }); + + it("binds every Finalization Request Result and Consumption coordinate", () => { + const request = finalizationRequest(); + expect(FinalizeReasoningInvocationRequestSchema.safeParse(request).success).toBe(true); + + const mismatchedOutcomeConsumption = { + ...consumption(), + finalOutcome: "failed", + failureEvidenceFingerprint: digest, + attemptHistorySummary: { + ...consumption().attemptHistorySummary, + finalOutcome: "failed", + attempts: [ + { + ...consumption().attemptHistorySummary.attempts[0], + outcome: "failed", + }, + ], + }, + }; + const mutations = [ + { consumptionEvidence: { ...consumption(), invocationRequestId: "invocation-two" } }, + { + consumptionEvidence: { + ...consumption(), + invocationRequestFingerprint: "b".repeat(64), + }, + }, + { consumptionEvidence: { ...consumption(), invocationIdempotencyKey: "reasoning:key:0002" } }, + { consumptionEvidence: { ...consumption(), finalResultEnvelopeId: "result-two" } }, + { + consumptionEvidence: { + ...consumption(), + finalResultEnvelopeFingerprint: "b".repeat(64), + }, + }, + { consumptionEvidence: mismatchedOutcomeConsumption }, + { consumptionEvidence: { ...consumption(), deliveryReceiptId: "delivery-receipt-two" } }, + { + consumptionEvidence: { + ...consumption(), + deliveryReceiptFingerprint: "b".repeat(64), + }, + }, + { + consumptionEvidence: { + ...consumption(), + deliveryTransactionId: "delivery-transaction-two", + }, + }, + { + consumptionEvidence: { + ...consumption(), + providerCapabilityId: "deterministic-evaluation-provider-two", + }, + }, + { + consumptionEvidence: { + ...consumption(), + providerCapabilityFingerprint: "b".repeat(64), + }, + }, + { + consumptionEvidence: { ...consumption(), usageEvidenceFingerprint: "b".repeat(64) }, + }, + { + consumptionEvidence: { ...consumption(), costEvidenceFingerprint: "b".repeat(64) }, + }, + { + consumptionEvidence: { + ...consumption(), + attemptHistorySummary: { + ...consumption().attemptHistorySummary, + attempts: [ + { + ...consumption().attemptHistorySummary.attempts[0], + executionAttemptId: "attempt-two", + }, + ], + }, + }, + }, + ]; + for (const mutation of mutations) { + expect( + FinalizeReasoningInvocationRequestSchema.safeParse({ ...request, ...mutation }).success, + ).toBe(false); + } + + const failedRequest = { + ...request, + resultEnvelope: failureResult(), + consumptionEvidence: failedConsumption(), + }; + expect(FinalizeReasoningInvocationRequestSchema.safeParse(failedRequest).success).toBe(true); + expect( + FinalizeReasoningInvocationRequestSchema.safeParse({ + ...failedRequest, + consumptionEvidence: { + ...failedConsumption(), + failureEvidenceFingerprint: "b".repeat(64), + }, + }).success, + ).toBe(false); + }); + + it("models ownership and finalization replay outcomes without reassignment", () => { + expect( + ReasoningInvocationOwnershipResolutionSchema.safeParse({ + schemaVersion: "1.0", + status: "identical-in-progress", + reasonCode: "invocation_already_in_progress", + ownership: ownership(), + }).success, + ).toBe(true); + expect( + ReasoningInvocationOwnershipResolutionSchema.safeParse({ + schemaVersion: "1.0", + status: "conflict", + reasonCode: "invocation_already_in_progress", + existingInvocationRequestId: "invocation-one", + existingInvocationRequestFingerprint: digest, + }).success, + ).toBe(false); + expect( + ReasoningInvocationFinalizationResultSchema.safeParse({ + schemaVersion: "1.0", + status: "identical-finalization", + finalization: finalization(), + }).success, + ).toBe(true); + const identicalFinalized = { + schemaVersion: "1.0", + status: "identical-finalized", + reasonCode: "invocation_already_finalized", + ownership: ownership(), + finalization: finalization(), + }; + expect(ReasoningInvocationOwnershipResolutionSchema.safeParse(identicalFinalized).success).toBe( + true, + ); + for (const ownershipMutation of [ + { ownershipId: "ownership-two" }, + { invocationIdempotencyKey: "reasoning:key:0002" }, + { invocationRequestId: "invocation-two" }, + { invocationRequestFingerprint: "b".repeat(64) }, + ]) { + expect( + ReasoningInvocationOwnershipResolutionSchema.safeParse({ + ...identicalFinalized, + ownership: { ...ownership(), ...ownershipMutation }, + }).success, + ).toBe(false); + } + }); + + it("rejects accessor-backed Ledger events without invoking accessors", () => { + let accessed = false; + const raw = Object.create(null) as Record; + Object.defineProperty(raw, "eventType", { + enumerable: true, + get() { + accessed = true; + return "invocation-ownership"; + }, + }); + expect(ReasoningExecutionLedgerEventSchema.safeParse(raw).success).toBe(false); + expect(accessed).toBe(false); + }); + + it("rejects accessor-backed exported heads and Ledger Issues without invoking accessors", () => { + let headAccessed = false; + const rawHead = Object.create(null) as Record; + Object.defineProperty(rawHead, "ledgerSequence", { + enumerable: true, + get() { + headAccessed = true; + return 0; + }, + }); + expect(ReasoningExecutionLedgerHeadExpectationSchema.safeParse(rawHead).success).toBe(false); + expect(headAccessed).toBe(false); + + let issueAccessed = false; + const rawIssue = Object.create(null) as Record; + Object.defineProperty(rawIssue, "code", { + enumerable: true, + get() { + issueAccessed = true; + return "invalid_raw_record"; + }, + }); + expect(ReasoningExecutionLedgerIssueSchema.safeParse(rawIssue).success).toBe(false); + expect(issueAccessed).toBe(false); + }); + + it("keeps exported Ledger Issue locations and messages path- and credential-private", () => { + const issue = { + code: "invalid_raw_record", + logicalLocation: "reasoning-ledger/events/1", + message: "The canonical event is invalid", + }; + expect(ReasoningExecutionLedgerIssueSchema.safeParse(issue).success).toBe(true); + expect( + ReasoningExecutionLedgerIssueSchema.safeParse({ + ...issue, + logicalLocation: "/srv/reasoning-ledger/event", + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerIssueSchema.safeParse({ + ...issue, + message: "api_key=exposed-value", + }).success, + ).toBe(false); + }); + + it("rejects Ledger events whose outer and authoritative chain positions differ", () => { + expect( + ReasoningExecutionLedgerEventSchema.safeParse({ + schemaVersion: "1.0", + eventType: "invocation-ownership", + ledgerSequence: 2, + previousAuditFingerprint: digest, + ownership: ownership(), + auditFingerprint: digest, + }).success, + ).toBe(false); + }); + + it("rejects unknown, storage-specific, Provider-specific, and unsupported Ledger fields", () => { + expect( + ReasoningInvocationOwnershipRecordSchema.safeParse({ + ...ownership(), + storagePath: "/tmp/reasoning-ledger", + }).success, + ).toBe(false); + expect( + ReasoningInvocationOwnershipRecordSchema.safeParse({ + ...ownership(), + providerApiKey: "secret", + }).success, + ).toBe(false); + expect( + ReasoningInvocationOwnershipRecordSchema.safeParse({ + ...ownership(), + schemaVersion: "2.0", + }).success, + ).toBe(false); + }); + + it("enforces capacity, ordering, head, and status invariants in Derived Indexes", () => { + const index = { + schemaVersion: "1.0", + retentionPolicyVersion: "bounded-latest-v1", + entryCapacity: 2, + verifiedThroughSequence: 4, + verifiedAuditFingerprint: digest, + invocationEntries: [ + { + invocationIdempotencyKey: "reasoning:key:0001", + ownershipId: "ownership-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + status: "finalized", + finalizationTransactionId: "finalization-one", + }, + ], + attemptEntries: [ + { + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + attemptNumber: 1, + outcomeFingerprint: digest, + }, + ], + resultEntries: [ + { + invocationRequestId: "invocation-one", + resultEnvelopeId: "result-one", + resultEnvelopeFingerprint: digest, + consumptionId: "consumption-one", + }, + ], + indexFingerprint: digest, + }; + expect(DurableReasoningExecutionDerivedIndexSchema.safeParse(index).success).toBe(true); + expect( + DurableReasoningExecutionDerivedIndexSchema.safeParse({ + ...index, + invocationEntries: [ + index.invocationEntries[0], + { + ...index.invocationEntries[0], + invocationIdempotencyKey: "reasoning:key:0000", + }, + ], + }).success, + ).toBe(false); + expect( + DurableReasoningExecutionDerivedIndexSchema.safeParse({ + ...index, + invocationEntries: [{ ...index.invocationEntries[0], status: "in-progress" }], + }).success, + ).toBe(false); + expect( + DurableReasoningExecutionDerivedIndexSchema.safeParse({ + ...index, + verifiedThroughSequence: 0, + }).success, + ).toBe(false); + }); + + it("exposes stable storage-independent issue codes", () => { + expect(ReasoningExecutionLedgerIssueCodeSchema.parse("attempt_order_invalid")).toBe( + "attempt_order_invalid", + ); + expect( + ReasoningExecutionLedgerIssueCodeSchema.safeParse("sql_constraint_failure").success, + ).toBe(false); + }); + + it("accepts coherent Recovery and Integrity success results", () => { + const recovery = { + schemaVersion: "1.0", + ledgerContractVersion: "1.0", + status: "recovered", + invocationOwnershipCount: 1, + executionAttemptCount: 1, + providerOutcomeCount: 1, + finalizedInvocationCount: 1, + finalizedConsumptionCount: 1, + integrityCheckpointCount: 0, + lastCommittedLedgerSequence: 4, + lastAuditFingerprint: digest, + derivedIndexStatus: "current", + executionEvidenceFingerprint: digest, + errors: [], + }; + const integrity = { + schemaVersion: "1.0", + status: "valid", + verifiedEventCount: 4, + verifiedInvocationCount: 1, + verifiedAttemptCount: 1, + verifiedOutcomeCount: 1, + verifiedFinalizationCount: 1, + verifiedThroughSequence: 4, + lastAuditFingerprint: digest, + executionEvidenceFingerprint: digest, + derivedIndexStatus: "current", + issues: [], + }; + expect(ReasoningExecutionLedgerRecoveryResultSchema.safeParse(recovery).success).toBe(true); + expect( + ReasoningExecutionLedgerIntegrityVerificationResultSchema.safeParse(integrity).success, + ).toBe(true); + expect( + ReasoningExecutionLedgerRecoveryResultSchema.safeParse({ + ...recovery, + status: "failed", + executionEvidenceFingerprint: null, + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerRecoveryResultSchema.safeParse({ + ...recovery, + finalizedInvocationCount: 2, + finalizedConsumptionCount: 2, + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerRecoveryResultSchema.safeParse({ + ...recovery, + executionAttemptCount: 5, + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerRecoveryResultSchema.safeParse({ + ...recovery, + executionAttemptCount: 2, + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerRecoveryResultSchema.safeParse({ + ...recovery, + integrityCheckpointCount: 0, + finalizedInvocationCount: 0, + finalizedConsumptionCount: 0, + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerIntegrityVerificationResultSchema.safeParse({ + ...integrity, + verifiedFinalizationCount: 2, + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerIntegrityVerificationResultSchema.safeParse({ + ...integrity, + verifiedAttemptCount: 5, + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerIntegrityVerificationResultSchema.safeParse({ + ...integrity, + verifiedAttemptCount: 2, + }).success, + ).toBe(false); + expect( + ReasoningExecutionLedgerIntegrityVerificationResultSchema.safeParse({ + ...integrity, + verifiedFinalizationCount: 0, + }).success, + ).toBe(true); + expect( + ReasoningExecutionLedgerRecoveryResultSchema.safeParse({ + ...recovery, + executionAttemptCount: 2, + providerOutcomeCount: 2, + lastCommittedLedgerSequence: 6, + }).success, + ).toBe(true); + expect( + ReasoningExecutionLedgerIntegrityVerificationResultSchema.safeParse({ + ...integrity, + verifiedEventCount: 6, + verifiedAttemptCount: 2, + verifiedOutcomeCount: 2, + verifiedThroughSequence: 6, + }).success, + ).toBe(true); + }); + + it("requires Derived Index rebuild failures to explain a missing fingerprint", () => { + expect( + ReasoningExecutionLedgerDerivedIndexRebuildResultSchema.safeParse({ + schemaVersion: "1.0", + status: "rebuilt", + verifiedThroughSequence: 4, + indexFingerprint: digest, + invocationEntryCount: 1, + attemptEntryCount: 1, + resultEntryCount: 1, + issues: [], + }).success, + ).toBe(true); + expect( + ReasoningExecutionLedgerDerivedIndexRebuildResultSchema.safeParse({ + schemaVersion: "1.0", + status: "failed", + verifiedThroughSequence: 0, + indexFingerprint: null, + invocationEntryCount: 0, + attemptEntryCount: 0, + resultEntryCount: 0, + issues: [], + }).success, + ).toBe(false); + }); +}); diff --git a/packages/knowledge-schema/tests/reasoning.test.ts b/packages/knowledge-schema/tests/reasoning.test.ts new file mode 100644 index 0000000..82a1d1e --- /dev/null +++ b/packages/knowledge-schema/tests/reasoning.test.ts @@ -0,0 +1,854 @@ +import { describe, expect, it } from "vitest"; + +import { + FinalizedReasoningConsumptionEvidenceSchema, + ProviderNeutralReasoningInputSchema, + ReasoningArtifactVerificationResultSchema, + ReasoningCanonicalTextSchema, + ReasoningCancellationEvidenceSchema, + ReasoningCostEvidenceSchema, + ReasoningExecutionAttemptSchema, + ReasoningExecutionPolicySchema, + ReasoningFailureEvidenceSchema, + ReasoningInvocationRequestSchema, + ReasoningProviderCapabilityDescriptorSchema, + ReasoningProviderCompatibilityResultSchema, + ReasoningProviderOutcomeSchema, + ReasoningResultEnvelopeSchema, + ReasoningTimeoutEvidenceSchema, + ReasoningUsageEvidenceSchema, + ReasoningVerificationIssueSchema, +} from "../src/index.js"; + +const digest = "a".repeat(64); +const timestamp = "2026-07-29T01:00:00.000Z"; + +function reasoningInput() { + return { + schemaVersion: "1.0" as const, + contentType: "provider-neutral-instruction-blocks-v1" as const, + instructionBlocks: [ + { + schemaVersion: "1.0" as const, + blockId: "context-reference", + blockType: "context-reference" as const, + contentType: "canonical-text" as const, + text: "Use only the governed Context Package referenced by this Invocation.", + priority: 0, + sourceClassification: "delivered-context" as const, + blockFingerprint: digest, + }, + { + schemaVersion: "1.0" as const, + blockId: "task-instruction", + blockType: "task-instruction" as const, + contentType: "canonical-text" as const, + text: "Produce a concise governed evaluation.", + priority: 1, + sourceClassification: "request-author" as const, + blockFingerprint: digest, + }, + ], + contextReference: { + contextPackageId: "context-package", + contextPackageFingerprint: digest, + deliveryEnvelopeId: "delivery-envelope", + deliveryEnvelopeFingerprint: digest, + }, + outputRequirements: { + contentType: "canonical-text" as const, + maxCharacters: 2_000, + requireNonEmpty: true, + }, + constraintBlocks: [], + inputFingerprint: digest, + }; +} + +function executionPolicy() { + return { + schemaVersion: "1.0" as const, + maxInputCharacters: 10_000, + maxOutputCharacters: 2_000, + timeoutMilliseconds: 5_000, + cancellationMode: "cooperative-cancellation" as const, + retryMode: "retry-deterministic-transient-failure" as const, + maxAttemptCount: 2, + deterministicModeRequired: true, + usageEvidenceRequired: true, + costEvidenceRequired: true, + failureEvidenceRequired: true, + resultPersistenceRequired: true, + evaluatedAt: timestamp, + policyFingerprint: digest, + }; +} + +function capabilityRequirements() { + return { + schemaVersion: "1.0" as const, + acceptedProviderClasses: ["deterministic-fake-provider" as const], + requiredInputContentTypes: ["provider-neutral-instruction-blocks-v1" as const], + requiredOutputContentType: "canonical-text" as const, + deterministicModeRequired: true, + usageEvidenceRequired: true, + costEvidenceRequired: true, + failureEvidenceRequired: true, + resultEnvelopeVersion: "1.0" as const, + requirementsFingerprint: digest, + }; +} + +function invocationRequest() { + return { + schemaVersion: "1.0" as const, + invocationRequestId: "invocation-one", + deliveryTransactionId: "delivery-transaction-one", + deliveryEnvelopeVersion: "1.0" as const, + deliveryEnvelopeId: "delivery-envelope", + deliveryEnvelopeFingerprint: digest, + deliveryReceiptId: "delivery-receipt", + deliveryReceiptFingerprint: digest, + contextPackageId: "context-package", + contextPackageFingerprint: digest, + activeSnapshotBinding: { + activeSnapshotId: "snapshot-one", + activeContentFingerprint: digest, + activeManifestFingerprint: digest, + sourceManifestReference: "knowledge/migration-manifest", + repositorySnapshotId: "snapshot-one", + repositoryContentFingerprint: digest, + }, + registryIntegrityBinding: { + registrySchemaVersion: "1.0" as const, + integrityFingerprint: digest, + verifiedRecordCount: 3, + verifiedThroughSequence: 3, + recoveredActiveSnapshotId: "snapshot-one", + }, + consumerId: "consumer-one", + consumerDescriptorFingerprint: digest, + policyDecisionFingerprint: digest, + purpose: "Evaluate the delivered Context Package", + capabilityRequirements: capabilityRequirements(), + reasoningInput: reasoningInput(), + executionPolicy: executionPolicy(), + idempotencyKey: "reasoning:key:0001", + requestActor: { actorId: "evaluation-runner", actorType: "service" as const }, + reason: "Verify provider-neutral reasoning contracts", + requestedAt: timestamp, + requestFingerprint: digest, + }; +} + +function capabilityDescriptor() { + return { + schemaVersion: "1.0" as const, + providerCapabilityId: "deterministic-evaluation-provider", + providerClass: "deterministic-fake-provider" as const, + acceptedInvocationRequestVersions: ["1.0" as const], + acceptedDeliveryEnvelopeVersions: ["1.0" as const], + acceptedInputContentTypes: ["provider-neutral-instruction-blocks-v1" as const], + acceptedOutputContentTypes: ["canonical-json" as const, "canonical-text" as const], + maxInputCharacters: 20_000, + maxOutputCharacters: 4_000, + minTimeoutMilliseconds: 100, + maxTimeoutMilliseconds: 10_000, + supportedCancellationModes: ["cooperative-cancellation" as const, "not-cancellable" as const], + supportedRetryModes: ["no-retry" as const, "retry-deterministic-transient-failure" as const], + supportsDeterministicExecution: true, + supportsUsageEvidence: true, + supportsCostEvidence: true, + supportsFailureEvidence: true, + supportedResultEnvelopeVersions: ["1.0" as const], + descriptorFingerprint: digest, + }; +} + +function executionAttempt() { + return { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + invocationIdempotencyKey: "reasoning:key:0001", + providerCapabilityId: "deterministic-evaluation-provider", + providerCapabilityFingerprint: digest, + executionPolicyFingerprint: digest, + attemptNumber: 1, + startedAt: timestamp, + deadlineAt: "2026-07-29T01:00:05.000Z", + cancellationState: "not-requested" as const, + attemptFingerprint: digest, + }; +} + +function usageEvidence() { + return { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + inputCharacterCount: 400, + outputCharacterCount: 20, + instructionBlockCount: 2, + contextPackageObjectCount: 3, + attemptNumber: 1, + durationMilliseconds: 100, + usageFingerprint: digest, + }; +} + +function costEvidence() { + return { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + status: "not-applicable" as const, + costFingerprint: digest, + }; +} + +function successResult() { + return { + schemaVersion: "1.0" as const, + resultEnvelopeId: "result-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + invocationIdempotencyKey: "reasoning:key:0001", + deliveryTransactionId: "delivery-transaction-one", + deliveryEnvelopeId: "delivery-envelope", + deliveryEnvelopeFingerprint: digest, + deliveryReceiptId: "delivery-receipt", + deliveryReceiptFingerprint: digest, + contextPackageId: "context-package", + contextPackageFingerprint: digest, + consumerId: "consumer-one", + consumerDescriptorFingerprint: digest, + providerCapabilityId: "deterministic-evaluation-provider", + providerCapabilityFingerprint: digest, + executionPolicyFingerprint: digest, + executionAttemptId: "attempt-one", + attemptNumber: 1, + outcome: "succeeded" as const, + outputContent: { contentType: "canonical-text" as const, text: "Governed evaluation." }, + outputCharacterCount: 20, + outputContentFingerprint: digest, + executionReceipt: { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + providerCapabilityId: "deterministic-evaluation-provider", + providerCapabilityFingerprint: digest, + attemptNumber: 1, + startedAt: timestamp, + completedAt: "2026-07-29T01:00:00.100Z", + outcome: "succeeded" as const, + receiptFingerprint: digest, + }, + usageEvidence: usageEvidence(), + costEvidence: costEvidence(), + completedAt: "2026-07-29T01:00:00.100Z", + resultEnvelopeFingerprint: digest, + }; +} + +function failureResult() { + const success = successResult(); + const { outputCharacterCount, outputContent, outputContentFingerprint, ...base } = success; + void outputCharacterCount; + void outputContent; + void outputContentFingerprint; + return { + ...base, + outcome: "failed" as const, + executionReceipt: { ...base.executionReceipt, outcome: "failed" as const }, + failureEvidence: { + schemaVersion: "1.0" as const, + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + failureCategory: "permanent-provider-failure" as const, + reasonCodes: ["permanent_provider_failure" as const], + retryable: false, + sanitizedDetail: "Deterministic permanent failure fixture", + attemptNumber: 1, + failureFingerprint: digest, + }, + }; +} + +describe("Milestone 13 provider-neutral Reasoning contracts", () => { + it("accepts the strict canonical Input, Policy, Capability, and Invocation shapes", () => { + expect(ProviderNeutralReasoningInputSchema.parse(reasoningInput())).toEqual(reasoningInput()); + expect(ReasoningExecutionPolicySchema.parse(executionPolicy())).toEqual(executionPolicy()); + expect(ReasoningProviderCapabilityDescriptorSchema.parse(capabilityDescriptor())).toEqual( + capabilityDescriptor(), + ); + expect(ReasoningInvocationRequestSchema.parse(invocationRequest())).toEqual( + invocationRequest(), + ); + }); + + it("rejects unsupported versions, unknown fields, explicit undefined, and unsorted blocks", () => { + expect( + ProviderNeutralReasoningInputSchema.safeParse({ ...reasoningInput(), schemaVersion: "2.0" }) + .success, + ).toBe(false); + expect( + ProviderNeutralReasoningInputSchema.safeParse({ ...reasoningInput(), model: "production" }) + .success, + ).toBe(false); + expect( + ProviderNeutralReasoningInputSchema.safeParse({ + ...reasoningInput(), + evaluationMetadata: undefined, + }).success, + ).toBe(false); + expect( + ProviderNeutralReasoningInputSchema.safeParse({ + ...reasoningInput(), + instructionBlocks: [...reasoningInput().instructionBlocks].reverse(), + }).success, + ).toBe(false); + expect( + ReasoningInvocationRequestSchema.safeParse({ + ...invocationRequest(), + invocationRequestId: " invocation-one ", + }).success, + ).toBe(false); + }); + + it("rejects duplicate governed arrays and missing structural Instruction Blocks", () => { + const input = reasoningInput(); + expect( + ProviderNeutralReasoningInputSchema.safeParse({ + ...input, + instructionBlocks: [input.instructionBlocks[0], input.instructionBlocks[0]], + }).success, + ).toBe(false); + expect( + ProviderNeutralReasoningInputSchema.safeParse({ + ...input, + instructionBlocks: [input.instructionBlocks[1]], + }).success, + ).toBe(false); + expect( + ReasoningProviderCapabilityDescriptorSchema.safeParse({ + ...capabilityDescriptor(), + acceptedInvocationRequestVersions: ["1.0", "1.0"], + }).success, + ).toBe(false); + }); + + it("rejects noncanonical text, physical paths, and credential-like material", () => { + const input = reasoningInput(); + expect( + ProviderNeutralReasoningInputSchema.safeParse({ + ...input, + instructionBlocks: [ + input.instructionBlocks[0], + { ...input.instructionBlocks[1], text: "Use /Users/example/private/data" }, + ], + }).success, + ).toBe(false); + expect( + ProviderNeutralReasoningInputSchema.safeParse({ + ...input, + instructionBlocks: [ + input.instructionBlocks[0], + { ...input.instructionBlocks[1], text: "api_key=super-secret-value" }, + ], + }).success, + ).toBe(false); + expect( + ProviderNeutralReasoningInputSchema.safeParse({ + ...input, + instructionBlocks: [ + input.instructionBlocks[0], + { ...input.instructionBlocks[1], text: "noncanonical\r\ntext" }, + ], + }).success, + ).toBe(false); + for (const unsafeText of [ + "Inspect (/Users/example/private/data).", + "Inspect /srv/founderos/runtime.", + "Inspect /usr/local/bin/runtime.", + "Inspect /workspace/private/data.", + "Inspect C:\\private\\runtime.", + "Inspect C:/private/runtime.", + "Inspect \\\\server\\share\\runtime.", + "Inspect file:///private/runtime.", + ]) { + expect(ReasoningCanonicalTextSchema.safeParse(unsafeText).success).toBe(false); + } + expect( + ReasoningCanonicalTextSchema.safeParse("Compare revenue/cost ratios using logical evidence.") + .success, + ).toBe(true); + }); + + it("rejects accessor-backed artifacts without executing accessors", () => { + let accessed = false; + const raw = Object.create(null) as Record; + Object.defineProperty(raw, "schemaVersion", { + enumerable: true, + get() { + accessed = true; + return "1.0"; + }, + }); + expect(ReasoningInvocationRequestSchema.safeParse(raw).success).toBe(false); + expect(accessed).toBe(false); + }); + + it.each([ + ["no-retry with two Attempts", { retryMode: "no-retry", maxAttemptCount: 2 }], + ["retry with one Attempt", { retryMode: "retry-until-attempt-limit", maxAttemptCount: 1 }], + [ + "deterministic retry without deterministic execution", + { retryMode: "retry-deterministic-transient-failure", deterministicModeRequired: false }, + ], + ["unpersisted Result", { resultPersistenceRequired: false }], + ])("rejects contradictory Execution Policy: %s", (_name, mutation) => { + expect( + ReasoningExecutionPolicySchema.safeParse({ ...executionPolicy(), ...mutation }).success, + ).toBe(false); + }); + + it("accepts every stable Policy mode in a consistent shape", () => { + expect( + ReasoningExecutionPolicySchema.safeParse({ + ...executionPolicy(), + cancellationMode: "not-cancellable", + retryMode: "no-retry", + maxAttemptCount: 1, + }).success, + ).toBe(true); + expect( + ReasoningExecutionPolicySchema.safeParse({ + ...executionPolicy(), + cancellationMode: "cancel-before-execution", + retryMode: "retry-until-attempt-limit", + }).success, + ).toBe(true); + expect( + ReasoningExecutionPolicySchema.safeParse({ + ...executionPolicy(), + cancellationMode: "deadline-cancellation", + retryMode: "evaluation-only-retry", + }).success, + ).toBe(true); + }); + + it("rejects contradictory Provider Capability limits and deterministic claims", () => { + expect( + ReasoningProviderCapabilityDescriptorSchema.safeParse({ + ...capabilityDescriptor(), + minTimeoutMilliseconds: 20_000, + }).success, + ).toBe(false); + expect( + ReasoningProviderCapabilityDescriptorSchema.safeParse({ + ...capabilityDescriptor(), + supportsDeterministicExecution: false, + }).success, + ).toBe(false); + expect( + ReasoningProviderCapabilityDescriptorSchema.safeParse({ + ...capabilityDescriptor(), + supportedRetryModes: ["evaluation-only-retry", "no-retry"], + supportsDeterministicExecution: false, + }).success, + ).toBe(false); + }); + + it("requires exact Request Input, Policy, and Capability-requirement bindings", () => { + expect( + ReasoningInvocationRequestSchema.safeParse({ + ...invocationRequest(), + contextPackageFingerprint: "b".repeat(64), + }).success, + ).toBe(false); + expect( + ReasoningInvocationRequestSchema.safeParse({ + ...invocationRequest(), + capabilityRequirements: { + ...capabilityRequirements(), + costEvidenceRequired: false, + }, + }).success, + ).toBe(false); + expect( + ReasoningInvocationRequestSchema.safeParse({ + ...invocationRequest(), + providerConfig: { endpoint: "https://provider.example" }, + }).success, + ).toBe(false); + }); + + it("enforces stable compatibility status, ordered reasons, and mismatch evidence", () => { + const compatible = { + schemaVersion: "1.0", + status: "compatible", + reasonCodes: ["compatible"], + mismatchedFields: [], + invocationRequestFingerprint: digest, + reasoningInputFingerprint: digest, + executionPolicyFingerprint: digest, + providerCapabilityFingerprint: digest, + compatibilityFingerprint: digest, + }; + expect(ReasoningProviderCompatibilityResultSchema.safeParse(compatible).success).toBe(true); + expect( + ReasoningProviderCompatibilityResultSchema.safeParse({ + ...compatible, + status: "incompatible", + }).success, + ).toBe(false); + expect( + ReasoningProviderCompatibilityResultSchema.safeParse({ + ...compatible, + status: "incompatible", + reasonCodes: ["timeout_out_of_range", "input_budget_exceeded"], + mismatchedFields: ["timeoutMilliseconds", "inputCharacters"], + }).success, + ).toBe(false); + expect( + ReasoningProviderCompatibilityResultSchema.safeParse({ + ...compatible, + status: "incompatible", + reasonCodes: ["input_budget_exceeded", "timeout_out_of_range"], + mismatchedFields: ["inputCharacters", "timeoutMilliseconds"], + }).success, + ).toBe(true); + expect( + ReasoningProviderCompatibilityResultSchema.safeParse({ + ...compatible, + status: "incompatible", + reasonCodes: ["input_budget_exceeded"], + mismatchedFields: ["timeoutMilliseconds"], + }).success, + ).toBe(false); + }); + + it("enforces first and later immutable Attempt structure", () => { + expect(ReasoningExecutionAttemptSchema.parse(executionAttempt())).toEqual(executionAttempt()); + expect( + ReasoningExecutionAttemptSchema.safeParse({ + ...executionAttempt(), + previousExecutionAttemptId: "attempt-zero", + }).success, + ).toBe(false); + expect( + ReasoningExecutionAttemptSchema.safeParse({ + ...executionAttempt(), + executionAttemptId: "attempt-two", + attemptNumber: 2, + }).success, + ).toBe(false); + expect( + ReasoningExecutionAttemptSchema.safeParse({ + ...executionAttempt(), + deadlineAt: timestamp, + }).success, + ).toBe(false); + expect( + ReasoningExecutionAttemptSchema.safeParse({ + ...executionAttempt(), + cancellationState: "requested-cooperatively", + }).success, + ).toBe(false); + expect( + ReasoningExecutionAttemptSchema.safeParse({ + ...executionAttempt(), + cancellationState: "requested-cooperatively", + cancellationAuthorityReference: "authority/schema-cancellation", + cancellationRequestedAt: "2026-07-29T01:00:00.010Z", + cancellationObservedAt: "2026-07-29T01:00:00.050Z", + }).success, + ).toBe(true); + expect( + ReasoningExecutionAttemptSchema.safeParse({ + ...executionAttempt(), + cancellationAuthorityReference: "authority/unrequested-cancellation", + cancellationRequestedAt: "2026-07-29T01:00:00.010Z", + cancellationObservedAt: "2026-07-29T01:00:00.050Z", + }).success, + ).toBe(false); + }); + + it("accepts strict usage and cost evidence and rejects forged combinations", () => { + expect(ReasoningUsageEvidenceSchema.parse(usageEvidence())).toEqual(usageEvidence()); + expect(ReasoningCostEvidenceSchema.parse(costEvidence())).toEqual(costEvidence()); + expect( + ReasoningUsageEvidenceSchema.safeParse({ + ...usageEvidence(), + estimatedInputUnits: 100, + }).success, + ).toBe(false); + expect( + ReasoningCostEvidenceSchema.safeParse({ + ...costEvidence(), + currencyCode: "USD", + amountMinorUnits: 0, + }).success, + ).toBe(false); + }); + + it("validates stable Failure, Timeout, and Cancellation evidence semantics", () => { + const failure = { + schemaVersion: "1.0", + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + failureCategory: "transient-provider-failure", + reasonCodes: ["transient_provider_failure"], + retryable: true, + sanitizedDetail: "Deterministic transient failure fixture", + attemptNumber: 1, + failureFingerprint: digest, + }; + const timeout = { + schemaVersion: "1.0", + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + configuredTimeoutMilliseconds: 5_000, + attemptStartedAt: timestamp, + deadlineAt: "2026-07-29T01:00:05.000Z", + elapsedMilliseconds: 5_000, + timeoutPhase: "during-execution", + reasonCode: "execution_timeout", + timeoutFingerprint: digest, + }; + const cancellation = { + schemaVersion: "1.0", + invocationRequestId: "invocation-one", + executionAttemptId: "attempt-one", + cancellationMode: "cooperative-cancellation", + cancellationPhase: "cooperative-execution", + cancellationAuthorityReference: "governance/cancellation/evaluation", + requestedAt: timestamp, + observedAt: timestamp, + reasonCode: "cancelled_cooperatively", + cancellationFingerprint: digest, + }; + expect(ReasoningFailureEvidenceSchema.safeParse(failure).success).toBe(true); + expect(ReasoningTimeoutEvidenceSchema.safeParse(timeout).success).toBe(true); + expect(ReasoningCancellationEvidenceSchema.safeParse(cancellation).success).toBe(true); + expect(ReasoningFailureEvidenceSchema.safeParse({ ...failure, retryable: false }).success).toBe( + false, + ); + expect( + ReasoningFailureEvidenceSchema.safeParse({ + ...failure, + failureCategory: "permanent-provider-failure", + retryable: false, + }).success, + ).toBe(false); + expect( + ReasoningTimeoutEvidenceSchema.safeParse({ ...timeout, elapsedMilliseconds: 4_999 }).success, + ).toBe(false); + expect( + ReasoningCancellationEvidenceSchema.safeParse({ + ...cancellation, + cancellationPhase: "deadline", + }).success, + ).toBe(false); + }); + + it("uses discriminated Provider Outcomes to reject contradictory structures", () => { + const outcome = { + schemaVersion: "1.0", + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + attemptNumber: 1, + completedAt: "2026-07-29T01:00:00.100Z", + status: "succeeded", + outputContent: { contentType: "canonical-text", text: "Governed evaluation." }, + outputCharacterCount: 20, + outputContentFingerprint: digest, + outcomeFingerprint: digest, + }; + expect(ReasoningProviderOutcomeSchema.safeParse(outcome).success).toBe(true); + expect(ReasoningProviderOutcomeSchema.safeParse({ ...outcome, status: "failed" }).success).toBe( + false, + ); + expect( + ReasoningProviderOutcomeSchema.safeParse({ + schemaVersion: "1.0", + executionAttemptId: "attempt-one", + invocationRequestId: "invocation-one", + attemptNumber: 1, + completedAt: "2026-07-29T01:00:00.100Z", + status: "failed", + failureEvidence: { + schemaVersion: "1.0", + executionAttemptId: "attempt-two", + invocationRequestId: "invocation-one", + failureCategory: "transient-provider-failure", + reasonCodes: ["transient_provider_failure"], + retryable: true, + sanitizedDetail: "Deterministic transient failure fixture", + attemptNumber: 1, + failureFingerprint: digest, + }, + outcomeFingerprint: digest, + }).success, + ).toBe(false); + expect( + ReasoningProviderOutcomeSchema.safeParse({ + ...outcome, + outputContent: { + contentType: "canonical-json", + value: { nested: "password=exposed-value" }, + }, + }).success, + ).toBe(false); + for (const credentialKey of ["apiKey", "api_key", "api-key", "Api_kEy"]) { + expect( + ReasoningProviderOutcomeSchema.safeParse({ + ...outcome, + outputContent: { + contentType: "canonical-json", + value: { nested: { [credentialKey]: "fixture-secret-value" } }, + }, + }).success, + ).toBe(false); + } + for (const credentialValue of [ + "sk_live_0123456789", + "ghp_0123456789abcdef", + "xoxb-0123456789-secret", + "-----BEGIN PRIVATE KEY-----", + ]) { + expect( + ReasoningProviderOutcomeSchema.safeParse({ + ...outcome, + outputContent: { + contentType: "canonical-json", + value: { nested: { opaqueValue: credentialValue } }, + }, + }).success, + ).toBe(false); + } + }); + + it("accepts exact success Results and rejects outcome or binding contradictions", () => { + expect(ReasoningResultEnvelopeSchema.parse(successResult())).toEqual(successResult()); + expect(ReasoningResultEnvelopeSchema.parse(failureResult())).toEqual(failureResult()); + expect( + ReasoningResultEnvelopeSchema.safeParse({ + ...successResult(), + failureEvidence: { + schemaVersion: "1.0", + executionAttemptId: "attempt-one", + }, + }).success, + ).toBe(false); + expect( + ReasoningResultEnvelopeSchema.safeParse({ + ...successResult(), + executionReceipt: { ...successResult().executionReceipt, outcome: "failed" }, + }).success, + ).toBe(false); + expect( + ReasoningResultEnvelopeSchema.safeParse({ + ...successResult(), + usageEvidence: { ...usageEvidence(), executionAttemptId: "attempt-two" }, + }).success, + ).toBe(false); + expect( + ReasoningResultEnvelopeSchema.safeParse({ + ...failureResult(), + failureEvidence: { ...failureResult().failureEvidence, attemptNumber: 2 }, + }).success, + ).toBe(false); + }); + + it("accepts canonical finalized Consumption evidence and enforces final Attempt binding", () => { + const consumption = { + schemaVersion: "1.0", + consumptionId: "consumption-one", + deliveryReceiptId: "delivery-receipt", + deliveryReceiptFingerprint: digest, + deliveryTransactionId: "delivery-transaction-one", + invocationRequestId: "invocation-one", + invocationRequestFingerprint: digest, + invocationIdempotencyKey: "reasoning:key:0001", + providerCapabilityId: "deterministic-evaluation-provider", + providerCapabilityFingerprint: digest, + finalResultEnvelopeId: "result-one", + finalResultEnvelopeFingerprint: digest, + finalOutcome: "succeeded", + attemptHistorySummary: { + attemptCount: 1, + finalAttemptNumber: 1, + finalOutcome: "succeeded", + attempts: [ + { + executionAttemptId: "attempt-one", + attemptNumber: 1, + outcome: "succeeded", + attemptFingerprint: digest, + outcomeFingerprint: digest, + }, + ], + historyFingerprint: digest, + }, + startedAt: timestamp, + completedAt: "2026-07-29T01:00:00.100Z", + usageEvidenceFingerprint: digest, + costEvidenceFingerprint: digest, + executionLedgerTransactionId: "finalization-one", + consumptionFingerprint: digest, + }; + expect(FinalizedReasoningConsumptionEvidenceSchema.safeParse(consumption).success).toBe(true); + expect( + FinalizedReasoningConsumptionEvidenceSchema.safeParse({ + ...consumption, + finalOutcome: "failed", + }).success, + ).toBe(false); + expect( + FinalizedReasoningConsumptionEvidenceSchema.safeParse({ + ...consumption, + attemptHistorySummary: { + ...consumption.attemptHistorySummary, + attemptCount: 2, + }, + }).success, + ).toBe(false); + }); + + it("enforces canonical verification result status and sorted issues", () => { + expect( + ReasoningArtifactVerificationResultSchema.safeParse({ + schemaVersion: "1.0", + artifactType: "result-envelope", + status: "valid", + fingerprint: digest, + issues: [], + }).success, + ).toBe(true); + expect( + ReasoningArtifactVerificationResultSchema.safeParse({ + schemaVersion: "1.0", + artifactType: "result-envelope", + status: "invalid", + fingerprint: digest, + issues: [], + }).success, + ).toBe(false); + }); + + it("rejects accessor-backed exported Verification Issues without executing accessors", () => { + let accessed = false; + const raw = Object.create(null) as Record; + Object.defineProperty(raw, "code", { + enumerable: true, + get() { + accessed = true; + return "invalid_artifact"; + }, + }); + expect(ReasoningVerificationIssueSchema.safeParse(raw).success).toBe(false); + expect(accessed).toBe(false); + }); +}); diff --git a/services/knowledge-engine/README.md b/services/knowledge-engine/README.md index ea2bbf4..a732484 100644 --- a/services/knowledge-engine/README.md +++ b/services/knowledge-engine/README.md @@ -156,6 +156,38 @@ const result = await ledger.commitVerifiedOriginalDelivery({ Milestone 12 does not invoke a provider or LLM, execute prompts, run Agents or Hermes, call MCP, implement authentication or authorization, add semantic retrieval, or introduce a database. +## Milestone 13 governed reasoning invocation + +`invokeGovernedReasoning` is the only public execution path. It accepts an exact Milestone 12 transaction identity and the Durable Delivery Ledger, independently recovers and verifies that Ledger, resolves the authoritative transaction, and verifies the Request registration, permanent idempotency owner, Envelope, Acknowledgment, Receipt, Context Package, Consumer, Policy, Freshness, Active Snapshot, and Registry bindings before accepting an Invocation. It then verifies provider-neutral input and policy fingerprints, performs deterministic capability matching, registers Invocation ownership, appends immutable ordered Attempts and Outcomes, independently verifies the terminal Result Envelope, and atomically finalizes Consumption Evidence. + +Milestone 13 instantiates exactly one executor: a deterministic fake provider. Its explicit fixture modes cover structured and empty success, transient and permanent failure, timeout, three cancellation phases, output overflow, malformed and contradictory outcomes, and physical-path or credential-bearing output. The adapter has no Repository, corpus, environment, credential, network, random, implicit-clock, tool, Agent, Hermes, or MCP dependency. Unsafe or malformed output is normalized into sanitized failure evidence before persistence. + +`openLocalFileGovernedReasoningExecutionEvidence` opens the local append-only execution-evidence runtime. Its public value exposes only verified reads, recovery, integrity verification, and derived-index rebuild; ownership registration, Attempt append, Outcome append, and finalization remain inaccessible outside the governed Invocation facade. The ownership envelope commits the exact Invocation Request, selected Provider Capability, and delivered Context Package object count under a separate rolling authority fingerprint in the atomic head. Result construction, finalization, recovery, and integrity verification independently reconstruct Receipt, Usage, deterministic-fake Cost, complete Attempt/Outcome history, full execution span, transaction identity, and terminal evidence from that authority. The complete explicit Attempt schedule is validated before ownership. Deadline and cancellation signals are execution controls with deterministic precedence: cancellation observed before execution wins first, explicit deadline cancellation wins at the deadline, an expired execution deadline then wins over cooperative cancellation, and cooperative cancellation applies only while the deadline remains live. An observed terminal control cannot become success, and pre-execution cancellation skips Provider execution. Authoritative events use expected-head compare-and-swap, a single-writer lock, fingerprinted atomic commit markers, immutable event envelopes, file sync, and containing-directory sync. The adapter rejects accessor-backed options, symlinked runtime parents/root/managed directories, and physical confinement changes around writes while normalizing filesystem failures to path-private logical errors. Writer settlement preserves a primary governed-operation error if cleanup also fails; without a primary error, handle-close failure precedes lock-removal failure, and every cleanup failure is normalized before crossing the public boundary. Staging and uncommitted suffix files are ignored; missing, malformed, invalid, or oversized derived indexes remain non-authoritative and cannot block authoritative replay; authoritative corruption fails closed. + +```typescript +import { + invokeGovernedReasoning, + openLocalFileGovernedReasoningExecutionEvidence, +} from "@founderos/knowledge-engine"; + +const executionEvidence = await openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot, + runtimeRoot: `${repositoryRoot}/.founderos/runtime/reasoning-execution-ledger`, + canonicalSourceRoots: [`${repositoryRoot}/docs`, `${repositoryRoot}/knowledge`], +}); + +const finalized = await invokeGovernedReasoning({ + deliveryLedger, + executionEvidence, + deliveryIdentity, + invocationRequest, + fixtureMode: "successful-structured-response", + attemptSchedule, +}); +``` + +The local adapter remains a cooperative single-process runtime. It does not provide a production model, provider selection, credentials, streaming, tools, distributed coordination, remote persistence, authentication, authorization, or Agent execution. + ```typescript import { assembleGovernedKnowledgeContext, diff --git a/services/knowledge-engine/src/application/invoke-governed-reasoning.ts b/services/knowledge-engine/src/application/invoke-governed-reasoning.ts new file mode 100644 index 0000000..1043ac4 --- /dev/null +++ b/services/knowledge-engine/src/application/invoke-governed-reasoning.ts @@ -0,0 +1,965 @@ +import { + DeliveryLedgerIntegrityVerificationResultSchema, + DeliveryLedgerRecoveryResultSchema, + ReasoningProviderOutcomeSchema, + findDurableCanonicalJsonIssue, + type DurableContextDeliveryLedger, + type FinalizedReasoningConsumptionEvidence, + type ReasoningExecutionAttempt, + type ReasoningInvocationRequest, + type ReasoningProviderOutcome, + type ReasoningResultEnvelope, +} from "@founderos/knowledge-schema"; + +import type { + DeterministicFakeReasoningFixtureMode, + ProviderNeutralReasoningExecutionPort, + ReasoningCancellationSignal, +} from "./reasoning-execution-port.js"; +import { + resolveInternalReasoningExecutionEvidence, + type GovernedReasoningExecutionEvidenceReader, +} from "./manage-governed-reasoning-execution-ledger.js"; +import { createDurableCanonicalJsonSha256Fingerprint } from "../domain/canonical-fingerprint.js"; +import { verifyOriginalDeliveryArtifacts } from "../domain/durable-context-delivery-ledger.js"; +import { + countCanonicalCharacters, + countOutputCharacters, + createFinalizedReasoningConsumptionEvidence, + createReasoningCostEvidence, + createReasoningCancellationEvidence, + createReasoningExecutionAttempt, + createReasoningExecutionReceipt, + createReasoningFailureEvidence, + createReasoningProviderOutcome, + createReasoningTimeoutEvidence, + createReasoningResultEnvelope, + createReasoningUsageEvidence, + isReasoningRetryTransitionAuthorized, + matchReasoningProviderCapabilities, + verifyFinalizedReasoningConsumptionEvidence, + verifyReasoningAttemptLifecycle, + verifyReasoningInvocationRequest, + verifyReasoningProviderOutcome, + verifyReasoningResultEnvelope, +} from "../domain/reasoning.js"; +import { deepFreeze } from "../domain/snapshot-lifecycle.js"; +import { createDeterministicFakeReasoningProvider } from "../infrastructure/deterministic-fake-reasoning-provider.js"; + +export interface DurableDeliveryTransactionIdentity { + readonly transactionId: string; + readonly deliveryRequestId: string; + readonly deliveryRequestFingerprint: string; + readonly deliveryEnvelopeId: string; + readonly deliveryEnvelopeFingerprint: string; + readonly deliveryReceiptId: string; + readonly deliveryReceiptFingerprint: string; +} + +export interface ReasoningAttemptSchedule { + readonly startedAt: string; + readonly deadlineAt: string; + readonly completedAt: string; + readonly cancellationSignal: ReasoningCancellationSignal; +} + +export interface InvokeGovernedReasoningInput { + readonly deliveryLedger: DurableContextDeliveryLedger; + readonly executionEvidence: GovernedReasoningExecutionEvidenceReader; + readonly deliveryIdentity: DurableDeliveryTransactionIdentity; + readonly invocationRequest: ReasoningInvocationRequest; + readonly fixtureMode: DeterministicFakeReasoningFixtureMode; + readonly attemptSchedule: readonly ReasoningAttemptSchedule[]; +} + +export type GovernedReasoningInvocationResult = + | { + readonly schemaVersion: "1.0"; + readonly status: "finalized" | "identical-finalized"; + readonly resultEnvelope: ReasoningResultEnvelope; + readonly consumptionEvidence: FinalizedReasoningConsumptionEvidence; + } + | { + readonly schemaVersion: "1.0"; + readonly status: "identical-in-progress"; + readonly invocationRequestId: string; + readonly reasonCode: "invocation_already_in_progress"; + }; + +export class GovernedReasoningInvocationError extends Error { + public constructor( + public readonly code: + | "capability_mismatch" + | "delivery_integrity_failure" + | "idempotency_conflict" + | "invalid_invocation" + | "invalid_schedule" + | "result_integrity_failure", + message: string, + ) { + super(message); + this.name = "GovernedReasoningInvocationError"; + } +} + +function immutableCopy(value: T): T { + return deepFreeze(structuredClone(value)); +} +function same(left: unknown, right: unknown): boolean { + return JSON.stringify(left) === JSON.stringify(right); +} +function head(sequence: number, fingerprint: string) { + return { ledgerSequence: sequence, auditFingerprint: fingerprint }; +} +function addMillisecondsIsExact( + startedAt: string, + deadlineAt: string, + milliseconds: number, +): boolean { + return Date.parse(deadlineAt) - Date.parse(startedAt) === milliseconds; +} +function safeSchedule( + schedule: readonly ReasoningAttemptSchedule[], +): readonly ReasoningAttemptSchedule[] { + if (findDurableCanonicalJsonIssue(schedule) !== null || schedule.length === 0) + throw new GovernedReasoningInvocationError( + "invalid_schedule", + "Invocation requires accessor-free explicit Attempt timing evidence", + ); + return immutableCopy(schedule); +} + +function validateCompleteSchedule( + request: ReasoningInvocationRequest, + fixtureMode: DeterministicFakeReasoningFixtureMode, + schedule: readonly ReasoningAttemptSchedule[], +): void { + if (schedule.length !== request.executionPolicy.maxAttemptCount) + throw new GovernedReasoningInvocationError( + "invalid_schedule", + "Attempt schedule must cover the complete authorized Attempt budget", + ); + if ( + fixtureMode === "transient-failure-then-success" && + request.executionPolicy.maxAttemptCount < 2 + ) + throw new GovernedReasoningInvocationError( + "invalid_schedule", + "Transient-then-success fixture requires at least two authorized Attempts", + ); + const fixtureCancellationState = { + "cancellation-before-execution": "requested-before-execution", + "cooperative-cancellation": "requested-cooperatively", + "deadline-cancellation": "requested-at-deadline", + } as const; + let priorCompletedAt = Date.parse(request.requestedAt); + for (const timing of schedule) { + const startedAt = Date.parse(timing.startedAt); + const deadlineAt = Date.parse(timing.deadlineAt); + const completedAt = Date.parse(timing.completedAt); + const requestedAt = Date.parse(timing.cancellationSignal.requestedAt); + const observedAt = Date.parse(timing.cancellationSignal.observedAt); + if ( + [startedAt, deadlineAt, completedAt, requestedAt, observedAt].some( + (value) => !Number.isFinite(value), + ) || + !addMillisecondsIsExact( + timing.startedAt, + timing.deadlineAt, + request.executionPolicy.timeoutMilliseconds, + ) || + startedAt < priorCompletedAt || + completedAt < startedAt + ) + throw new GovernedReasoningInvocationError( + "invalid_schedule", + "Attempt timing evidence does not match the complete verified timeout schedule", + ); + const state = timing.cancellationSignal.state; + const expectedMode = { + "requested-before-execution": "cancel-before-execution", + "requested-cooperatively": "cooperative-cancellation", + "requested-at-deadline": "deadline-cancellation", + } as const; + if ( + (state !== "not-requested" && + request.executionPolicy.cancellationMode !== expectedMode[state]) || + requestedAt > observedAt || + (state === "requested-before-execution" && + (requestedAt > startedAt || observedAt > startedAt)) || + (state === "requested-cooperatively" && + (requestedAt < startedAt || observedAt > completedAt)) || + (state === "requested-at-deadline" && + (requestedAt !== deadlineAt || + observedAt < deadlineAt || + observedAt > completedAt || + completedAt < deadlineAt)) + ) + throw new GovernedReasoningInvocationError( + "invalid_schedule", + "Cancellation timing evidence contradicts its governed phase", + ); + const fixtureState = + fixtureMode in fixtureCancellationState + ? fixtureCancellationState[fixtureMode as keyof typeof fixtureCancellationState] + : undefined; + if ( + (fixtureMode === "timeout" && completedAt < deadlineAt) || + (fixtureState !== undefined && state !== fixtureState) + ) + throw new GovernedReasoningInvocationError( + "invalid_schedule", + "Fixture schedule does not supply its required terminal control evidence", + ); + priorCompletedAt = completedAt; + } +} + +export async function invokeGovernedReasoning( + input: InvokeGovernedReasoningInput, +): Promise { + return invokeGovernedReasoningWithProvider(input, createDeterministicFakeReasoningProvider()); +} + +/** Test seam kept out of the package facade; production callers always use the governed fake. */ +export async function invokeGovernedReasoningWithProvider( + input: InvokeGovernedReasoningInput, + provider: ProviderNeutralReasoningExecutionPort, +): Promise { + input = captureFacadeInput(input); + const executionEvidence = resolveInternalReasoningExecutionEvidence(input.executionEvidence); + const schedule = safeSchedule(input.attemptSchedule); + const request = immutableCopy(input.invocationRequest); + if (verifyReasoningInvocationRequest(request).status !== "valid") + throw new GovernedReasoningInvocationError( + "invalid_invocation", + "Reasoning Invocation Request failed independent verification", + ); + validateCompleteSchedule(request, input.fixtureMode, schedule); + + const delivery = await resolveVerifiedDelivery( + input.deliveryLedger, + input.deliveryIdentity, + request, + ); + const executionIntegrity = await executionEvidence.verifyIntegrity(); + const executionRecovery = await executionEvidence.recover(); + if (executionIntegrity.status !== "valid" || executionRecovery.status !== "recovered") + throw new GovernedReasoningInvocationError( + "result_integrity_failure", + "Reasoning Execution Ledger failed integrity verification", + ); + let currentHead = head( + executionIntegrity.verifiedThroughSequence, + executionIntegrity.lastAuditFingerprint, + ); + + const compatibility = matchReasoningProviderCapabilities({ + invocationRequest: request, + providerCapability: provider.providerCapability, + }); + if (compatibility.status !== "compatible") + throw new GovernedReasoningInvocationError( + "capability_mismatch", + `Provider capability mismatch: ${compatibility.reasonCodes.join(",")}`, + ); + if (countCanonicalCharacters(request.reasoningInput) > request.executionPolicy.maxInputCharacters) + throw new GovernedReasoningInvocationError( + "invalid_invocation", + "Reasoning input exceeds the verified Execution Policy budget", + ); + + const registration = await executionEvidence.registerGovernedInvocation( + { + schemaVersion: "1.0", + expectedLedgerHead: currentHead, + expectedIdempotencyState: "unowned", + invocationRequest: request, + registeredAt: request.requestedAt, + }, + { + providerCapability: provider.providerCapability, + contextPackageObjectCount: delivery.envelope.contextPackage.included.length, + }, + ); + if (registration.status === "conflict") + throw new GovernedReasoningInvocationError( + "idempotency_conflict", + "Invocation idempotency key is owned by different canonical content", + ); + if (registration.status === "identical-in-progress") + return immutableCopy({ + schemaVersion: "1.0", + status: "identical-in-progress", + invocationRequestId: registration.ownership.invocationRequestId, + reasonCode: registration.reasonCode, + }); + if (registration.status === "identical-finalized") + return immutableCopy({ + schemaVersion: "1.0", + status: "identical-finalized", + resultEnvelope: registration.finalization.resultEnvelope, + consumptionEvidence: registration.finalization.consumptionEvidence, + }); + const attempts: ReasoningExecutionAttempt[] = []; + const outcomes: ReasoningProviderOutcome[] = []; + let terminalOutcome: ReasoningProviderOutcome | undefined; + for (let index = 0; index < request.executionPolicy.maxAttemptCount; index += 1) { + const timing = schedule[index]; + if (timing === undefined) throw new Error("Complete schedule validation invariant failed"); + const cancellationState = timing.cancellationSignal.state; + const attemptUnsigned = { + schemaVersion: "1.0" as const, + executionAttemptId: `reasoning-attempt-${createDurableCanonicalJsonSha256Fingerprint({ invocationRequestFingerprint: request.requestFingerprint, attemptNumber: index + 1 })}`, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: provider.providerCapability.providerCapabilityId, + providerCapabilityFingerprint: provider.providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: index + 1, + ...(index === 0 + ? {} + : { previousExecutionAttemptId: attempts[index - 1]!.executionAttemptId }), + startedAt: timing.startedAt, + deadlineAt: timing.deadlineAt, + cancellationState, + ...(cancellationState === "not-requested" + ? {} + : { + cancellationAuthorityReference: timing.cancellationSignal.authorityReference, + cancellationRequestedAt: timing.cancellationSignal.requestedAt, + cancellationObservedAt: timing.cancellationSignal.observedAt, + }), + }; + const attempt = createReasoningExecutionAttempt(attemptUnsigned); + const integrityBeforeAttempt = await executionEvidence.verifyIntegrity(); + currentHead = head( + integrityBeforeAttempt.verifiedThroughSequence, + integrityBeforeAttempt.lastAuditFingerprint, + ); + await executionEvidence.appendExecutionAttempt({ + schemaVersion: "1.0", + expectedLedgerHead: currentHead, + ownershipId: registration.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedPriorAttemptCount: attempts.length, + attempt, + }); + attempts.push(attempt); + + const controlled = controlledTerminalOutcome(request, attempt, timing); + const rawOutcome = + controlled ?? + (await provider.execute({ + invocationRequest: request, + providerCapability: provider.providerCapability, + compatibility, + attempt, + completedAt: timing.completedAt, + evaluationTime: request.requestedAt, + cancellationSignal: timing.cancellationSignal, + fixtureMode: input.fixtureMode, + })); + let outcome = normalizeProviderOutcome( + rawOutcome, + request, + attempt, + timing.completedAt, + input.fixtureMode, + index + 1 === request.executionPolicy.maxAttemptCount, + ); + // Timing and cancellation are execution controls. A provider label can never override them. + outcome = controlledTerminalOutcome(request, attempt, timing) ?? outcome; + if ( + !verifyReasoningAttemptLifecycle({ + invocationRequest: request, + providerCapability: provider.providerCapability, + attempts, + outcomes: [...outcomes, outcome], + }) + ) + throw new GovernedReasoningInvocationError( + "result_integrity_failure", + "Attempt terminal controls failed authoritative lifecycle verification", + ); + const integrityBeforeOutcome = await executionEvidence.verifyIntegrity(); + currentHead = head( + integrityBeforeOutcome.verifiedThroughSequence, + integrityBeforeOutcome.lastAuditFingerprint, + ); + await executionEvidence.appendProviderOutcome({ + schemaVersion: "1.0", + expectedLedgerHead: currentHead, + ownershipId: registration.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + attemptFingerprint: attempt.attemptFingerprint, + outcome, + }); + outcomes.push(outcome); + terminalOutcome = outcome; + if (!isReasoningRetryTransitionAuthorized(outcome, request.executionPolicy, index + 1)) break; + } + if (terminalOutcome === undefined) + throw new GovernedReasoningInvocationError( + "result_integrity_failure", + "Invocation produced no terminal Attempt outcome", + ); + + const finalAttempt = attempts.at(-1)!; + const result = buildResult({ + request, + provider, + attempt: finalAttempt, + outcome: terminalOutcome, + deliveryObjectCount: delivery.envelope.contextPackage.included.length, + }); + if ( + verifyReasoningResultEnvelope({ + resultEnvelope: result, + invocationRequest: request, + providerCapability: provider.providerCapability, + attempt: finalAttempt, + attemptHistory: attempts, + providerOutcome: terminalOutcome, + outcomeHistory: outcomes, + contextPackageObjectCount: delivery.envelope.contextPackage.included.length, + }).status !== "valid" + ) + throw new GovernedReasoningInvocationError( + "result_integrity_failure", + "Terminal Result Envelope failed independent verification", + ); + const transactionId = `reasoning-finalization-${createDurableCanonicalJsonSha256Fingerprint({ invocationRequestFingerprint: request.requestFingerprint, resultEnvelopeFingerprint: result.resultEnvelopeFingerprint })}`; + const historyEntries = attempts.map((attempt, index) => ({ + executionAttemptId: attempt.executionAttemptId, + attemptNumber: attempt.attemptNumber, + outcome: outcomes[index]!.status, + attemptFingerprint: attempt.attemptFingerprint, + outcomeFingerprint: outcomes[index]!.outcomeFingerprint, + })); + const historyUnsigned = { + attemptCount: historyEntries.length, + finalAttemptNumber: finalAttempt.attemptNumber, + finalOutcome: terminalOutcome.status, + attempts: historyEntries, + }; + const consumptionBase = { + schemaVersion: "1.0" as const, + consumptionId: `reasoning-consumption-${createDurableCanonicalJsonSha256Fingerprint({ invocationRequestFingerprint: request.requestFingerprint, resultEnvelopeFingerprint: result.resultEnvelopeFingerprint })}`, + deliveryReceiptId: request.deliveryReceiptId, + deliveryReceiptFingerprint: request.deliveryReceiptFingerprint, + deliveryTransactionId: request.deliveryTransactionId, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: provider.providerCapability.providerCapabilityId, + providerCapabilityFingerprint: provider.providerCapability.descriptorFingerprint, + finalResultEnvelopeId: result.resultEnvelopeId, + finalResultEnvelopeFingerprint: result.resultEnvelopeFingerprint, + finalOutcome: terminalOutcome.status, + attemptHistorySummary: { + ...historyUnsigned, + historyFingerprint: createDurableCanonicalJsonSha256Fingerprint(historyUnsigned), + }, + startedAt: attempts[0]!.startedAt, + completedAt: terminalOutcome.completedAt, + usageEvidenceFingerprint: result.usageEvidence.usageFingerprint, + costEvidenceFingerprint: result.costEvidence.costFingerprint, + executionLedgerTransactionId: transactionId, + }; + const consumption = createFinalizedReasoningConsumptionEvidence({ + ...consumptionBase, + ...terminalEvidenceFingerprint(terminalOutcome), + } as Parameters[0]); + if ( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: consumption, + resultEnvelope: result, + invocationRequest: request, + providerCapability: provider.providerCapability, + attempts, + outcomes, + contextPackageObjectCount: delivery.envelope.contextPackage.included.length, + executionLedgerTransactionId: transactionId, + }).status !== "valid" + ) + throw new GovernedReasoningInvocationError( + "result_integrity_failure", + "Finalized Consumption Evidence failed independent verification", + ); + const finalHead = await executionEvidence.verifyIntegrity(); + const finalized = await executionEvidence.finalizeInvocation({ + schemaVersion: "1.0", + expectedLedgerHead: head(finalHead.verifiedThroughSequence, finalHead.lastAuditFingerprint), + ownershipId: registration.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedAttemptCount: attempts.length, + transactionId, + resultEnvelope: result, + consumptionEvidence: consumption, + finalizedAt: terminalOutcome.completedAt, + }); + if (finalized.status === "conflict") + throw new GovernedReasoningInvocationError( + "idempotency_conflict", + "Invocation finalization conflicts with durable evidence", + ); + return immutableCopy({ + schemaVersion: "1.0", + status: "finalized", + resultEnvelope: finalized.finalization.resultEnvelope, + consumptionEvidence: finalized.finalization.consumptionEvidence, + }); +} + +function captureFacadeInput(raw: InvokeGovernedReasoningInput): InvokeGovernedReasoningInput { + if (raw === null || typeof raw !== "object" || Object.getPrototypeOf(raw) !== Object.prototype) + throw new GovernedReasoningInvocationError( + "invalid_invocation", + "Invocation input must be a plain governed record", + ); + const descriptors = Object.getOwnPropertyDescriptors(raw); + const fields = [ + "deliveryLedger", + "executionEvidence", + "deliveryIdentity", + "invocationRequest", + "fixtureMode", + "attemptSchedule", + ] as const; + if ( + Reflect.ownKeys(descriptors).length !== fields.length || + Reflect.ownKeys(descriptors).some( + (key) => typeof key !== "string" || !fields.includes(key as (typeof fields)[number]), + ) + ) + throw new GovernedReasoningInvocationError( + "invalid_invocation", + "Invocation input contains unsupported public fields", + ); + const values: Record = {}; + for (const field of fields) { + const descriptor = descriptors[field]; + if (descriptor === undefined || !("value" in descriptor) || !descriptor.enumerable) + throw new GovernedReasoningInvocationError( + "invalid_invocation", + "Invocation input must be accessor-free", + ); + values[field] = descriptor.value; + } + if ( + findDurableCanonicalJsonIssue({ + deliveryIdentity: values.deliveryIdentity, + invocationRequest: values.invocationRequest, + fixtureMode: values.fixtureMode, + attemptSchedule: values.attemptSchedule, + }) !== null + ) + throw new GovernedReasoningInvocationError( + "invalid_invocation", + "Invocation canonical fields must be accessor-free", + ); + if ( + typeof values.fixtureMode !== "string" || + !DETERMINISTIC_FIXTURE_MODES.has(values.fixtureMode as DeterministicFakeReasoningFixtureMode) + ) + throw new GovernedReasoningInvocationError( + "invalid_invocation", + "Invocation fixture mode is not a supported deterministic evaluation mode", + ); + return Object.freeze(values) as unknown as InvokeGovernedReasoningInput; +} + +const DETERMINISTIC_FIXTURE_MODES = new Set([ + "cancellation-before-execution", + "cooperative-cancellation", + "contradictory-outcome", + "credential-bearing-outcome", + "deterministic-permanent-failure", + "deterministic-transient-failure", + "deadline-cancellation", + "malformed-failure-outcome", + "malformed-success-outcome", + "output-budget-overflow", + "physical-path-bearing-outcome", + "successful-empty-response", + "successful-structured-response", + "timeout", + "transient-failure-then-success", +]); + +function controlledTerminalOutcome( + request: ReasoningInvocationRequest, + attempt: ReasoningExecutionAttempt, + timing: ReasoningAttemptSchedule, +): ReasoningProviderOutcome | null { + const signal = timing.cancellationSignal; + // Deterministic precedence: pre-execution cancellation; deadline cancellation; + // cooperative cancellation observed before the deadline; expired deadline/timeout. + if ( + signal.state === "requested-before-execution" || + signal.state === "requested-at-deadline" || + (signal.state === "requested-cooperatively" && + Date.parse(signal.observedAt) < Date.parse(timing.deadlineAt)) + ) { + const detail = + signal.state === "requested-before-execution" + ? { + cancellationMode: "cancel-before-execution" as const, + cancellationPhase: "before-execution" as const, + reasonCode: "cancelled_before_execution" as const, + } + : signal.state === "requested-cooperatively" + ? { + cancellationMode: "cooperative-cancellation" as const, + cancellationPhase: "cooperative-execution" as const, + reasonCode: "cancelled_cooperatively" as const, + } + : { + cancellationMode: "deadline-cancellation" as const, + cancellationPhase: "deadline" as const, + reasonCode: "cancelled_at_deadline" as const, + }; + const evidence = createReasoningCancellationEvidence({ + schemaVersion: "1.0", + invocationRequestId: request.invocationRequestId, + executionAttemptId: attempt.executionAttemptId, + ...detail, + cancellationAuthorityReference: signal.authorityReference, + requestedAt: signal.requestedAt, + observedAt: signal.observedAt, + }); + return createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: attempt.attemptNumber, + completedAt: timing.completedAt, + status: "cancelled", + cancellationEvidence: evidence, + }); + } + if (Date.parse(timing.completedAt) >= Date.parse(timing.deadlineAt)) { + const evidence = createReasoningTimeoutEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + configuredTimeoutMilliseconds: request.executionPolicy.timeoutMilliseconds, + attemptStartedAt: attempt.startedAt, + deadlineAt: timing.deadlineAt, + elapsedMilliseconds: Date.parse(timing.completedAt) - Date.parse(attempt.startedAt), + timeoutPhase: "during-execution", + reasonCode: "execution_deadline_reached", + }); + return createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: attempt.attemptNumber, + completedAt: timing.completedAt, + status: "timed-out", + timeoutEvidence: evidence, + }); + } + return null; +} + +async function resolveVerifiedDelivery( + ledger: DurableContextDeliveryLedger, + identity: DurableDeliveryTransactionIdentity, + request: ReasoningInvocationRequest, +) { + if (findDurableCanonicalJsonIssue(identity) !== null) + throw new GovernedReasoningInvocationError( + "delivery_integrity_failure", + "Durable Delivery identity is not accessor-safe canonical data", + ); + const integrity = DeliveryLedgerIntegrityVerificationResultSchema.parse( + await ledger.verifyIntegrity(), + ); + const recovery = DeliveryLedgerRecoveryResultSchema.parse(await ledger.recover()); + if (integrity.status !== "valid" || recovery.status !== "recovered") + throw new GovernedReasoningInvocationError( + "delivery_integrity_failure", + "Durable Delivery Ledger failed integrity verification", + ); + const transaction = (await ledger.listCommittedOriginalDeliveries()).find( + (candidate) => candidate.transactionId === identity.transactionId, + ); + if (transaction === undefined) + throw new GovernedReasoningInvocationError( + "delivery_integrity_failure", + "Durable Delivery transaction does not exist", + ); + const result = await ledger.readOriginalDeliveryResult(identity.transactionId); + if (result === null) + throw new GovernedReasoningInvocationError( + "delivery_integrity_failure", + "Durable Delivery transaction is incomplete", + ); + const verified = verifyOriginalDeliveryArtifacts({ + request: transaction.requestRegistration.request, + result, + }); + const envelope = verified.result.envelope; + const receipt = verified.result.receipt; + const exactIdentity = + transaction.requestRegistration.deliveryRequestId === identity.deliveryRequestId && + transaction.requestRegistration.deliveryRequestFingerprint === + identity.deliveryRequestFingerprint && + envelope.deliveryEnvelopeId === identity.deliveryEnvelopeId && + envelope.deliveryFingerprint === identity.deliveryEnvelopeFingerprint && + receipt.receiptId === identity.deliveryReceiptId && + receipt.receiptFingerprint === identity.deliveryReceiptFingerprint; + const requestBinding = + request.deliveryTransactionId === identity.transactionId && + request.deliveryEnvelopeId === envelope.deliveryEnvelopeId && + request.deliveryEnvelopeFingerprint === envelope.deliveryFingerprint && + request.deliveryReceiptId === receipt.receiptId && + request.deliveryReceiptFingerprint === receipt.receiptFingerprint && + request.contextPackageId === envelope.contextPackageId && + request.contextPackageFingerprint === envelope.contextPackageFingerprint && + request.consumerId === envelope.consumerId && + request.consumerDescriptorFingerprint === envelope.consumerDescriptorFingerprint && + request.policyDecisionFingerprint === envelope.policyDecisionEvidence.decisionFingerprint && + same(request.activeSnapshotBinding, envelope.activeSnapshotBinding) && + same(request.registryIntegrityBinding, envelope.registryIntegrityBinding); + const sourceBinding = + transaction.idempotencyOwnership.deliveryRequestId === + transaction.requestRegistration.deliveryRequestId && + transaction.idempotencyOwnership.deliveryRequestFingerprint === + transaction.requestRegistration.deliveryRequestFingerprint && + verified.result.acknowledgment.status === "accepted" && + receipt.deliveryStatus === "accepted"; + const requested = Date.parse(request.requestedAt); + const deliveryRequest = transaction.requestRegistration.request; + const temporal = + (deliveryRequest.freshnessPolicy.notBefore === undefined || + requested >= Date.parse(deliveryRequest.freshnessPolicy.notBefore)) && + (deliveryRequest.freshnessPolicy.expiresAt === undefined || + requested < Date.parse(deliveryRequest.freshnessPolicy.expiresAt) || + deliveryRequest.freshnessPolicy.allowHistoricalReplay) && + (envelope.policyDecisionEvidence.expiresAt === undefined || + requested < Date.parse(envelope.policyDecisionEvidence.expiresAt) || + deliveryRequest.freshnessPolicy.allowHistoricalReplay); + if (!exactIdentity || !requestBinding || !sourceBinding || !temporal) + throw new GovernedReasoningInvocationError( + "delivery_integrity_failure", + "Invocation does not bind an acceptable complete Durable Delivery transaction", + ); + return immutableCopy({ transaction, envelope, receipt }); +} + +function normalizeProviderOutcome( + raw: unknown, + request: ReasoningInvocationRequest, + attempt: ReasoningExecutionAttempt, + scheduledCompletedAt: string, + mode: DeterministicFakeReasoningFixtureMode, + exhausted: boolean, +): ReasoningProviderOutcome { + const parsed = ReasoningProviderOutcomeSchema.safeParse(raw); + if (parsed.success && verifyReasoningProviderOutcome(parsed.data).status === "valid") { + if ( + parsed.data.invocationRequestId !== request.invocationRequestId || + parsed.data.executionAttemptId !== attempt.executionAttemptId || + parsed.data.attemptNumber !== attempt.attemptNumber || + parsed.data.completedAt !== scheduledCompletedAt + ) + return validationFailure(request, attempt, scheduledCompletedAt, "invalid_provider_outcome"); + if (parsed.data.status === "succeeded") { + const count = countOutputCharacters(parsed.data.outputContent); + const outputRequirements = request.reasoningInput.outputRequirements; + if ( + parsed.data.outputContent.contentType !== outputRequirements.contentType || + count > request.executionPolicy.maxOutputCharacters || + count > outputRequirements.maxCharacters || + (outputRequirements.requireNonEmpty && count === 0) + ) + return validationFailure( + request, + attempt, + parsed.data.completedAt, + count > request.executionPolicy.maxOutputCharacters || + count > outputRequirements.maxCharacters + ? "output_budget_exceeded" + : "malformed_success_outcome", + ); + } + if (parsed.data.status === "failed" && parsed.data.failureEvidence.retryable && exhausted) + return attemptLimitFailure(request, attempt, parsed.data.completedAt); + return immutableCopy(parsed.data); + } + const reason = + mode === "physical-path-bearing-outcome" + ? "physical_path_rejected" + : mode === "credential-bearing-outcome" + ? "credential_material_rejected" + : mode === "malformed-success-outcome" + ? "malformed_success_outcome" + : mode === "malformed-failure-outcome" + ? "malformed_failure_outcome" + : "invalid_provider_outcome"; + return validationFailure(request, attempt, scheduledCompletedAt, reason); +} +function validationFailure( + request: ReasoningInvocationRequest, + attempt: ReasoningExecutionAttempt, + completedAt: string, + reason: + | "credential_material_rejected" + | "invalid_provider_outcome" + | "malformed_failure_outcome" + | "malformed_success_outcome" + | "output_budget_exceeded" + | "physical_path_rejected", +): ReasoningProviderOutcome { + const evidence = createReasoningFailureEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + failureCategory: "output-validation", + reasonCodes: [reason], + retryable: false, + sanitizedDetail: "Provider outcome failed governed output verification", + attemptNumber: attempt.attemptNumber, + }); + return createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: attempt.attemptNumber, + completedAt, + status: "failed", + failureEvidence: evidence, + }); +} +function attemptLimitFailure( + request: ReasoningInvocationRequest, + attempt: ReasoningExecutionAttempt, + completedAt: string, +): ReasoningProviderOutcome { + const evidence = createReasoningFailureEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + failureCategory: "attempt-limit-exhausted", + reasonCodes: ["attempt_limit_exhausted"], + retryable: false, + sanitizedDetail: "Verified Attempt limit exhausted", + attemptNumber: attempt.attemptNumber, + }); + return createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: attempt.attemptNumber, + completedAt, + status: "failed", + failureEvidence: evidence, + }); +} +function buildResult(input: { + readonly request: ReasoningInvocationRequest; + readonly provider: ProviderNeutralReasoningExecutionPort; + readonly attempt: ReasoningExecutionAttempt; + readonly outcome: ReasoningProviderOutcome; + readonly deliveryObjectCount: number; +}): ReasoningResultEnvelope { + const { request, attempt, outcome } = input; + const duration = Date.parse(outcome.completedAt) - Date.parse(attempt.startedAt); + const outputCharacters = outcome.status === "succeeded" ? outcome.outputCharacterCount : 0; + const receipt = createReasoningExecutionReceipt({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + providerCapabilityId: input.provider.providerCapability.providerCapabilityId, + providerCapabilityFingerprint: input.provider.providerCapability.descriptorFingerprint, + attemptNumber: attempt.attemptNumber, + startedAt: attempt.startedAt, + completedAt: outcome.completedAt, + outcome: outcome.status, + }); + const usage = createReasoningUsageEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + inputCharacterCount: countCanonicalCharacters(request.reasoningInput), + outputCharacterCount: outputCharacters, + instructionBlockCount: request.reasoningInput.instructionBlocks.length, + contextPackageObjectCount: input.deliveryObjectCount, + attemptNumber: attempt.attemptNumber, + durationMilliseconds: duration, + }); + const cost = createReasoningCostEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + status: "not-applicable", + }); + const base = { + schemaVersion: "1.0" as const, + resultEnvelopeId: `reasoning-result-${createDurableCanonicalJsonSha256Fingerprint({ invocationRequestFingerprint: request.requestFingerprint, executionAttemptId: attempt.executionAttemptId, outcomeFingerprint: outcome.outcomeFingerprint })}`, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + deliveryTransactionId: request.deliveryTransactionId, + deliveryEnvelopeId: request.deliveryEnvelopeId, + deliveryEnvelopeFingerprint: request.deliveryEnvelopeFingerprint, + deliveryReceiptId: request.deliveryReceiptId, + deliveryReceiptFingerprint: request.deliveryReceiptFingerprint, + contextPackageId: request.contextPackageId, + contextPackageFingerprint: request.contextPackageFingerprint, + consumerId: request.consumerId, + consumerDescriptorFingerprint: request.consumerDescriptorFingerprint, + providerCapabilityId: input.provider.providerCapability.providerCapabilityId, + providerCapabilityFingerprint: input.provider.providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + executionAttemptId: attempt.executionAttemptId, + attemptNumber: attempt.attemptNumber, + executionReceipt: receipt, + usageEvidence: usage, + costEvidence: cost, + completedAt: outcome.completedAt, + }; + if (outcome.status === "succeeded") + return createReasoningResultEnvelope({ + ...base, + outcome: "succeeded", + outputContent: outcome.outputContent, + outputCharacterCount: outcome.outputCharacterCount, + outputContentFingerprint: outcome.outputContentFingerprint, + }); + if (outcome.status === "failed") + return createReasoningResultEnvelope({ + ...base, + outcome: "failed", + failureEvidence: outcome.failureEvidence, + }); + if (outcome.status === "timed-out") + return createReasoningResultEnvelope({ + ...base, + outcome: "timed-out", + timeoutEvidence: outcome.timeoutEvidence, + }); + return createReasoningResultEnvelope({ + ...base, + outcome: "cancelled", + cancellationEvidence: outcome.cancellationEvidence, + }); +} +function terminalEvidenceFingerprint(outcome: ReasoningProviderOutcome): { + readonly failureEvidenceFingerprint?: string; + readonly timeoutEvidenceFingerprint?: string; + readonly cancellationEvidenceFingerprint?: string; +} { + if (outcome.status === "failed") + return { failureEvidenceFingerprint: outcome.failureEvidence.failureFingerprint }; + if (outcome.status === "timed-out") + return { timeoutEvidenceFingerprint: outcome.timeoutEvidence.timeoutFingerprint }; + if (outcome.status === "cancelled") + return { + cancellationEvidenceFingerprint: outcome.cancellationEvidence.cancellationFingerprint, + }; + return {}; +} diff --git a/services/knowledge-engine/src/application/manage-governed-reasoning-execution-ledger.ts b/services/knowledge-engine/src/application/manage-governed-reasoning-execution-ledger.ts new file mode 100644 index 0000000..3c2a41b --- /dev/null +++ b/services/knowledge-engine/src/application/manage-governed-reasoning-execution-ledger.ts @@ -0,0 +1,552 @@ +import { + AppendReasoningExecutionAttemptRequestSchema, + AppendReasoningProviderOutcomeRequestSchema, + FinalizeReasoningInvocationRequestSchema, + ReasoningExecutionLedgerDerivedIndexRebuildResultSchema, + ReasoningExecutionLedgerHeadExpectationSchema, + ReasoningInvocationFinalizationResultSchema, + ReasoningInvocationOwnershipResolutionSchema, + RegisterReasoningInvocationRequestSchema, + type DurableReasoningExecutionLedger, + type FinalizedReasoningConsumptionEvidence, + type ReasoningExecutionAttempt, + type ReasoningInvocationOwnershipRecord, + type ReasoningInvocationRequest, + type ReasoningProviderOutcome, + type ReasoningProviderCapabilityDescriptor, + type ReasoningResultEnvelope, +} from "@founderos/knowledge-schema"; + +import type { + ReasoningExecutionLedgerStoragePort, + ReasoningExecutionLedgerWriterPort, +} from "./reasoning-execution-ledger-port.js"; +import { + createExecutionAttemptRecord, + createFinalizationRecord, + createInvocationOwnershipRecord, + createProviderOutcomeRecord, + createReasoningExecutionDerivedIndex, + createReasoningExecutionLedgerEvent, + ReasoningExecutionLedgerConflictError, + ReasoningExecutionLedgerIntegrityError, + recoverReasoningExecutionLedger, + verifyReasoningExecutionLedgerIntegrity, +} from "../domain/durable-reasoning-execution-ledger.js"; +import { serializeCanonicalDurablePayload } from "../domain/durable-registry.js"; +import { + verifyFinalizedReasoningConsumptionEvidence, + verifyReasoningExecutionAttempt, + verifyReasoningInvocationRequest, + verifyReasoningProviderOutcome, + verifyReasoningProviderCapabilityDescriptor, + verifyReasoningAttemptLifecycle, +} from "../domain/reasoning.js"; +import { deepFreeze } from "../domain/snapshot-lifecycle.js"; + +function immutableCopy(value: T): T { + return deepFreeze(structuredClone(value)); +} +function same(left: unknown, right: unknown): boolean { + return serializeCanonicalDurablePayload(left) === serializeCanonicalDurablePayload(right); +} + +export interface GovernedReasoningExecutionEvidence extends DurableReasoningExecutionLedger { + registerGovernedInvocation( + raw: unknown, + authority: { + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly contextPackageObjectCount: number; + }, + ): ReturnType; +} + +export interface GovernedReasoningExecutionEvidenceReader { + readInvocationRequest(invocationRequestId: string): Promise; + readAttemptHistory(invocationRequestId: string): Promise; + readProviderOutcome(executionAttemptId: string): Promise; + readFinalizedResult(invocationRequestId: string): Promise; + readFinalizedConsumptionEvidence( + invocationRequestId: string, + ): Promise; + recover(): ReturnType; + verifyIntegrity(): ReturnType; + rebuildDerivedIndexes(): ReturnType; +} + +const INTERNAL_LEDGER = new WeakMap(); + +export function createSafeReasoningExecutionEvidenceReader( + ledger: GovernedReasoningExecutionEvidence, +): GovernedReasoningExecutionEvidenceReader { + const reader = Object.freeze({ + readInvocationRequest: (id: string) => ledger.readInvocationRequest(id), + readAttemptHistory: (id: string) => ledger.readAttemptHistory(id), + readProviderOutcome: (id: string) => ledger.readProviderOutcome(id), + readFinalizedResult: (id: string) => ledger.readFinalizedResult(id), + readFinalizedConsumptionEvidence: (id: string) => ledger.readFinalizedConsumptionEvidence(id), + recover: () => ledger.recover(), + verifyIntegrity: () => ledger.verifyIntegrity(), + rebuildDerivedIndexes: () => ledger.rebuildDerivedIndexes(), + }); + INTERNAL_LEDGER.set(reader, ledger); + return reader; +} + +export function resolveInternalReasoningExecutionEvidence( + reader: GovernedReasoningExecutionEvidenceReader, +): GovernedReasoningExecutionEvidence { + const ledger = INTERNAL_LEDGER.get(reader as object); + if (ledger === undefined) + throw new ReasoningExecutionLedgerIntegrityError( + "unsafe_content", + "Reasoning Execution Evidence runtime is not governed by FounderOS", + ); + return ledger; +} + +class PortGovernedReasoningExecutionEvidence implements GovernedReasoningExecutionEvidence { + public constructor(private readonly storage: ReasoningExecutionLedgerStoragePort) {} + + public async registerInvocation(): Promise { + throw new ReasoningExecutionLedgerIntegrityError( + "invocation_binding_mismatch", + "Invocation registration requires governed Delivery authority", + ); + } + + public async registerGovernedInvocation( + raw: unknown, + authorityInput: { + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly contextPackageObjectCount: number; + }, + ) { + const request = RegisterReasoningInvocationRequestSchema.parse(raw); + if ( + verifyReasoningInvocationRequest(request.invocationRequest).status !== "valid" || + verifyReasoningProviderCapabilityDescriptor(authorityInput.providerCapability).status !== + "valid" || + !Number.isSafeInteger(authorityInput.contextPackageObjectCount) || + authorityInput.contextPackageObjectCount < 0 + ) + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + "Invocation Request does not verify", + ); + return this.storage.withWriter(async (writer) => { + const state = await writer.readVerifiedState(); + const existing = state.replay.ownershipByKey.get(request.invocationRequest.idempotencyKey); + if (existing !== undefined) { + const existingAuthority = state.replay.authorityByInvocation.get( + existing.invocationRequestId, + ); + if ( + existing.invocationRequestFingerprint !== request.invocationRequest.requestFingerprint || + existingAuthority === undefined || + !same(existingAuthority.invocationRequest, request.invocationRequest) || + !same(existingAuthority.providerCapability, authorityInput.providerCapability) || + existingAuthority.contextPackageObjectCount !== authorityInput.contextPackageObjectCount + ) + return ReasoningInvocationOwnershipResolutionSchema.parse({ + schemaVersion: "1.0", + status: "conflict", + reasonCode: "idempotency_key_conflict", + existingInvocationRequestId: existing.invocationRequestId, + existingInvocationRequestFingerprint: existing.invocationRequestFingerprint, + }); + const finalization = state.replay.finalizationsByInvocation.get( + existing.invocationRequestId, + ); + return finalization === undefined + ? ReasoningInvocationOwnershipResolutionSchema.parse({ + schemaVersion: "1.0", + status: "identical-in-progress", + reasonCode: "invocation_already_in_progress", + ownership: existing, + }) + : ReasoningInvocationOwnershipResolutionSchema.parse({ + schemaVersion: "1.0", + status: "identical-finalized", + reasonCode: "invocation_already_finalized", + ownership: existing, + finalization, + }); + } + requireHead(request.expectedLedgerHead, state.replay); + const ownership = createInvocationOwnershipRecord({ + request: request.invocationRequest, + ledgerSequence: state.replay.lastSequence + 1, + previousAuditFingerprint: state.replay.lastAuditFingerprint, + registeredAt: request.registeredAt, + }); + const event = createReasoningExecutionLedgerEvent({ + eventType: "invocation-ownership", + ownership, + }); + await writer.appendAuthoritativeEvent(event, request.expectedLedgerHead, { + invocationRequest: request.invocationRequest, + providerCapability: authorityInput.providerCapability, + contextPackageObjectCount: authorityInput.contextPackageObjectCount, + }); + await replaceIndexBestEffort(writer); + return ReasoningInvocationOwnershipResolutionSchema.parse({ + schemaVersion: "1.0", + status: "registered", + reasonCode: "invocation_registered", + ownership, + }); + }); + } + + public async appendExecutionAttempt(raw: unknown): Promise { + const request = AppendReasoningExecutionAttemptRequestSchema.parse(raw); + if (verifyReasoningExecutionAttempt(request.attempt).status !== "valid") + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + "Execution Attempt does not verify", + ); + return this.storage.withWriter(async (writer) => { + const state = await writer.readVerifiedState(); + const duplicate = state.replay.attemptsById.get(request.attempt.executionAttemptId); + if (duplicate !== undefined) { + if (!same(duplicate, request.attempt)) + throw new ReasoningExecutionLedgerConflictError( + "transaction_conflict", + "Attempt ID is already owned by different content", + ); + return immutableCopy(duplicate); + } + const ownership = [...state.replay.ownershipByKey.values()].find( + (candidate) => candidate.ownershipId === request.ownershipId, + ); + const attempts = + state.replay.attemptsByInvocation.get(request.attempt.invocationRequestId) ?? []; + const authority = state.replay.authorityByInvocation.get(request.attempt.invocationRequestId); + const priorOutcomes = attempts.map((attempt) => + state.replay.outcomesByAttemptId.get(attempt.executionAttemptId), + ); + if ( + ownership === undefined || + authority === undefined || + state.replay.finalizationsByInvocation.has(ownership.invocationRequestId) || + ownership.invocationRequestId !== request.attempt.invocationRequestId || + ownership.invocationRequestFingerprint !== request.attempt.invocationRequestFingerprint || + ownership.invocationIdempotencyKey !== request.attempt.invocationIdempotencyKey || + attempts.length !== request.expectedPriorAttemptCount || + priorOutcomes.some((outcome) => outcome === undefined) || + !verifyReasoningAttemptLifecycle({ + invocationRequest: authority.invocationRequest, + providerCapability: authority.providerCapability, + attempts: [...attempts, request.attempt], + outcomes: priorOutcomes as ReasoningProviderOutcome[], + }) + ) + throw new ReasoningExecutionLedgerConflictError( + "attempt_binding_mismatch", + "Attempt does not bind the authoritative open Invocation", + ); + requireHead(request.expectedLedgerHead, state.replay); + const record = createExecutionAttemptRecord({ + attempt: request.attempt, + ledgerSequence: state.replay.lastSequence + 1, + previousAuditFingerprint: state.replay.lastAuditFingerprint, + }); + await writer.appendAuthoritativeEvent( + createReasoningExecutionLedgerEvent({ + eventType: "execution-attempt", + attemptRecord: record, + }), + request.expectedLedgerHead, + ); + await replaceIndexBestEffort(writer); + return immutableCopy(request.attempt); + }); + } + + public async appendProviderOutcome(raw: unknown): Promise { + const request = AppendReasoningProviderOutcomeRequestSchema.parse(raw); + if (verifyReasoningProviderOutcome(request.outcome).status !== "valid") + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + "Provider Outcome does not verify", + ); + return this.storage.withWriter(async (writer) => { + const state = await writer.readVerifiedState(); + const duplicate = state.replay.outcomesByAttemptId.get(request.outcome.executionAttemptId); + if (duplicate !== undefined) { + if (!same(duplicate, request.outcome)) + throw new ReasoningExecutionLedgerConflictError( + "transaction_conflict", + "Attempt outcome is already finalized differently", + ); + return immutableCopy(duplicate); + } + const ownership = [...state.replay.ownershipByKey.values()].find( + (candidate) => candidate.ownershipId === request.ownershipId, + ); + const attempt = state.replay.attemptsById.get(request.outcome.executionAttemptId); + const authority = + attempt === undefined + ? undefined + : state.replay.authorityByInvocation.get(attempt.invocationRequestId); + const attempts = + attempt === undefined + ? [] + : (state.replay.attemptsByInvocation.get(attempt.invocationRequestId) ?? []); + const candidateOutcomes = attempts.map((entry) => + entry.executionAttemptId === request.outcome.executionAttemptId + ? request.outcome + : state.replay.outcomesByAttemptId.get(entry.executionAttemptId), + ); + if ( + ownership === undefined || + attempt === undefined || + authority === undefined || + state.replay.finalizationsByInvocation.has(ownership.invocationRequestId) || + attempt.attemptFingerprint !== request.attemptFingerprint || + attempt.invocationRequestId !== ownership.invocationRequestId || + attempt.attemptNumber !== request.outcome.attemptNumber || + candidateOutcomes.some((outcome) => outcome === undefined) || + !verifyReasoningAttemptLifecycle({ + invocationRequest: authority.invocationRequest, + providerCapability: authority.providerCapability, + attempts, + outcomes: candidateOutcomes as ReasoningProviderOutcome[], + }) + ) + throw new ReasoningExecutionLedgerConflictError( + "outcome_binding_mismatch", + "Provider Outcome does not bind the authoritative open Attempt", + ); + requireHead(request.expectedLedgerHead, state.replay); + const record = createProviderOutcomeRecord({ + outcome: request.outcome, + ledgerSequence: state.replay.lastSequence + 1, + previousAuditFingerprint: state.replay.lastAuditFingerprint, + }); + await writer.appendAuthoritativeEvent( + createReasoningExecutionLedgerEvent({ + eventType: "provider-outcome", + outcomeRecord: record, + }), + request.expectedLedgerHead, + ); + await replaceIndexBestEffort(writer); + return immutableCopy(request.outcome); + }); + } + + public async finalizeInvocation(raw: unknown) { + const request = FinalizeReasoningInvocationRequestSchema.parse(raw); + return this.storage.withWriter(async (writer) => { + const state = await writer.readVerifiedState(); + const ownership = [...state.replay.ownershipByKey.values()].find( + (candidate) => candidate.ownershipId === request.ownershipId, + ); + if (ownership === undefined) + throw new ReasoningExecutionLedgerConflictError( + "invocation_binding_mismatch", + "Finalization has no Invocation owner", + ); + const existing = state.replay.finalizationsByInvocation.get(ownership.invocationRequestId); + if (existing !== undefined) { + if ( + existing.transactionId === request.transactionId && + same(existing.resultEnvelope, request.resultEnvelope) && + same(existing.consumptionEvidence, request.consumptionEvidence) + ) + return ReasoningInvocationFinalizationResultSchema.parse({ + schemaVersion: "1.0", + status: "identical-finalization", + finalization: existing, + }); + return ReasoningInvocationFinalizationResultSchema.parse({ + schemaVersion: "1.0", + status: "conflict", + reasonCode: "conflicting_finalization", + existingTransactionId: existing.transactionId, + existingResultEnvelopeFingerprint: existing.resultEnvelope.resultEnvelopeFingerprint, + }); + } + const attempts = state.replay.attemptsByInvocation.get(ownership.invocationRequestId) ?? []; + const authority = state.replay.authorityByInvocation.get(ownership.invocationRequestId); + const outcomes = attempts.map((attempt) => + state.replay.outcomesByAttemptId.get(attempt.executionAttemptId), + ); + if ( + attempts.length !== request.expectedAttemptCount || + authority === undefined || + outcomes.some((outcome) => outcome === undefined) || + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: request.consumptionEvidence, + resultEnvelope: request.resultEnvelope, + invocationRequest: authority.invocationRequest, + providerCapability: authority.providerCapability, + attempts, + outcomes: outcomes as ReasoningProviderOutcome[], + contextPackageObjectCount: authority.contextPackageObjectCount, + executionLedgerTransactionId: request.transactionId, + }).status !== "valid" + ) + throw new ReasoningExecutionLedgerIntegrityError( + "finalization_incomplete", + "Finalization evidence does not verify against authoritative Attempts", + ); + const finalAttempt = attempts.at(-1)!; + const finalOutcome = outcomes.at(-1)!; + if ( + request.resultEnvelope.invocationRequestFingerprint !== + ownership.invocationRequestFingerprint || + request.resultEnvelope.executionAttemptId !== finalAttempt.executionAttemptId || + request.resultEnvelope.outcome !== finalOutcome!.status + ) + throw new ReasoningExecutionLedgerIntegrityError( + "finalization_incomplete", + "Final Result does not bind the terminal Attempt", + ); + requireHead(request.expectedLedgerHead, state.replay); + const finalization = createFinalizationRecord({ + transactionId: request.transactionId, + ownership, + resultEnvelope: request.resultEnvelope, + consumptionEvidence: request.consumptionEvidence, + ledgerSequence: state.replay.lastSequence + 1, + previousAuditFingerprint: state.replay.lastAuditFingerprint, + finalizedAt: request.finalizedAt, + }); + await writer.appendAuthoritativeEvent( + createReasoningExecutionLedgerEvent({ eventType: "invocation-finalization", finalization }), + request.expectedLedgerHead, + ); + await replaceIndexBestEffort(writer); + return ReasoningInvocationFinalizationResultSchema.parse({ + schemaVersion: "1.0", + status: "finalized", + finalization, + }); + }); + } + + public async resolveInvocationOwnership( + key: string, + ): Promise { + return immutableCopy( + (await this.storage.readVerifiedState()).replay.ownershipByKey.get(key) ?? null, + ); + } + public async readInvocationRequest(id: string): Promise { + return immutableCopy( + (await this.storage.readVerifiedState()).replay.requestsById.get(id) ?? null, + ); + } + public async readAttemptHistory(id: string): Promise { + return immutableCopy( + (await this.storage.readVerifiedState()).replay.attemptsByInvocation.get(id) ?? [], + ); + } + public async readProviderOutcome(id: string): Promise { + return immutableCopy( + (await this.storage.readVerifiedState()).replay.outcomesByAttemptId.get(id) ?? null, + ); + } + public async readFinalizedResult(id: string): Promise { + return immutableCopy( + (await this.storage.readVerifiedState()).replay.finalizationsByInvocation.get(id) + ?.resultEnvelope ?? null, + ); + } + public async readFinalizedConsumptionEvidence( + id: string, + ): Promise { + return immutableCopy( + (await this.storage.readVerifiedState()).replay.finalizationsByInvocation.get(id) + ?.consumptionEvidence ?? null, + ); + } + public async recover() { + const state = await this.storage.readVerifiedState(); + return recoverReasoningExecutionLedger( + state.replay.events, + [...state.replay.authorityByInvocation.values()], + state.derivedIndex, + ); + } + public async verifyIntegrity() { + const state = await this.storage.readVerifiedState(); + return verifyReasoningExecutionLedgerIntegrity( + state.replay.events, + [...state.replay.authorityByInvocation.values()], + state.derivedIndex, + ); + } + public async rebuildDerivedIndexes() { + return this.storage.withWriter(async (writer) => { + try { + const state = await writer.readVerifiedState(); + const index = createReasoningExecutionDerivedIndex(state.replay); + await writer.replaceDerivedIndex(index); + return ReasoningExecutionLedgerDerivedIndexRebuildResultSchema.parse({ + schemaVersion: "1.0", + status: "rebuilt", + verifiedThroughSequence: state.replay.lastSequence, + indexFingerprint: index.indexFingerprint, + invocationEntryCount: index.invocationEntries.length, + attemptEntryCount: index.attemptEntries.length, + resultEntryCount: index.resultEntries.length, + issues: [], + }); + } catch { + return ReasoningExecutionLedgerDerivedIndexRebuildResultSchema.parse({ + schemaVersion: "1.0", + status: "failed", + verifiedThroughSequence: 0, + indexFingerprint: null, + invocationEntryCount: 0, + attemptEntryCount: 0, + resultEntryCount: 0, + issues: [ + { + code: "storage_failure", + logicalLocation: "derived-index", + message: "Execution Ledger index rebuild failed", + }, + ], + }); + } + }); + } +} + +function requireHead( + expected: { readonly ledgerSequence: number; readonly auditFingerprint: string }, + state: { readonly lastSequence: number; readonly lastAuditFingerprint: string }, +): void { + if ( + expected.ledgerSequence !== state.lastSequence || + expected.auditFingerprint !== state.lastAuditFingerprint + ) + throw new ReasoningExecutionLedgerConflictError( + "audit_chain_broken", + "Expected Execution Ledger head is stale", + ); +} +async function replaceIndexBestEffort(writer: ReasoningExecutionLedgerWriterPort): Promise { + try { + const next = await writer.readVerifiedState(); + await writer.replaceDerivedIndex(createReasoningExecutionDerivedIndex(next.replay)); + } catch { + /* authoritative append remains committed */ + } +} +export function createGovernedReasoningExecutionEvidence( + storage: ReasoningExecutionLedgerStoragePort, +): GovernedReasoningExecutionEvidence { + return new PortGovernedReasoningExecutionEvidence(storage); +} +export function emptyReasoningExecutionLedgerHead() { + return ReasoningExecutionLedgerHeadExpectationSchema.parse({ + ledgerSequence: 0, + auditFingerprint: "genesis", + }); +} diff --git a/services/knowledge-engine/src/application/reasoning-execution-ledger-port.ts b/services/knowledge-engine/src/application/reasoning-execution-ledger-port.ts new file mode 100644 index 0000000..3b2094f --- /dev/null +++ b/services/knowledge-engine/src/application/reasoning-execution-ledger-port.ts @@ -0,0 +1,28 @@ +import type { + DurableReasoningExecutionDerivedIndex, + ReasoningExecutionLedgerEvent, +} from "@founderos/knowledge-schema"; + +import type { ReasoningExecutionLedgerReplayState } from "../domain/durable-reasoning-execution-ledger.js"; +import type { ReasoningInvocationAuthority } from "../domain/durable-reasoning-execution-ledger.js"; + +export interface VerifiedReasoningExecutionLedgerState { + readonly replay: ReasoningExecutionLedgerReplayState; + readonly derivedIndex: unknown; + readonly authoritativeCommitFingerprint: string; +} + +export interface ReasoningExecutionLedgerWriterPort { + readVerifiedState(): Promise; + appendAuthoritativeEvent( + event: ReasoningExecutionLedgerEvent, + expected: { readonly ledgerSequence: number; readonly auditFingerprint: string }, + invocationAuthority?: ReasoningInvocationAuthority, + ): Promise; + replaceDerivedIndex(index: DurableReasoningExecutionDerivedIndex): Promise; +} + +export interface ReasoningExecutionLedgerStoragePort { + readVerifiedState(): Promise; + withWriter(operation: (writer: ReasoningExecutionLedgerWriterPort) => Promise): Promise; +} diff --git a/services/knowledge-engine/src/application/reasoning-execution-port.ts b/services/knowledge-engine/src/application/reasoning-execution-port.ts new file mode 100644 index 0000000..4562f61 --- /dev/null +++ b/services/knowledge-engine/src/application/reasoning-execution-port.ts @@ -0,0 +1,50 @@ +import type { + ReasoningExecutionAttempt, + ReasoningInvocationRequest, + ReasoningProviderCapabilityDescriptor, + ReasoningProviderCompatibilityResult, +} from "@founderos/knowledge-schema"; + +export type DeterministicFakeReasoningFixtureMode = + | "cancellation-before-execution" + | "cooperative-cancellation" + | "contradictory-outcome" + | "credential-bearing-outcome" + | "deterministic-permanent-failure" + | "deterministic-transient-failure" + | "deadline-cancellation" + | "malformed-failure-outcome" + | "malformed-success-outcome" + | "output-budget-overflow" + | "physical-path-bearing-outcome" + | "successful-empty-response" + | "successful-structured-response" + | "timeout" + | "transient-failure-then-success"; + +export interface ReasoningCancellationSignal { + readonly authorityReference: string; + readonly requestedAt: string; + readonly observedAt: string; + readonly state: + | "not-requested" + | "requested-at-deadline" + | "requested-before-execution" + | "requested-cooperatively"; +} + +export interface ReasoningExecutionPortInput { + readonly invocationRequest: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly compatibility: ReasoningProviderCompatibilityResult; + readonly attempt: ReasoningExecutionAttempt; + readonly completedAt: string; + readonly evaluationTime: string; + readonly cancellationSignal: ReasoningCancellationSignal; + readonly fixtureMode: DeterministicFakeReasoningFixtureMode; +} + +export interface ProviderNeutralReasoningExecutionPort { + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + execute(input: ReasoningExecutionPortInput): Promise; +} diff --git a/services/knowledge-engine/src/domain/durable-reasoning-execution-ledger.ts b/services/knowledge-engine/src/domain/durable-reasoning-execution-ledger.ts new file mode 100644 index 0000000..7c7a2a4 --- /dev/null +++ b/services/knowledge-engine/src/domain/durable-reasoning-execution-ledger.ts @@ -0,0 +1,661 @@ +import { + DurableReasoningExecutionAttemptRecordSchema, + DurableReasoningExecutionDerivedIndexSchema, + DurableReasoningProviderOutcomeRecordSchema, + FinalizedReasoningInvocationTransactionSchema, + ReasoningExecutionLedgerEventSchema, + ReasoningExecutionLedgerIntegrityVerificationResultSchema, + ReasoningExecutionLedgerIssueSchema, + ReasoningExecutionLedgerRecoveryResultSchema, + ReasoningInvocationOwnershipRecordSchema, + findDurableCanonicalJsonIssue, + type DurableReasoningExecutionDerivedIndex, + type FinalizedReasoningInvocationTransaction, + type ReasoningExecutionAttempt, + type ReasoningExecutionLedgerEvent, + type ReasoningExecutionLedgerIntegrityVerificationResult, + type ReasoningExecutionLedgerRecoveryResult, + type ReasoningInvocationOwnershipRecord, + type ReasoningInvocationRequest, + type ReasoningProviderCapabilityDescriptor, + type ReasoningProviderOutcome, +} from "@founderos/knowledge-schema"; + +import { createDurableCanonicalJsonSha256Fingerprint } from "./canonical-fingerprint.js"; +import { + verifyFinalizedReasoningConsumptionEvidence, + verifyReasoningExecutionAttempt, + verifyReasoningAttemptLifecycle, + verifyReasoningInvocationRequest, + verifyReasoningProviderOutcome, + verifyReasoningProviderCapabilityDescriptor, +} from "./reasoning.js"; +import { deepFreeze } from "./snapshot-lifecycle.js"; + +export class ReasoningExecutionLedgerError extends Error { + public constructor( + public readonly code: ReturnType["code"], + message: string, + ) { + super(message); + this.name = new.target.name; + } +} +export class ReasoningExecutionLedgerConflictError extends ReasoningExecutionLedgerError {} +export class ReasoningExecutionLedgerIntegrityError extends ReasoningExecutionLedgerError {} + +export interface ReasoningExecutionLedgerReplayState { + readonly events: readonly ReasoningExecutionLedgerEvent[]; + readonly ownershipByKey: ReadonlyMap; + readonly requestsById: ReadonlyMap; + readonly authorityByInvocation: ReadonlyMap; + readonly attemptsByInvocation: ReadonlyMap; + readonly attemptsById: ReadonlyMap; + readonly outcomesByAttemptId: ReadonlyMap; + readonly finalizationsByInvocation: ReadonlyMap; + readonly lastSequence: number; + readonly lastAuditFingerprint: "genesis" | string; + readonly executionEvidenceFingerprint: string; +} + +export interface ReasoningInvocationAuthority { + readonly invocationRequest: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly contextPackageObjectCount: number; +} + +function immutableCopy(value: T): T { + return deepFreeze(structuredClone(value)); +} +function without(value: object, field: string) { + return Object.fromEntries(Object.entries(value).filter(([key]) => key !== field)); +} +function requireFingerprint(value: object, field: string, label: string): void { + const record = value as Record; + if ( + typeof record[field] !== "string" || + record[field] !== createDurableCanonicalJsonSha256Fingerprint(without(value, field)) + ) + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + `${label} fingerprint does not verify`, + ); +} + +export function createInvocationOwnershipRecord(input: { + readonly request: ReasoningInvocationRequest; + readonly ledgerSequence: number; + readonly previousAuditFingerprint: string; + readonly registeredAt: string; +}): ReasoningInvocationOwnershipRecord { + if (verifyReasoningInvocationRequest(input.request).status !== "valid") + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + "Invocation Request does not verify", + ); + const unsigned = { + schemaVersion: "1.0" as const, + recordType: "invocation-ownership" as const, + ownershipId: `reasoning-ownership-${createDurableCanonicalJsonSha256Fingerprint(input.request.idempotencyKey)}`, + invocationIdempotencyKey: input.request.idempotencyKey, + invocationRequestId: input.request.invocationRequestId, + invocationRequestFingerprint: input.request.requestFingerprint, + ownershipStatus: "in-progress" as const, + ownershipSequence: input.ledgerSequence, + createdAt: input.registeredAt, + ledgerSequence: input.ledgerSequence, + previousAuditFingerprint: input.previousAuditFingerprint, + committedAt: input.registeredAt, + }; + return immutableCopy( + ReasoningInvocationOwnershipRecordSchema.parse({ + ...unsigned, + ownershipFingerprint: createDurableCanonicalJsonSha256Fingerprint(unsigned), + }), + ); +} + +export function createExecutionAttemptRecord(input: { + readonly attempt: ReasoningExecutionAttempt; + readonly ledgerSequence: number; + readonly previousAuditFingerprint: string; +}) { + if (verifyReasoningExecutionAttempt(input.attempt).status !== "valid") + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + "Execution Attempt does not verify", + ); + const unsigned = { + schemaVersion: "1.0" as const, + recordType: "execution-attempt" as const, + invocationRequestId: input.attempt.invocationRequestId, + invocationRequestFingerprint: input.attempt.invocationRequestFingerprint, + invocationIdempotencyKey: input.attempt.invocationIdempotencyKey, + attempt: input.attempt, + ledgerSequence: input.ledgerSequence, + previousAuditFingerprint: input.previousAuditFingerprint, + committedAt: input.attempt.startedAt, + }; + return immutableCopy( + DurableReasoningExecutionAttemptRecordSchema.parse({ + ...unsigned, + recordFingerprint: createDurableCanonicalJsonSha256Fingerprint(unsigned), + }), + ); +} + +export function createProviderOutcomeRecord(input: { + readonly outcome: ReasoningProviderOutcome; + readonly ledgerSequence: number; + readonly previousAuditFingerprint: string; +}) { + if (verifyReasoningProviderOutcome(input.outcome).status !== "valid") + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + "Provider Outcome does not verify", + ); + const unsigned = { + schemaVersion: "1.0" as const, + recordType: "provider-outcome" as const, + invocationRequestId: input.outcome.invocationRequestId, + executionAttemptId: input.outcome.executionAttemptId, + attemptNumber: input.outcome.attemptNumber, + outcome: input.outcome, + ledgerSequence: input.ledgerSequence, + previousAuditFingerprint: input.previousAuditFingerprint, + committedAt: input.outcome.completedAt, + }; + return immutableCopy( + DurableReasoningProviderOutcomeRecordSchema.parse({ + ...unsigned, + recordFingerprint: createDurableCanonicalJsonSha256Fingerprint(unsigned), + }), + ); +} + +export function createFinalizationRecord(input: { + readonly transactionId: string; + readonly ownership: ReasoningInvocationOwnershipRecord; + readonly resultEnvelope: FinalizedReasoningInvocationTransaction["resultEnvelope"]; + readonly consumptionEvidence: FinalizedReasoningInvocationTransaction["consumptionEvidence"]; + readonly ledgerSequence: number; + readonly previousAuditFingerprint: string; + readonly finalizedAt: string; +}) { + const unsigned = { + schemaVersion: "1.0" as const, + recordType: "finalized-invocation-transaction" as const, + transactionId: input.transactionId, + ownershipId: input.ownership.ownershipId, + invocationIdempotencyKey: input.ownership.invocationIdempotencyKey, + invocationRequestId: input.ownership.invocationRequestId, + invocationRequestFingerprint: input.ownership.invocationRequestFingerprint, + resultEnvelope: input.resultEnvelope, + consumptionEvidence: input.consumptionEvidence, + ledgerSequence: input.ledgerSequence, + previousAuditFingerprint: input.previousAuditFingerprint, + committedAt: input.finalizedAt, + }; + return immutableCopy( + FinalizedReasoningInvocationTransactionSchema.parse({ + ...unsigned, + transactionFingerprint: createDurableCanonicalJsonSha256Fingerprint(unsigned), + }), + ); +} + +export function createReasoningExecutionLedgerEvent( + event: + | { + readonly eventType: "invocation-ownership"; + readonly ownership: ReasoningInvocationOwnershipRecord; + } + | { + readonly eventType: "execution-attempt"; + readonly attemptRecord: ReturnType; + } + | { + readonly eventType: "provider-outcome"; + readonly outcomeRecord: ReturnType; + } + | { + readonly eventType: "invocation-finalization"; + readonly finalization: FinalizedReasoningInvocationTransaction; + }, +): ReasoningExecutionLedgerEvent { + const nested = + event.eventType === "invocation-ownership" + ? event.ownership + : event.eventType === "execution-attempt" + ? event.attemptRecord + : event.eventType === "provider-outcome" + ? event.outcomeRecord + : event.finalization; + const unsigned = { + schemaVersion: "1.0" as const, + ...event, + ledgerSequence: nested.ledgerSequence, + previousAuditFingerprint: nested.previousAuditFingerprint, + }; + return immutableCopy( + ReasoningExecutionLedgerEventSchema.parse({ + ...unsigned, + auditFingerprint: createDurableCanonicalJsonSha256Fingerprint(unsigned), + }), + ); +} + +export function verifyReasoningExecutionLedgerEvent(raw: unknown): ReasoningExecutionLedgerEvent { + if (findDurableCanonicalJsonIssue(raw) !== null) + throw new ReasoningExecutionLedgerIntegrityError( + "invalid_raw_record", + "Execution Ledger event is not accessor-safe canonical data", + ); + const event = ReasoningExecutionLedgerEventSchema.parse(raw); + requireFingerprint(event, "auditFingerprint", "Execution Ledger event"); + if (event.eventType === "invocation-ownership") + requireFingerprint(event.ownership, "ownershipFingerprint", "Invocation ownership"); + else if (event.eventType === "execution-attempt") { + requireFingerprint(event.attemptRecord, "recordFingerprint", "Attempt record"); + if (verifyReasoningExecutionAttempt(event.attemptRecord.attempt).status !== "valid") + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + "Attempt fingerprint does not verify", + ); + } else if (event.eventType === "provider-outcome") { + requireFingerprint(event.outcomeRecord, "recordFingerprint", "Provider Outcome record"); + if (verifyReasoningProviderOutcome(event.outcomeRecord.outcome).status !== "valid") + throw new ReasoningExecutionLedgerIntegrityError( + "fingerprint_mismatch", + "Provider Outcome fingerprint does not verify", + ); + } else if (event.eventType === "invocation-finalization") + requireFingerprint(event.finalization, "transactionFingerprint", "Finalization transaction"); + return immutableCopy(event); +} + +export function replayReasoningExecutionLedger( + rawEvents: readonly unknown[], + rawAuthorities: readonly ReasoningInvocationAuthority[], +): ReasoningExecutionLedgerReplayState { + const events: ReasoningExecutionLedgerEvent[] = []; + const ownershipByKey = new Map(); + const requestsById = new Map(); + const authorityByInvocation = new Map(); + const attemptsByInvocation = new Map(); + const attemptsById = new Map(); + const outcomesByAttemptId = new Map(); + const finalizationsByInvocation = new Map(); + for (const rawAuthority of rawAuthorities) { + if ( + findDurableCanonicalJsonIssue(rawAuthority) !== null || + !Number.isSafeInteger(rawAuthority.contextPackageObjectCount) || + rawAuthority.contextPackageObjectCount < 0 || + verifyReasoningInvocationRequest(rawAuthority.invocationRequest).status !== "valid" || + verifyReasoningProviderCapabilityDescriptor(rawAuthority.providerCapability).status !== + "valid" || + authorityByInvocation.has(rawAuthority.invocationRequest.invocationRequestId) + ) + throw new ReasoningExecutionLedgerIntegrityError( + "invocation_binding_mismatch", + "Invocation authority commitment is invalid or duplicated", + ); + const authority = immutableCopy(rawAuthority); + authorityByInvocation.set(authority.invocationRequest.invocationRequestId, authority); + requestsById.set(authority.invocationRequest.invocationRequestId, authority.invocationRequest); + } + let previous: string = "genesis"; + for (const [index, raw] of rawEvents.entries()) { + const event = verifyReasoningExecutionLedgerEvent(raw); + if (event.ledgerSequence !== index + 1 || event.previousAuditFingerprint !== previous) + throw new ReasoningExecutionLedgerIntegrityError( + "audit_chain_broken", + "Execution Ledger sequence or audit chain is invalid", + ); + if (event.eventType === "invocation-ownership") { + const owner = event.ownership; + const authority = authorityByInvocation.get(owner.invocationRequestId); + if ( + ownershipByKey.has(owner.invocationIdempotencyKey) || + authority === undefined || + authority.invocationRequest.requestFingerprint !== owner.invocationRequestFingerprint || + authority.invocationRequest.idempotencyKey !== owner.invocationIdempotencyKey + ) + throw new ReasoningExecutionLedgerIntegrityError( + "invocation_idempotency_conflict", + "Invocation ownership is duplicated", + ); + ownershipByKey.set(owner.invocationIdempotencyKey, owner); + } else if (event.eventType === "execution-attempt") { + const attempt = event.attemptRecord.attempt; + const owner = ownershipByKey.get(attempt.invocationIdempotencyKey); + const authority = authorityByInvocation.get(attempt.invocationRequestId); + const attempts = attemptsByInvocation.get(attempt.invocationRequestId) ?? []; + const priorOutcomes = attempts.map((entry) => + outcomesByAttemptId.get(entry.executionAttemptId), + ); + if ( + owner === undefined || + authority === undefined || + attempt.providerCapabilityId !== authority.providerCapability.providerCapabilityId || + attempt.providerCapabilityFingerprint !== + authority.providerCapability.descriptorFingerprint || + owner.invocationRequestId !== attempt.invocationRequestId || + owner.invocationRequestFingerprint !== attempt.invocationRequestFingerprint || + finalizationsByInvocation.has(attempt.invocationRequestId) || + attemptsById.has(attempt.executionAttemptId) || + priorOutcomes.some((outcome) => outcome === undefined) || + !verifyReasoningAttemptLifecycle({ + invocationRequest: authority.invocationRequest, + providerCapability: authority.providerCapability, + attempts: [...attempts, attempt], + outcomes: priorOutcomes as ReasoningProviderOutcome[], + }) + ) + throw new ReasoningExecutionLedgerIntegrityError( + "attempt_order_invalid", + "Execution Attempt ordering or ownership is invalid", + ); + attempts.push(attempt); + attemptsByInvocation.set(attempt.invocationRequestId, attempts); + attemptsById.set(attempt.executionAttemptId, attempt); + } else if (event.eventType === "provider-outcome") { + const outcome = event.outcomeRecord.outcome; + const attempt = attemptsById.get(outcome.executionAttemptId); + const authority = authorityByInvocation.get(outcome.invocationRequestId); + const attempts = attemptsByInvocation.get(outcome.invocationRequestId) ?? []; + const candidateOutcomes = attempts.map((entry) => + entry.executionAttemptId === outcome.executionAttemptId + ? outcome + : outcomesByAttemptId.get(entry.executionAttemptId), + ); + if ( + attempt === undefined || + authority === undefined || + outcomesByAttemptId.has(outcome.executionAttemptId) || + attempt.invocationRequestId !== outcome.invocationRequestId || + attempt.attemptNumber !== outcome.attemptNumber || + candidateOutcomes.some((entry) => entry === undefined) || + !verifyReasoningAttemptLifecycle({ + invocationRequest: authority.invocationRequest, + providerCapability: authority.providerCapability, + attempts, + outcomes: candidateOutcomes as ReasoningProviderOutcome[], + }) + ) + throw new ReasoningExecutionLedgerIntegrityError( + "outcome_binding_mismatch", + "Provider Outcome does not bind one open Attempt", + ); + outcomesByAttemptId.set(outcome.executionAttemptId, outcome); + } else if (event.eventType === "invocation-finalization") { + const finalization = event.finalization; + if (finalizationsByInvocation.has(finalization.invocationRequestId)) + throw new ReasoningExecutionLedgerIntegrityError( + "finalization_conflict", + "Invocation has multiple finalizations", + ); + const owner = ownershipByKey.get(finalization.invocationIdempotencyKey); + const attempts = attemptsByInvocation.get(finalization.invocationRequestId) ?? []; + const outcomes = attempts.map((attempt) => + outcomesByAttemptId.get(attempt.executionAttemptId), + ); + if ( + owner === undefined || + owner.ownershipId !== finalization.ownershipId || + outcomes.some((outcome) => outcome === undefined) + ) + throw new ReasoningExecutionLedgerIntegrityError( + "finalization_incomplete", + "Finalization lacks complete ownership or Attempt outcomes", + ); + const authority = authorityByInvocation.get(finalization.invocationRequestId); + const finalAttempt = attempts.at(-1)!; + const finalOutcome = outcomes.at(-1)!; + if ( + authority === undefined || + finalization.resultEnvelope.executionAttemptId !== finalAttempt.executionAttemptId || + finalization.resultEnvelope.resultEnvelopeFingerprint !== + finalization.consumptionEvidence.finalResultEnvelopeFingerprint || + finalization.resultEnvelope.outcome !== finalOutcome!.status || + finalization.resultEnvelope.invocationRequestFingerprint !== + authority.invocationRequest.requestFingerprint || + finalization.resultEnvelope.deliveryTransactionId !== + authority.invocationRequest.deliveryTransactionId || + finalization.resultEnvelope.executionPolicyFingerprint !== + authority.invocationRequest.executionPolicy.policyFingerprint + ) + throw new ReasoningExecutionLedgerIntegrityError( + "finalization_incomplete", + "Final Result Envelope does not verify against recorded execution", + ); + if ( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: finalization.consumptionEvidence, + resultEnvelope: finalization.resultEnvelope, + invocationRequest: authority.invocationRequest, + providerCapability: authority.providerCapability, + attempts, + outcomes: outcomes as ReasoningProviderOutcome[], + contextPackageObjectCount: authority.contextPackageObjectCount, + executionLedgerTransactionId: finalization.transactionId, + }).status !== "valid" + ) + throw new ReasoningExecutionLedgerIntegrityError( + "finalization_incomplete", + "Finalized Consumption Evidence does not verify", + ); + finalizationsByInvocation.set(finalization.invocationRequestId, finalization); + } else { + // Checkpoints are verified by their schema and audit chain and carry no replay authority. + } + previous = event.auditFingerprint; + events.push(event); + } + if (authorityByInvocation.size !== ownershipByKey.size) + throw new ReasoningExecutionLedgerIntegrityError( + "invocation_binding_mismatch", + "Invocation authority commitment has no matching ownership event", + ); + return immutableCopy({ + events, + ownershipByKey, + requestsById, + authorityByInvocation, + attemptsByInvocation, + attemptsById, + outcomesByAttemptId, + finalizationsByInvocation, + lastSequence: events.length, + lastAuditFingerprint: previous, + executionEvidenceFingerprint: createDurableCanonicalJsonSha256Fingerprint(events), + }); +} + +export function createReasoningExecutionDerivedIndex( + state: ReasoningExecutionLedgerReplayState, + entryCapacity = 10_000, +): DurableReasoningExecutionDerivedIndex { + const invocationEntries = [...state.ownershipByKey.entries()] + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .slice(-entryCapacity) + .map(([key, owner]) => { + const finalization = state.finalizationsByInvocation.get(owner.invocationRequestId); + return { + invocationIdempotencyKey: key, + ownershipId: owner.ownershipId, + invocationRequestId: owner.invocationRequestId, + invocationRequestFingerprint: owner.invocationRequestFingerprint, + status: finalization === undefined ? ("in-progress" as const) : ("finalized" as const), + finalizationTransactionId: finalization?.transactionId ?? null, + }; + }); + const attemptEntries = [...state.attemptsById.values()] + .sort((a, b) => + a.invocationRequestId === b.invocationRequestId + ? a.attemptNumber - b.attemptNumber + : a.invocationRequestId < b.invocationRequestId + ? -1 + : 1, + ) + .slice(-entryCapacity) + .map((attempt) => ({ + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: attempt.invocationRequestId, + attemptNumber: attempt.attemptNumber, + outcomeFingerprint: + state.outcomesByAttemptId.get(attempt.executionAttemptId)?.outcomeFingerprint ?? null, + })); + const resultEntries = [...state.finalizationsByInvocation.values()] + .sort((a, b) => (a.invocationRequestId < b.invocationRequestId ? -1 : 1)) + .slice(-entryCapacity) + .map((finalization) => ({ + invocationRequestId: finalization.invocationRequestId, + resultEnvelopeId: finalization.resultEnvelope.resultEnvelopeId, + resultEnvelopeFingerprint: finalization.resultEnvelope.resultEnvelopeFingerprint, + consumptionId: finalization.consumptionEvidence.consumptionId, + })); + const unsigned = { + schemaVersion: "1.0" as const, + retentionPolicyVersion: "bounded-latest-v1" as const, + entryCapacity, + verifiedThroughSequence: state.lastSequence, + verifiedAuditFingerprint: state.lastAuditFingerprint, + invocationEntries, + attemptEntries, + resultEntries, + }; + return immutableCopy( + DurableReasoningExecutionDerivedIndexSchema.parse({ + ...unsigned, + indexFingerprint: createDurableCanonicalJsonSha256Fingerprint(unsigned), + }), + ); +} + +function indexStatus( + raw: unknown, + state: ReasoningExecutionLedgerReplayState, +): "current" | "invalid" | "missing" | "stale" { + if (raw === null || raw === undefined) return "missing"; + const parsed = DurableReasoningExecutionDerivedIndexSchema.safeParse(raw); + if (!parsed.success) return "invalid"; + try { + requireFingerprint(parsed.data, "indexFingerprint", "Execution derived index"); + } catch { + return "invalid"; + } + if ( + parsed.data.verifiedThroughSequence !== state.lastSequence || + parsed.data.verifiedAuditFingerprint !== state.lastAuditFingerprint + ) + return "stale"; + const expected = createReasoningExecutionDerivedIndex(state, parsed.data.entryCapacity); + return expected.indexFingerprint === parsed.data.indexFingerprint ? "current" : "invalid"; +} + +export function recoverReasoningExecutionLedger( + events: readonly unknown[], + authorities: readonly ReasoningInvocationAuthority[], + derivedIndex: unknown, +): ReasoningExecutionLedgerRecoveryResult { + try { + const state = replayReasoningExecutionLedger(events, authorities); + const status = indexStatus(derivedIndex, state); + const counts = countState(state); + return ReasoningExecutionLedgerRecoveryResultSchema.parse({ + schemaVersion: "1.0", + ledgerContractVersion: "1.0", + status: "recovered", + ...counts, + derivedIndexStatus: status === "current" ? "current" : "rebuilt", + executionEvidenceFingerprint: state.executionEvidenceFingerprint, + errors: [], + }); + } catch { + return ReasoningExecutionLedgerRecoveryResultSchema.parse({ + schemaVersion: "1.0", + ledgerContractVersion: "1.0", + status: "failed", + invocationOwnershipCount: 0, + executionAttemptCount: 0, + providerOutcomeCount: 0, + finalizedInvocationCount: 0, + finalizedConsumptionCount: 0, + integrityCheckpointCount: 0, + lastCommittedLedgerSequence: 0, + lastAuditFingerprint: "genesis", + derivedIndexStatus: "invalid", + executionEvidenceFingerprint: null, + errors: [ + { + code: "invalid_raw_record", + logicalLocation: "authoritative-ledger", + message: "Reasoning Execution Ledger recovery failed", + }, + ], + }); + } +} + +export function verifyReasoningExecutionLedgerIntegrity( + events: readonly unknown[], + authorities: readonly ReasoningInvocationAuthority[], + derivedIndex: unknown, +): ReasoningExecutionLedgerIntegrityVerificationResult { + try { + const state = replayReasoningExecutionLedger(events, authorities); + const counts = countState(state); + return ReasoningExecutionLedgerIntegrityVerificationResultSchema.parse({ + schemaVersion: "1.0", + status: "valid", + verifiedEventCount: state.lastSequence, + verifiedInvocationCount: counts.invocationOwnershipCount, + verifiedAttemptCount: counts.executionAttemptCount, + verifiedOutcomeCount: counts.providerOutcomeCount, + verifiedFinalizationCount: counts.finalizedInvocationCount, + verifiedThroughSequence: state.lastSequence, + lastAuditFingerprint: state.lastAuditFingerprint, + executionEvidenceFingerprint: state.executionEvidenceFingerprint, + derivedIndexStatus: indexStatus(derivedIndex, state), + issues: [], + }); + } catch { + return ReasoningExecutionLedgerIntegrityVerificationResultSchema.parse({ + schemaVersion: "1.0", + status: "invalid", + verifiedEventCount: 0, + verifiedInvocationCount: 0, + verifiedAttemptCount: 0, + verifiedOutcomeCount: 0, + verifiedFinalizationCount: 0, + verifiedThroughSequence: 0, + lastAuditFingerprint: "genesis", + executionEvidenceFingerprint: null, + derivedIndexStatus: "invalid", + issues: [ + { + code: "invalid_raw_record", + logicalLocation: "authoritative-ledger", + message: "Reasoning Execution Ledger integrity verification failed", + }, + ], + }); + } +} + +function countState(state: ReasoningExecutionLedgerReplayState) { + const integrityCheckpointCount = state.events.filter( + (event) => event.eventType === "integrity-checkpoint", + ).length; + return { + invocationOwnershipCount: state.ownershipByKey.size, + executionAttemptCount: state.attemptsById.size, + providerOutcomeCount: state.outcomesByAttemptId.size, + finalizedInvocationCount: state.finalizationsByInvocation.size, + finalizedConsumptionCount: state.finalizationsByInvocation.size, + integrityCheckpointCount, + lastCommittedLedgerSequence: state.lastSequence, + lastAuditFingerprint: state.lastAuditFingerprint, + }; +} diff --git a/services/knowledge-engine/src/domain/reasoning.ts b/services/knowledge-engine/src/domain/reasoning.ts new file mode 100644 index 0000000..df9ae04 --- /dev/null +++ b/services/knowledge-engine/src/domain/reasoning.ts @@ -0,0 +1,1144 @@ +import { + FinalizedReasoningConsumptionEvidenceSchema, + ProviderNeutralReasoningInputSchema, + ReasoningArtifactVerificationResultSchema, + ReasoningCancellationEvidenceSchema, + ReasoningConstraintBlockSchema, + ReasoningCostEvidenceSchema, + ReasoningExecutionAttemptSchema, + ReasoningExecutionPolicySchema, + ReasoningExecutionReceiptSchema, + ReasoningFailureEvidenceSchema, + ReasoningInstructionBlockSchema, + ReasoningInvocationRequestSchema, + ReasoningProviderCapabilityDescriptorSchema, + ReasoningProviderCapabilityRequirementsSchema, + ReasoningProviderCompatibilityResultSchema, + ReasoningProviderOutcomeSchema, + ReasoningResultEnvelopeSchema, + ReasoningTimeoutEvidenceSchema, + ReasoningUsageEvidenceSchema, + findDurableCanonicalJsonIssue, + type FinalizedReasoningConsumptionEvidence, + type DurableCanonicalJsonValue, + type ProviderNeutralReasoningInput, + type ReasoningArtifactVerificationResult, + type ReasoningCancellationEvidence, + type ReasoningConstraintBlock, + type ReasoningCostEvidence, + type ReasoningExecutionAttempt, + type ReasoningExecutionPolicy, + type ReasoningExecutionReceipt, + type ReasoningFailureEvidence, + type ReasoningInstructionBlock, + type ReasoningInvocationRequest, + type ReasoningProviderCapabilityDescriptor, + type ReasoningProviderCapabilityRequirements, + type ReasoningProviderCompatibilityResult, + type ReasoningProviderOutcome, + type ReasoningResultEnvelope, + type ReasoningTimeoutEvidence, + type ReasoningUsageEvidence, +} from "@founderos/knowledge-schema"; + +import { + createDurableCanonicalJsonSha256Fingerprint, + serializeDurableCanonicalJsonValue, +} from "./canonical-fingerprint.js"; +import { deepFreeze } from "./snapshot-lifecycle.js"; + +type CanonicalRecord = Readonly>; +type VerificationArtifact = Parameters[0]; +type Schema = { parse(input: unknown): T }; +type DistributiveOmit = T extends unknown ? Omit : never; + +export class ReasoningIntegrityError extends Error { + public constructor( + public readonly code: + | "binding_mismatch" + | "budget_exceeded" + | "capability_mismatch" + | "fingerprint_mismatch" + | "invalid_artifact" + | "unsafe_content", + message: string, + ) { + super(message); + this.name = "ReasoningIntegrityError"; + } +} + +function immutableCopy(value: T): T { + return deepFreeze(structuredClone(value)); +} + +function without(value: CanonicalRecord, field: string): CanonicalRecord { + return Object.fromEntries(Object.entries(value).filter(([key]) => key !== field)); +} + +function captureCanonical(value: unknown, label: string): CanonicalRecord { + if (findDurableCanonicalJsonIssue(value) !== null || value === null || Array.isArray(value)) { + throw new ReasoningIntegrityError( + "invalid_artifact", + `${label} must contain only accessor-free canonical data`, + ); + } + return immutableCopy(value as CanonicalRecord); +} + +function signed(schema: Schema, unsignedInput: unknown, fingerprintField: string): T { + const unsigned = captureCanonical(unsignedInput, "Reasoning artifact"); + return immutableCopy( + schema.parse({ + ...unsigned, + [fingerprintField]: createDurableCanonicalJsonSha256Fingerprint(unsigned), + }), + ); +} + +function verifySigned( + artifactType: ReasoningArtifactVerificationResult["artifactType"], + schema: Schema, + raw: unknown, + fingerprintField: string, +): ReasoningArtifactVerificationResult { + try { + const canonical = captureCanonical(raw, artifactType); + const parsed = schema.parse(canonical) as T & CanonicalRecord; + const stored = parsed[fingerprintField]; + const expected = createDurableCanonicalJsonSha256Fingerprint(without(parsed, fingerprintField)); + if (stored !== expected) { + return invalidVerification(artifactType, "fingerprint_mismatch", fingerprintField); + } + return ReasoningArtifactVerificationResultSchema.parse({ + schemaVersion: "1.0", + artifactType, + status: "valid", + fingerprint: stored, + issues: [], + }); + } catch (error) { + const code = + error instanceof ReasoningIntegrityError ? "noncanonical_value" : "invalid_artifact"; + return invalidVerification(artifactType, code, "artifact"); + } +} + +function invalidVerification( + artifactType: ReasoningArtifactVerificationResult["artifactType"], + code: "budget_exceeded" | "fingerprint_mismatch" | "invalid_artifact" | "noncanonical_value", + path: string, +): ReasoningArtifactVerificationResult { + return ReasoningArtifactVerificationResultSchema.parse({ + schemaVersion: "1.0", + artifactType, + status: "invalid", + fingerprint: null, + issues: [{ code, path, message: "Reasoning artifact verification failed" }], + } satisfies VerificationArtifact); +} + +export function countCanonicalCharacters(value: unknown): number { + return [...serializeDurableCanonicalJsonValue(value)].length; +} + +export type ReasoningInstructionBlockInput = Omit; +export function createReasoningInstructionBlock( + input: ReasoningInstructionBlockInput, +): ReasoningInstructionBlock { + return signed(ReasoningInstructionBlockSchema, input, "blockFingerprint"); +} + +export type ReasoningConstraintBlockInput = Omit; +export function createReasoningConstraintBlock( + input: ReasoningConstraintBlockInput, +): ReasoningConstraintBlock { + return signed(ReasoningConstraintBlockSchema, input, "constraintFingerprint"); +} + +export type ProviderNeutralReasoningInputInput = Omit< + ProviderNeutralReasoningInput, + "inputFingerprint" +>; +export function createProviderNeutralReasoningInput( + input: ProviderNeutralReasoningInputInput, +): ProviderNeutralReasoningInput { + for (const block of input.instructionBlocks) { + if ( + verifySigned("reasoning-input", ReasoningInstructionBlockSchema, block, "blockFingerprint") + .status !== "valid" + ) + throw new ReasoningIntegrityError( + "fingerprint_mismatch", + "Instruction Block does not verify", + ); + } + for (const block of input.constraintBlocks) { + if ( + verifySigned( + "reasoning-input", + ReasoningConstraintBlockSchema, + block, + "constraintFingerprint", + ).status !== "valid" + ) + throw new ReasoningIntegrityError("fingerprint_mismatch", "Constraint Block does not verify"); + } + return signed(ProviderNeutralReasoningInputSchema, input, "inputFingerprint"); +} + +export type ReasoningExecutionPolicyInput = Omit; +export function createReasoningExecutionPolicy( + input: ReasoningExecutionPolicyInput, +): ReasoningExecutionPolicy { + return signed(ReasoningExecutionPolicySchema, input, "policyFingerprint"); +} + +export type ReasoningProviderCapabilityRequirementsInput = Omit< + ReasoningProviderCapabilityRequirements, + "requirementsFingerprint" +>; +export function createReasoningProviderCapabilityRequirements( + input: ReasoningProviderCapabilityRequirementsInput, +): ReasoningProviderCapabilityRequirements { + return signed(ReasoningProviderCapabilityRequirementsSchema, input, "requirementsFingerprint"); +} + +export type ReasoningProviderCapabilityDescriptorInput = Omit< + ReasoningProviderCapabilityDescriptor, + "descriptorFingerprint" +>; +export function createReasoningProviderCapabilityDescriptor( + input: ReasoningProviderCapabilityDescriptorInput, +): ReasoningProviderCapabilityDescriptor { + return signed(ReasoningProviderCapabilityDescriptorSchema, input, "descriptorFingerprint"); +} + +export function verifyProviderNeutralReasoningInput(raw: unknown) { + return verifySigned( + "reasoning-input", + ProviderNeutralReasoningInputSchema, + raw, + "inputFingerprint", + ); +} +export function verifyReasoningExecutionPolicy(raw: unknown) { + return verifySigned("execution-policy", ReasoningExecutionPolicySchema, raw, "policyFingerprint"); +} +export function verifyReasoningProviderCapabilityDescriptor(raw: unknown) { + return verifySigned( + "provider-capability-descriptor", + ReasoningProviderCapabilityDescriptorSchema, + raw, + "descriptorFingerprint", + ); +} + +const REASON_FIELD = { + cancellation_mode_unsupported: "cancellationMode", + cost_evidence_unsupported: "costEvidenceRequired", + delivery_envelope_version_unsupported: "deliveryEnvelopeVersion", + deterministic_mode_unsupported: "deterministicModeRequired", + failure_evidence_unsupported: "failureEvidenceRequired", + input_budget_exceeded: "inputCharacters", + input_content_type_unsupported: "inputContentType", + invocation_version_unsupported: "invocationRequestVersion", + output_budget_exceeded: "maxOutputCharacters", + output_content_type_unsupported: "outputContentType", + provider_class_unsupported: "providerClass", + result_envelope_version_unsupported: "resultEnvelopeVersion", + retry_mode_unsupported: "retryMode", + timeout_out_of_range: "timeoutMilliseconds", + usage_evidence_unsupported: "usageEvidenceRequired", +} as const; + +type MismatchReason = keyof typeof REASON_FIELD; + +export function matchReasoningProviderCapabilities(input: { + readonly invocationRequest: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; +}): ReasoningProviderCompatibilityResult { + const request = ReasoningInvocationRequestSchema.parse( + captureCanonical(input.invocationRequest, "Invocation Request"), + ); + const provider = ReasoningProviderCapabilityDescriptorSchema.parse( + captureCanonical(input.providerCapability, "Provider Capability"), + ); + if (verifyReasoningInvocationRequest(request).status !== "valid") + throw new ReasoningIntegrityError("fingerprint_mismatch", "Invocation Request does not verify"); + if (verifyReasoningProviderCapabilityDescriptor(provider).status !== "valid") + throw new ReasoningIntegrityError( + "fingerprint_mismatch", + "Provider Capability does not verify", + ); + + const policy = request.executionPolicy; + const requirements = request.capabilityRequirements; + const reasons: MismatchReason[] = []; + const add = (condition: boolean, reason: MismatchReason) => { + if (condition) reasons.push(reason); + }; + const inputCharacters = countCanonicalCharacters(request.reasoningInput); + add( + !provider.acceptedInvocationRequestVersions.includes(request.schemaVersion), + "invocation_version_unsupported", + ); + add( + !provider.acceptedDeliveryEnvelopeVersions.includes(request.deliveryEnvelopeVersion), + "delivery_envelope_version_unsupported", + ); + add( + !provider.acceptedInputContentTypes.includes(request.reasoningInput.contentType), + "input_content_type_unsupported", + ); + add( + inputCharacters > provider.maxInputCharacters || inputCharacters > policy.maxInputCharacters, + "input_budget_exceeded", + ); + add(policy.maxOutputCharacters > provider.maxOutputCharacters, "output_budget_exceeded"); + add( + !provider.acceptedOutputContentTypes.includes( + request.reasoningInput.outputRequirements.contentType, + ), + "output_content_type_unsupported", + ); + add( + !requirements.acceptedProviderClasses.includes(provider.providerClass), + "provider_class_unsupported", + ); + add( + policy.timeoutMilliseconds < provider.minTimeoutMilliseconds || + policy.timeoutMilliseconds > provider.maxTimeoutMilliseconds, + "timeout_out_of_range", + ); + add( + !provider.supportedCancellationModes.includes(policy.cancellationMode), + "cancellation_mode_unsupported", + ); + add(!provider.supportedRetryModes.includes(policy.retryMode), "retry_mode_unsupported"); + add( + requirements.deterministicModeRequired && !provider.supportsDeterministicExecution, + "deterministic_mode_unsupported", + ); + add( + requirements.usageEvidenceRequired && !provider.supportsUsageEvidence, + "usage_evidence_unsupported", + ); + add( + requirements.costEvidenceRequired && !provider.supportsCostEvidence, + "cost_evidence_unsupported", + ); + add( + requirements.failureEvidenceRequired && !provider.supportsFailureEvidence, + "failure_evidence_unsupported", + ); + add( + !provider.supportedResultEnvelopeVersions.includes(requirements.resultEnvelopeVersion), + "result_envelope_version_unsupported", + ); + const orderedReasons = [...new Set(reasons)].sort(); + const unsigned = { + schemaVersion: "1.0" as const, + status: orderedReasons.length === 0 ? ("compatible" as const) : ("incompatible" as const), + reasonCodes: orderedReasons.length === 0 ? (["compatible"] as const) : orderedReasons, + mismatchedFields: + orderedReasons.length === 0 + ? [] + : [...new Set(orderedReasons.map((reason) => REASON_FIELD[reason]))].sort(), + invocationRequestFingerprint: request.requestFingerprint, + reasoningInputFingerprint: request.reasoningInput.inputFingerprint, + executionPolicyFingerprint: policy.policyFingerprint, + providerCapabilityFingerprint: provider.descriptorFingerprint, + }; + return signed(ReasoningProviderCompatibilityResultSchema, unsigned, "compatibilityFingerprint"); +} + +export function verifyReasoningProviderCompatibilityResult(input: { + readonly compatibility: unknown; + readonly invocationRequest: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; +}): ReasoningArtifactVerificationResult { + let wrapper: CanonicalRecord; + try { + wrapper = captureCanonical(input, "Compatibility verification input"); + } catch { + return invalidVerification("compatibility-result", "invalid_artifact", "compatibility"); + } + const basic = verifySigned( + "compatibility-result", + ReasoningProviderCompatibilityResultSchema, + wrapper.compatibility, + "compatibilityFingerprint", + ); + if (basic.status !== "valid") return basic; + try { + const invocationRequest = ReasoningInvocationRequestSchema.parse(wrapper.invocationRequest); + const providerCapability = ReasoningProviderCapabilityDescriptorSchema.parse( + wrapper.providerCapability, + ); + const expected = matchReasoningProviderCapabilities({ + invocationRequest, + providerCapability, + }); + const actual = captureCanonical(wrapper.compatibility, "Compatibility Result"); + if (JSON.stringify(actual) !== JSON.stringify(expected)) + return invalidVerification("compatibility-result", "fingerprint_mismatch", "compatibility"); + return basic; + } catch { + return invalidVerification("compatibility-result", "invalid_artifact", "compatibility"); + } +} + +export type ReasoningInvocationRequestInput = Omit< + ReasoningInvocationRequest, + "requestFingerprint" +>; +export function createReasoningInvocationRequest( + input: ReasoningInvocationRequestInput, +): ReasoningInvocationRequest { + if ( + verifyProviderNeutralReasoningInput(input.reasoningInput).status !== "valid" || + verifyReasoningExecutionPolicy(input.executionPolicy).status !== "valid" + ) + throw new ReasoningIntegrityError( + "fingerprint_mismatch", + "Invocation nested artifacts do not verify", + ); + const requirements = verifySigned( + "invocation-request", + ReasoningProviderCapabilityRequirementsSchema, + input.capabilityRequirements, + "requirementsFingerprint", + ); + if (requirements.status !== "valid") + throw new ReasoningIntegrityError( + "fingerprint_mismatch", + "Capability Requirements do not verify", + ); + return signed(ReasoningInvocationRequestSchema, input, "requestFingerprint"); +} + +export function verifyReasoningInvocationRequest(raw: unknown) { + const basic = verifySigned( + "invocation-request", + ReasoningInvocationRequestSchema, + raw, + "requestFingerprint", + ); + if (basic.status !== "valid") return basic; + const request = raw as ReasoningInvocationRequest; + if ( + verifyProviderNeutralReasoningInput(request.reasoningInput).status !== "valid" || + verifyReasoningExecutionPolicy(request.executionPolicy).status !== "valid" || + verifySigned( + "invocation-request", + ReasoningProviderCapabilityRequirementsSchema, + request.capabilityRequirements, + "requirementsFingerprint", + ).status !== "valid" + ) + return invalidVerification("invocation-request", "fingerprint_mismatch", "nested-artifact"); + return basic; +} + +export type ReasoningExecutionAttemptInput = Omit; +export function createReasoningExecutionAttempt(input: ReasoningExecutionAttemptInput) { + return signed(ReasoningExecutionAttemptSchema, input, "attemptFingerprint"); +} +export function verifyReasoningExecutionAttempt(raw: unknown) { + return verifySigned( + "execution-attempt", + ReasoningExecutionAttemptSchema, + raw, + "attemptFingerprint", + ); +} + +export type ReasoningFailureEvidenceInput = Omit; +export function createReasoningFailureEvidence(input: ReasoningFailureEvidenceInput) { + return signed(ReasoningFailureEvidenceSchema, input, "failureFingerprint"); +} +export function verifyReasoningFailureEvidence(raw: unknown) { + return verifySigned( + "failure-evidence", + ReasoningFailureEvidenceSchema, + raw, + "failureFingerprint", + ); +} +export type ReasoningTimeoutEvidenceInput = Omit; +export function createReasoningTimeoutEvidence(input: ReasoningTimeoutEvidenceInput) { + return signed(ReasoningTimeoutEvidenceSchema, input, "timeoutFingerprint"); +} +export function verifyReasoningTimeoutEvidence(raw: unknown) { + return verifySigned( + "timeout-evidence", + ReasoningTimeoutEvidenceSchema, + raw, + "timeoutFingerprint", + ); +} +export type ReasoningCancellationEvidenceInput = Omit< + ReasoningCancellationEvidence, + "cancellationFingerprint" +>; +export function createReasoningCancellationEvidence(input: ReasoningCancellationEvidenceInput) { + return signed(ReasoningCancellationEvidenceSchema, input, "cancellationFingerprint"); +} +export function verifyReasoningCancellationEvidence(raw: unknown) { + return verifySigned( + "cancellation-evidence", + ReasoningCancellationEvidenceSchema, + raw, + "cancellationFingerprint", + ); +} +export type ReasoningExecutionReceiptInput = Omit; +export function createReasoningExecutionReceipt(input: ReasoningExecutionReceiptInput) { + return signed(ReasoningExecutionReceiptSchema, input, "receiptFingerprint"); +} +export function verifyReasoningExecutionReceipt(raw: unknown) { + return verifySigned( + "execution-receipt", + ReasoningExecutionReceiptSchema, + raw, + "receiptFingerprint", + ); +} +export type ReasoningUsageEvidenceInput = Omit; +export function createReasoningUsageEvidence(input: ReasoningUsageEvidenceInput) { + return signed(ReasoningUsageEvidenceSchema, input, "usageFingerprint"); +} +export function verifyReasoningUsageEvidence(raw: unknown) { + return verifySigned("usage-evidence", ReasoningUsageEvidenceSchema, raw, "usageFingerprint"); +} +export type ReasoningCostEvidenceInput = Omit; +export function createReasoningCostEvidence(input: ReasoningCostEvidenceInput) { + return signed(ReasoningCostEvidenceSchema, input, "costFingerprint"); +} +export function verifyReasoningCostEvidence(raw: unknown) { + return verifySigned("cost-evidence", ReasoningCostEvidenceSchema, raw, "costFingerprint"); +} + +export type ReasoningProviderOutcomeInput = DistributiveOmit< + ReasoningProviderOutcome, + "outcomeFingerprint" +>; +export function createReasoningProviderOutcome(input: ReasoningProviderOutcomeInput) { + if ("outputContentFingerprint" in input) { + const expected = createDurableCanonicalJsonSha256Fingerprint(input.outputContent); + if (input.outputContentFingerprint !== expected) + throw new ReasoningIntegrityError( + "fingerprint_mismatch", + "Provider output fingerprint does not verify", + ); + } + return signed(ReasoningProviderOutcomeSchema, input, "outcomeFingerprint"); +} +export function verifyReasoningProviderOutcome(raw: unknown) { + const basic = verifySigned( + "provider-outcome", + ReasoningProviderOutcomeSchema, + raw, + "outcomeFingerprint", + ); + if (basic.status !== "valid") return basic; + const outcome = raw as ReasoningProviderOutcome; + if (outcome.status === "succeeded") { + if ( + outcome.outputContentFingerprint !== + createDurableCanonicalJsonSha256Fingerprint(outcome.outputContent) + ) + return invalidVerification( + "provider-outcome", + "fingerprint_mismatch", + "outputContentFingerprint", + ); + } else { + const verification = + outcome.status === "failed" + ? verifyReasoningFailureEvidence(outcome.failureEvidence) + : outcome.status === "timed-out" + ? verifyReasoningTimeoutEvidence(outcome.timeoutEvidence) + : verifyReasoningCancellationEvidence(outcome.cancellationEvidence); + if (verification.status !== "valid") + return invalidVerification("provider-outcome", "fingerprint_mismatch", "terminal-evidence"); + } + return basic; +} + +export function isReasoningRetryTransitionAuthorized( + outcome: ReasoningProviderOutcome, + policy: ReasoningExecutionPolicy, + completedAttemptCount: number, +): boolean { + if ( + completedAttemptCount >= policy.maxAttemptCount || + outcome.status === "succeeded" || + outcome.status === "cancelled" || + policy.retryMode === "no-retry" + ) + return false; + if (policy.retryMode === "evaluation-only-retry") + return outcome.status === "failed" || outcome.status === "timed-out"; + if (policy.retryMode === "retry-until-attempt-limit") + return outcome.status === "failed" || outcome.status === "timed-out"; + return outcome.status === "failed" && outcome.failureEvidence.retryable; +} + +export function verifyReasoningAttemptLifecycle(input: { + readonly invocationRequest: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly attempts: readonly ReasoningExecutionAttempt[]; + readonly outcomes: readonly ReasoningProviderOutcome[]; +}): boolean { + const { invocationRequest: request, providerCapability: provider, attempts, outcomes } = input; + if ( + attempts.length === 0 || + attempts.length > request.executionPolicy.maxAttemptCount || + outcomes.length > attempts.length || + outcomes.length < attempts.length - 1 + ) + return false; + for (const [index, attempt] of attempts.entries()) { + const deadlineAt = attempt.deadlineAt; + const started = Date.parse(attempt.startedAt); + const deadline = deadlineAt === undefined ? Number.NaN : Date.parse(deadlineAt); + const priorOutcome = index === 0 ? undefined : outcomes[index - 1]; + const expectedCancellationState = { + "not-cancellable": "not-requested", + "cancel-before-execution": "requested-before-execution", + "cooperative-cancellation": "requested-cooperatively", + "deadline-cancellation": "requested-at-deadline", + } as const; + if ( + verifyReasoningExecutionAttempt(attempt).status !== "valid" || + attempt.attemptNumber !== index + 1 || + attempt.invocationRequestId !== request.invocationRequestId || + attempt.invocationRequestFingerprint !== request.requestFingerprint || + attempt.invocationIdempotencyKey !== request.idempotencyKey || + attempt.providerCapabilityId !== provider.providerCapabilityId || + attempt.providerCapabilityFingerprint !== provider.descriptorFingerprint || + attempt.executionPolicyFingerprint !== request.executionPolicy.policyFingerprint || + deadlineAt === undefined || + deadline - started !== request.executionPolicy.timeoutMilliseconds || + (attempt.cancellationState !== "not-requested" && + attempt.cancellationState !== + expectedCancellationState[request.executionPolicy.cancellationMode]) || + (index === 0 + ? started < Date.parse(request.requestedAt) + : priorOutcome === undefined || started < Date.parse(priorOutcome.completedAt)) || + (index === 0 + ? attempt.previousExecutionAttemptId !== undefined + : attempt.previousExecutionAttemptId !== attempts[index - 1]!.executionAttemptId) + ) + return false; + if (attempt.cancellationState !== "not-requested") { + const requested = Date.parse(attempt.cancellationRequestedAt!); + const observed = Date.parse(attempt.cancellationObservedAt!); + const cancellationPhaseIsValid = + attempt.cancellationState === "requested-before-execution" + ? requested <= observed && observed <= started + : attempt.cancellationState === "requested-cooperatively" + ? requested >= started && requested <= observed + : requested === deadline && observed >= deadline; + if (!cancellationPhaseIsValid) return false; + } + const outcome = outcomes[index]; + if ( + outcome !== undefined && + (verifyReasoningProviderOutcome(outcome).status !== "valid" || + outcome.executionAttemptId !== attempt.executionAttemptId || + outcome.invocationRequestId !== request.invocationRequestId || + outcome.attemptNumber !== attempt.attemptNumber) + ) + return false; + if (outcome !== undefined) { + const completed = Date.parse(outcome.completedAt); + if (completed < started) return false; + if (outcome.status === "succeeded" || outcome.status === "failed") { + if (completed >= deadline || attempt.cancellationState !== "not-requested") return false; + } else if (outcome.status === "timed-out") { + const evidence = outcome.timeoutEvidence; + if ( + completed < deadline || + (attempt.cancellationState !== "not-requested" && + attempt.cancellationState !== "requested-cooperatively") || + (attempt.cancellationState === "requested-cooperatively" && + (Date.parse(attempt.cancellationObservedAt!) < deadline || + Date.parse(attempt.cancellationObservedAt!) > completed)) || + evidence.configuredTimeoutMilliseconds !== request.executionPolicy.timeoutMilliseconds || + evidence.attemptStartedAt !== attempt.startedAt || + evidence.deadlineAt !== deadlineAt || + evidence.elapsedMilliseconds !== completed - started || + evidence.timeoutPhase !== "during-execution" || + evidence.reasonCode !== "execution_deadline_reached" + ) + return false; + } else { + const evidence = outcome.cancellationEvidence; + const state = attempt.cancellationState; + const observed = Date.parse(evidence.observedAt); + const exactCancellationBinding = + state !== "not-requested" && + evidence.cancellationMode === request.executionPolicy.cancellationMode && + evidence.cancellationAuthorityReference === attempt.cancellationAuthorityReference && + evidence.requestedAt === attempt.cancellationRequestedAt && + evidence.observedAt === attempt.cancellationObservedAt && + observed <= completed; + const phaseTiming = + state === "requested-before-execution" + ? true + : state === "requested-cooperatively" + ? observed < deadline + : state === "requested-at-deadline" + ? completed >= deadline + : false; + if (!exactCancellationBinding || !phaseTiming) return false; + } + } + if ( + index > 0 && + !isReasoningRetryTransitionAuthorized(outcomes[index - 1]!, request.executionPolicy, index) + ) + return false; + } + return true; +} + +export type ReasoningResultEnvelopeInput = DistributiveOmit< + ReasoningResultEnvelope, + "resultEnvelopeFingerprint" +>; +export function createReasoningResultEnvelope(input: ReasoningResultEnvelopeInput) { + if ( + verifyReasoningExecutionReceipt(input.executionReceipt).status !== "valid" || + verifyReasoningUsageEvidence(input.usageEvidence).status !== "valid" || + verifyReasoningCostEvidence(input.costEvidence).status !== "valid" + ) + throw new ReasoningIntegrityError( + "fingerprint_mismatch", + "Result operational evidence does not verify", + ); + if (input.outcome === "succeeded") { + if (input.outputCharacterCount !== countOutputCharacters(input.outputContent)) + throw new ReasoningIntegrityError( + "budget_exceeded", + "Result output character evidence is invalid", + ); + if ( + input.outputContentFingerprint !== + createDurableCanonicalJsonSha256Fingerprint(input.outputContent) + ) + throw new ReasoningIntegrityError( + "fingerprint_mismatch", + "Result output fingerprint does not verify", + ); + } + return signed(ReasoningResultEnvelopeSchema, input, "resultEnvelopeFingerprint"); +} + +export function verifyReasoningResultEnvelopeArtifact(raw: unknown) { + const basic = verifySigned( + "result-envelope", + ReasoningResultEnvelopeSchema, + raw, + "resultEnvelopeFingerprint", + ); + if (basic.status !== "valid") return basic; + const result = raw as ReasoningResultEnvelope; + if ( + verifyReasoningExecutionReceipt(result.executionReceipt).status !== "valid" || + verifyReasoningUsageEvidence(result.usageEvidence).status !== "valid" || + verifyReasoningCostEvidence(result.costEvidence).status !== "valid" + ) + return invalidVerification("result-envelope", "fingerprint_mismatch", "operational-evidence"); + if (result.outcome === "succeeded") { + if ( + result.outputCharacterCount !== countOutputCharacters(result.outputContent) || + result.outputContentFingerprint !== + createDurableCanonicalJsonSha256Fingerprint(result.outputContent) + ) + return invalidVerification("result-envelope", "fingerprint_mismatch", "outputContent"); + } else { + const verification = + result.outcome === "failed" + ? verifyReasoningFailureEvidence(result.failureEvidence) + : result.outcome === "timed-out" + ? verifyReasoningTimeoutEvidence(result.timeoutEvidence) + : verifyReasoningCancellationEvidence(result.cancellationEvidence); + if (verification.status !== "valid") + return invalidVerification("result-envelope", "fingerprint_mismatch", "terminal-evidence"); + } + return basic; +} + +export function countOutputCharacters( + output: + | { readonly contentType: "canonical-text"; readonly text: string } + | { readonly contentType: "canonical-json"; readonly value: DurableCanonicalJsonValue }, +): number { + return output.contentType === "canonical-text" + ? [...output.text].length + : [...serializeDurableCanonicalJsonValue(output.value)].length; +} + +export function verifyReasoningResultEnvelope(input: { + readonly resultEnvelope: unknown; + readonly invocationRequest: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly attempt: ReasoningExecutionAttempt; + readonly attemptHistory: readonly ReasoningExecutionAttempt[]; + readonly providerOutcome: ReasoningProviderOutcome; + readonly outcomeHistory: readonly ReasoningProviderOutcome[]; + readonly contextPackageObjectCount: number; +}): ReasoningArtifactVerificationResult { + let wrapper: CanonicalRecord; + try { + wrapper = captureCanonical(input, "Result verification input"); + } catch { + return invalidVerification("result-envelope", "invalid_artifact", "binding"); + } + const basic = verifySigned( + "result-envelope", + ReasoningResultEnvelopeSchema, + wrapper.resultEnvelope, + "resultEnvelopeFingerprint", + ); + if (basic.status !== "valid") return basic; + try { + const result = ReasoningResultEnvelopeSchema.parse(wrapper.resultEnvelope); + const request = ReasoningInvocationRequestSchema.parse(wrapper.invocationRequest); + const provider = ReasoningProviderCapabilityDescriptorSchema.parse(wrapper.providerCapability); + const attempt = ReasoningExecutionAttemptSchema.parse(wrapper.attempt); + if (!Array.isArray(wrapper.attemptHistory)) throw new Error("Attempt history must be an array"); + const attemptHistory = wrapper.attemptHistory.map((entry) => + ReasoningExecutionAttemptSchema.parse(entry), + ); + const outcome = ReasoningProviderOutcomeSchema.parse(wrapper.providerOutcome); + if (!Array.isArray(wrapper.outcomeHistory)) throw new Error("Outcome history must be an array"); + const outcomeHistory = wrapper.outcomeHistory.map((entry) => + ReasoningProviderOutcomeSchema.parse(entry), + ); + const contextPackageObjectCount = wrapper.contextPackageObjectCount; + if (!Number.isSafeInteger(contextPackageObjectCount) || Number(contextPackageObjectCount) < 0) + throw new Error("context object count is invalid"); + const orderedHistoryVerifies = + outcomeHistory.length === attemptHistory.length && + verifyReasoningAttemptLifecycle({ + invocationRequest: request, + providerCapability: provider, + attempts: attemptHistory, + outcomes: outcomeHistory, + }) && + serializeDurableCanonicalJsonValue(attemptHistory.at(-1)!) === + serializeDurableCanonicalJsonValue(attempt) && + serializeDurableCanonicalJsonValue(outcomeHistory.at(-1)!) === + serializeDurableCanonicalJsonValue(outcome); + const contextualArtifactsVerify = + verifyReasoningInvocationRequest(request).status === "valid" && + verifyReasoningProviderCapabilityDescriptor(provider).status === "valid" && + verifyReasoningExecutionAttempt(attempt).status === "valid" && + orderedHistoryVerifies; + const deliveryMatches = + result.deliveryTransactionId === request.deliveryTransactionId && + result.deliveryEnvelopeId === request.deliveryEnvelopeId && + result.deliveryEnvelopeFingerprint === request.deliveryEnvelopeFingerprint && + result.deliveryReceiptId === request.deliveryReceiptId && + result.deliveryReceiptFingerprint === request.deliveryReceiptFingerprint && + result.contextPackageId === request.contextPackageId && + result.contextPackageFingerprint === request.contextPackageFingerprint && + result.consumerId === request.consumerId && + result.consumerDescriptorFingerprint === request.consumerDescriptorFingerprint; + const executionMatches = + result.invocationRequestId === request.invocationRequestId && + result.invocationRequestFingerprint === request.requestFingerprint && + result.invocationIdempotencyKey === request.idempotencyKey && + result.executionPolicyFingerprint === request.executionPolicy.policyFingerprint && + result.providerCapabilityId === provider.providerCapabilityId && + result.providerCapabilityFingerprint === provider.descriptorFingerprint && + result.executionAttemptId === attempt.executionAttemptId && + result.attemptNumber === attempt.attemptNumber && + attempt.invocationRequestId === request.invocationRequestId && + attempt.invocationRequestFingerprint === request.requestFingerprint && + attempt.invocationIdempotencyKey === request.idempotencyKey && + attempt.providerCapabilityId === provider.providerCapabilityId && + attempt.providerCapabilityFingerprint === provider.descriptorFingerprint && + attempt.executionPolicyFingerprint === request.executionPolicy.policyFingerprint && + (attempt.attemptNumber === 1) === (attempt.previousExecutionAttemptId === undefined) && + outcome.invocationRequestId === request.invocationRequestId && + outcome.executionAttemptId === attempt.executionAttemptId && + outcome.attemptNumber === attempt.attemptNumber && + result.outcome === outcome.status && + result.completedAt === outcome.completedAt; + if ( + !contextualArtifactsVerify || + !deliveryMatches || + !executionMatches || + verifyReasoningProviderOutcome(outcome).status !== "valid" + ) + return invalidVerification("result-envelope", "fingerprint_mismatch", "binding"); + const expectedReceiptUnsigned = { + schemaVersion: "1.0" as const, + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + providerCapabilityId: provider.providerCapabilityId, + providerCapabilityFingerprint: provider.descriptorFingerprint, + attemptNumber: attempt.attemptNumber, + startedAt: attempt.startedAt, + completedAt: outcome.completedAt, + outcome: outcome.status, + }; + const expectedReceipt = createReasoningExecutionReceipt(expectedReceiptUnsigned); + const outputCharacterCount = + outcome.status === "succeeded" ? countOutputCharacters(outcome.outputContent) : 0; + const expectedUsage = createReasoningUsageEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + inputCharacterCount: countCanonicalCharacters(request.reasoningInput), + outputCharacterCount, + instructionBlockCount: request.reasoningInput.instructionBlocks.length, + contextPackageObjectCount: Number(contextPackageObjectCount), + attemptNumber: attempt.attemptNumber, + durationMilliseconds: Date.parse(outcome.completedAt) - Date.parse(attempt.startedAt), + }); + const expectedCost = + provider.providerClass === "deterministic-fake-provider" + ? createReasoningCostEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + status: "not-applicable", + }) + : result.costEvidence; + if ( + verifyReasoningExecutionReceipt(result.executionReceipt).status !== "valid" || + verifyReasoningUsageEvidence(result.usageEvidence).status !== "valid" || + verifyReasoningCostEvidence(result.costEvidence).status !== "valid" || + serializeDurableCanonicalJsonValue(result.executionReceipt) !== + serializeDurableCanonicalJsonValue(expectedReceipt) || + serializeDurableCanonicalJsonValue(result.usageEvidence) !== + serializeDurableCanonicalJsonValue(expectedUsage) || + serializeDurableCanonicalJsonValue(result.costEvidence) !== + serializeDurableCanonicalJsonValue(expectedCost) + ) + return invalidVerification("result-envelope", "fingerprint_mismatch", "operational-evidence"); + if (result.outcome === "succeeded") { + const characters = countOutputCharacters(result.outputContent); + const outputRequirements = request.reasoningInput.outputRequirements; + if ( + result.outputContent.contentType !== outputRequirements.contentType || + (outputRequirements.requireNonEmpty && characters === 0) + ) + return invalidVerification("result-envelope", "fingerprint_mismatch", "outputRequirements"); + if ( + characters !== result.outputCharacterCount || + characters > request.executionPolicy.maxOutputCharacters || + characters > request.reasoningInput.outputRequirements.maxCharacters + ) + return invalidVerification("result-envelope", "budget_exceeded", "outputCharacterCount"); + if ( + outcome.status !== "succeeded" || + JSON.stringify(result.outputContent) !== JSON.stringify(outcome.outputContent) + ) + return invalidVerification("result-envelope", "fingerprint_mismatch", "outputContent"); + } else { + const resultEvidence = + result.outcome === "failed" + ? result.failureEvidence + : result.outcome === "timed-out" + ? result.timeoutEvidence + : result.cancellationEvidence; + const outcomeEvidence = + outcome.status === "failed" + ? outcome.failureEvidence + : outcome.status === "timed-out" + ? outcome.timeoutEvidence + : outcome.status === "cancelled" + ? outcome.cancellationEvidence + : null; + if ( + outcomeEvidence === null || + JSON.stringify(resultEvidence) !== JSON.stringify(outcomeEvidence) + ) + return invalidVerification("result-envelope", "fingerprint_mismatch", "terminal-evidence"); + } + return basic; + } catch { + return invalidVerification("result-envelope", "invalid_artifact", "binding"); + } +} + +export type FinalizedReasoningConsumptionEvidenceInput = DistributiveOmit< + FinalizedReasoningConsumptionEvidence, + "consumptionFingerprint" +>; +export function createFinalizedReasoningConsumptionEvidence( + input: FinalizedReasoningConsumptionEvidenceInput, +) { + const attempts = input.attemptHistorySummary.attempts; + const historyUnsigned = { + attemptCount: input.attemptHistorySummary.attemptCount, + finalAttemptNumber: input.attemptHistorySummary.finalAttemptNumber, + finalOutcome: input.attemptHistorySummary.finalOutcome, + attempts, + }; + if ( + input.attemptHistorySummary.historyFingerprint !== + createDurableCanonicalJsonSha256Fingerprint(historyUnsigned) + ) + throw new ReasoningIntegrityError( + "fingerprint_mismatch", + "Attempt history fingerprint does not verify", + ); + return signed(FinalizedReasoningConsumptionEvidenceSchema, input, "consumptionFingerprint"); +} + +export function verifyFinalizedReasoningConsumptionEvidence(input: { + readonly consumptionEvidence: unknown; + readonly resultEnvelope: ReasoningResultEnvelope; + readonly invocationRequest: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly attempts: readonly ReasoningExecutionAttempt[]; + readonly outcomes: readonly ReasoningProviderOutcome[]; + readonly contextPackageObjectCount: number; + readonly executionLedgerTransactionId: string; +}): ReasoningArtifactVerificationResult { + let wrapper: CanonicalRecord; + try { + wrapper = captureCanonical(input, "Consumption verification input"); + } catch { + return invalidVerification("finalized-consumption-evidence", "invalid_artifact", "binding"); + } + const basic = verifySigned( + "finalized-consumption-evidence", + FinalizedReasoningConsumptionEvidenceSchema, + wrapper.consumptionEvidence, + "consumptionFingerprint", + ); + if (basic.status !== "valid") return basic; + try { + const evidence = FinalizedReasoningConsumptionEvidenceSchema.parse(wrapper.consumptionEvidence); + const result = ReasoningResultEnvelopeSchema.parse(wrapper.resultEnvelope); + const request = ReasoningInvocationRequestSchema.parse(wrapper.invocationRequest); + const provider = ReasoningProviderCapabilityDescriptorSchema.parse(wrapper.providerCapability); + if ( + verifyReasoningInvocationRequest(request).status !== "valid" || + verifyReasoningProviderCapabilityDescriptor(provider).status !== "valid" + ) + throw new Error("verification authority does not verify"); + if (!Array.isArray(wrapper.attempts) || !Array.isArray(wrapper.outcomes)) + throw new Error("attempt history must use arrays"); + const attempts = wrapper.attempts.map((attempt) => + ReasoningExecutionAttemptSchema.parse(attempt), + ); + const outcomes = wrapper.outcomes.map((outcome) => + ReasoningProviderOutcomeSchema.parse(outcome), + ); + const contextPackageObjectCount = wrapper.contextPackageObjectCount; + const executionLedgerTransactionId = wrapper.executionLedgerTransactionId; + if ( + !Number.isSafeInteger(contextPackageObjectCount) || + Number(contextPackageObjectCount) < 0 || + typeof executionLedgerTransactionId !== "string" + ) + throw new Error("verification context is invalid"); + if (attempts.length === 0 || attempts.length !== outcomes.length) + throw new Error("attempt history is incomplete"); + if ( + !verifyReasoningAttemptLifecycle({ + invocationRequest: request, + providerCapability: provider, + attempts, + outcomes, + }) + ) + throw new Error("attempt lifecycle is invalid"); + const expectedEntries = attempts.map((attempt, index) => { + const outcome = outcomes[index]; + if ( + outcome === undefined || + outcome.executionAttemptId !== attempt.executionAttemptId || + outcome.invocationRequestId !== request.invocationRequestId || + outcome.attemptNumber !== attempt.attemptNumber || + attempt.attemptNumber !== index + 1 || + attempt.invocationRequestId !== request.invocationRequestId || + attempt.invocationRequestFingerprint !== request.requestFingerprint || + attempt.invocationIdempotencyKey !== request.idempotencyKey || + attempt.providerCapabilityId !== provider.providerCapabilityId || + attempt.providerCapabilityFingerprint !== provider.descriptorFingerprint || + attempt.executionPolicyFingerprint !== request.executionPolicy.policyFingerprint + ) + throw new Error("attempt outcome mismatch"); + return { + executionAttemptId: attempt.executionAttemptId, + attemptNumber: attempt.attemptNumber, + outcome: outcome.status, + attemptFingerprint: attempt.attemptFingerprint, + outcomeFingerprint: outcome.outcomeFingerprint, + }; + }); + const historyUnsigned = { + attemptCount: expectedEntries.length, + finalAttemptNumber: expectedEntries.at(-1)?.attemptNumber, + finalOutcome: expectedEntries.at(-1)?.outcome, + attempts: expectedEntries, + }; + const finalAttempt = attempts.at(-1)!; + const finalOutcome = outcomes.at(-1)!; + if ( + verifyReasoningResultEnvelope({ + resultEnvelope: result, + invocationRequest: request, + providerCapability: provider, + attempt: finalAttempt, + attemptHistory: attempts, + providerOutcome: finalOutcome, + outcomeHistory: outcomes, + contextPackageObjectCount: Number(contextPackageObjectCount), + }).status !== "valid" + ) + throw new Error("result does not verify"); + const binding = + evidence.deliveryReceiptId === result.deliveryReceiptId && + evidence.deliveryReceiptFingerprint === result.deliveryReceiptFingerprint && + evidence.deliveryTransactionId === result.deliveryTransactionId && + evidence.invocationRequestId === result.invocationRequestId && + evidence.invocationRequestFingerprint === result.invocationRequestFingerprint && + evidence.invocationIdempotencyKey === result.invocationIdempotencyKey && + evidence.providerCapabilityId === result.providerCapabilityId && + evidence.providerCapabilityFingerprint === result.providerCapabilityFingerprint && + evidence.finalResultEnvelopeId === result.resultEnvelopeId && + evidence.finalResultEnvelopeFingerprint === result.resultEnvelopeFingerprint && + evidence.finalOutcome === result.outcome && + evidence.usageEvidenceFingerprint === result.usageEvidence.usageFingerprint && + evidence.costEvidenceFingerprint === result.costEvidence.costFingerprint && + evidence.startedAt === attempts[0]!.startedAt && + evidence.completedAt === finalOutcome.completedAt && + evidence.executionLedgerTransactionId === executionLedgerTransactionId && + JSON.stringify(evidence.attemptHistorySummary.attempts) === JSON.stringify(expectedEntries) && + evidence.attemptHistorySummary.historyFingerprint === + createDurableCanonicalJsonSha256Fingerprint(historyUnsigned); + const terminalBinding = + (evidence.finalOutcome === "succeeded" && result.outcome === "succeeded") || + (evidence.finalOutcome === "failed" && + result.outcome === "failed" && + evidence.failureEvidenceFingerprint === result.failureEvidence.failureFingerprint) || + (evidence.finalOutcome === "timed-out" && + result.outcome === "timed-out" && + evidence.timeoutEvidenceFingerprint === result.timeoutEvidence.timeoutFingerprint) || + (evidence.finalOutcome === "cancelled" && + result.outcome === "cancelled" && + evidence.cancellationEvidenceFingerprint === + result.cancellationEvidence.cancellationFingerprint); + if (!binding || !terminalBinding) + return invalidVerification( + "finalized-consumption-evidence", + "fingerprint_mismatch", + "binding", + ); + return basic; + } catch { + return invalidVerification("finalized-consumption-evidence", "invalid_artifact", "binding"); + } +} diff --git a/services/knowledge-engine/src/index.ts b/services/knowledge-engine/src/index.ts index 834b796..c1f0880 100644 --- a/services/knowledge-engine/src/index.ts +++ b/services/knowledge-engine/src/index.ts @@ -1,4 +1,13 @@ export * from "./application/ingest-markdown.js"; +export { + invokeGovernedReasoning, + GovernedReasoningInvocationError, + type DurableDeliveryTransactionIdentity, + type GovernedReasoningInvocationResult, + type InvokeGovernedReasoningInput, + type ReasoningAttemptSchedule, +} from "./application/invoke-governed-reasoning.js"; +export type { GovernedReasoningExecutionEvidenceReader } from "./application/manage-governed-reasoning-execution-ledger.js"; export * from "./application/assemble-governed-knowledge-context.js"; export * from "./application/ingest-markdown-directory.js"; export * from "./application/execute-knowledge-migration.js"; @@ -86,6 +95,62 @@ export { type VerifyContextDeliveryReplayEvidenceInput, type VerifyGovernedContextDeliveryEnvelopeInput, } from "./domain/context-delivery.js"; +export { + countCanonicalCharacters, + countOutputCharacters, + createFinalizedReasoningConsumptionEvidence, + createProviderNeutralReasoningInput, + createReasoningCancellationEvidence, + createReasoningConstraintBlock, + createReasoningCostEvidence, + createReasoningExecutionAttempt, + createReasoningExecutionPolicy, + createReasoningExecutionReceipt, + createReasoningFailureEvidence, + createReasoningInstructionBlock, + createReasoningInvocationRequest, + createReasoningProviderCapabilityDescriptor, + createReasoningProviderCapabilityRequirements, + createReasoningProviderOutcome, + createReasoningResultEnvelope, + createReasoningTimeoutEvidence, + createReasoningUsageEvidence, + matchReasoningProviderCapabilities, + ReasoningIntegrityError, + verifyFinalizedReasoningConsumptionEvidence, + verifyProviderNeutralReasoningInput, + verifyReasoningCancellationEvidence, + verifyReasoningCostEvidence, + verifyReasoningExecutionAttempt, + verifyReasoningExecutionPolicy, + verifyReasoningExecutionReceipt, + verifyReasoningFailureEvidence, + verifyReasoningInvocationRequest, + verifyReasoningProviderCapabilityDescriptor, + verifyReasoningProviderCompatibilityResult, + verifyReasoningProviderOutcome, + verifyReasoningResultEnvelope, + verifyReasoningResultEnvelopeArtifact, + verifyReasoningTimeoutEvidence, + verifyReasoningUsageEvidence, + type FinalizedReasoningConsumptionEvidenceInput, + type ProviderNeutralReasoningInputInput, + type ReasoningCancellationEvidenceInput, + type ReasoningConstraintBlockInput, + type ReasoningCostEvidenceInput, + type ReasoningExecutionAttemptInput, + type ReasoningExecutionPolicyInput, + type ReasoningExecutionReceiptInput, + type ReasoningFailureEvidenceInput, + type ReasoningInstructionBlockInput, + type ReasoningInvocationRequestInput, + type ReasoningProviderCapabilityDescriptorInput, + type ReasoningProviderCapabilityRequirementsInput, + type ReasoningProviderOutcomeInput, + type ReasoningResultEnvelopeInput, + type ReasoningTimeoutEvidenceInput, + type ReasoningUsageEvidenceInput, +} from "./domain/reasoning.js"; export * from "./domain/safe-path.js"; export * from "./infrastructure/load-migration-manifest.js"; export * from "./infrastructure/knowledge-corpus-candidate-source.js"; @@ -97,6 +162,11 @@ export { type LocalFileDeliveryLedgerLimits, type LocalFileDeliveryLedgerOptions, } from "./infrastructure/local-file-durable-context-delivery-ledger.js"; +export { + openLocalFileGovernedReasoningExecutionEvidence, + type LocalFileReasoningExecutionEvidenceLimits, + type LocalFileReasoningExecutionEvidenceOptions, +} from "./infrastructure/local-file-governed-reasoning-execution-evidence.js"; export * from "./infrastructure/parse-markdown.js"; export * from "./infrastructure/safe-path.js"; export * from "./interfaces/ingestion-report.js"; diff --git a/services/knowledge-engine/src/infrastructure/deterministic-fake-reasoning-provider.ts b/services/knowledge-engine/src/infrastructure/deterministic-fake-reasoning-provider.ts new file mode 100644 index 0000000..588a0f9 --- /dev/null +++ b/services/knowledge-engine/src/infrastructure/deterministic-fake-reasoning-provider.ts @@ -0,0 +1,280 @@ +import { + ReasoningExecutionAttemptSchema, + ReasoningInvocationRequestSchema, + ReasoningProviderCapabilityDescriptorSchema, + ReasoningProviderCompatibilityResultSchema, +} from "@founderos/knowledge-schema"; + +import type { + ProviderNeutralReasoningExecutionPort, + ReasoningExecutionPortInput, +} from "../application/reasoning-execution-port.js"; +import { createDurableCanonicalJsonSha256Fingerprint } from "../domain/canonical-fingerprint.js"; +import { + createReasoningCancellationEvidence, + createReasoningFailureEvidence, + createReasoningProviderCapabilityDescriptor, + createReasoningProviderOutcome, + createReasoningTimeoutEvidence, + countOutputCharacters, + verifyReasoningExecutionAttempt, + verifyReasoningInvocationRequest, + verifyReasoningProviderCapabilityDescriptor, + verifyReasoningProviderCompatibilityResult, +} from "../domain/reasoning.js"; + +export const DETERMINISTIC_FAKE_REASONING_CAPABILITY_ID = + "founderos-deterministic-fake-reasoning-v1"; + +export function createDeterministicFakeReasoningProvider(): ProviderNeutralReasoningExecutionPort { + const providerCapability = createReasoningProviderCapabilityDescriptor({ + schemaVersion: "1.0", + providerCapabilityId: DETERMINISTIC_FAKE_REASONING_CAPABILITY_ID, + providerClass: "deterministic-fake-provider", + acceptedInvocationRequestVersions: ["1.0"], + acceptedDeliveryEnvelopeVersions: ["1.0"], + acceptedInputContentTypes: ["provider-neutral-instruction-blocks-v1"], + acceptedOutputContentTypes: ["canonical-json", "canonical-text"], + maxInputCharacters: 1_000_000, + maxOutputCharacters: 1_000_000, + minTimeoutMilliseconds: 1, + maxTimeoutMilliseconds: 86_400_000, + supportedCancellationModes: [ + "cancel-before-execution", + "cooperative-cancellation", + "deadline-cancellation", + "not-cancellable", + ], + supportedRetryModes: [ + "evaluation-only-retry", + "no-retry", + "retry-deterministic-transient-failure", + "retry-until-attempt-limit", + ], + supportsDeterministicExecution: true, + supportsUsageEvidence: true, + supportsCostEvidence: true, + supportsFailureEvidence: true, + supportedResultEnvelopeVersions: ["1.0"], + }); + + return Object.freeze({ + providerCapability, + async execute(input: ReasoningExecutionPortInput): Promise { + const request = ReasoningInvocationRequestSchema.parse(input.invocationRequest); + const provider = ReasoningProviderCapabilityDescriptorSchema.parse(input.providerCapability); + const compatibility = ReasoningProviderCompatibilityResultSchema.parse(input.compatibility); + const attempt = ReasoningExecutionAttemptSchema.parse(input.attempt); + if ( + verifyReasoningInvocationRequest(request).status !== "valid" || + verifyReasoningProviderCapabilityDescriptor(provider).status !== "valid" || + verifyReasoningExecutionAttempt(attempt).status !== "valid" || + verifyReasoningProviderCompatibilityResult({ + compatibility, + invocationRequest: request, + providerCapability: provider, + }).status !== "valid" || + compatibility.status !== "compatible" || + provider.descriptorFingerprint !== providerCapability.descriptorFingerprint || + provider.providerCapabilityId !== providerCapability.providerCapabilityId || + input.evaluationTime !== request.requestedAt + ) { + throw new Error("Deterministic fake provider rejected unverified governed input"); + } + + const base = { + schemaVersion: "1.0" as const, + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: attempt.attemptNumber, + completedAt: input.completedAt, + }; + const success = (empty = false) => { + const outputContent = + request.reasoningInput.outputRequirements.contentType === "canonical-json" + ? { + contentType: "canonical-json" as const, + value: empty + ? null + : { + attemptNumber: attempt.attemptNumber, + contextPackageFingerprint: request.contextPackageFingerprint, + fixtureMode: input.fixtureMode, + instructionFingerprints: request.reasoningInput.instructionBlocks.map( + (block) => block.blockFingerprint, + ), + invocationRequestFingerprint: request.requestFingerprint, + }, + } + : { + contentType: "canonical-text" as const, + text: empty + ? "" + : `governed-result:${request.requestFingerprint}:${request.contextPackageFingerprint}:attempt-${attempt.attemptNumber}`, + }; + return createReasoningProviderOutcome({ + ...base, + status: "succeeded", + outputContent, + outputCharacterCount: countOutputCharacters(outputContent), + outputContentFingerprint: createDurableCanonicalJsonSha256Fingerprint(outputContent), + }); + }; + const failure = (transient: boolean) => { + const evidence = createReasoningFailureEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + failureCategory: transient ? "transient-provider-failure" : "permanent-provider-failure", + reasonCodes: [transient ? "transient_provider_failure" : "permanent_provider_failure"], + retryable: transient, + sanitizedDetail: transient + ? "Deterministic transient failure fixture" + : "Deterministic permanent failure fixture", + attemptNumber: attempt.attemptNumber, + }); + return createReasoningProviderOutcome({ + ...base, + status: "failed", + failureEvidence: evidence, + }); + }; + + switch (input.fixtureMode) { + case "successful-structured-response": + return success(); + case "successful-empty-response": + return success(true); + case "deterministic-transient-failure": + return failure(true); + case "transient-failure-then-success": + return attempt.attemptNumber === 1 ? failure(true) : success(); + case "deterministic-permanent-failure": + return failure(false); + case "timeout": { + const deadlineAt = attempt.deadlineAt; + if (deadlineAt === undefined) throw new Error("Timeout fixture requires a deadline"); + const evidence = createReasoningTimeoutEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + configuredTimeoutMilliseconds: request.executionPolicy.timeoutMilliseconds, + attemptStartedAt: attempt.startedAt, + deadlineAt, + elapsedMilliseconds: Date.parse(input.completedAt) - Date.parse(attempt.startedAt), + timeoutPhase: "during-execution", + reasonCode: "execution_timeout", + }); + return createReasoningProviderOutcome({ + ...base, + status: "timed-out", + timeoutEvidence: evidence, + }); + } + case "cooperative-cancellation": { + const signal = input.cancellationSignal; + if ( + signal.state !== "requested-cooperatively" || + request.executionPolicy.cancellationMode !== "cooperative-cancellation" + ) + throw new Error("Cooperative cancellation fixture requires a matching signal"); + const evidence = createReasoningCancellationEvidence({ + schemaVersion: "1.0", + invocationRequestId: request.invocationRequestId, + executionAttemptId: attempt.executionAttemptId, + cancellationMode: "cooperative-cancellation", + cancellationPhase: "cooperative-execution", + cancellationAuthorityReference: signal.authorityReference, + requestedAt: signal.requestedAt, + observedAt: signal.observedAt, + reasonCode: "cancelled_cooperatively", + }); + return createReasoningProviderOutcome({ + ...base, + status: "cancelled", + cancellationEvidence: evidence, + }); + } + case "cancellation-before-execution": + case "deadline-cancellation": { + const before = input.fixtureMode === "cancellation-before-execution"; + const signal = input.cancellationSignal; + const expectedState = before ? "requested-before-execution" : "requested-at-deadline"; + const expectedMode = before ? "cancel-before-execution" : "deadline-cancellation"; + if ( + signal.state !== expectedState || + request.executionPolicy.cancellationMode !== expectedMode + ) + throw new Error("Cancellation fixture requires a matching explicit signal"); + const evidence = createReasoningCancellationEvidence({ + schemaVersion: "1.0", + invocationRequestId: request.invocationRequestId, + executionAttemptId: attempt.executionAttemptId, + cancellationMode: expectedMode, + cancellationPhase: before ? "before-execution" : "deadline", + cancellationAuthorityReference: signal.authorityReference, + requestedAt: signal.requestedAt, + observedAt: signal.observedAt, + reasonCode: before ? "cancelled_before_execution" : "cancelled_at_deadline", + }); + return createReasoningProviderOutcome({ + ...base, + status: "cancelled", + cancellationEvidence: evidence, + }); + } + case "output-budget-overflow": { + const outputContent = { + contentType: "canonical-text" as const, + text: "x".repeat(request.executionPolicy.maxOutputCharacters + 1), + }; + return createReasoningProviderOutcome({ + ...base, + status: "succeeded", + outputContent, + outputCharacterCount: countOutputCharacters(outputContent), + outputContentFingerprint: createDurableCanonicalJsonSha256Fingerprint(outputContent), + }); + } + case "malformed-success-outcome": + return { + ...base, + status: "succeeded", + outputContent: { contentType: "canonical-text", text: "malformed" }, + }; + case "malformed-failure-outcome": + return { ...base, status: "failed", failureEvidence: { retryable: "yes" } }; + case "contradictory-outcome": + return { ...success(), status: "timed-out" }; + case "physical-path-bearing-outcome": + return unsafeSuccess(base, "provider output at /private/runtime/secret.txt"); + case "credential-bearing-outcome": + return unsafeSuccess(base, "api_key=fixture-secret-value"); + } + }, + }); +} + +function unsafeSuccess( + base: Readonly<{ + schemaVersion: "1.0"; + executionAttemptId: string; + invocationRequestId: string; + attemptNumber: number; + completedAt: string; + }>, + text: string, +): unknown { + const outputContent = { contentType: "canonical-text" as const, text }; + const unsigned = { + ...base, + status: "succeeded" as const, + outputContent, + outputCharacterCount: [...text].length, + outputContentFingerprint: createDurableCanonicalJsonSha256Fingerprint(outputContent), + }; + return { + ...unsigned, + outcomeFingerprint: createDurableCanonicalJsonSha256Fingerprint(unsigned), + }; +} diff --git a/services/knowledge-engine/src/infrastructure/local-file-governed-reasoning-execution-evidence.ts b/services/knowledge-engine/src/infrastructure/local-file-governed-reasoning-execution-evidence.ts new file mode 100644 index 0000000..5fdafb7 --- /dev/null +++ b/services/knowledge-engine/src/infrastructure/local-file-governed-reasoning-execution-evidence.ts @@ -0,0 +1,616 @@ +import { + constants, + type FileHandle, + lstat, + mkdir, + open, + readFile, + readdir, + realpath, + rename, + rm, +} from "node:fs/promises"; +import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path"; + +import { + DurableReasoningExecutionDerivedIndexSchema, + findDurableCanonicalJsonIssue, + type DurableReasoningExecutionDerivedIndex, + type ReasoningExecutionLedgerEvent, +} from "@founderos/knowledge-schema"; + +import { + createGovernedReasoningExecutionEvidence, + createSafeReasoningExecutionEvidenceReader, + type GovernedReasoningExecutionEvidenceReader, +} from "../application/manage-governed-reasoning-execution-ledger.js"; +import type { + ReasoningExecutionLedgerStoragePort, + ReasoningExecutionLedgerWriterPort, + VerifiedReasoningExecutionLedgerState, +} from "../application/reasoning-execution-ledger-port.js"; +import { createDurableCanonicalJsonSha256Fingerprint } from "../domain/canonical-fingerprint.js"; +import { + ReasoningExecutionLedgerConflictError, + ReasoningExecutionLedgerError, + ReasoningExecutionLedgerIntegrityError, + replayReasoningExecutionLedger, + type ReasoningInvocationAuthority, +} from "../domain/durable-reasoning-execution-ledger.js"; +import { deepFreeze } from "../domain/snapshot-lifecycle.js"; + +const HEAD_FILE = "commit-head.json"; +const INDEX_FILE = "execution-index.json"; +const DEFAULT_LIMITS = { + maxEntries: 10_000, + maxTotalBytes: 256 * 1024 * 1024, + maxRecordBytes: 16 * 1024 * 1024, +}; + +export interface LocalFileReasoningExecutionEvidenceLimits { + readonly maxEntries: number; + readonly maxTotalBytes: number; + readonly maxRecordBytes: number; +} +export interface LocalFileReasoningExecutionEvidenceOptions { + readonly runtimeRoot: string; + readonly repositoryRoot: string; + readonly canonicalSourceRoots: readonly string[]; + readonly limits?: LocalFileReasoningExecutionEvidenceLimits; +} + +interface CommitEnvelope { + readonly schemaVersion: "1.0"; + readonly event: ReasoningExecutionLedgerEvent; + readonly invocationAuthority?: ReasoningInvocationAuthority; + readonly commitFingerprint: string; +} +interface CommitHead { + readonly schemaVersion: "1.0"; + readonly committedEventCount: number; + readonly lastCommittedLedgerSequence: number; + readonly lastAuditFingerprint: "genesis" | string; + readonly executionEvidenceFingerprint: string; + readonly authoritativeCommitFingerprint: string; + readonly headFingerprint: string; +} + +function immutableCopy(value: T): T { + return deepFreeze(structuredClone(value)); +} +function isErrno(error: unknown, code: string): boolean { + return ( + error instanceof Error && "code" in error && (error as NodeJS.ErrnoException).code === code + ); +} +function isWithin(parent: string, child: string): boolean { + const path = relative(parent, child); + return path === "" || (!path.startsWith(`..${sep}`) && path !== ".." && !isAbsolute(path)); +} +function safeError(code: ReasoningExecutionLedgerIntegrityError["code"], message: string) { + return new ReasoningExecutionLedgerIntegrityError(code, message); +} +function serialize(value: unknown): string { + return `${JSON.stringify(value)}\n`; +} +function without(value: object, field: string) { + return Object.fromEntries(Object.entries(value).filter(([key]) => key !== field)); +} + +function validateLimits(raw: LocalFileReasoningExecutionEvidenceLimits | undefined) { + if (raw === undefined) return DEFAULT_LIMITS; + if ( + findDurableCanonicalJsonIssue(raw) !== null || + !Number.isSafeInteger(raw.maxEntries) || + raw.maxEntries <= 0 || + !Number.isSafeInteger(raw.maxTotalBytes) || + raw.maxTotalBytes <= 0 || + !Number.isSafeInteger(raw.maxRecordBytes) || + raw.maxRecordBytes <= 0 || + raw.maxRecordBytes > raw.maxTotalBytes + ) + throw safeError("resource_limit_exceeded", "Execution Ledger resource limits are invalid"); + return immutableCopy(raw); +} + +async function validateOptions(raw: LocalFileReasoningExecutionEvidenceOptions) { + if (raw === null || typeof raw !== "object" || Object.getPrototypeOf(raw) !== Object.prototype) + throw safeError( + "unsafe_content", + "Execution Ledger options must be an accessor-free plain record", + ); + const descriptors = Object.getOwnPropertyDescriptors(raw); + const allowed = new Set(["runtimeRoot", "repositoryRoot", "canonicalSourceRoots", "limits"]); + if (Reflect.ownKeys(descriptors).some((key) => typeof key !== "string" || !allowed.has(key))) + throw safeError("unsafe_content", "Execution Ledger options contain unsupported fields"); + for (const field of [ + "runtimeRoot", + "repositoryRoot", + "canonicalSourceRoots", + "limits", + ] as const) { + const descriptor = descriptors[field]; + if (field === "limits" && descriptor === undefined) continue; + if (descriptor === undefined || !("value" in descriptor) || !descriptor.enumerable) + throw safeError("unsafe_content", "Execution Ledger options require data properties"); + } + const runtimeRoot = descriptors.runtimeRoot!.value; + const repositoryRoot = descriptors.repositoryRoot!.value; + const canonicalSourceRoots = descriptors.canonicalSourceRoots!.value; + if ( + typeof runtimeRoot !== "string" || + typeof repositoryRoot !== "string" || + findDurableCanonicalJsonIssue(canonicalSourceRoots) !== null || + !Array.isArray(canonicalSourceRoots) || + canonicalSourceRoots.some((value) => typeof value !== "string") || + [runtimeRoot, repositoryRoot, ...canonicalSourceRoots].some( + (path) => !isAbsolute(path) || path.includes("\0") || path.split(/[\\/]/u).includes(".."), + ) + ) + throw safeError("unsafe_content", "Execution Ledger paths are invalid"); + const realRepository = await realpath(repositoryRoot); + const resolvedRuntime = resolve( + realRepository, + relative(resolve(repositoryRoot), resolve(runtimeRoot)), + ); + const allowedRoot = join(realRepository, ".founderos", "runtime"); + if (!isWithin(allowedRoot, resolvedRuntime) || resolvedRuntime === allowedRoot) + throw safeError("unsafe_content", "Execution Ledger runtime must be a dedicated runtime child"); + const realSources = await Promise.all(canonicalSourceRoots.map((path) => realpath(path))); + if ( + realSources.some( + (source) => isWithin(source, resolvedRuntime) || isWithin(resolvedRuntime, source), + ) + ) + throw safeError("unsafe_content", "Execution Ledger runtime cannot overlap canonical sources"); + let ancestor = dirname(resolvedRuntime); + while (ancestor !== realRepository && isWithin(realRepository, ancestor)) { + try { + if ((await lstat(ancestor)).isSymbolicLink()) + throw safeError( + "unsafe_content", + "Execution Ledger runtime ancestors cannot be symbolic links", + ); + } catch (error) { + if (!isErrno(error, "ENOENT")) throw error; + } + ancestor = dirname(ancestor); + } + try { + const target = await lstat(resolvedRuntime); + if (target.isSymbolicLink() || !target.isDirectory()) + throw safeError("unsafe_content", "Execution Ledger runtime root type is unsafe"); + } catch (error) { + if (!isErrno(error, "ENOENT")) throw error; + } + return { + runtimeRoot: resolvedRuntime, + limits: validateLimits( + descriptors.limits === undefined + ? undefined + : (descriptors.limits.value as LocalFileReasoningExecutionEvidenceLimits), + ), + }; +} + +async function writeExclusive(path: string, bytes: string): Promise { + const handle = await open(path, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600); + try { + await handle.writeFile(bytes, "utf8"); + await handle.sync(); + } finally { + await handle.close(); + } +} +async function replaceAtomic(path: string, bytes: string, staging: string): Promise { + const temporary = join(staging, `${basename(path)}.${process.pid}.partial`); + await rm(temporary, { force: true }); + await writeExclusive(temporary, bytes); + await rename(temporary, path); + await flushDirectory(dirname(path)); +} +async function flushDirectory(path: string): Promise { + let handle: FileHandle | undefined; + try { + handle = await open(path, constants.O_RDONLY); + await handle.sync(); + } catch (error) { + if (!["EINVAL", "ENOTSUP", "EISDIR", "EBADF"].some((code) => isErrno(error, code))) throw error; + } finally { + await handle?.close(); + } +} +function nextAuthoritativeFingerprint(previous: string, commitFingerprint: string): string { + return createDurableCanonicalJsonSha256Fingerprint({ previous, commitFingerprint }); +} +function emptyHead(): CommitHead { + const unsigned = { + schemaVersion: "1.0" as const, + committedEventCount: 0, + lastCommittedLedgerSequence: 0, + lastAuditFingerprint: "genesis" as const, + executionEvidenceFingerprint: createDurableCanonicalJsonSha256Fingerprint([]), + authoritativeCommitFingerprint: createDurableCanonicalJsonSha256Fingerprint([]), + }; + return { ...unsigned, headFingerprint: createDurableCanonicalJsonSha256Fingerprint(unsigned) }; +} +function parseHead(raw: unknown): CommitHead { + if (findDurableCanonicalJsonIssue(raw) !== null || raw === null || typeof raw !== "object") + throw safeError("invalid_raw_record", "Execution Ledger commit marker is invalid"); + const head = raw as CommitHead; + const keys = Object.keys(head).sort(); + const expectedKeys = [ + "authoritativeCommitFingerprint", + "committedEventCount", + "executionEvidenceFingerprint", + "headFingerprint", + "lastAuditFingerprint", + "lastCommittedLedgerSequence", + "schemaVersion", + ]; + const isDigest = (value: unknown) => typeof value === "string" && /^[a-f0-9]{64}$/u.test(value); + if ( + JSON.stringify(keys) !== JSON.stringify(expectedKeys) || + head.schemaVersion !== "1.0" || + !Number.isSafeInteger(head.committedEventCount) || + head.committedEventCount < 0 || + !isDigest(head.executionEvidenceFingerprint) || + !isDigest(head.authoritativeCommitFingerprint) || + !isDigest(head.headFingerprint) || + head.lastCommittedLedgerSequence !== head.committedEventCount || + (head.committedEventCount === 0) !== (head.lastAuditFingerprint === "genesis") || + (head.lastAuditFingerprint !== "genesis" && !isDigest(head.lastAuditFingerprint)) || + head.headFingerprint !== + createDurableCanonicalJsonSha256Fingerprint(without(head, "headFingerprint")) + ) + throw safeError("fingerprint_mismatch", "Execution Ledger commit marker does not verify"); + return head; +} +function parseEnvelope(raw: unknown): CommitEnvelope { + if (findDurableCanonicalJsonIssue(raw) !== null || raw === null || typeof raw !== "object") + throw safeError("invalid_raw_record", "Execution Ledger commit envelope is invalid"); + const envelope = raw as CommitEnvelope; + const keys = Object.keys(envelope).sort(); + const expected = + envelope.invocationAuthority === undefined + ? ["commitFingerprint", "event", "schemaVersion"] + : ["commitFingerprint", "event", "invocationAuthority", "schemaVersion"]; + if ( + JSON.stringify(keys) !== JSON.stringify(expected) || + envelope.schemaVersion !== "1.0" || + envelope.commitFingerprint !== + createDurableCanonicalJsonSha256Fingerprint(without(envelope, "commitFingerprint")) + ) + throw safeError("fingerprint_mismatch", "Execution Ledger commit envelope does not verify"); + if ( + (envelope.event.eventType === "invocation-ownership") !== + (envelope.invocationAuthority !== undefined) + ) + throw safeError( + "invocation_binding_mismatch", + "Execution Ledger authority must be committed with exactly one ownership event", + ); + return immutableCopy(envelope); +} + +class LocalReasoningExecutionStorage implements ReasoningExecutionLedgerStoragePort { + private constructor( + private readonly root: string, + private readonly limits: LocalFileReasoningExecutionEvidenceLimits, + ) {} + public static async open(options: LocalFileReasoningExecutionEvidenceOptions) { + try { + const validated = await validateOptions(options); + const storage = new LocalReasoningExecutionStorage(validated.runtimeRoot, validated.limits); + await storage.initialize(); + await storage.readVerifiedState(); + return storage; + } catch (error) { + throw normalizeStorageError(error); + } + } + private get events() { + return join(this.root, "events"); + } + private get staging() { + return join(this.root, "staging"); + } + private get derived() { + return join(this.root, "derived"); + } + private get head() { + return join(this.root, HEAD_FILE); + } + private get index() { + return join(this.derived, INDEX_FILE); + } + private get lock() { + return join(this.root, ".single-writer.lock"); + } + private async initialize() { + await mkdir(this.root, { recursive: true, mode: 0o700 }); + await mkdir(this.events, { recursive: true, mode: 0o700 }); + await mkdir(this.staging, { recursive: true, mode: 0o700 }); + await mkdir(this.derived, { recursive: true, mode: 0o700 }); + try { + await writeExclusive(this.head, serialize(emptyHead())); + } catch (error) { + if (!isErrno(error, "EEXIST")) + throw safeError("storage_failure", "Execution Ledger initialization failed"); + } + await this.assertPhysicalLayout(); + } + private async assertPhysicalLayout(): Promise { + const expectedRoot = resolve(this.root); + for (const path of [this.root, this.events, this.staging, this.derived]) { + const info = await lstat(path); + if (info.isSymbolicLink() || !info.isDirectory()) + throw safeError("unsafe_content", "Execution Ledger managed directory type is unsafe"); + const physical = await realpath(path); + if (!isWithin(expectedRoot, physical) || (path === this.root && physical !== expectedRoot)) + throw safeError("unsafe_content", "Execution Ledger managed directory escaped its root"); + } + } + private async readJson(path: string, maxBytes: number): Promise { + let bytes: string; + try { + bytes = await readFile(path, "utf8"); + } catch { + throw safeError("storage_failure", "Execution Ledger read failed"); + } + if (Buffer.byteLength(bytes) > maxBytes) + throw safeError( + "resource_limit_exceeded", + "Execution Ledger record exceeds configured limits", + ); + try { + return JSON.parse(bytes) as unknown; + } catch { + throw safeError("invalid_raw_record", "Execution Ledger record is not valid JSON"); + } + } + private async readHeadJson(): Promise { + let handle: FileHandle | undefined; + try { + const before = await lstat(this.head); + if (before.isSymbolicLink() || !before.isFile() || before.size > this.limits.maxRecordBytes) + throw safeError("unsafe_content", "Execution Ledger commit marker type is unsafe"); + const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0; + handle = await open(this.head, constants.O_RDONLY | noFollow); + const opened = await handle.stat(); + if (!opened.isFile() || opened.size > this.limits.maxRecordBytes) + throw safeError("unsafe_content", "Execution Ledger commit marker type is unsafe"); + const bytes = await handle.readFile("utf8"); + if (Buffer.byteLength(bytes) > this.limits.maxRecordBytes) + throw safeError( + "resource_limit_exceeded", + "Execution Ledger record exceeds configured limits", + ); + try { + return JSON.parse(bytes) as unknown; + } catch { + throw safeError("invalid_raw_record", "Execution Ledger record is not valid JSON"); + } + } catch (error) { + if (error instanceof ReasoningExecutionLedgerError) throw error; + if (isErrno(error, "ELOOP")) + throw safeError("unsafe_content", "Execution Ledger commit marker type is unsafe"); + throw safeError("storage_failure", "Execution Ledger read failed"); + } finally { + await handle?.close(); + } + } + public async readVerifiedState(): Promise { + try { + return await this.readVerifiedStateInternal(); + } catch (error) { + throw normalizeStorageError(error); + } + } + private async readVerifiedStateInternal(): Promise { + await this.assertPhysicalLayout(); + const head = parseHead(await this.readHeadJson()); + if (head.committedEventCount > this.limits.maxEntries) + throw safeError("resource_limit_exceeded", "Execution Ledger entry limit exceeded"); + const names = await readdir(this.events); + const committedNames = names.filter((name) => /^\d{16}\.json$/u.test(name)).sort(); + const events: ReasoningExecutionLedgerEvent[] = []; + const authorities: ReasoningInvocationAuthority[] = []; + let authoritativeCommitFingerprint = createDurableCanonicalJsonSha256Fingerprint([]); + let totalBytes = 0; + for (let sequence = 1; sequence <= head.committedEventCount; sequence += 1) { + const name = `${String(sequence).padStart(16, "0")}.json`; + if (!committedNames.includes(name)) + throw safeError("sequence_invalid", "Execution Ledger committed sequence is incomplete"); + const path = join(this.events, name); + const info = await lstat(path); + if (info.isSymbolicLink() || !info.isFile()) + throw safeError("unsafe_content", "Execution Ledger authoritative entry type is unsafe"); + totalBytes += info.size; + if (info.size > this.limits.maxRecordBytes || totalBytes > this.limits.maxTotalBytes) + throw safeError("resource_limit_exceeded", "Execution Ledger byte limit exceeded"); + const envelope = parseEnvelope(await this.readJson(path, this.limits.maxRecordBytes)); + if (envelope.event.ledgerSequence !== sequence) + throw safeError("sequence_invalid", "Execution Ledger file sequence is invalid"); + events.push(envelope.event); + authoritativeCommitFingerprint = nextAuthoritativeFingerprint( + authoritativeCommitFingerprint, + envelope.commitFingerprint, + ); + if (envelope.invocationAuthority !== undefined) + authorities.push(envelope.invocationAuthority); + } + if (authoritativeCommitFingerprint !== head.authoritativeCommitFingerprint) + throw safeError( + "fingerprint_mismatch", + "Execution Ledger committed authority does not match its head", + ); + const replay = replayReasoningExecutionLedger(events, authorities); + if ( + replay.lastAuditFingerprint !== head.lastAuditFingerprint || + replay.executionEvidenceFingerprint !== head.executionEvidenceFingerprint + ) + throw safeError( + "fingerprint_mismatch", + "Execution Ledger committed head does not match authoritative history", + ); + const derivedIndex = await this.readOptionalDerivedIndex(); + return immutableCopy({ replay, derivedIndex, authoritativeCommitFingerprint }); + } + private async readOptionalDerivedIndex(): Promise { + try { + const info = await lstat(this.index); + if (info.isSymbolicLink() || !info.isFile() || info.size > this.limits.maxRecordBytes) + return null; + return await this.readJson(this.index, this.limits.maxRecordBytes); + } catch { + return null; + } + } + public async withWriter( + operation: (writer: ReasoningExecutionLedgerWriterPort) => Promise, + ): Promise { + let handle: FileHandle; + try { + handle = await open( + this.lock, + constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, + 0o600, + ); + } catch { + throw new ReasoningExecutionLedgerConflictError( + "transaction_conflict", + "Execution Ledger already has an active writer", + ); + } + const writer: ReasoningExecutionLedgerWriterPort = { + readVerifiedState: () => this.readVerifiedState(), + appendAuthoritativeEvent: (event, expected, invocationAuthority) => + this.append(event, expected, invocationAuthority), + replaceDerivedIndex: (index) => this.replaceIndex(index), + }; + return runReasoningWriterSession( + () => operation(writer), + () => handle.close(), + () => rm(this.lock, { force: true }), + ); + } + private async append( + event: ReasoningExecutionLedgerEvent, + expected: { readonly ledgerSequence: number; readonly auditFingerprint: string }, + invocationAuthority?: ReasoningInvocationAuthority, + ) { + await this.assertPhysicalLayout(); + const current = await this.readVerifiedState(); + if ( + current.replay.lastSequence !== expected.ledgerSequence || + current.replay.lastAuditFingerprint !== expected.auditFingerprint || + event.ledgerSequence !== expected.ledgerSequence + 1 || + event.previousAuditFingerprint !== expected.auditFingerprint + ) + throw new ReasoningExecutionLedgerConflictError( + "audit_chain_broken", + "Expected Execution Ledger head is stale", + ); + const envelopeUnsigned = { + schemaVersion: "1.0" as const, + event, + ...(invocationAuthority === undefined ? {} : { invocationAuthority }), + }; + const envelope = { + ...envelopeUnsigned, + commitFingerprint: createDurableCanonicalJsonSha256Fingerprint(envelopeUnsigned), + }; + const eventPath = join(this.events, `${String(event.ledgerSequence).padStart(16, "0")}.json`); + try { + const orphan = await lstat(eventPath); + if (orphan.isSymbolicLink() || !orphan.isFile()) + throw safeError( + "unsafe_content", + "Execution Ledger uncommitted suffix has an unsafe entry type", + ); + await rm(eventPath); + } catch (error) { + if (!isErrno(error, "ENOENT")) throw error; + } + try { + await writeExclusive(eventPath, serialize(envelope)); + await flushDirectory(this.events); + } catch { + throw safeError("storage_failure", "Execution Ledger authoritative append failed"); + } + const nextEvents = [...current.replay.events, event]; + const headUnsigned = { + schemaVersion: "1.0" as const, + committedEventCount: nextEvents.length, + lastCommittedLedgerSequence: nextEvents.length, + lastAuditFingerprint: event.auditFingerprint, + executionEvidenceFingerprint: createDurableCanonicalJsonSha256Fingerprint(nextEvents), + authoritativeCommitFingerprint: nextAuthoritativeFingerprint( + current.authoritativeCommitFingerprint, + envelope.commitFingerprint, + ), + }; + await this.assertPhysicalLayout(); + await replaceAtomic( + this.head, + serialize({ + ...headUnsigned, + headFingerprint: createDurableCanonicalJsonSha256Fingerprint(headUnsigned), + }), + this.staging, + ); + await this.assertPhysicalLayout(); + } + private async replaceIndex(index: DurableReasoningExecutionDerivedIndex) { + await this.assertPhysicalLayout(); + const parsed = DurableReasoningExecutionDerivedIndexSchema.parse(index); + await replaceAtomic(this.index, serialize(parsed), this.staging); + } +} + +function normalizeStorageError(error: unknown): ReasoningExecutionLedgerError { + if (error instanceof ReasoningExecutionLedgerError) return error; + return safeError("storage_failure", "Execution Ledger storage operation failed"); +} + +/** Deep-module test seam for deterministic primary-operation/cleanup error precedence. */ +export async function runReasoningWriterSession( + operation: () => Promise, + closeHandle: () => Promise, + removeLock: () => Promise, +): Promise { + let value: T | undefined; + let operationCompleted = false; + let primaryError: unknown; + try { + value = await operation(); + operationCompleted = true; + } catch (error) { + primaryError = error; + } + let cleanupError: unknown; + try { + await closeHandle(); + } catch (error) { + cleanupError = error; + } + try { + await removeLock(); + } catch (error) { + cleanupError ??= error; + } + // The primary operation is authoritative; otherwise close precedes lock removal. + if (primaryError !== undefined) throw normalizeStorageError(primaryError); + if (cleanupError !== undefined) throw normalizeStorageError(cleanupError); + if (!operationCompleted) throw safeError("storage_failure", "Execution Ledger writer failed"); + return value as T; +} + +export async function openLocalFileGovernedReasoningExecutionEvidence( + options: LocalFileReasoningExecutionEvidenceOptions, +): Promise { + return createSafeReasoningExecutionEvidenceReader( + createGovernedReasoningExecutionEvidence(await LocalReasoningExecutionStorage.open(options)), + ); +} diff --git a/services/knowledge-engine/tests/fixtures/reasoning-evaluations.ts b/services/knowledge-engine/tests/fixtures/reasoning-evaluations.ts new file mode 100644 index 0000000..334ce64 --- /dev/null +++ b/services/knowledge-engine/tests/fixtures/reasoning-evaluations.ts @@ -0,0 +1,462 @@ +const EVALUATION_CASES = [ + ["success-structured", "successful-execution"], + ["success-empty", "successful-execution"], + ["repeat-deterministic", "successful-execution"], + ["restart-lookup", "successful-execution"], + ["missing-transaction", "delivery-binding"], + ["envelope-substitution", "delivery-binding"], + ["receipt-substitution", "delivery-binding"], + ["context-substitution", "delivery-binding"], + ["consumer-substitution", "delivery-binding"], + ["registry-substitution", "delivery-binding"], + ["invocation-version", "capability"], + ["delivery-version", "capability"], + ["input-type", "capability"], + ["input-budget", "capability"], + ["output-budget", "capability"], + ["timeout-range", "capability"], + ["cancellation-mode", "capability"], + ["retry-mode", "capability"], + ["usage-capability", "capability"], + ["cost-capability", "capability"], + ["failure-capability", "capability"], + ["first-ownership", "idempotency"], + ["identical-finalized", "idempotency"], + ["conflicting-key", "idempotency"], + ["in-progress", "idempotency"], + ["conflicting-finalization", "idempotency"], + ["transient-success", "retry"], + ["permanent-no-retry", "retry"], + ["attempt-exhaustion", "retry"], + ["identical-attempt", "retry"], + ["conflicting-attempt", "retry"], + ["timeout-no-retry", "timeout"], + ["timeout-retry", "timeout"], + ["timeout-contradiction", "timeout"], + ["deadline-expired", "timeout"], + ["cancel-before", "cancellation"], + ["cancel-cooperative", "cancellation"], + ["cancel-deadline", "cancellation"], + ["cancel-contradiction", "cancellation"], + ["output-mutation", "evidence-integrity"], + ["usage-mutation", "evidence-integrity"], + ["cost-mutation", "evidence-integrity"], + ["failure-mutation", "evidence-integrity"], + ["timeout-mutation", "evidence-integrity"], + ["cancellation-mutation", "evidence-integrity"], + ["receipt-mutation", "evidence-integrity"], + ["result-mutation", "evidence-integrity"], + ["consumption-mutation", "evidence-integrity"], + ["resigned-substitution", "evidence-integrity"], + ["network-free", "fake-provider-safety"], + ["environment-free", "fake-provider-safety"], + ["randomness-free", "fake-provider-safety"], + ["wall-clock-free", "fake-provider-safety"], + ["physical-path", "fake-provider-safety"], + ["credential", "fake-provider-safety"], + ["malformed", "fake-provider-safety"], + ["contradictory", "fake-provider-safety"], + ["raw-object", "no-provider-bypass"], + ["query-result", "no-provider-bypass"], + ["hidden-context", "no-provider-bypass"], + ["provider-payload", "no-provider-bypass"], + ["preconstructed-result", "no-provider-bypass"], + ["low-level-finalization", "no-provider-bypass"], +] as const; + +export type ReasoningEvaluationCategory = (typeof EVALUATION_CASES)[number][1]; +export type ReasoningEvaluationScenarioId = (typeof EVALUATION_CASES)[number][0]; + +const RETAINED_MUTATION_TARGETS = { + "invocation-version": "invocationRequestVersion", + "delivery-version": "deliveryEnvelopeVersion", + "input-type": "inputContentType", + "input-budget": "inputCharacters", + "output-budget": "maxOutputCharacters", + "timeout-range": "timeoutMilliseconds", + "cancellation-mode": "cancellationMode", + "retry-mode": "retryMode", + "usage-capability": "usageEvidenceRequired", + "cost-capability": "costEvidenceRequired", + "failure-capability": "failureEvidenceRequired", + "timeout-contradiction": "providerOutcome.timeoutEvidence", + "cancel-contradiction": "providerOutcome.cancellationEvidence", + "network-free": "provider.source.network", + "environment-free": "provider.source.environment", + "randomness-free": "provider.source.randomness", + "wall-clock-free": "provider.source.wallClock", + "raw-object": "facade.rawKnowledgeObjects", + "query-result": "facade.queryResult", + "hidden-context": "facade.hiddenContext", + "provider-payload": "facade.providerPayload", + "preconstructed-result": "facade.preconstructedResult", +} as const satisfies Partial>; + +type TargetedReasoningEvaluationScenarioId = keyof typeof RETAINED_MUTATION_TARGETS; +type ReasoningEvaluationMutation = + | { + readonly operation: TargetedReasoningEvaluationScenarioId; + readonly target: string; + } + | { + readonly operation: Exclude< + ReasoningEvaluationScenarioId, + TargetedReasoningEvaluationScenarioId + >; + readonly target?: never; + }; + +export interface ReasoningEvaluationExpected { + readonly disposition: "accept" | "reject" | "resolve"; + readonly errorCode: string | null; + readonly status: string | null; + readonly outcome: string | null; + readonly reasonCodes: readonly string[]; + readonly attemptCount: number; + readonly durable: boolean | "not-applicable"; + readonly fingerprintStatus: "invalid" | "not-applicable" | "valid"; + readonly attemptIdentity: "content-derived" | "none" | "stable-replay"; + readonly resultExpectation: "finalized" | "none" | "rejected"; + readonly evidenceExpectation: "none" | "rejected" | "sanitized" | "verified"; + readonly finalizationExpectation: "committed" | "conflict" | "none"; +} + +export interface ReasoningEvaluation { + readonly scenarioId: ReasoningEvaluationScenarioId; + readonly category: ReasoningEvaluationCategory; + readonly setup: { + readonly source: "canonical-artifacts" | "governed-runtime" | "provider-source"; + }; + readonly mutation: ReasoningEvaluationMutation; + readonly expected: ReasoningEvaluationExpected; +} + +const CAPABILITY_REASONS: Partial> = { + "invocation-version": "invocation_version_unsupported", + "delivery-version": "delivery_envelope_version_unsupported", + "input-type": "input_content_type_unsupported", + "input-budget": "input_budget_exceeded", + "output-budget": "output_budget_exceeded", + "timeout-range": "timeout_out_of_range", + "cancellation-mode": "cancellation_mode_unsupported", + "retry-mode": "retry_mode_unsupported", + "usage-capability": "usage_evidence_unsupported", + "cost-capability": "cost_evidence_unsupported", + "failure-capability": "failure_evidence_unsupported", +}; + +function expectedFor( + scenarioId: ReasoningEvaluationScenarioId, + category: ReasoningEvaluationCategory, +): ReasoningEvaluationExpected { + if (category === "successful-execution") + return { + disposition: "accept", + errorCode: null, + status: scenarioId === "repeat-deterministic" ? "identical-finalized" : "finalized", + outcome: "succeeded", + reasonCodes: [], + attemptCount: 1, + durable: true, + fingerprintStatus: "valid", + attemptIdentity: scenarioId === "repeat-deterministic" ? "stable-replay" : "content-derived", + resultExpectation: "finalized", + evidenceExpectation: "verified", + finalizationExpectation: "committed", + }; + if (category === "delivery-binding") + return { + disposition: "reject", + errorCode: "delivery_integrity_failure", + status: null, + outcome: null, + reasonCodes: [], + attemptCount: 0, + durable: true, + fingerprintStatus: "not-applicable", + attemptIdentity: "none", + resultExpectation: "rejected", + evidenceExpectation: "none", + finalizationExpectation: "none", + }; + if (category === "capability") + return { + disposition: "reject", + errorCode: null, + status: "incompatible", + reasonCodes: [CAPABILITY_REASONS[scenarioId]!], + outcome: null, + attemptCount: 0, + durable: "not-applicable", + fingerprintStatus: "valid", + attemptIdentity: "none", + resultExpectation: "none", + evidenceExpectation: "verified", + finalizationExpectation: "none", + }; + if (category === "idempotency") + return { + disposition: "resolve", + errorCode: scenarioId === "conflicting-key" ? "idempotency_conflict" : null, + status: + scenarioId === "conflicting-key" || scenarioId === "conflicting-finalization" + ? "conflict" + : scenarioId === "in-progress" + ? "identical-in-progress" + : scenarioId === "identical-finalized" + ? "identical-finalized" + : "registered", + attemptCount: scenarioId === "first-ownership" || scenarioId === "in-progress" ? 0 : 1, + outcome: + scenarioId === "first-ownership" || scenarioId === "in-progress" ? null : "succeeded", + reasonCodes: [], + durable: true, + fingerprintStatus: "valid", + attemptIdentity: + scenarioId === "identical-finalized" + ? "stable-replay" + : scenarioId === "first-ownership" || scenarioId === "in-progress" + ? "none" + : "content-derived", + resultExpectation: + scenarioId === "first-ownership" || scenarioId === "in-progress" ? "none" : "finalized", + evidenceExpectation: "verified", + finalizationExpectation: + scenarioId === "conflicting-finalization" + ? "conflict" + : scenarioId === "first-ownership" || scenarioId === "in-progress" + ? "none" + : "committed", + }; + if (category === "retry") + return { + disposition: "resolve", + errorCode: null, + status: + scenarioId === "identical-attempt" || scenarioId === "conflicting-attempt" + ? "in-progress" + : "finalized", + outcome: + scenarioId === "transient-success" + ? "succeeded" + : scenarioId === "permanent-no-retry" || scenarioId === "attempt-exhaustion" + ? "failed" + : null, + reasonCodes: + scenarioId === "attempt-exhaustion" + ? ["attempt_limit_exhausted"] + : scenarioId === "permanent-no-retry" + ? ["permanent_provider_failure"] + : [], + attemptCount: + scenarioId === "transient-success" || scenarioId === "attempt-exhaustion" ? 2 : 1, + durable: true, + fingerprintStatus: "valid", + attemptIdentity: scenarioId === "identical-attempt" ? "stable-replay" : "content-derived", + resultExpectation: + scenarioId === "identical-attempt" || scenarioId === "conflicting-attempt" + ? "none" + : "finalized", + evidenceExpectation: "verified", + finalizationExpectation: + scenarioId === "identical-attempt" || scenarioId === "conflicting-attempt" + ? "none" + : "committed", + }; + if (category === "timeout") { + if (scenarioId === "timeout-contradiction") + return { + disposition: "reject", + errorCode: null, + status: "invalid", + outcome: null, + reasonCodes: ["invalid_artifact"], + attemptCount: 1, + durable: "not-applicable", + fingerprintStatus: "invalid", + attemptIdentity: "content-derived", + resultExpectation: "rejected", + evidenceExpectation: "rejected", + finalizationExpectation: "none", + }; + return { + disposition: "resolve", + errorCode: null, + status: "finalized", + outcome: "timed-out", + attemptCount: scenarioId === "timeout-retry" ? 2 : 1, + reasonCodes: ["execution_deadline_reached"], + durable: true, + fingerprintStatus: "valid", + attemptIdentity: "content-derived", + resultExpectation: "finalized", + evidenceExpectation: "verified", + finalizationExpectation: "committed", + }; + } + if (category === "cancellation") { + if (scenarioId === "cancel-contradiction") + return { + disposition: "reject", + errorCode: null, + status: "invalid", + outcome: null, + reasonCodes: ["invalid_artifact"], + attemptCount: 1, + durable: "not-applicable", + fingerprintStatus: "invalid", + attemptIdentity: "content-derived", + resultExpectation: "rejected", + evidenceExpectation: "rejected", + finalizationExpectation: "none", + }; + return { + disposition: "resolve", + errorCode: null, + status: "finalized", + outcome: "cancelled", + attemptCount: 1, + reasonCodes: [ + scenarioId === "cancel-before" + ? "cancelled_before_execution" + : scenarioId === "cancel-deadline" + ? "cancelled_at_deadline" + : "cancelled_cooperatively", + ], + durable: true, + fingerprintStatus: "valid", + attemptIdentity: "content-derived", + resultExpectation: "finalized", + evidenceExpectation: "verified", + finalizationExpectation: "committed", + }; + } + if (category === "evidence-integrity") + return { + disposition: "reject", + errorCode: null, + status: "invalid", + outcome: null, + reasonCodes: ["fingerprint_mismatch"], + fingerprintStatus: "invalid", + durable: true, + attemptCount: 1, + attemptIdentity: "content-derived", + resultExpectation: "finalized", + evidenceExpectation: "rejected", + finalizationExpectation: "committed", + }; + if (category === "fake-provider-safety") + return { + disposition: "reject", + errorCode: null, + status: ["physical-path", "credential", "malformed", "contradictory"].includes(scenarioId) + ? "finalized" + : "safe", + outcome: ["physical-path", "credential", "malformed", "contradictory"].includes(scenarioId) + ? "failed" + : null, + reasonCodes: + scenarioId === "physical-path" + ? ["physical_path_rejected"] + : scenarioId === "credential" + ? ["credential_material_rejected"] + : scenarioId === "malformed" + ? ["malformed_success_outcome"] + : scenarioId === "contradictory" + ? ["invalid_provider_outcome"] + : [], + attemptCount: ["physical-path", "credential", "malformed", "contradictory"].includes( + scenarioId, + ) + ? 1 + : 0, + durable: ["physical-path", "credential", "malformed", "contradictory"].includes(scenarioId) + ? true + : "not-applicable", + fingerprintStatus: ["physical-path", "credential", "malformed", "contradictory"].includes( + scenarioId, + ) + ? "valid" + : "not-applicable", + attemptIdentity: ["physical-path", "credential", "malformed", "contradictory"].includes( + scenarioId, + ) + ? "content-derived" + : "none", + resultExpectation: ["physical-path", "credential", "malformed", "contradictory"].includes( + scenarioId, + ) + ? "finalized" + : "none", + evidenceExpectation: "sanitized", + finalizationExpectation: [ + "physical-path", + "credential", + "malformed", + "contradictory", + ].includes(scenarioId) + ? "committed" + : "none", + }; + if (scenarioId === "low-level-finalization") + return { + disposition: "reject", + errorCode: null, + status: "absent", + outcome: null, + reasonCodes: [], + attemptCount: 0, + durable: true, + fingerprintStatus: "not-applicable", + attemptIdentity: "none", + resultExpectation: "rejected", + evidenceExpectation: "none", + finalizationExpectation: "none", + }; + return { + disposition: "reject", + errorCode: "invalid_invocation", + status: "invalid", + outcome: null, + reasonCodes: [], + attemptCount: 0, + durable: true, + fingerprintStatus: "not-applicable", + attemptIdentity: "none", + resultExpectation: "rejected", + evidenceExpectation: "none", + finalizationExpectation: "none", + }; +} + +function isTargetedScenario( + scenarioId: ReasoningEvaluationScenarioId, +): scenarioId is TargetedReasoningEvaluationScenarioId { + return scenarioId in RETAINED_MUTATION_TARGETS; +} + +function mutationFor(scenarioId: ReasoningEvaluationScenarioId): ReasoningEvaluationMutation { + return isTargetedScenario(scenarioId) + ? { operation: scenarioId, target: RETAINED_MUTATION_TARGETS[scenarioId] } + : { operation: scenarioId }; +} + +export const EXECUTABLE_REASONING_EVALUATIONS: readonly ReasoningEvaluation[] = + EVALUATION_CASES.map(([scenarioId, category]) => ({ + scenarioId, + category, + setup: { + source: + category === "fake-provider-safety" && + ["network-free", "environment-free", "randomness-free", "wall-clock-free"].includes( + scenarioId, + ) + ? "provider-source" + : category === "capability" || category === "evidence-integrity" + ? "canonical-artifacts" + : "governed-runtime", + }, + mutation: mutationFor(scenarioId), + expected: expectedFor(scenarioId, category), + })); diff --git a/services/knowledge-engine/tests/governed-reasoning.test.ts b/services/knowledge-engine/tests/governed-reasoning.test.ts new file mode 100644 index 0000000..a766f2c --- /dev/null +++ b/services/knowledge-engine/tests/governed-reasoning.test.ts @@ -0,0 +1,3278 @@ +import { mkdir, mkdtemp, readFile, rm, symlink, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { afterEach, describe, expect, it } from "vitest"; + +import type { + ReasoningExecutionAttempt, + ReasoningInvocationRequest, + ReasoningProviderCapabilityDescriptor, + ReasoningProviderOutcome, +} from "@founderos/knowledge-schema"; + +import * as PublicKnowledgeEngine from "../src/index.js"; +import { + countOutputCharacters, + countCanonicalCharacters, + createReasoningCancellationEvidence, + createReasoningExecutionAttempt, + createReasoningCostEvidence, + createReasoningExecutionReceipt, + createReasoningFailureEvidence, + createFinalizedReasoningConsumptionEvidence, + createReasoningInvocationRequest, + createReasoningProviderOutcome, + createReasoningProviderCapabilityDescriptor, + createReasoningResultEnvelope, + createReasoningTimeoutEvidence, + createReasoningUsageEvidence, + invokeGovernedReasoning, + matchReasoningProviderCapabilities, + openLocalFileGovernedReasoningExecutionEvidence, + verifyFinalizedReasoningConsumptionEvidence, + verifyReasoningProviderCompatibilityResult, + verifyReasoningResultEnvelope, +} from "../src/index.js"; +import { invokeGovernedReasoningWithProvider } from "../src/application/invoke-governed-reasoning.js"; +import { resolveInternalReasoningExecutionEvidence } from "../src/application/manage-governed-reasoning-execution-ledger.js"; +import { createDurableCanonicalJsonSha256Fingerprint } from "../src/domain/canonical-fingerprint.js"; +import { verifyReasoningAttemptLifecycle } from "../src/domain/reasoning.js"; +import { + createExecutionAttemptRecord, + createProviderOutcomeRecord, + createReasoningExecutionLedgerEvent, + ReasoningExecutionLedgerConflictError, + replayReasoningExecutionLedger, +} from "../src/domain/durable-reasoning-execution-ledger.js"; +import { createDeterministicFakeReasoningProvider } from "../src/infrastructure/deterministic-fake-reasoning-provider.js"; +import { runReasoningWriterSession } from "../src/infrastructure/local-file-governed-reasoning-execution-evidence.js"; +import { EXECUTABLE_REASONING_EVALUATIONS } from "./fixtures/reasoning-evaluations.js"; +import { executeReasoningEvaluation } from "./reasoning-evaluation-runner.js"; +import { createInvocation, createReasoningTestRuntime, schedule } from "./reasoning-fixtures.js"; + +const roots: string[] = []; +afterEach(async () => { + await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); +}); + +function createSuccessfulFinalizationArtifacts(input: { + readonly request: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly attempt: ReasoningExecutionAttempt; + readonly outcome: Extract; + readonly contextPackageObjectCount: number; + readonly transactionId: string; +}) { + const { request, providerCapability: provider, attempt, outcome } = input; + const executionReceipt = createReasoningExecutionReceipt({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + providerCapabilityId: provider.providerCapabilityId, + providerCapabilityFingerprint: provider.descriptorFingerprint, + attemptNumber: attempt.attemptNumber, + startedAt: attempt.startedAt, + completedAt: outcome.completedAt, + outcome: "succeeded", + }); + const usageEvidence = createReasoningUsageEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + inputCharacterCount: countCanonicalCharacters(request.reasoningInput), + outputCharacterCount: outcome.outputCharacterCount, + instructionBlockCount: request.reasoningInput.instructionBlocks.length, + contextPackageObjectCount: input.contextPackageObjectCount, + attemptNumber: attempt.attemptNumber, + durationMilliseconds: Date.parse(outcome.completedAt) - Date.parse(attempt.startedAt), + }); + const costEvidence = createReasoningCostEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + status: "not-applicable", + }); + const resultEnvelope = createReasoningResultEnvelope({ + schemaVersion: "1.0", + resultEnvelopeId: `reasoning-result-${createDurableCanonicalJsonSha256Fingerprint({ invocationRequestFingerprint: request.requestFingerprint, executionAttemptId: attempt.executionAttemptId, outcomeFingerprint: outcome.outcomeFingerprint })}`, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + deliveryTransactionId: request.deliveryTransactionId, + deliveryEnvelopeId: request.deliveryEnvelopeId, + deliveryEnvelopeFingerprint: request.deliveryEnvelopeFingerprint, + deliveryReceiptId: request.deliveryReceiptId, + deliveryReceiptFingerprint: request.deliveryReceiptFingerprint, + contextPackageId: request.contextPackageId, + contextPackageFingerprint: request.contextPackageFingerprint, + consumerId: request.consumerId, + consumerDescriptorFingerprint: request.consumerDescriptorFingerprint, + providerCapabilityId: provider.providerCapabilityId, + providerCapabilityFingerprint: provider.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + executionAttemptId: attempt.executionAttemptId, + attemptNumber: attempt.attemptNumber, + executionReceipt, + usageEvidence, + costEvidence, + completedAt: outcome.completedAt, + outcome: "succeeded", + outputContent: outcome.outputContent, + outputCharacterCount: outcome.outputCharacterCount, + outputContentFingerprint: outcome.outputContentFingerprint, + }); + const historyEntry = { + executionAttemptId: attempt.executionAttemptId, + attemptNumber: attempt.attemptNumber, + outcome: outcome.status, + attemptFingerprint: attempt.attemptFingerprint, + outcomeFingerprint: outcome.outcomeFingerprint, + }; + const historyUnsigned = { + attemptCount: 1, + finalAttemptNumber: 1, + finalOutcome: outcome.status, + attempts: [historyEntry], + }; + const consumptionEvidence = createFinalizedReasoningConsumptionEvidence({ + schemaVersion: "1.0", + consumptionId: `reasoning-consumption-${createDurableCanonicalJsonSha256Fingerprint({ resultEnvelopeFingerprint: resultEnvelope.resultEnvelopeFingerprint })}`, + deliveryReceiptId: request.deliveryReceiptId, + deliveryReceiptFingerprint: request.deliveryReceiptFingerprint, + deliveryTransactionId: request.deliveryTransactionId, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: provider.providerCapabilityId, + providerCapabilityFingerprint: provider.descriptorFingerprint, + finalResultEnvelopeId: resultEnvelope.resultEnvelopeId, + finalResultEnvelopeFingerprint: resultEnvelope.resultEnvelopeFingerprint, + finalOutcome: "succeeded", + attemptHistorySummary: { + ...historyUnsigned, + historyFingerprint: createDurableCanonicalJsonSha256Fingerprint(historyUnsigned), + }, + startedAt: attempt.startedAt, + completedAt: outcome.completedAt, + usageEvidenceFingerprint: usageEvidence.usageFingerprint, + costEvidenceFingerprint: costEvidence.costFingerprint, + executionLedgerTransactionId: input.transactionId, + }); + return { resultEnvelope, consumptionEvidence }; +} + +describe("Milestone 13 governed provider-neutral reasoning", () => { + it("defines a complete executable evaluation matrix", () => { + const ids = EXECUTABLE_REASONING_EVALUATIONS.map((entry) => entry.scenarioId); + expect(new Set(ids).size).toBe(ids.length); + expect(new Set(EXECUTABLE_REASONING_EVALUATIONS.map((entry) => entry.category))).toEqual( + new Set([ + "successful-execution", + "delivery-binding", + "capability", + "idempotency", + "retry", + "timeout", + "cancellation", + "evidence-integrity", + "fake-provider-safety", + "no-provider-bypass", + ]), + ); + }); + + it("fails every retained semantic target when the definition changes it", async () => { + let targetedCount = 0; + for (const evaluation of EXECUTABLE_REASONING_EVALUATIONS) { + if (evaluation.mutation.target === undefined) continue; + targetedCount += 1; + const changed = { + ...evaluation, + mutation: { + ...evaluation.mutation, + target: `changed.${evaluation.mutation.target}`, + }, + }; + await expect(executeReasoningEvaluation(changed, roots)).rejects.toBeDefined(); + } + expect(targetedCount).toBe(22); + }); + + it.each(EXECUTABLE_REASONING_EVALUATIONS)( + "executes evaluation $scenarioId", + async (evaluation) => { + await executeReasoningEvaluation(evaluation, roots); + }, + ); + + it("executes one exact durable Delivery and returns byte-identical finalized replay after restart", async () => { + const runtime = await createReasoningTestRuntime(roots); + const invocationRequest = createInvocation(runtime); + const sourceBefore = JSON.stringify( + await runtime.deliveryLedger.listCommittedOriginalDeliveries(), + ); + await writeFile( + join(runtime.reasoningRuntimeRoot, "events", "0000000000000001.json"), + "uncommitted suffix ignored by the atomic head\n", + ); + const first = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + expect(first.status).toBe("finalized"); + if (first.status === "identical-in-progress") throw new Error("unexpected in-progress result"); + expect(first.resultEnvelope.outcome).toBe("succeeded"); + expect(first.resultEnvelope.costEvidence.status).toBe("not-applicable"); + expect(first.consumptionEvidence.finalResultEnvelopeFingerprint).toBe( + first.resultEnvelope.resultEnvelopeFingerprint, + ); + const reopened = await openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: runtime.repositoryRoot, + runtimeRoot: runtime.reasoningRuntimeRoot, + canonicalSourceRoots: runtime.canonicalSourceRoots, + }); + const replay = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: reopened, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + expect(replay.status).toBe("identical-finalized"); + expect( + JSON.stringify(replay.status === "identical-in-progress" ? replay : replay.resultEnvelope), + ).toBe(JSON.stringify(first.resultEnvelope)); + expect(await reopened.readAttemptHistory(invocationRequest.invocationRequestId)).toHaveLength( + 1, + ); + expect(JSON.stringify(await runtime.deliveryLedger.listCommittedOriginalDeliveries())).toBe( + sourceBefore, + ); + expect((await reopened.recover()).status).toBe("recovered"); + expect((await reopened.verifyIntegrity()).status).toBe("valid"); + }); + + it("retries deterministic transient failure once and preserves both immutable Attempts", async () => { + const runtime = await createReasoningTestRuntime(roots); + const invocationRequest = createInvocation(runtime, { + idempotencyKey: "reasoning:key:retry", + retryMode: "retry-deterministic-transient-failure", + maxAttemptCount: 2, + }); + const result = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest, + fixtureMode: "transient-failure-then-success", + attemptSchedule: schedule(2), + }); + expect(result.status).toBe("finalized"); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress result"); + expect(result.resultEnvelope.outcome).toBe("succeeded"); + expect(result.consumptionEvidence.attemptHistorySummary.attemptCount).toBe(2); + const attempts = await runtime.executionEvidence.readAttemptHistory( + invocationRequest.invocationRequestId, + ); + expect(result.consumptionEvidence.startedAt).toBe(attempts[0]!.startedAt); + expect(result.consumptionEvidence.completedAt).toBe(result.resultEnvelope.completedAt); + expect(attempts[1]?.previousExecutionAttemptId).toBe(attempts[0]?.executionAttemptId); + expect( + (await runtime.executionEvidence.readProviderOutcome(attempts[0]!.executionAttemptId)) + ?.status, + ).toBe("failed"); + }); + + it("finalizes stable attempt-exhaustion evidence and permits timeout retry only by policy", async () => { + const exhaustedRuntime = await createReasoningTestRuntime(roots); + const exhaustedRequest = createInvocation(exhaustedRuntime, { + idempotencyKey: "reasoning:key:exhausted", + retryMode: "retry-deterministic-transient-failure", + maxAttemptCount: 2, + }); + const exhausted = await invokeGovernedReasoning({ + deliveryLedger: exhaustedRuntime.deliveryLedger, + executionEvidence: exhaustedRuntime.executionEvidence, + deliveryIdentity: exhaustedRuntime.deliveryIdentity, + invocationRequest: exhaustedRequest, + fixtureMode: "deterministic-transient-failure", + attemptSchedule: schedule(2), + }); + if (exhausted.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(exhausted.resultEnvelope.outcome).toBe("failed"); + if (exhausted.resultEnvelope.outcome === "failed") + expect(exhausted.resultEnvelope.failureEvidence.reasonCodes).toEqual([ + "attempt_limit_exhausted", + ]); + expect(exhausted.consumptionEvidence.attemptHistorySummary.attemptCount).toBe(2); + + const timeoutRuntime = await createReasoningTestRuntime(roots); + const timeoutRequest = createInvocation(timeoutRuntime, { + idempotencyKey: "reasoning:key:timeout-retry", + retryMode: "retry-until-attempt-limit", + maxAttemptCount: 2, + }); + const timeout = await invokeGovernedReasoning({ + deliveryLedger: timeoutRuntime.deliveryLedger, + executionEvidence: timeoutRuntime.executionEvidence, + deliveryIdentity: timeoutRuntime.deliveryIdentity, + invocationRequest: timeoutRequest, + fixtureMode: "timeout", + attemptSchedule: schedule(2).map((entry) => ({ + ...entry, + completedAt: entry.deadlineAt, + })), + }); + if (timeout.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(timeout.resultEnvelope.outcome).toBe("timed-out"); + expect(timeout.consumptionEvidence.attemptHistorySummary.attemptCount).toBe(2); + }); + + it.each([ + ["deterministic-permanent-failure", "failed"], + ["timeout", "timed-out"], + ["output-budget-overflow", "failed"], + ["malformed-success-outcome", "failed"], + ["malformed-failure-outcome", "failed"], + ["contradictory-outcome", "failed"], + ["physical-path-bearing-outcome", "failed"], + ["credential-bearing-outcome", "failed"], + ] as const)("fails closed for deterministic fixture %s", async (fixtureMode, expected) => { + const runtime = await createReasoningTestRuntime(roots); + const invocationRequest = createInvocation(runtime, { + idempotencyKey: `reasoning:key:${fixtureMode}`, + maxOutputCharacters: fixtureMode === "output-budget-overflow" ? 64 : 4_000, + }); + const result = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest, + fixtureMode, + attemptSchedule: + fixtureMode === "timeout" + ? [{ ...schedule()[0]!, completedAt: "2026-07-29T01:00:02.000Z" }] + : schedule(), + }); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress result"); + expect(result.resultEnvelope.outcome).toBe(expected); + expect(JSON.stringify(result)).not.toMatch(/\/private\/|api_key|fixture-secret-value/u); + }); + + it.each([ + ["cancellation-before-execution", "cancel-before-execution", "requested-before-execution"], + ["cooperative-cancellation", "cooperative-cancellation", "requested-cooperatively"], + ["deadline-cancellation", "deadline-cancellation", "requested-at-deadline"], + ] as const)("records explicit %s evidence", async (fixtureMode, cancellationMode, state) => { + const runtime = await createReasoningTestRuntime(roots); + const invocationRequest = createInvocation(runtime, { + idempotencyKey: `reasoning:key:${fixtureMode}`, + cancellationMode, + }); + const cancellationSignal = { + state, + authorityReference: "authority/evaluation", + requestedAt: + state === "requested-before-execution" + ? "2026-07-29T01:00:00.900Z" + : state === "requested-at-deadline" + ? "2026-07-29T01:00:02.000Z" + : "2026-07-29T01:00:01.010Z", + observedAt: + state === "requested-before-execution" + ? "2026-07-29T01:00:00.950Z" + : state === "requested-at-deadline" + ? "2026-07-29T01:00:02.000Z" + : "2026-07-29T01:00:01.050Z", + } as const; + const result = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest, + fixtureMode, + attemptSchedule: + state === "requested-at-deadline" + ? [ + { + ...schedule(1, cancellationSignal)[0]!, + completedAt: "2026-07-29T01:00:02.000Z", + }, + ] + : schedule(1, cancellationSignal), + }); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress result"); + expect(result.resultEnvelope.outcome).toBe("cancelled"); + }); + + it("enforces deadline and cancellation controls independently of provider fixture labels", async () => { + const deadlineRuntime = await createReasoningTestRuntime(roots); + const deadlineRequest = createInvocation(deadlineRuntime, { + idempotencyKey: "reasoning:key:controlled-deadline", + }); + const deadline = await invokeGovernedReasoning({ + deliveryLedger: deadlineRuntime.deliveryLedger, + executionEvidence: deadlineRuntime.executionEvidence, + deliveryIdentity: deadlineRuntime.deliveryIdentity, + invocationRequest: deadlineRequest, + fixtureMode: "successful-structured-response", + attemptSchedule: [{ ...schedule()[0]!, completedAt: schedule()[0]!.deadlineAt }], + }); + if (deadline.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(deadline.resultEnvelope.outcome).toBe("timed-out"); + + const cancelledRuntime = await createReasoningTestRuntime(roots); + const cancelledRequest = createInvocation(cancelledRuntime, { + idempotencyKey: "reasoning:key:controlled-cancel", + cancellationMode: "cancel-before-execution", + }); + const underlying = createDeterministicFakeReasoningProvider(); + let providerCalls = 0; + const provider = Object.freeze({ + providerCapability: underlying.providerCapability, + async execute(input: Parameters[0]) { + providerCalls += 1; + return underlying.execute(input); + }, + }); + const cancellationSignal = { + state: "requested-before-execution" as const, + authorityReference: "authority/independent-control", + requestedAt: "2026-07-29T01:00:00.900Z", + observedAt: "2026-07-29T01:00:00.950Z", + }; + const cancelled = await invokeGovernedReasoningWithProvider( + { + deliveryLedger: cancelledRuntime.deliveryLedger, + executionEvidence: cancelledRuntime.executionEvidence, + deliveryIdentity: cancelledRuntime.deliveryIdentity, + invocationRequest: cancelledRequest, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(1, cancellationSignal), + }, + provider, + ); + if (cancelled.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(cancelled.resultEnvelope.outcome).toBe("cancelled"); + expect(providerCalls).toBe(0); + }); + + it("cross-binds adversarial provider outcomes to the authorized Attempt and schedule before persistence", async () => { + const mutations = [ + { field: "invocationRequestId", value: "substituted-invocation" }, + { field: "executionAttemptId", value: "substituted-attempt" }, + { field: "attemptNumber", value: 2 }, + { field: "completedAt", value: "2026-07-29T01:00:02.100Z" }, + ] as const; + for (const mutation of mutations) { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:provider-${mutation.field}`, + }); + const underlying = createDeterministicFakeReasoningProvider(); + const provider = Object.freeze({ + providerCapability: underlying.providerCapability, + async execute(input: Parameters[0]) { + const baseline = await underlying.execute(input); + const { outcomeFingerprint: _fingerprint, ...unsigned } = baseline as ReturnType< + typeof createReasoningProviderOutcome + >; + void _fingerprint; + return createReasoningProviderOutcome({ ...unsigned, [mutation.field]: mutation.value }); + }, + }); + const authorizedTiming = schedule()[0]!; + const result = await invokeGovernedReasoningWithProvider( + { + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: [authorizedTiming], + }, + provider, + ); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(result.resultEnvelope.outcome).toBe("failed"); + if (result.resultEnvelope.outcome === "failed") + expect(result.resultEnvelope.failureEvidence.reasonCodes).toEqual([ + "invalid_provider_outcome", + ]); + const attempts = await runtime.executionEvidence.readAttemptHistory( + request.invocationRequestId, + ); + const stored = await runtime.executionEvidence.readProviderOutcome( + attempts[0]!.executionAttemptId, + ); + expect(stored).toMatchObject({ + invocationRequestId: request.invocationRequestId, + executionAttemptId: attempts[0]!.executionAttemptId, + attemptNumber: 1, + completedAt: authorizedTiming.completedAt, + status: "failed", + }); + expect((await runtime.executionEvidence.verifyIntegrity()).status).toBe("valid"); + } + + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:provider-accessor", + }); + const underlying = createDeterministicFakeReasoningProvider(); + let accessorReads = 0; + const provider = Object.freeze({ + providerCapability: underlying.providerCapability, + async execute() { + const raw = {}; + Object.defineProperty(raw, "completedAt", { + enumerable: true, + get() { + accessorReads += 1; + return "2026-07-29T01:00:02.100Z"; + }, + }); + return raw; + }, + }); + const authorizedTiming = schedule()[0]!; + const result = await invokeGovernedReasoningWithProvider( + { + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: [authorizedTiming], + }, + provider, + ); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(accessorReads).toBe(0); + expect(result.resultEnvelope.completedAt).toBe(authorizedTiming.completedAt); + expect((await runtime.executionEvidence.verifyIntegrity()).status).toBe("valid"); + expect("invokeGovernedReasoningWithProvider" in PublicKnowledgeEngine).toBe(false); + }); + + it("enforces exact successful output type and non-empty requirements at the provider seam and independent verifier", async () => { + const cases = [ + { + name: "text-to-json", + outputContentType: "canonical-text" as const, + requireNonEmpty: true, + outputContent: { contentType: "canonical-json" as const, value: null }, + }, + { + name: "json-to-text", + outputContentType: "canonical-json" as const, + requireNonEmpty: true, + outputContent: { contentType: "canonical-text" as const, text: "unexpected" }, + }, + { + name: "required-empty", + outputContentType: "canonical-text" as const, + requireNonEmpty: true, + outputContent: { contentType: "canonical-text" as const, text: "" }, + }, + ]; + for (const testCase of cases) { + const seamRuntime = await createReasoningTestRuntime(roots); + const seamRequest = createInvocation(seamRuntime, { + idempotencyKey: `reasoning:key:output-${testCase.name}`, + outputContentType: testCase.outputContentType, + requireNonEmpty: testCase.requireNonEmpty, + }); + const underlying = createDeterministicFakeReasoningProvider(); + const seamProvider = Object.freeze({ + providerCapability: underlying.providerCapability, + async execute(input: Parameters[0]) { + const outputCharacterCount = countOutputCharacters(testCase.outputContent); + return createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: input.attempt.executionAttemptId, + invocationRequestId: input.invocationRequest.invocationRequestId, + attemptNumber: input.attempt.attemptNumber, + completedAt: input.completedAt, + status: "succeeded", + outputContent: testCase.outputContent, + outputCharacterCount, + outputContentFingerprint: createDurableCanonicalJsonSha256Fingerprint( + testCase.outputContent, + ), + }); + }, + }); + const seamResult = await invokeGovernedReasoningWithProvider( + { + deliveryLedger: seamRuntime.deliveryLedger, + executionEvidence: seamRuntime.executionEvidence, + deliveryIdentity: seamRuntime.deliveryIdentity, + invocationRequest: seamRequest, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }, + seamProvider, + ); + if (seamResult.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(seamResult.resultEnvelope.outcome).toBe("failed"); + if (seamResult.resultEnvelope.outcome === "failed") + expect(seamResult.resultEnvelope.failureEvidence.reasonCodes).toEqual([ + "malformed_success_outcome", + ]); + + const verifierRuntime = await createReasoningTestRuntime(roots); + const verifierRequest = createInvocation(verifierRuntime, { + idempotencyKey: `reasoning:key:verify-output-${testCase.name}`, + outputContentType: testCase.outputContentType, + requireNonEmpty: testCase.requireNonEmpty, + }); + const baseline = await invokeGovernedReasoning({ + deliveryLedger: verifierRuntime.deliveryLedger, + executionEvidence: verifierRuntime.executionEvidence, + deliveryIdentity: verifierRuntime.deliveryIdentity, + invocationRequest: verifierRequest, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + if (baseline.status === "identical-in-progress") throw new Error("unexpected in-progress"); + if (baseline.resultEnvelope.outcome !== "succeeded") + throw new Error("expected successful verifier baseline"); + const attempt = ( + await verifierRuntime.executionEvidence.readAttemptHistory( + verifierRequest.invocationRequestId, + ) + )[0]!; + const outputCharacterCount = countOutputCharacters(testCase.outputContent); + const substitutedOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: verifierRequest.invocationRequestId, + attemptNumber: attempt.attemptNumber, + completedAt: baseline.resultEnvelope.completedAt, + status: "succeeded", + outputContent: testCase.outputContent, + outputCharacterCount, + outputContentFingerprint: createDurableCanonicalJsonSha256Fingerprint( + testCase.outputContent, + ), + }); + if (substitutedOutcome.status !== "succeeded") + throw new Error("expected substituted success outcome"); + const { usageFingerprint: _usageFingerprint, ...usageUnsigned } = + baseline.resultEnvelope.usageEvidence; + const { resultEnvelopeFingerprint: _resultFingerprint, ...resultUnsigned } = + baseline.resultEnvelope; + void _usageFingerprint; + void _resultFingerprint; + const substitutedResult = createReasoningResultEnvelope({ + ...resultUnsigned, + outputContent: testCase.outputContent, + outputCharacterCount, + outputContentFingerprint: substitutedOutcome.outputContentFingerprint, + usageEvidence: createReasoningUsageEvidence({ + ...usageUnsigned, + outputCharacterCount, + }), + }); + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: substitutedResult, + invocationRequest: verifierRequest, + providerCapability: createDeterministicFakeReasoningProvider().providerCapability, + attempt, + attemptHistory: [attempt], + providerOutcome: substitutedOutcome, + outcomeHistory: [substitutedOutcome], + contextPackageObjectCount: + verifierRuntime.fixture.result.envelope.contextPackage.included.length, + }).status, + ).toBe("invalid"); + } + }); + + it("rejects pre-deadline timeout fixtures and gives cooperative observation exact deadline precedence", async () => { + const invalidRuntime = await createReasoningTestRuntime(roots); + const invalidRequest = createInvocation(invalidRuntime, { + idempotencyKey: "reasoning:key:predeadline-timeout", + }); + await expect( + invokeGovernedReasoning({ + deliveryLedger: invalidRuntime.deliveryLedger, + executionEvidence: invalidRuntime.executionEvidence, + deliveryIdentity: invalidRuntime.deliveryIdentity, + invocationRequest: invalidRequest, + fixtureMode: "timeout", + attemptSchedule: schedule(), + }), + ).rejects.toMatchObject({ code: "invalid_schedule" }); + expect((await invalidRuntime.executionEvidence.verifyIntegrity()).verifiedInvocationCount).toBe( + 0, + ); + + const precedenceRuntime = await createReasoningTestRuntime(roots); + const precedenceRequest = createInvocation(precedenceRuntime, { + idempotencyKey: "reasoning:key:deadline-precedence", + cancellationMode: "cooperative-cancellation", + }); + const lateCancellation = { + state: "requested-cooperatively" as const, + authorityReference: "authority/late-cooperative-cancel", + requestedAt: "2026-07-29T01:00:01.900Z", + observedAt: "2026-07-29T01:00:02.050Z", + }; + const precedence = await invokeGovernedReasoning({ + deliveryLedger: precedenceRuntime.deliveryLedger, + executionEvidence: precedenceRuntime.executionEvidence, + deliveryIdentity: precedenceRuntime.deliveryIdentity, + invocationRequest: precedenceRequest, + fixtureMode: "successful-structured-response", + attemptSchedule: [ + { + ...schedule(1, lateCancellation)[0]!, + completedAt: "2026-07-29T01:00:02.100Z", + }, + ], + }); + if (precedence.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(precedence.resultEnvelope.outcome).toBe("timed-out"); + + const observedRuntime = await createReasoningTestRuntime(roots); + const observedRequest = createInvocation(observedRuntime, { + idempotencyKey: "reasoning:key:cooperative-observation-precedence", + cancellationMode: "cooperative-cancellation", + }); + const earlyObservedCancellation = { + state: "requested-cooperatively" as const, + authorityReference: "authority/early-observed-cooperative-cancel", + requestedAt: "2026-07-29T01:00:01.900Z", + observedAt: "2026-07-29T01:00:01.950Z", + }; + const observed = await invokeGovernedReasoning({ + deliveryLedger: observedRuntime.deliveryLedger, + executionEvidence: observedRuntime.executionEvidence, + deliveryIdentity: observedRuntime.deliveryIdentity, + invocationRequest: observedRequest, + fixtureMode: "successful-structured-response", + attemptSchedule: [ + { + ...schedule(1, earlyObservedCancellation)[0]!, + completedAt: "2026-07-29T01:00:02.100Z", + }, + ], + }); + if (observed.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(observed.resultEnvelope.outcome).toBe("cancelled"); + if (observed.resultEnvelope.outcome !== "cancelled") throw new Error("expected cancellation"); + expect(observed.resultEnvelope.cancellationEvidence.observedAt).toBe( + earlyObservedCancellation.observedAt, + ); + }); + + it("validates the complete Attempt schedule before durable ownership", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:invalid-complete-schedule", + retryMode: "retry-until-attempt-limit", + maxAttemptCount: 2, + }); + await expect( + invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(1), + }), + ).rejects.toMatchObject({ code: "invalid_schedule" }); + expect((await runtime.executionEvidence.verifyIntegrity()).verifiedInvocationCount).toBe(0); + expect(await runtime.executionEvidence.readInvocationRequest(request.invocationRequestId)).toBe( + null, + ); + }); + + it("rejects unsupported fixture modes before claiming Invocation ownership", async () => { + const runtime = await createReasoningTestRuntime(roots); + await expect( + invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: createInvocation(runtime), + fixtureMode: "unknown-fixture" as never, + attemptSchedule: schedule(), + }), + ).rejects.toMatchObject({ code: "invalid_invocation" }); + expect(await runtime.executionEvidence.readAttemptHistory("reasoning-invocation-0001")).toEqual( + [], + ); + expect((await runtime.executionEvidence.verifyIntegrity()).verifiedInvocationCount).toBe(0); + }); + + it("supports an empty success only when the output requirement permits it", async () => { + const runtime = await createReasoningTestRuntime(roots); + const invocationRequest = createInvocation(runtime, { + idempotencyKey: "reasoning:key:empty", + outputContentType: "canonical-text", + requireNonEmpty: false, + }); + const result = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest, + fixtureMode: "successful-empty-response", + attemptSchedule: schedule(), + }); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress result"); + expect(result.resultEnvelope.outcome).toBe("succeeded"); + if (result.resultEnvelope.outcome === "succeeded") + expect(result.resultEnvelope.outputCharacterCount).toBe(0); + }); + + it("returns stable ordered capability mismatches without mutating either artifact", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime); + const before = JSON.stringify(request); + const provider = createReasoningProviderCapabilityDescriptor({ + schemaVersion: "1.0", + providerCapabilityId: "incompatible-evaluation", + providerClass: "evaluation-provider", + acceptedInvocationRequestVersions: ["1.0"], + acceptedDeliveryEnvelopeVersions: ["1.0"], + acceptedInputContentTypes: ["provider-neutral-instruction-blocks-v1"], + acceptedOutputContentTypes: ["canonical-text"], + maxInputCharacters: 1, + maxOutputCharacters: 1, + minTimeoutMilliseconds: 2_000, + maxTimeoutMilliseconds: 3_000, + supportedCancellationModes: ["cooperative-cancellation"], + supportedRetryModes: ["retry-until-attempt-limit"], + supportsDeterministicExecution: false, + supportsUsageEvidence: false, + supportsCostEvidence: false, + supportsFailureEvidence: false, + supportedResultEnvelopeVersions: ["1.0"], + }); + const result = matchReasoningProviderCapabilities({ + invocationRequest: request, + providerCapability: provider, + }); + expect(result.status).toBe("incompatible"); + expect(result.reasonCodes).toEqual([...result.reasonCodes].sort()); + expect(result.reasonCodes.length).toBeGreaterThan(6); + expect(JSON.stringify(request)).toBe(before); + }); + + it("rejects a compatibility-verifier wrapper accessor without invoking it", async () => { + const runtime = await createReasoningTestRuntime(roots); + const invocationRequest = createInvocation(runtime); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const compatibility = matchReasoningProviderCapabilities({ + invocationRequest, + providerCapability, + }); + let accessorReads = 0; + const wrapper = { compatibility, invocationRequest, providerCapability }; + Object.defineProperty(wrapper, "compatibility", { + enumerable: true, + get() { + accessorReads += 1; + return compatibility; + }, + }); + expect(verifyReasoningProviderCompatibilityResult(wrapper as never).status).toBe("invalid"); + expect(accessorReads).toBe(0); + }); + + it("rejects Delivery substitutions, conflicting idempotency, accessors, and public low-level persistence bypass", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime); + await expect( + invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: { + ...runtime.deliveryIdentity, + deliveryReceiptFingerprint: "0".repeat(64), + }, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }), + ).rejects.toMatchObject({ code: "delivery_integrity_failure" }); + const input = { + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }; + let accesses = 0; + Object.defineProperty(input, "invocationRequest", { + enumerable: true, + get() { + accesses += 1; + return request; + }, + }); + await expect(invokeGovernedReasoning(input as never)).rejects.toMatchObject({ + code: "invalid_invocation", + }); + expect(accesses).toBe(0); + expect("registerInvocation" in runtime.executionEvidence).toBe(false); + expect("finalizeInvocation" in runtime.executionEvidence).toBe(false); + await expect( + invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + queryResult: { rawKnowledgeObjects: [] }, + } as never), + ).rejects.toMatchObject({ code: "invalid_invocation" }); + expect("createDeterministicFakeReasoningProvider" in PublicKnowledgeEngine).toBe(false); + expect("createGovernedReasoningExecutionEvidence" in PublicKnowledgeEngine).toBe(false); + }); + + it("keeps the sole fake-provider adapter free of network, credentials, randomness, implicit time, repository reads, and agents", async () => { + const source = await readFile( + new URL("../src/infrastructure/deterministic-fake-reasoning-provider.ts", import.meta.url), + "utf8", + ); + expect(source).not.toMatch( + /\b(?:fetch|Date\.now|Math\.random|process\.env|readFile|readdir|Repository|Hermes|MCP|agent)\b/u, + ); + }); + + it("classifies in-progress duplication, conflicting keys, and Attempt ID replay without rewriting evidence", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime); + const internal = resolveInternalReasoningExecutionEvidence(runtime.executionEvidence); + const provider = createDeterministicFakeReasoningProvider(); + const registered = await internal.registerGovernedInvocation( + { + schemaVersion: "1.0", + expectedLedgerHead: { ledgerSequence: 0, auditFingerprint: "genesis" }, + expectedIdempotencyState: "unowned", + invocationRequest: request, + registeredAt: request.requestedAt, + }, + { + providerCapability: provider.providerCapability, + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }, + ); + if (registered.status !== "registered") throw new Error("registration failed"); + const duplicate = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + expect(duplicate.status).toBe("identical-in-progress"); + + const { requestFingerprint: _fingerprint, ...unsigned } = request; + void _fingerprint; + const conflicting = createReasoningInvocationRequest({ + ...unsigned, + reason: "Conflicting canonical Invocation content", + }); + await expect( + invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: conflicting, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }), + ).rejects.toMatchObject({ code: "idempotency_conflict" }); + + const ledgerHead = await internal.verifyIntegrity(); + const attempt = createReasoningExecutionAttempt({ + schemaVersion: "1.0", + executionAttemptId: "attempt-replay-evaluation", + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: provider.providerCapability.providerCapabilityId, + providerCapabilityFingerprint: provider.providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: 1, + startedAt: schedule()[0]!.startedAt, + deadlineAt: schedule()[0]!.deadlineAt, + cancellationState: "not-requested", + }); + const append = { + schemaVersion: "1.0" as const, + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress" as const, + expectedPriorAttemptCount: 0, + attempt, + }; + expect(await internal.appendExecutionAttempt(append)).toEqual(attempt); + expect(await internal.appendExecutionAttempt(append)).toEqual(attempt); + const { attemptFingerprint: _attemptFingerprint, ...attemptUnsigned } = attempt; + void _attemptFingerprint; + const conflictingAttempt = createReasoningExecutionAttempt({ + ...attemptUnsigned, + startedAt: "2026-07-29T01:00:03.000Z", + deadlineAt: "2026-07-29T01:00:04.000Z", + }); + await expect( + internal.appendExecutionAttempt({ ...append, attempt: conflictingAttempt }), + ).rejects.toThrow(/different content/u); + expect(await internal.readAttemptHistory(request.invocationRequestId)).toEqual([attempt]); + }); + + it("enforces authoritative policy and prior-Outcome retry transitions during append and replay", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:append-lifecycle", + retryMode: "retry-deterministic-transient-failure", + maxAttemptCount: 2, + }); + const internal = resolveInternalReasoningExecutionEvidence(runtime.executionEvidence); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const registered = await internal.registerGovernedInvocation( + { + schemaVersion: "1.0", + expectedLedgerHead: { ledgerSequence: 0, auditFingerprint: "genesis" }, + expectedIdempotencyState: "unowned", + invocationRequest: request, + registeredAt: request.requestedAt, + }, + { + providerCapability, + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }, + ); + if (registered.status !== "registered") throw new Error("registration failed"); + const firstTiming = schedule(2)[0]!; + const firstAttempt = createReasoningExecutionAttempt({ + schemaVersion: "1.0", + executionAttemptId: "reasoning-attempt-append-lifecycle-1", + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: providerCapability.providerCapabilityId, + providerCapabilityFingerprint: providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: 1, + startedAt: firstTiming.startedAt, + deadlineAt: firstTiming.deadlineAt, + cancellationState: "not-requested", + }); + const firstHead = await internal.verifyIntegrity(); + const firstAppend = { + schemaVersion: "1.0" as const, + expectedLedgerHead: { + ledgerSequence: firstHead.verifiedThroughSequence, + auditFingerprint: firstHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress" as const, + expectedPriorAttemptCount: 0, + attempt: firstAttempt, + }; + const { attemptFingerprint: _firstFingerprint, ...firstUnsigned } = firstAttempt; + void _firstFingerprint; + const substitutedPolicyAttempt = createReasoningExecutionAttempt({ + ...firstUnsigned, + executionPolicyFingerprint: "0".repeat(64), + }); + await expect( + internal.appendExecutionAttempt({ ...firstAppend, attempt: substitutedPolicyAttempt }), + ).rejects.toThrow(/authoritative open Invocation/u); + await internal.appendExecutionAttempt(firstAppend); + + const secondTiming = schedule(2)[1]!; + const secondAttempt = createReasoningExecutionAttempt({ + ...firstUnsigned, + executionAttemptId: "reasoning-attempt-append-lifecycle-2", + attemptNumber: 2, + previousExecutionAttemptId: firstAttempt.executionAttemptId, + startedAt: secondTiming.startedAt, + deadlineAt: secondTiming.deadlineAt, + }); + const secondHead = await internal.verifyIntegrity(); + const secondAppend = { + ...firstAppend, + expectedLedgerHead: { + ledgerSequence: secondHead.verifiedThroughSequence, + auditFingerprint: secondHead.lastAuditFingerprint, + }, + expectedPriorAttemptCount: 1, + attempt: secondAttempt, + }; + await expect(internal.appendExecutionAttempt(secondAppend)).rejects.toThrow( + /authoritative open Invocation/u, + ); + + const ownershipEnvelope = JSON.parse( + await readFile(join(runtime.reasoningRuntimeRoot, "events", "0000000000000001.json"), "utf8"), + ) as { readonly event: unknown; readonly invocationAuthority: unknown }; + const firstAttemptEnvelope = JSON.parse( + await readFile(join(runtime.reasoningRuntimeRoot, "events", "0000000000000002.json"), "utf8"), + ) as { readonly event: { readonly auditFingerprint: string } }; + const secondRecord = createExecutionAttemptRecord({ + attempt: secondAttempt, + ledgerSequence: 3, + previousAuditFingerprint: firstAttemptEnvelope.event.auditFingerprint, + }); + const prematureSecondEvent = createReasoningExecutionLedgerEvent({ + eventType: "execution-attempt", + attemptRecord: secondRecord, + }); + expect(() => + replayReasoningExecutionLedger( + [ownershipEnvelope.event, firstAttemptEnvelope.event, prematureSecondEvent], + [ownershipEnvelope.invocationAuthority] as never, + ), + ).toThrow(/ordering or ownership/u); + + const permanentFailure = createReasoningFailureEvidence({ + schemaVersion: "1.0", + executionAttemptId: firstAttempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + failureCategory: "permanent-provider-failure", + reasonCodes: ["permanent_provider_failure"], + retryable: false, + sanitizedDetail: "Permanent append transition failure", + attemptNumber: 1, + }); + const permanentOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: firstAttempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 1, + completedAt: firstTiming.completedAt, + status: "failed", + failureEvidence: permanentFailure, + }); + await internal.appendProviderOutcome({ + schemaVersion: "1.0", + expectedLedgerHead: secondAppend.expectedLedgerHead, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + attemptFingerprint: firstAttempt.attemptFingerprint, + outcome: permanentOutcome, + }); + const outcomeHead = await internal.verifyIntegrity(); + await expect( + internal.appendExecutionAttempt({ + ...secondAppend, + expectedLedgerHead: { + ledgerSequence: outcomeHead.verifiedThroughSequence, + auditFingerprint: outcomeHead.lastAuditFingerprint, + }, + }), + ).rejects.toThrow(/authoritative open Invocation/u); + }); + + it("rejects coherent open-Attempt chronology and cancellation poison during append and replay", async () => { + const cases = [ + { + name: "first-before-request", + cancellationMode: "not-cancellable" as const, + startedAt: "2026-07-28T23:59:59.000Z", + deadlineAt: "2026-07-29T00:00:00.000Z", + cancellationState: "not-requested" as const, + }, + { + name: "before-observed-after-start", + cancellationMode: "cancel-before-execution" as const, + startedAt: "2026-07-29T01:00:01.000Z", + deadlineAt: "2026-07-29T01:00:02.000Z", + cancellationState: "requested-before-execution" as const, + cancellationRequestedAt: "2026-07-29T01:00:00.900Z", + cancellationObservedAt: "2026-07-29T01:00:01.050Z", + }, + { + name: "cooperative-request-before-start", + cancellationMode: "cooperative-cancellation" as const, + startedAt: "2026-07-29T01:00:01.000Z", + deadlineAt: "2026-07-29T01:00:02.000Z", + cancellationState: "requested-cooperatively" as const, + cancellationRequestedAt: "2026-07-29T01:00:00.900Z", + cancellationObservedAt: "2026-07-29T01:00:01.050Z", + }, + { + name: "deadline-request-before-deadline", + cancellationMode: "deadline-cancellation" as const, + startedAt: "2026-07-29T01:00:01.000Z", + deadlineAt: "2026-07-29T01:00:02.000Z", + cancellationState: "requested-at-deadline" as const, + cancellationRequestedAt: "2026-07-29T01:00:01.900Z", + cancellationObservedAt: "2026-07-29T01:00:02.000Z", + }, + { + name: "policy-mode-substitution", + cancellationMode: "cancel-before-execution" as const, + startedAt: "2026-07-29T01:00:01.000Z", + deadlineAt: "2026-07-29T01:00:02.000Z", + cancellationState: "requested-cooperatively" as const, + cancellationRequestedAt: "2026-07-29T01:00:01.010Z", + cancellationObservedAt: "2026-07-29T01:00:01.050Z", + }, + ] as const; + for (const poison of cases) { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:open-attempt-poison:${poison.name}`, + cancellationMode: poison.cancellationMode, + }); + const internal = resolveInternalReasoningExecutionEvidence(runtime.executionEvidence); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const registered = await internal.registerGovernedInvocation( + { + schemaVersion: "1.0", + expectedLedgerHead: { ledgerSequence: 0, auditFingerprint: "genesis" }, + expectedIdempotencyState: "unowned", + invocationRequest: request, + registeredAt: request.requestedAt, + }, + { + providerCapability, + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }, + ); + if (registered.status !== "registered") throw new Error("registration failed"); + const attempt = createReasoningExecutionAttempt({ + schemaVersion: "1.0", + executionAttemptId: `reasoning-attempt-open-poison-${poison.name}`, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: providerCapability.providerCapabilityId, + providerCapabilityFingerprint: providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: 1, + startedAt: poison.startedAt, + deadlineAt: poison.deadlineAt, + cancellationState: poison.cancellationState, + ...(poison.cancellationState === "not-requested" + ? {} + : { + cancellationAuthorityReference: `authority/open-poison-${poison.name}`, + cancellationRequestedAt: poison.cancellationRequestedAt, + cancellationObservedAt: poison.cancellationObservedAt, + }), + }); + const ownershipHead = await internal.verifyIntegrity(); + await expect( + internal.appendExecutionAttempt({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: ownershipHead.verifiedThroughSequence, + auditFingerprint: ownershipHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedPriorAttemptCount: 0, + attempt, + }), + ).rejects.toThrow(/authoritative open Invocation/u); + + const ownershipEnvelope = JSON.parse( + await readFile( + join(runtime.reasoningRuntimeRoot, "events", "0000000000000001.json"), + "utf8", + ), + ) as { + readonly event: { readonly auditFingerprint: string }; + readonly invocationAuthority: unknown; + }; + const poisonRecord = createExecutionAttemptRecord({ + attempt, + ledgerSequence: 2, + previousAuditFingerprint: ownershipEnvelope.event.auditFingerprint, + }); + expect(() => + replayReasoningExecutionLedger( + [ + ownershipEnvelope.event, + createReasoningExecutionLedgerEvent({ + eventType: "execution-attempt", + attemptRecord: poisonRecord, + }), + ], + [ownershipEnvelope.invocationAuthority] as never, + ), + ).toThrow(/ordering or ownership/u); + } + }); + + it("rejects a coherent retry Attempt that starts before its predecessor Outcome completes", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:retry-predecessor-chronology", + retryMode: "retry-deterministic-transient-failure", + maxAttemptCount: 2, + }); + const internal = resolveInternalReasoningExecutionEvidence(runtime.executionEvidence); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const registered = await internal.registerGovernedInvocation( + { + schemaVersion: "1.0", + expectedLedgerHead: { ledgerSequence: 0, auditFingerprint: "genesis" }, + expectedIdempotencyState: "unowned", + invocationRequest: request, + registeredAt: request.requestedAt, + }, + { + providerCapability, + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }, + ); + if (registered.status !== "registered") throw new Error("registration failed"); + const firstTiming = schedule(2)[0]!; + const firstAttempt = createReasoningExecutionAttempt({ + schemaVersion: "1.0", + executionAttemptId: "reasoning-attempt-retry-chronology-1", + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: providerCapability.providerCapabilityId, + providerCapabilityFingerprint: providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: 1, + startedAt: firstTiming.startedAt, + deadlineAt: firstTiming.deadlineAt, + cancellationState: "not-requested", + }); + let ledgerHead = await internal.verifyIntegrity(); + await internal.appendExecutionAttempt({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedPriorAttemptCount: 0, + attempt: firstAttempt, + }); + const failureEvidence = createReasoningFailureEvidence({ + schemaVersion: "1.0", + executionAttemptId: firstAttempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + failureCategory: "transient-provider-failure", + reasonCodes: ["transient_provider_failure"], + retryable: true, + sanitizedDetail: "Retry chronology baseline", + attemptNumber: 1, + }); + const firstOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: firstAttempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 1, + completedAt: "2026-07-29T01:00:01.500Z", + status: "failed", + failureEvidence, + }); + ledgerHead = await internal.verifyIntegrity(); + await internal.appendProviderOutcome({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + attemptFingerprint: firstAttempt.attemptFingerprint, + outcome: firstOutcome, + }); + const secondAttempt = createReasoningExecutionAttempt({ + schemaVersion: "1.0", + executionAttemptId: "reasoning-attempt-retry-chronology-2", + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: providerCapability.providerCapabilityId, + providerCapabilityFingerprint: providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: 2, + previousExecutionAttemptId: firstAttempt.executionAttemptId, + startedAt: "2026-07-29T01:00:01.400Z", + deadlineAt: "2026-07-29T01:00:02.400Z", + cancellationState: "not-requested", + }); + ledgerHead = await internal.verifyIntegrity(); + const secondAppend = { + schemaVersion: "1.0" as const, + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress" as const, + expectedPriorAttemptCount: 1, + attempt: secondAttempt, + }; + await expect(internal.appendExecutionAttempt(secondAppend)).rejects.toThrow( + /authoritative open Invocation/u, + ); + + const envelopes = await Promise.all( + [1, 2, 3].map(async (sequence) => + JSON.parse( + await readFile( + join( + runtime.reasoningRuntimeRoot, + "events", + sequence.toString().padStart(16, "0") + ".json", + ), + "utf8", + ), + ), + ), + ); + const secondRecord = createExecutionAttemptRecord({ + attempt: secondAttempt, + ledgerSequence: 4, + previousAuditFingerprint: envelopes[2].event.auditFingerprint, + }); + expect(() => + replayReasoningExecutionLedger( + [ + ...envelopes.map((envelope) => envelope.event), + createReasoningExecutionLedgerEvent({ + eventType: "execution-attempt", + attemptRecord: secondRecord, + }), + ], + [envelopes[0].invocationAuthority] as never, + ), + ).toThrow(/ordering or ownership/u); + }); + + it("rejects post-deadline and cancelled-state successes during append, finalization, and replay", async () => { + const exercise = async (kind: "post-deadline" | "cancelled-state") => { + const runtime = await createReasoningTestRuntime(roots); + const cancellationMode = + kind === "cancelled-state" ? "cooperative-cancellation" : "not-cancellable"; + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:persistence-${kind}`, + cancellationMode, + }); + const internal = resolveInternalReasoningExecutionEvidence(runtime.executionEvidence); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const registered = await internal.registerGovernedInvocation( + { + schemaVersion: "1.0", + expectedLedgerHead: { ledgerSequence: 0, auditFingerprint: "genesis" }, + expectedIdempotencyState: "unowned", + invocationRequest: request, + registeredAt: request.requestedAt, + }, + { + providerCapability, + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }, + ); + if (registered.status !== "registered") throw new Error("registration failed"); + const timing = schedule()[0]!; + const attempt = createReasoningExecutionAttempt({ + schemaVersion: "1.0", + executionAttemptId: `reasoning-attempt-persistence-${kind}`, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: providerCapability.providerCapabilityId, + providerCapabilityFingerprint: providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: 1, + startedAt: timing.startedAt, + deadlineAt: timing.deadlineAt, + cancellationState: kind === "cancelled-state" ? "requested-cooperatively" : "not-requested", + ...(kind === "cancelled-state" + ? { + cancellationAuthorityReference: "authority/persistence-terminal-control", + cancellationRequestedAt: "2026-07-29T01:00:01.010Z", + cancellationObservedAt: "2026-07-29T01:00:01.050Z", + } + : {}), + }); + const ownershipHead = await internal.verifyIntegrity(); + await internal.appendExecutionAttempt({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: ownershipHead.verifiedThroughSequence, + auditFingerprint: ownershipHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedPriorAttemptCount: 0, + attempt, + }); + const outputContent = { + contentType: "canonical-json" as const, + value: { status: "coherent-signed-success" }, + }; + const badOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 1, + completedAt: kind === "post-deadline" ? timing.deadlineAt : timing.completedAt, + status: "succeeded", + outputContent, + outputCharacterCount: countOutputCharacters(outputContent), + outputContentFingerprint: createDurableCanonicalJsonSha256Fingerprint(outputContent), + }); + if (badOutcome.status !== "succeeded") throw new Error("expected signed success attack"); + const attemptHead = await internal.verifyIntegrity(); + const badAppend = { + schemaVersion: "1.0" as const, + expectedLedgerHead: { + ledgerSequence: attemptHead.verifiedThroughSequence, + auditFingerprint: attemptHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress" as const, + attemptFingerprint: attempt.attemptFingerprint, + outcome: badOutcome, + }; + await expect(internal.appendProviderOutcome(badAppend)).rejects.toThrow( + /authoritative open Attempt/u, + ); + + const ownershipEnvelope = JSON.parse( + await readFile( + join(runtime.reasoningRuntimeRoot, "events", "0000000000000001.json"), + "utf8", + ), + ) as { readonly event: unknown; readonly invocationAuthority: unknown }; + const attemptEnvelope = JSON.parse( + await readFile( + join(runtime.reasoningRuntimeRoot, "events", "0000000000000002.json"), + "utf8", + ), + ) as { readonly event: { readonly auditFingerprint: string } }; + const badOutcomeRecord = createProviderOutcomeRecord({ + outcome: badOutcome, + ledgerSequence: 3, + previousAuditFingerprint: attemptEnvelope.event.auditFingerprint, + }); + const badOutcomeEvent = createReasoningExecutionLedgerEvent({ + eventType: "provider-outcome", + outcomeRecord: badOutcomeRecord, + }); + expect(() => + replayReasoningExecutionLedger( + [ownershipEnvelope.event, attemptEnvelope.event, badOutcomeEvent], + [ownershipEnvelope.invocationAuthority] as never, + ), + ).toThrow(/does not bind one open Attempt/u); + + const { outcomeFingerprint: _badOutcomeFingerprint, ...badOutcomeUnsigned } = badOutcome; + void _badOutcomeFingerprint; + const validOutcome = + kind === "post-deadline" + ? createReasoningProviderOutcome({ + ...badOutcomeUnsigned, + completedAt: timing.completedAt, + }) + : createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 1, + completedAt: timing.completedAt, + status: "cancelled", + cancellationEvidence: createReasoningCancellationEvidence({ + schemaVersion: "1.0", + invocationRequestId: request.invocationRequestId, + executionAttemptId: attempt.executionAttemptId, + cancellationMode: "cooperative-cancellation", + cancellationPhase: "cooperative-execution", + cancellationAuthorityReference: "authority/persistence-terminal-control", + requestedAt: "2026-07-29T01:00:01.010Z", + observedAt: "2026-07-29T01:00:01.050Z", + reasonCode: "cancelled_cooperatively", + }), + }); + await internal.appendProviderOutcome({ ...badAppend, outcome: validOutcome }); + + const transactionId = `reasoning-finalization-persistence-${kind}`; + const badArtifacts = createSuccessfulFinalizationArtifacts({ + request, + providerCapability, + attempt, + outcome: badOutcome, + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + transactionId, + }); + const outcomeHead = await internal.verifyIntegrity(); + await expect( + internal.finalizeInvocation({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: outcomeHead.verifiedThroughSequence, + auditFingerprint: outcomeHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedAttemptCount: 1, + transactionId, + resultEnvelope: badArtifacts.resultEnvelope, + consumptionEvidence: badArtifacts.consumptionEvidence, + finalizedAt: badOutcome.completedAt, + }), + ).rejects.toThrow(/does not verify against authoritative Attempts/u); + }; + await exercise("post-deadline"); + await exercise("cancelled-state"); + }); + + it("rejects a conflicting finalization without rewriting the committed result", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { idempotencyKey: "reasoning:key:final-conflict" }); + const finalized = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + if (finalized.status === "identical-in-progress") throw new Error("unexpected in-progress"); + const internal = resolveInternalReasoningExecutionEvidence(runtime.executionEvidence); + const ownership = await internal.resolveInvocationOwnership(request.idempotencyKey); + if (ownership === null) throw new Error("missing ownership"); + const { consumptionFingerprint: _fingerprint, ...consumptionUnsigned } = + finalized.consumptionEvidence; + void _fingerprint; + const transactionId = "reasoning-finalization-conflicting-evaluation"; + const consumption = createFinalizedReasoningConsumptionEvidence({ + ...consumptionUnsigned, + executionLedgerTransactionId: transactionId, + }); + const ledgerHead = await internal.verifyIntegrity(); + const conflict = await internal.finalizeInvocation({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedAttemptCount: consumption.attemptHistorySummary.attemptCount, + transactionId, + resultEnvelope: finalized.resultEnvelope, + consumptionEvidence: consumption, + finalizedAt: finalized.resultEnvelope.completedAt, + }); + expect(conflict.status).toBe("conflict"); + expect(await internal.readFinalizedResult(request.invocationRequestId)).toEqual( + finalized.resultEnvelope, + ); + }); + + it("detects Result and Consumption tampering, including re-signed semantic substitutions", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime); + const final = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + if (final.status === "identical-in-progress") throw new Error("unexpected in-progress result"); + const attempts = await runtime.executionEvidence.readAttemptHistory( + request.invocationRequestId, + ); + const outcome = await runtime.executionEvidence.readProviderOutcome( + attempts[0]!.executionAttemptId, + ); + if (outcome === null) throw new Error("missing outcome"); + const { resultEnvelopeFingerprint: _resultFingerprint, ...resultUnsigned } = + final.resultEnvelope; + void _resultFingerprint; + const tampered = createReasoningResultEnvelope({ + ...resultUnsigned, + consumerId: "substituted-consumer", + }); + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: tampered, + invocationRequest: request, + providerCapability: { + schemaVersion: "1.0", + providerCapabilityId: final.resultEnvelope.providerCapabilityId, + providerClass: "deterministic-fake-provider", + acceptedInvocationRequestVersions: ["1.0"], + acceptedDeliveryEnvelopeVersions: ["1.0"], + acceptedInputContentTypes: ["provider-neutral-instruction-blocks-v1"], + acceptedOutputContentTypes: ["canonical-json", "canonical-text"], + maxInputCharacters: 1_000_000, + maxOutputCharacters: 1_000_000, + minTimeoutMilliseconds: 1, + maxTimeoutMilliseconds: 86_400_000, + supportedCancellationModes: [ + "cancel-before-execution", + "cooperative-cancellation", + "deadline-cancellation", + "not-cancellable", + ], + supportedRetryModes: [ + "evaluation-only-retry", + "no-retry", + "retry-deterministic-transient-failure", + "retry-until-attempt-limit", + ], + supportsDeterministicExecution: true, + supportsUsageEvidence: true, + supportsCostEvidence: true, + supportsFailureEvidence: true, + supportedResultEnvelopeVersions: ["1.0"], + descriptorFingerprint: final.resultEnvelope.providerCapabilityFingerprint, + }, + attempt: attempts[0]!, + attemptHistory: attempts, + providerOutcome: outcome, + outcomeHistory: [outcome], + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }).status, + ).toBe("invalid"); + const provider = createDeterministicFakeReasoningProvider().providerCapability; + const contextPackageObjectCount = + runtime.fixture.result.envelope.contextPackage.included.length; + const { receiptFingerprint: _receiptFingerprint, ...receiptUnsigned } = + resultUnsigned.executionReceipt; + const { usageFingerprint: _usageFingerprint, ...usageUnsigned } = resultUnsigned.usageEvidence; + void _receiptFingerprint; + void _usageFingerprint; + const alteredOperationalEvidence = [ + createReasoningResultEnvelope({ + ...resultUnsigned, + executionReceipt: createReasoningExecutionReceipt({ + ...receiptUnsigned, + startedAt: request.requestedAt, + }), + }), + createReasoningResultEnvelope({ + ...resultUnsigned, + usageEvidence: createReasoningUsageEvidence({ + ...usageUnsigned, + durationMilliseconds: resultUnsigned.usageEvidence.durationMilliseconds + 1, + contextPackageObjectCount: contextPackageObjectCount + 1, + }), + }), + createReasoningResultEnvelope({ + ...resultUnsigned, + costEvidence: createReasoningCostEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempts[0]!.executionAttemptId, + status: "unavailable", + reasonCode: "cost_evidence_unavailable", + } as never), + }), + ]; + for (const candidate of alteredOperationalEvidence) + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: candidate, + invocationRequest: request, + providerCapability: provider, + attempt: attempts[0]!, + attemptHistory: attempts, + providerOutcome: outcome, + outcomeHistory: [outcome], + contextPackageObjectCount, + }).status, + ).toBe("invalid"); + const { consumptionFingerprint: _consumptionFingerprint, ...consumptionUnsigned } = + final.consumptionEvidence; + void _consumptionFingerprint; + const resignedConsumption = createFinalizedReasoningConsumptionEvidence({ + ...consumptionUnsigned, + executionLedgerTransactionId: "reasoning-finalization-substituted", + }); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: resignedConsumption, + resultEnvelope: final.resultEnvelope, + invocationRequest: request, + providerCapability: provider, + attempts, + outcomes: [outcome], + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + executionLedgerTransactionId: final.consumptionEvidence.executionLedgerTransactionId, + }).status, + ).toBe("invalid"); + }); + + it("rejects public verifier wrapper and history accessors without invoking them", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:verifier-accessors", + }); + const final = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + if (final.status === "identical-in-progress") throw new Error("unexpected in-progress"); + const attempts = await runtime.executionEvidence.readAttemptHistory( + request.invocationRequestId, + ); + const outcome = await runtime.executionEvidence.readProviderOutcome( + attempts[0]!.executionAttemptId, + ); + if (outcome === null) throw new Error("missing outcome"); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const contextPackageObjectCount = + runtime.fixture.result.envelope.contextPackage.included.length; + let accessorReads = 0; + const resultWrapper = { + resultEnvelope: final.resultEnvelope, + invocationRequest: request, + providerCapability, + attempt: attempts[0]!, + attemptHistory: attempts, + providerOutcome: outcome, + outcomeHistory: [outcome], + contextPackageObjectCount, + }; + Object.defineProperty(resultWrapper, "providerOutcome", { + enumerable: true, + get() { + accessorReads += 1; + return outcome; + }, + }); + expect(verifyReasoningResultEnvelope(resultWrapper as never).status).toBe("invalid"); + expect(accessorReads).toBe(0); + + const consumptionBase = { + consumptionEvidence: final.consumptionEvidence, + resultEnvelope: final.resultEnvelope, + invocationRequest: request, + providerCapability, + attempts, + outcomes: [outcome], + contextPackageObjectCount, + executionLedgerTransactionId: final.consumptionEvidence.executionLedgerTransactionId, + }; + const consumptionWrapper = { ...consumptionBase }; + Object.defineProperty(consumptionWrapper, "attempts", { + enumerable: true, + get() { + accessorReads += 1; + return attempts; + }, + }); + expect(verifyFinalizedReasoningConsumptionEvidence(consumptionWrapper as never).status).toBe( + "invalid", + ); + expect(accessorReads).toBe(0); + + for (const arrayField of ["attempts", "outcomes"] as const) { + const accessorArray = [...consumptionBase[arrayField]]; + Object.defineProperty(accessorArray, "0", { + enumerable: true, + get() { + accessorReads += 1; + return consumptionBase[arrayField][0]; + }, + }); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + ...consumptionBase, + [arrayField]: accessorArray, + } as never).status, + ).toBe("invalid"); + expect(accessorReads).toBe(0); + } + }); + + it("independently verifies and exactly cross-binds every Result and Consumption context artifact", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:context-artifacts", + }); + const final = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + if (final.status === "identical-in-progress") throw new Error("unexpected in-progress"); + const attempt = ( + await runtime.executionEvidence.readAttemptHistory(request.invocationRequestId) + )[0]!; + const outcome = await runtime.executionEvidence.readProviderOutcome(attempt.executionAttemptId); + if (outcome === null) throw new Error("missing outcome"); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const contextPackageObjectCount = + runtime.fixture.result.envelope.contextPackage.included.length; + const assertInvalid = (context: { + readonly invocationRequest: unknown; + readonly providerCapability: unknown; + readonly attempt: unknown; + }) => { + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: final.resultEnvelope, + invocationRequest: context.invocationRequest, + providerCapability: context.providerCapability, + attempt: context.attempt, + attemptHistory: [context.attempt], + providerOutcome: outcome, + outcomeHistory: [outcome], + contextPackageObjectCount, + } as never).status, + ).toBe("invalid"); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: final.consumptionEvidence, + resultEnvelope: final.resultEnvelope, + invocationRequest: context.invocationRequest, + providerCapability: context.providerCapability, + attempts: [context.attempt], + outcomes: [outcome], + contextPackageObjectCount, + executionLedgerTransactionId: final.consumptionEvidence.executionLedgerTransactionId, + } as never).status, + ).toBe("invalid"); + }; + + const { requestFingerprint: _requestFingerprint, ...requestUnsigned } = request; + const { descriptorFingerprint: _descriptorFingerprint, ...providerUnsigned } = + providerCapability; + const { attemptFingerprint: _attemptFingerprint, ...attemptUnsigned } = attempt; + void _requestFingerprint; + void _descriptorFingerprint; + void _attemptFingerprint; + assertInvalid({ + invocationRequest: { ...request, reason: "Raw stale Request substitution" }, + providerCapability, + attempt, + }); + assertInvalid({ + invocationRequest: createReasoningInvocationRequest({ + ...requestUnsigned, + reason: "Re-signed Request substitution", + }), + providerCapability, + attempt, + }); + assertInvalid({ + invocationRequest: request, + providerCapability: { + ...providerCapability, + maxInputCharacters: providerCapability.maxInputCharacters + 1, + }, + attempt, + }); + assertInvalid({ + invocationRequest: request, + providerCapability: createReasoningProviderCapabilityDescriptor({ + ...providerUnsigned, + maxInputCharacters: providerCapability.maxInputCharacters + 1, + }), + attempt, + }); + assertInvalid({ + invocationRequest: request, + providerCapability, + attempt: { ...attempt, cancellationState: "requested-cooperatively" }, + }); + assertInvalid({ + invocationRequest: request, + providerCapability, + attempt: createReasoningExecutionAttempt({ + ...attemptUnsigned, + providerCapabilityId: "substituted-provider-capability", + }), + }); + + const retryRuntime = await createReasoningTestRuntime(roots); + const retryRequest = createInvocation(retryRuntime, { + idempotencyKey: "reasoning:key:context-attempt-chain", + retryMode: "retry-deterministic-transient-failure", + maxAttemptCount: 2, + }); + const retryFinal = await invokeGovernedReasoning({ + deliveryLedger: retryRuntime.deliveryLedger, + executionEvidence: retryRuntime.executionEvidence, + deliveryIdentity: retryRuntime.deliveryIdentity, + invocationRequest: retryRequest, + fixtureMode: "transient-failure-then-success", + attemptSchedule: schedule(2), + }); + if (retryFinal.status === "identical-in-progress") throw new Error("unexpected in-progress"); + const retryAttempts = await retryRuntime.executionEvidence.readAttemptHistory( + retryRequest.invocationRequestId, + ); + const retryOutcomes = await Promise.all( + retryAttempts.map((entry) => + retryRuntime.executionEvidence.readProviderOutcome(entry.executionAttemptId), + ), + ); + if (retryOutcomes.some((entry) => entry === null)) throw new Error("missing retry outcome"); + const finalRetryOutcome = retryOutcomes[1]; + if (finalRetryOutcome === null || finalRetryOutcome === undefined) + throw new Error("missing final retry outcome"); + const { attemptFingerprint: _secondFingerprint, ...secondUnsigned } = retryAttempts[1]!; + void _secondFingerprint; + for (const changedSecond of [ + createReasoningExecutionAttempt({ + ...secondUnsigned, + previousExecutionAttemptId: "substituted-predecessor", + }), + createReasoningExecutionAttempt({ ...secondUnsigned, attemptNumber: 3 }), + ]) { + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: retryFinal.resultEnvelope, + invocationRequest: retryRequest, + providerCapability, + attempt: changedSecond, + attemptHistory: [retryAttempts[0]!, changedSecond], + providerOutcome: finalRetryOutcome, + outcomeHistory: retryOutcomes as never, + contextPackageObjectCount: + retryRuntime.fixture.result.envelope.contextPackage.included.length, + }).status, + ).toBe("invalid"); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: retryFinal.consumptionEvidence, + resultEnvelope: retryFinal.resultEnvelope, + invocationRequest: retryRequest, + providerCapability, + attempts: [retryAttempts[0]!, changedSecond], + outcomes: retryOutcomes, + contextPackageObjectCount: + retryRuntime.fixture.result.envelope.contextPackage.included.length, + executionLedgerTransactionId: retryFinal.consumptionEvidence.executionLedgerTransactionId, + } as never).status, + ).toBe("invalid"); + } + }); + + it("rejects coherent re-signed over-limit, retry-transition, and policy substitutions", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:lifecycle-verification", + retryMode: "retry-deterministic-transient-failure", + maxAttemptCount: 2, + }); + const final = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "transient-failure-then-success", + attemptSchedule: schedule(2), + }); + if (final.status === "identical-in-progress") throw new Error("unexpected in-progress"); + const attempts = await runtime.executionEvidence.readAttemptHistory( + request.invocationRequestId, + ); + const outcomes = await Promise.all( + attempts.map((attempt) => + runtime.executionEvidence.readProviderOutcome(attempt.executionAttemptId), + ), + ); + if (outcomes.some((outcome) => outcome === null)) throw new Error("missing lifecycle outcome"); + const completeOutcomes = outcomes as Exclude<(typeof outcomes)[number], null>[]; + if ( + completeOutcomes[1]?.status !== "succeeded" || + final.resultEnvelope.outcome !== "succeeded" || + final.consumptionEvidence.finalOutcome !== "succeeded" + ) + throw new Error("expected successful lifecycle baseline"); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const contextPackageObjectCount = + runtime.fixture.result.envelope.contextPackage.included.length; + const assertPublicVerificationInvalid = ( + candidateAttempts: readonly (typeof attempts)[number][], + candidateOutcomes: readonly (typeof completeOutcomes)[number][], + resultEnvelope = final.resultEnvelope, + consumptionEvidence = final.consumptionEvidence, + ) => { + expect( + verifyReasoningResultEnvelope({ + resultEnvelope, + invocationRequest: request, + providerCapability, + attempt: candidateAttempts.at(-1)!, + attemptHistory: candidateAttempts, + providerOutcome: candidateOutcomes.at(-1)!, + outcomeHistory: candidateOutcomes, + contextPackageObjectCount, + }).status, + ).toBe("invalid"); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence, + resultEnvelope, + invocationRequest: request, + providerCapability, + attempts: candidateAttempts, + outcomes: candidateOutcomes, + contextPackageObjectCount, + executionLedgerTransactionId: consumptionEvidence.executionLedgerTransactionId, + }).status, + ).toBe("invalid"); + }; + + const permanentFailure = createReasoningFailureEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempts[0]!.executionAttemptId, + invocationRequestId: request.invocationRequestId, + failureCategory: "permanent-provider-failure", + reasonCodes: ["permanent_provider_failure"], + retryable: false, + sanitizedDetail: "Coherent permanent failure substitution", + attemptNumber: 1, + }); + const permanentOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempts[0]!.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 1, + completedAt: completeOutcomes[0]!.completedAt, + status: "failed", + failureEvidence: permanentFailure, + }); + const timeoutEvidence = createReasoningTimeoutEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempts[0]!.executionAttemptId, + invocationRequestId: request.invocationRequestId, + configuredTimeoutMilliseconds: request.executionPolicy.timeoutMilliseconds, + attemptStartedAt: attempts[0]!.startedAt, + deadlineAt: attempts[0]!.deadlineAt!, + elapsedMilliseconds: request.executionPolicy.timeoutMilliseconds, + timeoutPhase: "during-execution", + reasonCode: "execution_timeout", + }); + const timeoutOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempts[0]!.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 1, + completedAt: completeOutcomes[0]!.completedAt, + status: "timed-out", + timeoutEvidence, + }); + const cancellationEvidence = createReasoningCancellationEvidence({ + schemaVersion: "1.0", + invocationRequestId: request.invocationRequestId, + executionAttemptId: attempts[0]!.executionAttemptId, + cancellationMode: "cooperative-cancellation", + cancellationPhase: "cooperative-execution", + cancellationAuthorityReference: "authority/coherent-cancellation-substitution", + requestedAt: attempts[0]!.startedAt, + observedAt: completeOutcomes[0]!.completedAt, + reasonCode: "cancelled_cooperatively", + }); + const cancellationOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempts[0]!.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 1, + completedAt: completeOutcomes[0]!.completedAt, + status: "cancelled", + cancellationEvidence, + }); + const { outcomeFingerprint: _successfulFingerprint, ...successfulUnsigned } = + completeOutcomes[1]!; + void _successfulFingerprint; + const successfulOutcome = createReasoningProviderOutcome({ + ...successfulUnsigned, + executionAttemptId: attempts[0]!.executionAttemptId, + attemptNumber: 1, + completedAt: completeOutcomes[0]!.completedAt, + }); + for (const unauthorizedPriorOutcome of [ + permanentOutcome, + timeoutOutcome, + cancellationOutcome, + successfulOutcome, + ]) + assertPublicVerificationInvalid(attempts, [unauthorizedPriorOutcome, completeOutcomes[1]!]); + + const { attemptFingerprint: _attemptFingerprint, ...secondAttemptUnsigned } = attempts[1]!; + void _attemptFingerprint; + const substitutedPolicyAttempt = createReasoningExecutionAttempt({ + ...secondAttemptUnsigned, + executionPolicyFingerprint: "0".repeat(64), + }); + assertPublicVerificationInvalid([attempts[0]!, substitutedPolicyAttempt], completeOutcomes); + + const secondTransientFailure = createReasoningFailureEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempts[1]!.executionAttemptId, + invocationRequestId: request.invocationRequestId, + failureCategory: "transient-provider-failure", + reasonCodes: ["transient_provider_failure"], + retryable: true, + sanitizedDetail: "Coherent second transient failure", + attemptNumber: 2, + }); + const secondTransientOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: attempts[1]!.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 2, + completedAt: completeOutcomes[1]!.completedAt, + status: "failed", + failureEvidence: secondTransientFailure, + }); + const thirdAttempt = createReasoningExecutionAttempt({ + ...secondAttemptUnsigned, + executionAttemptId: "reasoning-attempt-coherent-over-limit", + attemptNumber: 3, + previousExecutionAttemptId: attempts[1]!.executionAttemptId, + startedAt: "2026-07-29T01:00:04.000Z", + deadlineAt: "2026-07-29T01:00:05.000Z", + }); + const { outcomeFingerprint: _outcomeFingerprint, ...thirdOutcomeUnsigned } = + completeOutcomes[1]!; + void _outcomeFingerprint; + const thirdOutcome = createReasoningProviderOutcome({ + ...thirdOutcomeUnsigned, + executionAttemptId: thirdAttempt.executionAttemptId, + attemptNumber: 3, + completedAt: "2026-07-29T01:00:04.500Z", + }); + if (thirdOutcome.status !== "succeeded") throw new Error("expected successful third outcome"); + const thirdReceipt = createReasoningExecutionReceipt({ + schemaVersion: "1.0", + executionAttemptId: thirdAttempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + providerCapabilityId: providerCapability.providerCapabilityId, + providerCapabilityFingerprint: providerCapability.descriptorFingerprint, + attemptNumber: 3, + startedAt: thirdAttempt.startedAt, + completedAt: thirdOutcome.completedAt, + outcome: thirdOutcome.status, + }); + const { usageFingerprint: _usageFingerprint, ...usageUnsigned } = + final.resultEnvelope.usageEvidence; + void _usageFingerprint; + const thirdUsage = createReasoningUsageEvidence({ + ...usageUnsigned, + executionAttemptId: thirdAttempt.executionAttemptId, + attemptNumber: 3, + durationMilliseconds: 500, + }); + const { costFingerprint: _costFingerprint, ...costUnsigned } = + final.resultEnvelope.costEvidence; + void _costFingerprint; + const thirdCost = createReasoningCostEvidence({ + ...costUnsigned, + executionAttemptId: thirdAttempt.executionAttemptId, + }); + const { resultEnvelopeFingerprint: _resultFingerprint, ...resultUnsigned } = + final.resultEnvelope; + void _resultFingerprint; + const thirdResult = createReasoningResultEnvelope({ + ...resultUnsigned, + executionAttemptId: thirdAttempt.executionAttemptId, + attemptNumber: 3, + completedAt: thirdOutcome.completedAt, + executionReceipt: thirdReceipt, + usageEvidence: thirdUsage, + costEvidence: thirdCost, + }); + if (thirdResult.outcome !== "succeeded") throw new Error("expected successful third result"); + const overLimitAttempts = [...attempts, thirdAttempt]; + const overLimitOutcomes = [completeOutcomes[0]!, secondTransientOutcome, thirdOutcome]; + const historyEntries = overLimitAttempts.map((attempt, index) => ({ + executionAttemptId: attempt.executionAttemptId, + attemptNumber: attempt.attemptNumber, + outcome: overLimitOutcomes[index]!.status, + attemptFingerprint: attempt.attemptFingerprint, + outcomeFingerprint: overLimitOutcomes[index]!.outcomeFingerprint, + })); + const historyUnsigned = { + attemptCount: 3, + finalAttemptNumber: 3, + finalOutcome: thirdOutcome.status, + attempts: historyEntries, + }; + const { consumptionFingerprint: _consumptionFingerprint, ...consumptionUnsigned } = + final.consumptionEvidence; + void _consumptionFingerprint; + const thirdConsumption = createFinalizedReasoningConsumptionEvidence({ + ...consumptionUnsigned, + finalResultEnvelopeId: thirdResult.resultEnvelopeId, + finalResultEnvelopeFingerprint: thirdResult.resultEnvelopeFingerprint, + finalOutcome: thirdResult.outcome, + attemptHistorySummary: { + ...historyUnsigned, + historyFingerprint: createDurableCanonicalJsonSha256Fingerprint(historyUnsigned), + }, + usageEvidenceFingerprint: thirdUsage.usageFingerprint, + costEvidenceFingerprint: thirdCost.costFingerprint, + completedAt: thirdOutcome.completedAt, + }); + assertPublicVerificationInvalid( + overLimitAttempts, + overLimitOutcomes, + thirdResult, + thirdConsumption, + ); + }); + + it("rejects coherent re-signed post-deadline and cancelled-state successes", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:terminal-control-verification", + cancellationMode: "cooperative-cancellation", + }); + const finalized = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + if ( + finalized.status === "identical-in-progress" || + finalized.resultEnvelope.outcome !== "succeeded" + ) + throw new Error("expected successful baseline"); + const [attempt] = await runtime.executionEvidence.readAttemptHistory( + request.invocationRequestId, + ); + if (attempt === undefined) throw new Error("missing baseline Attempt"); + const outcome = await runtime.executionEvidence.readProviderOutcome(attempt.executionAttemptId); + if (outcome?.status !== "succeeded") throw new Error("missing successful baseline Outcome"); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const contextPackageObjectCount = + runtime.fixture.result.envelope.contextPackage.included.length; + const assertRejected = ( + candidateAttempt: ReasoningExecutionAttempt, + candidateOutcome: Extract, + suffix: string, + ) => { + const artifacts = createSuccessfulFinalizationArtifacts({ + request, + providerCapability, + attempt: candidateAttempt, + outcome: candidateOutcome, + contextPackageObjectCount, + transactionId: `reasoning-finalization-${suffix}`, + }); + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: artifacts.resultEnvelope, + invocationRequest: request, + providerCapability, + attempt: candidateAttempt, + attemptHistory: [candidateAttempt], + providerOutcome: candidateOutcome, + outcomeHistory: [candidateOutcome], + contextPackageObjectCount, + }).status, + ).toBe("invalid"); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: artifacts.consumptionEvidence, + resultEnvelope: artifacts.resultEnvelope, + invocationRequest: request, + providerCapability, + attempts: [candidateAttempt], + outcomes: [candidateOutcome], + contextPackageObjectCount, + executionLedgerTransactionId: `reasoning-finalization-${suffix}`, + }).status, + ).toBe("invalid"); + }; + const { outcomeFingerprint: _outcomeFingerprint, ...outcomeUnsigned } = outcome; + void _outcomeFingerprint; + const postDeadlineOutcome = createReasoningProviderOutcome({ + ...outcomeUnsigned, + completedAt: attempt.deadlineAt!, + }); + if (postDeadlineOutcome.status !== "succeeded") + throw new Error("expected post-deadline success"); + assertRejected(attempt, postDeadlineOutcome, "post-deadline-success"); + const { attemptFingerprint: _attemptFingerprint, ...attemptUnsigned } = attempt; + void _attemptFingerprint; + const cancelledAttempt = createReasoningExecutionAttempt({ + ...attemptUnsigned, + cancellationState: "requested-cooperatively", + cancellationAuthorityReference: "authority/coherent-cancelled-state-success", + cancellationRequestedAt: "2026-07-29T01:00:01.010Z", + cancellationObservedAt: "2026-07-29T01:00:01.050Z", + }); + assertRejected(cancelledAttempt, outcome, "cancelled-state-success"); + }); + + it("rejects coherent re-signed timeout and cancellation evidence mismatches", async () => { + const assertTerminalVerificationInvalid = (input: { + readonly request: ReasoningInvocationRequest; + readonly providerCapability: ReasoningProviderCapabilityDescriptor; + readonly attempt: ReasoningExecutionAttempt; + readonly outcome: ReasoningProviderOutcome; + readonly resultEnvelope: Parameters< + typeof verifyReasoningResultEnvelope + >[0]["resultEnvelope"]; + readonly consumptionEvidence: Parameters< + typeof verifyFinalizedReasoningConsumptionEvidence + >[0]["consumptionEvidence"]; + readonly contextPackageObjectCount: number; + readonly transactionId: string; + }) => { + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: input.resultEnvelope, + invocationRequest: input.request, + providerCapability: input.providerCapability, + attempt: input.attempt, + attemptHistory: [input.attempt], + providerOutcome: input.outcome, + outcomeHistory: [input.outcome], + contextPackageObjectCount: input.contextPackageObjectCount, + }).status, + ).toBe("invalid"); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: input.consumptionEvidence, + resultEnvelope: input.resultEnvelope as never, + invocationRequest: input.request, + providerCapability: input.providerCapability, + attempts: [input.attempt], + outcomes: [input.outcome], + contextPackageObjectCount: input.contextPackageObjectCount, + executionLedgerTransactionId: input.transactionId, + }).status, + ).toBe("invalid"); + }; + + const timeoutRuntime = await createReasoningTestRuntime(roots); + const timeoutRequest = createInvocation(timeoutRuntime, { + idempotencyKey: "reasoning:key:timeout-evidence-mismatch", + }); + const timeoutFinal = await invokeGovernedReasoning({ + deliveryLedger: timeoutRuntime.deliveryLedger, + executionEvidence: timeoutRuntime.executionEvidence, + deliveryIdentity: timeoutRuntime.deliveryIdentity, + invocationRequest: timeoutRequest, + fixtureMode: "timeout", + attemptSchedule: [{ ...schedule()[0]!, completedAt: schedule()[0]!.deadlineAt }], + }); + if ( + timeoutFinal.status === "identical-in-progress" || + timeoutFinal.resultEnvelope.outcome !== "timed-out" || + timeoutFinal.consumptionEvidence.finalOutcome !== "timed-out" + ) + throw new Error("expected timeout baseline"); + const [timeoutAttempt] = await timeoutRuntime.executionEvidence.readAttemptHistory( + timeoutRequest.invocationRequestId, + ); + const timeoutOutcome = await timeoutRuntime.executionEvidence.readProviderOutcome( + timeoutAttempt!.executionAttemptId, + ); + if (timeoutOutcome?.status !== "timed-out") throw new Error("missing timeout Outcome"); + const { timeoutFingerprint: _timeoutFingerprint, ...timeoutEvidenceUnsigned } = + timeoutOutcome.timeoutEvidence; + void _timeoutFingerprint; + const changedTimeoutEvidence = createReasoningTimeoutEvidence({ + ...timeoutEvidenceUnsigned, + elapsedMilliseconds: timeoutEvidenceUnsigned.elapsedMilliseconds + 1, + }); + const { outcomeFingerprint: _timeoutOutcomeFingerprint, ...timeoutOutcomeUnsigned } = + timeoutOutcome; + void _timeoutOutcomeFingerprint; + const changedTimeoutOutcome = createReasoningProviderOutcome({ + ...timeoutOutcomeUnsigned, + timeoutEvidence: changedTimeoutEvidence, + }); + const { resultEnvelopeFingerprint: _timeoutResultFingerprint, ...timeoutResultUnsigned } = + timeoutFinal.resultEnvelope; + void _timeoutResultFingerprint; + const changedTimeoutResult = createReasoningResultEnvelope({ + ...timeoutResultUnsigned, + timeoutEvidence: changedTimeoutEvidence, + }); + const timeoutHistoryUnsigned = { + attemptCount: 1, + finalAttemptNumber: 1, + finalOutcome: "timed-out" as const, + attempts: [ + { + executionAttemptId: timeoutAttempt!.executionAttemptId, + attemptNumber: 1, + outcome: "timed-out" as const, + attemptFingerprint: timeoutAttempt!.attemptFingerprint, + outcomeFingerprint: changedTimeoutOutcome.outcomeFingerprint, + }, + ], + }; + const { + consumptionFingerprint: _timeoutConsumptionFingerprint, + ...timeoutConsumptionUnsigned + } = timeoutFinal.consumptionEvidence; + void _timeoutConsumptionFingerprint; + const timeoutTransactionId = "reasoning-finalization-timeout-evidence-mismatch"; + const changedTimeoutConsumption = createFinalizedReasoningConsumptionEvidence({ + ...timeoutConsumptionUnsigned, + finalResultEnvelopeFingerprint: changedTimeoutResult.resultEnvelopeFingerprint, + attemptHistorySummary: { + ...timeoutHistoryUnsigned, + historyFingerprint: createDurableCanonicalJsonSha256Fingerprint(timeoutHistoryUnsigned), + }, + timeoutEvidenceFingerprint: changedTimeoutEvidence.timeoutFingerprint, + executionLedgerTransactionId: timeoutTransactionId, + }); + assertTerminalVerificationInvalid({ + request: timeoutRequest, + providerCapability: createDeterministicFakeReasoningProvider().providerCapability, + attempt: timeoutAttempt!, + outcome: changedTimeoutOutcome, + resultEnvelope: changedTimeoutResult, + consumptionEvidence: changedTimeoutConsumption, + contextPackageObjectCount: + timeoutRuntime.fixture.result.envelope.contextPackage.included.length, + transactionId: timeoutTransactionId, + }); + + const cancellationRuntime = await createReasoningTestRuntime(roots); + const cancellationRequest = createInvocation(cancellationRuntime, { + idempotencyKey: "reasoning:key:cancellation-evidence-mismatch", + cancellationMode: "cooperative-cancellation", + }); + const cancellationSignal = { + state: "requested-cooperatively" as const, + authorityReference: "authority/cancellation-evidence-mismatch", + requestedAt: "2026-07-29T01:00:01.010Z", + observedAt: "2026-07-29T01:00:01.050Z", + }; + const cancellationFinal = await invokeGovernedReasoning({ + deliveryLedger: cancellationRuntime.deliveryLedger, + executionEvidence: cancellationRuntime.executionEvidence, + deliveryIdentity: cancellationRuntime.deliveryIdentity, + invocationRequest: cancellationRequest, + fixtureMode: "cooperative-cancellation", + attemptSchedule: schedule(1, cancellationSignal), + }); + if ( + cancellationFinal.status === "identical-in-progress" || + cancellationFinal.resultEnvelope.outcome !== "cancelled" || + cancellationFinal.consumptionEvidence.finalOutcome !== "cancelled" + ) + throw new Error("expected cancellation baseline"); + const [cancellationAttempt] = await cancellationRuntime.executionEvidence.readAttemptHistory( + cancellationRequest.invocationRequestId, + ); + const cancellationOutcome = await cancellationRuntime.executionEvidence.readProviderOutcome( + cancellationAttempt!.executionAttemptId, + ); + if (cancellationOutcome?.status !== "cancelled") + throw new Error("missing cancellation Outcome"); + const { cancellationFingerprint: _cancellationFingerprint, ...cancellationUnsigned } = + cancellationOutcome.cancellationEvidence; + void _cancellationFingerprint; + const changedCancellationEvidence = createReasoningCancellationEvidence({ + ...cancellationUnsigned, + cancellationAuthorityReference: "authority/re-signed-substitution", + observedAt: "2026-07-29T01:00:01.200Z", + }); + const { outcomeFingerprint: _cancelOutcomeFingerprint, ...cancelOutcomeUnsigned } = + cancellationOutcome; + void _cancelOutcomeFingerprint; + const changedCancellationOutcome = createReasoningProviderOutcome({ + ...cancelOutcomeUnsigned, + cancellationEvidence: changedCancellationEvidence, + }); + const { resultEnvelopeFingerprint: _cancelResultFingerprint, ...cancelResultUnsigned } = + cancellationFinal.resultEnvelope; + void _cancelResultFingerprint; + const changedCancellationResult = createReasoningResultEnvelope({ + ...cancelResultUnsigned, + cancellationEvidence: changedCancellationEvidence, + }); + const cancellationHistoryUnsigned = { + attemptCount: 1, + finalAttemptNumber: 1, + finalOutcome: "cancelled" as const, + attempts: [ + { + executionAttemptId: cancellationAttempt!.executionAttemptId, + attemptNumber: 1, + outcome: "cancelled" as const, + attemptFingerprint: cancellationAttempt!.attemptFingerprint, + outcomeFingerprint: changedCancellationOutcome.outcomeFingerprint, + }, + ], + }; + const { consumptionFingerprint: _cancelConsumptionFingerprint, ...cancelConsumptionUnsigned } = + cancellationFinal.consumptionEvidence; + void _cancelConsumptionFingerprint; + const cancellationTransactionId = "reasoning-finalization-cancellation-evidence-mismatch"; + const changedCancellationConsumption = createFinalizedReasoningConsumptionEvidence({ + ...cancelConsumptionUnsigned, + finalResultEnvelopeFingerprint: changedCancellationResult.resultEnvelopeFingerprint, + attemptHistorySummary: { + ...cancellationHistoryUnsigned, + historyFingerprint: createDurableCanonicalJsonSha256Fingerprint( + cancellationHistoryUnsigned, + ), + }, + cancellationEvidenceFingerprint: changedCancellationEvidence.cancellationFingerprint, + executionLedgerTransactionId: cancellationTransactionId, + }); + assertTerminalVerificationInvalid({ + request: cancellationRequest, + providerCapability: createDeterministicFakeReasoningProvider().providerCapability, + attempt: cancellationAttempt!, + outcome: changedCancellationOutcome, + resultEnvelope: changedCancellationResult, + consumptionEvidence: changedCancellationConsumption, + contextPackageObjectCount: + cancellationRuntime.fixture.result.envelope.contextPackage.included.length, + transactionId: cancellationTransactionId, + }); + }); + + it("rejects a coherent re-signed non-canonical runtime timeout reason", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:timeout-reason-substitution", + }); + const finalized = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "timeout", + attemptSchedule: [{ ...schedule()[0]!, completedAt: schedule()[0]!.deadlineAt }], + }); + if ( + finalized.status === "identical-in-progress" || + finalized.resultEnvelope.outcome !== "timed-out" || + finalized.consumptionEvidence.finalOutcome !== "timed-out" + ) + throw new Error("expected timeout baseline"); + const [attempt] = await runtime.executionEvidence.readAttemptHistory( + request.invocationRequestId, + ); + if (attempt === undefined) throw new Error("missing timeout Attempt"); + const outcome = await runtime.executionEvidence.readProviderOutcome(attempt.executionAttemptId); + if (outcome?.status !== "timed-out") throw new Error("missing timeout Outcome"); + const { timeoutFingerprint: _timeoutFingerprint, ...timeoutUnsigned } = outcome.timeoutEvidence; + void _timeoutFingerprint; + const substitutedEvidence = createReasoningTimeoutEvidence({ + ...timeoutUnsigned, + reasonCode: "execution_timeout", + }); + const { outcomeFingerprint: _outcomeFingerprint, ...outcomeUnsigned } = outcome; + void _outcomeFingerprint; + const substitutedOutcome = createReasoningProviderOutcome({ + ...outcomeUnsigned, + timeoutEvidence: substitutedEvidence, + }); + const { resultEnvelopeFingerprint: _resultFingerprint, ...resultUnsigned } = + finalized.resultEnvelope; + void _resultFingerprint; + const substitutedResult = createReasoningResultEnvelope({ + ...resultUnsigned, + timeoutEvidence: substitutedEvidence, + }); + const historyUnsigned = { + attemptCount: 1, + finalAttemptNumber: 1, + finalOutcome: "timed-out" as const, + attempts: [ + { + executionAttemptId: attempt.executionAttemptId, + attemptNumber: 1, + outcome: "timed-out" as const, + attemptFingerprint: attempt.attemptFingerprint, + outcomeFingerprint: substitutedOutcome.outcomeFingerprint, + }, + ], + }; + const { consumptionFingerprint: _consumptionFingerprint, ...consumptionUnsigned } = + finalized.consumptionEvidence; + void _consumptionFingerprint; + const transactionId = "reasoning-finalization-timeout-reason-substitution"; + const substitutedConsumption = createFinalizedReasoningConsumptionEvidence({ + ...consumptionUnsigned, + finalResultEnvelopeFingerprint: substitutedResult.resultEnvelopeFingerprint, + attemptHistorySummary: { + ...historyUnsigned, + historyFingerprint: createDurableCanonicalJsonSha256Fingerprint(historyUnsigned), + }, + timeoutEvidenceFingerprint: substitutedEvidence.timeoutFingerprint, + executionLedgerTransactionId: transactionId, + }); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const contextPackageObjectCount = + runtime.fixture.result.envelope.contextPackage.included.length; + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: substitutedResult, + invocationRequest: request, + providerCapability, + attempt, + attemptHistory: [attempt], + providerOutcome: substitutedOutcome, + outcomeHistory: [substitutedOutcome], + contextPackageObjectCount, + }).status, + ).toBe("invalid"); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: substitutedConsumption, + resultEnvelope: substitutedResult, + invocationRequest: request, + providerCapability, + attempts: [attempt], + outcomes: [substitutedOutcome], + contextPackageObjectCount, + executionLedgerTransactionId: transactionId, + }).status, + ).toBe("invalid"); + }); + + it("rejects coherent cooperative timeout observation after completion across every lifecycle path", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: "reasoning:key:cooperative-timeout-observation-after-completion", + cancellationMode: "cooperative-cancellation", + }); + const cancellationSignal = { + state: "requested-cooperatively" as const, + authorityReference: "authority/cooperative-timeout-observation", + requestedAt: "2026-07-29T01:00:01.900Z", + observedAt: "2026-07-29T01:00:02.050Z", + }; + const finalized = await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: [ + { + ...schedule(1, cancellationSignal)[0]!, + completedAt: "2026-07-29T01:00:02.100Z", + }, + ], + }); + if ( + finalized.status === "identical-in-progress" || + finalized.resultEnvelope.outcome !== "timed-out" || + finalized.consumptionEvidence.finalOutcome !== "timed-out" + ) + throw new Error("expected cooperative timeout baseline"); + const [attempt] = await runtime.executionEvidence.readAttemptHistory( + request.invocationRequestId, + ); + if (attempt === undefined) throw new Error("missing cooperative timeout Attempt"); + const outcome = await runtime.executionEvidence.readProviderOutcome(attempt.executionAttemptId); + if (outcome?.status !== "timed-out") throw new Error("missing cooperative timeout Outcome"); + const { attemptFingerprint: _attemptFingerprint, ...attemptUnsigned } = attempt; + void _attemptFingerprint; + const poisonedAttempt = createReasoningExecutionAttempt({ + ...attemptUnsigned, + cancellationObservedAt: "2026-07-29T01:00:02.200Z", + }); + const providerCapability = createDeterministicFakeReasoningProvider().providerCapability; + const contextPackageObjectCount = + runtime.fixture.result.envelope.contextPackage.included.length; + expect( + verifyReasoningAttemptLifecycle({ + invocationRequest: request, + providerCapability, + attempts: [poisonedAttempt], + outcomes: [outcome], + }), + ).toBe(false); + expect( + verifyReasoningResultEnvelope({ + resultEnvelope: finalized.resultEnvelope, + invocationRequest: request, + providerCapability, + attempt: poisonedAttempt, + attemptHistory: [poisonedAttempt], + providerOutcome: outcome, + outcomeHistory: [outcome], + contextPackageObjectCount, + }).status, + ).toBe("invalid"); + const historyUnsigned = { + attemptCount: 1, + finalAttemptNumber: 1, + finalOutcome: "timed-out" as const, + attempts: [ + { + executionAttemptId: poisonedAttempt.executionAttemptId, + attemptNumber: 1, + outcome: "timed-out" as const, + attemptFingerprint: poisonedAttempt.attemptFingerprint, + outcomeFingerprint: outcome.outcomeFingerprint, + }, + ], + }; + const { consumptionFingerprint: _consumptionFingerprint, ...consumptionUnsigned } = + finalized.consumptionEvidence; + void _consumptionFingerprint; + const transactionId = "reasoning-finalization-cooperative-observation-after-completion"; + const poisonedConsumption = createFinalizedReasoningConsumptionEvidence({ + ...consumptionUnsigned, + attemptHistorySummary: { + ...historyUnsigned, + historyFingerprint: createDurableCanonicalJsonSha256Fingerprint(historyUnsigned), + }, + executionLedgerTransactionId: transactionId, + }); + expect( + verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: poisonedConsumption, + resultEnvelope: finalized.resultEnvelope, + invocationRequest: request, + providerCapability, + attempts: [poisonedAttempt], + outcomes: [outcome], + contextPackageObjectCount, + executionLedgerTransactionId: transactionId, + }).status, + ).toBe("invalid"); + + const persistenceRuntime = await createReasoningTestRuntime(roots); + const internal = resolveInternalReasoningExecutionEvidence( + persistenceRuntime.executionEvidence, + ); + const registered = await internal.registerGovernedInvocation( + { + schemaVersion: "1.0", + expectedLedgerHead: { ledgerSequence: 0, auditFingerprint: "genesis" }, + expectedIdempotencyState: "unowned", + invocationRequest: request, + registeredAt: request.requestedAt, + }, + { providerCapability, contextPackageObjectCount }, + ); + if (registered.status !== "registered") throw new Error("registration failed"); + let ledgerHead = await internal.verifyIntegrity(); + await internal.appendExecutionAttempt({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedPriorAttemptCount: 0, + attempt: poisonedAttempt, + }); + ledgerHead = await internal.verifyIntegrity(); + const poisonedOutcomeAppend = { + schemaVersion: "1.0" as const, + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress" as const, + attemptFingerprint: poisonedAttempt.attemptFingerprint, + outcome, + }; + await expect(internal.appendProviderOutcome(poisonedOutcomeAppend)).rejects.toThrow( + /authoritative open Attempt/u, + ); + + const ownershipEnvelope = JSON.parse( + await readFile( + join(persistenceRuntime.reasoningRuntimeRoot, "events", "0000000000000001.json"), + "utf8", + ), + ) as { readonly event: unknown; readonly invocationAuthority: unknown }; + const attemptEnvelope = JSON.parse( + await readFile( + join(persistenceRuntime.reasoningRuntimeRoot, "events", "0000000000000002.json"), + "utf8", + ), + ) as { readonly event: { readonly auditFingerprint: string } }; + const poisonedOutcomeRecord = createProviderOutcomeRecord({ + outcome, + ledgerSequence: 3, + previousAuditFingerprint: attemptEnvelope.event.auditFingerprint, + }); + expect(() => + replayReasoningExecutionLedger( + [ + ownershipEnvelope.event, + attemptEnvelope.event, + createReasoningExecutionLedgerEvent({ + eventType: "provider-outcome", + outcomeRecord: poisonedOutcomeRecord, + }), + ], + [ownershipEnvelope.invocationAuthority] as never, + ), + ).toThrow(/does not bind one open Attempt/u); + + const validCompletedAt = poisonedAttempt.cancellationObservedAt!; + const validTimeoutEvidence = createReasoningTimeoutEvidence({ + schemaVersion: "1.0", + executionAttemptId: poisonedAttempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + configuredTimeoutMilliseconds: request.executionPolicy.timeoutMilliseconds, + attemptStartedAt: poisonedAttempt.startedAt, + deadlineAt: poisonedAttempt.deadlineAt!, + elapsedMilliseconds: Date.parse(validCompletedAt) - Date.parse(poisonedAttempt.startedAt), + timeoutPhase: "during-execution", + reasonCode: "execution_deadline_reached", + }); + const validOutcome = createReasoningProviderOutcome({ + schemaVersion: "1.0", + executionAttemptId: poisonedAttempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + attemptNumber: 1, + completedAt: validCompletedAt, + status: "timed-out", + timeoutEvidence: validTimeoutEvidence, + }); + await internal.appendProviderOutcome({ ...poisonedOutcomeAppend, outcome: validOutcome }); + ledgerHead = await internal.verifyIntegrity(); + await expect( + internal.finalizeInvocation({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: registered.ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedAttemptCount: 1, + transactionId, + resultEnvelope: finalized.resultEnvelope, + consumptionEvidence: poisonedConsumption, + finalizedAt: finalized.resultEnvelope.completedAt, + }), + ).rejects.toThrow(/does not verify against authoritative Attempts/u); + }); + + it("fails closed after authoritative corruption while ignoring staging and a corrupt derived index", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime); + await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + await writeFile(join(runtime.reasoningRuntimeRoot, "staging", "ignored.partial"), "not-json"); + await writeFile(join(runtime.reasoningRuntimeRoot, "derived", "execution-index.json"), "{}\n"); + const derivedReopen = await openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: runtime.repositoryRoot, + runtimeRoot: runtime.reasoningRuntimeRoot, + canonicalSourceRoots: runtime.canonicalSourceRoots, + }); + expect((await derivedReopen.recover()).status).toBe("recovered"); + await writeFile( + join(runtime.reasoningRuntimeRoot, "derived", "execution-index.json"), + "x".repeat(65_537), + ); + const oversizedIndexReopen = await openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: runtime.repositoryRoot, + runtimeRoot: runtime.reasoningRuntimeRoot, + canonicalSourceRoots: runtime.canonicalSourceRoots, + limits: { maxEntries: 10_000, maxTotalBytes: 10_000_000, maxRecordBytes: 65_536 }, + }); + expect((await oversizedIndexReopen.recover()).status).toBe("recovered"); + const eventPath = join(runtime.reasoningRuntimeRoot, "events", "0000000000000001.json"); + const event = JSON.parse(await readFile(eventPath, "utf8")) as Record; + await writeFile( + eventPath, + `${JSON.stringify({ ...event, commitFingerprint: "0".repeat(64) })}\n`, + ); + await expect( + openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: runtime.repositoryRoot, + runtimeRoot: runtime.reasoningRuntimeRoot, + canonicalSourceRoots: runtime.canonicalSourceRoots, + }), + ).rejects.toThrow(/does not verify|invalid/u); + }); + + it("binds re-signed Invocation authority to the authoritative commit head", async () => { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime); + await invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + }); + const eventPath = join(runtime.reasoningRuntimeRoot, "events", "0000000000000001.json"); + const envelope = JSON.parse(await readFile(eventPath, "utf8")) as { + readonly schemaVersion: "1.0"; + readonly event: unknown; + readonly invocationAuthority: { + readonly invocationRequest: ReturnType; + readonly providerCapability: unknown; + readonly contextPackageObjectCount: number; + }; + readonly commitFingerprint: string; + }; + const { requestFingerprint: _requestFingerprint, ...requestUnsigned } = + envelope.invocationAuthority.invocationRequest; + void _requestFingerprint; + const substituted = createReasoningInvocationRequest({ + ...requestUnsigned, + reason: "Re-signed but unauthorized request substitution", + }); + const { commitFingerprint: _commitFingerprint, ...commitUnsigned } = envelope; + void _commitFingerprint; + const changedUnsigned = { + ...commitUnsigned, + invocationAuthority: { + ...commitUnsigned.invocationAuthority, + invocationRequest: substituted, + }, + }; + await writeFile( + eventPath, + `${JSON.stringify({ + ...changedUnsigned, + commitFingerprint: createDurableCanonicalJsonSha256Fingerprint(changedUnsigned), + })}\n`, + ); + await expect( + openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: runtime.repositoryRoot, + runtimeRoot: runtime.reasoningRuntimeRoot, + canonicalSourceRoots: runtime.canonicalSourceRoots, + }), + ).rejects.toMatchObject({ code: "fingerprint_mismatch" }); + }); + + it("rejects a symlinked commit head and re-signed unknown or unsafe head metadata", async () => { + const symlinkRuntime = await createReasoningTestRuntime(roots); + const headPath = join(symlinkRuntime.reasoningRuntimeRoot, "commit-head.json"); + const outsideHead = join(symlinkRuntime.repositoryRoot, "outside-commit-head.json"); + await writeFile(outsideHead, await readFile(headPath, "utf8")); + await rm(headPath); + await symlink(outsideHead, headPath); + await expect( + openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: symlinkRuntime.repositoryRoot, + runtimeRoot: symlinkRuntime.reasoningRuntimeRoot, + canonicalSourceRoots: symlinkRuntime.canonicalSourceRoots, + }), + ).rejects.toMatchObject({ code: "unsafe_content" }); + + const metadataRuntime = await createReasoningTestRuntime(roots); + const metadataHeadPath = join(metadataRuntime.reasoningRuntimeRoot, "commit-head.json"); + const original = JSON.parse(await readFile(metadataHeadPath, "utf8")) as Record< + string, + unknown + >; + const { headFingerprint: _headFingerprint, ...unsigned } = original; + void _headFingerprint; + for (const metadata of [ + { unknownMetadata: "unexpected" }, + { apiKey: "fixture-secret-value" }, + { physicalPath: "/private/runtime/commit-head" }, + ]) { + const changed = { ...unsigned, ...metadata }; + await writeFile( + metadataHeadPath, + `${JSON.stringify({ + ...changed, + headFingerprint: createDurableCanonicalJsonSha256Fingerprint(changed), + })}\n`, + ); + await expect( + openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: metadataRuntime.repositoryRoot, + runtimeRoot: metadataRuntime.reasoningRuntimeRoot, + canonicalSourceRoots: metadataRuntime.canonicalSourceRoots, + }), + ).rejects.toMatchObject({ code: "fingerprint_mismatch" }); + } + }); + + it.each(["runtime-parent", "runtime-root", "events", "staging", "derived"] as const)( + "rejects symlinked local adapter %s confinement", + async (target) => { + const repositoryRoot = await mkdtemp(join(tmpdir(), "founderos-m13-symlink-")); + roots.push(repositoryRoot); + const docs = join(repositoryRoot, "docs"); + const outside = await mkdtemp(join(tmpdir(), "founderos-m13-outside-")); + roots.push(outside); + await mkdir(docs); + const runtimeRoot = join(repositoryRoot, ".founderos", "runtime", "reasoning-ledger"); + if (target === "runtime-parent") { + await mkdir(join(repositoryRoot, ".founderos"), { recursive: true }); + await symlink(outside, join(repositoryRoot, ".founderos", "runtime")); + } else if (target === "runtime-root") { + await mkdir(join(repositoryRoot, ".founderos", "runtime"), { recursive: true }); + await symlink(outside, runtimeRoot); + } else { + const reader = await openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot, + runtimeRoot, + canonicalSourceRoots: [docs], + }); + expect((await reader.verifyIntegrity()).status).toBe("valid"); + const managed = join(runtimeRoot, target); + await rm(managed, { recursive: true }); + await symlink(outside, managed); + } + await expect( + openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot, + runtimeRoot, + canonicalSourceRoots: [docs], + }), + ).rejects.toMatchObject({ code: "unsafe_content" }); + }, + ); + + it("captures nested local adapter accessors without invoking them and sanitizes fs errors", async () => { + const repositoryRoot = await mkdtemp(join(tmpdir(), "founderos-m13-accessor-")); + roots.push(repositoryRoot); + const docs = join(repositoryRoot, "docs"); + await mkdir(docs); + let accesses = 0; + const limits = { maxEntries: 1, maxTotalBytes: 1, maxRecordBytes: 1 }; + Object.defineProperty(limits, "maxEntries", { + enumerable: true, + get() { + accesses += 1; + return 10; + }, + }); + await expect( + openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot, + runtimeRoot: join(repositoryRoot, ".founderos", "runtime", "reasoning-ledger"), + canonicalSourceRoots: [docs], + limits, + }), + ).rejects.toMatchObject({ code: "resource_limit_exceeded" }); + expect(accesses).toBe(0); + const topLevelAccessorOptions = { + repositoryRoot, + runtimeRoot: join(repositoryRoot, ".founderos", "runtime", "top-accessor"), + canonicalSourceRoots: [docs], + }; + Object.defineProperty(topLevelAccessorOptions, "runtimeRoot", { + enumerable: true, + get() { + accesses += 1; + return join(repositoryRoot, ".founderos", "runtime", "top-accessor"); + }, + }); + await expect( + openLocalFileGovernedReasoningExecutionEvidence(topLevelAccessorOptions), + ).rejects.toMatchObject({ code: "unsafe_content" }); + expect(accesses).toBe(0); + const rootsWithAccessor = [docs]; + Object.defineProperty(rootsWithAccessor, "0", { + enumerable: true, + get() { + accesses += 1; + return docs; + }, + }); + await expect( + openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot, + runtimeRoot: join(repositoryRoot, ".founderos", "runtime", "second-ledger"), + canonicalSourceRoots: rootsWithAccessor, + }), + ).rejects.toMatchObject({ code: "unsafe_content" }); + expect(accesses).toBe(0); + + const secretPath = join(repositoryRoot, "private-physical-secret", "missing-repository"); + let caught: unknown; + try { + await openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: secretPath, + runtimeRoot: join(secretPath, ".founderos", "runtime", "reasoning-ledger"), + canonicalSourceRoots: [docs], + }); + } catch (error) { + caught = error; + } + expect(caught).toMatchObject({ code: "storage_failure" }); + expect(String(caught)).not.toContain(secretPath); + }); + + it("sanitizes writer cleanup failures and preserves primary-operation precedence", async () => { + const physicalSecret = "/private/runtime/cleanup-secret.lock"; + let cleanupFailure: unknown; + try { + await runReasoningWriterSession( + async () => "completed", + async () => { + throw new Error(`close failed at ${physicalSecret}`); + }, + async () => { + throw new Error(`remove failed at ${physicalSecret}`); + }, + ); + } catch (error) { + cleanupFailure = error; + } + expect(cleanupFailure).toMatchObject({ code: "storage_failure" }); + expect(String(cleanupFailure)).not.toContain(physicalSecret); + expect(String(cleanupFailure)).toContain("storage operation failed"); + let primaryFailure: unknown; + try { + await runReasoningWriterSession( + async () => { + throw new ReasoningExecutionLedgerConflictError( + "audit_chain_broken", + "Primary governed operation failed", + ); + }, + async () => { + throw new Error(`close failed at ${physicalSecret}`); + }, + async () => { + throw new Error(`remove failed at ${physicalSecret}`); + }, + ); + } catch (error) { + primaryFailure = error; + } + expect(primaryFailure).toMatchObject({ code: "audit_chain_broken" }); + expect(String(primaryFailure)).not.toContain(physicalSecret); + expect(String(primaryFailure)).toContain("Primary governed operation failed"); + }); +}); diff --git a/services/knowledge-engine/tests/reasoning-evaluation-runner.ts b/services/knowledge-engine/tests/reasoning-evaluation-runner.ts new file mode 100644 index 0000000..1930530 --- /dev/null +++ b/services/knowledge-engine/tests/reasoning-evaluation-runner.ts @@ -0,0 +1,1173 @@ +import { readFile } from "node:fs/promises"; + +import { expect } from "vitest"; + +import { + createFinalizedReasoningConsumptionEvidence, + createProviderNeutralReasoningInput, + createReasoningCancellationEvidence, + createReasoningExecutionAttempt, + createReasoningInvocationRequest, + createReasoningProviderCapabilityDescriptor, + createReasoningResultEnvelope, + createReasoningTimeoutEvidence, + invokeGovernedReasoning, + matchReasoningProviderCapabilities, + openLocalFileGovernedReasoningExecutionEvidence, + verifyFinalizedReasoningConsumptionEvidence, + verifyReasoningCancellationEvidence, + verifyReasoningCostEvidence, + verifyReasoningExecutionAttempt, + verifyReasoningExecutionReceipt, + verifyReasoningFailureEvidence, + verifyReasoningProviderOutcome, + verifyReasoningResultEnvelope, + verifyReasoningResultEnvelopeArtifact, + verifyReasoningTimeoutEvidence, + verifyReasoningUsageEvidence, + type InvokeGovernedReasoningInput, +} from "../src/index.js"; +import { resolveInternalReasoningExecutionEvidence } from "../src/application/manage-governed-reasoning-execution-ledger.js"; +import { createDeterministicFakeReasoningProvider } from "../src/infrastructure/deterministic-fake-reasoning-provider.js"; +import type { + ReasoningEvaluation, + ReasoningEvaluationExpected, + ReasoningEvaluationScenarioId, +} from "./fixtures/reasoning-evaluations.js"; +import { createInvocation, createReasoningTestRuntime, schedule } from "./reasoning-fixtures.js"; + +type Runtime = Awaited>; +type ScenarioObservation = ReasoningEvaluationExpected; + +function observedErrorCode(error: unknown): string | null { + return error instanceof Error && "code" in error && typeof error.code === "string" + ? error.code + : null; +} + +function requiredMutationTarget(evaluation: ReasoningEvaluation): string { + const { target } = evaluation.mutation; + if (target === undefined) + throw new Error(`Evaluation ${evaluation.mutation.operation} requires a mutation target`); + return target; +} + +export async function executeReasoningEvaluation( + evaluation: ReasoningEvaluation, + roots: string[], +): Promise { + let actual: ScenarioObservation; + if (evaluation.setup.source === "provider-source") + actual = await executeProviderSafety(evaluation, roots); + else if (evaluation.setup.source === "canonical-artifacts") + actual = + evaluation.category === "capability" + ? await executeCapability(evaluation, roots) + : await executeEvidenceMutation(evaluation, roots); + else if (evaluation.category === "successful-execution") + actual = await executeSuccess(evaluation, roots); + else if (evaluation.category === "delivery-binding") + actual = await executeDeliveryBinding(evaluation, roots); + else if (evaluation.category === "idempotency") + actual = await executeIdempotency(evaluation, roots); + else if (evaluation.category === "retry") actual = await executeRetry(evaluation, roots); + else if (evaluation.category === "timeout") actual = await executeTimeout(evaluation, roots); + else if (evaluation.category === "cancellation") + actual = await executeCancellation(evaluation, roots); + else if (evaluation.category === "fake-provider-safety") + actual = await executeProviderSafety(evaluation, roots); + else actual = await executeFacadeBypass(evaluation, roots); + expect(actual).toEqual(evaluation.expected); +} + +async function invoke( + runtime: Runtime, + scenarioId: ReasoningEvaluationScenarioId, + overrides: Partial = {}, +) { + return invokeGovernedReasoning({ + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${scenarioId}`, + }), + fixtureMode: "successful-structured-response", + attemptSchedule: schedule(), + ...overrides, + }); +} + +async function executeSuccess(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${evaluation.mutation.operation}`, + ...(evaluation.mutation.operation === "success-empty" + ? { outputContentType: "canonical-text" as const, requireNonEmpty: false } + : {}), + }); + const input = { + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: request, + fixtureMode: + evaluation.mutation.operation === "success-empty" + ? ("successful-empty-response" as const) + : ("successful-structured-response" as const), + attemptSchedule: schedule(), + }; + const first = await invokeGovernedReasoning(input); + if (first.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(first.resultEnvelope.outcome).toBe(evaluation.expected.outcome); + expect(first.consumptionEvidence.attemptHistorySummary.attemptCount).toBe( + evaluation.expected.attemptCount, + ); + expect(first.resultEnvelope.resultEnvelopeFingerprint).toMatch(/^[a-f0-9]{64}$/u); + const integrity = await runtime.executionEvidence.verifyIntegrity(); + expect(integrity.status).toBe("valid"); + let observedStatus: string = first.status; + let stableReplay = false; + if (evaluation.mutation.operation === "success-empty") { + expect(first.resultEnvelope.outcome).toBe("succeeded"); + if (first.resultEnvelope.outcome === "succeeded") + expect(first.resultEnvelope.outputCharacterCount).toBe(0); + } + if (evaluation.mutation.operation === "repeat-deterministic") { + const repeat = await invokeGovernedReasoning(input); + expect(repeat.status).toBe("identical-finalized"); + if (repeat.status !== "identical-in-progress") + expect(repeat.resultEnvelope.resultEnvelopeFingerprint).toBe( + first.resultEnvelope.resultEnvelopeFingerprint, + ); + observedStatus = repeat.status; + stableReplay = + repeat.status !== "identical-in-progress" && + repeat.resultEnvelope.resultEnvelopeFingerprint === + first.resultEnvelope.resultEnvelopeFingerprint; + } + if (evaluation.mutation.operation === "restart-lookup") { + const reopened = await openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot: runtime.repositoryRoot, + runtimeRoot: runtime.reasoningRuntimeRoot, + canonicalSourceRoots: runtime.canonicalSourceRoots, + }); + expect(await reopened.readFinalizedResult(request.invocationRequestId)).toEqual( + first.resultEnvelope, + ); + } + const attempts = await runtime.executionEvidence.readAttemptHistory(request.invocationRequestId); + const outcome = await runtime.executionEvidence.readProviderOutcome( + first.resultEnvelope.executionAttemptId, + ); + const resultVerified = + outcome !== null && + verifyReasoningResultEnvelope({ + resultEnvelope: first.resultEnvelope, + invocationRequest: request, + providerCapability: createDeterministicFakeReasoningProvider().providerCapability, + attempt: attempts[0]!, + attemptHistory: attempts, + providerOutcome: outcome, + outcomeHistory: [outcome], + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }).status === "valid"; + return { + disposition: "accept" as const, + errorCode: null, + status: observedStatus, + outcome: first.resultEnvelope.outcome, + reasonCodes: [], + attemptCount: attempts.length, + durable: integrity.status === "valid", + fingerprintStatus: resultVerified ? ("valid" as const) : ("invalid" as const), + attemptIdentity: observedAttemptIdentity(attempts, stableReplay), + resultExpectation: + (await runtime.executionEvidence.readFinalizedResult(request.invocationRequestId)) === null + ? ("none" as const) + : ("finalized" as const), + evidenceExpectation: resultVerified ? ("verified" as const) : ("rejected" as const), + finalizationExpectation: + (await runtime.executionEvidence.readFinalizedConsumptionEvidence( + request.invocationRequestId, + )) === null + ? ("none" as const) + : ("committed" as const), + }; +} + +function resignRequest( + request: ReturnType, + changes: Partial, "requestFingerprint">>, +) { + const { requestFingerprint: _fingerprint, ...unsigned } = request; + void _fingerprint; + return createReasoningInvocationRequest({ ...unsigned, ...changes }); +} + +async function executeDeliveryBinding(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + let request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${evaluation.mutation.operation}`, + }); + let deliveryIdentity = { ...runtime.deliveryIdentity }; + if (evaluation.mutation.operation === "missing-transaction") + deliveryIdentity = { ...deliveryIdentity, transactionId: "missing-delivery-transaction" }; + else if (evaluation.mutation.operation === "envelope-substitution") + deliveryIdentity = { ...deliveryIdentity, deliveryEnvelopeFingerprint: "0".repeat(64) }; + else if (evaluation.mutation.operation === "receipt-substitution") + deliveryIdentity = { ...deliveryIdentity, deliveryReceiptFingerprint: "0".repeat(64) }; + else if (evaluation.mutation.operation === "context-substitution") { + const { inputFingerprint: _inputFingerprint, ...inputUnsigned } = request.reasoningInput; + void _inputFingerprint; + const contextPackageId = "substituted-context-package"; + const contextPackageFingerprint = "0".repeat(64); + const reasoningInput = createProviderNeutralReasoningInput({ + ...inputUnsigned, + contextReference: { + ...inputUnsigned.contextReference, + contextPackageId, + contextPackageFingerprint, + }, + }); + request = resignRequest(request, { + contextPackageId, + contextPackageFingerprint, + reasoningInput, + }); + } else if (evaluation.mutation.operation === "consumer-substitution") + request = resignRequest(request, { consumerId: "substituted-consumer" }); + else if (evaluation.mutation.operation === "registry-substitution") + request = resignRequest(request, { + registryIntegrityBinding: { + ...request.registryIntegrityBinding, + integrityFingerprint: "0".repeat(64), + }, + }); + let error: unknown; + try { + await invoke(runtime, evaluation.mutation.operation, { + invocationRequest: request, + deliveryIdentity, + }); + } catch (caught) { + error = caught; + } + expect(error).toMatchObject({ code: evaluation.expected.errorCode }); + const integrity = await runtime.executionEvidence.verifyIntegrity(); + expect(integrity.verifiedInvocationCount).toBe(0); + return { + disposition: error === undefined ? ("accept" as const) : ("reject" as const), + errorCode: observedErrorCode(error), + status: null, + outcome: null, + reasonCodes: [], + attemptCount: 0, + durable: integrity.status === "valid", + fingerprintStatus: "not-applicable" as const, + attemptIdentity: "none" as const, + resultExpectation: "rejected" as const, + evidenceExpectation: "none" as const, + finalizationExpectation: "none" as const, + }; +} + +async function executeCapability(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${evaluation.mutation.operation}`, + }); + const capability = createDeterministicFakeReasoningProvider().providerCapability; + const { descriptorFingerprint: _fingerprint, ...unsigned } = capability; + void _fingerprint; + const changes = + evaluation.mutation.operation === "invocation-version" + ? { acceptedInvocationRequestVersions: ["2.0" as const] } + : evaluation.mutation.operation === "delivery-version" + ? { acceptedDeliveryEnvelopeVersions: ["2.0" as const] } + : evaluation.mutation.operation === "input-type" + ? { acceptedInputContentTypes: ["provider-neutral-instruction-blocks-v2" as const] } + : evaluation.mutation.operation === "input-budget" + ? { maxInputCharacters: 1 } + : evaluation.mutation.operation === "output-budget" + ? { maxOutputCharacters: 1 } + : evaluation.mutation.operation === "timeout-range" + ? { maxTimeoutMilliseconds: 500 } + : evaluation.mutation.operation === "cancellation-mode" + ? { supportedCancellationModes: ["cooperative-cancellation" as const] } + : evaluation.mutation.operation === "retry-mode" + ? { supportedRetryModes: ["retry-until-attempt-limit" as const] } + : evaluation.mutation.operation === "usage-capability" + ? { supportsUsageEvidence: false } + : evaluation.mutation.operation === "cost-capability" + ? { supportsCostEvidence: false } + : { supportsFailureEvidence: false }; + const provider = createReasoningProviderCapabilityDescriptor({ ...unsigned, ...changes }); + const result = matchReasoningProviderCapabilities({ + invocationRequest: request, + providerCapability: provider, + }); + expect(result.status).toBe(evaluation.expected.status); + expect(result.reasonCodes).toContain(evaluation.expected.reasonCodes![0]); + expect(result.mismatchedFields).toEqual([requiredMutationTarget(evaluation)]); + expect(result.compatibilityFingerprint).toMatch(/^[a-f0-9]{64}$/u); + return { + disposition: result.status === "incompatible" ? ("reject" as const) : ("accept" as const), + errorCode: null, + status: result.status, + outcome: null, + reasonCodes: result.reasonCodes, + attemptCount: 0, + durable: "not-applicable" as const, + fingerprintStatus: /^[a-f0-9]{64}$/u.test(result.compatibilityFingerprint) + ? ("valid" as const) + : ("invalid" as const), + attemptIdentity: "none" as const, + resultExpectation: "none" as const, + evidenceExpectation: "verified" as const, + finalizationExpectation: "none" as const, + }; +} + +async function registerOnly(runtime: Runtime, request: ReturnType) { + const internal = resolveInternalReasoningExecutionEvidence(runtime.executionEvidence); + const provider = createDeterministicFakeReasoningProvider(); + const registration = await internal.registerGovernedInvocation( + { + schemaVersion: "1.0", + expectedLedgerHead: { ledgerSequence: 0, auditFingerprint: "genesis" }, + expectedIdempotencyState: "unowned", + invocationRequest: request, + registeredAt: request.requestedAt, + }, + { + providerCapability: provider.providerCapability, + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }, + ); + return { internal, provider, registration }; +} + +async function readObservedLedgerState( + runtime: Runtime, + request: ReturnType, +) { + const integrity = await runtime.executionEvidence.verifyIntegrity(); + const attempts = await runtime.executionEvidence.readAttemptHistory(request.invocationRequestId); + const result = await runtime.executionEvidence.readFinalizedResult(request.invocationRequestId); + const consumption = await runtime.executionEvidence.readFinalizedConsumptionEvidence( + request.invocationRequestId, + ); + return { attempts, consumption, integrity, result }; +} + +function resultReasonCodes( + result: NonNullable>>, +) { + if (result.outcome === "failed") return result.failureEvidence.reasonCodes; + if (result.outcome === "timed-out") return [result.timeoutEvidence.reasonCode]; + if (result.outcome === "cancelled") return [result.cancellationEvidence.reasonCode]; + return []; +} + +function observedAttemptIdentity( + attempts: readonly unknown[], + stableReplay = false, +): ReasoningEvaluationExpected["attemptIdentity"] { + if (stableReplay) return "stable-replay"; + if (attempts.length === 0) return "none"; + return attempts.every((attempt) => verifyReasoningExecutionAttempt(attempt).status === "valid") + ? "content-derived" + : "none"; +} + +async function executeIdempotency(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + const operation = evaluation.mutation.operation; + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${operation}`, + }); + if (operation === "first-ownership" || operation === "in-progress") { + const { registration } = await registerOnly(runtime, request); + let status: string = registration.status; + if (operation === "in-progress") + status = (await invoke(runtime, operation, { invocationRequest: request })).status; + const state = await readObservedLedgerState(runtime, request); + return { + disposition: "resolve" as const, + errorCode: null, + status, + outcome: state.result?.outcome ?? null, + reasonCodes: state.result === null ? [] : resultReasonCodes(state.result), + attemptCount: state.attempts.length, + durable: state.integrity.status === "valid", + fingerprintStatus: + state.integrity.status === "valid" ? ("valid" as const) : ("invalid" as const), + attemptIdentity: observedAttemptIdentity(state.attempts), + resultExpectation: state.result === null ? ("none" as const) : ("finalized" as const), + evidenceExpectation: + state.integrity.status === "valid" ? ("verified" as const) : ("rejected" as const), + finalizationExpectation: + state.consumption === null ? ("none" as const) : ("committed" as const), + }; + } + const finalized = await invoke(runtime, operation, { invocationRequest: request }); + if (finalized.status === "identical-in-progress") throw new Error("unexpected in-progress"); + let status: string = finalized.status; + let errorCode: string | null = null; + let finalizationExpectation: ReasoningEvaluationExpected["finalizationExpectation"] = "committed"; + if (operation === "identical-finalized") { + const replay = await invoke(runtime, operation, { invocationRequest: request }); + status = replay.status; + if (replay.status !== "identical-in-progress") + expect(replay.resultEnvelope).toEqual(finalized.resultEnvelope); + } else if (operation === "conflicting-key") { + const conflicting = resignRequest(request, { reason: "Conflicting evaluation content" }); + try { + await invoke(runtime, operation, { invocationRequest: conflicting }); + } catch (error) { + errorCode = observedErrorCode(error); + status = "conflict"; + } + } else { + const internal = resolveInternalReasoningExecutionEvidence(runtime.executionEvidence); + const ownership = await internal.resolveInvocationOwnership(request.idempotencyKey); + if (ownership === null) throw new Error("missing ownership"); + const { consumptionFingerprint: _fingerprint, ...unsigned } = finalized.consumptionEvidence; + void _fingerprint; + const transactionId = "reasoning-finalization-evaluation-conflict"; + const consumption = createFinalizedReasoningConsumptionEvidence({ + ...unsigned, + executionLedgerTransactionId: transactionId, + }); + const ledgerHead = await internal.verifyIntegrity(); + const conflict = await internal.finalizeInvocation({ + schemaVersion: "1.0", + expectedLedgerHead: { + ledgerSequence: ledgerHead.verifiedThroughSequence, + auditFingerprint: ledgerHead.lastAuditFingerprint, + }, + ownershipId: ownership.ownershipId, + expectedOwnershipStatus: "in-progress", + expectedAttemptCount: 1, + transactionId, + resultEnvelope: finalized.resultEnvelope, + consumptionEvidence: consumption, + finalizedAt: finalized.resultEnvelope.completedAt, + }); + status = conflict.status; + finalizationExpectation = conflict.status === "conflict" ? "conflict" : "committed"; + } + const state = await readObservedLedgerState(runtime, request); + return { + disposition: "resolve" as const, + errorCode, + status, + outcome: state.result?.outcome ?? null, + reasonCodes: state.result === null ? [] : resultReasonCodes(state.result), + attemptCount: state.attempts.length, + durable: state.integrity.status === "valid", + fingerprintStatus: verifyReasoningResultEnvelopeArtifact(state.result).status, + attemptIdentity: observedAttemptIdentity(state.attempts, operation === "identical-finalized"), + resultExpectation: state.result === null ? ("none" as const) : ("finalized" as const), + evidenceExpectation: + state.integrity.status === "valid" ? ("verified" as const) : ("rejected" as const), + finalizationExpectation, + }; +} + +async function executeRetry(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + const operation = evaluation.mutation.operation; + if (operation === "identical-attempt" || operation === "conflicting-attempt") { + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${operation}`, + }); + const { internal, provider, registration } = await registerOnly(runtime, request); + if (registration.status !== "registered") throw new Error("registration failed"); + const timing = schedule()[0]!; + const attempt = createReasoningExecutionAttempt({ + schemaVersion: "1.0", + executionAttemptId: `evaluation-${operation}`, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: provider.providerCapability.providerCapabilityId, + providerCapabilityFingerprint: provider.providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: 1, + startedAt: timing.startedAt, + deadlineAt: timing.deadlineAt, + cancellationState: "not-requested", + }); + const head = await internal.verifyIntegrity(); + const append = { + schemaVersion: "1.0" as const, + expectedLedgerHead: { + ledgerSequence: head.verifiedThroughSequence, + auditFingerprint: head.lastAuditFingerprint, + }, + ownershipId: registration.ownership.ownershipId, + expectedOwnershipStatus: "in-progress" as const, + expectedPriorAttemptCount: 0, + attempt, + }; + expect(await internal.appendExecutionAttempt(append)).toEqual(attempt); + let stableReplay = false; + if (operation === "identical-attempt") { + expect(await internal.appendExecutionAttempt(append)).toEqual(attempt); + stableReplay = true; + } else { + const { attemptFingerprint: _fingerprint, ...attemptUnsigned } = attempt; + void _fingerprint; + const conflicting = createReasoningExecutionAttempt({ + ...attemptUnsigned, + startedAt: "2026-07-29T01:00:01.010Z", + deadlineAt: "2026-07-29T01:00:02.010Z", + }); + await expect( + internal.appendExecutionAttempt({ ...append, attempt: conflicting }), + ).rejects.toMatchObject({ code: "transaction_conflict" }); + } + const state = await readObservedLedgerState(runtime, request); + return { + disposition: "resolve" as const, + errorCode: null, + status: "in-progress", + outcome: null, + reasonCodes: [], + attemptCount: state.attempts.length, + durable: state.integrity.status === "valid", + fingerprintStatus: + state.integrity.status === "valid" ? ("valid" as const) : ("invalid" as const), + attemptIdentity: observedAttemptIdentity(state.attempts, stableReplay), + resultExpectation: "none" as const, + evidenceExpectation: + state.integrity.status === "valid" ? ("verified" as const) : ("rejected" as const), + finalizationExpectation: "none" as const, + }; + } + const transient = operation === "transient-success"; + const exhaustion = operation === "attempt-exhaustion"; + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${operation}`, + retryMode: transient || exhaustion ? "retry-deterministic-transient-failure" : "no-retry", + maxAttemptCount: transient || exhaustion ? 2 : 1, + }); + const result = await invoke(runtime, operation, { + invocationRequest: request, + fixtureMode: transient + ? "transient-failure-then-success" + : exhaustion + ? "deterministic-transient-failure" + : "deterministic-permanent-failure", + attemptSchedule: schedule(transient || exhaustion ? 2 : 1), + }); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(result.resultEnvelope.outcome).toBe(evaluation.expected.outcome); + expect(result.consumptionEvidence.attemptHistorySummary.attemptCount).toBe( + evaluation.expected.attemptCount, + ); + const attempts = await runtime.executionEvidence.readAttemptHistory(request.invocationRequestId); + expect(new Set(attempts.map((attempt) => attempt.executionAttemptId)).size).toBe(attempts.length); + if (attempts.length === 2) + expect(attempts[1]!.previousExecutionAttemptId).toBe(attempts[0]!.executionAttemptId); + if (exhaustion && result.resultEnvelope.outcome === "failed") + expect(result.resultEnvelope.failureEvidence.reasonCodes).toEqual(["attempt_limit_exhausted"]); + const state = await readObservedLedgerState(runtime, request); + if (state.result === null) throw new Error("missing finalized retry result"); + return { + disposition: "resolve" as const, + errorCode: null, + status: result.status, + outcome: state.result.outcome, + reasonCodes: resultReasonCodes(state.result), + attemptCount: state.attempts.length, + durable: state.integrity.status === "valid", + fingerprintStatus: verifyReasoningResultEnvelopeArtifact(state.result).status, + attemptIdentity: observedAttemptIdentity(state.attempts), + resultExpectation: "finalized" as const, + evidenceExpectation: + state.integrity.status === "valid" ? ("verified" as const) : ("rejected" as const), + finalizationExpectation: + state.consumption === null ? ("none" as const) : ("committed" as const), + }; +} + +async function createSuccessfulProviderArtifact( + runtime: Runtime, + request: ReturnType, + cancellationState: "not-requested" | "requested-cooperatively" = "not-requested", +) { + const provider = createDeterministicFakeReasoningProvider(); + const compatibility = matchReasoningProviderCapabilities({ + invocationRequest: request, + providerCapability: provider.providerCapability, + }); + const timing = schedule()[0]!; + const attempt = createReasoningExecutionAttempt({ + schemaVersion: "1.0", + executionAttemptId: `evaluation-contradiction-${evaluationArtifactSuffix(request)}`, + invocationRequestId: request.invocationRequestId, + invocationRequestFingerprint: request.requestFingerprint, + invocationIdempotencyKey: request.idempotencyKey, + providerCapabilityId: provider.providerCapability.providerCapabilityId, + providerCapabilityFingerprint: provider.providerCapability.descriptorFingerprint, + executionPolicyFingerprint: request.executionPolicy.policyFingerprint, + attemptNumber: 1, + startedAt: timing.startedAt, + deadlineAt: timing.deadlineAt, + cancellationState, + ...(cancellationState === "not-requested" + ? {} + : { + cancellationAuthorityReference: "authority/evaluation-contradiction", + cancellationRequestedAt: "2026-07-29T01:00:01.010Z", + cancellationObservedAt: "2026-07-29T01:00:01.050Z", + }), + }); + const outcome = await provider.execute({ + invocationRequest: request, + providerCapability: provider.providerCapability, + compatibility, + attempt, + completedAt: timing.completedAt, + evaluationTime: request.requestedAt, + cancellationSignal: { + state: cancellationState, + authorityReference: "authority/evaluation-contradiction", + requestedAt: "2026-07-29T01:00:01.010Z", + observedAt: "2026-07-29T01:00:01.050Z", + }, + fixtureMode: "successful-structured-response", + }); + if (verifyReasoningProviderOutcome(outcome).status !== "valid") + throw new Error("successful provider baseline did not verify"); + return { attempt, outcome }; +} + +function evaluationArtifactSuffix(request: ReturnType) { + return request.invocationRequestId.replace(/[^a-z0-9-]/giu, "-"); +} + +async function executeTimeout(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + const operation = evaluation.mutation.operation; + const retry = operation === "timeout-retry"; + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${operation}`, + retryMode: retry ? "retry-until-attempt-limit" : "no-retry", + maxAttemptCount: retry ? 2 : 1, + }); + if (operation === "timeout-contradiction") { + const { attempt, outcome } = await createSuccessfulProviderArtifact(runtime, request); + if (typeof outcome !== "object" || outcome === null) throw new Error("missing outcome object"); + const timeoutEvidence = createReasoningTimeoutEvidence({ + schemaVersion: "1.0", + executionAttemptId: attempt.executionAttemptId, + invocationRequestId: request.invocationRequestId, + configuredTimeoutMilliseconds: request.executionPolicy.timeoutMilliseconds, + attemptStartedAt: attempt.startedAt, + deadlineAt: attempt.deadlineAt!, + elapsedMilliseconds: request.executionPolicy.timeoutMilliseconds, + timeoutPhase: "during-execution", + reasonCode: "execution_timeout", + }); + expect(verifyReasoningTimeoutEvidence(timeoutEvidence).status).toBe("valid"); + const target = requiredMutationTarget(evaluation); + if (target !== "providerOutcome.timeoutEvidence") + throw new Error(`Unsupported timeout contradiction target: ${target}`); + const contradictory = { + ...outcome, + timeoutEvidence, + }; + const verification = verifyReasoningProviderOutcome(contradictory); + expect(verification.status).toBe("invalid"); + return { + disposition: "reject" as const, + errorCode: null, + status: verification.status, + outcome: null, + reasonCodes: verification.issues.map((issue) => issue.code), + attemptCount: attempt.attemptNumber, + durable: "not-applicable" as const, + fingerprintStatus: verification.status, + attemptIdentity: observedAttemptIdentity([attempt]), + resultExpectation: "rejected" as const, + evidenceExpectation: "rejected" as const, + finalizationExpectation: "none" as const, + }; + } + const timings = schedule(retry ? 2 : 1).map((timing) => ({ + ...timing, + completedAt: + operation === "deadline-expired" + ? new Date(Date.parse(timing.deadlineAt) + 100).toISOString() + : timing.deadlineAt, + })); + const result = await invoke(runtime, operation, { + invocationRequest: request, + fixtureMode: + operation === "timeout-no-retry" || retry ? "timeout" : "successful-structured-response", + attemptSchedule: timings, + }); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(result.resultEnvelope.outcome).toBe("timed-out"); + expect(result.consumptionEvidence.attemptHistorySummary.attemptCount).toBe( + evaluation.expected.attemptCount, + ); + const attempts = await runtime.executionEvidence.readAttemptHistory(request.invocationRequestId); + expect(new Set(attempts.map((attempt) => attempt.executionAttemptId)).size).toBe(attempts.length); + if (attempts.length === 2) + expect(attempts[1]!.previousExecutionAttemptId).toBe(attempts[0]!.executionAttemptId); + if (result.resultEnvelope.outcome === "timed-out") + expect(result.resultEnvelope.timeoutEvidence.reasonCode).toBe( + evaluation.expected.reasonCodes![0], + ); + const state = await readObservedLedgerState(runtime, request); + if (state.result === null) throw new Error("missing finalized timeout result"); + return { + disposition: "resolve" as const, + errorCode: null, + status: result.status, + outcome: state.result.outcome, + reasonCodes: resultReasonCodes(state.result), + attemptCount: state.attempts.length, + durable: state.integrity.status === "valid", + fingerprintStatus: verifyReasoningResultEnvelopeArtifact(state.result).status, + attemptIdentity: observedAttemptIdentity(state.attempts), + resultExpectation: "finalized" as const, + evidenceExpectation: + state.integrity.status === "valid" ? ("verified" as const) : ("rejected" as const), + finalizationExpectation: + state.consumption === null ? ("none" as const) : ("committed" as const), + }; +} + +function cancellationSetup(scenarioId: ReasoningEvaluationScenarioId) { + if (scenarioId === "cancel-before") + return { + mode: "cancel-before-execution" as const, + fixture: "cancellation-before-execution" as const, + signal: { + state: "requested-before-execution" as const, + authorityReference: "authority/evaluation-cancel-before", + requestedAt: "2026-07-29T01:00:00.900Z", + observedAt: "2026-07-29T01:00:00.950Z", + }, + }; + if (scenarioId === "cancel-deadline") + return { + mode: "deadline-cancellation" as const, + fixture: "deadline-cancellation" as const, + signal: { + state: "requested-at-deadline" as const, + authorityReference: "authority/evaluation-cancel-deadline", + requestedAt: "2026-07-29T01:00:02.000Z", + observedAt: "2026-07-29T01:00:02.000Z", + }, + }; + return { + mode: "cooperative-cancellation" as const, + fixture: + scenarioId === "cancel-contradiction" + ? ("successful-structured-response" as const) + : ("cooperative-cancellation" as const), + signal: { + state: "requested-cooperatively" as const, + authorityReference: "authority/evaluation-cancel-cooperative", + requestedAt: "2026-07-29T01:00:01.010Z", + observedAt: "2026-07-29T01:00:01.050Z", + }, + }; +} + +async function executeCancellation(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + const operation = evaluation.mutation.operation; + const setup = cancellationSetup(operation); + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${operation}`, + cancellationMode: setup.mode, + }); + if (operation === "cancel-contradiction") { + const { attempt, outcome } = await createSuccessfulProviderArtifact( + runtime, + request, + "requested-cooperatively", + ); + if (typeof outcome !== "object" || outcome === null) throw new Error("missing outcome object"); + const cancellationEvidence = createReasoningCancellationEvidence({ + schemaVersion: "1.0", + invocationRequestId: request.invocationRequestId, + executionAttemptId: attempt.executionAttemptId, + cancellationMode: "cooperative-cancellation", + cancellationPhase: "cooperative-execution", + cancellationAuthorityReference: setup.signal.authorityReference, + requestedAt: setup.signal.requestedAt, + observedAt: setup.signal.observedAt, + reasonCode: "cancelled_cooperatively", + }); + expect(verifyReasoningCancellationEvidence(cancellationEvidence).status).toBe("valid"); + const target = requiredMutationTarget(evaluation); + if (target !== "providerOutcome.cancellationEvidence") + throw new Error(`Unsupported cancellation contradiction target: ${target}`); + const contradictory = { + ...outcome, + cancellationEvidence, + }; + const verification = verifyReasoningProviderOutcome(contradictory); + expect(verification.status).toBe("invalid"); + return { + disposition: "reject" as const, + errorCode: null, + status: verification.status, + outcome: null, + reasonCodes: verification.issues.map((issue) => issue.code), + attemptCount: attempt.attemptNumber, + durable: "not-applicable" as const, + fingerprintStatus: verification.status, + attemptIdentity: observedAttemptIdentity([attempt]), + resultExpectation: "rejected" as const, + evidenceExpectation: "rejected" as const, + finalizationExpectation: "none" as const, + }; + } + const timings = schedule(1, setup.signal).map((timing) => ({ + ...timing, + completedAt: operation === "cancel-deadline" ? timing.deadlineAt : timing.completedAt, + })); + const result = await invoke(runtime, operation, { + invocationRequest: request, + fixtureMode: setup.fixture, + attemptSchedule: timings, + }); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(result.resultEnvelope.outcome).toBe("cancelled"); + if (result.resultEnvelope.outcome === "cancelled") + expect(result.resultEnvelope.cancellationEvidence.reasonCode).toBe( + evaluation.expected.reasonCodes![0], + ); + expect(result.consumptionEvidence.attemptHistorySummary.attemptCount).toBe(1); + const state = await readObservedLedgerState(runtime, request); + if (state.result === null) throw new Error("missing finalized cancellation result"); + return { + disposition: "resolve" as const, + errorCode: null, + status: result.status, + outcome: state.result.outcome, + reasonCodes: resultReasonCodes(state.result), + attemptCount: state.attempts.length, + durable: state.integrity.status === "valid", + fingerprintStatus: verifyReasoningResultEnvelopeArtifact(state.result).status, + attemptIdentity: observedAttemptIdentity(state.attempts), + resultExpectation: "finalized" as const, + evidenceExpectation: + state.integrity.status === "valid" ? ("verified" as const) : ("rejected" as const), + finalizationExpectation: + state.consumption === null ? ("none" as const) : ("committed" as const), + }; +} + +async function executeEvidenceMutation(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + const operation = evaluation.mutation.operation; + const isFailure = operation === "failure-mutation"; + const isTimeout = operation === "timeout-mutation"; + const isCancellation = operation === "cancellation-mutation"; + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${operation}`, + ...(isCancellation ? { cancellationMode: "cancel-before-execution" as const } : {}), + }); + const cancellationSignal = { + state: "requested-before-execution" as const, + authorityReference: "authority/evaluation-evidence-cancel", + requestedAt: "2026-07-29T01:00:00.900Z", + observedAt: "2026-07-29T01:00:00.950Z", + }; + const result = await invoke(runtime, operation, { + invocationRequest: request, + fixtureMode: isFailure + ? "deterministic-permanent-failure" + : isTimeout + ? "timeout" + : isCancellation + ? "cancellation-before-execution" + : "successful-structured-response", + attemptSchedule: isTimeout + ? [{ ...schedule()[0]!, completedAt: schedule()[0]!.deadlineAt }] + : isCancellation + ? schedule(1, cancellationSignal) + : schedule(), + }); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress"); + const attempt = ( + await runtime.executionEvidence.readAttemptHistory(request.invocationRequestId) + )[0]!; + const outcome = await runtime.executionEvidence.readProviderOutcome(attempt.executionAttemptId); + if (outcome === null) throw new Error("missing outcome"); + const envelope = result.resultEnvelope; + if (operation === "output-mutation") { + const verification = verifyReasoningResultEnvelopeArtifact({ + ...envelope, + outputContent: { contentType: "canonical-json", value: null }, + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + if (operation === "usage-mutation") { + const verification = verifyReasoningUsageEvidence({ + ...envelope.usageEvidence, + durationMilliseconds: envelope.usageEvidence.durationMilliseconds + 1, + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + if (operation === "cost-mutation") { + const verification = verifyReasoningCostEvidence({ + ...envelope.costEvidence, + costFingerprint: "0".repeat(64), + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + if (operation === "failure-mutation") { + if (envelope.outcome !== "failed") throw new Error("expected failure"); + const verification = verifyReasoningFailureEvidence({ + ...envelope.failureEvidence, + failureFingerprint: "0".repeat(64), + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + if (operation === "timeout-mutation") { + if (envelope.outcome !== "timed-out") throw new Error("expected timeout"); + const verification = verifyReasoningTimeoutEvidence({ + ...envelope.timeoutEvidence, + timeoutFingerprint: "0".repeat(64), + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + if (operation === "cancellation-mutation") { + if (envelope.outcome !== "cancelled") throw new Error("expected cancellation"); + const verification = verifyReasoningCancellationEvidence({ + ...envelope.cancellationEvidence, + cancellationFingerprint: "0".repeat(64), + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + if (operation === "receipt-mutation") { + const verification = verifyReasoningExecutionReceipt({ + ...envelope.executionReceipt, + startedAt: request.requestedAt, + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + if (operation === "result-mutation") { + const verification = verifyReasoningResultEnvelopeArtifact({ + ...envelope, + consumerId: "mutated-evaluation-consumer", + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + if (operation === "consumption-mutation") { + const verification = verifyFinalizedReasoningConsumptionEvidence({ + consumptionEvidence: { + ...result.consumptionEvidence, + executionLedgerTransactionId: "mutated-evaluation-transaction", + }, + resultEnvelope: envelope, + invocationRequest: request, + providerCapability: createDeterministicFakeReasoningProvider().providerCapability, + attempts: [attempt], + outcomes: [outcome], + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + executionLedgerTransactionId: result.consumptionEvidence.executionLedgerTransactionId, + }); + return rejectedEvidenceObservation(runtime, request, verification); + } + const { resultEnvelopeFingerprint: _fingerprint, ...unsigned } = envelope; + void _fingerprint; + const resigned = createReasoningResultEnvelope({ + ...unsigned, + consumerId: "resigned-evaluation-consumer", + }); + const verification = verifyReasoningResultEnvelope({ + resultEnvelope: resigned, + invocationRequest: request, + providerCapability: createDeterministicFakeReasoningProvider().providerCapability, + attempt, + attemptHistory: [attempt], + providerOutcome: outcome, + outcomeHistory: [outcome], + contextPackageObjectCount: runtime.fixture.result.envelope.contextPackage.included.length, + }); + return rejectedEvidenceObservation(runtime, request, verification); +} + +async function rejectedEvidenceObservation( + runtime: Runtime, + request: ReturnType, + verification: ReturnType, +) { + expect(verification.status).toBe("invalid"); + const state = await readObservedLedgerState(runtime, request); + return { + disposition: "reject" as const, + errorCode: null, + status: verification.status, + outcome: null, + reasonCodes: verification.issues.map((issue) => issue.code), + attemptCount: state.attempts.length, + durable: state.integrity.status === "valid", + fingerprintStatus: verification.status, + attemptIdentity: observedAttemptIdentity(state.attempts), + resultExpectation: state.result === null ? ("none" as const) : ("finalized" as const), + evidenceExpectation: "rejected" as const, + finalizationExpectation: + state.consumption === null ? ("none" as const) : ("committed" as const), + }; +} + +async function executeProviderSafety(evaluation: ReasoningEvaluation, roots: string[]) { + const operation = evaluation.mutation.operation; + if ( + ["network-free", "environment-free", "randomness-free", "wall-clock-free"].includes(operation) + ) { + const source = await readFile( + new URL("../src/infrastructure/deterministic-fake-reasoning-provider.ts", import.meta.url), + "utf8", + ); + const target = requiredMutationTarget(evaluation); + const forbiddenByTarget: Readonly> = { + "provider.source.network": /\bfetch\b|https?:\/\//u, + "provider.source.environment": /process\.env|credential store|keychain/iu, + "provider.source.randomness": /Math\.random|randomUUID|randomBytes/u, + "provider.source.wallClock": /Date\.now|new Date\s*\(/u, + }; + const forbidden = forbiddenByTarget[target]; + if (forbidden === undefined) throw new Error(`Unsupported provider source target: ${target}`); + expect(source).not.toMatch(forbidden); + return { + disposition: "reject" as const, + errorCode: null, + status: "safe", + outcome: null, + reasonCodes: [], + attemptCount: 0, + durable: "not-applicable" as const, + fingerprintStatus: "not-applicable" as const, + attemptIdentity: "none" as const, + resultExpectation: "none" as const, + evidenceExpectation: "sanitized" as const, + finalizationExpectation: "none" as const, + }; + } + const runtime = await createReasoningTestRuntime(roots); + const fixtureMode = + operation === "physical-path" + ? "physical-path-bearing-outcome" + : operation === "credential" + ? "credential-bearing-outcome" + : operation === "malformed" + ? "malformed-success-outcome" + : "contradictory-outcome"; + const request = createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${operation}`, + }); + const result = await invoke(runtime, operation, { fixtureMode, invocationRequest: request }); + if (result.status === "identical-in-progress") throw new Error("unexpected in-progress"); + expect(result.resultEnvelope.outcome).toBe("failed"); + const serialized = JSON.stringify(result); + if (operation === "physical-path") expect(serialized).not.toContain("/private/"); + if (operation === "credential") expect(serialized).not.toContain("fixture-secret"); + if (result.resultEnvelope.outcome === "failed") + expect(result.resultEnvelope.failureEvidence.reasonCodes[0]).toBe( + operation === "physical-path" + ? "physical_path_rejected" + : operation === "credential" + ? "credential_material_rejected" + : operation === "malformed" + ? "malformed_success_outcome" + : "invalid_provider_outcome", + ); + const state = await readObservedLedgerState(runtime, request); + if (state.result === null) throw new Error("missing sanitized provider result"); + return { + disposition: "reject" as const, + errorCode: null, + status: result.status, + outcome: state.result.outcome, + reasonCodes: resultReasonCodes(state.result), + attemptCount: state.attempts.length, + durable: state.integrity.status === "valid", + fingerprintStatus: verifyReasoningResultEnvelopeArtifact(state.result).status, + attemptIdentity: observedAttemptIdentity(state.attempts), + resultExpectation: "finalized" as const, + evidenceExpectation: "sanitized" as const, + finalizationExpectation: + state.consumption === null ? ("none" as const) : ("committed" as const), + }; +} + +async function executeFacadeBypass(evaluation: ReasoningEvaluation, roots: string[]) { + const runtime = await createReasoningTestRuntime(roots); + const operation = evaluation.mutation.operation; + if (operation === "low-level-finalization") { + expect("finalizeInvocation" in runtime.executionEvidence).toBe(false); + expect("appendProviderOutcome" in runtime.executionEvidence).toBe(false); + const integrity = await runtime.executionEvidence.verifyIntegrity(); + return { + disposition: "reject" as const, + errorCode: null, + status: "absent", + outcome: null, + reasonCodes: [], + attemptCount: 0, + durable: integrity.status === "valid", + fingerprintStatus: "not-applicable" as const, + attemptIdentity: "none" as const, + resultExpectation: "rejected" as const, + evidenceExpectation: "none" as const, + finalizationExpectation: "none" as const, + }; + } + const target = requiredMutationTarget(evaluation); + const fieldByTarget: Readonly> = { + "facade.rawKnowledgeObjects": "rawKnowledgeObjects", + "facade.queryResult": "queryResult", + "facade.hiddenContext": "hiddenContext", + "facade.providerPayload": "providerPayload", + "facade.preconstructedResult": "preconstructedResult", + }; + const field = fieldByTarget[target]; + if (field === undefined) throw new Error(`Unsupported facade target: ${target}`); + const base = { + deliveryLedger: runtime.deliveryLedger, + executionEvidence: runtime.executionEvidence, + deliveryIdentity: runtime.deliveryIdentity, + invocationRequest: createInvocation(runtime, { + idempotencyKey: `reasoning:key:evaluation:${operation}`, + }), + fixtureMode: "successful-structured-response" as const, + attemptSchedule: schedule(), + }; + let error: unknown; + try { + await invokeGovernedReasoning({ ...base, [field]: {} } as never); + } catch (caught) { + error = caught; + } + const integrity = await runtime.executionEvidence.verifyIntegrity(); + expect(integrity.verifiedInvocationCount).toBe(0); + return { + disposition: error === undefined ? ("accept" as const) : ("reject" as const), + errorCode: observedErrorCode(error), + status: error === undefined ? "accepted" : "invalid", + outcome: null, + reasonCodes: [], + attemptCount: 0, + durable: integrity.status === "valid", + fingerprintStatus: "not-applicable" as const, + attemptIdentity: "none" as const, + resultExpectation: "rejected" as const, + evidenceExpectation: "none" as const, + finalizationExpectation: "none" as const, + }; +} diff --git a/services/knowledge-engine/tests/reasoning-fixtures.ts b/services/knowledge-engine/tests/reasoning-fixtures.ts new file mode 100644 index 0000000..cdce47c --- /dev/null +++ b/services/knowledge-engine/tests/reasoning-fixtures.ts @@ -0,0 +1,188 @@ +import { mkdir, mkdtemp } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import type { ReasoningInvocationRequest } from "@founderos/knowledge-schema"; + +import { + createProviderNeutralReasoningInput, + createReasoningExecutionPolicy, + createReasoningInstructionBlock, + createReasoningInvocationRequest, + createReasoningProviderCapabilityRequirements, + openLocalFileDurableContextDeliveryLedger, + openLocalFileGovernedReasoningExecutionEvidence, + type DurableDeliveryTransactionIdentity, + type ReasoningAttemptSchedule, +} from "../src/index.js"; +import { DELIVERY_TIME } from "./context-delivery-fixtures.js"; +import { createDurableDeliveryFixture } from "./durable-delivery-ledger-fixtures.js"; + +export async function createReasoningTestRuntime(roots: string[]) { + const repositoryRoot = await mkdtemp(join(tmpdir(), "founderos-m13-")); + roots.push(repositoryRoot); + const docs = join(repositoryRoot, "docs"); + const knowledge = join(repositoryRoot, "knowledge"); + await mkdir(docs); + await mkdir(knowledge); + const canonicalSourceRoots = [docs, knowledge]; + const deliveryRuntimeRoot = join(repositoryRoot, ".founderos", "runtime", "delivery-ledger"); + const reasoningRuntimeRoot = join(repositoryRoot, ".founderos", "runtime", "reasoning-ledger"); + const fixture = await createDurableDeliveryFixture(); + const deliveryLedger = await openLocalFileDurableContextDeliveryLedger({ + repositoryRoot, + runtimeRoot: deliveryRuntimeRoot, + canonicalSourceRoots, + }); + await deliveryLedger.commitVerifiedOriginalDelivery(fixture.commitInput); + const executionEvidence = await openLocalFileGovernedReasoningExecutionEvidence({ + repositoryRoot, + runtimeRoot: reasoningRuntimeRoot, + canonicalSourceRoots, + }); + const envelope = fixture.result.envelope; + const receipt = fixture.result.receipt; + const deliveryIdentity: DurableDeliveryTransactionIdentity = { + transactionId: fixture.commitInput.transaction.transactionId, + deliveryRequestId: fixture.context.request.deliveryRequestId, + deliveryRequestFingerprint: fixture.context.request.requestFingerprint, + deliveryEnvelopeId: envelope.deliveryEnvelopeId, + deliveryEnvelopeFingerprint: envelope.deliveryFingerprint, + deliveryReceiptId: receipt.receiptId, + deliveryReceiptFingerprint: receipt.receiptFingerprint, + }; + return { + repositoryRoot, + docs, + knowledge, + canonicalSourceRoots, + deliveryRuntimeRoot, + reasoningRuntimeRoot, + fixture, + deliveryLedger, + executionEvidence, + deliveryIdentity, + }; +} + +export function createInvocation( + runtime: Awaited>, + options: { + readonly idempotencyKey?: string; + readonly retryMode?: ReasoningInvocationRequest["executionPolicy"]["retryMode"]; + readonly cancellationMode?: ReasoningInvocationRequest["executionPolicy"]["cancellationMode"]; + readonly maxAttemptCount?: number; + readonly maxOutputCharacters?: number; + readonly outputContentType?: "canonical-json" | "canonical-text"; + readonly requireNonEmpty?: boolean; + } = {}, +): ReasoningInvocationRequest { + const envelope = runtime.fixture.result.envelope; + const contextBlock = createReasoningInstructionBlock({ + schemaVersion: "1.0", + blockId: "context-reference", + blockType: "context-reference", + contentType: "canonical-text", + text: "Use only the exact governed Context Package reference.", + priority: 0, + sourceClassification: "delivered-context", + }); + const taskBlock = createReasoningInstructionBlock({ + schemaVersion: "1.0", + blockId: "task-instruction", + blockType: "task-instruction", + contentType: "canonical-text", + text: "Produce the deterministic governed evaluation fixture.", + priority: 1, + sourceClassification: "evaluation-fixture", + }); + const outputContentType = options.outputContentType ?? "canonical-json"; + const maxOutputCharacters = options.maxOutputCharacters ?? 4_000; + const reasoningInput = createProviderNeutralReasoningInput({ + schemaVersion: "1.0", + contentType: "provider-neutral-instruction-blocks-v1", + instructionBlocks: [contextBlock, taskBlock], + contextReference: { + contextPackageId: envelope.contextPackageId, + contextPackageFingerprint: envelope.contextPackageFingerprint, + deliveryEnvelopeId: envelope.deliveryEnvelopeId, + deliveryEnvelopeFingerprint: envelope.deliveryFingerprint, + }, + outputRequirements: { + contentType: outputContentType, + maxCharacters: maxOutputCharacters, + requireNonEmpty: options.requireNonEmpty ?? true, + }, + constraintBlocks: [], + }); + const retryMode = options.retryMode ?? "no-retry"; + const maxAttemptCount = options.maxAttemptCount ?? (retryMode === "no-retry" ? 1 : 2); + const executionPolicy = createReasoningExecutionPolicy({ + schemaVersion: "1.0", + maxInputCharacters: 20_000, + maxOutputCharacters, + timeoutMilliseconds: 1_000, + cancellationMode: options.cancellationMode ?? "not-cancellable", + retryMode, + maxAttemptCount, + deterministicModeRequired: true, + usageEvidenceRequired: true, + costEvidenceRequired: true, + failureEvidenceRequired: true, + resultPersistenceRequired: true, + evaluatedAt: DELIVERY_TIME, + }); + const requirements = createReasoningProviderCapabilityRequirements({ + schemaVersion: "1.0", + acceptedProviderClasses: ["deterministic-fake-provider"], + requiredInputContentTypes: ["provider-neutral-instruction-blocks-v1"], + requiredOutputContentType: outputContentType, + deterministicModeRequired: true, + usageEvidenceRequired: true, + costEvidenceRequired: true, + failureEvidenceRequired: true, + resultEnvelopeVersion: "1.0", + }); + return createReasoningInvocationRequest({ + schemaVersion: "1.0", + invocationRequestId: `reasoning-invocation-${options.idempotencyKey?.replaceAll(":", "-") ?? "0001"}`, + deliveryTransactionId: runtime.deliveryIdentity.transactionId, + deliveryEnvelopeVersion: "1.0", + deliveryEnvelopeId: envelope.deliveryEnvelopeId, + deliveryEnvelopeFingerprint: envelope.deliveryFingerprint, + deliveryReceiptId: runtime.fixture.result.receipt.receiptId, + deliveryReceiptFingerprint: runtime.fixture.result.receipt.receiptFingerprint, + contextPackageId: envelope.contextPackageId, + contextPackageFingerprint: envelope.contextPackageFingerprint, + activeSnapshotBinding: envelope.activeSnapshotBinding, + registryIntegrityBinding: envelope.registryIntegrityBinding, + consumerId: envelope.consumerId, + consumerDescriptorFingerprint: envelope.consumerDescriptorFingerprint, + policyDecisionFingerprint: envelope.policyDecisionEvidence.decisionFingerprint, + purpose: "Evaluate the exact governed delivery", + capabilityRequirements: requirements, + reasoningInput, + executionPolicy, + idempotencyKey: options.idempotencyKey ?? "reasoning:key:0001", + requestActor: { actorId: "milestone-13-evaluation", actorType: "service" }, + reason: "Verify governed provider-neutral reasoning", + requestedAt: DELIVERY_TIME, + }); +} + +export function schedule( + count = 1, + cancellation: ReasoningAttemptSchedule["cancellationSignal"] = { + state: "not-requested", + authorityReference: "authority/evaluation", + requestedAt: "2026-07-29T01:00:00.000Z", + observedAt: "2026-07-29T01:00:00.000Z", + }, +): readonly ReasoningAttemptSchedule[] { + return Array.from({ length: count }, (_, index) => ({ + startedAt: `2026-07-29T01:00:0${index + 1}.000Z`, + deadlineAt: `2026-07-29T01:00:0${index + 2}.000Z`, + completedAt: `2026-07-29T01:00:0${index + 1}.100Z`, + cancellationSignal: cancellation, + })); +}