@tangle-network/agent-runtime 0.339.0 → 0.342.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/{activation-CVSFxis9.js → activation-CWPmt0Do.js} +4 -4
  2. package/dist/{activation-CVSFxis9.js.map → activation-CWPmt0Do.js.map} +1 -1
  3. package/dist/{activation-CJIIl_Ey.d.ts → activation-CXqtijue.d.ts} +2 -2
  4. package/dist/agent.d.ts +4 -18
  5. package/dist/agent.js +3 -21
  6. package/dist/agent.js.map +1 -1
  7. package/dist/analyst-loop.d.ts +2 -2
  8. package/dist/{bundle-DVOhBTic.js → bundle-Cwpit6Tg.js} +2 -2
  9. package/dist/{bundle-DVOhBTic.js.map → bundle-Cwpit6Tg.js.map} +1 -1
  10. package/dist/candidate-execution/index.d.ts +2 -40
  11. package/dist/candidate-execution/index.js +9 -255
  12. package/dist/candidate-execution/index.js.map +1 -1
  13. package/dist/{driver-control-acknowledgers-C53ggdJ6.js → coordination-manager-B5JsolDR.js} +4852 -4539
  14. package/dist/coordination-manager-B5JsolDR.js.map +1 -0
  15. package/dist/{delegate-CCWE_AkU.js → delegate-Rl-5paLJ.js} +2 -2
  16. package/dist/{delegate-CCWE_AkU.js.map → delegate-Rl-5paLJ.js.map} +1 -1
  17. package/dist/durable.d.ts +1 -1
  18. package/dist/durable.js +451 -358
  19. package/dist/durable.js.map +1 -1
  20. package/dist/{graph-CI9JXKqO.js → graph-Ce-59ZXn.js} +5 -5
  21. package/dist/{graph-CI9JXKqO.js.map → graph-Ce-59ZXn.js.map} +1 -1
  22. package/dist/{improve-BOXTLWJ3.js → improve-BZXt2qM0.js} +837 -704
  23. package/dist/improve-BZXt2qM0.js.map +1 -0
  24. package/dist/{improvement-adapter-HUt_-cWA.d.ts → improvement-adapter-sIthWkcN.d.ts} +2 -2
  25. package/dist/index.d.ts +6 -14
  26. package/dist/index.js +10 -10
  27. package/dist/intelligence.d.ts +4 -4
  28. package/dist/intelligence.js +205 -191
  29. package/dist/intelligence.js.map +1 -1
  30. package/dist/kernel.d.ts +3 -3
  31. package/dist/kernel.js +10 -10
  32. package/dist/{loop-runner-pmPIHFVY.js → loop-runner-B0MV1-CD.js} +2 -2
  33. package/dist/{loop-runner-pmPIHFVY.js.map → loop-runner-B0MV1-CD.js.map} +1 -1
  34. package/dist/{loop-runner-CWzG1bH4.d.ts → loop-runner-CuhbgVGo.d.ts} +3 -3
  35. package/dist/loop-runner-bin.d.ts +1 -1
  36. package/dist/loop-runner-bin.js +1 -1
  37. package/dist/mcp/bin.js +3 -3
  38. package/dist/mcp/index.d.ts +1 -1
  39. package/dist/mcp/index.js +5 -5
  40. package/dist/placement.d.ts +2 -26
  41. package/dist/placement.js +1 -35
  42. package/dist/placement.js.map +1 -1
  43. package/dist/{prepare-bXkvPMJA.js → prepare-C-cWCyt3.js} +988 -735
  44. package/dist/prepare-C-cWCyt3.js.map +1 -0
  45. package/dist/{profile-Dpei_Sq0.js → profile-CbMw5hAn.js} +2 -2
  46. package/dist/{profile-Dpei_Sq0.js.map → profile-CbMw5hAn.js.map} +1 -1
  47. package/dist/profile-materialization-bPm0gGLO.d.ts +49 -0
  48. package/dist/profiles.d.ts +1 -1
  49. package/dist/{protected-model-port-BGgpy2r9.d.ts → protected-model-port-DVVh-hEk.d.ts} +2 -6
  50. package/dist/{provision-supervisor-CJ6Zz6dz.js → provision-supervisor-DL6gEMQp.js} +444 -419
  51. package/dist/provision-supervisor-DL6gEMQp.js.map +1 -0
  52. package/dist/{runtime-B2fjL9Oi.js → runtime-eghmj6W4.js} +1245 -1028
  53. package/dist/runtime-eghmj6W4.js.map +1 -0
  54. package/dist/{sandbox-profile-compat-BzVBFqrz.js → sandbox-profile-compat-FN2kab2-.js} +72 -72
  55. package/dist/{sandbox-profile-compat-BzVBFqrz.js.map → sandbox-profile-compat-FN2kab2-.js.map} +1 -1
  56. package/dist/{search-executor-zMumiak_.js → search-executor-rbjdZ3OD.js} +3 -3
  57. package/dist/{search-executor-zMumiak_.js.map → search-executor-rbjdZ3OD.js.map} +1 -1
  58. package/dist/{server-_4voDNrl.js → server-BiK1Kcno.js} +4 -4
  59. package/dist/{server-_4voDNrl.js.map → server-BiK1Kcno.js.map} +1 -1
  60. package/dist/{structural-rollout-DpLCXzaL.js → structural-rollout-BD9IN7K_.js} +3 -3
  61. package/dist/{structural-rollout-DpLCXzaL.js.map → structural-rollout-BD9IN7K_.js.map} +1 -1
  62. package/dist/{supervise-qAwXmPtD.js → supervise-DmOi7gll.js} +6525 -5562
  63. package/dist/supervise-DmOi7gll.js.map +1 -0
  64. package/dist/{supervisor-DHrUJhEZ.js → supervisor-DUWcecAd.js} +13717 -12778
  65. package/dist/supervisor-DUWcecAd.js.map +1 -0
  66. package/dist/testing.d.ts +1 -1
  67. package/dist/testing.js +13 -13
  68. package/dist/tui/index.d.ts +1 -1
  69. package/dist/tui/index.js +1 -1
  70. package/dist/{types-CaOXqRTq.d.ts → types-Cgs89PQd.d.ts} +315 -409
  71. package/dist/{types-zWfqDjeL.d.ts → types-Cwrea-bU.d.ts} +2 -17
  72. package/dist/workspace-store/index.d.ts +1 -82
  73. package/dist/workspace-store/index.js +274 -680
  74. package/dist/workspace-store/index.js.map +1 -1
  75. package/package.json +8 -8
  76. package/dist/driver-control-acknowledgers-C53ggdJ6.js.map +0 -1
  77. package/dist/improve-BOXTLWJ3.js.map +0 -1
  78. package/dist/prepare-bXkvPMJA.js.map +0 -1
  79. package/dist/profile-materialization-B1wm2SPT.d.ts +0 -94
  80. package/dist/provision-supervisor-CJ6Zz6dz.js.map +0 -1
  81. package/dist/runtime-B2fjL9Oi.js.map +0 -1
  82. package/dist/supervise-qAwXmPtD.js.map +0 -1
  83. package/dist/supervisor-DHrUJhEZ.js.map +0 -1
@@ -1,20 +1,20 @@
1
1
  import { o as writeAtomicDurableFile } from "./durable-file-gNI9ILAn.js";
2
- import { Di as contentAddress, Ei as detachedSnapshot, L as rollingDispatch, M as settledToIteration, Qn as verdictFromJudgeScore, Qt as createWorktreeCliExecutor, Ti as detachedFrozen, Wi as createSandboxTurnEventCollector, Xn as gateOnDeliverable, Yn as CheckUnavailableError, Zn as mapExecutorResult, _t as runAgentRounds, jt as routerBrain, k as coordinationProfileToolPrefix, li as executableAgentProfileSnapshot, lt as insideCursorNamespace, n as createSupervisor, ot as InMemoryResultBlobStore, p as isTraceAnalysisStore, pt as createExecutor, qi as notifySandboxEventObserver, st as InMemorySpawnJournal, u as withDriverExecutor, ui as executableAgentSpecSnapshot, ut as createExecutorRegistry, vt as assertBoxlessPromptOptions, wt as defaultSelectWinner, xt as createSandboxLineage, yr as runAbortable, yt as readPromptOptions } from "./supervisor-DHrUJhEZ.js";
2
+ import { $t as createWorktreeCliExecutor, Hi as notifySandboxEventObserver, L as rollingDispatch, M as settledToIteration, Mt as routerBrain, Qn as verdictFromJudgeScore, Si as contentAddress, St as createSandboxLineage, Tt as defaultSelectWinner, Xn as gateOnDeliverable, Yn as CheckUnavailableError, Zn as mapExecutorResult, _r as runAbortable, ai as executableAgentSpecSnapshot, bi as detachedFrozen, bt as readPromptOptions, ct as InMemorySpawnJournal, dt as createExecutorRegistry, ii as executableAgentProfileSnapshot, k as coordinationProfileToolPrefix, mt as createExecutor, n as createSupervisor, p as isTraceAnalysisStore, st as InMemoryResultBlobStore, u as withDriverExecutor, ut as insideCursorNamespace, vt as runAgentRounds, xi as detachedSnapshot, yt as assertBoxlessPromptOptions, zi as createSandboxTurnEventCollector } from "./supervisor-DUWcecAd.js";
3
3
  import { i as ConfigError, m as ValidationError, n as AnalystError, s as PlannerError } from "./errors-DodWX-cb.js";
4
- import { D as runAgentic, E as refine, M as renderReport, N as profileChatClient, O as sample, j as observe, k as ObservationError, v as loadAuthoredStrategy, x as strategyAuthorContract, y as requestStrategySource } from "./structural-rollout-DpLCXzaL.js";
5
- import { $ as hasCompleteCacheBreakdown, F as canonicalCandidateDigest$1, G as addSpend, J as cloneSpend, M as markPutStreamVerified, Q as fnv1a32Hex, V as sha256Bytes$1, Z as errorMessage, ct as stringifySafe, et as isAbortError, it as randomSuffix, nt as mapWithConcurrency, pt as zeroSpend, q as chargedTokens, st as sleep, tt as isAsyncIterable, w as captureMaterializedWorkspace, wt as armDeadlineTimer, x as WorkspaceScanLimitError, z as immutableCandidateValue } from "./sandbox-profile-compat-BzVBFqrz.js";
4
+ import { D as runAgentic, E as refine, M as renderReport, N as profileChatClient, O as sample, j as observe, k as ObservationError, v as loadAuthoredStrategy, x as strategyAuthorContract, y as requestStrategySource } from "./structural-rollout-BD9IN7K_.js";
5
+ import { $ as isAbortError, B as sha256Bytes$1, C as WorkspaceScanLimitError, Ct as armDeadlineTimer, E as captureMaterializedWorkspace, K as chargedTokens, P as canonicalCandidateDigest$1, Q as hasCompleteCacheBreakdown, R as immutableCandidateValue, W as addSpend, X as errorMessage, Z as fnv1a32Hex, et as isAsyncIterable, ft as zeroSpend, h as markPutStreamVerified, ot as sleep, q as cloneSpend, rt as randomSuffix, st as stringifySafe, tt as mapWithConcurrency } from "./sandbox-profile-compat-FN2kab2-.js";
6
6
  import { c as profileModelExecutionSettings, i as concreteModelId, l as profileProviderModel, o as enforceTokenLimits, p as canonicalObservedModelParts, t as assertExecutableAgentProfile, v as harnessRunsAgent } from "./model-policy-CyCUwHed.js";
7
7
  import { i as notifyRuntimeHookEvent } from "./runtime-hooks-tXpAarhW.js";
8
8
  import { a as readCommittedJsonLines, i as readCommittedJsonFile, n as isNoEntError, o as upsertCommittedJsonLine, s as withJsonlFileLock, t as appendCommittedJsonLine } from "./jsonl-file-C9Kde_0Z.js";
9
- import { g as foldCoordinationRecords, p as createInMemoryRunContext } from "./driver-control-acknowledgers-C53ggdJ6.js";
10
- import { I as runBrainLoop, t as supervise } from "./supervise-qAwXmPtD.js";
11
- import { a as reconcileInterruptedSearchCalls, c as searchExecutor, r as dedicatedLane, x as runtimeShipDecision } from "./search-executor-zMumiak_.js";
9
+ import { g as foldCoordinationRecords, p as createInMemoryRunContext } from "./coordination-manager-B5JsolDR.js";
10
+ import { _ as runBrainLoop, t as supervise } from "./supervise-DmOi7gll.js";
11
+ import { a as reconcileInterruptedSearchCalls, c as searchExecutor, r as dedicatedLane, x as runtimeShipDecision } from "./search-executor-rbjdZ3OD.js";
12
12
  import "./run-cancellation-C9oL62sW.js";
13
13
  import { a as graphRunsFor, d as recordGraphRun, i as graphRegistry, l as lookupGraph, p as taskShapeDigest, r as graphFromStored, t as digestOfGraph } from "./graph-registry-BnO64cn8.js";
14
14
  import { i as redactProtectedValue, r as redactProtectedReason } from "./protected-redaction-DFCeo4vg.js";
15
- import "./provision-supervisor-CJ6Zz6dz.js";
16
- import "./delegate-CCWE_AkU.js";
17
- import "./graph-CI9JXKqO.js";
15
+ import "./provision-supervisor-DL6gEMQp.js";
16
+ import "./delegate-Rl-5paLJ.js";
17
+ import "./graph-Ce-59ZXn.js";
18
18
  import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, sha256Bytes, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
19
19
  import { CODING_HARNESSES, DEFAULT_TRACE_ANALYST_KINDS, InMemoryTraceStore, OUTPUT_VALUE, benjaminiHochberg, buildTrajectory, computeFindingId as computeFindingId$1, confidenceInterval, createTraceAnalyst, expandProfileAxes, makeFinding as makeFinding$1, pairedBootstrap, paretoFrontier, wilcoxonSignedRank, wilson } from "@tangle-network/agent-eval";
20
20
  import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
