@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,9 +2,18 @@ import {
|
|
|
2
2
|
TraceFileMissingError,
|
|
3
3
|
buildTraceAnalystTools
|
|
4
4
|
} from "./chunk-LNQEP766.js";
|
|
5
|
+
import {
|
|
6
|
+
validateAgentProfileCell
|
|
7
|
+
} from "./chunk-XJYR7XFV.js";
|
|
8
|
+
import {
|
|
9
|
+
canonicalize
|
|
10
|
+
} from "./chunk-VSMTAMNK.js";
|
|
5
11
|
import {
|
|
6
12
|
callLlm
|
|
7
13
|
} from "./chunk-GY4SYVPJ.js";
|
|
14
|
+
import {
|
|
15
|
+
ValidationError
|
|
16
|
+
} from "./chunk-ONWEPEDO.js";
|
|
8
17
|
|
|
9
18
|
// src/analyst/types.ts
|
|
10
19
|
import { createHash } from "crypto";
|
|
@@ -1119,6 +1128,724 @@ function selectPriorFindings(source, analystId) {
|
|
|
1119
1128
|
return merged.length > 0 ? merged : void 0;
|
|
1120
1129
|
}
|
|
1121
1130
|
|
|
1131
|
+
// src/analyst/steer-firewall.ts
|
|
1132
|
+
var OBSERVABLE_KINDS = /* @__PURE__ */ new Set([
|
|
1133
|
+
"span",
|
|
1134
|
+
"event",
|
|
1135
|
+
"artifact"
|
|
1136
|
+
]);
|
|
1137
|
+
function isTraceObservable(finding) {
|
|
1138
|
+
return finding.evidence_refs.some((ref) => OBSERVABLE_KINDS.has(ref.kind));
|
|
1139
|
+
}
|
|
1140
|
+
function isJudgeVerdict(finding) {
|
|
1141
|
+
return finding.derived_from_judge === true;
|
|
1142
|
+
}
|
|
1143
|
+
function assertNoJudgeVerdict(findings, context = "steer") {
|
|
1144
|
+
const leaks = findings.filter(isJudgeVerdict);
|
|
1145
|
+
if (leaks.length > 0) {
|
|
1146
|
+
throw new Error(
|
|
1147
|
+
`${context}: a judge verdict cannot be admitted as steering input \u2014 that is the held-out judge leaking into the loop. Offending judge-derived findings: [${leaks.map((f) => f.finding_id).join(", ")}]. Steering consumes observations of behavior, never acceptance verdicts.`
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
return findings;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
// src/analyst/policy-edit.ts
|
|
1154
|
+
import { createHash as createHash2 } from "crypto";
|
|
1155
|
+
var POLICY_EDIT_AXES = [
|
|
1156
|
+
"carrier",
|
|
1157
|
+
"representation",
|
|
1158
|
+
"budget",
|
|
1159
|
+
"sampling",
|
|
1160
|
+
"output_contract",
|
|
1161
|
+
"tool_contract",
|
|
1162
|
+
"routing",
|
|
1163
|
+
"memory",
|
|
1164
|
+
"agent_profile",
|
|
1165
|
+
"deployment_target"
|
|
1166
|
+
];
|
|
1167
|
+
var POLICY_EDIT_TARGET_SURFACES = [
|
|
1168
|
+
"prompt",
|
|
1169
|
+
"tool-contract",
|
|
1170
|
+
"runtime-config",
|
|
1171
|
+
"memory",
|
|
1172
|
+
"agent-profile",
|
|
1173
|
+
"code",
|
|
1174
|
+
"deployment"
|
|
1175
|
+
];
|
|
1176
|
+
var POLICY_EDIT_CANDIDATE_RECORD_SCHEMA = "tangle.policy-edit-candidate.v1";
|
|
1177
|
+
var PolicyEditValidationError = class extends ValidationError {
|
|
1178
|
+
path;
|
|
1179
|
+
constructor(message, path = "") {
|
|
1180
|
+
super(path ? `${message} (at ${path})` : message);
|
|
1181
|
+
this.path = path;
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
var DEFAULT_MIN_SCORE = 0.7;
|
|
1185
|
+
var DEFAULT_MIN_EXPECTED_GAIN = 0.01;
|
|
1186
|
+
var POLICY_EDIT_ID = /^policy-edit:sha256:[0-9a-f]{64}$/;
|
|
1187
|
+
function makePolicyEdit(init) {
|
|
1188
|
+
const normalized = normalizePolicyEdit({
|
|
1189
|
+
schemaVersion: "policy-edit/v1",
|
|
1190
|
+
...init,
|
|
1191
|
+
source: normalizeSource(init.source)
|
|
1192
|
+
});
|
|
1193
|
+
const edit = {
|
|
1194
|
+
...normalized,
|
|
1195
|
+
editId: init.editId ?? computePolicyEditId(normalized)
|
|
1196
|
+
};
|
|
1197
|
+
return validatePolicyEdit(edit);
|
|
1198
|
+
}
|
|
1199
|
+
function computePolicyEditId(edit) {
|
|
1200
|
+
const { editId: _editId, schemaVersion, ...material } = edit;
|
|
1201
|
+
void _editId;
|
|
1202
|
+
const canonical = JSON.stringify(canonicalize({ schemaVersion, ...material }));
|
|
1203
|
+
return `policy-edit:sha256:${createHash2("sha256").update(canonical).digest("hex")}`;
|
|
1204
|
+
}
|
|
1205
|
+
function validatePolicyEdit(input) {
|
|
1206
|
+
if (input === null || typeof input !== "object") {
|
|
1207
|
+
throw new PolicyEditValidationError("expected object");
|
|
1208
|
+
}
|
|
1209
|
+
const obj = input;
|
|
1210
|
+
expectLiteral(obj.schemaVersion, "policy-edit/v1", "schemaVersion");
|
|
1211
|
+
expectString(obj.editId, "editId");
|
|
1212
|
+
if (!POLICY_EDIT_ID.test(obj.editId)) {
|
|
1213
|
+
throw new PolicyEditValidationError(
|
|
1214
|
+
"editId must match policy-edit:sha256:<64 lowercase hex chars>",
|
|
1215
|
+
"editId"
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
expectOneOf(obj.axis, POLICY_EDIT_AXES, "axis");
|
|
1219
|
+
validateTarget(obj.target);
|
|
1220
|
+
validateChange(obj.change);
|
|
1221
|
+
expectString(obj.claim, "claim");
|
|
1222
|
+
validateExpectedGain(obj.expectedGain);
|
|
1223
|
+
expectConfidence(obj.confidence, "confidence");
|
|
1224
|
+
expectOneOf(obj.risk, ["low", "medium", "high", "unknown"], "risk");
|
|
1225
|
+
validateSource(obj.source);
|
|
1226
|
+
if (obj.rationale !== void 0) expectString(obj.rationale, "rationale");
|
|
1227
|
+
if (obj.validationPlan !== void 0) expectString(obj.validationPlan, "validationPlan");
|
|
1228
|
+
if (obj.metadata !== void 0 && (obj.metadata === null || typeof obj.metadata !== "object")) {
|
|
1229
|
+
throw new PolicyEditValidationError("expected object", "metadata");
|
|
1230
|
+
}
|
|
1231
|
+
const expectedId = computePolicyEditId(obj);
|
|
1232
|
+
if (obj.editId !== expectedId) {
|
|
1233
|
+
throw new PolicyEditValidationError("editId does not match policy edit content", "editId");
|
|
1234
|
+
}
|
|
1235
|
+
return obj;
|
|
1236
|
+
}
|
|
1237
|
+
function makePolicyEditCandidateRecord(edit) {
|
|
1238
|
+
return validatePolicyEditCandidateRecord({
|
|
1239
|
+
schema: POLICY_EDIT_CANDIDATE_RECORD_SCHEMA,
|
|
1240
|
+
policyEdit: edit
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
function validatePolicyEditCandidateRecord(input) {
|
|
1244
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
1245
|
+
throw new PolicyEditValidationError("expected object", "candidateRecord");
|
|
1246
|
+
}
|
|
1247
|
+
const obj = input;
|
|
1248
|
+
const keys = Object.keys(obj).sort();
|
|
1249
|
+
if (keys.length !== 2 || keys[0] !== "policyEdit" || keys[1] !== "schema") {
|
|
1250
|
+
throw new PolicyEditValidationError("expected exactly schema and policyEdit", "candidateRecord");
|
|
1251
|
+
}
|
|
1252
|
+
expectLiteral(obj.schema, POLICY_EDIT_CANDIDATE_RECORD_SCHEMA, "candidateRecord.schema");
|
|
1253
|
+
const policyEdit = validatePolicyEdit(obj.policyEdit);
|
|
1254
|
+
assertJsonSafe(policyEdit, "candidateRecord.policyEdit");
|
|
1255
|
+
const snapshot = JSON.parse(JSON.stringify(policyEdit));
|
|
1256
|
+
return {
|
|
1257
|
+
schema: POLICY_EDIT_CANDIDATE_RECORD_SCHEMA,
|
|
1258
|
+
policyEdit: validatePolicyEdit(snapshot)
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
function isPolicyEdit(input) {
|
|
1262
|
+
try {
|
|
1263
|
+
validatePolicyEdit(input);
|
|
1264
|
+
return true;
|
|
1265
|
+
} catch {
|
|
1266
|
+
return false;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
function policyEditsFromFindings(findings, opts = {}) {
|
|
1270
|
+
assertNoJudgeVerdict(findings, "policyEditsFromFindings");
|
|
1271
|
+
const edits = [];
|
|
1272
|
+
for (const finding of findings) {
|
|
1273
|
+
const edit = policyEditFromFinding(finding, opts);
|
|
1274
|
+
if (edit) edits.push(edit);
|
|
1275
|
+
}
|
|
1276
|
+
return edits;
|
|
1277
|
+
}
|
|
1278
|
+
function policyEditFromFinding(finding, opts = {}) {
|
|
1279
|
+
assertNoJudgeVerdict([finding], "policyEditFromFinding");
|
|
1280
|
+
if (!finding.recommended_action?.trim()) return null;
|
|
1281
|
+
const expectedGain = resolveExpectedGain(finding, opts);
|
|
1282
|
+
if (!expectedGain) return null;
|
|
1283
|
+
const routed = routeFindingSubject(finding.subject, opts);
|
|
1284
|
+
const risk = resolveRisk(finding, opts);
|
|
1285
|
+
return makePolicyEdit({
|
|
1286
|
+
axis: routed.axis,
|
|
1287
|
+
target: routed.target,
|
|
1288
|
+
change: { kind: "text", mode: "append", value: finding.recommended_action.trim() },
|
|
1289
|
+
claim: finding.claim,
|
|
1290
|
+
rationale: finding.rationale,
|
|
1291
|
+
expectedGain,
|
|
1292
|
+
confidence: finding.confidence,
|
|
1293
|
+
risk,
|
|
1294
|
+
validationPlan: finding.validation_plan,
|
|
1295
|
+
source: {
|
|
1296
|
+
findingIds: [finding.finding_id],
|
|
1297
|
+
analystIds: [finding.analyst_id],
|
|
1298
|
+
evidenceRefs: finding.evidence_refs,
|
|
1299
|
+
derivedFromJudge: finding.derived_from_judge
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
function scorePolicyEditReadiness(edit, opts = {}) {
|
|
1304
|
+
validatePolicyEdit(edit);
|
|
1305
|
+
const minExpectedGain = opts.minExpectedGain ?? DEFAULT_MIN_EXPECTED_GAIN;
|
|
1306
|
+
const evidenceScore = Math.min(1, edit.source.evidenceRefs.length / 2);
|
|
1307
|
+
const confidenceScore = clamp01(edit.confidence);
|
|
1308
|
+
const gainScore = clamp01(
|
|
1309
|
+
Math.abs(edit.expectedGain.amount) / Math.max(minExpectedGain * 5, 1e-3)
|
|
1310
|
+
);
|
|
1311
|
+
const targetScore = targetSpecificityScore(edit);
|
|
1312
|
+
const riskPenalty = edit.risk === "high" && opts.allowHighRisk !== true ? 0.35 : edit.risk === "unknown" ? 0.2 : 0;
|
|
1313
|
+
return clamp01(
|
|
1314
|
+
0.3 * evidenceScore + 0.25 * confidenceScore + 0.25 * gainScore + 0.2 * targetScore - riskPenalty
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
function admitPolicyEdit(edit, opts = {}) {
|
|
1318
|
+
const validated = validatePolicyEdit(edit);
|
|
1319
|
+
const score = scorePolicyEditReadiness(validated, opts);
|
|
1320
|
+
const reasons = [];
|
|
1321
|
+
const minExpectedGain = opts.minExpectedGain ?? DEFAULT_MIN_EXPECTED_GAIN;
|
|
1322
|
+
const requireEvidence = opts.requireEvidence ?? true;
|
|
1323
|
+
if (validated.source.derivedFromJudge) {
|
|
1324
|
+
reasons.push("source is judge-derived; judge verdicts cannot steer policy edits");
|
|
1325
|
+
}
|
|
1326
|
+
if (requireEvidence && validated.source.evidenceRefs.length === 0) {
|
|
1327
|
+
reasons.push("missing evidence refs");
|
|
1328
|
+
}
|
|
1329
|
+
if (Math.abs(validated.expectedGain.amount) < minExpectedGain) {
|
|
1330
|
+
reasons.push(`expected gain below ${minExpectedGain}`);
|
|
1331
|
+
}
|
|
1332
|
+
if (validated.risk === "high" && opts.allowHighRisk !== true) {
|
|
1333
|
+
reasons.push("high-risk edit requires explicit allowHighRisk");
|
|
1334
|
+
}
|
|
1335
|
+
if (score < (opts.minScore ?? DEFAULT_MIN_SCORE)) {
|
|
1336
|
+
reasons.push(
|
|
1337
|
+
`readiness score ${score.toFixed(3)} below ${(opts.minScore ?? DEFAULT_MIN_SCORE).toFixed(3)}`
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
return {
|
|
1341
|
+
edit: validated,
|
|
1342
|
+
decision: reasons.length === 0 ? "admit" : "reject",
|
|
1343
|
+
score,
|
|
1344
|
+
reasons
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
function applyPolicyEditToSurface(surface, edit) {
|
|
1348
|
+
const validated = validatePolicyEdit(edit);
|
|
1349
|
+
if (validated.change.kind === "text") return applyTextChange(surface, validated.change);
|
|
1350
|
+
return applyJsonChange(surface, validated.change);
|
|
1351
|
+
}
|
|
1352
|
+
function routeFindingSubject(subject, opts) {
|
|
1353
|
+
const parsed = parseFindingSubject(subject);
|
|
1354
|
+
if (!parsed) {
|
|
1355
|
+
return {
|
|
1356
|
+
axis: opts.defaultAxis ?? "representation",
|
|
1357
|
+
target: { surface: opts.defaultTargetSurface ?? "prompt" }
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
return routeParsedSubject(parsed);
|
|
1361
|
+
}
|
|
1362
|
+
function routeParsedSubject(subject) {
|
|
1363
|
+
switch (subject.kind) {
|
|
1364
|
+
case "system-prompt":
|
|
1365
|
+
return {
|
|
1366
|
+
axis: "representation",
|
|
1367
|
+
target: { surface: "prompt", path: `system-prompt:${subject.section}` }
|
|
1368
|
+
};
|
|
1369
|
+
case "skill":
|
|
1370
|
+
return {
|
|
1371
|
+
axis: "agent_profile",
|
|
1372
|
+
target: { surface: "agent-profile", path: `skill:${subject.name}` }
|
|
1373
|
+
};
|
|
1374
|
+
case "tool-doc":
|
|
1375
|
+
return {
|
|
1376
|
+
axis: "tool_contract",
|
|
1377
|
+
target: {
|
|
1378
|
+
surface: "tool-contract",
|
|
1379
|
+
path: subject.aspect ? `tool-doc:${subject.tool}:${subject.aspect}` : `tool-doc:${subject.tool}`
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
case "new-tool":
|
|
1383
|
+
return {
|
|
1384
|
+
axis: "tool_contract",
|
|
1385
|
+
target: { surface: "tool-contract", path: `new-tool:${subject.name}` }
|
|
1386
|
+
};
|
|
1387
|
+
case "mcp":
|
|
1388
|
+
return {
|
|
1389
|
+
axis: "tool_contract",
|
|
1390
|
+
target: {
|
|
1391
|
+
surface: "agent-profile",
|
|
1392
|
+
path: subject.tool ? `mcp:${subject.server}:${subject.tool}` : `mcp:${subject.server}`
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
case "hook":
|
|
1396
|
+
return {
|
|
1397
|
+
axis: "agent_profile",
|
|
1398
|
+
target: { surface: "agent-profile", path: `hook:${subject.name}` }
|
|
1399
|
+
};
|
|
1400
|
+
case "subagent":
|
|
1401
|
+
return {
|
|
1402
|
+
axis: "routing",
|
|
1403
|
+
target: { surface: "agent-profile", path: `subagent:${subject.name}` }
|
|
1404
|
+
};
|
|
1405
|
+
case "workflow":
|
|
1406
|
+
return {
|
|
1407
|
+
axis: "routing",
|
|
1408
|
+
target: { surface: "runtime-config", path: `workflow:${subject.name}` }
|
|
1409
|
+
};
|
|
1410
|
+
case "rollout-policy":
|
|
1411
|
+
return {
|
|
1412
|
+
axis: rolloutPolicyAxis(subject.field),
|
|
1413
|
+
target: { surface: "runtime-config", path: `rollout-policy:${subject.field}` }
|
|
1414
|
+
};
|
|
1415
|
+
case "agent-profile":
|
|
1416
|
+
return {
|
|
1417
|
+
axis: "agent_profile",
|
|
1418
|
+
target: { surface: "agent-profile", path: `agent-profile:${subject.field}` }
|
|
1419
|
+
};
|
|
1420
|
+
case "code":
|
|
1421
|
+
return {
|
|
1422
|
+
axis: "representation",
|
|
1423
|
+
target: { surface: "code", path: `code:${subject.path}` }
|
|
1424
|
+
};
|
|
1425
|
+
case "rag":
|
|
1426
|
+
return {
|
|
1427
|
+
axis: "memory",
|
|
1428
|
+
target: { surface: "memory", path: `rag:${subject.corpus}:${subject.docId}` }
|
|
1429
|
+
};
|
|
1430
|
+
case "memory":
|
|
1431
|
+
return { axis: "memory", target: { surface: "memory", path: `memory:${subject.key}` } };
|
|
1432
|
+
case "scaffolding":
|
|
1433
|
+
return {
|
|
1434
|
+
axis: "routing",
|
|
1435
|
+
target: { surface: "runtime-config", path: `scaffolding:${subject.concern}` }
|
|
1436
|
+
};
|
|
1437
|
+
case "output-schema":
|
|
1438
|
+
return {
|
|
1439
|
+
axis: "output_contract",
|
|
1440
|
+
target: { surface: "runtime-config", path: `output-schema:${subject.field}` }
|
|
1441
|
+
};
|
|
1442
|
+
case "knowledge.wiki":
|
|
1443
|
+
return {
|
|
1444
|
+
axis: "memory",
|
|
1445
|
+
target: {
|
|
1446
|
+
surface: "memory",
|
|
1447
|
+
path: `agent-knowledge:wiki:${subject.slug}${subject.heading ? `#${subject.heading}` : ""}`
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1450
|
+
case "knowledge.claim":
|
|
1451
|
+
return {
|
|
1452
|
+
axis: "memory",
|
|
1453
|
+
target: { surface: "memory", path: `agent-knowledge:claim:${subject.topic}` }
|
|
1454
|
+
};
|
|
1455
|
+
case "knowledge.raw":
|
|
1456
|
+
return {
|
|
1457
|
+
axis: "memory",
|
|
1458
|
+
target: { surface: "memory", path: `agent-knowledge:raw:${subject.sourceId}` }
|
|
1459
|
+
};
|
|
1460
|
+
case "knowledge.stale":
|
|
1461
|
+
return {
|
|
1462
|
+
axis: "memory",
|
|
1463
|
+
target: { surface: "memory", path: `agent-knowledge:stale:${subject.slug}` }
|
|
1464
|
+
};
|
|
1465
|
+
case "websearch.outdated":
|
|
1466
|
+
return {
|
|
1467
|
+
axis: "memory",
|
|
1468
|
+
target: { surface: "memory", path: `websearch:outdated:${subject.topic}` }
|
|
1469
|
+
};
|
|
1470
|
+
case "prior-run-summary":
|
|
1471
|
+
return {
|
|
1472
|
+
axis: "memory",
|
|
1473
|
+
target: { surface: "memory", path: `prior-run-summary:${subject.topic}` }
|
|
1474
|
+
};
|
|
1475
|
+
case "cluster":
|
|
1476
|
+
return { axis: "representation", target: { surface: "prompt", path: subject.label } };
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
function rolloutPolicyAxis(field) {
|
|
1480
|
+
const normalized = field.toLowerCase();
|
|
1481
|
+
if (/budget|max(?:imum)?[-_. ]?(?:turns?|tokens?|cost)|timeout|deadline/.test(normalized)) {
|
|
1482
|
+
return "budget";
|
|
1483
|
+
}
|
|
1484
|
+
if (/temperature|top[-_. ]?p|sampling|seed|shots?|parallel|concurrency/.test(normalized)) {
|
|
1485
|
+
return "sampling";
|
|
1486
|
+
}
|
|
1487
|
+
if (/output|schema|format/.test(normalized)) return "output_contract";
|
|
1488
|
+
return "routing";
|
|
1489
|
+
}
|
|
1490
|
+
function resolveExpectedGain(finding, opts) {
|
|
1491
|
+
if (typeof opts.expectedGain === "function") return opts.expectedGain(finding) ?? null;
|
|
1492
|
+
if (opts.expectedGain) return opts.expectedGain;
|
|
1493
|
+
return readExpectedGainFromMetadata(finding.metadata);
|
|
1494
|
+
}
|
|
1495
|
+
function readExpectedGainFromMetadata(metadata) {
|
|
1496
|
+
const raw = readPolicyEditMetadata(metadata)?.expectedGain ?? readPolicyEditMetadata(metadata)?.expected_gain;
|
|
1497
|
+
if (!raw || typeof raw !== "object") return null;
|
|
1498
|
+
const obj = raw;
|
|
1499
|
+
if (typeof obj.metric !== "string" || obj.direction !== "increase" && obj.direction !== "decrease" || typeof obj.amount !== "number") {
|
|
1500
|
+
return null;
|
|
1501
|
+
}
|
|
1502
|
+
const out = {
|
|
1503
|
+
metric: obj.metric,
|
|
1504
|
+
direction: obj.direction,
|
|
1505
|
+
amount: obj.amount
|
|
1506
|
+
};
|
|
1507
|
+
if (obj.unit === "absolute" || obj.unit === "relative" || obj.unit === "percent" || obj.unit === "score") {
|
|
1508
|
+
out.unit = obj.unit;
|
|
1509
|
+
}
|
|
1510
|
+
if (typeof obj.rationale === "string") out.rationale = obj.rationale;
|
|
1511
|
+
return out;
|
|
1512
|
+
}
|
|
1513
|
+
function readPolicyEditMetadata(metadata) {
|
|
1514
|
+
const raw = metadata?.policyEdit ?? metadata?.policy_edit;
|
|
1515
|
+
return raw && typeof raw === "object" ? raw : null;
|
|
1516
|
+
}
|
|
1517
|
+
function resolveRisk(finding, opts) {
|
|
1518
|
+
if (typeof opts.risk === "function") return opts.risk(finding);
|
|
1519
|
+
if (opts.risk) return opts.risk;
|
|
1520
|
+
const raw = readPolicyEditMetadata(finding.metadata)?.risk;
|
|
1521
|
+
if (raw === "low" || raw === "medium" || raw === "high" || raw === "unknown") return raw;
|
|
1522
|
+
if (finding.severity === "critical" || finding.severity === "high") return "medium";
|
|
1523
|
+
return "low";
|
|
1524
|
+
}
|
|
1525
|
+
function applyTextChange(surface, change) {
|
|
1526
|
+
if (typeof surface !== "string") {
|
|
1527
|
+
throw new PolicyEditValidationError("text policy edits require a string surface", "change");
|
|
1528
|
+
}
|
|
1529
|
+
if (change.mode === "append") {
|
|
1530
|
+
if (hasExactTextBlock(surface, change.value)) return surface;
|
|
1531
|
+
return `${surface.trimEnd()}
|
|
1532
|
+
|
|
1533
|
+
${change.value}`.trimStart();
|
|
1534
|
+
}
|
|
1535
|
+
if (change.mode === "prepend") {
|
|
1536
|
+
if (hasExactTextBlock(surface, change.value)) return surface;
|
|
1537
|
+
return `${change.value}
|
|
1538
|
+
|
|
1539
|
+
${surface.trimStart()}`.trimEnd();
|
|
1540
|
+
}
|
|
1541
|
+
const find = expectNonEmpty(change.find, "change.find");
|
|
1542
|
+
if (!surface.includes(find)) {
|
|
1543
|
+
throw new PolicyEditValidationError("replace target not found in surface", "change.find");
|
|
1544
|
+
}
|
|
1545
|
+
return surface.replace(find, change.value);
|
|
1546
|
+
}
|
|
1547
|
+
function applyJsonChange(surface, change) {
|
|
1548
|
+
const root = parseJsonSurface(surface);
|
|
1549
|
+
const path = splitPath(change.path);
|
|
1550
|
+
if (change.mode === "remove") return setJsonAtPath(root, path, void 0, "remove");
|
|
1551
|
+
if (change.mode === "set") return setJsonAtPath(root, path, change.value ?? null, "set");
|
|
1552
|
+
const prior = readJsonAtPath(root, path);
|
|
1553
|
+
const merged = prior && typeof prior === "object" && !Array.isArray(prior) && change.value && typeof change.value === "object" && !Array.isArray(change.value) ? { ...prior, ...change.value } : change.value ?? null;
|
|
1554
|
+
return setJsonAtPath(root, path, merged, "set");
|
|
1555
|
+
}
|
|
1556
|
+
function parseJsonSurface(surface) {
|
|
1557
|
+
if (typeof surface === "string") {
|
|
1558
|
+
try {
|
|
1559
|
+
return JSON.parse(surface);
|
|
1560
|
+
} catch {
|
|
1561
|
+
throw new PolicyEditValidationError(
|
|
1562
|
+
"json policy edits require a JSON string surface",
|
|
1563
|
+
"change"
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
assertJson(surface, "surface");
|
|
1568
|
+
return surface;
|
|
1569
|
+
}
|
|
1570
|
+
function readJsonAtPath(root, path) {
|
|
1571
|
+
let cursor = root;
|
|
1572
|
+
for (const part of path) {
|
|
1573
|
+
if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) return void 0;
|
|
1574
|
+
cursor = cursor[part];
|
|
1575
|
+
}
|
|
1576
|
+
return cursor;
|
|
1577
|
+
}
|
|
1578
|
+
function setJsonAtPath(root, path, value, mode) {
|
|
1579
|
+
if (path.length === 0) {
|
|
1580
|
+
if (mode === "remove") return null;
|
|
1581
|
+
return value ?? null;
|
|
1582
|
+
}
|
|
1583
|
+
if (root === null || typeof root !== "object" || Array.isArray(root)) {
|
|
1584
|
+
throw new PolicyEditValidationError("json edit root must be an object", "change.path");
|
|
1585
|
+
}
|
|
1586
|
+
const out = { ...root };
|
|
1587
|
+
let cursor = out;
|
|
1588
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
1589
|
+
const key = path[i];
|
|
1590
|
+
const existing = cursor[key];
|
|
1591
|
+
if (mode === "remove" && (!existing || typeof existing !== "object" || Array.isArray(existing))) {
|
|
1592
|
+
return out;
|
|
1593
|
+
}
|
|
1594
|
+
const next = existing && typeof existing === "object" && !Array.isArray(existing) ? { ...existing } : {};
|
|
1595
|
+
cursor[key] = next;
|
|
1596
|
+
cursor = next;
|
|
1597
|
+
}
|
|
1598
|
+
const leaf = path[path.length - 1];
|
|
1599
|
+
if (mode === "remove") delete cursor[leaf];
|
|
1600
|
+
else cursor[leaf] = value ?? null;
|
|
1601
|
+
return out;
|
|
1602
|
+
}
|
|
1603
|
+
function normalizePolicyEdit(input) {
|
|
1604
|
+
const out = {
|
|
1605
|
+
schemaVersion: "policy-edit/v1",
|
|
1606
|
+
axis: input.axis,
|
|
1607
|
+
target: normalizeTarget(input.target),
|
|
1608
|
+
change: normalizeChange(input.change),
|
|
1609
|
+
claim: input.claim.trim(),
|
|
1610
|
+
expectedGain: normalizeExpectedGain(input.expectedGain),
|
|
1611
|
+
confidence: input.confidence,
|
|
1612
|
+
risk: input.risk,
|
|
1613
|
+
source: normalizeSource(input.source)
|
|
1614
|
+
};
|
|
1615
|
+
if (input.rationale?.trim()) out.rationale = input.rationale.trim();
|
|
1616
|
+
if (input.validationPlan?.trim()) out.validationPlan = input.validationPlan.trim();
|
|
1617
|
+
if (input.metadata) out.metadata = input.metadata;
|
|
1618
|
+
return out;
|
|
1619
|
+
}
|
|
1620
|
+
function assertJsonSafe(value, path, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
1621
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return;
|
|
1622
|
+
if (typeof value === "number") {
|
|
1623
|
+
if (Number.isFinite(value)) return;
|
|
1624
|
+
throw new PolicyEditValidationError("expected finite JSON number", path);
|
|
1625
|
+
}
|
|
1626
|
+
if (typeof value !== "object") {
|
|
1627
|
+
throw new PolicyEditValidationError("expected JSON-safe value", path);
|
|
1628
|
+
}
|
|
1629
|
+
if (ancestors.has(value)) {
|
|
1630
|
+
throw new PolicyEditValidationError("cyclic value is not JSON-safe", path);
|
|
1631
|
+
}
|
|
1632
|
+
ancestors.add(value);
|
|
1633
|
+
if (Array.isArray(value)) {
|
|
1634
|
+
for (let i = 0; i < value.length; i++) {
|
|
1635
|
+
if (!(i in value)) {
|
|
1636
|
+
throw new PolicyEditValidationError("sparse array is not JSON-safe", `${path}.${i}`);
|
|
1637
|
+
}
|
|
1638
|
+
assertJsonSafe(value[i], `${path}.${i}`, ancestors);
|
|
1639
|
+
}
|
|
1640
|
+
} else {
|
|
1641
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1642
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
1643
|
+
throw new PolicyEditValidationError("expected plain JSON object", path);
|
|
1644
|
+
}
|
|
1645
|
+
if (Object.getOwnPropertySymbols(value).length > 0) {
|
|
1646
|
+
throw new PolicyEditValidationError("symbol keys are not JSON-safe", path);
|
|
1647
|
+
}
|
|
1648
|
+
for (const [key, child] of Object.entries(value)) {
|
|
1649
|
+
assertJsonSafe(child, `${path}.${key}`, ancestors);
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
ancestors.delete(value);
|
|
1653
|
+
}
|
|
1654
|
+
function normalizeTarget(target) {
|
|
1655
|
+
const out = { surface: target.surface };
|
|
1656
|
+
if (target.path?.trim()) out.path = target.path.trim();
|
|
1657
|
+
if (target.agentProfileCell)
|
|
1658
|
+
out.agentProfileCell = validateAgentProfileCell(target.agentProfileCell);
|
|
1659
|
+
if (target.label?.trim()) out.label = target.label.trim();
|
|
1660
|
+
return out;
|
|
1661
|
+
}
|
|
1662
|
+
function normalizeChange(change) {
|
|
1663
|
+
if (change.kind === "text") {
|
|
1664
|
+
const out2 = {
|
|
1665
|
+
kind: "text",
|
|
1666
|
+
mode: change.mode,
|
|
1667
|
+
value: change.value.trim()
|
|
1668
|
+
};
|
|
1669
|
+
if (change.find?.trim()) out2.find = change.find.trim();
|
|
1670
|
+
return out2;
|
|
1671
|
+
}
|
|
1672
|
+
const out = {
|
|
1673
|
+
kind: "json",
|
|
1674
|
+
mode: change.mode,
|
|
1675
|
+
path: change.path.trim()
|
|
1676
|
+
};
|
|
1677
|
+
if (change.value !== void 0) out.value = change.value;
|
|
1678
|
+
return out;
|
|
1679
|
+
}
|
|
1680
|
+
function normalizeExpectedGain(gain) {
|
|
1681
|
+
const out = {
|
|
1682
|
+
metric: gain.metric.trim(),
|
|
1683
|
+
direction: gain.direction,
|
|
1684
|
+
amount: gain.amount
|
|
1685
|
+
};
|
|
1686
|
+
if (gain.unit) out.unit = gain.unit;
|
|
1687
|
+
if (gain.rationale?.trim()) out.rationale = gain.rationale.trim();
|
|
1688
|
+
return out;
|
|
1689
|
+
}
|
|
1690
|
+
function normalizeSource(source) {
|
|
1691
|
+
const out = {
|
|
1692
|
+
findingIds: uniqueSorted(source.findingIds.map((s) => s.trim()).filter(Boolean)),
|
|
1693
|
+
analystIds: uniqueSorted(source.analystIds.map((s) => s.trim()).filter(Boolean)),
|
|
1694
|
+
evidenceRefs: source.evidenceRefs
|
|
1695
|
+
};
|
|
1696
|
+
if (source.derivedFromJudge) out.derivedFromJudge = true;
|
|
1697
|
+
return out;
|
|
1698
|
+
}
|
|
1699
|
+
function validateTarget(target) {
|
|
1700
|
+
if (!target || typeof target !== "object")
|
|
1701
|
+
throw new PolicyEditValidationError("expected object", "target");
|
|
1702
|
+
const obj = target;
|
|
1703
|
+
expectOneOf(obj.surface, POLICY_EDIT_TARGET_SURFACES, "target.surface");
|
|
1704
|
+
if (obj.path !== void 0) expectString(obj.path, "target.path");
|
|
1705
|
+
if (obj.label !== void 0) expectString(obj.label, "target.label");
|
|
1706
|
+
if (obj.agentProfileCell !== void 0) validateAgentProfileCell(obj.agentProfileCell);
|
|
1707
|
+
}
|
|
1708
|
+
function validateChange(change) {
|
|
1709
|
+
if (!change || typeof change !== "object")
|
|
1710
|
+
throw new PolicyEditValidationError("expected object", "change");
|
|
1711
|
+
const obj = change;
|
|
1712
|
+
if (obj.kind !== "text" && obj.kind !== "json") {
|
|
1713
|
+
throw new PolicyEditValidationError("kind must be text or json", "change.kind");
|
|
1714
|
+
}
|
|
1715
|
+
if (obj.kind === "text") {
|
|
1716
|
+
expectOneOf(obj.mode, ["append", "prepend", "replace"], "change.mode");
|
|
1717
|
+
expectString(obj.value, "change.value");
|
|
1718
|
+
if (obj.mode === "replace") expectString(obj.find, "change.find");
|
|
1719
|
+
return;
|
|
1720
|
+
}
|
|
1721
|
+
expectOneOf(obj.mode, ["set", "merge", "remove"], "change.mode");
|
|
1722
|
+
expectString(obj.path, "change.path");
|
|
1723
|
+
if (obj.value !== void 0) assertJson(obj.value, "change.value");
|
|
1724
|
+
}
|
|
1725
|
+
function validateExpectedGain(gain) {
|
|
1726
|
+
if (!gain || typeof gain !== "object")
|
|
1727
|
+
throw new PolicyEditValidationError("expected object", "expectedGain");
|
|
1728
|
+
const obj = gain;
|
|
1729
|
+
expectString(obj.metric, "expectedGain.metric");
|
|
1730
|
+
expectOneOf(obj.direction, ["increase", "decrease"], "expectedGain.direction");
|
|
1731
|
+
if (!Number.isFinite(obj.amount) || obj.amount <= 0) {
|
|
1732
|
+
throw new PolicyEditValidationError(
|
|
1733
|
+
"amount must be a positive finite number",
|
|
1734
|
+
"expectedGain.amount"
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1737
|
+
if (obj.unit !== void 0) {
|
|
1738
|
+
expectOneOf(
|
|
1739
|
+
obj.unit,
|
|
1740
|
+
["absolute", "relative", "percent", "score"],
|
|
1741
|
+
"expectedGain.unit"
|
|
1742
|
+
);
|
|
1743
|
+
}
|
|
1744
|
+
if (obj.rationale !== void 0) expectString(obj.rationale, "expectedGain.rationale");
|
|
1745
|
+
}
|
|
1746
|
+
function validateSource(source) {
|
|
1747
|
+
if (!source || typeof source !== "object")
|
|
1748
|
+
throw new PolicyEditValidationError("expected object", "source");
|
|
1749
|
+
const obj = source;
|
|
1750
|
+
expectNonEmptyStringArray(obj.findingIds, "source.findingIds");
|
|
1751
|
+
expectNonEmptyStringArray(obj.analystIds, "source.analystIds");
|
|
1752
|
+
if (!Array.isArray(obj.evidenceRefs)) {
|
|
1753
|
+
throw new PolicyEditValidationError("expected array", "source.evidenceRefs");
|
|
1754
|
+
}
|
|
1755
|
+
for (const [i, ref] of obj.evidenceRefs.entries())
|
|
1756
|
+
validateEvidenceRef(ref, `source.evidenceRefs.${i}`);
|
|
1757
|
+
if (obj.derivedFromJudge !== void 0 && typeof obj.derivedFromJudge !== "boolean") {
|
|
1758
|
+
throw new PolicyEditValidationError("expected boolean", "source.derivedFromJudge");
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
function validateEvidenceRef(ref, path) {
|
|
1762
|
+
if (!ref || typeof ref !== "object") throw new PolicyEditValidationError("expected object", path);
|
|
1763
|
+
const obj = ref;
|
|
1764
|
+
expectOneOf(obj.kind, ["span", "event", "artifact", "finding", "metric"], `${path}.kind`);
|
|
1765
|
+
expectString(obj.uri, `${path}.uri`);
|
|
1766
|
+
if (obj.excerpt !== void 0) expectString(obj.excerpt, `${path}.excerpt`);
|
|
1767
|
+
}
|
|
1768
|
+
function assertJson(value, path) {
|
|
1769
|
+
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) {
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
if (Array.isArray(value)) {
|
|
1773
|
+
for (const [i, item] of value.entries()) assertJson(item, `${path}.${i}`);
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
if (typeof value === "object") {
|
|
1777
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1778
|
+
if (!key) throw new PolicyEditValidationError("empty object key", path);
|
|
1779
|
+
assertJson(item, `${path}.${key}`);
|
|
1780
|
+
}
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
throw new PolicyEditValidationError("expected JSON-compatible value", path);
|
|
1784
|
+
}
|
|
1785
|
+
function targetSpecificityScore(edit) {
|
|
1786
|
+
let score = 0.4;
|
|
1787
|
+
if (edit.target.path) score += 0.25;
|
|
1788
|
+
if (edit.target.agentProfileCell) score += 0.15;
|
|
1789
|
+
if (edit.change.kind === "json" || edit.change.mode === "replace") score += 0.2;
|
|
1790
|
+
else if (edit.change.value.length > 0) score += 0.1;
|
|
1791
|
+
return clamp01(score);
|
|
1792
|
+
}
|
|
1793
|
+
function splitPath(path) {
|
|
1794
|
+
const parts = path.split(".").map((p) => p.trim()).filter(Boolean);
|
|
1795
|
+
if (parts.length === 0)
|
|
1796
|
+
throw new PolicyEditValidationError("path must not be empty", "change.path");
|
|
1797
|
+
return parts;
|
|
1798
|
+
}
|
|
1799
|
+
function expectLiteral(value, expected, path) {
|
|
1800
|
+
if (value !== expected) throw new PolicyEditValidationError(`expected ${expected}`, path);
|
|
1801
|
+
}
|
|
1802
|
+
function expectString(value, path) {
|
|
1803
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1804
|
+
throw new PolicyEditValidationError("expected non-empty string", path);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
function expectNonEmpty(value, path) {
|
|
1808
|
+
expectString(value, path);
|
|
1809
|
+
return value;
|
|
1810
|
+
}
|
|
1811
|
+
function expectConfidence(value, path) {
|
|
1812
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
|
|
1813
|
+
throw new PolicyEditValidationError("expected finite number in [0,1]", path);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
function hasExactTextBlock(surface, value) {
|
|
1817
|
+
const needle = normalizeTextBlock(value);
|
|
1818
|
+
const normalizedSurface = surface.replace(/\r\n/g, "\n");
|
|
1819
|
+
return [...normalizedSurface.split(/\n{2,}/), ...normalizedSurface.split("\n")].some(
|
|
1820
|
+
(block) => normalizeTextBlock(block) === needle
|
|
1821
|
+
);
|
|
1822
|
+
}
|
|
1823
|
+
function normalizeTextBlock(value) {
|
|
1824
|
+
return value.replace(/\r\n/g, "\n").trim();
|
|
1825
|
+
}
|
|
1826
|
+
function expectOneOf(value, allowed, path) {
|
|
1827
|
+
if (typeof value !== "string" || !allowed.includes(value)) {
|
|
1828
|
+
throw new PolicyEditValidationError(`expected one of ${allowed.join(", ")}`, path);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
function expectStringArray(value, path) {
|
|
1832
|
+
if (!Array.isArray(value)) throw new PolicyEditValidationError("expected array", path);
|
|
1833
|
+
for (const [i, item] of value.entries()) expectString(item, `${path}.${i}`);
|
|
1834
|
+
}
|
|
1835
|
+
function expectNonEmptyStringArray(value, path) {
|
|
1836
|
+
expectStringArray(value, path);
|
|
1837
|
+
if (value.length === 0) throw new PolicyEditValidationError("expected non-empty array", path);
|
|
1838
|
+
}
|
|
1839
|
+
function uniqueSorted(values) {
|
|
1840
|
+
return [...new Set(values)].sort();
|
|
1841
|
+
}
|
|
1842
|
+
function clamp01(n) {
|
|
1843
|
+
if (!Number.isFinite(n)) return 0;
|
|
1844
|
+
if (n < 0) return 0;
|
|
1845
|
+
if (n > 1) return 1;
|
|
1846
|
+
return n;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1122
1849
|
export {
|
|
1123
1850
|
computeFindingId,
|
|
1124
1851
|
makeFinding,
|
|
@@ -1146,6 +1873,24 @@ export {
|
|
|
1146
1873
|
KNOWLEDGE_GAP_KIND_SPEC,
|
|
1147
1874
|
KNOWLEDGE_POISONING_KIND_SPEC,
|
|
1148
1875
|
DEFAULT_TRACE_ANALYST_KINDS,
|
|
1149
|
-
AnalystRegistry
|
|
1876
|
+
AnalystRegistry,
|
|
1877
|
+
isTraceObservable,
|
|
1878
|
+
isJudgeVerdict,
|
|
1879
|
+
assertNoJudgeVerdict,
|
|
1880
|
+
POLICY_EDIT_AXES,
|
|
1881
|
+
POLICY_EDIT_TARGET_SURFACES,
|
|
1882
|
+
POLICY_EDIT_CANDIDATE_RECORD_SCHEMA,
|
|
1883
|
+
PolicyEditValidationError,
|
|
1884
|
+
makePolicyEdit,
|
|
1885
|
+
computePolicyEditId,
|
|
1886
|
+
validatePolicyEdit,
|
|
1887
|
+
makePolicyEditCandidateRecord,
|
|
1888
|
+
validatePolicyEditCandidateRecord,
|
|
1889
|
+
isPolicyEdit,
|
|
1890
|
+
policyEditsFromFindings,
|
|
1891
|
+
policyEditFromFinding,
|
|
1892
|
+
scorePolicyEditReadiness,
|
|
1893
|
+
admitPolicyEdit,
|
|
1894
|
+
applyPolicyEditToSurface
|
|
1150
1895
|
};
|
|
1151
|
-
//# sourceMappingURL=chunk-
|
|
1896
|
+
//# sourceMappingURL=chunk-CIUOICJT.js.map
|