diff --git a/CHANGELOG.md b/CHANGELOG.md index af338b44..392fc6f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Changelog +## 0.233.0 + +**A released retained child now settles (#1247).** A child whose provider execution was RETAINED +— admitted durably, result read lost — settles `down` with its cursor slot open and its +reservation reconciled at the floor it had streamed (0.230.0, #1190), so that a later process +could resume the run and reconcile the paid execution. On the pursuit path no later process ever +comes: `supervisePursuit` writes a settle record that refuses re-entry and forces +`retainedAtSettlement: 'release'`, so every one of these children is released at root settlement +and none is ever recovered — by construction, not by accident. Measured 2026-09-15: on +`capability-per-parameter-cpp-glm-20260915c`, 0 of 35 reconciled children ever settled, and 185 +of 223 lost sandbox children across 385 runs stopped at `reconciled`. Each one read as +`never-settled` to every journal reader and was charged its ceiling, while the pool had committed +the floor; Lab told them apart from ordinary downs by matching the reason string. + +- The release sweep now writes the node's terminal record after the `environment-teardown` + receipt, once the executor confirms teardown: the settlement the driver received (reason, + `infra`, `trace`, `harnessTranscript`, `outRef`, `providerModel`), under the seq the driver + saw, marked `retainedExecution: 'released'`. Its `spent` is the node's child-work component + of the reconcile the pool committed — the streamed floor for a leaf, `accounting().reported` + for a recursive executor — never the reservation. A cancelled retained child keeps the + `cancelled` kind and its `source`. The overspend a retained reconcile returned, which the + open-slot surfaces withhold, is carried on this record, because when the run releases the node + the floor is its final charge. A refused release (`destroyed: false`, or an executor whose + teardown will not confirm) writes nothing: the environment may still exist, so the slot stays + open and the node stays in `teardownUnconfirmed`. +- `retainedExecution: 'pending' | 'released'` (new `RetainedExecutionState`) is stated on + `Settled`'s down arm (`'pending'` at the reconcile, `'released'` on replay of a closed node), + on the journal's `settled`/`cancelled` records (`'released'` only), on `NodeSnapshot` from + both the live and the materialized tree, on the `agent.child` payload (a second event per + released node, carrying `releasedAt`), and on `PursuitNodeProjection`. A reader never splits + the population on `reason` text again. `PursuitStatus` stays three-valued. +- `SupervisedResult` gains `fleetYield` on every arm (new `FleetYield`): `spawned`, `done`, + `down`, `cancelled`, `neverSettled`, `releasedUnrecovered`, counted by node id across the + whole journal forest, with `spawned === done + down + cancelled + neverSettled` asserted. + Always present; zeros are facts. It rides into `result.json`. `spendGaps` stays root-tree + scoped, so the two disagree on a nested run by design. A no-winner's `downCount` is unchanged: + the breaker skips released records, so a retained child is counted in `fleetYield.down` and + never in `downCount` — as it never was. +- `spentTotal.tokensKnown`/`usdKnown` stay `false` on a run with a released child: its record + carries the unknown-flagged floor, so the gap changes kind from `never-settled` (a ceiling) to + `unreported` (a floor), not presence. The one exception is a ticket already reconciled at a + measured terminal spend (a persistence failure after the artifact landed), whose released record + is known. The pool half — the refund at the reconcile (#1190) — is unchanged. +- A crash between the receipt and the terminal record leaves an open slot beside a destroyed + environment; the next process cannot self-heal it and this release does not try. + ## 0.232.0 External directors can use `repromptOnUnmet: 'until-complete'` with a completion check and finite positive budget deadline. @@ -75,50 +121,6 @@ blobs)`. Consequences, all deliberate: Settlements recorded before this release carry no `harnessTranscript` on the record, which is not the same fact as a recorded `unavailable`, and stays absent rather than defaulting. -**A released retained child now settles (#1247).** A child whose provider execution was RETAINED -— admitted durably, result read lost — settles `down` with its cursor slot open and its -reservation reconciled at the floor it had streamed (0.230.0, #1190), so that a later process -could resume the run and reconcile the paid execution. On the pursuit path no later process ever -comes: `supervisePursuit` writes a settle record that refuses re-entry and forces -`retainedAtSettlement: 'release'`, so every one of these children is released at root settlement -and none is ever recovered — by construction, not by accident. Measured 2026-09-15: on -`capability-per-parameter-cpp-glm-20260915c`, 0 of 35 reconciled children ever settled, and 185 -of 223 lost sandbox children across 385 runs stopped at `reconciled`. Each one read as -`never-settled` to every journal reader and was charged its ceiling, while the pool had committed -the floor; Lab told them apart from ordinary downs by matching the reason string. - -- The release sweep now writes the node's terminal record after the `environment-teardown` - receipt, once the executor confirms teardown: the settlement the driver received (reason, - `infra`, `trace`, `harnessTranscript`, `outRef`, `providerModel`), under the seq the driver - saw, marked `retainedExecution: 'released'`. Its `spent` is the node's child-work component - of the reconcile the pool committed — the streamed floor for a leaf, `accounting().reported` - for a recursive executor — never the reservation. A cancelled retained child keeps the - `cancelled` kind and its `source`. The overspend a retained reconcile returned, which the - open-slot surfaces withhold, is carried on this record, because when the run releases the node - the floor is its final charge. A refused release (`destroyed: false`, or an executor whose - teardown will not confirm) writes nothing: the environment may still exist, so the slot stays - open and the node stays in `teardownUnconfirmed`. -- `retainedExecution: 'pending' | 'released'` (new `RetainedExecutionState`) is stated on - `Settled`'s down arm (`'pending'` at the reconcile, `'released'` on replay of a closed node), - on the journal's `settled`/`cancelled` records (`'released'` only), on `NodeSnapshot` from - both the live and the materialized tree, on the `agent.child` payload (a second event per - released node, carrying `releasedAt`), and on `PursuitNodeProjection`. A reader never splits - the population on `reason` text again. `PursuitStatus` stays three-valued. -- `SupervisedResult` gains `fleetYield` on every arm (new `FleetYield`): `spawned`, `done`, - `down`, `cancelled`, `neverSettled`, `releasedUnrecovered`, counted by node id across the - whole journal forest, with `spawned === done + down + cancelled + neverSettled` asserted. - Always present; zeros are facts. It rides into `result.json`. `spendGaps` stays root-tree - scoped, so the two disagree on a nested run by design. A no-winner's `downCount` is unchanged: - the breaker skips released records, so a retained child is counted in `fleetYield.down` and - never in `downCount` — as it never was. -- `spentTotal.tokensKnown`/`usdKnown` stay `false` on a run with a released child: its record - carries the unknown-flagged floor, so the gap changes kind from `never-settled` (a ceiling) to - `unreported` (a floor), not presence. The one exception is a ticket already reconciled at a - measured terminal spend (a persistence failure after the artifact landed), whose released record - is known. The pool half — the refund at the reconcile (#1190) — is unchanged. -- A crash between the receipt and the terminal record leaves an open slot beside a destroyed - environment; the next process cannot self-heal it and this release does not try. - ## 0.231.1 Allow Sandbox 0.40.x beside Runtime without a consumer dependency override. diff --git a/docs/api/primitive-catalog.md b/docs/api/primitive-catalog.md index 9db3b744..07adb87f 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.232.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.233.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/`. ## 1. agent-runtime — own public surface diff --git a/docs/canonical-api.md b/docs/canonical-api.md index 84751c88..7cc468a8 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.232.0.** +> **Version 0.233.0.** > [`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.41.0`. diff --git a/package.json b/package.json index a266f53f..890dc7af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tangle-network/agent-runtime", - "version": "0.232.0", + "version": "0.233.0", "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/testing/fixtures/agent-improvement-proposal.json b/src/testing/fixtures/agent-improvement-proposal.json index 8ad18e32..3cfe302f 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:201a9a98fbdc078d03c35314e4e03f34abaa36d7db394a11c4b1110bd036521c", + "digest": "sha256:c955600d688a194cfb429c3c6165a5b8f16ca1634597cab757af0b05cd3290e3", "evaluation": { "decision": { "contributingChecks": [ @@ -4882,7 +4882,7 @@ ], "metadata": { "fixture": "agent-improvement-proposal", - "runtimeVersion": "0.232.0" + "runtimeVersion": "0.233.0" }, "objectives": [ { @@ -4993,8 +4993,8 @@ "baselineContentHash": "sha256:5c21ee53e513fc604cb09754e21c392b24a424da0ef37dbf8f1ee4a8a0b08f09", "candidateContentHash": "sha256:60fcbb1c728194bd51d7d19cb732d1c3f1881dce7e0a6266b41c8b98cfd65693", "kind": "agent-eval-loop", - "recordDigest": "sha256:d26f696c1a140606d4e75b1ade7a03f08ce13f4fc4fdfe0527d2fbb4717e438d", - "runId": "agent-runtime-0.232.0-proposal-fixture", + "recordDigest": "sha256:cbf8298e0f8dd8a60ef8fe8ce3cc4b5c214e35a3c40c05c167e22a4848c43a90", + "runId": "agent-runtime-0.233.0-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.232.0-proposal-fixture" + "runId": "agent-runtime-0.233.0-proposal-fixture" } diff --git a/src/testing/fixtures/agent-profile-improvement-proposal.json b/src/testing/fixtures/agent-profile-improvement-proposal.json index 1d92c27a..cfbb467a 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:702dc1a85ce46804d67de7fd179bd69f6af0027dca7b6a99c46ab7f159bf7f5f", + "digest": "sha256:a28e23a8892b3d8ba6c66c374750e321b06bc036fad7aa76984e617cdc378ff3", "evaluation": { "decision": { "contributingChecks": [ @@ -1715,7 +1715,7 @@ ], "metadata": { "fixture": "agent-profile-improvement-proposal", - "runtimeVersion": "0.232.0" + "runtimeVersion": "0.233.0" }, "objectives": [ { @@ -1826,7 +1826,7 @@ "baselineContentHash": "sha256:21c495a37c418c10bde64fbaa188beddeed31f1f051ea60a6a6582a9ee0db704", "candidateContentHash": "sha256:103f77bc8481601eef1ad5fe6ba84a40dffabc3a44f421f8c8559121edab84e9", "kind": "agent-eval-loop", - "recordDigest": "sha256:6a55eeeef02f261ce41fa35063839ec37d0b64815dae2517e9d92c75dd2585ce", + "recordDigest": "sha256:1bcc70b1e1bb5a020da56e97fcc4a2d89824ecf8ca59b2e0232b868333daa4c4", "runId": "profile-improvement-1", "schema": "agent-profile-improvement-experiment" }