@tangle-network/agent-eval 0.115.3 → 0.116.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.
- package/CHANGELOG.md +24 -0
- package/dist/analyst/index.d.ts +8 -10
- package/dist/analyst/index.js +27 -22
- package/dist/analyst/index.js.map +1 -1
- package/dist/{analyst-C8HHvfJp.d.ts → analyst-CFBc14Wc.d.ts} +1 -1
- package/dist/{analyze-runs-BYHg6Irm.d.ts → analyze-runs-0rz_m29H.d.ts} +3 -3
- package/dist/belief-state/index.d.ts +3 -3
- package/dist/benchmarks/index.d.ts +7 -3
- package/dist/benchmarks/index.js +4 -4
- package/dist/campaign/index.d.ts +212 -23
- package/dist/campaign/index.js +19 -4
- package/dist/{chunk-ADYLPOSX.js → chunk-3274WNK7.js} +427 -93
- package/dist/chunk-3274WNK7.js.map +1 -0
- package/dist/{chunk-I6LVHOV3.js → chunk-7GKEAIAD.js} +2 -2
- package/dist/{chunk-5S5NJ63F.js → chunk-CIUOICJT.js} +747 -2
- package/dist/chunk-CIUOICJT.js.map +1 -0
- package/dist/{chunk-KG4TD7EQ.js → chunk-GSW3OBHK.js} +1283 -181
- package/dist/chunk-GSW3OBHK.js.map +1 -0
- package/dist/chunk-MPHTT5HE.js +74 -0
- package/dist/chunk-MPHTT5HE.js.map +1 -0
- package/dist/{chunk-WSBUZMBU.js → chunk-NBSS5NDZ.js} +3 -3
- package/dist/{code-agent-session-D-g04tcy.d.ts → code-agent-session-CdxteG0y.d.ts} +1 -1
- package/dist/contract/index.d.ts +19 -19
- package/dist/contract/index.js +5 -3
- package/dist/contract/index.js.map +1 -1
- package/dist/{control-CcBiAEnn.d.ts → control-DbcDxouY.d.ts} +1 -1
- package/dist/control.d.ts +2 -2
- package/dist/{default-registry-DltpYR5u.d.ts → default-registry-DDfv22MQ.d.ts} +2 -1
- package/dist/{gepa-dne9JDPL.d.ts → gepa-CQelRtuC.d.ts} +10 -8
- package/dist/hosted/index.d.ts +8 -4
- package/dist/{index-BTEpx9He.d.ts → index-DbCXJfZ1.d.ts} +2 -2
- package/dist/index.d.ts +27 -30
- package/dist/index.js +26 -20
- package/dist/index.js.map +1 -1
- package/dist/{insight-report-IwwvqZZv.d.ts → insight-report-oMVxDTxl.d.ts} +1 -1
- package/dist/{integrity-qemeBAyx.d.ts → integrity-C6PZ73iC.d.ts} +1 -1
- package/dist/kind-factory-DWOvXjR_.d.ts +171 -0
- package/dist/meta-eval/index.d.ts +2 -2
- package/dist/multishot/index.d.ts +6 -2
- package/dist/openapi.json +1 -1
- package/dist/policy-edit-Clb2v6Oa.d.ts +708 -0
- package/dist/{pre-registration-D8h7ZxNL.d.ts → pre-registration--vU0mMtD.d.ts} +4 -4
- package/dist/{provenance-Bibyg1U9.d.ts → provenance-BbVagC68.d.ts} +26 -14
- package/dist/{release-report-CCtzajxP.d.ts → release-report-CamNDe90.d.ts} +2 -2
- package/dist/reporting.d.ts +4 -4
- package/dist/{researcher-Dq-EtpbE.d.ts → researcher-Dwbo_Fxx.d.ts} +5 -5
- package/dist/rl.d.ts +11 -9
- package/dist/{rubric-predictive-validity-DYTLjGWu.d.ts → rubric-predictive-validity-BIdf9h4R.d.ts} +1 -1
- package/dist/{run-record-B7RTi_ix.d.ts → run-record-CZmcpWPo.d.ts} +1 -1
- package/dist/{runtime-trajectory-Dws7Kpgi.d.ts → runtime-trajectory-CC0jx9ql.d.ts} +1 -1
- package/dist/{semantic-concept-judge-DxJmRkyJ.d.ts → semantic-concept-judge-CKjePUMh.d.ts} +3 -3
- package/dist/{store-C1YxJDEK.d.ts → store-9cAScOcb.d.ts} +132 -1
- package/dist/{summary-report-BJ5aNwZ1.d.ts → summary-report-DTNgQycC.d.ts} +1 -1
- package/dist/traces.d.ts +6 -8
- package/dist/{types-C5gJrOVT.d.ts → types-Ca_63YSD.d.ts} +59 -2
- package/docs/design/loop-taxonomy.md +1 -2
- package/package.json +1 -1
- package/dist/chunk-5S5NJ63F.js.map +0 -1
- package/dist/chunk-ADYLPOSX.js.map +0 -1
- package/dist/chunk-KG4TD7EQ.js.map +0 -1
- package/dist/chunk-QMXXSNC4.js +0 -761
- package/dist/chunk-QMXXSNC4.js.map +0 -1
- package/dist/kind-factory-DcNg13sZ.d.ts +0 -508
- package/dist/llm-client-DyqEH4jH.d.ts +0 -265
- package/dist/policy-edit-RLn8GWof.d.ts +0 -103
- package/dist/raw-provider-sink-C46HDghv.d.ts +0 -132
- /package/dist/{chunk-I6LVHOV3.js.map → chunk-7GKEAIAD.js.map} +0 -0
- /package/dist/{chunk-WSBUZMBU.js.map → chunk-NBSS5NDZ.js.map} +0 -0
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
runCampaign,
|
|
3
3
|
summarizeBackendIntegrity
|
|
4
4
|
} from "./chunk-FAOEFFRT.js";
|
|
5
|
+
import {
|
|
6
|
+
validatePolicyEditCandidateRecord
|
|
7
|
+
} from "./chunk-CIUOICJT.js";
|
|
5
8
|
import {
|
|
6
9
|
detectRewardHacking
|
|
7
10
|
} from "./chunk-ARU2PZFM.js";
|
|
@@ -922,8 +925,14 @@ function pairHoldout(candidate, baseline, scenarioIds, select) {
|
|
|
922
925
|
if (!scores) return void 0;
|
|
923
926
|
const vals = [];
|
|
924
927
|
for (const s of Object.values(scores)) {
|
|
928
|
+
if (s.failed === true) {
|
|
929
|
+
throw new Error(`pairHoldout: cell '${cellId}' contains a failed judge score`);
|
|
930
|
+
}
|
|
925
931
|
const v = select(s);
|
|
926
|
-
if (typeof v === "number" && Number.isFinite(v))
|
|
932
|
+
if (typeof v === "number" && !Number.isFinite(v)) {
|
|
933
|
+
throw new Error(`pairHoldout: cell '${cellId}' contains a non-finite selected score`);
|
|
934
|
+
}
|
|
935
|
+
if (typeof v === "number") vals.push(v);
|
|
927
936
|
}
|
|
928
937
|
if (vals.length === 0) return void 0;
|
|
929
938
|
return vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
@@ -942,7 +951,10 @@ function pairHoldout(candidate, baseline, scenarioIds, select) {
|
|
|
942
951
|
for (const cellId of candCells) {
|
|
943
952
|
const b = cellValue(baseline, cellId);
|
|
944
953
|
const a = cellValue(candidate, cellId);
|
|
945
|
-
if (b === void 0
|
|
954
|
+
if (b === void 0 && a === void 0) continue;
|
|
955
|
+
if (b === void 0 || a === void 0) {
|
|
956
|
+
throw new Error(`pairHoldout: cell '${cellId}' has a selected score on only one arm`);
|
|
957
|
+
}
|
|
946
958
|
before.push(b);
|
|
947
959
|
after.push(a);
|
|
948
960
|
cellIds.push(cellId);
|
|
@@ -1707,6 +1719,65 @@ function parseReflectionResponse(raw, maxProposals) {
|
|
|
1707
1719
|
return out;
|
|
1708
1720
|
}
|
|
1709
1721
|
|
|
1722
|
+
// src/campaign/surface-identity.ts
|
|
1723
|
+
import { createHash } from "crypto";
|
|
1724
|
+
var GIT_OBJECT_ID = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/;
|
|
1725
|
+
var SHA256 = /^sha256:[a-f0-9]{64}$/;
|
|
1726
|
+
function assertCodeSurfaceIdentity(surface) {
|
|
1727
|
+
if (!surface || typeof surface !== "object") {
|
|
1728
|
+
throw new TypeError("CodeSurface must be an object");
|
|
1729
|
+
}
|
|
1730
|
+
const candidate = surface;
|
|
1731
|
+
if (candidate.kind !== "code") throw new TypeError('CodeSurface.kind must be "code"');
|
|
1732
|
+
if (typeof candidate.worktreeRef !== "string" || candidate.worktreeRef.trim().length === 0) {
|
|
1733
|
+
throw new TypeError("CodeSurface.worktreeRef must be a non-empty locator");
|
|
1734
|
+
}
|
|
1735
|
+
if (typeof candidate.baseRef !== "string" || candidate.baseRef.trim().length === 0) {
|
|
1736
|
+
throw new TypeError("CodeSurface.baseRef must be a non-empty ref label");
|
|
1737
|
+
}
|
|
1738
|
+
for (const [field, value] of [
|
|
1739
|
+
["baseCommit", candidate.baseCommit],
|
|
1740
|
+
["baseTree", candidate.baseTree],
|
|
1741
|
+
["candidateCommit", candidate.candidateCommit],
|
|
1742
|
+
["candidateTree", candidate.candidateTree]
|
|
1743
|
+
]) {
|
|
1744
|
+
if (typeof value !== "string" || !GIT_OBJECT_ID.test(value)) {
|
|
1745
|
+
throw new TypeError(`CodeSurface.${field} must be a full Git object id`);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
const patch = candidate.patch;
|
|
1749
|
+
if (!patch || typeof patch !== "object" || patch.format !== "git-diff-binary") {
|
|
1750
|
+
throw new TypeError('CodeSurface.patch.format must be "git-diff-binary"');
|
|
1751
|
+
}
|
|
1752
|
+
if (typeof patch.sha256 !== "string" || !SHA256.test(patch.sha256)) {
|
|
1753
|
+
throw new TypeError("CodeSurface.patch.sha256 must be a sha256 digest");
|
|
1754
|
+
}
|
|
1755
|
+
if (!Number.isSafeInteger(patch.byteLength) || patch.byteLength < 0) {
|
|
1756
|
+
throw new TypeError("CodeSurface.patch.byteLength must be a non-negative safe integer");
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
function codeSurfaceIdentityMaterial(surface) {
|
|
1760
|
+
assertCodeSurfaceIdentity(surface);
|
|
1761
|
+
return JSON.stringify({
|
|
1762
|
+
schema: "tangle.code-surface.v1",
|
|
1763
|
+
baseCommit: surface.baseCommit,
|
|
1764
|
+
baseTree: surface.baseTree,
|
|
1765
|
+
candidateTree: surface.candidateTree,
|
|
1766
|
+
patch: {
|
|
1767
|
+
format: surface.patch.format,
|
|
1768
|
+
sha256: surface.patch.sha256,
|
|
1769
|
+
byteLength: surface.patch.byteLength
|
|
1770
|
+
}
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
function surfaceContentHash(surface) {
|
|
1774
|
+
const material = typeof surface === "string" ? surface : codeSurfaceIdentityMaterial(surface);
|
|
1775
|
+
return `sha256:${createHash("sha256").update(material).digest("hex")}`;
|
|
1776
|
+
}
|
|
1777
|
+
function surfaceHash(surface) {
|
|
1778
|
+
return surfaceContentHash(surface).slice("sha256:".length, "sha256:".length + 16);
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1710
1781
|
// src/campaign/proposers/gepa.ts
|
|
1711
1782
|
var REFLECTION_SYSTEM = 'You are an expert prompt engineer performing GEPA-style reflective mutation. You are given a prompt surface, its top trials (preserve what works) and its bottom trials (the evidence to fix). For each proposal, reason in this order before writing the payload: (1) LOCALIZE \u2014 point to the exact span of the current surface responsible for a bottom-trial failure; (2) DIAGNOSE the root cause (a missing rule, an ambiguous instruction, an over-broad directive), not just the symptom; (3) propose the MINIMAL, GENERALIZABLE edit that fixes the whole failure class \u2014 state it as a rule the agent should follow, never a patch memorized to the shown trials (that is overfitting and will not transfer to the held-out set); (4) PRESERVE every instruction the top trials depend on \u2014 do not delete or weaken working guidance. Put this localize\u2192diagnose\u2192fix reasoning in each proposal\'s `rationale`. Output ONLY a JSON object of shape {"proposals":[{"label":string,"rationale":string,"payload":string}]} where each `payload` is the FULL improved surface text. No prose outside the JSON.';
|
|
1712
1783
|
var COMBINE_SYSTEM = 'You are an expert prompt engineer performing a GEPA "combine complementary lessons" merge. You are given several non-dominated versions of one surface; each is uniquely best on different scenarios. Produce ONE new version that keeps what makes each version strong on its winning scenarios and resolves conflicts in favor of the more general rule. Output ONLY a JSON object of shape {"proposals":[{"label":string,"rationale":string,"payload":string}]} with exactly one proposal whose `payload` is the FULL merged surface text. No prose outside the JSON.';
|
|
@@ -1854,10 +1925,11 @@ function validatePreservedSections(candidate, required) {
|
|
|
1854
1925
|
}
|
|
1855
1926
|
function buildEvidence(ctx, evidenceK, baseTarget) {
|
|
1856
1927
|
const last = ctx.history.at(-1);
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1928
|
+
const currentSurfaceHash = surfaceHash(ctx.currentSurface);
|
|
1929
|
+
const measuredCurrentSurface = ctx.history.flatMap((record) => record.candidates).reverse().find(
|
|
1930
|
+
(candidate) => candidate.surfaceHash === currentSurfaceHash && candidate.eligibleForPromotion !== false
|
|
1931
|
+
);
|
|
1932
|
+
const best = ctx.incumbentOutcome ?? measuredCurrentSurface ?? (last ? [...last.candidates].filter((candidate) => candidate.eligibleForPromotion !== false).sort((a, b) => b.composite - a.composite)[0] : void 0);
|
|
1861
1933
|
if (!best) return { top: [], bottom: [], target: baseTarget };
|
|
1862
1934
|
const byScore = [...best.scenarios].sort((a, b) => b.composite - a.composite);
|
|
1863
1935
|
const toTrace = (s) => ({
|
|
@@ -1878,7 +1950,7 @@ function buildEvidence(ctx, evidenceK, baseTarget) {
|
|
|
1878
1950
|
function campaignMeanComposite(campaign) {
|
|
1879
1951
|
const composites = [];
|
|
1880
1952
|
for (const cell of campaign.cells) {
|
|
1881
|
-
const cellComposites = Object.values(cell.judgeScores).map((
|
|
1953
|
+
const cellComposites = Object.values(cell.judgeScores).filter((score) => score.failed !== true && Number.isFinite(score.composite)).map((score) => score.composite);
|
|
1882
1954
|
if (cellComposites.length > 0) {
|
|
1883
1955
|
composites.push(cellComposites.reduce((a, b) => a + b, 0) / cellComposites.length);
|
|
1884
1956
|
}
|
|
@@ -1891,7 +1963,9 @@ function campaignBreakdown(campaign) {
|
|
|
1891
1963
|
const byScenario = /* @__PURE__ */ new Map();
|
|
1892
1964
|
const notesByScenario = /* @__PURE__ */ new Map();
|
|
1893
1965
|
for (const cell of campaign.cells) {
|
|
1894
|
-
const judgeScores = Object.values(cell.judgeScores)
|
|
1966
|
+
const judgeScores = Object.values(cell.judgeScores).filter(
|
|
1967
|
+
(score) => score.failed !== true && Number.isFinite(score.composite)
|
|
1968
|
+
);
|
|
1895
1969
|
if (judgeScores.length === 0) continue;
|
|
1896
1970
|
const cellComposite = judgeScores.reduce((a, s) => a + s.composite, 0) / judgeScores.length;
|
|
1897
1971
|
const arr = byScenario.get(cell.scenarioId) ?? [];
|
|
@@ -1906,6 +1980,7 @@ function campaignBreakdown(campaign) {
|
|
|
1906
1980
|
}
|
|
1907
1981
|
for (const score of judgeScores) {
|
|
1908
1982
|
for (const [key, value] of Object.entries(score.dimensions)) {
|
|
1983
|
+
if (!Number.isFinite(value)) continue;
|
|
1909
1984
|
dimSums[key] = (dimSums[key] ?? 0) + value;
|
|
1910
1985
|
dimCounts[key] = (dimCounts[key] ?? 0) + 1;
|
|
1911
1986
|
}
|
|
@@ -1928,84 +2003,120 @@ function campaignBreakdown(campaign) {
|
|
|
1928
2003
|
return { dimensions, scenarios };
|
|
1929
2004
|
}
|
|
1930
2005
|
|
|
1931
|
-
// src/campaign/
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
2006
|
+
// src/campaign/coverage.ts
|
|
2007
|
+
function campaignCoverage(cells, scenarios, reps, requireJudgeScore) {
|
|
2008
|
+
const expectedCellIds = designedCellIds(scenarios, reps);
|
|
2009
|
+
const cellsById = /* @__PURE__ */ new Map();
|
|
2010
|
+
for (const cell of cells) {
|
|
2011
|
+
const matches = cellsById.get(cell.cellId) ?? [];
|
|
2012
|
+
matches.push(cell);
|
|
2013
|
+
cellsById.set(cell.cellId, matches);
|
|
2014
|
+
}
|
|
2015
|
+
const scorableCellIds = [];
|
|
2016
|
+
const unscorableCells = [];
|
|
2017
|
+
for (const cellId of expectedCellIds) {
|
|
2018
|
+
const matches = cellsById.get(cellId) ?? [];
|
|
2019
|
+
if (matches.length === 0) {
|
|
2020
|
+
unscorableCells.push({ cellId, reason: "missing campaign cell" });
|
|
2021
|
+
continue;
|
|
2022
|
+
}
|
|
2023
|
+
if (matches.length > 1) {
|
|
2024
|
+
unscorableCells.push({ cellId, reason: `duplicate campaign cell (${matches.length})` });
|
|
2025
|
+
continue;
|
|
2026
|
+
}
|
|
2027
|
+
const cell = matches[0];
|
|
2028
|
+
const scoreEntries = Object.entries(cell.judgeScores);
|
|
2029
|
+
const successfulScores = scoreEntries.map(([, score]) => score).filter((score) => score.failed !== true && Number.isFinite(score.composite));
|
|
2030
|
+
const nonFiniteScores = scoreEntries.filter(
|
|
2031
|
+
([, score]) => score.failed !== true && (!Number.isFinite(score.composite) || Object.values(score.dimensions).some((value) => !Number.isFinite(value)))
|
|
2032
|
+
);
|
|
2033
|
+
const reasons = [];
|
|
2034
|
+
if (cell.error) reasons.push(cell.error);
|
|
2035
|
+
if (cell.artifact === null || cell.artifact === void 0) reasons.push("missing artifact");
|
|
2036
|
+
if (!cell.error && requireJudgeScore && successfulScores.length === 0) {
|
|
2037
|
+
reasons.push("no successful finite judge score");
|
|
2038
|
+
}
|
|
2039
|
+
if (scoreEntries.some(([, score]) => score.failed === true)) {
|
|
2040
|
+
reasons.push("judge score marked failed");
|
|
2041
|
+
}
|
|
2042
|
+
if (nonFiniteScores.length > 0) {
|
|
2043
|
+
reasons.push(
|
|
2044
|
+
`non-finite judge score: ${nonFiniteScores.map(([name]) => name).sort().join(", ")}`
|
|
2045
|
+
);
|
|
2046
|
+
}
|
|
2047
|
+
if (reasons.length > 0) {
|
|
2048
|
+
unscorableCells.push({ cellId, reason: reasons.join("; ") });
|
|
2049
|
+
} else {
|
|
2050
|
+
scorableCellIds.push(cellId);
|
|
1955
2051
|
}
|
|
1956
2052
|
}
|
|
1957
|
-
const
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
if (typeof patch.sha256 !== "string" || !SHA256.test(patch.sha256)) {
|
|
1962
|
-
throw new TypeError("CodeSurface.patch.sha256 must be a sha256 digest");
|
|
1963
|
-
}
|
|
1964
|
-
if (!Number.isSafeInteger(patch.byteLength) || patch.byteLength < 0) {
|
|
1965
|
-
throw new TypeError("CodeSurface.patch.byteLength must be a non-negative safe integer");
|
|
1966
|
-
}
|
|
1967
|
-
}
|
|
1968
|
-
function codeSurfaceIdentityMaterial(surface) {
|
|
1969
|
-
assertCodeSurfaceIdentity(surface);
|
|
1970
|
-
return JSON.stringify({
|
|
1971
|
-
schema: "tangle.code-surface.v1",
|
|
1972
|
-
baseCommit: surface.baseCommit,
|
|
1973
|
-
baseTree: surface.baseTree,
|
|
1974
|
-
candidateTree: surface.candidateTree,
|
|
1975
|
-
patch: {
|
|
1976
|
-
format: surface.patch.format,
|
|
1977
|
-
sha256: surface.patch.sha256,
|
|
1978
|
-
byteLength: surface.patch.byteLength
|
|
2053
|
+
const expected = new Set(expectedCellIds);
|
|
2054
|
+
for (const cell of cells) {
|
|
2055
|
+
if (!expected.has(cell.cellId)) {
|
|
2056
|
+
unscorableCells.push({ cellId: cell.cellId, reason: "unexpected campaign cell" });
|
|
1979
2057
|
}
|
|
1980
|
-
}
|
|
2058
|
+
}
|
|
2059
|
+
return {
|
|
2060
|
+
complete: unscorableCells.length === 0 && scorableCellIds.length === expectedCellIds.length,
|
|
2061
|
+
expectedCellIds,
|
|
2062
|
+
scorableCellIds,
|
|
2063
|
+
unscorableCells
|
|
2064
|
+
};
|
|
1981
2065
|
}
|
|
1982
|
-
function
|
|
1983
|
-
const
|
|
1984
|
-
|
|
2066
|
+
function formatCoverageFailures(coverage) {
|
|
2067
|
+
const shown = coverage.unscorableCells.slice(0, 3).map((cell) => `${cell.cellId}: ${cell.reason}`).join("; ");
|
|
2068
|
+
const remainder = coverage.unscorableCells.length - Math.min(3, coverage.unscorableCells.length);
|
|
2069
|
+
return remainder > 0 ? `${shown}; +${remainder} more` : shown || "unknown coverage failure";
|
|
1985
2070
|
}
|
|
1986
|
-
function
|
|
1987
|
-
|
|
2071
|
+
function designedCellIds(scenarios, reps) {
|
|
2072
|
+
const ids = [];
|
|
2073
|
+
for (const scenario of scenarios) {
|
|
2074
|
+
for (let rep = 0; rep < reps; rep++) ids.push(`${scenario.id}:${rep}`);
|
|
2075
|
+
}
|
|
2076
|
+
return ids;
|
|
1988
2077
|
}
|
|
1989
2078
|
|
|
1990
2079
|
// src/campaign/presets/run-optimization.ts
|
|
1991
2080
|
async function runOptimization(opts) {
|
|
1992
2081
|
const { proposer } = opts;
|
|
1993
|
-
const promoteTopK = opts.promoteTopK ?? 2;
|
|
1994
2082
|
if (typeof opts.runDir !== "string" || opts.runDir.trim().length === 0) {
|
|
1995
2083
|
throw new Error("runOptimization: runDir is required and must be a non-empty string");
|
|
1996
2084
|
}
|
|
2085
|
+
if (opts.promoteTopK !== void 0 && opts.promoteTopK !== 1) {
|
|
2086
|
+
throw new Error(
|
|
2087
|
+
"runOptimization: promoteTopK must be 1 because the loop has one global incumbent"
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
1997
2090
|
const baselineCampaign = await runCampaign({
|
|
1998
2091
|
...opts,
|
|
1999
2092
|
dispatch: (scenario, ctx) => opts.dispatchWithSurface(opts.baselineSurface, scenario, ctx),
|
|
2000
2093
|
runDir: `${opts.runDir}/baseline`
|
|
2001
2094
|
});
|
|
2095
|
+
const requireJudgeScore = (opts.judges?.length ?? 0) > 0;
|
|
2096
|
+
const baselineCoverage = campaignCoverage(
|
|
2097
|
+
baselineCampaign.cells,
|
|
2098
|
+
opts.scenarios,
|
|
2099
|
+
opts.reps ?? 1,
|
|
2100
|
+
requireJudgeScore
|
|
2101
|
+
);
|
|
2102
|
+
if (!baselineCoverage.complete) {
|
|
2103
|
+
throw new Error(
|
|
2104
|
+
`runOptimization: baseline is incomplete (${baselineCoverage.scorableCellIds.length}/${baselineCoverage.expectedCellIds.length} designed cells scorable) \u2014 ${formatCoverageFailures(baselineCoverage)}. Refusing to optimize against an incomplete incumbent.`
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2002
2107
|
const generations = [];
|
|
2003
2108
|
const history = [];
|
|
2004
2109
|
let currentFindings = opts.findings ?? [];
|
|
2005
|
-
let currentSurfaces = [opts.baselineSurface];
|
|
2006
2110
|
let winnerSurface = opts.baselineSurface;
|
|
2007
2111
|
let winnerSurfaceHash = surfaceHash(opts.baselineSurface);
|
|
2008
2112
|
let winnerComposite = campaignMeanComposite(baselineCampaign);
|
|
2113
|
+
const baselineOutcome = toScoredSurfaceOutcome(
|
|
2114
|
+
winnerSurfaceHash,
|
|
2115
|
+
baselineCampaign,
|
|
2116
|
+
baselineCoverage,
|
|
2117
|
+
-1
|
|
2118
|
+
);
|
|
2119
|
+
let winnerOutcome = baselineOutcome;
|
|
2009
2120
|
let winnerLabel;
|
|
2010
2121
|
let winnerRationale;
|
|
2011
2122
|
const scored = [
|
|
@@ -2025,13 +2136,20 @@ async function runOptimization(opts) {
|
|
|
2025
2136
|
for (let gen = 0; gen < opts.maxGenerations; gen++) {
|
|
2026
2137
|
if (proposer.decide?.({ history }).stop) break;
|
|
2027
2138
|
const paretoParents = computeParetoFrontier(scored);
|
|
2139
|
+
const parentSurfaceHash = winnerSurfaceHash;
|
|
2140
|
+
const parentComposite = winnerComposite;
|
|
2028
2141
|
const proposed = await proposer.propose({
|
|
2029
|
-
|
|
2142
|
+
// The mutation anchor is always the best complete surface seen across the
|
|
2143
|
+
// whole run. Exploratory losers remain in history/Pareto evidence, but a
|
|
2144
|
+
// later generation never compounds a candidate already known to regress.
|
|
2145
|
+
currentSurface: winnerSurface,
|
|
2030
2146
|
history,
|
|
2031
2147
|
findings: currentFindings,
|
|
2032
2148
|
populationSize: opts.populationSize,
|
|
2033
2149
|
generation: gen,
|
|
2034
2150
|
signal: new AbortController().signal,
|
|
2151
|
+
baselineOutcome,
|
|
2152
|
+
incumbentOutcome: winnerOutcome,
|
|
2035
2153
|
report: opts.report,
|
|
2036
2154
|
dataset: opts.labeledStore && opts.labeledStore !== "off" ? opts.labeledStore : void 0,
|
|
2037
2155
|
maxImprovementShots: opts.maxImprovementShots,
|
|
@@ -2042,7 +2160,7 @@ async function runOptimization(opts) {
|
|
|
2042
2160
|
);
|
|
2043
2161
|
const surfaceResults = [];
|
|
2044
2162
|
for (let i = 0; i < candidates.length; i++) {
|
|
2045
|
-
const { surface, label, rationale } = candidates[i];
|
|
2163
|
+
const { surface, label, rationale, candidateRecord } = candidates[i];
|
|
2046
2164
|
const hash = surfaceHash(surface);
|
|
2047
2165
|
const campaign = await runCampaign({
|
|
2048
2166
|
...opts,
|
|
@@ -2050,21 +2168,43 @@ async function runOptimization(opts) {
|
|
|
2050
2168
|
runDir: `${opts.runDir}/gen-${gen}/candidate-${i}`
|
|
2051
2169
|
});
|
|
2052
2170
|
const composite = campaignMeanComposite(campaign);
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2171
|
+
const coverage = campaignCoverage(
|
|
2172
|
+
campaign.cells,
|
|
2173
|
+
opts.scenarios,
|
|
2174
|
+
opts.reps ?? 1,
|
|
2175
|
+
requireJudgeScore
|
|
2056
2176
|
);
|
|
2177
|
+
surfaceResults.push({
|
|
2178
|
+
surfaceHash: hash,
|
|
2179
|
+
surface,
|
|
2180
|
+
label,
|
|
2181
|
+
rationale,
|
|
2182
|
+
...candidateRecord ? { candidateRecord } : {},
|
|
2183
|
+
campaign,
|
|
2184
|
+
composite,
|
|
2185
|
+
coverage
|
|
2186
|
+
});
|
|
2187
|
+
if (coverage.complete) {
|
|
2188
|
+
scored.push(
|
|
2189
|
+
toParetoParent(surface, hash, campaign, gen, label || void 0, rationale || void 0)
|
|
2190
|
+
);
|
|
2191
|
+
}
|
|
2057
2192
|
}
|
|
2058
|
-
surfaceResults.sort((a, b) =>
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2193
|
+
surfaceResults.sort((a, b) => {
|
|
2194
|
+
if (a.coverage.complete !== b.coverage.complete) return a.coverage.complete ? -1 : 1;
|
|
2195
|
+
return b.composite - a.composite;
|
|
2196
|
+
});
|
|
2197
|
+
const eligibleResults = surfaceResults.filter((result) => result.coverage.complete);
|
|
2198
|
+
const top = eligibleResults[0];
|
|
2199
|
+
const promoted = top && top.composite > winnerComposite ? [top] : [];
|
|
2200
|
+
if (promoted[0]) {
|
|
2201
|
+
const top2 = promoted[0];
|
|
2202
|
+
winnerSurface = top2.surface;
|
|
2203
|
+
winnerSurfaceHash = top2.surfaceHash;
|
|
2204
|
+
winnerComposite = top2.composite;
|
|
2205
|
+
winnerOutcome = toScoredSurfaceOutcome(top2.surfaceHash, top2.campaign, top2.coverage, gen);
|
|
2206
|
+
winnerLabel = top2.label || void 0;
|
|
2207
|
+
winnerRationale = top2.rationale || void 0;
|
|
2068
2208
|
}
|
|
2069
2209
|
const record = {
|
|
2070
2210
|
generationIndex: gen,
|
|
@@ -2074,11 +2214,21 @@ async function runOptimization(opts) {
|
|
|
2074
2214
|
surfaceHash: s.surfaceHash,
|
|
2075
2215
|
composite: s.composite,
|
|
2076
2216
|
ci95: [s.composite, s.composite],
|
|
2217
|
+
parentSurfaceHash,
|
|
2218
|
+
parentComposite,
|
|
2219
|
+
...s.coverage.complete ? { observedDeltaFromParent: s.composite - parentComposite } : {},
|
|
2220
|
+
eligibleForPromotion: s.coverage.complete,
|
|
2221
|
+
coverage: {
|
|
2222
|
+
expectedCells: s.coverage.expectedCellIds.length,
|
|
2223
|
+
scorableCells: s.coverage.scorableCellIds.length,
|
|
2224
|
+
unscorableCells: s.coverage.unscorableCells
|
|
2225
|
+
},
|
|
2077
2226
|
dimensions: breakdown.dimensions,
|
|
2078
2227
|
scenarios: breakdown.scenarios
|
|
2079
2228
|
};
|
|
2080
2229
|
if (s.label) candidate.label = s.label;
|
|
2081
2230
|
if (s.rationale) candidate.rationale = s.rationale;
|
|
2231
|
+
if (s.candidateRecord) candidate.candidateRecord = s.candidateRecord;
|
|
2082
2232
|
return candidate;
|
|
2083
2233
|
}),
|
|
2084
2234
|
promoted: promoted.map((p) => p.surfaceHash)
|
|
@@ -2156,6 +2306,21 @@ function computeParetoFrontier(scored) {
|
|
|
2156
2306
|
}));
|
|
2157
2307
|
return paretoFrontier(scored, objectives).frontier;
|
|
2158
2308
|
}
|
|
2309
|
+
function toScoredSurfaceOutcome(surfaceHash2, campaign, coverage, generation) {
|
|
2310
|
+
const breakdown = campaignBreakdown(campaign);
|
|
2311
|
+
return {
|
|
2312
|
+
split: "search",
|
|
2313
|
+
generation,
|
|
2314
|
+
surfaceHash: surfaceHash2,
|
|
2315
|
+
composite: campaignMeanComposite(campaign),
|
|
2316
|
+
dimensions: breakdown.dimensions,
|
|
2317
|
+
scenarios: breakdown.scenarios,
|
|
2318
|
+
coverage: {
|
|
2319
|
+
expectedCells: coverage.expectedCellIds.length,
|
|
2320
|
+
scorableCells: coverage.scorableCellIds.length
|
|
2321
|
+
}
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2159
2324
|
|
|
2160
2325
|
// src/campaign/presets/run-improvement-loop.ts
|
|
2161
2326
|
var DEFAULT_DISPATCH_TIMEOUT_MS = 6e5;
|
|
@@ -2200,15 +2365,23 @@ async function runImprovementLoop(opts) {
|
|
|
2200
2365
|
dispatch: (scenario, ctx) => opts.dispatchWithSurface(optimization.winnerSurface, scenario, ctx),
|
|
2201
2366
|
runDir: `${opts.runDir}/holdout-winner`
|
|
2202
2367
|
});
|
|
2203
|
-
const
|
|
2204
|
-
const
|
|
2205
|
-
const
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2368
|
+
const requireJudgeScore = (opts.judges?.length ?? 0) > 0;
|
|
2369
|
+
const reps = opts.reps ?? 1;
|
|
2370
|
+
const assertCompleteHoldout = (arm, campaign) => {
|
|
2371
|
+
const coverage = campaignCoverage(
|
|
2372
|
+
campaign.cells,
|
|
2373
|
+
opts.holdoutScenarios,
|
|
2374
|
+
reps,
|
|
2375
|
+
requireJudgeScore
|
|
2210
2376
|
);
|
|
2211
|
-
|
|
2377
|
+
if (!coverage.complete) {
|
|
2378
|
+
throw new Error(
|
|
2379
|
+
`runImprovementLoop: ${arm} holdout is incomplete (${coverage.scorableCellIds.length}/${coverage.expectedCellIds.length} designed cells scorable) \u2014 ${formatCoverageFailures(coverage)}. Refusing to compare unequal holdout results.`
|
|
2380
|
+
);
|
|
2381
|
+
}
|
|
2382
|
+
};
|
|
2383
|
+
assertCompleteHoldout("baseline", baselineOnHoldout);
|
|
2384
|
+
assertCompleteHoldout("winner", winnerOnHoldout);
|
|
2212
2385
|
const candidateArtifacts = /* @__PURE__ */ new Map();
|
|
2213
2386
|
const baselineArtifacts = /* @__PURE__ */ new Map();
|
|
2214
2387
|
const judgeScores = /* @__PURE__ */ new Map();
|
|
@@ -2232,6 +2405,7 @@ async function runImprovementLoop(opts) {
|
|
|
2232
2405
|
dispatch: (scenario, ctx) => opts.dispatchWithSurface(neutralizedSurface, scenario, ctx),
|
|
2233
2406
|
runDir: `${opts.runDir}/holdout-neutralized`
|
|
2234
2407
|
});
|
|
2408
|
+
assertCompleteHoldout("neutralized", neutralizedOnHoldout);
|
|
2235
2409
|
neutralizedArtifacts = /* @__PURE__ */ new Map();
|
|
2236
2410
|
neutralizedJudgeScores = /* @__PURE__ */ new Map();
|
|
2237
2411
|
for (const cell of neutralizedOnHoldout.cells) {
|
|
@@ -2335,28 +2509,103 @@ function meanHoldoutComposite(campaign) {
|
|
|
2335
2509
|
function buildLoopProvenanceRecord(args) {
|
|
2336
2510
|
const integrity = summarizeBackendIntegrity(args.workerRecords);
|
|
2337
2511
|
const models = [...new Set(args.workerRecords.map((r) => r.model))].sort();
|
|
2512
|
+
if (!Number.isFinite(args.baselineSearchComposite)) {
|
|
2513
|
+
throw new Error("buildLoopProvenanceRecord: baselineSearchComposite must be finite");
|
|
2514
|
+
}
|
|
2338
2515
|
const candidates = [];
|
|
2516
|
+
let incumbentSurfaceHash = surfaceHash(args.baselineSurface);
|
|
2517
|
+
let incumbentComposite = args.baselineSearchComposite;
|
|
2518
|
+
let previousGeneration = -1;
|
|
2339
2519
|
for (const gen of args.generations) {
|
|
2520
|
+
if (!Number.isSafeInteger(gen.generationIndex) || gen.generationIndex <= previousGeneration) {
|
|
2521
|
+
throw new Error(
|
|
2522
|
+
"buildLoopProvenanceRecord: generation indices must be strictly increasing integers"
|
|
2523
|
+
);
|
|
2524
|
+
}
|
|
2525
|
+
previousGeneration = gen.generationIndex;
|
|
2526
|
+
if (new Set(gen.promoted).size !== gen.promoted.length || gen.promoted.length > 1) {
|
|
2527
|
+
throw new Error(
|
|
2528
|
+
"buildLoopProvenanceRecord: each generation may promote at most one candidate"
|
|
2529
|
+
);
|
|
2530
|
+
}
|
|
2340
2531
|
const promotedSet = new Set(gen.promoted);
|
|
2341
2532
|
const surfaceByHash = new Map(gen.surfaces.map((s) => [s.surfaceHash, s.surface]));
|
|
2533
|
+
const candidateByHash = new Map(
|
|
2534
|
+
gen.candidates.map((candidate) => [candidate.surfaceHash, candidate])
|
|
2535
|
+
);
|
|
2536
|
+
if (candidateByHash.size !== gen.candidates.length) {
|
|
2537
|
+
throw new Error("buildLoopProvenanceRecord: duplicate candidate surface hash");
|
|
2538
|
+
}
|
|
2539
|
+
if (surfaceByHash.size !== gen.surfaces.length) {
|
|
2540
|
+
throw new Error("buildLoopProvenanceRecord: duplicate candidate surface entry");
|
|
2541
|
+
}
|
|
2542
|
+
if (surfaceByHash.size !== candidateByHash.size) {
|
|
2543
|
+
throw new Error(
|
|
2544
|
+
"buildLoopProvenanceRecord: every measured candidate requires exactly one surface"
|
|
2545
|
+
);
|
|
2546
|
+
}
|
|
2547
|
+
for (const promotedHash2 of promotedSet) {
|
|
2548
|
+
if (!candidateByHash.has(promotedHash2)) {
|
|
2549
|
+
throw new Error("buildLoopProvenanceRecord: promoted hash has no measured candidate");
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2342
2552
|
for (const c of gen.candidates) {
|
|
2553
|
+
validateCandidateMeasurement(
|
|
2554
|
+
c,
|
|
2555
|
+
incumbentSurfaceHash,
|
|
2556
|
+
incumbentComposite,
|
|
2557
|
+
promotedSet.has(c.surfaceHash)
|
|
2558
|
+
);
|
|
2343
2559
|
const surface = surfaceByHash.get(c.surfaceHash);
|
|
2560
|
+
if (surface === void 0) {
|
|
2561
|
+
throw new Error("buildLoopProvenanceRecord: measured candidate is missing its surface");
|
|
2562
|
+
}
|
|
2563
|
+
if (surfaceHash(surface) !== c.surfaceHash) {
|
|
2564
|
+
throw new Error(
|
|
2565
|
+
"buildLoopProvenanceRecord: candidate surface hash does not match its surface bytes"
|
|
2566
|
+
);
|
|
2567
|
+
}
|
|
2344
2568
|
const entry = {
|
|
2345
2569
|
generation: gen.generationIndex,
|
|
2346
2570
|
surfaceHash: c.surfaceHash,
|
|
2347
|
-
contentHash:
|
|
2571
|
+
contentHash: surfaceContentHash(surface),
|
|
2572
|
+
parentSurfaceHash: c.parentSurfaceHash,
|
|
2573
|
+
parentComposite: c.parentComposite,
|
|
2574
|
+
eligibleForPromotion: c.eligibleForPromotion,
|
|
2575
|
+
coverage: {
|
|
2576
|
+
expectedCells: c.coverage.expectedCells,
|
|
2577
|
+
scorableCells: c.coverage.scorableCells,
|
|
2578
|
+
unscorableCells: c.coverage.unscorableCells.map((cell) => ({ ...cell }))
|
|
2579
|
+
},
|
|
2348
2580
|
composite: c.composite,
|
|
2349
2581
|
promoted: promotedSet.has(c.surfaceHash)
|
|
2350
2582
|
};
|
|
2351
2583
|
if (c.label) entry.label = c.label;
|
|
2352
2584
|
if (c.rationale) entry.rationale = c.rationale;
|
|
2585
|
+
if (c.candidateRecord) {
|
|
2586
|
+
entry.candidateRecord = validatePolicyEditCandidateRecord(c.candidateRecord);
|
|
2587
|
+
}
|
|
2588
|
+
if (c.observedDeltaFromParent !== void 0) {
|
|
2589
|
+
entry.observedDeltaFromParent = c.observedDeltaFromParent;
|
|
2590
|
+
}
|
|
2353
2591
|
candidates.push(entry);
|
|
2354
2592
|
}
|
|
2593
|
+
const promotedHash = gen.promoted[0];
|
|
2594
|
+
if (promotedHash) {
|
|
2595
|
+
const promoted = candidateByHash.get(promotedHash);
|
|
2596
|
+
incumbentSurfaceHash = promoted.surfaceHash;
|
|
2597
|
+
incumbentComposite = promoted.composite;
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
if (surfaceHash(args.winnerSurface) !== incumbentSurfaceHash) {
|
|
2601
|
+
throw new Error(
|
|
2602
|
+
"buildLoopProvenanceRecord: winner surface does not match the final promoted incumbent"
|
|
2603
|
+
);
|
|
2355
2604
|
}
|
|
2356
2605
|
const baselineHoldoutComposite = meanHoldoutComposite(args.baselineOnHoldout);
|
|
2357
2606
|
const winnerHoldoutComposite = meanHoldoutComposite(args.winnerOnHoldout);
|
|
2358
2607
|
const record = {
|
|
2359
|
-
schema: "tangle.loop-provenance.
|
|
2608
|
+
schema: "tangle.loop-provenance.v3",
|
|
2360
2609
|
runId: args.runId,
|
|
2361
2610
|
runDir: args.runDir,
|
|
2362
2611
|
timestamp: args.timestamp,
|
|
@@ -2364,6 +2613,7 @@ function buildLoopProvenanceRecord(args) {
|
|
|
2364
2613
|
winnerContentHash: surfaceContentHash(args.winnerSurface),
|
|
2365
2614
|
diff: args.diff,
|
|
2366
2615
|
candidates,
|
|
2616
|
+
baselineSearchComposite: args.baselineSearchComposite,
|
|
2367
2617
|
gate: {
|
|
2368
2618
|
decision: args.gate.decision,
|
|
2369
2619
|
reasons: args.gate.reasons,
|
|
@@ -2391,6 +2641,77 @@ function buildLoopProvenanceRecord(args) {
|
|
|
2391
2641
|
if (args.winnerRationale) record.winnerRationale = args.winnerRationale;
|
|
2392
2642
|
return record;
|
|
2393
2643
|
}
|
|
2644
|
+
function validateCandidateMeasurement(candidate, expectedParentHash, expectedParentComposite, promoted) {
|
|
2645
|
+
if (!Number.isFinite(candidate.composite)) {
|
|
2646
|
+
throw new Error("buildLoopProvenanceRecord: candidate composite must be finite");
|
|
2647
|
+
}
|
|
2648
|
+
if (!candidate.parentSurfaceHash || !/^[a-f0-9]{16}$/.test(candidate.parentSurfaceHash)) {
|
|
2649
|
+
throw new Error(
|
|
2650
|
+
"buildLoopProvenanceRecord: parentSurfaceHash must be 16 lowercase hex characters"
|
|
2651
|
+
);
|
|
2652
|
+
}
|
|
2653
|
+
if (candidate.parentSurfaceHash !== expectedParentHash) {
|
|
2654
|
+
throw new Error("buildLoopProvenanceRecord: candidate parent does not match the incumbent");
|
|
2655
|
+
}
|
|
2656
|
+
if (candidate.parentComposite === void 0 || !Number.isFinite(candidate.parentComposite) || Math.abs(candidate.parentComposite - expectedParentComposite) > 1e-12) {
|
|
2657
|
+
throw new Error(
|
|
2658
|
+
"buildLoopProvenanceRecord: candidate parentComposite does not match the incumbent"
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2661
|
+
if (candidate.eligibleForPromotion === void 0 || !candidate.coverage) {
|
|
2662
|
+
throw new Error(
|
|
2663
|
+
"buildLoopProvenanceRecord: candidate measurement requires eligibility and coverage"
|
|
2664
|
+
);
|
|
2665
|
+
}
|
|
2666
|
+
if (candidate.observedDeltaFromParent !== void 0) {
|
|
2667
|
+
if (!Number.isFinite(candidate.observedDeltaFromParent)) {
|
|
2668
|
+
throw new Error("buildLoopProvenanceRecord: observedDeltaFromParent must be finite");
|
|
2669
|
+
}
|
|
2670
|
+
if (candidate.eligibleForPromotion !== true) {
|
|
2671
|
+
throw new Error(
|
|
2672
|
+
"buildLoopProvenanceRecord: observedDeltaFromParent requires a complete eligible candidate and parentSurfaceHash"
|
|
2673
|
+
);
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
const coverage = candidate.coverage;
|
|
2677
|
+
if (!Number.isSafeInteger(coverage.expectedCells) || coverage.expectedCells <= 0 || !Number.isSafeInteger(coverage.scorableCells) || coverage.scorableCells < 0 || coverage.scorableCells > coverage.expectedCells) {
|
|
2678
|
+
throw new Error("buildLoopProvenanceRecord: invalid candidate coverage denominator");
|
|
2679
|
+
}
|
|
2680
|
+
const unscorableIds = /* @__PURE__ */ new Set();
|
|
2681
|
+
for (const failure of coverage.unscorableCells) {
|
|
2682
|
+
if (typeof failure.cellId !== "string" || failure.cellId.length === 0 || typeof failure.reason !== "string" || failure.reason.length === 0 || unscorableIds.has(failure.cellId)) {
|
|
2683
|
+
throw new Error("buildLoopProvenanceRecord: invalid candidate coverage failures");
|
|
2684
|
+
}
|
|
2685
|
+
unscorableIds.add(failure.cellId);
|
|
2686
|
+
}
|
|
2687
|
+
if (coverage.expectedCells - coverage.scorableCells !== coverage.unscorableCells.length) {
|
|
2688
|
+
throw new Error(
|
|
2689
|
+
"buildLoopProvenanceRecord: candidate coverage counts do not match its failures"
|
|
2690
|
+
);
|
|
2691
|
+
}
|
|
2692
|
+
const complete = coverage.scorableCells === coverage.expectedCells && coverage.unscorableCells.length === 0;
|
|
2693
|
+
if (candidate.eligibleForPromotion !== void 0 && candidate.eligibleForPromotion !== complete) {
|
|
2694
|
+
throw new Error(
|
|
2695
|
+
"buildLoopProvenanceRecord: candidate eligibility contradicts its coverage receipt"
|
|
2696
|
+
);
|
|
2697
|
+
}
|
|
2698
|
+
if (complete) {
|
|
2699
|
+
if (candidate.observedDeltaFromParent === void 0) {
|
|
2700
|
+
throw new Error(
|
|
2701
|
+
"buildLoopProvenanceRecord: complete candidate is missing observedDeltaFromParent"
|
|
2702
|
+
);
|
|
2703
|
+
}
|
|
2704
|
+
const recomputed = candidate.composite - candidate.parentComposite;
|
|
2705
|
+
if (Math.abs(candidate.observedDeltaFromParent - recomputed) > 1e-12) {
|
|
2706
|
+
throw new Error("buildLoopProvenanceRecord: observed delta does not match measured scores");
|
|
2707
|
+
}
|
|
2708
|
+
} else if (candidate.observedDeltaFromParent !== void 0) {
|
|
2709
|
+
throw new Error("buildLoopProvenanceRecord: incomplete candidate cannot carry observed delta");
|
|
2710
|
+
}
|
|
2711
|
+
if (promoted && (!complete || (candidate.observedDeltaFromParent ?? 0) <= 0)) {
|
|
2712
|
+
throw new Error("buildLoopProvenanceRecord: promoted candidate must improve the incumbent");
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2394
2715
|
var DECISION_OK = ["ship"];
|
|
2395
2716
|
function hashId(parts) {
|
|
2396
2717
|
return createHash2("sha256").update(parts.join(":")).digest("hex");
|
|
@@ -2415,6 +2736,7 @@ function loopProvenanceSpans(record, opts = {}) {
|
|
|
2415
2736
|
"tangle.runDir": record.runDir,
|
|
2416
2737
|
"tangle.baselineContentHash": record.baselineContentHash,
|
|
2417
2738
|
"tangle.winnerContentHash": record.winnerContentHash,
|
|
2739
|
+
"tangle.baselineSearchComposite": record.baselineSearchComposite,
|
|
2418
2740
|
"tangle.heldOutLift": record.heldOutLift,
|
|
2419
2741
|
"tangle.gateDecision": record.gate.decision,
|
|
2420
2742
|
"tangle.backendVerdict": record.backend.verdict,
|
|
@@ -2432,7 +2754,7 @@ function loopProvenanceSpans(record, opts = {}) {
|
|
|
2432
2754
|
}
|
|
2433
2755
|
for (const [generation, cands] of [...byGen.entries()].sort((a, b) => a[0] - b[0])) {
|
|
2434
2756
|
const genSpanId = hashId(["gen", record.runId, String(generation)]).slice(0, 16);
|
|
2435
|
-
const bestComposite = cands.
|
|
2757
|
+
const bestComposite = Math.max(...cands.map((candidate) => candidate.composite));
|
|
2436
2758
|
spans.push({
|
|
2437
2759
|
traceId,
|
|
2438
2760
|
spanId: genSpanId,
|
|
@@ -2460,9 +2782,21 @@ function loopProvenanceSpans(record, opts = {}) {
|
|
|
2460
2782
|
"tangle.generation": generation,
|
|
2461
2783
|
"tangle.surfaceHash": c.surfaceHash,
|
|
2462
2784
|
"tangle.contentHash": c.contentHash,
|
|
2785
|
+
"tangle.parentSurfaceHash": c.parentSurfaceHash,
|
|
2786
|
+
"tangle.parentComposite": c.parentComposite,
|
|
2463
2787
|
"tangle.composite": c.composite,
|
|
2788
|
+
"tangle.eligibleForPromotion": c.eligibleForPromotion,
|
|
2789
|
+
"tangle.expectedCells": c.coverage.expectedCells,
|
|
2790
|
+
"tangle.scorableCells": c.coverage.scorableCells,
|
|
2791
|
+
"tangle.unscorableCells": c.coverage.unscorableCells.length,
|
|
2464
2792
|
"tangle.promoted": c.promoted
|
|
2465
2793
|
};
|
|
2794
|
+
if (c.observedDeltaFromParent !== void 0) {
|
|
2795
|
+
attributes["tangle.observedDeltaFromParent"] = c.observedDeltaFromParent;
|
|
2796
|
+
}
|
|
2797
|
+
if (c.candidateRecord) {
|
|
2798
|
+
attributes["tangle.policyEditId"] = c.candidateRecord.policyEdit.editId;
|
|
2799
|
+
}
|
|
2466
2800
|
if (c.label) attributes["tangle.candidateLabel"] = c.label;
|
|
2467
2801
|
if (c.rationale) attributes["tangle.candidateRationale"] = c.rationale;
|
|
2468
2802
|
spans.push({
|
|
@@ -2613,15 +2947,15 @@ export {
|
|
|
2613
2947
|
buildReflectionPrompt,
|
|
2614
2948
|
renderAnalystEvidence,
|
|
2615
2949
|
parseReflectionResponse,
|
|
2950
|
+
assertCodeSurfaceIdentity,
|
|
2951
|
+
codeSurfaceIdentityMaterial,
|
|
2952
|
+
surfaceContentHash,
|
|
2953
|
+
surfaceHash,
|
|
2616
2954
|
gepaProposer,
|
|
2617
2955
|
extractH2Sections,
|
|
2618
2956
|
countSentenceEdits,
|
|
2619
2957
|
campaignMeanComposite,
|
|
2620
2958
|
campaignBreakdown,
|
|
2621
|
-
assertCodeSurfaceIdentity,
|
|
2622
|
-
codeSurfaceIdentityMaterial,
|
|
2623
|
-
surfaceContentHash,
|
|
2624
|
-
surfaceHash,
|
|
2625
2959
|
runOptimization,
|
|
2626
2960
|
runImprovementLoop,
|
|
2627
2961
|
defaultRenderDiff,
|
|
@@ -2633,4 +2967,4 @@ export {
|
|
|
2633
2967
|
provenanceSpansPath,
|
|
2634
2968
|
emitLoopProvenance
|
|
2635
2969
|
};
|
|
2636
|
-
//# sourceMappingURL=chunk-
|
|
2970
|
+
//# sourceMappingURL=chunk-3274WNK7.js.map
|