From 9ed215fc6cbbf9886ae27fbf60deb2864a4ddefd Mon Sep 17 00:00:00 2001 From: Drew Stone Date: Wed, 16 Sep 2026 13:14:31 -0700 Subject: [PATCH] fix(supervise): classify agent-provider-tangle's typed JSON bound refusal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provider 1.5.0 throws JsonBoundError (code JSON_BOUND_VIOLATION) where it threw a plain Error; the classifier files it with the schema violations — a rejected request at admission, a provider contract violation after — closing #1204's exhibit 6. Exhibit 3 is delivered rather than thrown since provider 1.4.0; the doc says so instead of calling it uncovered. 0.235.1. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 9 +++++++++ docs/api/primitive-catalog.md | 2 +- docs/api/runtime.md | 8 +++++--- docs/canonical-api.md | 2 +- package.json | 2 +- src/runtime/supervise/retained-executor.ts | 20 +++++++++++++------ .../fixtures/agent-improvement-proposal.json | 10 +++++----- .../agent-profile-improvement-proposal.json | 6 +++--- 8 files changed, 39 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9a4fc64..cb4cbdf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.235.1 + +`classifyRetainedPendingCause` recognises agent-provider-tangle's typed bound refusal +(`JsonBoundError`, `code: 'JSON_BOUND_VIOLATION'`, provider 1.5.0) and files it with the schema +violations: a rejected request at admission, a provider contract violation after. That closes +#1204's exhibit 6, which 0.235.0 could only leave on `'unobservable'` while the provider threw +a plain `Error`. Exhibit 3 (an event without a stable id) is delivered rather than thrown since +provider 1.4.0 and no longer reaches this path; the doc says so instead of calling it uncovered. + ## 0.235.0 **A retained child's settlement says WHY it is pending, as a value (#1204).** One reason string — diff --git a/docs/api/primitive-catalog.md b/docs/api/primitive-catalog.md index e93cc0cb..15369eef 100644 --- a/docs/api/primitive-catalog.md +++ b/docs/api/primitive-catalog.md @@ -7,7 +7,7 @@ # Primitive catalog — the never-stale anti-reinvention inventory -> **GENERATED** from `@tangle-network/agent-runtime@0.235.0` and `@tangle-network/agent-eval@0.182.0` by `scripts/gen-primitive-catalog.mjs`. Do NOT hand-edit — run `pnpm run docs:api`. This is the mechanical companion to the JUDGMENT in `canonical-api.md` (§2 decision table + §1.5 AgentProfile law): that doc says WHICH primitive to reach for and what NOT to build; this catalog proves WHAT exists. Per-symbol signatures + `file:line` live in the per-module pages under `docs/api/`. +> **GENERATED** from `@tangle-network/agent-runtime@0.235.1` and `@tangle-network/agent-eval@0.182.0` by `scripts/gen-primitive-catalog.mjs`. Do NOT hand-edit — run `pnpm run docs:api`. This is the mechanical companion to the JUDGMENT in `canonical-api.md` (§2 decision table + §1.5 AgentProfile law): that doc says WHICH primitive to reach for and what NOT to build; this catalog proves WHAT exists. Per-symbol signatures + `file:line` live in the per-module pages under `docs/api/`. ## 1. agent-runtime — own public surface diff --git a/docs/api/runtime.md b/docs/api/runtime.md index e13e9aa6..647e9ea6 100644 --- a/docs/api/runtime.md +++ b/docs/api/runtime.md @@ -27998,9 +27998,11 @@ fix or report the provider. Six exhibits in three days wore the first name for t Classification reads the cause's structure — class name, `code`, HTTP `status`, a Zod issue list — never its message text, because the provider is not a dependency of this package and -its messages are not a contract. Two exhibits (#1204's 3 and 6) are thrown by the provider as -plain `Error`s with no code, so a structure-only classifier cannot name them until the provider -types them; they land on `'unobservable'`, which is the safe side. +its messages are not a contract. #1204's exhibit 3 (an event without a stable id) is delivered +rather than thrown since agent-provider-tangle 1.4.0, so it no longer reaches this path; its +exhibit 6 is typed as `JsonBoundError` (`code: 'JSON_BOUND_VIOLATION'`) since 1.5.0 and lands +with the schema violations. A provider still throwing plain `Error`s lands on `'unobservable'`, +which is the safe side. One `RetainedRunProviderContractError` is NOT one meaning. The runtime mints it both when the provider answered wrongly and when a READ of the provider failed (`RETAINED_RESULT_READ_FAILED`, diff --git a/docs/canonical-api.md b/docs/canonical-api.md index fbdf173f..d2496a9d 100644 --- a/docs/canonical-api.md +++ b/docs/canonical-api.md @@ -4,7 +4,7 @@ Generated signatures and the complete export list live in docs/api/. Run pnpm docs:freshness after editing this file. --> -> **Version 0.235.0.** +> **Version 0.235.1.** > [`docs/api/primitive-catalog.md`](./api/primitive-catalog.md) lists every export and import path. > `agent-eval` must satisfy `>=0.182.0 <0.183.0`. > `sandbox` must satisfy `>=0.36.4 <0.42.0`. diff --git a/package.json b/package.json index d8855398..5ebb9478 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tangle-network/agent-runtime", - "version": "0.235.0", + "version": "0.235.1", "description": "Shared task-lifecycle skeleton for agents: a recursive loop kernel for chat turns, one-shot tasks, and multi-attempt loops, with trace capture and eval-gated self-improvement. Domain behavior lives in adapters; scoring and ship-gates in @tangle-network/agent-eval.", "homepage": "https://github.com/tangle-network/agent-runtime#readme", "repository": { diff --git a/src/runtime/supervise/retained-executor.ts b/src/runtime/supervise/retained-executor.ts index bd9a7ae5..8315aa19 100644 --- a/src/runtime/supervise/retained-executor.ts +++ b/src/runtime/supervise/retained-executor.ts @@ -60,9 +60,11 @@ export function retainedExecutorContext(ctx: ExecutorContext): RetainedExecutorC * * Classification reads the cause's structure — class name, `code`, HTTP `status`, a Zod issue * list — never its message text, because the provider is not a dependency of this package and - * its messages are not a contract. Two exhibits (#1204's 3 and 6) are thrown by the provider as - * plain `Error`s with no code, so a structure-only classifier cannot name them until the provider - * types them; they land on `'unobservable'`, which is the safe side. + * its messages are not a contract. #1204's exhibit 3 (an event without a stable id) is delivered + * rather than thrown since agent-provider-tangle 1.4.0, so it no longer reaches this path; its + * exhibit 6 is typed as `JsonBoundError` (`code: 'JSON_BOUND_VIOLATION'`) since 1.5.0 and lands + * with the schema violations. A provider still throwing plain `Error`s lands on `'unobservable'`, + * which is the safe side. * * One `RetainedRunProviderContractError` is NOT one meaning. The runtime mints it both when the * provider answered wrongly and when a READ of the provider failed (`RETAINED_RESULT_READ_FAILED`, @@ -151,9 +153,15 @@ export function classifyRetainedPendingCause( queue.unshift({ value: Reflect.get(value, 'cause'), phase: 'execution' }) continue } - if (name === 'ZodError' || Array.isArray(Reflect.get(value, 'issues'))) { - // A schema violation at admission is a rejected request. After admission it is the - // runtime refusing the PROVIDER's answer — a contract violation on the provider's side. + if ( + name === 'ZodError' || + Array.isArray(Reflect.get(value, 'issues')) || + // agent-provider-tangle's bound refusal (JsonBoundError, since 1.5.0): the same fact as a + // schema violation, typed at last — #1204's exhibit 6. + code === 'JSON_BOUND_VIOLATION' + ) { + // A schema or bound violation at admission is a rejected request. After admission it is + // the runtime refusing the PROVIDER's answer — a contract violation on the provider's side. return at === 'admission' ? 'request-rejected' : 'provider-contract' } if (code !== undefined && transportCodes.has(code)) return 'transport' diff --git a/src/testing/fixtures/agent-improvement-proposal.json b/src/testing/fixtures/agent-improvement-proposal.json index 518e2f4d..53ec5cdc 100644 --- a/src/testing/fixtures/agent-improvement-proposal.json +++ b/src/testing/fixtures/agent-improvement-proposal.json @@ -1,6 +1,6 @@ { "changedSurfaces": ["prompt"], - "digest": "sha256:1796588e4afa2c014ab97ea9f0bd890cfb52fe252a0368658701e76d30c13d5c", + "digest": "sha256:f4b45e70c7c94dc1e0df06cceca3a487b5a6a204f1a8142ee19aea1f749728c3", "evaluation": { "decision": { "contributingChecks": [ @@ -4882,7 +4882,7 @@ ], "metadata": { "fixture": "agent-improvement-proposal", - "runtimeVersion": "0.235.0" + "runtimeVersion": "0.235.1" }, "objectives": [ { @@ -4993,8 +4993,8 @@ "baselineContentHash": "sha256:5c21ee53e513fc604cb09754e21c392b24a424da0ef37dbf8f1ee4a8a0b08f09", "candidateContentHash": "sha256:60fcbb1c728194bd51d7d19cb732d1c3f1881dce7e0a6266b41c8b98cfd65693", "kind": "agent-eval-loop", - "recordDigest": "sha256:6354241d7ef4a495c5f49fa308f1e197d198d03d9b13f81bf95bc81cf23dedf4", - "runId": "agent-runtime-0.235.0-proposal-fixture", + "recordDigest": "sha256:6db337c07377b720a6138bb25a6c182e04a8e8127208cce5b3f10cf676d263ce", + "runId": "agent-runtime-0.235.1-proposal-fixture", "schema": "agent-candidate-experiment" } }, @@ -5021,5 +5021,5 @@ ], "kind": "agent-improvement-proposal", "proposedAt": "2026-07-10T01:00:00.000Z", - "runId": "agent-runtime-0.235.0-proposal-fixture" + "runId": "agent-runtime-0.235.1-proposal-fixture" } diff --git a/src/testing/fixtures/agent-profile-improvement-proposal.json b/src/testing/fixtures/agent-profile-improvement-proposal.json index e1b9ae63..60a95b5d 100644 --- a/src/testing/fixtures/agent-profile-improvement-proposal.json +++ b/src/testing/fixtures/agent-profile-improvement-proposal.json @@ -1,6 +1,6 @@ { "changedSurfaces": ["prompt", "skills"], - "digest": "sha256:abe63493ef0f10236a6a77c5eee3cf4ea771e02bd085735fd57eb6180c086c09", + "digest": "sha256:9613289ccc7edffde9b9b8f5bc638ef69412229ff4ba10c89b5e7bca3808e60c", "evaluation": { "decision": { "contributingChecks": [ @@ -1715,7 +1715,7 @@ ], "metadata": { "fixture": "agent-profile-improvement-proposal", - "runtimeVersion": "0.235.0" + "runtimeVersion": "0.235.1" }, "objectives": [ { @@ -1826,7 +1826,7 @@ "baselineContentHash": "sha256:21c495a37c418c10bde64fbaa188beddeed31f1f051ea60a6a6582a9ee0db704", "candidateContentHash": "sha256:103f77bc8481601eef1ad5fe6ba84a40dffabc3a44f421f8c8559121edab84e9", "kind": "agent-eval-loop", - "recordDigest": "sha256:dbc8aa9c080c23a0b1cf3ca9116767beb27f75f9b8313574942b6c5d33e8a78b", + "recordDigest": "sha256:0529c4828b41eab9e08f535cea6b9f3c303db0decaeb89fc89c50e81382b5d4b", "runId": "profile-improvement-1", "schema": "agent-profile-improvement-experiment" }