@@ -2808,27 +2808,24 @@ function gitSha() {
2808
2808
  function normalizeScore(s) {
2809
2809
  return typeof s === "number" ? { composite: s } : s;
2810
2810
  }
2811
- /**
2812
- * Assemble a declarative spec (`cases` + `prompt` + `score`) into a runnable
2813
- * harness×model leaderboard — `run()` executes the matrix, `toBenchmarkAdapter()`
2814
- * exposes the same domain as a structural `BenchmarkAdapter`.
2815
- */
2816
- function defineLeaderboard(spec) {
2817
- const caseId = (c) => {
2818
- const id = spec.caseId ? spec.caseId(c) : c.id;
2819
- if (typeof id !== "string" || id.length === 0) throw new Error(`defineLeaderboard(${spec.name}): every case needs a stable string id — give cases an \`id\` property or supply spec.caseId`);
2820
- return id;
2821
- };
2822
- const selectCases = (ids) => {
2823
- if (!ids) return spec.cases;
2824
- const byId = new Map(spec.cases.map((c) => [caseId(c), c]));
2825
- return ids.map((id) => {
2826
- const c = byId.get(id);
2827
- if (c === void 0) throw new Error(`defineLeaderboard(${spec.name}): unknown case "${id}" (have: ${[...byId.keys()].join(", ")})`);
2828
- return c;
2829
- });
2830
- };
2831
- const scoreJudge = {
2811
+ /** The stable string id of a case. */
2812
+ function leaderboardCaseId(spec, c) {
2813
+ const id = spec.caseId ? spec.caseId(c) : c.id;
2814
+ if (typeof id !== "string" || id.length === 0) throw new Error(`defineLeaderboard(${spec.name}): every case needs a stable string id — give cases an \`id\` property or supply spec.caseId`);
2815
+ return id;
2816
+ }
2817
+ /** The cases named by `ids`, in that order; every case when `ids` is omitted. */
2818
+ function selectLeaderboardCases(spec, ids) {
2819
+ if (!ids) return spec.cases;
2820
+ const byId = new Map(spec.cases.map((c) => [leaderboardCaseId(spec, c), c]));
2821
+ return ids.map((id) => {
2822
+ const c = byId.get(id);
2823
+ if (c === void 0) throw new Error(`defineLeaderboard(${spec.name}): unknown case "${id}" (have: ${[...byId.keys()].join(", ")})`);
2824
+ return c;
2825
+ });
2826
+ }
2827
+ function leaderboardScoreJudge(spec) {
2828
+ return {
2832
2829
  name: `${spec.name}-score`,
2833
2830
  dimensions: [{
2834
2831
  key: "composite",
@@ -2846,20 +2843,174 @@ function defineLeaderboard(spec) {
2846
2843
  };
2847
2844
  }
2848
2845
  };
2846
+ }
2847
+ /** The standard flags plus every `spec.flags` entry, read from argv. */
2848
+ function parseLeaderboardArgs(spec, argv) {
2849
+ const args = {};
2850
+ for (const name of [
2851
+ "backend",
2852
+ "harnesses",
2853
+ "models",
2854
+ "cases",
2855
+ "shots",
2856
+ "reps",
2857
+ "model-snapshot",
2858
+ "run-dir",
2859
+ "export-dir"
2860
+ ]) args[name] = argOf(argv, name);
2861
+ for (const [name, flag] of Object.entries(spec.flags ?? {})) args[name] = argOf(argv, name) ?? flag.default;
2862
+ return args;
2863
+ }
2864
+ /** The harness×model axes and the executable profiles they expand to. */
2865
+ function resolveLeaderboardProfiles(spec, args, snapshot) {
2866
+ const harnesses = splitList(args.harnesses) ?? spec.axis?.harnesses ?? CODING_HARNESSES;
2867
+ const rawModels = splitList(args.models) ?? spec.axis?.models ?? (spec.baseProfile?.model?.default !== void 0 ? [spec.baseProfile.model.default] : void 0);
2868
+ if (!rawModels || rawModels.length === 0) throw new Error(`defineLeaderboard(${spec.name}): no models — pass --models, set spec.axis.models, or give spec.baseProfile a model.default`);
2869
+ const models = rawModels.map((m) => withSnapshot(m, snapshot));
2870
+ const profiles = expandProfileAxes({
2871
+ base: spec.baseProfile,
2872
+ harnesses,
2873
+ models
2874
+ });
2875
+ for (const profile of profiles) assertExecutableAgentProfile(profile, `defineLeaderboard(${spec.name})`);
2876
+ return {
2877
+ harnesses,
2878
+ models,
2879
+ profiles
2880
+ };
2881
+ }
2882
+ /** The sandbox client for the named backend: defaults plus spec overrides (spec wins).
2883
+ * Factories are lazy so an unused backend never resolves credentials. */
2884
+ function resolveLeaderboardClient(spec, backendName) {
2885
+ const backends = {
2886
+ sandbox: () => {
2887
+ throw new Error(`defineLeaderboard(${spec.name}): the 'sandbox' backend needs your product's real Sandbox client — supply spec.backends.sandbox (e.g. () => new Sandbox({ apiKey, baseUrl }))`);
2888
+ },
2889
+ "cli-bridge": () => {
2890
+ const bearer = process.env.BRIDGE_BEARER ?? process.env.CLI_BRIDGE_BEARER;
2891
+ if (!bearer) throw new Error(`defineLeaderboard(${spec.name}): backend 'cli-bridge' needs BRIDGE_BEARER or CLI_BRIDGE_BEARER set`);
2892
+ return resolveSandboxClient({
2893
+ backend: "bridge",
2894
+ bridge: {
2895
+ url: process.env.CLI_BRIDGE_URL,
2896
+ bearer,
2897
+ timeoutMs: 9e5
2898
+ }
2899
+ });
2900
+ },
2901
+ ...spec.backends
2902
+ };
2903
+ const makeClient = backends[backendName];
2904
+ if (!makeClient) throw new Error(`defineLeaderboard(${spec.name}): unknown backend "${backendName}" (have: ${Object.keys(backends).join(", ")})`);
2905
+ return makeClient();
2906
+ }
2907
+ /**
2908
+ * The default dispatch wraps loopDispatch per cell (closures only — no
2909
+ * per-cell resource cost) so the loop's finished iterations can be joined
2910
+ * with the campaign ctx: onCellEvents gets EVERY shot's outcome (a thrown
2911
+ * shot never reaches parse, so parse-time tapping would hide it), and a
2912
+ * the cost receipt records the spec-resolved served model.
2913
+ */
2914
+ function leaderboardDispatch(spec, sandboxClient, shots, promptOf) {
2915
+ let shotNonce = 0;
2916
+ const maximumCharge = spec.maximumCharge;
2917
+ return (profile, scenario, dispatchCtx) => {
2918
+ return loopDispatch({
2919
+ sandboxClient,
2920
+ maximumCharge: typeof maximumCharge === "function" ? (cellScenario, cellProfile) => maximumCharge(cellProfile, cellScenario) : maximumCharge,
2921
+ resolveCostModel: (result, _cellScenario, cellProfile) => {
2922
+ if (!spec.resolveModel) return cellProfile.model?.default;
2923
+ const served = new Set(result.iterations.map((iteration) => spec.resolveModel?.(iteration.events)).filter((model) => model !== void 0));
2924
+ if (served.size > 1) throw new Error(`defineLeaderboard(${spec.name}): one cell reported multiple served models: ${[...served].join(", ")}`);
2925
+ return [...served][0] ?? cellProfile.model?.default;
2926
+ },
2927
+ toLoopOptions: (cellScenario, cellProfile) => {
2928
+ return {
2929
+ driver: naiveRetryDriver(shots),
2930
+ agentRun: {
2931
+ profile: cellProfile,
2932
+ taskToPrompt: (s) => `${promptOf(s)}\n\n<!-- independent-attempt:${shotNonce++} -->`
2933
+ },
2934
+ output: { parse: (events) => spec.parseOutput ? spec.parseOutput(events, cellScenario.case) : collectAgentResponseText(events) ?? "" },
2935
+ validator: { validate: async (output) => {
2936
+ const s = normalizeScore(spec.score(output, cellScenario.case));
2937
+ return {
2938
+ valid: s.composite > 0,
2939
+ score: s.composite
2940
+ };
2941
+ } },
2942
+ task: cellScenario,
2943
+ maxIterations: shots
2944
+ };
2945
+ },
2946
+ toArtifact: (result) => {
2947
+ for (const iter of result.iterations) spec.onCellEvents?.(iter.events, scenario.case, {
2948
+ index: iter.index,
2949
+ ...iter.error ? { error: iter.error.message } : {},
2950
+ ...iter.verdict ? { verdict: { score: iter.verdict.score } } : {}
2951
+ });
2952
+ return result.winner?.output;
2953
+ }
2954
+ })(profile, scenario, dispatchCtx);
2955
+ };
2956
+ }
2957
+ /** Hand the result to `spec.export`, or write the default JSON and markdown leaderboard. */
2958
+ async function exportLeaderboardResult(spec, result, ctx) {
2959
+ if (spec.export) {
2960
+ await spec.export(result, ctx);
2961
+ return;
2962
+ }
2963
+ mkdirSync(ctx.exportDir, { recursive: true });
2964
+ writeFileSync(join(ctx.runDir, "matrix-result.json"), `${JSON.stringify(result, null, 2)}\n`);
2965
+ const table = renderLeaderboardMarkdown(leaderboard(result.records, {
2966
+ title: spec.name,
2967
+ meta: { backend: ctx.backend }
2968
+ }));
2969
+ writeFileSync(join(ctx.exportDir, "leaderboard.md"), table);
2970
+ console.log(table);
2971
+ }
2972
+ /** The leaderboard's domain surface in the structural `BenchmarkAdapter` shape. */
2973
+ function leaderboardBenchmarkAdapter(spec) {
2974
+ return {
2975
+ name: spec.name,
2976
+ async preflight() {
2977
+ const seen = /* @__PURE__ */ new Set();
2978
+ for (const c of spec.cases) {
2979
+ const id = leaderboardCaseId(spec, c);
2980
+ if (seen.has(id)) throw new Error(`defineLeaderboard(${spec.name}): duplicate case id "${id}"`);
2981
+ seen.add(id);
2982
+ }
2983
+ },
2984
+ async loadTasks(opts) {
2985
+ const selected = selectLeaderboardCases(spec, opts?.ids);
2986
+ const limited = opts?.limit !== void 0 ? selected.slice(0, opts.limit) : selected;
2987
+ return Promise.all(limited.map(async (c) => ({
2988
+ id: leaderboardCaseId(spec, c),
2989
+ prompt: await spec.prompt(c),
2990
+ metadata: { case: c }
2991
+ })));
2992
+ },
2993
+ async judge(task, artifact) {
2994
+ const [c] = selectLeaderboardCases(spec, [task.id]);
2995
+ if (c === void 0) throw new Error(`defineLeaderboard(${spec.name}): no case "${task.id}"`);
2996
+ const s = normalizeScore(spec.score(artifact, c));
2997
+ return {
2998
+ resolved: s.composite > 0,
2999
+ score: s.composite,
3000
+ detail: s.notes
3001
+ };
3002
+ },
3003
+ async goldArtifact() {}
3004
+ };
3005
+ }
3006
+ /**
3007
+ * Assemble a declarative spec (`cases` + `prompt` + `score`) into a runnable
3008
+ * harness×model leaderboard — `run()` executes the matrix, `toBenchmarkAdapter()`
3009
+ * exposes the same domain as a structural `BenchmarkAdapter`.
3010
+ */
3011
+ function defineLeaderboard(spec) {
2849
3012
  async function run(argv = process.argv.slice(2)) {
2850
- const args = {};
2851
- for (const name of [
2852
- "backend",
2853
- "harnesses",
2854
- "models",
2855
- "cases",
2856
- "shots",
2857
- "reps",
2858
- "model-snapshot",
2859
- "run-dir",
2860
- "export-dir"
2861
- ]) args[name] = argOf(argv, name);
2862
- for (const [name, flag] of Object.entries(spec.flags ?? {})) args[name] = argOf(argv, name) ?? flag.default;
3013
+ const args = parseLeaderboardArgs(spec, argv);
2863
3014
  const backendName = args.backend ?? "sandbox";
2864
3015
  const shots = Number(args.shots ?? spec.shots ?? 1);
2865
3016
  const reps = Number(args.reps ?? spec.reps ?? 1);
@@ -2867,23 +3018,14 @@ function defineLeaderboard(spec) {
2867
3018
  const runDir = args["run-dir"] ?? join(tmpdir(), `leaderboard-${spec.name}-${Date.now()}-${process.pid}`);
2868
3019
  const exportDir = args["export-dir"] ?? join(runDir, "export");
2869
3020
  mkdirSync(runDir, { recursive: true });
2870
- const cases = selectCases(splitList(args.cases));
3021
+ const cases = selectLeaderboardCases(spec, splitList(args.cases));
2871
3022
  if (cases.length === 0) throw new Error(`defineLeaderboard(${spec.name}): no cases to run`);
2872
3023
  const scenarios = cases.map((c) => ({
2873
- id: caseId(c),
3024
+ id: leaderboardCaseId(spec, c),
2874
3025
  kind: spec.name,
2875
3026
  case: c
2876
3027
  }));
2877
- const harnesses = splitList(args.harnesses) ?? spec.axis?.harnesses ?? CODING_HARNESSES;
2878
- const rawModels = splitList(args.models) ?? spec.axis?.models ?? (spec.baseProfile?.model?.default !== void 0 ? [spec.baseProfile.model.default] : void 0);
2879
- if (!rawModels || rawModels.length === 0) throw new Error(`defineLeaderboard(${spec.name}): no models — pass --models, set spec.axis.models, or give spec.baseProfile a model.default`);
2880
- const models = rawModels.map((m) => withSnapshot(m, snapshot));
2881
- const profiles = expandProfileAxes({
2882
- base: spec.baseProfile,
2883
- harnesses,
2884
- models
2885
- });
2886
- for (const profile of profiles) assertExecutableAgentProfile(profile, `defineLeaderboard(${spec.name})`);
3028
+ const { harnesses, models, profiles } = resolveLeaderboardProfiles(spec, args, snapshot);
2887
3029
  const ctx = {
2888
3030
  name: spec.name,
2889
3031
  backend: backendName,
@@ -2896,27 +3038,7 @@ function defineLeaderboard(spec) {
2896
3038
  shots,
2897
3039
  reps
2898
3040
  };
2899
- const backends = {
2900
- sandbox: () => {
2901
- throw new Error(`defineLeaderboard(${spec.name}): the 'sandbox' backend needs your product's real Sandbox client — supply spec.backends.sandbox (e.g. () => new Sandbox({ apiKey, baseUrl }))`);
2902
- },
2903
- "cli-bridge": () => {
2904
- const bearer = process.env.BRIDGE_BEARER ?? process.env.CLI_BRIDGE_BEARER;
2905
- if (!bearer) throw new Error(`defineLeaderboard(${spec.name}): backend 'cli-bridge' needs BRIDGE_BEARER or CLI_BRIDGE_BEARER set`);
2906
- return resolveSandboxClient({
2907
- backend: "bridge",
2908
- bridge: {
2909
- url: process.env.CLI_BRIDGE_URL,
2910
- bearer,
2911
- timeoutMs: 9e5
2912
- }
2913
- });
2914
- },
2915
- ...spec.backends
2916
- };
2917
- const makeClient = backends[backendName];
2918
- if (!makeClient) throw new Error(`defineLeaderboard(${spec.name}): unknown backend "${backendName}" (have: ${Object.keys(backends).join(", ")})`);
2919
- const sandboxClient = makeClient();
3041
+ const sandboxClient = resolveLeaderboardClient(spec, backendName);
2920
3042
  const promptById = /* @__PURE__ */ new Map();
2921
3043
  for (const s of scenarios) promptById.set(s.id, await spec.prompt(s.case));
2922
3044
  const promptOf = (s) => {
@@ -2924,111 +3046,28 @@ function defineLeaderboard(spec) {
2924
3046
  if (p === void 0) throw new Error(`defineLeaderboard(${spec.name}): no prompt for case "${s.id}"`);
2925
3047
  return p;
2926
3048
  };
2927
- let shotNonce = 0;
2928
- const maximumCharge = spec.maximumCharge;
2929
- const dispatch = spec.dispatch ?? ((profile, scenario, dispatchCtx) => {
2930
- return loopDispatch({
2931
- sandboxClient,
2932
- maximumCharge: typeof maximumCharge === "function" ? (cellScenario, cellProfile) => maximumCharge(cellProfile, cellScenario) : maximumCharge,
2933
- resolveCostModel: (result, _cellScenario, cellProfile) => {
2934
- if (!spec.resolveModel) return cellProfile.model?.default;
2935
- const served = new Set(result.iterations.map((iteration) => spec.resolveModel?.(iteration.events)).filter((model) => model !== void 0));
2936
- if (served.size > 1) throw new Error(`defineLeaderboard(${spec.name}): one cell reported multiple served models: ${[...served].join(", ")}`);
2937
- return [...served][0] ?? cellProfile.model?.default;
2938
- },
2939
- toLoopOptions: (cellScenario, cellProfile) => {
2940
- return {
2941
- driver: naiveRetryDriver(shots),
2942
- agentRun: {
2943
- profile: cellProfile,
2944
- taskToPrompt: (s) => `${promptOf(s)}\n\n<!-- independent-attempt:${shotNonce++} -->`
2945
- },
2946
- output: { parse: (events) => spec.parseOutput ? spec.parseOutput(events, cellScenario.case) : collectAgentResponseText(events) ?? "" },
2947
- validator: { validate: async (output) => {
2948
- const s = normalizeScore(spec.score(output, cellScenario.case));
2949
- return {
2950
- valid: s.composite > 0,
2951
- score: s.composite
2952
- };
2953
- } },
2954
- task: cellScenario,
2955
- maxIterations: shots
2956
- };
2957
- },
2958
- toArtifact: (result) => {
2959
- for (const iter of result.iterations) spec.onCellEvents?.(iter.events, scenario.case, {
2960
- index: iter.index,
2961
- ...iter.error ? { error: iter.error.message } : {},
2962
- ...iter.verdict ? { verdict: { score: iter.verdict.score } } : {}
2963
- });
2964
- return result.winner?.output;
2965
- }
2966
- })(profile, scenario, dispatchCtx);
2967
- });
3049
+ const dispatch = spec.dispatch ?? leaderboardDispatch(spec, sandboxClient, shots, promptOf);
2968
3050
  await spec.setup?.(ctx);
2969
3051
  try {
2970
3052
  const result = await runProfileMatrix({
2971
3053
  profiles,
2972
3054
  scenarios,
2973
3055
  dispatch,
2974
- judges: spec.judges ?? [scoreJudge],
3056
+ judges: spec.judges ?? [leaderboardScoreJudge(spec)],
2975
3057
  runDir,
2976
3058
  commitSha: gitSha(),
2977
3059
  reps,
2978
3060
  ...spec.matrix
2979
3061
  });
2980
- if (spec.export) await spec.export(result, ctx);
2981
- else {
2982
- mkdirSync(exportDir, { recursive: true });
2983
- writeFileSync(join(runDir, "matrix-result.json"), `${JSON.stringify(result, null, 2)}\n`);
2984
- const table = renderLeaderboardMarkdown(leaderboard(result.records, {
2985
- title: spec.name,
2986
- meta: { backend: backendName }
2987
- }));
2988
- writeFileSync(join(exportDir, "leaderboard.md"), table);
2989
- console.log(table);
2990
- }
3062
+ await exportLeaderboardResult(spec, result, ctx);
2991
3063
  return result;
2992
3064
  } finally {
2993
3065
  await spec.teardown?.(ctx);
2994
3066
  }
2995
3067
  }
2996
- function toBenchmarkAdapter() {
2997
- return {
2998
- name: spec.name,
2999
- async preflight() {
3000
- const seen = /* @__PURE__ */ new Set();
3001
- for (const c of spec.cases) {
3002
- const id = caseId(c);
3003
- if (seen.has(id)) throw new Error(`defineLeaderboard(${spec.name}): duplicate case id "${id}"`);
3004
- seen.add(id);
3005
- }
3006
- },
3007
- async loadTasks(opts) {
3008
- const selected = selectCases(opts?.ids);
3009
- const limited = opts?.limit !== void 0 ? selected.slice(0, opts.limit) : selected;
3010
- return Promise.all(limited.map(async (c) => ({
3011
- id: caseId(c),
3012
- prompt: await spec.prompt(c),
3013
- metadata: { case: c }
3014
- })));
3015
- },
3016
- async judge(task, artifact) {
3017
- const [c] = selectCases([task.id]);
3018
- if (c === void 0) throw new Error(`defineLeaderboard(${spec.name}): no case "${task.id}"`);
3019
- const s = normalizeScore(spec.score(artifact, c));
3020
- return {
3021
- resolved: s.composite > 0,
3022
- score: s.composite,
3023
- detail: s.notes
3024
- };
3025
- },
3026
- async goldArtifact() {}
3027
- };
3028
- }
3029
3068
  return {
3030
3069
  run,
3031
- toBenchmarkAdapter
3070
+ toBenchmarkAdapter: () => leaderboardBenchmarkAdapter(spec)
3032
3071
  };
3033
3072
  }
3034
3073
  //#endregion
@@ -4650,8 +4689,10 @@ function dispatch() {
4650
4689
  run(worker, jobs.shift());
4651
4690
  }
4652
4691
  }
4692
+ let syncs = 0;
4653
4693
  /** fsync an open file or directory on a sync thread; keep the handle open until this settles. */
4654
4694
  function syncHandle(handle) {
4695
+ syncs += 1;
4655
4696
  if (threadsUnavailable) return handle.sync();
4656
4697
  return new Promise((resolve, reject) => {
4657
4698
  jobs.push({
@@ -4671,21 +4712,42 @@ async function syncDirectory(directory) {
4671
4712
  }
4672
4713
  }
4673
4714
  //#endregion
4674
- //#region src/runtime/private-cas.ts
4715
+ //#region src/runtime/private-cas-objects.ts
4716
+ /**
4717
+ * The local object store of a private CAS: where an object lives, how it is written, read back
4718
+ * and verified, and how a locator is checked. An object's name is published only after its bytes
4719
+ * are synced, and that order is what makes a name trustworthy, except in an `ephemeral` store, which
4720
+ * syncs nothing and is never read after its process ends: see `createPrivateCasArtifactPort`.
4721
+ * Durable copies build on these.
4722
+ */
4675
4723
  const DIGEST$1 = /^sha256:([0-9a-f]{64})$/u;
4676
- const HEX = /^[0-9a-f]{64}$/u;
4677
- const SHARD = /^[0-9a-f]{2}$/u;
4678
- const SAFE_NAMESPACE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/u;
4679
- const RECEIPT_SCHEMA = "agent-runtime.private-cas-durable-receipt.v1";
4680
- const DURABLE_ATTEMPTS = 3;
4681
- const DURABLE_STALL_MS = 12e4;
4682
- const BUFFERED_BYTES_PER_MS = 256;
4683
- const OFFLOAD_COPIES_AT_ONCE = 16;
4684
- const LIST_SHARDS_AT_ONCE = 16;
4724
+ const isMissingPath = (error) => error?.code === "ENOENT";
4725
+ const casSha256 = (bytes) => `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
4726
+ function privateCasRef(namespace, digest, byteLength) {
4727
+ return {
4728
+ locator: {
4729
+ kind: "private-cas",
4730
+ namespace,
4731
+ digest
4732
+ },
4733
+ sha256: digest,
4734
+ byteLength
4735
+ };
4736
+ }
4737
+ function hexOf(digest) {
4738
+ const match = DIGEST$1.exec(digest);
4739
+ if (!match) throw new Error("private CAS digest must be sha256:<64 lowercase hex>");
4740
+ return match[1];
4741
+ }
4742
+ function objectPath(layout, digest) {
4743
+ const hex = hexOf(digest);
4744
+ return join(layout.store, hex.slice(0, 2), hex);
4745
+ }
4685
4746
  async function realDirectory(path) {
4686
4747
  const entry = await lstat(path);
4687
4748
  if (!entry.isDirectory() || entry.isSymbolicLink()) throw new Error(`private CAS directory is not a real directory: ${path}`);
4688
4749
  }
4750
+ /** Require every component of `path` to be a real directory, creating them when `create`. */
4689
4751
  async function checkDirectories(path, create) {
4690
4752
  const parts = resolve(path).split(sep);
4691
4753
  let current = sep;
@@ -4700,16 +4762,13 @@ async function checkDirectories(path, create) {
4700
4762
  await realDirectory(current);
4701
4763
  }
4702
4764
  }
4703
- const missing = (error) => error?.code === "ENOENT";
4704
- const message = (error) => error instanceof Error ? error.message : String(error);
4705
- const sha256 = (bytes) => `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
4706
4765
  /** Read one local object, or undefined when the host no longer holds it. */
4707
4766
  async function readLocal(path) {
4708
4767
  let file;
4709
4768
  try {
4710
4769
  file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
4711
4770
  } catch (error) {
4712
- if (missing(error)) return void 0;
4771
+ if (isMissingPath(error)) return void 0;
4713
4772
  throw error;
4714
4773
  }
4715
4774
  try {
@@ -4718,219 +4777,308 @@ async function readLocal(path) {
4718
4777
  await file.close();
4719
4778
  }
4720
4779
  }
4721
- /**
4722
- * Private content-addressed storage scoped to one recorded run identity.
4723
- *
4724
- * Bytes are written to the host first. With a durable store, every object is also copied off the
4725
- * host as it is written, and `localBudgetBytes` bounds what the host keeps: an object's local copy
4726
- * is deleted only after its durable receipt exists, and reads fall back to the durable store.
4727
- *
4728
- * An object's name is published only after its bytes are synced, and that order is what makes a
4729
- * name trustworthy. A put whose digest already exists links nothing: it re-reads the existing
4730
- * object and refuses on a mismatch, and no later put replaces that file. So a deferred-sync mode
4731
- * that published names before one batch sync would, after a crash, leave a torn object under its
4732
- * valid name, and every later put of that digest would fail. Any batching must keep the order:
4733
- * write under temporary names, sync, publish the names, sync again (discovery-lab
4734
- * runner/evidence-store.mjs commits receipts this way). On drew-gtr-pro's USB SMR disk on
4735
- * 2026-10-21 these per-object fsyncs, 545 ms each on the 16 SYNC_THREADS, set a store's rate at
4736
- * about 26 files/s.
4737
- */
4738
- function createPrivateCasArtifactPort(root, namespace, options = {}) {
4739
- if (!isAbsolute(root)) throw new Error("private CAS root must be absolute");
4740
- if (!SAFE_NAMESPACE.test(namespace) || namespace === "." || namespace === "..") throw new Error("private CAS namespace must be one safe identifier");
4741
- const { durable, localBudgetBytes, durableStallMs = DURABLE_STALL_MS } = options;
4742
- if (!Number.isSafeInteger(durableStallMs) || durableStallMs <= 0) throw new Error("private CAS durableStallMs must be a positive integer");
4743
- if (localBudgetBytes !== void 0 && (durable === void 0 || !Number.isSafeInteger(localBudgetBytes) || localBudgetBytes < 0)) throw new Error("private CAS localBudgetBytes needs a durable store and a non-negative integer");
4744
- const store = join(resolve(root), "sha256");
4745
- const receipts = join(resolve(root), "durable", "sha256");
4746
- const hexOf = (digest) => {
4747
- const match = DIGEST$1.exec(digest);
4748
- if (!match) throw new Error("private CAS digest must be sha256:<64 lowercase hex>");
4749
- return match[1];
4750
- };
4751
- const destination = (digest) => {
4752
- const hex = hexOf(digest);
4753
- return join(store, hex.slice(0, 2), hex);
4754
- };
4755
- const hasReceipt = async (hex) => {
4756
- try {
4757
- return (await lstat(join(receipts, hex))).isFile();
4758
- } catch (error) {
4759
- if (missing(error)) return false;
4760
- throw error;
4761
- }
4762
- };
4763
- const writeReceipt = async (digest, byteLength) => {
4764
- await checkDirectories(receipts, true);
4765
- const hex = hexOf(digest);
4766
- const temporary = join(receipts, `.${hex}.${randomUUID()}.tmp`);
4767
- const file = await open(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 384);
4780
+ async function* readObject(path, ref, signal) {
4781
+ signal?.throwIfAborted();
4782
+ const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
4783
+ try {
4784
+ const stats = await file.stat();
4785
+ if (!stats.isFile() || stats.size !== ref.byteLength) throw new Error("private CAS object failed digest or length verification");
4786
+ yield* checkedChunks(file.createReadStream({
4787
+ autoClose: false,
4788
+ highWaterMark: 64 * 1024
4789
+ }), ref, signal);
4790
+ } finally {
4791
+ await file.close();
4792
+ }
4793
+ }
4794
+ async function* checkedChunks(chunks, ref, signal) {
4795
+ const hash = createHash("sha256");
4796
+ let byteLength = 0;
4797
+ for await (const chunk of chunks) {
4798
+ signal?.throwIfAborted();
4799
+ if (!(chunk instanceof Uint8Array)) throw new Error("private CAS emitted a non-byte chunk");
4800
+ byteLength += chunk.byteLength;
4801
+ if (byteLength > ref.byteLength) throw new Error("private CAS object failed digest or length verification");
4802
+ hash.update(chunk);
4803
+ yield chunk;
4804
+ }
4805
+ signal?.throwIfAborted();
4806
+ if (`sha256:${hash.digest("hex")}` !== ref.sha256 || byteLength !== ref.byteLength) throw new Error("private CAS object failed digest or length verification");
4807
+ }
4808
+ function verified(bytes, ref) {
4809
+ if (casSha256(bytes) !== ref.sha256 || bytes.byteLength !== ref.byteLength) throw new Error("private CAS object failed digest or length verification");
4810
+ return bytes;
4811
+ }
4812
+ function assertOwnLocator(layout, ref) {
4813
+ if (ref.locator.kind !== "private-cas" || ref.locator.namespace !== layout.namespace || ref.locator.digest !== ref.sha256) throw new Error("private CAS locator does not match its digest and namespace");
4814
+ }
4815
+ /** Stream an object from the host, falling back to the durable store when the host lacks it. */
4816
+ async function* readPrivateCasStream(layout, ref, options = {}) {
4817
+ const { signal } = options;
4818
+ const { durable } = layout;
4819
+ signal?.throwIfAborted();
4820
+ assertOwnLocator(layout, ref);
4821
+ const path = objectPath(layout, ref.sha256);
4822
+ try {
4823
+ await checkDirectories(join(layout.store, hexOf(ref.sha256).slice(0, 2)), false);
4824
+ yield* readObject(path, ref, signal);
4825
+ return;
4826
+ } catch (error) {
4827
+ if (!isMissingPath(error)) throw error;
4828
+ }
4829
+ if (!durable?.getStream) throw new Error(`private CAS object is not on this host; streaming durable reads are unavailable: ${ref.sha256}`);
4830
+ const chunks = await durable.getStream({
4831
+ namespace: layout.namespace,
4832
+ digest: ref.sha256,
4833
+ signal
4834
+ });
4835
+ if (!chunks) throw new Error(`private CAS object is neither on this host nor in ${durable.location}: ${ref.sha256}`);
4836
+ yield* checkedChunks(chunks, ref, signal);
4837
+ }
4838
+ /** Read a whole object from the host, falling back to the durable store. */
4839
+ async function readPrivateCasRef(layout, ref) {
4840
+ const { durable } = layout;
4841
+ assertOwnLocator(layout, ref);
4842
+ const path = objectPath(layout, ref.sha256);
4843
+ const shard = join(layout.store, hexOf(ref.sha256).slice(0, 2));
4844
+ let local;
4845
+ try {
4846
+ await checkDirectories(shard, false);
4847
+ local = await readLocal(path);
4848
+ } catch (error) {
4849
+ if (!isMissingPath(error)) throw error;
4850
+ }
4851
+ if (local !== void 0) return verified(local, ref);
4852
+ if (durable === void 0) throw new Error(`private CAS object is not on this host: ${ref.sha256}`);
4853
+ const stored = await durable.get({
4854
+ namespace: layout.namespace,
4855
+ digest: ref.sha256
4856
+ });
4857
+ if (stored === void 0) throw new Error(`private CAS object is neither on this host nor in ${durable.location}: ${ref.sha256}`);
4858
+ return verified(stored, ref);
4859
+ }
4860
+ /** The ref of an object this CAS holds with exactly this length, on the host or by receipt. */
4861
+ async function locatePrivateCasObject(layout, object, options = {}) {
4862
+ options.signal?.throwIfAborted();
4863
+ const digest = object.sha256;
4864
+ const hex = hexOf(digest);
4865
+ const ref = privateCasRef(layout.namespace, digest, object.byteLength);
4866
+ try {
4867
+ await checkDirectories(join(layout.store, hex.slice(0, 2)), false);
4868
+ const local = await lstat(objectPath(layout, digest));
4869
+ if (local.isFile()) return local.size === object.byteLength ? ref : void 0;
4870
+ } catch (error) {
4871
+ if (!isMissingPath(error)) throw error;
4872
+ }
4873
+ if (layout.durable === void 0) return void 0;
4874
+ const receipt = await readLocal(join(layout.receipts, hex));
4875
+ if (receipt === void 0) return void 0;
4876
+ return JSON.parse(Buffer.from(receipt).toString("utf8")).byteLength === object.byteLength ? ref : void 0;
4877
+ }
4878
+ const CREATE_EXCLUSIVE = constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW;
4879
+ /** Store a stream: stage it under a temporary name, verify the staged inode, then publish it. */
4880
+ async function putPrivateCasStream(layout, offload, input) {
4881
+ const { signal } = input;
4882
+ const { store, durable } = layout;
4883
+ signal?.throwIfAborted();
4884
+ await checkDirectories(store, true);
4885
+ const temporary = join(store, `.${randomUUID()}.tmp`);
4886
+ try {
4887
+ const file = await open(temporary, CREATE_EXCLUSIVE, 384);
4888
+ const hash = createHash("sha256");
4889
+ let byteLength = 0;
4768
4890
  try {
4769
- await file.writeFile(`${JSON.stringify({
4770
- schema: RECEIPT_SCHEMA,
4771
- location: durable.location,
4772
- namespace,
4773
- digest,
4774
- byteLength,
4775
- storedAt: (/* @__PURE__ */ new Date()).toISOString()
4776
- })}\n`);
4777
- await syncHandle(file);
4891
+ for await (const chunk of input.chunks) {
4892
+ signal?.throwIfAborted();
4893
+ if (!(chunk instanceof Uint8Array)) throw new Error("private CAS received a non-byte chunk");
4894
+ hash.update(chunk);
4895
+ byteLength += chunk.byteLength;
4896
+ if (!Number.isSafeInteger(byteLength)) throw new Error("private CAS object is too large");
4897
+ await file.writeFile(chunk);
4898
+ }
4899
+ signal?.throwIfAborted();
4900
+ if (!layout.ephemeral) await syncHandle(file);
4778
4901
  } finally {
4779
4902
  await file.close();
4780
4903
  }
4781
- await rename(temporary, join(receipts, hex));
4782
- await syncDirectory(receipts);
4783
- };
4784
- const watchAttempt = (idleMs, signal) => {
4785
- const stall = new AbortController();
4786
- let timer;
4787
- const touch = () => {
4788
- clearTimeout(timer);
4789
- timer = setTimeout(() => stall.abort(/* @__PURE__ */ new Error(`durable copy moved no bytes for ${idleMs} ms`)), idleMs);
4790
- };
4791
- touch();
4792
- const attempt = signal === void 0 ? stall.signal : AbortSignal.any([signal, stall.signal]);
4793
- return {
4794
- signal: attempt,
4795
- touch,
4796
- run: (act) => runAbortable(act, attempt, "private CAS durable copy was cancelled"),
4797
- done: () => clearTimeout(timer)
4798
- };
4799
- };
4800
- const storeDurably = async (digest, bytes, signal) => {
4801
- let failure;
4802
- for (let attempt = 1; attempt <= DURABLE_ATTEMPTS; attempt++) {
4803
- signal?.throwIfAborted();
4804
- const watch = watchAttempt(durableStallMs + Math.ceil(bytes.byteLength / BUFFERED_BYTES_PER_MS), signal);
4805
- try {
4806
- await watch.run(() => durable.put({
4807
- namespace,
4808
- digest,
4809
- bytes,
4810
- signal: watch.signal
4811
- }));
4812
- await writeReceipt(digest, bytes.byteLength);
4813
- return;
4814
- } catch (error) {
4815
- failure = error;
4816
- if (signal?.aborted) throw error;
4817
- if (attempt < DURABLE_ATTEMPTS) await new Promise((settle) => setTimeout(settle, 1e3 * 4 ** (attempt - 1)));
4818
- } finally {
4819
- watch.done();
4820
- }
4821
- }
4822
- throw failure;
4823
- };
4824
- const localObjects = async () => {
4825
- let shards;
4904
+ const sha = hash.digest("hex");
4905
+ const digest = `sha256:${sha}`;
4906
+ const ref = privateCasRef(layout.namespace, digest, byteLength);
4907
+ for await (const _chunk of readObject(temporary, ref, signal));
4908
+ const path = objectPath(layout, digest);
4909
+ const directory = join(store, sha.slice(0, 2));
4910
+ await checkDirectories(directory, true);
4911
+ signal?.throwIfAborted();
4912
+ let linked = true;
4826
4913
  try {
4827
- shards = await readdir(store);
4914
+ await link(temporary, path);
4828
4915
  } catch (error) {
4829
- if (missing(error)) return [];
4830
- throw error;
4916
+ if (error.code !== "EEXIST") throw error;
4917
+ linked = false;
4918
+ for await (const _chunk of readPrivateCasStream(layout, ref, { signal }));
4919
+ }
4920
+ if (!layout.ephemeral) await syncDirectory(directory);
4921
+ if (durable !== void 0) await offload.settlePut({
4922
+ sha,
4923
+ byteLength,
4924
+ linked
4925
+ }, signal);
4926
+ return ref;
4927
+ } finally {
4928
+ await unlink(temporary).catch((error) => {
4929
+ if (error.code !== "ENOENT") throw error;
4930
+ });
4931
+ }
4932
+ }
4933
+ /** Store bytes already in memory; the durable copy then reuses those bytes. */
4934
+ async function putPrivateCasBuffered(layout, offload, object, signal) {
4935
+ const { bytes, digest, sha } = object;
4936
+ const path = objectPath(layout, digest);
4937
+ const directory = join(layout.store, sha.slice(0, 2));
4938
+ await checkDirectories(directory, true);
4939
+ const temporary = join(directory, `.${sha}.${randomUUID()}.tmp`);
4940
+ const file = await open(temporary, CREATE_EXCLUSIVE, 384);
4941
+ try {
4942
+ await file.writeFile(bytes);
4943
+ if (!layout.ephemeral) await syncHandle(file);
4944
+ } finally {
4945
+ await file.close();
4946
+ }
4947
+ let linked = true;
4948
+ try {
4949
+ signal?.throwIfAborted();
4950
+ try {
4951
+ await link(temporary, path);
4952
+ } catch (error) {
4953
+ if (error.code !== "EEXIST") throw error;
4954
+ linked = false;
4831
4955
  }
4832
- return (await mapWithConcurrency(shards.filter((name) => SHARD.test(name)), LIST_SHARDS_AT_ONCE, async (shard) => {
4833
- const objects = [];
4834
- for (const hex of await readdir(join(store, shard))) {
4835
- if (!HEX.test(hex) || hex.slice(0, 2) !== shard) continue;
4836
- const path = join(store, shard, hex);
4837
- try {
4838
- const entry = await lstat(path);
4839
- if (entry.isFile()) objects.push({
4840
- hex,
4841
- path,
4842
- size: entry.size,
4843
- modifiedMs: entry.mtimeMs
4844
- });
4845
- } catch (error) {
4846
- if (!missing(error)) throw error;
4847
- }
4848
- }
4849
- return objects;
4850
- })).flat();
4851
- };
4852
- const streamDurably = async (digest, path, byteLength, signal) => {
4853
- const ref = {
4854
- locator: {
4855
- kind: "private-cas",
4856
- namespace,
4857
- digest
4858
- },
4859
- sha256: digest,
4860
- byteLength
4861
- };
4862
- let failure;
4863
- for (let attempt = 1; attempt <= DURABLE_ATTEMPTS; attempt++) {
4864
- signal?.throwIfAborted();
4865
- const watch = watchAttempt(durableStallMs, signal);
4866
- const chunks = readObject(path, ref, watch.signal);
4867
- const pulled = (async function* () {
4868
- for await (const chunk of chunks) {
4869
- watch.touch();
4870
- yield chunk;
4871
- }
4872
- })();
4956
+ if (!layout.ephemeral) await syncDirectory(directory);
4957
+ } finally {
4958
+ await unlink(temporary).catch(() => void 0);
4959
+ }
4960
+ const ref = privateCasRef(layout.namespace, digest, bytes.byteLength);
4961
+ await readPrivateCasRef(layout, ref);
4962
+ if (layout.durable !== void 0) await offload.settlePut({
4963
+ sha,
4964
+ byteLength: bytes.byteLength,
4965
+ linked,
4966
+ bytes
4967
+ }, signal);
4968
+ return ref;
4969
+ }
4970
+ //#endregion
4971
+ //#region src/runtime/private-cas-offload.ts
4972
+ /**
4973
+ * Durable copies of a private CAS, and the offload passes that make them: one object at a time to
4974
+ * the off-host store, with a stall bound, retries, a receipt on the host once the store holds the
4975
+ * bytes, and one copy in flight per digest. A pass copies every local object without a receipt,
4976
+ * then deletes the oldest durable local copies above the host's budget.
4977
+ */
4978
+ const HEX = /^[0-9a-f]{64}$/u;
4979
+ const SHARD = /^[0-9a-f]{2}$/u;
4980
+ const OFFLOAD_COPIES_AT_ONCE = 16;
4981
+ const LIST_SHARDS_AT_ONCE = 16;
4982
+ async function receiptCount(layout) {
4983
+ try {
4984
+ return (await readdir(layout.receipts)).filter((name) => HEX.test(name)).length;
4985
+ } catch (error) {
4986
+ if (!isMissingPath(error)) throw error;
4987
+ return 0;
4988
+ }
4989
+ }
4990
+ async function listLocalObjects(layout) {
4991
+ let shards;
4992
+ try {
4993
+ shards = await readdir(layout.store);
4994
+ } catch (error) {
4995
+ if (isMissingPath(error)) return [];
4996
+ throw error;
4997
+ }
4998
+ return (await mapWithConcurrency(shards.filter((name) => SHARD.test(name)), LIST_SHARDS_AT_ONCE, async (shard) => {
4999
+ const objects = [];
5000
+ for (const hex of await readdir(join(layout.store, shard))) {
5001
+ if (!HEX.test(hex) || hex.slice(0, 2) !== shard) continue;
5002
+ const path = join(layout.store, shard, hex);
4873
5003
  try {
4874
- await watch.run(() => durable.putStream({
4875
- namespace,
4876
- digest,
4877
- byteLength,
4878
- chunks: pulled,
4879
- signal: watch.signal
4880
- }));
4881
- await writeReceipt(digest, byteLength);
4882
- return;
5004
+ const entry = await lstat(path);
5005
+ if (entry.isFile()) objects.push({
5006
+ hex,
5007
+ path,
5008
+ size: entry.size,
5009
+ modifiedMs: entry.mtimeMs
5010
+ });
4883
5011
  } catch (error) {
4884
- failure = error;
4885
- if (signal?.aborted) throw error;
4886
- if (attempt < DURABLE_ATTEMPTS) await new Promise((settle) => setTimeout(settle, 1e3 * 4 ** (attempt - 1)));
4887
- } finally {
4888
- watch.done();
4889
- await chunks.return(void 0);
5012
+ if (!isMissingPath(error)) throw error;
4890
5013
  }
4891
5014
  }
4892
- throw failure;
4893
- };
4894
- let lastPass;
4895
- const localIndex = /* @__PURE__ */ new Map();
4896
- const undurable = /* @__PURE__ */ new Set();
4897
- const settlePut = async (sha, byteLength, linked, upload, signal) => {
4898
- if (upload !== void 0 && !await hasReceipt(sha)) await copyOnce(sha, upload, signal).catch(() => void 0);
4899
- const durableNow = await hasReceipt(sha);
4900
- if (linked) localIndex.set(sha, byteLength);
4901
- if (durableNow) undurable.delete(sha);
4902
- else undurable.add(sha);
5015
+ return objects;
5016
+ })).flat();
5017
+ }
5018
+ /**
5019
+ * The state offload passes share, with the passes that read and write it.
5020
+ *
5021
+ * A pass after the first reads only the objects this process wrote without a receipt: a full
5022
+ * pass lists every object of the store and reads its receipt, and on canary
5023
+ * test-acceptance-canary-20261019q two of them per capture (the Lab offloads before and after)
5024
+ * took 60.1-63.2 s on each native copy, on a store whose puts had already uploaded their own
5025
+ * objects. The first pass of every process is full, so objects an earlier process left on disk
5026
+ * without a receipt are always found.
5027
+ */
5028
+ var PrivateCasOffload = class {
5029
+ layout;
5030
+ lastPass;
5031
+ localIndex = /* @__PURE__ */ new Map();
5032
+ undurable = /* @__PURE__ */ new Set();
5033
+ copier;
5034
+ passes = Promise.resolve();
5035
+ waiting;
5036
+ constructor(layout) {
5037
+ this.layout = layout;
5038
+ this.copier = createDurableCopier(layout);
5039
+ }
5040
+ /** Make a just-written object durable, then run a pass unless the last one proves it needs none. */
5041
+ async settlePut(put, signal) {
5042
+ const { sha, byteLength, linked } = put;
5043
+ const { layout } = this;
5044
+ if (!await hasReceipt(layout, sha)) await this.copier.copyOnce(sha, put.bytes === void 0 ? {
5045
+ path: join(layout.store, sha.slice(0, 2), sha),
5046
+ byteLength
5047
+ } : { bytes: put.bytes }, signal).catch(() => void 0);
5048
+ const durableNow = await hasReceipt(layout, sha);
5049
+ if (linked) this.localIndex.set(sha, byteLength);
5050
+ if (durableNow) this.undurable.delete(sha);
5051
+ else this.undurable.add(sha);
4903
5052
  const added = linked ? byteLength : 0;
4904
- const known = lastPass;
4905
- if (durableNow && known !== void 0 && known.pending === 0 && (localBudgetBytes === void 0 || known.localBytes + added <= localBudgetBytes)) {
5053
+ const known = this.lastPass;
5054
+ if (durableNow && known !== void 0 && known.pending === 0 && (layout.localBudgetBytes === void 0 || known.localBytes + added <= layout.localBudgetBytes)) {
4906
5055
  known.localBytes += added;
4907
5056
  return;
4908
5057
  }
4909
- await offload(signal);
4910
- };
4911
- const uploading = /* @__PURE__ */ new Map();
4912
- const waitFor = (copy, signal) => {
4913
- const settled = copy.catch(() => void 0);
4914
- return signal === void 0 ? settled : runAbortable(() => settled, signal, "private CAS wait for a copy in flight was cancelled");
4915
- };
4916
- const copyOnce = async (sha, copy, signal) => {
4917
- for (let inflight = uploading.get(sha); inflight !== void 0; inflight = uploading.get(sha)) {
4918
- await waitFor(inflight, signal);
4919
- if (await hasReceipt(sha)) return false;
4920
- }
4921
- const current = copy();
4922
- uploading.set(sha, current);
4923
- try {
4924
- await current;
4925
- return true;
4926
- } finally {
4927
- if (uploading.get(sha) === current) uploading.delete(sha);
5058
+ await this.offload(signal);
5059
+ }
5060
+ offload(signal) {
5061
+ let pass = this.waiting;
5062
+ if (pass === void 0) {
5063
+ pass = this.passes.then(() => {
5064
+ this.waiting = void 0;
5065
+ return this.sweep();
5066
+ });
5067
+ this.waiting = pass;
5068
+ this.passes = pass.catch(() => void 0);
4928
5069
  }
4929
- };
4930
- const undurableObjects = async () => {
5070
+ const shared = pass;
5071
+ return signal === void 0 ? shared : runAbortable(() => shared, signal, "private CAS offload wait was cancelled");
5072
+ }
5073
+ indexedBytes() {
5074
+ let total = 0;
5075
+ for (const size of this.localIndex.values()) total += size;
5076
+ return total;
5077
+ }
5078
+ async undurableObjects() {
4931
5079
  const objects = [];
4932
- for (const hex of [...undurable]) {
4933
- const path = join(store, hex.slice(0, 2), hex);
5080
+ for (const hex of [...this.undurable]) {
5081
+ const path = join(this.layout.store, hex.slice(0, 2), hex);
4934
5082
  try {
4935
5083
  const entry = await lstat(path);
4936
5084
  if (entry.isFile()) objects.push({
@@ -4940,30 +5088,92 @@ function createPrivateCasArtifactPort(root, namespace, options = {}) {
4940
5088
  modifiedMs: entry.mtimeMs
4941
5089
  });
4942
5090
  } catch (error) {
4943
- if (!missing(error)) throw error;
4944
- undurable.delete(hex);
5091
+ if (!isMissingPath(error)) throw error;
5092
+ this.undurable.delete(hex);
4945
5093
  }
4946
5094
  }
4947
5095
  return objects;
4948
- };
4949
- const receiptCount = async () => {
4950
- try {
4951
- return (await readdir(receipts)).filter((name) => HEX.test(name)).length;
4952
- } catch (error) {
4953
- if (!missing(error)) throw error;
4954
- return 0;
5096
+ }
5097
+ async sweep() {
5098
+ const { durable, localBudgetBytes } = this.layout;
5099
+ const full = this.lastPass === void 0 || durable === void 0 || localBudgetBytes !== void 0 && this.indexedBytes() > localBudgetBytes;
5100
+ const objects = full ? await listLocalObjects(this.layout) : await this.undurableObjects();
5101
+ const outcomes = await this.copyObjects(objects);
5102
+ const pending = [];
5103
+ let uploaded = 0;
5104
+ const durableHex = /* @__PURE__ */ new Set();
5105
+ for (const outcome of outcomes) if (outcome.durable) {
5106
+ durableHex.add(outcome.hex);
5107
+ if (outcome.copied) uploaded++;
5108
+ } else if (outcome.error !== void 0) pending.push({
5109
+ digest: `sha256:${outcome.hex}`,
5110
+ error: outcome.error
5111
+ });
5112
+ for (const outcome of outcomes) if (outcome.durable) this.undurable.delete(outcome.hex);
5113
+ else if (durable !== void 0) this.undurable.add(outcome.hex);
5114
+ if (!full) {
5115
+ const localBytes = this.indexedBytes();
5116
+ this.lastPass = {
5117
+ localBytes,
5118
+ pending: pending.length
5119
+ };
5120
+ return {
5121
+ durable: await receiptCount(this.layout),
5122
+ uploaded,
5123
+ pending,
5124
+ evicted: 0,
5125
+ localObjects: this.localIndex.size,
5126
+ localBytes
5127
+ };
4955
5128
  }
4956
- };
4957
- const sweep = async (signal) => {
4958
- let indexedBytes = 0;
4959
- for (const size of localIndex.values()) indexedBytes += size;
4960
- const full = lastPass === void 0 || durable === void 0 || localBudgetBytes !== void 0 && indexedBytes > localBudgetBytes;
4961
- const objects = full ? await localObjects() : await undurableObjects();
5129
+ this.localIndex.clear();
5130
+ for (const object of objects) this.localIndex.set(object.hex, object.size);
5131
+ const total = objects.reduce((sum, object) => sum + object.size, 0);
5132
+ const { evicted, localBytes } = await this.evictOldest(objects, durableHex, total);
5133
+ this.lastPass = {
5134
+ localBytes,
5135
+ pending: pending.length
5136
+ };
5137
+ return {
5138
+ durable: await receiptCount(this.layout),
5139
+ uploaded,
5140
+ pending,
5141
+ evicted,
5142
+ localObjects: objects.length - evicted,
5143
+ localBytes
5144
+ };
5145
+ }
5146
+ async evictOldest(objects, durableHex, totalBytes) {
5147
+ const { localBudgetBytes } = this.layout;
5148
+ let localBytes = totalBytes;
5149
+ let evicted = 0;
5150
+ if (localBudgetBytes === void 0) return {
5151
+ evicted,
5152
+ localBytes
5153
+ };
5154
+ for (const object of [...objects].sort((a, b) => a.modifiedMs - b.modifiedMs)) {
5155
+ if (localBytes <= localBudgetBytes) break;
5156
+ if (!durableHex.has(object.hex) || !await hasReceipt(this.layout, object.hex)) continue;
5157
+ try {
5158
+ await unlink(object.path);
5159
+ } catch (error) {
5160
+ if (!isMissingPath(error)) throw error;
5161
+ }
5162
+ localBytes -= object.size;
5163
+ this.localIndex.delete(object.hex);
5164
+ evicted++;
5165
+ }
5166
+ return {
5167
+ evicted,
5168
+ localBytes
5169
+ };
5170
+ }
5171
+ async copyObjects(objects) {
5172
+ const { durable } = this.layout;
4962
5173
  let refusal;
4963
- const outcomes = await mapWithConcurrency(objects, durable === void 0 || durable.putStream && durable.getStream ? OFFLOAD_COPIES_AT_ONCE : 1, async ({ hex, path, size }) => {
4964
- const inflight = uploading.get(hex);
4965
- if (inflight !== void 0) await waitFor(inflight, signal);
4966
- if (await hasReceipt(hex)) return {
5174
+ return mapWithConcurrency(objects, durable === void 0 || durable.putStream && durable.getStream ? OFFLOAD_COPIES_AT_ONCE : 1, async ({ hex, path, size }) => {
5175
+ await this.copier.waitForCopy(hex);
5176
+ if (await hasReceipt(this.layout, hex)) return {
4967
5177
  hex,
4968
5178
  durable: true,
4969
5179
  copied: false
@@ -4982,14 +5192,17 @@ function createPrivateCasArtifactPort(root, namespace, options = {}) {
4982
5192
  if (durable.putStream && durable.getStream) return {
4983
5193
  hex,
4984
5194
  durable: true,
4985
- copied: await copyOnce(hex, () => streamDurably(digest, path, size, signal), signal)
5195
+ copied: await this.copier.copyOnce(hex, {
5196
+ path,
5197
+ byteLength: size
5198
+ })
4986
5199
  };
4987
5200
  const bytes = await readLocal(path);
4988
5201
  if (bytes === void 0) return {
4989
5202
  hex,
4990
5203
  durable: false
4991
5204
  };
4992
- if (sha256(bytes) !== digest) return {
5205
+ if (casSha256(bytes) !== digest) return {
4993
5206
  hex,
4994
5207
  durable: false,
4995
5208
  error: "local object failed digest verification; it stays on the host"
@@ -4997,199 +5210,206 @@ function createPrivateCasArtifactPort(root, namespace, options = {}) {
4997
5210
  return {
4998
5211
  hex,
4999
5212
  durable: true,
5000
- copied: await copyOnce(hex, () => storeDurably(digest, bytes, signal), signal)
5213
+ copied: await this.copier.copyOnce(hex, { bytes })
5001
5214
  };
5002
5215
  } catch (error) {
5003
- if (signal?.aborted) throw error;
5004
- refusal ??= message(error);
5216
+ refusal ??= errorMessage(error);
5005
5217
  return {
5006
5218
  hex,
5007
5219
  durable: false,
5008
- error: message(error)
5220
+ error: errorMessage(error)
5009
5221
  };
5010
5222
  }
5011
5223
  });
5012
- const pending = [];
5013
- let uploaded = 0;
5014
- const durableHex = /* @__PURE__ */ new Set();
5015
- for (const outcome of outcomes) if (outcome.durable) {
5016
- durableHex.add(outcome.hex);
5017
- if (outcome.copied) uploaded++;
5018
- } else if (outcome.error !== void 0) pending.push({
5019
- digest: `sha256:${outcome.hex}`,
5020
- error: outcome.error
5021
- });
5022
- for (const outcome of outcomes) if (outcome.durable) undurable.delete(outcome.hex);
5023
- else if (durable !== void 0) undurable.add(outcome.hex);
5024
- if (!full) {
5025
- let localBytes = 0;
5026
- for (const size of localIndex.values()) localBytes += size;
5027
- lastPass = {
5028
- localBytes,
5029
- pending: pending.length
5030
- };
5031
- return {
5032
- durable: await receiptCount(),
5033
- uploaded,
5034
- pending,
5035
- evicted: 0,
5036
- localObjects: localIndex.size,
5037
- localBytes
5038
- };
5039
- }
5040
- localIndex.clear();
5041
- for (const object of objects) localIndex.set(object.hex, object.size);
5042
- let localBytes = objects.reduce((total, object) => total + object.size, 0);
5043
- let evicted = 0;
5044
- if (localBudgetBytes !== void 0) for (const object of [...objects].sort((a, b) => a.modifiedMs - b.modifiedMs)) {
5045
- if (localBytes <= localBudgetBytes) break;
5046
- if (!durableHex.has(object.hex) || !await hasReceipt(object.hex)) continue;
5047
- try {
5048
- await unlink(object.path);
5049
- } catch (error) {
5050
- if (!missing(error)) throw error;
5051
- }
5052
- localBytes -= object.size;
5053
- localIndex.delete(object.hex);
5054
- evicted++;
5055
- }
5056
- lastPass = {
5057
- localBytes,
5058
- pending: pending.length
5059
- };
5060
- return {
5061
- durable: await receiptCount(),
5062
- uploaded,
5063
- pending,
5064
- evicted,
5065
- localObjects: objects.length - evicted,
5066
- localBytes
5067
- };
5068
- };
5069
- let passes = Promise.resolve();
5070
- let waiting;
5071
- const offload = (signal) => {
5072
- let pass = waiting;
5073
- if (pass === void 0) {
5074
- pass = passes.then(() => {
5075
- waiting = void 0;
5076
- return sweep();
5077
- });
5078
- waiting = pass;
5079
- passes = pass.catch(() => void 0);
5080
- }
5081
- const shared = pass;
5082
- return signal === void 0 ? shared : runAbortable(() => shared, signal, "private CAS offload wait was cancelled");
5083
- };
5084
- const verified = (bytes, ref) => {
5085
- if (sha256(bytes) !== ref.sha256 || bytes.byteLength !== ref.byteLength) throw new Error("private CAS object failed digest or length verification");
5086
- return bytes;
5224
+ }
5225
+ };
5226
+ const RECEIPT_SCHEMA = "agent-runtime.private-cas-durable-receipt.v1";
5227
+ const DURABLE_ATTEMPTS = 3;
5228
+ const BUFFERED_BYTES_PER_MS = 256;
5229
+ async function hasReceipt(layout, hex) {
5230
+ try {
5231
+ return (await lstat(join(layout.receipts, hex))).isFile();
5232
+ } catch (error) {
5233
+ if (isMissingPath(error)) return false;
5234
+ throw error;
5235
+ }
5236
+ }
5237
+ async function writeReceipt(layout, digest, byteLength) {
5238
+ const { receipts } = layout;
5239
+ await checkDirectories(receipts, true);
5240
+ const hex = hexOf(digest);
5241
+ const temporary = join(receipts, `.${hex}.${randomUUID()}.tmp`);
5242
+ const file = await open(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 384);
5243
+ try {
5244
+ await file.writeFile(`${JSON.stringify({
5245
+ schema: RECEIPT_SCHEMA,
5246
+ location: layout.durable.location,
5247
+ namespace: layout.namespace,
5248
+ digest,
5249
+ byteLength,
5250
+ storedAt: (/* @__PURE__ */ new Date()).toISOString()
5251
+ })}\n`);
5252
+ if (!layout.ephemeral) await syncHandle(file);
5253
+ } finally {
5254
+ await file.close();
5255
+ }
5256
+ await rename(temporary, join(receipts, hex));
5257
+ if (!layout.ephemeral) await syncDirectory(receipts);
5258
+ }
5259
+ function watchAttempt(idleMs, signal) {
5260
+ const stall = new AbortController();
5261
+ let timer;
5262
+ const touch = () => {
5263
+ clearTimeout(timer);
5264
+ timer = setTimeout(() => stall.abort(/* @__PURE__ */ new Error(`durable copy moved no bytes for ${idleMs} ms`)), idleMs);
5265
+ };
5266
+ touch();
5267
+ const attempt = signal === void 0 ? stall.signal : AbortSignal.any([signal, stall.signal]);
5268
+ return {
5269
+ signal: attempt,
5270
+ touch,
5271
+ run: (act) => runAbortable(act, attempt, "private CAS durable copy was cancelled"),
5272
+ done: () => clearTimeout(timer)
5087
5273
  };
5088
- async function* readStream(ref, options = {}) {
5089
- const { signal } = options;
5274
+ }
5275
+ async function retryCopy(signal, attemptCopy) {
5276
+ let failure;
5277
+ for (let attempt = 1; attempt <= DURABLE_ATTEMPTS; attempt++) {
5090
5278
  signal?.throwIfAborted();
5091
- if (ref.locator.kind !== "private-cas" || ref.locator.namespace !== namespace || ref.locator.digest !== ref.sha256) throw new Error("private CAS locator does not match its digest and namespace");
5092
- const path = destination(ref.sha256);
5093
5279
  try {
5094
- await checkDirectories(join(store, hexOf(ref.sha256).slice(0, 2)), false);
5095
- yield* readObject(path, ref, signal);
5280
+ await attemptCopy();
5096
5281
  return;
5097
5282
  } catch (error) {
5098
- if (!missing(error)) throw error;
5283
+ failure = error;
5284
+ if (signal?.aborted) throw error;
5285
+ if (attempt < DURABLE_ATTEMPTS) await new Promise((settle) => setTimeout(settle, 1e3 * 4 ** (attempt - 1)));
5099
5286
  }
5100
- if (!durable?.getStream) throw new Error(`private CAS object is not on this host; streaming durable reads are unavailable: ${ref.sha256}`);
5101
- const chunks = await durable.getStream({
5102
- namespace,
5103
- digest: ref.sha256,
5104
- signal
5105
- });
5106
- if (!chunks) throw new Error(`private CAS object is neither on this host nor in ${durable.location}: ${ref.sha256}`);
5107
- yield* checkedChunks(chunks, ref, signal);
5108
5287
  }
5109
- async function* readObject(path, ref, signal) {
5110
- signal?.throwIfAborted();
5111
- const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
5288
+ throw failure;
5289
+ }
5290
+ function storeDurably(layout, digest, bytes, signal) {
5291
+ return retryCopy(signal, async () => {
5292
+ const watch = watchAttempt(layout.durableStallMs + Math.ceil(bytes.byteLength / BUFFERED_BYTES_PER_MS), signal);
5112
5293
  try {
5113
- const stats = await file.stat();
5114
- if (!stats.isFile() || stats.size !== ref.byteLength) throw new Error("private CAS object failed digest or length verification");
5115
- yield* checkedChunks(file.createReadStream({
5116
- autoClose: false,
5117
- highWaterMark: 64 * 1024
5118
- }), ref, signal);
5294
+ await watch.run(() => layout.durable.put({
5295
+ namespace: layout.namespace,
5296
+ digest,
5297
+ bytes,
5298
+ signal: watch.signal
5299
+ }));
5300
+ await writeReceipt(layout, digest, bytes.byteLength);
5119
5301
  } finally {
5120
- await file.close();
5302
+ watch.done();
5121
5303
  }
5122
- }
5123
- async function* checkedChunks(chunks, ref, signal) {
5124
- const hash = createHash("sha256");
5125
- let byteLength = 0;
5126
- for await (const chunk of chunks) {
5127
- signal?.throwIfAborted();
5128
- if (!(chunk instanceof Uint8Array)) throw new Error("private CAS emitted a non-byte chunk");
5129
- byteLength += chunk.byteLength;
5130
- if (byteLength > ref.byteLength) throw new Error("private CAS object failed digest or length verification");
5131
- hash.update(chunk);
5132
- yield chunk;
5133
- }
5134
- signal?.throwIfAborted();
5135
- if (`sha256:${hash.digest("hex")}` !== ref.sha256 || byteLength !== ref.byteLength) throw new Error("private CAS object failed digest or length verification");
5136
- }
5137
- async function putStream(input) {
5138
- const { signal } = input;
5139
- signal?.throwIfAborted();
5140
- await checkDirectories(store, true);
5141
- const temporary = join(store, `.${randomUUID()}.tmp`);
5304
+ });
5305
+ }
5306
+ function streamDurably(layout, digest, path, byteLength, signal) {
5307
+ const ref = privateCasRef(layout.namespace, digest, byteLength);
5308
+ return retryCopy(signal, async () => {
5309
+ const watch = watchAttempt(layout.durableStallMs, signal);
5310
+ const chunks = readObject(path, ref, watch.signal);
5311
+ const pulled = (async function* () {
5312
+ for await (const chunk of chunks) {
5313
+ watch.touch();
5314
+ yield chunk;
5315
+ }
5316
+ })();
5142
5317
  try {
5143
- const file = await open(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 384);
5144
- const hash = createHash("sha256");
5145
- let byteLength = 0;
5146
- try {
5147
- for await (const chunk of input.chunks) {
5148
- signal?.throwIfAborted();
5149
- if (!(chunk instanceof Uint8Array)) throw new Error("private CAS received a non-byte chunk");
5150
- hash.update(chunk);
5151
- byteLength += chunk.byteLength;
5152
- if (!Number.isSafeInteger(byteLength)) throw new Error("private CAS object is too large");
5153
- await file.writeFile(chunk);
5154
- }
5155
- signal?.throwIfAborted();
5156
- await syncHandle(file);
5157
- } finally {
5158
- await file.close();
5318
+ await watch.run(() => layout.durable.putStream({
5319
+ namespace: layout.namespace,
5320
+ digest,
5321
+ byteLength,
5322
+ chunks: pulled,
5323
+ signal: watch.signal
5324
+ }));
5325
+ await writeReceipt(layout, digest, byteLength);
5326
+ } finally {
5327
+ watch.done();
5328
+ await chunks.return(void 0);
5329
+ }
5330
+ });
5331
+ }
5332
+ /**
5333
+ * The one copy of each digest to the durable store in flight, from a put or a pass. A put or pass
5334
+ * that finds its digest in flight waits for that copy, then reads the receipt. Copying it again
5335
+ * doubles the upload and, for a buffered store, the archive in memory. Reporting it pending
5336
+ * failed captures: a capture refuses on any pending object, so two captures sharing one store
5337
+ * refused each other (discovery-lab provider-retention, agent-runtime 0.325.6, 2026-10-18).
5338
+ * A copy never waits for a pass, so a pass may wait for a copy.
5339
+ */
5340
+ function createDurableCopier(layout) {
5341
+ const uploading = /* @__PURE__ */ new Map();
5342
+ const waitFor = (copy, signal) => {
5343
+ const settled = copy.catch(() => void 0);
5344
+ return signal === void 0 ? settled : runAbortable(() => settled, signal, "private CAS wait for a copy in flight was cancelled");
5345
+ };
5346
+ return {
5347
+ async waitForCopy(hex, signal) {
5348
+ const inflight = uploading.get(hex);
5349
+ if (inflight !== void 0) await waitFor(inflight, signal);
5350
+ },
5351
+ async copyOnce(hex, source, signal) {
5352
+ for (let inflight = uploading.get(hex); inflight !== void 0; inflight = uploading.get(hex)) {
5353
+ await waitFor(inflight, signal);
5354
+ if (await hasReceipt(layout, hex)) return false;
5159
5355
  }
5160
- const sha = hash.digest("hex");
5161
- const digest = `sha256:${sha}`;
5162
- const ref = {
5163
- locator: {
5164
- kind: "private-cas",
5165
- namespace,
5166
- digest
5167
- },
5168
- sha256: digest,
5169
- byteLength
5170
- };
5171
- for await (const _chunk of readObject(temporary, ref, signal));
5172
- const path = destination(digest);
5173
- const directory = join(store, sha.slice(0, 2));
5174
- await checkDirectories(directory, true);
5175
- signal?.throwIfAborted();
5176
- let linked = true;
5356
+ const digest = `sha256:${hex}`;
5357
+ const current = "bytes" in source ? storeDurably(layout, digest, source.bytes, signal) : streamDurably(layout, digest, source.path, source.byteLength, signal);
5358
+ uploading.set(hex, current);
5177
5359
  try {
5178
- await link(temporary, path);
5179
- } catch (error) {
5180
- if (error.code !== "EEXIST") throw error;
5181
- linked = false;
5182
- for await (const _chunk of readStream(ref, { signal }));
5360
+ await current;
5361
+ return true;
5362
+ } finally {
5363
+ if (uploading.get(hex) === current) uploading.delete(hex);
5183
5364
  }
5184
- await syncDirectory(directory);
5185
- if (durable !== void 0) await settlePut(sha, byteLength, linked, () => streamDurably(digest, path, byteLength, signal), signal);
5186
- return ref;
5187
- } finally {
5188
- await unlink(temporary).catch((error) => {
5189
- if (error.code !== "ENOENT") throw error;
5190
- });
5191
5365
  }
5192
- }
5366
+ };
5367
+ }
5368
+ //#endregion
5369
+ //#region src/runtime/private-cas.ts
5370
+ const SAFE_NAMESPACE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/u;
5371
+ const DURABLE_STALL_MS = 12e4;
5372
+ /**
5373
+ * Private content-addressed storage scoped to one recorded run identity.
5374
+ *
5375
+ * Bytes are written to the host first. With a durable store, every object is also copied off the
5376
+ * host as it is written, and `localBudgetBytes` bounds what the host keeps: an object's local copy
5377
+ * is deleted only after its durable receipt exists, and reads fall back to the durable store.
5378
+ *
5379
+ * An object's name is published only after its bytes are synced, and that order is what makes a
5380
+ * name trustworthy. A put whose digest already exists links nothing: it re-reads the existing
5381
+ * object and refuses on a mismatch, and no later put replaces that file. So a deferred-sync mode
5382
+ * that published names before one batch sync would, after a crash, leave a torn object under its
5383
+ * valid name, and every later put of that digest would fail. Any batching must keep the order:
5384
+ * write under temporary names, sync, publish the names, sync again (discovery-lab
5385
+ * runner/evidence-store.mjs commits receipts this way). On drew-gtr-pro's USB SMR disk on
5386
+ * 2026-10-21 these per-object fsyncs, 545 ms each on the 16 SYNC_THREADS, set a store's rate at
5387
+ * about 26 files/s.
5388
+ *
5389
+ * The one exception is an `ephemeral` store, which syncs nothing: its root is discarded with its
5390
+ * process, so no name in it is ever read after a crash, and nothing durable may be derived from it
5391
+ * but by a caller that copies and syncs what it keeps.
5392
+ */
5393
+ function createPrivateCasArtifactPort(root, namespace, options = {}) {
5394
+ if (!isAbsolute(root)) throw new Error("private CAS root must be absolute");
5395
+ if (!SAFE_NAMESPACE.test(namespace) || namespace === "." || namespace === "..") throw new Error("private CAS namespace must be one safe identifier");
5396
+ const { durable, localBudgetBytes, durableStallMs = DURABLE_STALL_MS, ephemeral = false } = options;
5397
+ if (!Number.isSafeInteger(durableStallMs) || durableStallMs <= 0) throw new Error("private CAS durableStallMs must be a positive integer");
5398
+ if (typeof ephemeral !== "boolean") throw new Error("private CAS ephemeral must be a boolean");
5399
+ if (ephemeral && durable === void 0) throw new Error("private CAS ephemeral needs a durable store");
5400
+ if (localBudgetBytes !== void 0 && (durable === void 0 || !Number.isSafeInteger(localBudgetBytes) || localBudgetBytes < 0)) throw new Error("private CAS localBudgetBytes needs a durable store and a non-negative integer");
5401
+ const layout = {
5402
+ namespace,
5403
+ store: join(resolve(root), "sha256"),
5404
+ receipts: join(resolve(root), "durable", "sha256"),
5405
+ durable,
5406
+ localBudgetBytes,
5407
+ durableStallMs,
5408
+ ephemeral
5409
+ };
5410
+ const offload = new PrivateCasOffload(layout);
5411
+ const readStream = (ref, options) => readPrivateCasStream(layout, ref, options);
5412
+ const putStream = (input) => putPrivateCasStream(layout, offload, input);
5193
5413
  const port = {
5194
5414
  ...durable === void 0 || durable.putStream && durable.getStream ? {
5195
5415
  putStream,
@@ -5197,97 +5417,17 @@ function createPrivateCasArtifactPort(root, namespace, options = {}) {
5197
5417
  } : {},
5198
5418
  async put({ bytes, signal }) {
5199
5419
  signal?.throwIfAborted();
5200
- const digest = sha256(bytes);
5201
- return putBuffered(bytes, digest, hexOf(digest), signal);
5202
- },
5203
- async read(ref) {
5204
- return readRef(ref);
5205
- },
5206
- async locate(object, options = {}) {
5207
- options.signal?.throwIfAborted();
5208
- const digest = object.sha256;
5209
- const hex = hexOf(digest);
5210
- const ref = {
5211
- locator: {
5212
- kind: "private-cas",
5213
- namespace,
5214
- digest
5215
- },
5216
- sha256: digest,
5217
- byteLength: object.byteLength
5218
- };
5219
- try {
5220
- await checkDirectories(join(store, hex.slice(0, 2)), false);
5221
- const local = await lstat(destination(digest));
5222
- if (local.isFile()) return local.size === object.byteLength ? ref : void 0;
5223
- } catch (error) {
5224
- if (!missing(error)) throw error;
5225
- }
5226
- if (durable === void 0) return void 0;
5227
- const receipt = await readLocal(join(receipts, hex));
5228
- if (receipt === void 0) return void 0;
5229
- return JSON.parse(Buffer.from(receipt).toString("utf8")).byteLength === object.byteLength ? ref : void 0;
5420
+ const digest = casSha256(bytes);
5421
+ return putPrivateCasBuffered(layout, offload, {
5422
+ bytes,
5423
+ digest,
5424
+ sha: hexOf(digest)
5425
+ }, signal);
5230
5426
  },
5231
- offload
5427
+ read: (ref) => readPrivateCasRef(layout, ref),
5428
+ locate: (object, options) => locatePrivateCasObject(layout, object, options),
5429
+ offload: (signal) => offload.offload(signal)
5232
5430
  };
5233
- async function putBuffered(bytes, digest, sha, signal) {
5234
- const path = destination(digest);
5235
- const directory = join(store, sha.slice(0, 2));
5236
- await checkDirectories(directory, true);
5237
- const temporary = join(directory, `.${sha}.${randomUUID()}.tmp`);
5238
- const file = await open(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 384);
5239
- try {
5240
- await file.writeFile(bytes);
5241
- await syncHandle(file);
5242
- } finally {
5243
- await file.close();
5244
- }
5245
- let linked = true;
5246
- try {
5247
- signal?.throwIfAborted();
5248
- try {
5249
- await link(temporary, path);
5250
- } catch (error) {
5251
- if (error.code !== "EEXIST") throw error;
5252
- linked = false;
5253
- }
5254
- await syncDirectory(directory);
5255
- } finally {
5256
- await unlink(temporary).catch(() => void 0);
5257
- }
5258
- const ref = {
5259
- locator: {
5260
- kind: "private-cas",
5261
- namespace,
5262
- digest
5263
- },
5264
- sha256: digest,
5265
- byteLength: bytes.byteLength
5266
- };
5267
- await readRef(ref);
5268
- if (durable !== void 0) await settlePut(sha, bytes.byteLength, linked, () => storeDurably(digest, bytes, signal), signal);
5269
- return ref;
5270
- }
5271
- async function readRef(ref) {
5272
- if (ref.locator.kind !== "private-cas" || ref.locator.namespace !== namespace || ref.locator.digest !== ref.sha256) throw new Error("private CAS locator does not match its digest and namespace");
5273
- const path = destination(ref.sha256);
5274
- const shard = join(store, hexOf(ref.sha256).slice(0, 2));
5275
- let local;
5276
- try {
5277
- await checkDirectories(shard, false);
5278
- local = await readLocal(path);
5279
- } catch (error) {
5280
- if (!missing(error)) throw error;
5281
- }
5282
- if (local !== void 0) return verified(local, ref);
5283
- if (durable === void 0) throw new Error(`private CAS object is not on this host: ${ref.sha256}`);
5284
- const stored = await durable.get({
5285
- namespace,
5286
- digest: ref.sha256
5287
- });
5288
- if (stored === void 0) throw new Error(`private CAS object is neither on this host nor in ${durable.location}: ${ref.sha256}`);
5289
- return verified(stored, ref);
5290
- }
5291
5431
  if (durable === void 0) markPutStreamVerified(putStream, readStream);
5292
5432
  return port;
5293
5433
  }
@@ -6040,30 +6180,169 @@ function hashText(value) {
6040
6180
  return (hash >>> 0).toString(16).padStart(8, "0");
6041
6181
  }
6042
6182
  //#endregion
6043
- //#region src/runtime/strategy-evolution.ts
6183
+ //#region src/runtime/strategy-evolution-cells.ts
6044
6184
  /**
6045
- * runStrategyEvolution: strategy search on Eval's search kernel (`runSearch`).
6046
- *
6047
- * Every node is a strategy: the caller's root, or a module an author model wrote from the
6048
- * train results of the parent the policy chose. The default policy is `beam({ width: 2 })`
6049
- * and the default allocator `asha()`, so a strategy is screened on a few selection tasks and
6050
- * earns more tasks only by ranking well. Each cell is one `runAgentic` run of one strategy on
6051
- * one task, scored by the environment's own check.
6052
- *
6053
- * Measurement follows the kernel's splits. The author reads train results only; the policy
6054
- * and allocator rank on the private selection split; the claim runs the root and at most 3
6055
- * finalists together on the sealed test split, once, with a power check and a Bonferroni
6056
- * decision. The report is a projection of the ledger, and the ledger is the only checkpoint:
6057
- * calling again with the same inputs continues an interrupted search and returns a finished
6058
- * one without running anything.
6059
- *
6060
- * @experimental
6185
+ * Cells run in this process on one dedicated lane of Runtime's search executor, which
6186
+ * records each finished attempt under its run id (a restarted search adopts it instead of
6187
+ * running it again), meters it through the search's cost ledger, and traces it.
6061
6188
  */
6062
- const STRATEGY_EVOLUTION_SOURCE = {
6063
- uri: "npm:@tangle-network/agent-runtime#runStrategyEvolution",
6064
- revision: canonicalCandidateDigest$1({
6065
- name: "agent-runtime.strategy-evolution.2026-09",
6066
- node: "the root strategy by name under the caller executionRef, or an authored module content-addressed by the sha256 of its source",
6189
+ async function openStrategyCellExecutor(cfg, plan, strategyOf) {
6190
+ const storage = fsCampaignStorage();
6191
+ const costLedger = createRunCostLedger({
6192
+ storage,
6193
+ runDir: plan.searchDir
6194
+ });
6195
+ const lanes = [dedicatedLane({
6196
+ name: "in-process",
6197
+ capacity: plan.concurrency,
6198
+ cellUsd: plan.cellUsd
6199
+ })];
6200
+ await reconcileInterruptedSearchCalls(costLedger, plan.searchId, lanes);
6201
+ return searchExecutor({
6202
+ lanes,
6203
+ profileOf: () => cfg.worker.workerProfile,
6204
+ costLedger,
6205
+ identity: plan.execution,
6206
+ storage,
6207
+ dir: plan.searchDir,
6208
+ ...cfg.workerSlots ? { workerSlots: cfg.workerSlots } : {},
6209
+ runAttempt: ({ work, lane, costLedger: cellLedger }) => runStrategyCell(cfg, plan, {
6210
+ work,
6211
+ lane,
6212
+ costLedger: cellLedger
6213
+ }, strategyOf)
6214
+ });
6215
+ }
6216
+ async function runStrategyCell(cfg, plan, attempt, strategyOf) {
6217
+ const { work, lane, costLedger: cellLedger } = attempt;
6218
+ const { workerModel } = plan;
6219
+ if (work.artifact.kind === "authored" && work.artifact.refusal !== null) throw new Error(`evolution: refused node ${work.nodeId} was given a cell`);
6220
+ const strategy = await strategyOf(work.artifact);
6221
+ const task = plan.taskById.get(work.taskId);
6222
+ if (!task) throw new Error(`evolution: cell ${work.cellId} names unknown task ${work.taskId}`);
6223
+ const faults = [];
6224
+ const environment = faultRecording(cfg.environment, faults);
6225
+ const paid = await cellLedger.runPaidCall({
6226
+ channel: "agent",
6227
+ phase: `search.${work.stage}`,
6228
+ actor: `strategy:${strategy.name}`,
6229
+ model: workerModel,
6230
+ signal: work.signal,
6231
+ execute: () => runAgentic({
6232
+ ...cfg.worker,
6233
+ surface: environment,
6234
+ task,
6235
+ strategy,
6236
+ budget: plan.budget,
6237
+ ...cfg.hooks ? { hooks: cfg.hooks } : {}
6238
+ }),
6239
+ receipt: (run) => ({
6240
+ model: workerModel,
6241
+ inputTokens: run.tokens.input,
6242
+ outputTokens: run.tokens.output,
6243
+ ...run.usdKnown ? { actualCostUsd: run.usd } : { costUnknown: true },
6244
+ ...run.tokensKnown ? {} : { usageUnknown: true }
6245
+ }),
6246
+ receiptFromError: () => ({
6247
+ model: workerModel,
6248
+ inputTokens: 0,
6249
+ outputTokens: 0,
6250
+ costUnknown: true,
6251
+ usageUnknown: true
6252
+ })
6253
+ });
6254
+ const settled = {
6255
+ identity: plan.execution,
6256
+ placement: {
6257
+ lane: lane.name,
6258
+ boxId: null
6259
+ },
6260
+ accounting: unknownAccounting("replaced by the attempt receipts"),
6261
+ ...paid.succeeded ? { wallMs: paid.value.ms } : {}
6262
+ };
6263
+ if (faults.length > 0) return {
6264
+ ...settled,
6265
+ ...environmentFault(faults)
6266
+ };
6267
+ if (!paid.succeeded) return {
6268
+ ...settled,
6269
+ outcome: {
6270
+ status: "failed",
6271
+ score: 0,
6272
+ metrics: {},
6273
+ failure: {
6274
+ code: "strategy-threw",
6275
+ message: shareText(paid.error)
6276
+ }
6277
+ }
6278
+ };
6279
+ const run = paid.value;
6280
+ return {
6281
+ ...settled,
6282
+ outcome: {
6283
+ status: "passed",
6284
+ score: run.score,
6285
+ metrics: {
6286
+ resolved: run.resolved ? 1 : 0,
6287
+ shots: run.shots
6288
+ }
6289
+ }
6290
+ };
6291
+ }
6292
+ /** The environment as one attempt sees it, recording each throw from `open`, `tools`,
6293
+ * `score` or `close`: those are the environment's faults. A `call` that throws is a tool
6294
+ * error the agent's loop handles. */
6295
+ function faultRecording(environment, faults) {
6296
+ const recorded = (name, method) => async (...args) => {
6297
+ try {
6298
+ return await method(...args);
6299
+ } catch (error) {
6300
+ faults.push(`${name}: ${shareText(error)}`);
6301
+ throw error;
6302
+ }
6303
+ };
6304
+ return {
6305
+ name: environment.name,
6306
+ open: recorded("open", (task) => environment.open(task)),
6307
+ tools: recorded("tools", (task, handle) => environment.tools(task, handle)),
6308
+ call: (handle, name, args) => environment.call(handle, name, args),
6309
+ score: recorded("score", (task, handle) => environment.score(task, handle)),
6310
+ close: recorded("close", (handle) => environment.close(handle))
6311
+ };
6312
+ }
6313
+ function environmentFault(faults) {
6314
+ return { outcome: {
6315
+ status: "errored",
6316
+ metrics: {},
6317
+ error: {
6318
+ code: "environment-fault",
6319
+ message: faults[0],
6320
+ retryable: true
6321
+ }
6322
+ } };
6323
+ }
6324
+ function unknownAccounting(reason) {
6325
+ return {
6326
+ tokens: {
6327
+ status: "unknown",
6328
+ reason
6329
+ },
6330
+ cost: {
6331
+ status: "unknown",
6332
+ knownLowerBoundUsd: 0,
6333
+ reason
6334
+ }
6335
+ };
6336
+ }
6337
+ /** Free text as the ledger stores it: redacted with the share profile and bounded. */
6338
+ function shareText(error) {
6339
+ return redact(error instanceof Error ? error.message : String(error), { profile: "share" }).value.slice(0, 300);
6340
+ }
6341
+ const STRATEGY_EVOLUTION_SOURCE = {
6342
+ uri: "npm:@tangle-network/agent-runtime#runStrategyEvolution",
6343
+ revision: canonicalCandidateDigest$1({
6344
+ name: "agent-runtime.strategy-evolution.2026-09",
6345
+ node: "the root strategy by name under the caller executionRef, or an authored module content-addressed by the sha256 of its source",
6067
6346
  edge: "a text diff from the parent module source to the child; unknown from the root, which has no source here",
6068
6347
  admission: "a module is refused when the reply carries none, it breaks the author contract, or it does not load a default Strategy",
6069
6348
  cell: "one runAgentic run on one task, metered as one paid call on the search cost ledger through the Runtime search executor; an environment fault during it is errored and retried, a thrown strategy is failed at score 0, anything else passed at its harness-verified score",
@@ -6071,9 +6350,8 @@ const STRATEGY_EVOLUTION_SOURCE = {
6071
6350
  ship: "the claim shipped, re-derives from the ledger, cost accounting is complete, and the shipped finalist test lower bound exceeds 0"
6072
6351
  })
6073
6352
  };
6074
- const NO_MODULE = "the author reply carried no fenced ts module";
6075
- /** Evolve a strategy on the search kernel and claim once on the sealed test split. */
6076
- async function runStrategyEvolution(cfg) {
6353
+ /** Check every option and derive the search's identity; throws `ConfigError` on a bad one. */
6354
+ function planStrategyEvolution(cfg) {
6077
6355
  const root = cfg.root ?? refine;
6078
6356
  const budget = positiveInteger("budget", cfg.budget ?? 3);
6079
6357
  const concurrency = positiveInteger("concurrency", cfg.concurrency ?? 3);
@@ -6090,36 +6368,14 @@ async function runStrategyEvolution(cfg) {
6090
6368
  const claim = defineEvaluationClaim(cfg.claim);
6091
6369
  if (claim.minimumEffect === void 0) throw new ConfigError("evolution: the claim needs minimumEffect for its power check");
6092
6370
  const taskIds = /* @__PURE__ */ new Set();
6093
- const splitTasks = (label, tasks) => {
6094
- if (!Array.isArray(tasks) || tasks.length === 0) throw new ConfigError(`evolution: ${label} needs at least one task`);
6095
- for (const task of tasks) {
6096
- if (typeof task.id !== "string" || !task.id.trim() || taskIds.has(task.id)) throw new ConfigError(`evolution: task IDs must be non-empty and unique across splits`);
6097
- taskIds.add(task.id);
6098
- }
6099
- return immutableCandidateValue(tasks);
6100
- };
6101
- const train = splitTasks("train", cfg.train);
6102
- const selection = splitTasks("selection", cfg.selection);
6103
- const test = splitTasks("test", cfg.test);
6104
- const taskById = new Map([
6105
- ...train,
6106
- ...selection,
6107
- ...test
6108
- ].map((task) => [task.id, task]));
6109
- const searchTasks = (tasks) => tasks.map((task) => ({
6110
- taskId: task.id,
6111
- unitId: summarizeEvaluationUnits(claim, [task]).units[0].id,
6112
- source: {
6113
- uri: `task://${task.id}`,
6114
- revision: canonicalCandidateDigest$1(task)
6115
- }
6116
- }));
6371
+ const train = splitTasks(taskIds, "train", cfg.train);
6372
+ const selection = splitTasks(taskIds, "selection", cfg.selection);
6373
+ const test = splitTasks(taskIds, "test", cfg.test);
6117
6374
  const splits = {
6118
- train: searchTasks(train),
6119
- selection: searchTasks(selection),
6120
- test: searchTasks(test)
6375
+ train: searchTasks(claim, train),
6376
+ selection: searchTasks(claim, selection),
6377
+ test: searchTasks(claim, test)
6121
6378
  };
6122
- const developmentUnits = new Set([...splits.train, ...splits.selection].map((task) => task.unitId));
6123
6379
  const workerProfile = cfg.worker.workerProfile;
6124
6380
  const analystProfile = cfg.worker.analystProfile ?? workerProfile;
6125
6381
  const workerModel = concreteModelId(workerProfile.model?.default);
@@ -6150,11 +6406,6 @@ async function runStrategyEvolution(cfg) {
6150
6406
  uri: `environment:${cfg.environment.name}`,
6151
6407
  revision: cfg.executionRef
6152
6408
  };
6153
- const execution = {
6154
- model: searchModelIdentity(workerModel, workerProfile.model?.provider ?? "unknown"),
6155
- agent: workerSource,
6156
- benchmark: environmentSource
6157
- };
6158
6409
  const searchId = `evolution-${canonicalCandidateDigest$1({
6159
6410
  process: STRATEGY_EVOLUTION_SOURCE,
6160
6411
  executionRef: cfg.executionRef,
@@ -6175,12 +6426,135 @@ async function runStrategyEvolution(cfg) {
6175
6426
  seed
6176
6427
  }).slice(7, 31)}`;
6177
6428
  const searchDir = `${cfg.outDir}/${searchId}`;
6178
- const modulesDir = `${searchDir}/strategies`;
6179
- const ledgerPath = `${searchDir}/ledger.jsonl`;
6180
- mkdirSync(searchDir, { recursive: true });
6181
- const recorder = await SearchRecorder.open({ ledger: openSearchLedger({
6182
- path: ledgerPath,
6183
- searchId
6429
+ return {
6430
+ root,
6431
+ budget,
6432
+ concurrency,
6433
+ maxExpansions,
6434
+ maxAttempts,
6435
+ seed,
6436
+ cellUsd,
6437
+ maxUsd,
6438
+ policy,
6439
+ allocation,
6440
+ claim,
6441
+ train,
6442
+ taskById: new Map([
6443
+ ...train,
6444
+ ...selection,
6445
+ ...test
6446
+ ].map((task) => [task.id, task])),
6447
+ splits,
6448
+ developmentUnits: new Set([...splits.train, ...splits.selection].map((task) => task.unitId)),
6449
+ workerModel,
6450
+ authorModel,
6451
+ authorSource,
6452
+ environmentSource,
6453
+ execution: {
6454
+ model: searchModelIdentity(workerModel, workerProfile.model?.provider ?? "unknown"),
6455
+ agent: workerSource,
6456
+ benchmark: environmentSource
6457
+ },
6458
+ searchId,
6459
+ searchDir,
6460
+ modulesDir: `${searchDir}/strategies`,
6461
+ ledgerPath: `${searchDir}/ledger.jsonl`
6462
+ };
6463
+ }
6464
+ function splitTasks(taskIds, label, tasks) {
6465
+ if (!Array.isArray(tasks) || tasks.length === 0) throw new ConfigError(`evolution: ${label} needs at least one task`);
6466
+ for (const task of tasks) {
6467
+ if (typeof task.id !== "string" || !task.id.trim() || taskIds.has(task.id)) throw new ConfigError(`evolution: task IDs must be non-empty and unique across splits`);
6468
+ taskIds.add(task.id);
6469
+ }
6470
+ return immutableCandidateValue(tasks);
6471
+ }
6472
+ function searchTasks(claim, tasks) {
6473
+ return tasks.map((task) => ({
6474
+ taskId: task.id,
6475
+ unitId: summarizeEvaluationUnits(claim, [task]).units[0].id,
6476
+ source: {
6477
+ uri: `task://${task.id}`,
6478
+ revision: canonicalCandidateDigest$1(task)
6479
+ }
6480
+ }));
6481
+ }
6482
+ function positiveInteger(name, value) {
6483
+ if (!Number.isSafeInteger(value) || value < 1) throw new ConfigError(`evolution: ${name} must be a positive integer`);
6484
+ return value;
6485
+ }
6486
+ function nonNegativeInteger(name, value) {
6487
+ if (!Number.isSafeInteger(value) || value < 0) throw new ConfigError(`evolution: ${name} must be a non-negative integer`);
6488
+ return value;
6489
+ }
6490
+ function dollars(name, value) {
6491
+ if (value === void 0) return null;
6492
+ if (!Number.isFinite(value) || value < 0) throw new ConfigError(`evolution: ${name} must be a finite non-negative number`);
6493
+ return value;
6494
+ }
6495
+ //#endregion
6496
+ //#region src/runtime/strategy-evolution.ts
6497
+ /**
6498
+ * runStrategyEvolution: strategy search on Eval's search kernel (`runSearch`).
6499
+ *
6500
+ * Every node is a strategy: the caller's root, or a module an author model wrote from the
6501
+ * train results of the parent the policy chose. The default policy is `beam({ width: 2 })`
6502
+ * and the default allocator `asha()`, so a strategy is screened on a few selection tasks and
6503
+ * earns more tasks only by ranking well. Each cell is one `runAgentic` run of one strategy on
6504
+ * one task, scored by the environment's own check.
6505
+ *
6506
+ * Measurement follows the kernel's splits. The author reads train results only; the policy
6507
+ * and allocator rank on the private selection split; the claim runs the root and at most 3
6508
+ * finalists together on the sealed test split, once, with a power check and a Bonferroni
6509
+ * decision. The report is a projection of the ledger, and the ledger is the only checkpoint:
6510
+ * calling again with the same inputs continues an interrupted search and returns a finished
6511
+ * one without running anything.
6512
+ *
6513
+ * @experimental
6514
+ */
6515
+ const NO_MODULE = "the author reply carried no fenced ts module";
6516
+ /** Evolve a strategy on the search kernel and claim once on the sealed test split. */
6517
+ async function runStrategyEvolution(cfg) {
6518
+ const plan = planStrategyEvolution(cfg);
6519
+ mkdirSync(plan.searchDir, { recursive: true });
6520
+ const recorder = await openEvolutionRecorder(cfg, plan);
6521
+ if (!(await recorder.state()).closed) await preflightModels({
6522
+ worker: cfg.worker,
6523
+ modelPreflight: cfg.modelPreflight,
6524
+ modelPreflightTimeoutMs: cfg.modelPreflightTimeoutMs
6525
+ });
6526
+ const rootNode = {
6527
+ kind: "root",
6528
+ name: plan.root.name
6529
+ };
6530
+ const codec = strategyNodeCodec(plan.root);
6531
+ const executor = await openStrategyCellExecutor(cfg, plan, strategyLoader(plan.root, plan.modulesDir));
6532
+ const proposer = strategyAuthorProposer(cfg, plan, recorder, codec);
6533
+ const result = await runSearch({
6534
+ recorder,
6535
+ root: rootNode,
6536
+ codec,
6537
+ policy: plan.policy,
6538
+ allocation: plan.allocation,
6539
+ proposer,
6540
+ executor,
6541
+ admit: (node) => node.kind === "authored" ? node.refusal : null,
6542
+ maxExpansions: plan.maxExpansions,
6543
+ maxAttempts: plan.maxAttempts,
6544
+ ...cfg.signal ? { signal: cfg.signal } : {}
6545
+ });
6546
+ if (!result.claim || !result.claimVerification) throw new Error(`evolution: search ${plan.searchId} closed without a claim`);
6547
+ return evolutionReport(plan, recorder, codec, {
6548
+ ...result,
6549
+ claim: result.claim,
6550
+ claimVerification: result.claimVerification
6551
+ });
6552
+ }
6553
+ function openEvolutionRecorder(cfg, plan) {
6554
+ const { splits, policy, allocation, maxUsd } = plan;
6555
+ return SearchRecorder.open({ ledger: openSearchLedger({
6556
+ path: plan.ledgerPath,
6557
+ searchId: plan.searchId
6184
6558
  }) }, {
6185
6559
  subject: `strategy/${cfg.environment.name}`,
6186
6560
  process: {
@@ -6191,269 +6565,124 @@ async function runStrategyEvolution(cfg) {
6191
6565
  objective: {
6192
6566
  metric: "score",
6193
6567
  direction: "maximize",
6194
- judge: environmentSource,
6195
- claim
6568
+ judge: plan.environmentSource,
6569
+ claim: plan.claim
6196
6570
  },
6197
6571
  splits: {
6198
6572
  ...splits,
6199
- heldOutUnits: splits.test.every((task) => !developmentUnits.has(task.unitId))
6573
+ heldOutUnits: splits.test.every((task) => !plan.developmentUnits.has(task.unitId))
6200
6574
  },
6201
6575
  policy: {
6202
6576
  expansion: policy.name,
6203
6577
  allocation: allocation.name,
6204
- seed
6578
+ seed: plan.seed
6205
6579
  },
6206
6580
  budget: {
6207
6581
  maxUsd,
6208
6582
  maxCells: null,
6209
- maxNodes: 1 + maxExpansions,
6583
+ maxNodes: 1 + plan.maxExpansions,
6210
6584
  deadline: cfg.deadline === void 0 ? null : new Date(cfg.deadline).toISOString(),
6211
- maxConcurrency: concurrency,
6585
+ maxConcurrency: plan.concurrency,
6212
6586
  reservedClaimUsd: maxUsd === null ? 0 : searchClaimReserveUsd({
6213
6587
  testTasks: splits.test.length,
6214
6588
  reps: allocation.reps,
6215
- cellUsd
6589
+ cellUsd: plan.cellUsd
6216
6590
  })
6217
6591
  },
6218
6592
  containment: null,
6219
6593
  derivedFrom: null,
6220
- identity: execution
6594
+ identity: plan.execution
6221
6595
  });
6222
- if (!(await recorder.state()).closed) await preflightModels({
6223
- worker: cfg.worker,
6224
- modelPreflight: cfg.modelPreflight,
6225
- modelPreflightTimeoutMs: cfg.modelPreflightTimeoutMs
6226
- });
6227
- const rootNode = {
6228
- kind: "root",
6229
- name: root.name
6596
+ }
6597
+ /** The author model as the search's proposer: it reads the train results and writes a module. */
6598
+ function strategyAuthorProposer(cfg, plan, recorder, codec) {
6599
+ const { authorSource } = plan;
6600
+ let toolCatalog;
6601
+ const catalog = () => {
6602
+ toolCatalog ??= listToolCatalog(cfg.environment, plan.train[0]);
6603
+ return toolCatalog;
6230
6604
  };
6231
- const codec = {
6232
- node(rec, node) {
6233
- const artifact = rec.blob("strategy", { ...node });
6234
- return {
6235
- artifactDigest: node.kind === "root" ? canonicalCandidateDigest$1({
6236
- kind: "root",
6237
- name: node.name
6238
- }) : sha256Bytes$1(Buffer.from(node.code, "utf8")),
6239
- artifact,
6240
- surfaces: [{
6241
- surfaceId: "strategy",
6242
- kind: "code",
6243
- artifact
6244
- }]
6245
- };
6246
- },
6247
- diff(rec, parent, child) {
6248
- if (parent.kind === "root" || child.kind === "root") return { unknown: "the root is a caller-supplied strategy with no source here" };
6249
- return surfaceDiff(rec, parent.code, child.code);
6605
+ const authorProvider = cfg.author.profile.model?.provider ?? "unknown";
6606
+ return {
6607
+ name: "strategy-author",
6608
+ kind: "frontier-author",
6609
+ source: authorSource,
6610
+ execution: {
6611
+ kind: "model",
6612
+ model: searchModelIdentity(plan.authorModel, authorProvider),
6613
+ source: authorSource
6250
6614
  },
6251
- load(rec, node) {
6252
- const stored = rec.readBlob(node.artifact);
6253
- if (stored.kind === "root") {
6254
- if (stored.name !== root.name) throw new Error(`evolution: node ${node.nodeId} is root '${stored.name}', not '${root.name}'`);
6255
- return rootNode;
6256
- }
6257
- if (stored.kind === "authored" && typeof stored.code === "string") return stored;
6258
- throw new Error(`evolution: node ${node.nodeId} holds no strategy`);
6259
- }
6260
- };
6261
- const loaded = /* @__PURE__ */ new Map();
6262
- const strategyOf = (node) => {
6263
- if (node.kind === "root") return Promise.resolve(root);
6264
- let strategy = loaded.get(node.code);
6265
- if (!strategy) {
6266
- strategy = loadAuthoredStrategy(node.code, modulesDir).then((module) => module.strategy);
6267
- loaded.set(node.code, strategy);
6268
- }
6269
- return strategy;
6270
- };
6271
- const storage = fsCampaignStorage();
6272
- const costLedger = createRunCostLedger({
6273
- storage,
6274
- runDir: searchDir
6275
- });
6276
- const lanes = [dedicatedLane({
6277
- name: "in-process",
6278
- capacity: concurrency,
6279
- cellUsd
6280
- })];
6281
- await reconcileInterruptedSearchCalls(costLedger, searchId, lanes);
6282
- const executor = searchExecutor({
6283
- lanes,
6284
- profileOf: () => workerProfile,
6285
- costLedger,
6286
- identity: execution,
6287
- storage,
6288
- dir: searchDir,
6289
- ...cfg.workerSlots ? { workerSlots: cfg.workerSlots } : {},
6290
- async runAttempt({ work, lane, costLedger: cellLedger }) {
6291
- if (work.artifact.kind === "authored" && work.artifact.refusal !== null) throw new Error(`evolution: refused node ${work.nodeId} was given a cell`);
6292
- const strategy = await strategyOf(work.artifact);
6293
- const task = taskById.get(work.taskId);
6294
- if (!task) throw new Error(`evolution: cell ${work.cellId} names unknown task ${work.taskId}`);
6295
- const faults = [];
6296
- const environment = faultRecording(cfg.environment, faults);
6297
- const paid = await cellLedger.runPaidCall({
6298
- channel: "agent",
6299
- phase: `search.${work.stage}`,
6300
- actor: `strategy:${strategy.name}`,
6301
- model: workerModel,
6302
- signal: work.signal,
6303
- execute: () => runAgentic({
6304
- ...cfg.worker,
6305
- surface: environment,
6306
- task,
6307
- strategy,
6308
- budget,
6309
- ...cfg.hooks ? { hooks: cfg.hooks } : {}
6310
- }),
6311
- receipt: (run) => ({
6312
- model: workerModel,
6313
- inputTokens: run.tokens.input,
6314
- outputTokens: run.tokens.output,
6315
- ...run.usdKnown ? { actualCostUsd: run.usd } : { costUnknown: true },
6316
- ...run.tokensKnown ? {} : { usageUnknown: true }
6317
- }),
6318
- receiptFromError: () => ({
6319
- model: workerModel,
6320
- inputTokens: 0,
6321
- outputTokens: 0,
6322
- costUnknown: true,
6323
- usageUnknown: true
6324
- })
6615
+ childrenPerProposal: 1,
6616
+ async propose(request) {
6617
+ const state = await recorder.state();
6618
+ const names = strategyNames(state, recorder, codec);
6619
+ const losses = JSON.stringify(strategyTournament(state, "train", names).rows.map((row) => ({
6620
+ task: row.taskId,
6621
+ ...row.rep > 0 ? { rep: row.rep } : {},
6622
+ cells: row.cells
6623
+ }))).slice(0, 12e3);
6624
+ const summary = renderSearchSummary(state, { split: "train" });
6625
+ const parent = request.parents[0];
6626
+ const parentName = names.get(parent.nodeId) ?? parent.nodeId;
6627
+ const tried = [...names.values()].join(", ");
6628
+ const parentSource = parent.artifact.kind === "authored" ? `\n\nPARENT STRATEGY "${parentName}" (improve on it):\n${parent.artifact.code}` : `\n\nPARENT STRATEGY "${parentName}" is the built-in baseline; improve on it.`;
6629
+ const contract = `${strategyAuthorContract}\n\nEXAMPLE TOOLS FROM ONE TASK (tool sets VARY per task on this domain — a strategy MUST select tool names from await listTools(handle) at runtime; hardcoding these example names will zero your score on most tasks):\n${await catalog()}\n\nTHE SEARCH SO FAR (train split):\n${summary}\n\nSTRATEGIES ALREADY TRIED (author something MEANINGFULLY different — a new composition, not a rename): ${tried}${parentSource}`;
6630
+ const source = await requestStrategySource({
6631
+ profile: cfg.author.profile,
6632
+ executor: cfg.author.executor,
6633
+ ...cfg.author.fallbackProfile ? { fallbackProfile: cfg.author.fallbackProfile } : {},
6634
+ contract,
6635
+ environmentName: cfg.environment.name,
6636
+ lossesJson: losses,
6637
+ budget: plan.budget,
6638
+ outDir: plan.modulesDir,
6639
+ signal: request.signal
6325
6640
  });
6326
- const settled = {
6327
- identity: execution,
6328
- placement: {
6329
- lane: lane.name,
6330
- boxId: null
6331
- },
6332
- accounting: unknownAccounting("replaced by the attempt receipts"),
6333
- ...paid.succeeded ? { wallMs: paid.value.ms } : {}
6334
- };
6335
- if (faults.length > 0) return {
6336
- ...settled,
6337
- ...environmentFault(faults)
6338
- };
6339
- if (!paid.succeeded) return {
6340
- ...settled,
6341
- outcome: {
6342
- status: "failed",
6343
- score: 0,
6344
- metrics: {},
6345
- failure: {
6346
- code: "strategy-threw",
6347
- message: shareText(paid.error)
6348
- }
6349
- }
6350
- };
6351
- const run = paid.value;
6641
+ const child = await authoredNode(source.code, plan.modulesDir);
6642
+ const answered = source.turns.at(-1);
6352
6643
  return {
6353
- ...settled,
6354
- outcome: {
6355
- status: "passed",
6356
- score: run.score,
6357
- metrics: {
6358
- resolved: run.resolved ? 1 : 0,
6359
- shots: run.shots
6360
- }
6361
- }
6644
+ children: [{
6645
+ artifact: child,
6646
+ label: child.name ?? "refused module",
6647
+ rationale: `authored from the train results of ${parentName} and ${names.size - 1} other strategies`
6648
+ }],
6649
+ accounting: authorAccounting(source.turns),
6650
+ ...answered ? { execution: {
6651
+ kind: "model",
6652
+ model: searchModelIdentity(answered.model, authorProvider),
6653
+ source: authorSource
6654
+ } } : {}
6362
6655
  };
6363
6656
  }
6364
- });
6365
- let toolCatalog;
6366
- const catalog = () => {
6367
- toolCatalog ??= listToolCatalog(cfg.environment, train[0]);
6368
- return toolCatalog;
6369
6657
  };
6370
- const authorProvider = cfg.author.profile.model?.provider ?? "unknown";
6371
- const result = await runSearch({
6372
- recorder,
6373
- root: rootNode,
6374
- codec,
6375
- policy,
6376
- allocation,
6377
- proposer: {
6378
- name: "strategy-author",
6379
- kind: "frontier-author",
6380
- source: authorSource,
6381
- execution: {
6382
- kind: "model",
6383
- model: searchModelIdentity(authorModel, authorProvider),
6384
- source: authorSource
6385
- },
6386
- childrenPerProposal: 1,
6387
- async propose(request) {
6388
- const state = await recorder.state();
6389
- const names = strategyNames(state, recorder, codec);
6390
- const losses = JSON.stringify(strategyTournament(state, "train", names).rows.map((row) => ({
6391
- task: row.taskId,
6392
- ...row.rep > 0 ? { rep: row.rep } : {},
6393
- cells: row.cells
6394
- }))).slice(0, 12e3);
6395
- const summary = renderSearchSummary(state, { split: "train" });
6396
- const parent = request.parents[0];
6397
- const parentName = names.get(parent.nodeId) ?? parent.nodeId;
6398
- const tried = [...names.values()].join(", ");
6399
- const parentSource = parent.artifact.kind === "authored" ? `\n\nPARENT STRATEGY "${parentName}" (improve on it):\n${parent.artifact.code}` : `\n\nPARENT STRATEGY "${parentName}" is the built-in baseline; improve on it.`;
6400
- const contract = `${strategyAuthorContract}\n\nEXAMPLE TOOLS FROM ONE TASK (tool sets VARY per task on this domain — a strategy MUST select tool names from await listTools(handle) at runtime; hardcoding these example names will zero your score on most tasks):\n${await catalog()}\n\nTHE SEARCH SO FAR (train split):\n${summary}\n\nSTRATEGIES ALREADY TRIED (author something MEANINGFULLY different — a new composition, not a rename): ${tried}${parentSource}`;
6401
- const source = await requestStrategySource({
6402
- profile: cfg.author.profile,
6403
- executor: cfg.author.executor,
6404
- ...cfg.author.fallbackProfile ? { fallbackProfile: cfg.author.fallbackProfile } : {},
6405
- contract,
6406
- environmentName: cfg.environment.name,
6407
- lossesJson: losses,
6408
- budget,
6409
- outDir: modulesDir,
6410
- signal: request.signal
6411
- });
6412
- let child = {
6413
- kind: "authored",
6414
- name: null,
6415
- code: "",
6416
- refusal: NO_MODULE
6417
- };
6418
- if (source.code !== null) try {
6419
- const { strategy } = await loadAuthoredStrategy(source.code, modulesDir);
6420
- child = {
6421
- kind: "authored",
6422
- name: strategy.name,
6423
- code: source.code,
6424
- refusal: null
6425
- };
6426
- } catch (error) {
6427
- child = {
6428
- kind: "authored",
6429
- name: null,
6430
- code: source.code,
6431
- refusal: shareText(error)
6432
- };
6433
- }
6434
- const answered = source.turns.at(-1);
6435
- return {
6436
- children: [{
6437
- artifact: child,
6438
- label: child.name ?? "refused module",
6439
- rationale: `authored from the train results of ${parentName} and ${names.size - 1} other strategies`
6440
- }],
6441
- accounting: authorAccounting(source.turns),
6442
- ...answered ? { execution: {
6443
- kind: "model",
6444
- model: searchModelIdentity(answered.model, authorProvider),
6445
- source: authorSource
6446
- } } : {}
6447
- };
6448
- }
6449
- },
6450
- executor,
6451
- admit: (node) => node.kind === "authored" ? node.refusal : null,
6452
- maxExpansions,
6453
- maxAttempts,
6454
- ...cfg.signal ? { signal: cfg.signal } : {}
6455
- });
6456
- if (!result.claim || !result.claimVerification) throw new Error(`evolution: search ${searchId} closed without a claim`);
6658
+ }
6659
+ /** The node an author reply makes: admitted when the module loads, else carrying the refusal. */
6660
+ async function authoredNode(code, modulesDir) {
6661
+ if (code === null) return {
6662
+ kind: "authored",
6663
+ name: null,
6664
+ code: "",
6665
+ refusal: NO_MODULE
6666
+ };
6667
+ try {
6668
+ const { strategy } = await loadAuthoredStrategy(code, modulesDir);
6669
+ return {
6670
+ kind: "authored",
6671
+ name: strategy.name,
6672
+ code,
6673
+ refusal: null
6674
+ };
6675
+ } catch (error) {
6676
+ return {
6677
+ kind: "authored",
6678
+ name: null,
6679
+ code,
6680
+ refusal: shareText(error)
6681
+ };
6682
+ }
6683
+ }
6684
+ /** The report: a projection of the ledger the finished search leaves. */
6685
+ function evolutionReport(plan, recorder, codec, result) {
6457
6686
  const { state } = result;
6458
6687
  const names = strategyNames(state, recorder, codec);
6459
6688
  const rootId = state.rootNodeId;
@@ -6487,8 +6716,8 @@ async function runStrategyEvolution(cfg) {
6487
6716
  minimumLift: 0
6488
6717
  });
6489
6718
  return {
6490
- searchId,
6491
- ledger: ledgerPath,
6719
+ searchId: plan.searchId,
6720
+ ledger: plan.ledgerPath,
6492
6721
  closeReason: result.reason,
6493
6722
  strategies,
6494
6723
  selected: strategies.find((strategy) => strategy.nodeId === result.leader),
@@ -6565,50 +6794,6 @@ function strategyTournament(state, split, names) {
6565
6794
  perStrategy
6566
6795
  };
6567
6796
  }
6568
- /** Report names: each node's strategy name, suffixed `~<ordinal>` when an earlier node has it. */
6569
- function strategyNames(state, recorder, codec) {
6570
- const names = /* @__PURE__ */ new Map();
6571
- const taken = /* @__PURE__ */ new Set();
6572
- for (const node of state.nodes()) {
6573
- const base = codec.load(recorder, node).name ?? "refused-module";
6574
- const name = taken.has(base) ? `${base}~${node.ordinal}` : base;
6575
- taken.add(name);
6576
- names.set(node.nodeId, name);
6577
- }
6578
- return names;
6579
- }
6580
- /** The environment as one attempt sees it, recording each throw from `open`, `tools`,
6581
- * `score` or `close`: those are the environment's faults. A `call` that throws is a tool
6582
- * error the agent's loop handles. */
6583
- function faultRecording(environment, faults) {
6584
- const recorded = (name, method) => async (...args) => {
6585
- try {
6586
- return await method(...args);
6587
- } catch (error) {
6588
- faults.push(`${name}: ${shareText(error)}`);
6589
- throw error;
6590
- }
6591
- };
6592
- return {
6593
- name: environment.name,
6594
- open: recorded("open", (task) => environment.open(task)),
6595
- tools: recorded("tools", (task, handle) => environment.tools(task, handle)),
6596
- call: (handle, name, args) => environment.call(handle, name, args),
6597
- score: recorded("score", (task, handle) => environment.score(task, handle)),
6598
- close: recorded("close", (handle) => environment.close(handle))
6599
- };
6600
- }
6601
- function environmentFault(faults) {
6602
- return { outcome: {
6603
- status: "errored",
6604
- metrics: {},
6605
- error: {
6606
- code: "environment-fault",
6607
- message: faults[0],
6608
- retryable: true
6609
- }
6610
- } };
6611
- }
6612
6797
  function authorAccounting(turns) {
6613
6798
  let usd = 0;
6614
6799
  let costKnown = true;
@@ -6635,19 +6820,6 @@ function authorAccounting(turns) {
6635
6820
  }
6636
6821
  };
6637
6822
  }
6638
- function unknownAccounting(reason) {
6639
- return {
6640
- tokens: {
6641
- status: "unknown",
6642
- reason
6643
- },
6644
- cost: {
6645
- status: "unknown",
6646
- knownLowerBoundUsd: 0,
6647
- reason
6648
- }
6649
- };
6650
- }
6651
6823
  /** One probe round-trip lists the domain's tools so the author can focus shots, names and
6652
6824
  * descriptions only, never the implementations. */
6653
6825
  async function listToolCatalog(environment, task) {
@@ -6658,25 +6830,70 @@ async function listToolCatalog(environment, task) {
6658
6830
  await environment.close(handle);
6659
6831
  }
6660
6832
  }
6661
- /** Free text as the ledger stores it: redacted with the share profile and bounded. */
6662
- function shareText(error) {
6663
- return redact(error instanceof Error ? error.message : String(error), { profile: "share" }).value.slice(0, 300);
6664
- }
6665
6833
  function compare(left, right) {
6666
6834
  return left < right ? -1 : left > right ? 1 : 0;
6667
6835
  }
6668
- function positiveInteger(name, value) {
6669
- if (!Number.isSafeInteger(value) || value < 1) throw new ConfigError(`evolution: ${name} must be a positive integer`);
6670
- return value;
6836
+ /** How the ledger stores a node's artifact and reads it back. */
6837
+ function strategyNodeCodec(root) {
6838
+ const rootNode = {
6839
+ kind: "root",
6840
+ name: root.name
6841
+ };
6842
+ return {
6843
+ node(rec, node) {
6844
+ const artifact = rec.blob("strategy", { ...node });
6845
+ return {
6846
+ artifactDigest: node.kind === "root" ? canonicalCandidateDigest$1({
6847
+ kind: "root",
6848
+ name: node.name
6849
+ }) : sha256Bytes$1(Buffer.from(node.code, "utf8")),
6850
+ artifact,
6851
+ surfaces: [{
6852
+ surfaceId: "strategy",
6853
+ kind: "code",
6854
+ artifact
6855
+ }]
6856
+ };
6857
+ },
6858
+ diff(rec, parent, child) {
6859
+ if (parent.kind === "root" || child.kind === "root") return { unknown: "the root is a caller-supplied strategy with no source here" };
6860
+ return surfaceDiff(rec, parent.code, child.code);
6861
+ },
6862
+ load(rec, node) {
6863
+ const stored = rec.readBlob(node.artifact);
6864
+ if (stored.kind === "root") {
6865
+ if (stored.name !== root.name) throw new Error(`evolution: node ${node.nodeId} is root '${stored.name}', not '${root.name}'`);
6866
+ return rootNode;
6867
+ }
6868
+ if (stored.kind === "authored" && typeof stored.code === "string") return stored;
6869
+ throw new Error(`evolution: node ${node.nodeId} holds no strategy`);
6870
+ }
6871
+ };
6671
6872
  }
6672
- function nonNegativeInteger(name, value) {
6673
- if (!Number.isSafeInteger(value) || value < 0) throw new ConfigError(`evolution: ${name} must be a non-negative integer`);
6674
- return value;
6873
+ /** Resolve a node to its runnable strategy; an authored module loads once per source. */
6874
+ function strategyLoader(root, modulesDir) {
6875
+ const loaded = /* @__PURE__ */ new Map();
6876
+ return (node) => {
6877
+ if (node.kind === "root") return Promise.resolve(root);
6878
+ let strategy = loaded.get(node.code);
6879
+ if (!strategy) {
6880
+ strategy = loadAuthoredStrategy(node.code, modulesDir).then((module) => module.strategy);
6881
+ loaded.set(node.code, strategy);
6882
+ }
6883
+ return strategy;
6884
+ };
6675
6885
  }
6676
- function dollars(name, value) {
6677
- if (value === void 0) return null;
6678
- if (!Number.isFinite(value) || value < 0) throw new ConfigError(`evolution: ${name} must be a finite non-negative number`);
6679
- return value;
6886
+ /** Report names: each node's strategy name, suffixed `~<ordinal>` when an earlier node has it. */
6887
+ function strategyNames(state, recorder, codec) {
6888
+ const names = /* @__PURE__ */ new Map();
6889
+ const taken = /* @__PURE__ */ new Set();
6890
+ for (const node of state.nodes()) {
6891
+ const base = codec.load(recorder, node).name ?? "refused-module";
6892
+ const name = taken.has(base) ? `${base}~${node.ordinal}` : base;
6893
+ taken.add(name);
6894
+ names.set(node.nodeId, name);
6895
+ }
6896
+ return names;
6680
6897
  }
6681
6898
  //#endregion
6682
6899
  //#region src/runtime/supervise/chat-transport-executor.ts
@@ -7445,7 +7662,7 @@ function compileSearchSpec(raw, inputs) {
7445
7662
  })
7446
7663
  });
7447
7664
  const continuation = {
7448
- deadline: inputs.deadline,
7665
+ ...inputs.deadline === void 0 ? {} : { deadline: inputs.deadline },
7449
7666
  maxBarren: spec.stop.maxBarren,
7450
7667
  profile: inputs.continuation.profile,
7451
7668
  failures: spec.evaluate.feedback,
@@ -8980,4 +9197,4 @@ function tail(s) {
8980
9197
  //#endregion
8981
9198
  export { runPersonified as $, openSqlRunStore as $t, searchSpecDigest as A, secretEnvOfMcpServer as At, chatWorkerSeam as B, readDeclaredCheck as Bt, withUntrackedArtifacts as C, materializeLocalMcp as Ct, assertSearchSpec as D, mcpSecretEnvMetadataKey as Dt, SEARCH_SPEC_CORRELATION_KEY as E, envKeyProvider as Et, profileRegistry as F, assertDeclaredCheck as Ft, openSandboxRun as G, stopSentinel as Gt, runStrategyEvolution as H, completionAuthorizes as Ht, profileRunsForName as I, checkProgramDigest as It, runBenchmark as J, renderLeaderboardHtml as Jt, createS3PrivateCasStore as K, leaderboard as Kt, recordProfileRun as L, declaredCheckDeliverable as Lt, bestProfileFor as M, loopCampaignDispatch as Mt, loadProfile as N, loopDispatch as Nt, compileSearchSpec as O, resolveMcpServerLaunch as Ot, pickBestProfile as P, superviseDispatch as Pt, definePersona as Q, SqlRunOwnershipError as Qt, graphDesignerExtraTools as R, declaredCheckDigest as Rt, copyUntrackedIntoClone as S, connectStdioMcp as St, createFencedSqlRunContext as T, sanitizeMcpToolSchema as Tt, strategyTournament as U, deterministicCompletion as Ut, createChatSessionStore as V, runIsolatedCheck as Vt, SandboxRunAbortError as W, sentinelCompletion as Wt, equalKOnCost as X, renderLeaderboardSvg as Xt, createPrivateCasArtifactPort as Y, renderLeaderboardMarkdown as Yt, trajectoryReport as Z, renderPairwiseMarkdown as Zt, NOTE_MAX_CHARS as _, HarvestError as _t, localShell as a, loopUntil as at, composeWorkerEvidence as b, resolveSandboxClient as bt, createVerifierEnvironment as c, selectValidWinner as ct, harvestSurfaceDiffs as d, assertTraceDerivedFindings as dt, FileCorpus as et, analystsFromRegistry as f, buildSteerContext as ft, EVIDENCE_MAX_CHARS as g, inProcessSandboxClient as gt, runCoderChecks as h, observationFromRegistry as ht, jjWorkspace as i, flatWidenGate as it, connectRemoteSupervisor as j, inlineSandboxClient as jt, searchPresets as k, resolveSecretEnv as kt, boxSurfaceReader as l, verify as lt, worktreeFanout as m, registryScopeAnalyst as mt, makeFinding$1 as n, renderCorpusToInstructions as nt, runInWorkspace as o, panel as ot, failuresAnalyst as p, createScopeAnalyst as pt, printBenchmarkReport as q, pairwiseSignificance as qt, gitWorkspace as r, fanout as rt, createWaterfallCollector as s, pipeline as st, computeFindingId$1 as t, InMemoryCorpus as tt, fsSurfaceReader as u, widen as ut, VERIFY_TAIL_CHARS as v, harvestCorpus as vt, analyzeTrace as w, createMcpEnvironment as wt, settledWorkerOut as x, McpSpawnFault as xt, closingWorkerNote as y, defineLeaderboard as yt, chatTransportExecutor as z, declaredCheckJudge as zt };
8982
9199
 
8983
- //# sourceMappingURL=runtime-B2fjL9Oi.js.map
9200
+ //# sourceMappingURL=runtime-eghmj6W4.js.map