@nathapp/nax 0.67.8 → 0.67.10
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/dist/nax.js +665 -441
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -17224,7 +17224,11 @@ var init_schemas_review = __esm(() => {
|
|
|
17224
17224
|
timeoutMs: exports_external.number().int().positive().default(600000),
|
|
17225
17225
|
excludePatterns: exports_external.array(exports_external.string()).optional(),
|
|
17226
17226
|
parallel: exports_external.boolean().default(false),
|
|
17227
|
-
maxConcurrentSessions: exports_external.number().int().min(1).max(4).default(2)
|
|
17227
|
+
maxConcurrentSessions: exports_external.number().int().min(1).max(4).default(2),
|
|
17228
|
+
substantiation: exports_external.object({
|
|
17229
|
+
requote: exports_external.boolean().default(true),
|
|
17230
|
+
maxRequotes: exports_external.number().int().min(0).default(5)
|
|
17231
|
+
}).optional()
|
|
17228
17232
|
});
|
|
17229
17233
|
ReviewConfigSchema = exports_external.object({
|
|
17230
17234
|
enabled: exports_external.boolean(),
|
|
@@ -17450,6 +17454,18 @@ var init_schemas3 = __esm(() => {
|
|
|
17450
17454
|
":!.nax/",
|
|
17451
17455
|
":!.nax-pids"
|
|
17452
17456
|
]
|
|
17457
|
+
},
|
|
17458
|
+
adversarial: {
|
|
17459
|
+
model: "balanced",
|
|
17460
|
+
diffMode: "ref",
|
|
17461
|
+
rules: [],
|
|
17462
|
+
timeoutMs: 600000,
|
|
17463
|
+
parallel: false,
|
|
17464
|
+
maxConcurrentSessions: 2,
|
|
17465
|
+
substantiation: {
|
|
17466
|
+
requote: true,
|
|
17467
|
+
maxRequotes: 5
|
|
17468
|
+
}
|
|
17453
17469
|
}
|
|
17454
17470
|
}),
|
|
17455
17471
|
plan: PlanConfigSchema.default({
|
|
@@ -21922,7 +21938,8 @@ function makeParseRetryStrategy(opts) {
|
|
|
21922
21938
|
if (ctx.site === "complete") {
|
|
21923
21939
|
getSafeLogger()?.warn(opts.reviewerKind, "makeParseRetryStrategy: lastOutput is not populated on complete-kind ops \u2014 retry will never fire", { storyId: ctx.storyId });
|
|
21924
21940
|
}
|
|
21925
|
-
|
|
21941
|
+
const fallback = opts.exhaustedFallback ? opts.exhaustedFallback("") : undefined;
|
|
21942
|
+
return { retry: false, ...fallback !== undefined ? { fallback } : {} };
|
|
21926
21943
|
}
|
|
21927
21944
|
let parsed;
|
|
21928
21945
|
try {
|
|
@@ -30381,18 +30398,19 @@ Schema: {"passed": boolean, "findings": [{"severity": string, "category": string
|
|
|
30381
30398
|
const line = opts.finding.verifiedBy?.line ?? opts.finding.line;
|
|
30382
30399
|
return `Your previous verifiedBy.observed value did not match the referenced file on disk.
|
|
30383
30400
|
|
|
30401
|
+
You MUST use your file-reading tool to open ${file3} and copy the actual bytes around line ${line}. Do NOT quote from memory or from the prior conversation \u2014 the previous quote was wrong precisely because it was not read from disk. If you reply without a file-read tool call, the quote will be rejected.
|
|
30402
|
+
|
|
30384
30403
|
Return ONLY this JSON object:
|
|
30385
30404
|
{"file":"${file3}","line":${line},"observed":"exact 1-3 line quote"}
|
|
30386
30405
|
|
|
30387
30406
|
Finding issue: ${opts.finding.issue}
|
|
30388
30407
|
Referenced file: ${file3}
|
|
30389
30408
|
Referenced line: ${line}
|
|
30390
|
-
Previous observed: ${opts.previousObserved}
|
|
30391
30409
|
|
|
30392
30410
|
Rules:
|
|
30393
|
-
-
|
|
30394
|
-
- observed must be a 1-3 line excerpt that proves the claim.
|
|
30395
|
-
- If you cannot
|
|
30411
|
+
- Read ${file3} with your file tool first. Then copy observed verbatim from the read result.
|
|
30412
|
+
- observed must be a 1-3 line excerpt that proves the claim, taken from at or near line ${line}.
|
|
30413
|
+
- If after reading the file you cannot find anything that proves the claim, set observed to "".
|
|
30396
30414
|
- Do not return a full review. Do not include markdown fences or explanation.`;
|
|
30397
30415
|
}
|
|
30398
30416
|
}
|
|
@@ -30625,6 +30643,26 @@ ${config2.rules.map((r) => `- ${r}`).join(`
|
|
|
30625
30643
|
diffBlock
|
|
30626
30644
|
].join("");
|
|
30627
30645
|
}
|
|
30646
|
+
static requoteVerbatim(opts) {
|
|
30647
|
+
const file3 = opts.finding.verifiedBy?.file ?? opts.finding.file;
|
|
30648
|
+
const line = opts.finding.verifiedBy?.line ?? opts.finding.line;
|
|
30649
|
+
return `Your previous verifiedBy.observed value did not match the referenced file on disk.
|
|
30650
|
+
|
|
30651
|
+
You MUST use your file-reading tool to open ${file3} and copy the actual bytes around line ${line}. Do NOT quote from memory or from the prior conversation \u2014 the previous quote was wrong precisely because it was not read from disk. If you reply without a file-read tool call, the quote will be rejected.
|
|
30652
|
+
|
|
30653
|
+
Return ONLY this JSON object:
|
|
30654
|
+
{"file":"${file3}","line":${line},"observed":"exact 1-3 line quote"}
|
|
30655
|
+
|
|
30656
|
+
Finding issue: ${opts.finding.issue}
|
|
30657
|
+
Referenced file: ${file3}
|
|
30658
|
+
Referenced line: ${line}
|
|
30659
|
+
|
|
30660
|
+
Rules:
|
|
30661
|
+
- Read ${file3} with your file tool first. Then copy observed verbatim from the read result.
|
|
30662
|
+
- observed must be a 1-3 line excerpt that proves the claim, taken from at or near line ${line}.
|
|
30663
|
+
- If after reading the file you cannot find anything that proves the claim, set observed to "".
|
|
30664
|
+
- Do not return a full review. Do not include markdown fences or explanation.`;
|
|
30665
|
+
}
|
|
30628
30666
|
}
|
|
30629
30667
|
var ADVERSARIAL_ROLE = `You are an adversarial code reviewer with full access to the repository.
|
|
30630
30668
|
|
|
@@ -31248,8 +31286,335 @@ var init_adversarial_helpers = __esm(() => {
|
|
|
31248
31286
|
init_severity();
|
|
31249
31287
|
});
|
|
31250
31288
|
|
|
31289
|
+
// src/review/semantic-helpers.ts
|
|
31290
|
+
function validateLLMShape(parsed) {
|
|
31291
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
31292
|
+
return null;
|
|
31293
|
+
const obj = parsed;
|
|
31294
|
+
if (typeof obj.passed !== "boolean")
|
|
31295
|
+
return null;
|
|
31296
|
+
if (!Array.isArray(obj.findings))
|
|
31297
|
+
return null;
|
|
31298
|
+
return { passed: obj.passed, findings: obj.findings };
|
|
31299
|
+
}
|
|
31300
|
+
function parseLLMResponse(raw) {
|
|
31301
|
+
try {
|
|
31302
|
+
return validateLLMShape(tryParseLLMJson(raw));
|
|
31303
|
+
} catch {
|
|
31304
|
+
return null;
|
|
31305
|
+
}
|
|
31306
|
+
}
|
|
31307
|
+
function formatFindings2(findings) {
|
|
31308
|
+
return findings.map((f) => `[${f.severity}] ${f.file}:${f.line} \u2014 ${f.issue}
|
|
31309
|
+
Suggestion: ${f.suggestion}`).join(`
|
|
31310
|
+
`);
|
|
31311
|
+
}
|
|
31312
|
+
function normalizeSeverity2(sev) {
|
|
31313
|
+
if (sev === "warn")
|
|
31314
|
+
return "warning";
|
|
31315
|
+
if (sev === "critical" || sev === "error" || sev === "warning" || sev === "info" || sev === "low" || sev === "unverifiable")
|
|
31316
|
+
return sev;
|
|
31317
|
+
return "info";
|
|
31318
|
+
}
|
|
31319
|
+
function sanitizeRefModeFindings(findings, diffMode, blockingThreshold = "error") {
|
|
31320
|
+
if (diffMode !== "ref")
|
|
31321
|
+
return findings;
|
|
31322
|
+
return findings.map((finding) => needsDowngradeForMissingEvidence(finding, blockingThreshold) ? downgradeToUnverifiable(finding) : finding);
|
|
31323
|
+
}
|
|
31324
|
+
function needsDowngradeForMissingEvidence(finding, blockingThreshold) {
|
|
31325
|
+
if (!isBlockingSeverity(finding.severity, blockingThreshold))
|
|
31326
|
+
return false;
|
|
31327
|
+
return mentionsUnverifiedSource(finding) || !hasVerifiedEvidence(finding);
|
|
31328
|
+
}
|
|
31329
|
+
function mentionsUnverifiedSource(finding) {
|
|
31330
|
+
const text = `${finding.issue} ${finding.suggestion}`.toLowerCase();
|
|
31331
|
+
return UNVERIFIED_FINDING_PATTERNS.some((pattern) => text.includes(pattern));
|
|
31332
|
+
}
|
|
31333
|
+
function hasVerifiedEvidence(finding) {
|
|
31334
|
+
const evidence = finding.verifiedBy;
|
|
31335
|
+
return !!evidence?.file?.trim() && !!evidence.observed?.trim();
|
|
31336
|
+
}
|
|
31337
|
+
function downgradeToUnverifiable(finding) {
|
|
31338
|
+
return {
|
|
31339
|
+
...finding,
|
|
31340
|
+
severity: "unverifiable"
|
|
31341
|
+
};
|
|
31342
|
+
}
|
|
31343
|
+
function llmFindingToFinding(f) {
|
|
31344
|
+
const metaExtras = {};
|
|
31345
|
+
if (f.verifiedBy)
|
|
31346
|
+
metaExtras.verifiedBy = f.verifiedBy;
|
|
31347
|
+
if (f.acQuote)
|
|
31348
|
+
metaExtras.acQuote = f.acQuote;
|
|
31349
|
+
if (f.acIndex != null)
|
|
31350
|
+
metaExtras.acIndex = f.acIndex;
|
|
31351
|
+
return {
|
|
31352
|
+
source: "semantic-review",
|
|
31353
|
+
severity: normalizeSeverity2(f.severity),
|
|
31354
|
+
category: "",
|
|
31355
|
+
file: f.file,
|
|
31356
|
+
line: f.line,
|
|
31357
|
+
message: f.issue,
|
|
31358
|
+
suggestion: f.suggestion ?? undefined,
|
|
31359
|
+
fixTarget: "source",
|
|
31360
|
+
meta: Object.keys(metaExtras).length > 0 ? metaExtras : undefined
|
|
31361
|
+
};
|
|
31362
|
+
}
|
|
31363
|
+
function toReviewFindings(findings) {
|
|
31364
|
+
return findings.map(llmFindingToFinding);
|
|
31365
|
+
}
|
|
31366
|
+
var UNVERIFIED_FINDING_PATTERNS;
|
|
31367
|
+
var init_semantic_helpers = __esm(() => {
|
|
31368
|
+
init_severity();
|
|
31369
|
+
UNVERIFIED_FINDING_PATTERNS = [
|
|
31370
|
+
"cannot verify",
|
|
31371
|
+
"can't verify",
|
|
31372
|
+
"from diff alone",
|
|
31373
|
+
"missing from diff",
|
|
31374
|
+
"not found in diff",
|
|
31375
|
+
"not present in diff",
|
|
31376
|
+
"does not appear in diff"
|
|
31377
|
+
];
|
|
31378
|
+
});
|
|
31379
|
+
|
|
31380
|
+
// src/review/semantic-evidence.ts
|
|
31381
|
+
import { isAbsolute as isAbsolute8 } from "path";
|
|
31382
|
+
async function substantiateSemanticEvidence(findings, diffMode, workdir, storyId, blockingThreshold = "error") {
|
|
31383
|
+
if (diffMode !== "ref")
|
|
31384
|
+
return findings;
|
|
31385
|
+
return Promise.all(findings.map(async (finding) => {
|
|
31386
|
+
if (!isBlockingSeverity(finding.severity, blockingThreshold))
|
|
31387
|
+
return finding;
|
|
31388
|
+
const evidence = await checkFindingEvidence({ finding, workdir });
|
|
31389
|
+
if (evidence.status !== "unmatched")
|
|
31390
|
+
return finding;
|
|
31391
|
+
return downgradeUnsubstantiatedFinding({ finding, storyId, ...evidence });
|
|
31392
|
+
}));
|
|
31393
|
+
}
|
|
31394
|
+
async function checkFindingEvidence(opts) {
|
|
31395
|
+
const observed = opts.finding.verifiedBy?.observed?.trim();
|
|
31396
|
+
const file3 = opts.finding.verifiedBy?.file?.trim() || opts.finding.file;
|
|
31397
|
+
const line = opts.finding.verifiedBy?.line ?? opts.finding.line;
|
|
31398
|
+
if (!observed)
|
|
31399
|
+
return { status: "missing-observed", file: file3, line };
|
|
31400
|
+
const contents = await readSafeFile(opts.workdir, file3);
|
|
31401
|
+
if (contents === null)
|
|
31402
|
+
return { status: "unreadable", file: file3, line, observed };
|
|
31403
|
+
return matchesEvidence(contents, observed, line) ? { status: "matched", file: file3, line, observed } : { status: "unmatched", file: file3, line, observed };
|
|
31404
|
+
}
|
|
31405
|
+
function matchesEvidence(contents, observed, line) {
|
|
31406
|
+
if (!line || line <= 0) {
|
|
31407
|
+
return normalizedIncludes(contents, observed);
|
|
31408
|
+
}
|
|
31409
|
+
const lines = contents.split(`
|
|
31410
|
+
`);
|
|
31411
|
+
const cited = Math.min(Math.max(0, line - 1), lines.length - 1);
|
|
31412
|
+
const start = Math.max(0, cited - EVIDENCE_LINE_WINDOW);
|
|
31413
|
+
const end = Math.min(lines.length, cited + EVIDENCE_LINE_WINDOW + 1);
|
|
31414
|
+
const windowText = lines.slice(start, end).join(`
|
|
31415
|
+
`);
|
|
31416
|
+
return normalizedIncludes(windowText, observed);
|
|
31417
|
+
}
|
|
31418
|
+
function downgradeUnsubstantiatedFinding(opts) {
|
|
31419
|
+
_evidenceDeps.getLogger()?.warn("review", "Downgraded unsubstantiated review finding", {
|
|
31420
|
+
storyId: opts.storyId,
|
|
31421
|
+
event: opts.event ?? SEMANTIC_FINDING_DOWNGRADED_EVENT,
|
|
31422
|
+
file: opts.file ?? opts.finding.verifiedBy?.file ?? opts.finding.file,
|
|
31423
|
+
line: opts.line ?? opts.finding.verifiedBy?.line ?? opts.finding.line,
|
|
31424
|
+
issue: opts.finding.issue?.slice(0, ISSUE_PREVIEW_CHARS),
|
|
31425
|
+
observed: opts.observed?.slice(0, OBSERVED_PREVIEW_CHARS)
|
|
31426
|
+
});
|
|
31427
|
+
return { ...opts.finding, severity: "unverifiable" };
|
|
31428
|
+
}
|
|
31429
|
+
async function readSafeFile(workdir, file3) {
|
|
31430
|
+
const validated = validateModulePath(file3, [workdir]);
|
|
31431
|
+
if (validated.valid && validated.absolutePath) {
|
|
31432
|
+
try {
|
|
31433
|
+
return await Bun.file(validated.absolutePath).text();
|
|
31434
|
+
} catch {
|
|
31435
|
+
return null;
|
|
31436
|
+
}
|
|
31437
|
+
}
|
|
31438
|
+
if (isAbsolute8(file3)) {
|
|
31439
|
+
try {
|
|
31440
|
+
return await Bun.file(file3).text();
|
|
31441
|
+
} catch {
|
|
31442
|
+
return null;
|
|
31443
|
+
}
|
|
31444
|
+
}
|
|
31445
|
+
return null;
|
|
31446
|
+
}
|
|
31447
|
+
function normalizedIncludes(contents, observed) {
|
|
31448
|
+
const normalizedObserved = normalizeEvidenceText(observed);
|
|
31449
|
+
return normalizedObserved.length > 0 && normalizeEvidenceText(contents).includes(normalizedObserved);
|
|
31450
|
+
}
|
|
31451
|
+
function normalizeEvidenceText(text) {
|
|
31452
|
+
return stripWrappingQuotes(text).replace(/\s+/g, " ").trim();
|
|
31453
|
+
}
|
|
31454
|
+
function stripWrappingQuotes(text) {
|
|
31455
|
+
let trimmed = text.trim();
|
|
31456
|
+
while (trimmed.length >= 2 && isMatchingWrapper(trimmed[0], trimmed[trimmed.length - 1])) {
|
|
31457
|
+
trimmed = trimmed.slice(1, -1).trim();
|
|
31458
|
+
}
|
|
31459
|
+
return trimmed;
|
|
31460
|
+
}
|
|
31461
|
+
function isMatchingWrapper(first, last) {
|
|
31462
|
+
return first === "`" && last === "`" || first === `"` && last === `"` || first === "'" && last === "'";
|
|
31463
|
+
}
|
|
31464
|
+
var OBSERVED_PREVIEW_CHARS = 160, ISSUE_PREVIEW_CHARS = 200, EVIDENCE_LINE_WINDOW = 10, SEMANTIC_FINDING_DOWNGRADED_EVENT = "review.semantic.finding.downgraded", ADVERSARIAL_FINDING_DOWNGRADED_EVENT = "review.adversarial.finding.downgraded", _evidenceDeps;
|
|
31465
|
+
var init_semantic_evidence = __esm(() => {
|
|
31466
|
+
init_logger2();
|
|
31467
|
+
init_path_security2();
|
|
31468
|
+
init_semantic_helpers();
|
|
31469
|
+
_evidenceDeps = {
|
|
31470
|
+
getLogger: getSafeLogger
|
|
31471
|
+
};
|
|
31472
|
+
});
|
|
31473
|
+
|
|
31474
|
+
// src/review/finding-filters.ts
|
|
31475
|
+
async function substantiateAdversarialFindings(opts) {
|
|
31476
|
+
const { findings, workdir, storyId, blockingThreshold } = opts;
|
|
31477
|
+
return Promise.all(findings.map(async (finding) => {
|
|
31478
|
+
if (!isBlockingSeverity(finding.severity, blockingThreshold))
|
|
31479
|
+
return finding;
|
|
31480
|
+
const evidence = await checkFindingEvidence({ finding, workdir });
|
|
31481
|
+
if (evidence.status !== "unmatched" && evidence.status !== "missing-observed")
|
|
31482
|
+
return finding;
|
|
31483
|
+
return downgradeUnsubstantiatedFinding({
|
|
31484
|
+
finding,
|
|
31485
|
+
storyId,
|
|
31486
|
+
event: ADVERSARIAL_FINDING_DOWNGRADED_EVENT,
|
|
31487
|
+
file: evidence.file,
|
|
31488
|
+
line: evidence.line,
|
|
31489
|
+
observed: evidence.observed
|
|
31490
|
+
});
|
|
31491
|
+
}));
|
|
31492
|
+
}
|
|
31493
|
+
var init_finding_filters = __esm(() => {
|
|
31494
|
+
init_adversarial_helpers();
|
|
31495
|
+
init_semantic_evidence();
|
|
31496
|
+
init_semantic_helpers();
|
|
31497
|
+
init_semantic_evidence();
|
|
31498
|
+
init_ac_quote_validator();
|
|
31499
|
+
});
|
|
31500
|
+
|
|
31501
|
+
// src/review/requote-response.ts
|
|
31502
|
+
function parseRequoteResponse(output) {
|
|
31503
|
+
const parsed = tryParseLLMJson(output);
|
|
31504
|
+
if (!isRecord(parsed))
|
|
31505
|
+
return null;
|
|
31506
|
+
const canonical = extractCanonical(parsed);
|
|
31507
|
+
if (canonical)
|
|
31508
|
+
return canonical;
|
|
31509
|
+
const findings = parsed.findings;
|
|
31510
|
+
if (!Array.isArray(findings) || findings.length !== 1)
|
|
31511
|
+
return null;
|
|
31512
|
+
const finding = findings[0];
|
|
31513
|
+
if (!isRecord(finding))
|
|
31514
|
+
return null;
|
|
31515
|
+
return extractCanonical(finding.verifiedBy) ?? extractCanonical(finding);
|
|
31516
|
+
}
|
|
31517
|
+
function extractCanonical(value) {
|
|
31518
|
+
if (!isRecord(value))
|
|
31519
|
+
return null;
|
|
31520
|
+
if (typeof value.file !== "string" || typeof value.observed !== "string")
|
|
31521
|
+
return null;
|
|
31522
|
+
const file3 = value.file.trim();
|
|
31523
|
+
if (!file3)
|
|
31524
|
+
return null;
|
|
31525
|
+
const line = coerceLine(value.line);
|
|
31526
|
+
if (line === null)
|
|
31527
|
+
return null;
|
|
31528
|
+
return {
|
|
31529
|
+
file: file3,
|
|
31530
|
+
line: line === undefined ? undefined : line,
|
|
31531
|
+
observed: value.observed
|
|
31532
|
+
};
|
|
31533
|
+
}
|
|
31534
|
+
function coerceLine(value) {
|
|
31535
|
+
if (value == null)
|
|
31536
|
+
return;
|
|
31537
|
+
if (typeof value === "number")
|
|
31538
|
+
return value;
|
|
31539
|
+
if (typeof value === "string" && /^\d+$/.test(value))
|
|
31540
|
+
return Number.parseInt(value, 10);
|
|
31541
|
+
return null;
|
|
31542
|
+
}
|
|
31543
|
+
function isRecord(value) {
|
|
31544
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31545
|
+
}
|
|
31546
|
+
var init_requote_response = () => {};
|
|
31547
|
+
|
|
31251
31548
|
// src/operations/adversarial-review.ts
|
|
31252
|
-
|
|
31549
|
+
async function requoteBlockingAdversarialFindings(findings, ctx) {
|
|
31550
|
+
const threshold = ctx.input.blockingThreshold ?? "error";
|
|
31551
|
+
const maxRequotes = ctx.input.adversarialConfig.substantiation?.maxRequotes ?? DEFAULT_MAX_REQUOTES;
|
|
31552
|
+
const requoteEnabled = ctx.input.adversarialConfig.substantiation?.requote ?? true;
|
|
31553
|
+
if (ctx.input.mode !== "ref" || !requoteEnabled || maxRequotes <= 0) {
|
|
31554
|
+
return { findings, changed: false, extraCostUsd: 0 };
|
|
31555
|
+
}
|
|
31556
|
+
const next = [...findings];
|
|
31557
|
+
let changed = false;
|
|
31558
|
+
let extraCostUsd = 0;
|
|
31559
|
+
let used = 0;
|
|
31560
|
+
for (const [index, finding] of next.entries()) {
|
|
31561
|
+
if (!isBlockingSeverity(finding.severity, threshold))
|
|
31562
|
+
continue;
|
|
31563
|
+
const initialEvidence = await checkFindingEvidence({ finding, workdir: ctx.input.workdir });
|
|
31564
|
+
if (initialEvidence.status !== "unmatched")
|
|
31565
|
+
continue;
|
|
31566
|
+
if (used >= maxRequotes)
|
|
31567
|
+
break;
|
|
31568
|
+
used += 1;
|
|
31569
|
+
const retry = await ctx.send(AdversarialReviewPromptBuilder.requoteVerbatim({ finding }));
|
|
31570
|
+
extraCostUsd += retry.estimatedCostUsd ?? 0;
|
|
31571
|
+
const requote = parseRequoteResponse(retry.output);
|
|
31572
|
+
if (!requote) {
|
|
31573
|
+
next[index] = downgradeUnsubstantiatedFinding({
|
|
31574
|
+
finding,
|
|
31575
|
+
storyId: ctx.input.story.id,
|
|
31576
|
+
event: ADVERSARIAL_REQUOTE_FAILED_EVENT,
|
|
31577
|
+
...initialEvidence
|
|
31578
|
+
});
|
|
31579
|
+
changed = true;
|
|
31580
|
+
continue;
|
|
31581
|
+
}
|
|
31582
|
+
const updatedFinding = {
|
|
31583
|
+
...finding,
|
|
31584
|
+
verifiedBy: {
|
|
31585
|
+
file: requote.file,
|
|
31586
|
+
line: requote.line,
|
|
31587
|
+
observed: requote.observed
|
|
31588
|
+
}
|
|
31589
|
+
};
|
|
31590
|
+
const requotedEvidence = await checkFindingEvidence({
|
|
31591
|
+
finding: updatedFinding,
|
|
31592
|
+
workdir: ctx.input.workdir
|
|
31593
|
+
});
|
|
31594
|
+
if (requotedEvidence.status === "matched") {
|
|
31595
|
+
getSafeLogger()?.info("review", "Recovered adversarial finding via same-session requote", {
|
|
31596
|
+
storyId: ctx.input.story.id,
|
|
31597
|
+
event: ADVERSARIAL_REQUOTE_RECOVERED_EVENT,
|
|
31598
|
+
file: requotedEvidence.file,
|
|
31599
|
+
line: requotedEvidence.line
|
|
31600
|
+
});
|
|
31601
|
+
next[index] = updatedFinding;
|
|
31602
|
+
changed = true;
|
|
31603
|
+
continue;
|
|
31604
|
+
}
|
|
31605
|
+
next[index] = downgradeUnsubstantiatedFinding({
|
|
31606
|
+
finding: updatedFinding,
|
|
31607
|
+
storyId: ctx.input.story.id,
|
|
31608
|
+
event: ADVERSARIAL_REQUOTE_FAILED_EVENT,
|
|
31609
|
+
file: requotedEvidence.file,
|
|
31610
|
+
line: requotedEvidence.line,
|
|
31611
|
+
observed: requotedEvidence.observed
|
|
31612
|
+
});
|
|
31613
|
+
changed = true;
|
|
31614
|
+
}
|
|
31615
|
+
return { findings: next, changed, extraCostUsd };
|
|
31616
|
+
}
|
|
31617
|
+
var FAIL_OPEN, ADVERSARIAL_REQUOTE_RECOVERED_EVENT = "review.adversarial.finding.requote_recovered", ADVERSARIAL_REQUOTE_FAILED_EVENT = "review.adversarial.finding.requote_failed", DEFAULT_MAX_REQUOTES = 5, adversarialParseRetry = (input) => makeParseRetryStrategy({
|
|
31253
31618
|
validate: (parsed) => validateAdversarialShape(parsed) !== null,
|
|
31254
31619
|
reviewerKind: "adversarial",
|
|
31255
31620
|
maxAttempts: 2,
|
|
@@ -31257,15 +31622,24 @@ var FAIL_OPEN, adversarialParseRetry = (input) => makeParseRetryStrategy({
|
|
|
31257
31622
|
invalid: () => ReviewPromptBuilder.jsonRetry(),
|
|
31258
31623
|
truncated: () => ReviewPromptBuilder.jsonRetryCondensed({ blockingThreshold: input.blockingThreshold })
|
|
31259
31624
|
},
|
|
31260
|
-
exhaustedFallback: (lastOutput) => /"passed"\s*:\s*false/.test(lastOutput) ? { passed: false, findings: [], looksLikeFail: true } : FAIL_OPEN,
|
|
31625
|
+
exhaustedFallback: (lastOutput) => /"passed"\s*:\s*false/.test(lastOutput) ? { passed: false, findings: [], normalizedFindings: [], acDropped: [], looksLikeFail: true } : FAIL_OPEN,
|
|
31261
31626
|
logContext: { blockingThreshold: input.blockingThreshold ?? "error" }
|
|
31262
31627
|
}), adversarialReviewOp;
|
|
31263
31628
|
var init_adversarial_review = __esm(() => {
|
|
31264
31629
|
init_retry();
|
|
31265
31630
|
init_config();
|
|
31631
|
+
init_logger2();
|
|
31266
31632
|
init_prompts();
|
|
31267
31633
|
init_adversarial_helpers();
|
|
31268
|
-
|
|
31634
|
+
init_finding_filters();
|
|
31635
|
+
init_requote_response();
|
|
31636
|
+
FAIL_OPEN = {
|
|
31637
|
+
passed: true,
|
|
31638
|
+
findings: [],
|
|
31639
|
+
normalizedFindings: [],
|
|
31640
|
+
acDropped: [],
|
|
31641
|
+
failOpen: true
|
|
31642
|
+
};
|
|
31269
31643
|
adversarialReviewOp = {
|
|
31270
31644
|
kind: "run",
|
|
31271
31645
|
name: "adversarial-review",
|
|
@@ -31275,6 +31649,21 @@ var init_adversarial_review = __esm(() => {
|
|
|
31275
31649
|
model: (input) => input.adversarialConfig.model,
|
|
31276
31650
|
timeoutMs: (input) => input.adversarialConfig.timeoutMs,
|
|
31277
31651
|
retry: (input) => adversarialParseRetry(input),
|
|
31652
|
+
async hopBody(initialPrompt, ctx) {
|
|
31653
|
+
const turn = await ctx.sendWithParseRetry(initialPrompt);
|
|
31654
|
+
const parsed = validateAdversarialShape(tryParseLLMJson(turn.output));
|
|
31655
|
+
if (!parsed)
|
|
31656
|
+
return turn;
|
|
31657
|
+
const requoted = await requoteBlockingAdversarialFindings(parsed.findings, ctx);
|
|
31658
|
+
if (!requoted.changed)
|
|
31659
|
+
return turn;
|
|
31660
|
+
const passed = !requoted.findings.some((finding) => isBlockingSeverity(finding.severity, ctx.input.blockingThreshold ?? "error"));
|
|
31661
|
+
return {
|
|
31662
|
+
...turn,
|
|
31663
|
+
output: JSON.stringify({ passed, findings: requoted.findings }),
|
|
31664
|
+
estimatedCostUsd: (turn.estimatedCostUsd ?? 0) + requoted.extraCostUsd
|
|
31665
|
+
};
|
|
31666
|
+
},
|
|
31278
31667
|
build(input, _ctx) {
|
|
31279
31668
|
const base = new AdversarialReviewPromptBuilder().buildAdversarialReviewPrompt(input.story, input.adversarialConfig, {
|
|
31280
31669
|
mode: input.mode,
|
|
@@ -31297,12 +31686,42 @@ var init_adversarial_review = __esm(() => {
|
|
|
31297
31686
|
parse(output, _input, _ctx) {
|
|
31298
31687
|
const raw = tryParseLLMJson(output);
|
|
31299
31688
|
const parsed = validateAdversarialShape(raw);
|
|
31300
|
-
if (parsed)
|
|
31301
|
-
return {
|
|
31689
|
+
if (parsed) {
|
|
31690
|
+
return {
|
|
31691
|
+
passed: parsed.passed,
|
|
31692
|
+
findings: parsed.findings,
|
|
31693
|
+
normalizedFindings: [],
|
|
31694
|
+
acDropped: []
|
|
31695
|
+
};
|
|
31696
|
+
}
|
|
31302
31697
|
if (/"passed"\s*:\s*false/.test(output) && !/"findings"\s*:\s*\[\s*\{/.test(output)) {
|
|
31303
|
-
return { passed: false, findings: [], looksLikeFail: true };
|
|
31698
|
+
return { passed: false, findings: [], normalizedFindings: [], acDropped: [], looksLikeFail: true };
|
|
31304
31699
|
}
|
|
31305
31700
|
throw new ParseValidationError("[adversarial-review] parse failed: invalid JSON shape");
|
|
31701
|
+
},
|
|
31702
|
+
async verify(parsed, input, _verifyCtx) {
|
|
31703
|
+
if (parsed.failOpen || parsed.looksLikeFail)
|
|
31704
|
+
return parsed;
|
|
31705
|
+
if (parsed.findings.length === 0)
|
|
31706
|
+
return parsed;
|
|
31707
|
+
const threshold = input.blockingThreshold ?? "error";
|
|
31708
|
+
const findings = parsed.findings;
|
|
31709
|
+
const substantiated = await substantiateAdversarialFindings({
|
|
31710
|
+
findings,
|
|
31711
|
+
workdir: input.workdir,
|
|
31712
|
+
storyId: input.story.id,
|
|
31713
|
+
blockingThreshold: threshold
|
|
31714
|
+
});
|
|
31715
|
+
const { accepted, dropped } = filterByAcQuote(substantiated, input.story.acceptanceCriteria);
|
|
31716
|
+
const blocking = accepted.filter((f) => isBlockingSeverity(f.severity, threshold));
|
|
31717
|
+
const passed = parsed.passed && blocking.length === 0;
|
|
31718
|
+
return {
|
|
31719
|
+
...parsed,
|
|
31720
|
+
passed,
|
|
31721
|
+
findings: accepted,
|
|
31722
|
+
normalizedFindings: toAdversarialReviewFindings(blocking),
|
|
31723
|
+
acDropped: dropped
|
|
31724
|
+
};
|
|
31306
31725
|
}
|
|
31307
31726
|
};
|
|
31308
31727
|
});
|
|
@@ -31737,178 +32156,6 @@ var init_review_audit = __esm(() => {
|
|
|
31737
32156
|
};
|
|
31738
32157
|
});
|
|
31739
32158
|
|
|
31740
|
-
// src/review/semantic-helpers.ts
|
|
31741
|
-
function validateLLMShape(parsed) {
|
|
31742
|
-
if (typeof parsed !== "object" || parsed === null)
|
|
31743
|
-
return null;
|
|
31744
|
-
const obj = parsed;
|
|
31745
|
-
if (typeof obj.passed !== "boolean")
|
|
31746
|
-
return null;
|
|
31747
|
-
if (!Array.isArray(obj.findings))
|
|
31748
|
-
return null;
|
|
31749
|
-
return { passed: obj.passed, findings: obj.findings };
|
|
31750
|
-
}
|
|
31751
|
-
function parseLLMResponse(raw) {
|
|
31752
|
-
try {
|
|
31753
|
-
return validateLLMShape(tryParseLLMJson(raw));
|
|
31754
|
-
} catch {
|
|
31755
|
-
return null;
|
|
31756
|
-
}
|
|
31757
|
-
}
|
|
31758
|
-
function formatFindings2(findings) {
|
|
31759
|
-
return findings.map((f) => `[${f.severity}] ${f.file}:${f.line} \u2014 ${f.issue}
|
|
31760
|
-
Suggestion: ${f.suggestion}`).join(`
|
|
31761
|
-
`);
|
|
31762
|
-
}
|
|
31763
|
-
function normalizeSeverity2(sev) {
|
|
31764
|
-
if (sev === "warn")
|
|
31765
|
-
return "warning";
|
|
31766
|
-
if (sev === "critical" || sev === "error" || sev === "warning" || sev === "info" || sev === "low" || sev === "unverifiable")
|
|
31767
|
-
return sev;
|
|
31768
|
-
return "info";
|
|
31769
|
-
}
|
|
31770
|
-
function sanitizeRefModeFindings(findings, diffMode, blockingThreshold = "error") {
|
|
31771
|
-
if (diffMode !== "ref")
|
|
31772
|
-
return findings;
|
|
31773
|
-
return findings.map((finding) => needsDowngradeForMissingEvidence(finding, blockingThreshold) ? downgradeToUnverifiable(finding) : finding);
|
|
31774
|
-
}
|
|
31775
|
-
function needsDowngradeForMissingEvidence(finding, blockingThreshold) {
|
|
31776
|
-
if (!isBlockingSeverity(finding.severity, blockingThreshold))
|
|
31777
|
-
return false;
|
|
31778
|
-
return mentionsUnverifiedSource(finding) || !hasVerifiedEvidence(finding);
|
|
31779
|
-
}
|
|
31780
|
-
function mentionsUnverifiedSource(finding) {
|
|
31781
|
-
const text = `${finding.issue} ${finding.suggestion}`.toLowerCase();
|
|
31782
|
-
return UNVERIFIED_FINDING_PATTERNS.some((pattern) => text.includes(pattern));
|
|
31783
|
-
}
|
|
31784
|
-
function hasVerifiedEvidence(finding) {
|
|
31785
|
-
const evidence = finding.verifiedBy;
|
|
31786
|
-
return !!evidence?.file?.trim() && !!evidence.observed?.trim();
|
|
31787
|
-
}
|
|
31788
|
-
function downgradeToUnverifiable(finding) {
|
|
31789
|
-
return {
|
|
31790
|
-
...finding,
|
|
31791
|
-
severity: "unverifiable"
|
|
31792
|
-
};
|
|
31793
|
-
}
|
|
31794
|
-
function llmFindingToFinding(f) {
|
|
31795
|
-
const metaExtras = {};
|
|
31796
|
-
if (f.verifiedBy)
|
|
31797
|
-
metaExtras.verifiedBy = f.verifiedBy;
|
|
31798
|
-
if (f.acQuote)
|
|
31799
|
-
metaExtras.acQuote = f.acQuote;
|
|
31800
|
-
if (f.acIndex != null)
|
|
31801
|
-
metaExtras.acIndex = f.acIndex;
|
|
31802
|
-
return {
|
|
31803
|
-
source: "semantic-review",
|
|
31804
|
-
severity: normalizeSeverity2(f.severity),
|
|
31805
|
-
category: "",
|
|
31806
|
-
file: f.file,
|
|
31807
|
-
line: f.line,
|
|
31808
|
-
message: f.issue,
|
|
31809
|
-
suggestion: f.suggestion ?? undefined,
|
|
31810
|
-
fixTarget: "source",
|
|
31811
|
-
meta: Object.keys(metaExtras).length > 0 ? metaExtras : undefined
|
|
31812
|
-
};
|
|
31813
|
-
}
|
|
31814
|
-
function toReviewFindings(findings) {
|
|
31815
|
-
return findings.map(llmFindingToFinding);
|
|
31816
|
-
}
|
|
31817
|
-
var UNVERIFIED_FINDING_PATTERNS;
|
|
31818
|
-
var init_semantic_helpers = __esm(() => {
|
|
31819
|
-
init_severity();
|
|
31820
|
-
UNVERIFIED_FINDING_PATTERNS = [
|
|
31821
|
-
"cannot verify",
|
|
31822
|
-
"can't verify",
|
|
31823
|
-
"from diff alone",
|
|
31824
|
-
"missing from diff",
|
|
31825
|
-
"not found in diff",
|
|
31826
|
-
"not present in diff",
|
|
31827
|
-
"does not appear in diff"
|
|
31828
|
-
];
|
|
31829
|
-
});
|
|
31830
|
-
|
|
31831
|
-
// src/review/semantic-evidence.ts
|
|
31832
|
-
import { isAbsolute as isAbsolute8 } from "path";
|
|
31833
|
-
async function substantiateSemanticEvidence(findings, diffMode, workdir, storyId, blockingThreshold = "error") {
|
|
31834
|
-
if (diffMode !== "ref")
|
|
31835
|
-
return findings;
|
|
31836
|
-
return Promise.all(findings.map(async (finding) => {
|
|
31837
|
-
if (!isBlockingSeverity(finding.severity, blockingThreshold))
|
|
31838
|
-
return finding;
|
|
31839
|
-
const evidence = await checkFindingEvidence({ finding, workdir });
|
|
31840
|
-
if (evidence.status !== "unmatched")
|
|
31841
|
-
return finding;
|
|
31842
|
-
return downgradeUnsubstantiatedFinding({ finding, storyId, ...evidence });
|
|
31843
|
-
}));
|
|
31844
|
-
}
|
|
31845
|
-
async function checkFindingEvidence(opts) {
|
|
31846
|
-
const observed = opts.finding.verifiedBy?.observed?.trim();
|
|
31847
|
-
const file3 = opts.finding.verifiedBy?.file?.trim() || opts.finding.file;
|
|
31848
|
-
const line = opts.finding.verifiedBy?.line ?? opts.finding.line;
|
|
31849
|
-
if (!observed)
|
|
31850
|
-
return { status: "missing-observed", file: file3, line };
|
|
31851
|
-
const contents = await readSafeFile(opts.workdir, file3);
|
|
31852
|
-
if (contents === null)
|
|
31853
|
-
return { status: "unreadable", file: file3, line, observed };
|
|
31854
|
-
return normalizedIncludes(contents, observed) ? { status: "matched", file: file3, line, observed } : { status: "unmatched", file: file3, line, observed };
|
|
31855
|
-
}
|
|
31856
|
-
function downgradeUnsubstantiatedFinding(opts) {
|
|
31857
|
-
_evidenceDeps.getLogger()?.warn("review", "Downgraded unsubstantiated review finding", {
|
|
31858
|
-
storyId: opts.storyId,
|
|
31859
|
-
event: opts.event ?? SEMANTIC_FINDING_DOWNGRADED_EVENT,
|
|
31860
|
-
file: opts.file ?? opts.finding.verifiedBy?.file ?? opts.finding.file,
|
|
31861
|
-
line: opts.line ?? opts.finding.verifiedBy?.line ?? opts.finding.line,
|
|
31862
|
-
issue: opts.finding.issue?.slice(0, ISSUE_PREVIEW_CHARS),
|
|
31863
|
-
observed: opts.observed?.slice(0, OBSERVED_PREVIEW_CHARS)
|
|
31864
|
-
});
|
|
31865
|
-
return { ...opts.finding, severity: "unverifiable" };
|
|
31866
|
-
}
|
|
31867
|
-
async function readSafeFile(workdir, file3) {
|
|
31868
|
-
const validated = validateModulePath(file3, [workdir]);
|
|
31869
|
-
if (validated.valid && validated.absolutePath) {
|
|
31870
|
-
try {
|
|
31871
|
-
return await Bun.file(validated.absolutePath).text();
|
|
31872
|
-
} catch {
|
|
31873
|
-
return null;
|
|
31874
|
-
}
|
|
31875
|
-
}
|
|
31876
|
-
if (isAbsolute8(file3)) {
|
|
31877
|
-
try {
|
|
31878
|
-
return await Bun.file(file3).text();
|
|
31879
|
-
} catch {
|
|
31880
|
-
return null;
|
|
31881
|
-
}
|
|
31882
|
-
}
|
|
31883
|
-
return null;
|
|
31884
|
-
}
|
|
31885
|
-
function normalizedIncludes(contents, observed) {
|
|
31886
|
-
const normalizedObserved = normalizeEvidenceText(observed);
|
|
31887
|
-
return normalizedObserved.length > 0 && normalizeEvidenceText(contents).includes(normalizedObserved);
|
|
31888
|
-
}
|
|
31889
|
-
function normalizeEvidenceText(text) {
|
|
31890
|
-
return stripWrappingQuotes(text).replace(/\s+/g, " ").trim();
|
|
31891
|
-
}
|
|
31892
|
-
function stripWrappingQuotes(text) {
|
|
31893
|
-
let trimmed = text.trim();
|
|
31894
|
-
while (trimmed.length >= 2 && isMatchingWrapper(trimmed[0], trimmed[trimmed.length - 1])) {
|
|
31895
|
-
trimmed = trimmed.slice(1, -1).trim();
|
|
31896
|
-
}
|
|
31897
|
-
return trimmed;
|
|
31898
|
-
}
|
|
31899
|
-
function isMatchingWrapper(first, last) {
|
|
31900
|
-
return first === "`" && last === "`" || first === `"` && last === `"` || first === "'" && last === "'";
|
|
31901
|
-
}
|
|
31902
|
-
var OBSERVED_PREVIEW_CHARS = 160, ISSUE_PREVIEW_CHARS = 200, SEMANTIC_FINDING_DOWNGRADED_EVENT = "review.semantic.finding.downgraded", ADVERSARIAL_FINDING_DOWNGRADED_EVENT = "review.adversarial.finding.downgraded", _evidenceDeps;
|
|
31903
|
-
var init_semantic_evidence = __esm(() => {
|
|
31904
|
-
init_logger2();
|
|
31905
|
-
init_path_security2();
|
|
31906
|
-
init_semantic_helpers();
|
|
31907
|
-
_evidenceDeps = {
|
|
31908
|
-
getLogger: getSafeLogger
|
|
31909
|
-
};
|
|
31910
|
-
});
|
|
31911
|
-
|
|
31912
32159
|
// src/review/adversarial.ts
|
|
31913
32160
|
import { relative as relative7, sep } from "path";
|
|
31914
32161
|
function recordAdversarialAudit(opts) {
|
|
@@ -31941,7 +32188,6 @@ async function runAdversarialReview(opts) {
|
|
|
31941
32188
|
agentManager,
|
|
31942
32189
|
config: naxConfig,
|
|
31943
32190
|
featureName,
|
|
31944
|
-
priorFailures,
|
|
31945
32191
|
blockingThreshold,
|
|
31946
32192
|
featureContextMarkdown,
|
|
31947
32193
|
contextBundle,
|
|
@@ -32062,13 +32308,13 @@ async function runAdversarialReview(opts) {
|
|
|
32062
32308
|
let opResult;
|
|
32063
32309
|
try {
|
|
32064
32310
|
opResult = await _adversarialDeps.callOp(callCtx, adversarialReviewOp, {
|
|
32311
|
+
workdir,
|
|
32065
32312
|
story,
|
|
32066
32313
|
adversarialConfig,
|
|
32067
32314
|
mode: diffMode,
|
|
32068
32315
|
diff,
|
|
32069
32316
|
storyGitRef: effectiveRef,
|
|
32070
32317
|
stat,
|
|
32071
|
-
priorFailures,
|
|
32072
32318
|
testInventory,
|
|
32073
32319
|
excludePatterns: adversarialConfig.excludePatterns,
|
|
32074
32320
|
testGlobs: resolvedTestPatterns.globs,
|
|
@@ -32153,27 +32399,11 @@ async function runAdversarialReview(opts) {
|
|
|
32153
32399
|
durationMs: Date.now() - startTime
|
|
32154
32400
|
};
|
|
32155
32401
|
}
|
|
32156
|
-
const
|
|
32157
|
-
|
|
32158
|
-
|
|
32159
|
-
|
|
32160
|
-
const
|
|
32161
|
-
const substantiatedFindings = await Promise.all(rawParsedRaw.findings.map(async (finding) => {
|
|
32162
|
-
if (!isBlockingSeverity(finding.severity, blockingThresholdEffective))
|
|
32163
|
-
return finding;
|
|
32164
|
-
const evidence = await checkFindingEvidence({ finding, workdir });
|
|
32165
|
-
if (evidence.status !== "unmatched" && evidence.status !== "missing-observed")
|
|
32166
|
-
return finding;
|
|
32167
|
-
return downgradeUnsubstantiatedFinding({
|
|
32168
|
-
finding,
|
|
32169
|
-
storyId: story.id,
|
|
32170
|
-
event: ADVERSARIAL_FINDING_DOWNGRADED_EVENT,
|
|
32171
|
-
file: evidence.file,
|
|
32172
|
-
line: evidence.line,
|
|
32173
|
-
observed: evidence.observed
|
|
32174
|
-
});
|
|
32175
|
-
}));
|
|
32176
|
-
const rawParsed = { ...rawParsedRaw, findings: substantiatedFindings };
|
|
32402
|
+
const threshold = blockingThreshold ?? "error";
|
|
32403
|
+
const allFindings = opResult.findings;
|
|
32404
|
+
const blockingFindings = allFindings.filter((f) => isBlockingSeverity(f.severity, threshold));
|
|
32405
|
+
const advisoryFindings = allFindings.filter((f) => !isBlockingSeverity(f.severity, threshold));
|
|
32406
|
+
const acDropped = opResult.acDropped ?? [];
|
|
32177
32407
|
let diffFiles;
|
|
32178
32408
|
let diffAvailable;
|
|
32179
32409
|
if (diff && diff.length > 0) {
|
|
@@ -32189,13 +32419,6 @@ async function runAdversarialReview(opts) {
|
|
|
32189
32419
|
diffAvailable = true;
|
|
32190
32420
|
}
|
|
32191
32421
|
}
|
|
32192
|
-
const { accepted: acGroundedFindings, dropped: acDropped } = filterByAcQuote(rawParsed.findings, story.acceptanceCriteria);
|
|
32193
|
-
if (acDropped.length > 0) {
|
|
32194
|
-
logger?.warn("review", "Adversarial findings dropped: acQuote validation failed", {
|
|
32195
|
-
storyId: story.id,
|
|
32196
|
-
dropped: acDropped.map((d) => ({ file: d.finding.file, issue: d.finding.issue, code: d.code }))
|
|
32197
|
-
});
|
|
32198
|
-
}
|
|
32199
32422
|
const adversarialDropAnalysis = acDropped.map((d) => ({
|
|
32200
32423
|
finding: {
|
|
32201
32424
|
file: d.finding.file ?? "<unknown>",
|
|
@@ -32209,10 +32432,6 @@ async function runAdversarialReview(opts) {
|
|
|
32209
32432
|
rawCategory: d.finding.category ?? "",
|
|
32210
32433
|
counterfactual: analyzeStructuralCounterfactual({ acIndex: d.finding.acIndex, category: d.finding.category, file: d.finding.file }, story.acceptanceCriteria, diffFiles)
|
|
32211
32434
|
}));
|
|
32212
|
-
const parsed = { ...rawParsed, findings: acGroundedFindings };
|
|
32213
|
-
const threshold = blockingThresholdEffective;
|
|
32214
|
-
const blockingFindings = parsed.findings.filter((f) => isBlockingSeverity(f.severity, threshold));
|
|
32215
|
-
const advisoryFindings = parsed.findings.filter((f) => !isBlockingSeverity(f.severity, threshold));
|
|
32216
32435
|
const adversarialAcceptAnalysis = blockingFindings.map((f) => ({
|
|
32217
32436
|
finding: {
|
|
32218
32437
|
file: f.file,
|
|
@@ -32235,11 +32454,11 @@ async function runAdversarialReview(opts) {
|
|
|
32235
32454
|
}))
|
|
32236
32455
|
});
|
|
32237
32456
|
}
|
|
32457
|
+
const durationMs = Date.now() - startTime;
|
|
32238
32458
|
if (blockingFindings.length > 0) {
|
|
32239
|
-
const durationMs2 = Date.now() - startTime;
|
|
32240
32459
|
logger?.warn("review", `Adversarial review failed: ${blockingFindings.length} blocking findings`, {
|
|
32241
32460
|
storyId: story.id,
|
|
32242
|
-
durationMs
|
|
32461
|
+
durationMs,
|
|
32243
32462
|
findings: blockingFindings.map((f) => ({
|
|
32244
32463
|
severity: f.severity,
|
|
32245
32464
|
category: f.category,
|
|
@@ -32260,72 +32479,37 @@ async function runAdversarialReview(opts) {
|
|
|
32260
32479
|
blockingThreshold: threshold,
|
|
32261
32480
|
result: {
|
|
32262
32481
|
passed: false,
|
|
32263
|
-
findings: llmFindingsToReviewFindings(
|
|
32482
|
+
findings: llmFindingsToReviewFindings(allFindings, { source: "adversarial-review" })
|
|
32264
32483
|
},
|
|
32265
32484
|
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "adversarial-review" }) : undefined,
|
|
32266
32485
|
diffAvailable,
|
|
32267
32486
|
adversarialDropAnalysis,
|
|
32268
32487
|
adversarialAcceptAnalysis
|
|
32269
32488
|
});
|
|
32489
|
+
const output = blockingFindings.length > 0 ? `Adversarial review failed:
|
|
32490
|
+
|
|
32491
|
+
${formatFindings(blockingFindings)}` : "Adversarial review failed (no findings)";
|
|
32270
32492
|
return {
|
|
32271
32493
|
check: "adversarial",
|
|
32272
32494
|
success: false,
|
|
32273
32495
|
command: "",
|
|
32274
32496
|
exitCode: 1,
|
|
32275
|
-
output
|
|
32276
|
-
|
|
32277
|
-
|
|
32278
|
-
durationMs: durationMs2,
|
|
32279
|
-
findings: toAdversarialReviewFindings(blockingFindings),
|
|
32497
|
+
output,
|
|
32498
|
+
durationMs,
|
|
32499
|
+
findings: blockingFindings.length > 0 ? toAdversarialReviewFindings(blockingFindings) : undefined,
|
|
32280
32500
|
advisoryFindings: advisoryFindings.length > 0 ? toAdversarialReviewFindings(advisoryFindings) : undefined,
|
|
32281
32501
|
cost: llmCost
|
|
32282
32502
|
};
|
|
32283
32503
|
}
|
|
32284
|
-
if (!
|
|
32285
|
-
|
|
32286
|
-
const durationMs3 = Date.now() - startTime;
|
|
32287
|
-
logger?.warn("review", "Adversarial review fail-closed: blocking findings dropped as ungrounded", {
|
|
32288
|
-
storyId: story.id,
|
|
32289
|
-
durationMs: durationMs3,
|
|
32290
|
-
droppedCount: acDropped.length,
|
|
32291
|
-
dropCodes: acDropped.map((d) => d.code)
|
|
32292
|
-
});
|
|
32293
|
-
const dropSummary = acDropped.map((d, i) => `${i + 1}. [${d.code}] ${d.finding.file ?? "<unknown>"}: ${d.finding.issue}`).join(`
|
|
32294
|
-
`);
|
|
32295
|
-
recordAdversarialAudit({
|
|
32296
|
-
runtime,
|
|
32297
|
-
workdir,
|
|
32298
|
-
projectDir,
|
|
32299
|
-
storyId: story.id,
|
|
32300
|
-
featureName,
|
|
32301
|
-
parsed: true,
|
|
32302
|
-
failOpen: false,
|
|
32303
|
-
passed: false,
|
|
32304
|
-
blockingThreshold: threshold,
|
|
32305
|
-
result: { passed: false, findings: [] },
|
|
32306
|
-
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "adversarial-review" }) : undefined,
|
|
32307
|
-
diffAvailable,
|
|
32308
|
-
adversarialDropAnalysis,
|
|
32309
|
-
adversarialAcceptAnalysis: []
|
|
32310
|
-
});
|
|
32311
|
-
return {
|
|
32312
|
-
check: "adversarial",
|
|
32313
|
-
success: false,
|
|
32314
|
-
command: "",
|
|
32315
|
-
exitCode: 1,
|
|
32316
|
-
output: `Adversarial review failed: ${acDropped.length} blocking finding(s) dropped as ungrounded \u2014 the model emitted "passed: false" with concerns it could not ground in any acceptance criterion. Either re-classify these as "info" upstream or extend the ACs. Drops:
|
|
32317
|
-
|
|
32318
|
-
${dropSummary}`,
|
|
32319
|
-
durationMs: durationMs3,
|
|
32320
|
-
advisoryFindings: advisoryFindings.length > 0 ? toAdversarialReviewFindings(advisoryFindings) : undefined,
|
|
32321
|
-
cost: llmCost
|
|
32322
|
-
};
|
|
32323
|
-
}
|
|
32324
|
-
const durationMs2 = Date.now() - startTime;
|
|
32325
|
-
logger?.info("review", "Adversarial review passed (all findings below blocking threshold)", {
|
|
32504
|
+
if (!opResult.passed && acDropped.length > 0) {
|
|
32505
|
+
logger?.warn("review", "Adversarial review fail-closed: blocking findings dropped as ungrounded", {
|
|
32326
32506
|
storyId: story.id,
|
|
32327
|
-
durationMs
|
|
32507
|
+
durationMs,
|
|
32508
|
+
droppedCount: acDropped.length,
|
|
32509
|
+
dropCodes: acDropped.map((d) => d.code)
|
|
32328
32510
|
});
|
|
32511
|
+
const dropSummary = acDropped.map((d, i) => `${i + 1}. [${d.code}] ${d.finding.file ?? "<unknown>"}: ${d.finding.issue}`).join(`
|
|
32512
|
+
`);
|
|
32329
32513
|
recordAdversarialAudit({
|
|
32330
32514
|
runtime,
|
|
32331
32515
|
workdir,
|
|
@@ -32334,12 +32518,9 @@ ${dropSummary}`,
|
|
|
32334
32518
|
featureName,
|
|
32335
32519
|
parsed: true,
|
|
32336
32520
|
failOpen: false,
|
|
32337
|
-
passed:
|
|
32521
|
+
passed: false,
|
|
32338
32522
|
blockingThreshold: threshold,
|
|
32339
|
-
result: {
|
|
32340
|
-
passed: true,
|
|
32341
|
-
findings: llmFindingsToReviewFindings(parsed.findings, { source: "adversarial-review" })
|
|
32342
|
-
},
|
|
32523
|
+
result: { passed: false, findings: [] },
|
|
32343
32524
|
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "adversarial-review" }) : undefined,
|
|
32344
32525
|
diffAvailable,
|
|
32345
32526
|
adversarialDropAnalysis,
|
|
@@ -32347,19 +32528,18 @@ ${dropSummary}`,
|
|
|
32347
32528
|
});
|
|
32348
32529
|
return {
|
|
32349
32530
|
check: "adversarial",
|
|
32350
|
-
success:
|
|
32531
|
+
success: false,
|
|
32351
32532
|
command: "",
|
|
32352
|
-
exitCode:
|
|
32353
|
-
output:
|
|
32354
|
-
|
|
32533
|
+
exitCode: 1,
|
|
32534
|
+
output: `Adversarial review failed: ${acDropped.length} blocking finding(s) dropped as ungrounded \u2014 the model emitted "passed: false" with concerns it could not ground in any acceptance criterion. Drops:
|
|
32535
|
+
|
|
32536
|
+
${dropSummary}`,
|
|
32537
|
+
durationMs,
|
|
32355
32538
|
advisoryFindings: advisoryFindings.length > 0 ? toAdversarialReviewFindings(advisoryFindings) : undefined,
|
|
32356
32539
|
cost: llmCost
|
|
32357
32540
|
};
|
|
32358
32541
|
}
|
|
32359
|
-
|
|
32360
|
-
if (parsed.passed) {
|
|
32361
|
-
logger?.info("review", "Adversarial review passed", { storyId: story.id, durationMs });
|
|
32362
|
-
}
|
|
32542
|
+
logger?.info("review", "Adversarial review passed", { storyId: story.id, durationMs });
|
|
32363
32543
|
recordAdversarialAudit({
|
|
32364
32544
|
runtime,
|
|
32365
32545
|
workdir,
|
|
@@ -32368,23 +32548,23 @@ ${dropSummary}`,
|
|
|
32368
32548
|
featureName,
|
|
32369
32549
|
parsed: true,
|
|
32370
32550
|
failOpen: false,
|
|
32371
|
-
passed:
|
|
32551
|
+
passed: true,
|
|
32372
32552
|
blockingThreshold: threshold,
|
|
32373
32553
|
result: {
|
|
32374
|
-
passed:
|
|
32375
|
-
findings: llmFindingsToReviewFindings(
|
|
32554
|
+
passed: true,
|
|
32555
|
+
findings: llmFindingsToReviewFindings(allFindings, { source: "adversarial-review" })
|
|
32376
32556
|
},
|
|
32377
32557
|
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "adversarial-review" }) : undefined,
|
|
32378
32558
|
diffAvailable,
|
|
32379
32559
|
adversarialDropAnalysis,
|
|
32380
|
-
adversarialAcceptAnalysis
|
|
32560
|
+
adversarialAcceptAnalysis: []
|
|
32381
32561
|
});
|
|
32382
32562
|
return {
|
|
32383
32563
|
check: "adversarial",
|
|
32384
|
-
success:
|
|
32564
|
+
success: true,
|
|
32385
32565
|
command: "",
|
|
32386
|
-
exitCode:
|
|
32387
|
-
output:
|
|
32566
|
+
exitCode: 0,
|
|
32567
|
+
output: allFindings.length === 0 ? "Adversarial review passed" : "Adversarial review passed (all findings were advisory \u2014 below blocking threshold)",
|
|
32388
32568
|
durationMs,
|
|
32389
32569
|
advisoryFindings: advisoryFindings.length > 0 ? toAdversarialReviewFindings(advisoryFindings) : undefined,
|
|
32390
32570
|
cost: llmCost
|
|
@@ -32399,13 +32579,11 @@ var init_adversarial = __esm(() => {
|
|
|
32399
32579
|
init_adversarial_review();
|
|
32400
32580
|
init_call();
|
|
32401
32581
|
init_test_runners();
|
|
32402
|
-
init_ac_quote_validator();
|
|
32403
32582
|
init_ac_structural_counterfactual();
|
|
32404
32583
|
init_adversarial_helpers();
|
|
32405
32584
|
init_diff_utils();
|
|
32406
32585
|
init_finding_projection();
|
|
32407
32586
|
init_review_audit();
|
|
32408
|
-
init_semantic_evidence();
|
|
32409
32587
|
_adversarialDeps = {
|
|
32410
32588
|
writeReviewAudit,
|
|
32411
32589
|
callOp
|
|
@@ -34989,57 +35167,10 @@ var init_acceptance_fix = __esm(() => {
|
|
|
34989
35167
|
};
|
|
34990
35168
|
});
|
|
34991
35169
|
|
|
34992
|
-
// src/review/requote-response.ts
|
|
34993
|
-
function parseRequoteResponse(output) {
|
|
34994
|
-
const parsed = tryParseLLMJson(output);
|
|
34995
|
-
if (!isRecord(parsed))
|
|
34996
|
-
return null;
|
|
34997
|
-
const canonical = extractCanonical(parsed);
|
|
34998
|
-
if (canonical)
|
|
34999
|
-
return canonical;
|
|
35000
|
-
const findings = parsed.findings;
|
|
35001
|
-
if (!Array.isArray(findings) || findings.length !== 1)
|
|
35002
|
-
return null;
|
|
35003
|
-
const finding = findings[0];
|
|
35004
|
-
if (!isRecord(finding))
|
|
35005
|
-
return null;
|
|
35006
|
-
return extractCanonical(finding.verifiedBy) ?? extractCanonical(finding);
|
|
35007
|
-
}
|
|
35008
|
-
function extractCanonical(value) {
|
|
35009
|
-
if (!isRecord(value))
|
|
35010
|
-
return null;
|
|
35011
|
-
if (typeof value.file !== "string" || typeof value.observed !== "string")
|
|
35012
|
-
return null;
|
|
35013
|
-
const file3 = value.file.trim();
|
|
35014
|
-
if (!file3)
|
|
35015
|
-
return null;
|
|
35016
|
-
const line = coerceLine(value.line);
|
|
35017
|
-
if (line === null)
|
|
35018
|
-
return null;
|
|
35019
|
-
return {
|
|
35020
|
-
file: file3,
|
|
35021
|
-
line: line === undefined ? undefined : line,
|
|
35022
|
-
observed: value.observed
|
|
35023
|
-
};
|
|
35024
|
-
}
|
|
35025
|
-
function coerceLine(value) {
|
|
35026
|
-
if (value == null)
|
|
35027
|
-
return;
|
|
35028
|
-
if (typeof value === "number")
|
|
35029
|
-
return value;
|
|
35030
|
-
if (typeof value === "string" && /^\d+$/.test(value))
|
|
35031
|
-
return Number.parseInt(value, 10);
|
|
35032
|
-
return null;
|
|
35033
|
-
}
|
|
35034
|
-
function isRecord(value) {
|
|
35035
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
35036
|
-
}
|
|
35037
|
-
var init_requote_response = () => {};
|
|
35038
|
-
|
|
35039
35170
|
// src/operations/semantic-review.ts
|
|
35040
35171
|
async function requoteBlockingFindings(findings, ctx) {
|
|
35041
35172
|
const threshold = ctx.input.blockingThreshold ?? "error";
|
|
35042
|
-
const maxRequotes = ctx.input.semanticConfig.substantiation?.maxRequotes ??
|
|
35173
|
+
const maxRequotes = ctx.input.semanticConfig.substantiation?.maxRequotes ?? DEFAULT_MAX_REQUOTES2;
|
|
35043
35174
|
const requoteEnabled = ctx.input.semanticConfig.substantiation?.requote ?? true;
|
|
35044
35175
|
if (ctx.input.mode !== "ref" || !requoteEnabled || maxRequotes <= 0) {
|
|
35045
35176
|
return { findings, changed: false, extraCostUsd: 0 };
|
|
@@ -35057,7 +35188,7 @@ async function requoteBlockingFindings(findings, ctx) {
|
|
|
35057
35188
|
if (used >= maxRequotes)
|
|
35058
35189
|
break;
|
|
35059
35190
|
used += 1;
|
|
35060
|
-
const retry = await ctx.send(ReviewPromptBuilder.requoteVerbatim({ finding
|
|
35191
|
+
const retry = await ctx.send(ReviewPromptBuilder.requoteVerbatim({ finding }));
|
|
35061
35192
|
extraCostUsd += retry.estimatedCostUsd ?? 0;
|
|
35062
35193
|
const requote = parseRequoteResponse(retry.output);
|
|
35063
35194
|
if (!requote) {
|
|
@@ -35106,7 +35237,7 @@ async function requoteBlockingFindings(findings, ctx) {
|
|
|
35106
35237
|
}
|
|
35107
35238
|
return { findings: next, changed, extraCostUsd };
|
|
35108
35239
|
}
|
|
35109
|
-
var FAIL_OPEN2, SEMANTIC_REQUOTE_RECOVERED_EVENT = "review.semantic.finding.requote_recovered", SEMANTIC_REQUOTE_FAILED_EVENT = "review.semantic.finding.requote_failed",
|
|
35240
|
+
var FAIL_OPEN2, SEMANTIC_REQUOTE_RECOVERED_EVENT = "review.semantic.finding.requote_recovered", SEMANTIC_REQUOTE_FAILED_EVENT = "review.semantic.finding.requote_failed", DEFAULT_MAX_REQUOTES2 = 5, semanticReviewHopBody = async (initialPrompt, ctx) => {
|
|
35110
35241
|
const turn = await ctx.sendWithParseRetry(initialPrompt);
|
|
35111
35242
|
const parsed = validateLLMShape(tryParseLLMJson(turn.output));
|
|
35112
35243
|
if (!parsed)
|
|
@@ -35126,10 +35257,9 @@ var init_semantic_review = __esm(() => {
|
|
|
35126
35257
|
init_config();
|
|
35127
35258
|
init_logger2();
|
|
35128
35259
|
init_prompts();
|
|
35260
|
+
init_finding_filters();
|
|
35129
35261
|
init_requote_response();
|
|
35130
|
-
|
|
35131
|
-
init_semantic_helpers();
|
|
35132
|
-
FAIL_OPEN2 = { passed: true, findings: [], failOpen: true };
|
|
35262
|
+
FAIL_OPEN2 = { passed: true, findings: [], normalizedFindings: [], failOpen: true };
|
|
35133
35263
|
semanticReviewOp = {
|
|
35134
35264
|
kind: "run",
|
|
35135
35265
|
name: "semantic-review",
|
|
@@ -35146,6 +35276,7 @@ var init_semantic_review = __esm(() => {
|
|
|
35146
35276
|
invalid: () => ReviewPromptBuilder.jsonRetry(),
|
|
35147
35277
|
truncated: () => ReviewPromptBuilder.jsonRetryCondensed({ blockingThreshold: input.blockingThreshold })
|
|
35148
35278
|
},
|
|
35279
|
+
exhaustedFallback: (lastOutput) => /"passed"\s*:\s*false/.test(lastOutput) ? { passed: false, findings: [], normalizedFindings: [], looksLikeFail: true } : FAIL_OPEN2,
|
|
35149
35280
|
logContext: { blockingThreshold: input.blockingThreshold ?? "error" }
|
|
35150
35281
|
}),
|
|
35151
35282
|
hopBody: semanticReviewHopBody,
|
|
@@ -35167,11 +35298,36 @@ var init_semantic_review = __esm(() => {
|
|
|
35167
35298
|
parse(output, _input, _ctx) {
|
|
35168
35299
|
const raw = tryParseLLMJson(output);
|
|
35169
35300
|
const parsed = validateLLMShape(raw);
|
|
35170
|
-
if (parsed)
|
|
35171
|
-
return {
|
|
35172
|
-
|
|
35173
|
-
|
|
35301
|
+
if (parsed) {
|
|
35302
|
+
return {
|
|
35303
|
+
passed: parsed.passed,
|
|
35304
|
+
findings: parsed.findings,
|
|
35305
|
+
normalizedFindings: []
|
|
35306
|
+
};
|
|
35307
|
+
}
|
|
35308
|
+
if (/"passed"\s*:\s*false/.test(output)) {
|
|
35309
|
+
return { passed: false, findings: [], normalizedFindings: [], looksLikeFail: true };
|
|
35310
|
+
}
|
|
35174
35311
|
return FAIL_OPEN2;
|
|
35312
|
+
},
|
|
35313
|
+
async verify(parsed, input, _verifyCtx) {
|
|
35314
|
+
if (parsed.failOpen || parsed.looksLikeFail)
|
|
35315
|
+
return parsed;
|
|
35316
|
+
if (parsed.findings.length === 0)
|
|
35317
|
+
return parsed;
|
|
35318
|
+
const threshold = input.blockingThreshold ?? "error";
|
|
35319
|
+
const findings = parsed.findings;
|
|
35320
|
+
const sanitized = sanitizeRefModeFindings(findings, input.mode, threshold);
|
|
35321
|
+
const substantiated = await substantiateSemanticEvidence(sanitized, input.mode, input.workdir, input.story.id, threshold);
|
|
35322
|
+
const { accepted } = filterByAcGroundingMinimal(substantiated, input.story.acceptanceCriteria);
|
|
35323
|
+
const blocking = accepted.filter((f) => isBlockingSeverity(f.severity, threshold));
|
|
35324
|
+
const passed = parsed.passed && blocking.length === 0;
|
|
35325
|
+
return {
|
|
35326
|
+
...parsed,
|
|
35327
|
+
passed,
|
|
35328
|
+
findings: accepted,
|
|
35329
|
+
normalizedFindings: toReviewFindings(blocking)
|
|
35330
|
+
};
|
|
35175
35331
|
}
|
|
35176
35332
|
};
|
|
35177
35333
|
});
|
|
@@ -37334,14 +37490,45 @@ var init_full_suite_rectify = __esm(() => {
|
|
|
37334
37490
|
init_implement();
|
|
37335
37491
|
});
|
|
37336
37492
|
|
|
37493
|
+
// src/operations/_finding-to-check.ts
|
|
37494
|
+
function findingsToFailedChecks(findings) {
|
|
37495
|
+
const grouped = new Map;
|
|
37496
|
+
for (const finding of findings) {
|
|
37497
|
+
const check2 = SOURCE_TO_CHECK[finding.source];
|
|
37498
|
+
if (!check2)
|
|
37499
|
+
continue;
|
|
37500
|
+
const bucket = grouped.get(check2) ?? [];
|
|
37501
|
+
bucket.push(finding);
|
|
37502
|
+
grouped.set(check2, bucket);
|
|
37503
|
+
}
|
|
37504
|
+
return [...grouped.entries()].map(([check2, grpFindings]) => ({
|
|
37505
|
+
check: check2,
|
|
37506
|
+
success: false,
|
|
37507
|
+
command: "",
|
|
37508
|
+
exitCode: 1,
|
|
37509
|
+
output: "",
|
|
37510
|
+
durationMs: 0,
|
|
37511
|
+
findings: grpFindings
|
|
37512
|
+
}));
|
|
37513
|
+
}
|
|
37514
|
+
var SOURCE_TO_CHECK;
|
|
37515
|
+
var init__finding_to_check = __esm(() => {
|
|
37516
|
+
SOURCE_TO_CHECK = {
|
|
37517
|
+
"semantic-review": "semantic",
|
|
37518
|
+
"adversarial-review": "adversarial",
|
|
37519
|
+
lint: "lint",
|
|
37520
|
+
typecheck: "typecheck"
|
|
37521
|
+
};
|
|
37522
|
+
});
|
|
37523
|
+
|
|
37337
37524
|
// src/operations/autofix-implementer-strategy.ts
|
|
37338
37525
|
function makeAutofixImplementerStrategy(story) {
|
|
37339
37526
|
return {
|
|
37340
37527
|
name: "autofix-implementer",
|
|
37341
37528
|
appliesTo: (f) => f.fixTarget === "source" && IMPLEMENTER_SOURCES.has(f.source),
|
|
37342
37529
|
fixOp: implementerRectifyOp,
|
|
37343
|
-
buildInput: (
|
|
37344
|
-
failedChecks:
|
|
37530
|
+
buildInput: (findings, _prior, _cycleCtx) => ({
|
|
37531
|
+
failedChecks: findingsToFailedChecks(findings),
|
|
37345
37532
|
story
|
|
37346
37533
|
}),
|
|
37347
37534
|
extractApplied: (output) => ({
|
|
@@ -37354,6 +37541,7 @@ function makeAutofixImplementerStrategy(story) {
|
|
|
37354
37541
|
}
|
|
37355
37542
|
var IMPLEMENTER_SOURCES;
|
|
37356
37543
|
var init_autofix_implementer_strategy = __esm(() => {
|
|
37544
|
+
init__finding_to_check();
|
|
37357
37545
|
init_autofix_implementer();
|
|
37358
37546
|
IMPLEMENTER_SOURCES = new Set(["lint", "typecheck", "semantic-review"]);
|
|
37359
37547
|
});
|
|
@@ -37364,8 +37552,8 @@ function makeAutofixTestWriterStrategy(story, config2) {
|
|
|
37364
37552
|
name: "autofix-test-writer",
|
|
37365
37553
|
appliesTo: (f) => f.fixTarget === "test" || f.source === "adversarial-review",
|
|
37366
37554
|
fixOp: testWriterRectifyOp,
|
|
37367
|
-
buildInput: (
|
|
37368
|
-
failedChecks:
|
|
37555
|
+
buildInput: (findings, _prior, _cycleCtx) => ({
|
|
37556
|
+
failedChecks: findingsToFailedChecks(findings),
|
|
37369
37557
|
story,
|
|
37370
37558
|
blockingThreshold: config2.review?.blockingThreshold
|
|
37371
37559
|
}),
|
|
@@ -37374,6 +37562,7 @@ function makeAutofixTestWriterStrategy(story, config2) {
|
|
|
37374
37562
|
};
|
|
37375
37563
|
}
|
|
37376
37564
|
var init_autofix_test_writer_strategy = __esm(() => {
|
|
37565
|
+
init__finding_to_check();
|
|
37377
37566
|
init_autofix_test_writer();
|
|
37378
37567
|
});
|
|
37379
37568
|
|
|
@@ -37857,6 +38046,7 @@ var init_operations = __esm(() => {
|
|
|
37857
38046
|
init_full_suite_rectify();
|
|
37858
38047
|
init_autofix_implementer_strategy();
|
|
37859
38048
|
init_autofix_test_writer_strategy();
|
|
38049
|
+
init__finding_to_check();
|
|
37860
38050
|
init_mechanical_lintfix_strategy();
|
|
37861
38051
|
init_mechanical_formatfix_strategy();
|
|
37862
38052
|
init_lint_check();
|
|
@@ -38062,7 +38252,10 @@ async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
|
|
|
38062
38252
|
if (allExhausted) {
|
|
38063
38253
|
let liteFindingsAfter;
|
|
38064
38254
|
try {
|
|
38065
|
-
liteFindingsAfter = await cycle.validate(ctx, {
|
|
38255
|
+
liteFindingsAfter = await cycle.validate(ctx, {
|
|
38256
|
+
mode: "lite",
|
|
38257
|
+
strategiesRun: group.map((s) => s.name)
|
|
38258
|
+
});
|
|
38066
38259
|
} catch (err) {
|
|
38067
38260
|
const finishedAt3 = now();
|
|
38068
38261
|
cycle.iterations.push({
|
|
@@ -38134,7 +38327,7 @@ async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
|
|
|
38134
38327
|
let validatorAttempt = 0;
|
|
38135
38328
|
for (;; ) {
|
|
38136
38329
|
try {
|
|
38137
|
-
findingsAfter = await cycle.validate(ctx, { mode: "full" });
|
|
38330
|
+
findingsAfter = await cycle.validate(ctx, { mode: "full", strategiesRun: group.map((s) => s.name) });
|
|
38138
38331
|
break;
|
|
38139
38332
|
} catch (err) {
|
|
38140
38333
|
if (validatorAttempt >= cycle.config.validatorRetries) {
|
|
@@ -39309,30 +39502,21 @@ async function runSemanticReview(opts) {
|
|
|
39309
39502
|
durationMs: Date.now() - startTime
|
|
39310
39503
|
};
|
|
39311
39504
|
}
|
|
39312
|
-
const parsed = { passed: opResult.passed, findings: opResult.findings };
|
|
39313
|
-
const sanitizedFindings = await substantiateSemanticEvidence(sanitizeRefModeFindings(parsed.findings, diffMode, blockingThreshold ?? "error"), diffMode, workdir, story.id, blockingThreshold ?? "error");
|
|
39314
|
-
const { accepted: acGroundedFindings, dropped: acDropped } = filterByAcGroundingMinimal(sanitizedFindings, story.acceptanceCriteria);
|
|
39315
|
-
if (acDropped.length > 0) {
|
|
39316
|
-
logger?.warn("review", "Semantic findings dropped: acIndex missing or out of range", {
|
|
39317
|
-
storyId: story.id,
|
|
39318
|
-
dropped: acDropped.map((d) => ({ file: d.finding.file, issue: d.finding.issue, code: d.code }))
|
|
39319
|
-
});
|
|
39320
|
-
}
|
|
39321
|
-
const sanitizedParsed = { ...parsed, findings: acGroundedFindings };
|
|
39322
39505
|
const threshold = blockingThreshold ?? "error";
|
|
39323
|
-
const
|
|
39324
|
-
const
|
|
39506
|
+
const allFindings = opResult.findings;
|
|
39507
|
+
const blockingFindings = allFindings.filter((f) => isBlockingSeverity(f.severity, threshold));
|
|
39508
|
+
const advisoryFindings = allFindings.filter((f) => !isBlockingSeverity(f.severity, threshold));
|
|
39325
39509
|
if (advisoryFindings.length > 0) {
|
|
39326
39510
|
logger?.debug("review", `Semantic review: ${advisoryFindings.length} advisory findings (below threshold '${threshold}')`, {
|
|
39327
39511
|
storyId: story.id,
|
|
39328
39512
|
findings: advisoryFindings.map((f) => ({ severity: f.severity, file: f.file, issue: f.issue }))
|
|
39329
39513
|
});
|
|
39330
39514
|
}
|
|
39331
|
-
|
|
39332
|
-
|
|
39515
|
+
const durationMs = Date.now() - startTime;
|
|
39516
|
+
if (blockingFindings.length > 0) {
|
|
39333
39517
|
logger?.warn("review", `Semantic review failed: ${blockingFindings.length} blocking findings`, {
|
|
39334
39518
|
storyId: story.id,
|
|
39335
|
-
durationMs
|
|
39519
|
+
durationMs
|
|
39336
39520
|
});
|
|
39337
39521
|
logger?.debug("review", "Semantic review findings", {
|
|
39338
39522
|
storyId: story.id,
|
|
@@ -39359,7 +39543,7 @@ ${formatFindings2(blockingFindings)}`;
|
|
|
39359
39543
|
blockingThreshold: threshold,
|
|
39360
39544
|
result: {
|
|
39361
39545
|
passed: false,
|
|
39362
|
-
findings: llmFindingsToReviewFindings(
|
|
39546
|
+
findings: llmFindingsToReviewFindings(allFindings, { source: "semantic-review" })
|
|
39363
39547
|
},
|
|
39364
39548
|
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "semantic-review" }) : undefined
|
|
39365
39549
|
});
|
|
@@ -39369,53 +39553,16 @@ ${formatFindings2(blockingFindings)}`;
|
|
|
39369
39553
|
command: "",
|
|
39370
39554
|
exitCode: 1,
|
|
39371
39555
|
output,
|
|
39372
|
-
durationMs
|
|
39556
|
+
durationMs,
|
|
39373
39557
|
findings: toReviewFindings(blockingFindings),
|
|
39374
39558
|
advisoryFindings: advisoryFindings.length > 0 ? toReviewFindings(advisoryFindings) : undefined,
|
|
39375
39559
|
cost: llmCost
|
|
39376
39560
|
};
|
|
39377
39561
|
}
|
|
39378
|
-
if (!
|
|
39379
|
-
|
|
39380
|
-
const durationMs3 = Date.now() - startTime;
|
|
39381
|
-
logger?.warn("review", "Semantic review fail-closed: blocking findings dropped (acIndex invalid)", {
|
|
39382
|
-
storyId: story.id,
|
|
39383
|
-
durationMs: durationMs3,
|
|
39384
|
-
droppedCount: acDropped.length,
|
|
39385
|
-
dropCodes: acDropped.map((d) => d.code)
|
|
39386
|
-
});
|
|
39387
|
-
const dropSummary = acDropped.map((d, i) => `${i + 1}. [${d.code}] ${d.finding.file ?? "<unknown>"}: ${d.finding.issue}`).join(`
|
|
39388
|
-
`);
|
|
39389
|
-
recordSemanticAudit({
|
|
39390
|
-
runtime,
|
|
39391
|
-
workdir,
|
|
39392
|
-
projectDir,
|
|
39393
|
-
storyId: story.id,
|
|
39394
|
-
featureName,
|
|
39395
|
-
parsed: true,
|
|
39396
|
-
failOpen: false,
|
|
39397
|
-
passed: false,
|
|
39398
|
-
blockingThreshold: threshold,
|
|
39399
|
-
result: { passed: false, findings: [] },
|
|
39400
|
-
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "semantic-review" }) : undefined
|
|
39401
|
-
});
|
|
39402
|
-
return {
|
|
39403
|
-
check: "semantic",
|
|
39404
|
-
success: false,
|
|
39405
|
-
command: "",
|
|
39406
|
-
exitCode: 1,
|
|
39407
|
-
output: `Semantic review failed: ${acDropped.length} blocking finding(s) dropped \u2014 acIndex was missing or out of range. The model emitted "passed: false" without valid AC attribution. Either re-classify these as "info" or ensure each error finding includes a valid acIndex. Drops:
|
|
39408
|
-
|
|
39409
|
-
${dropSummary}`,
|
|
39410
|
-
durationMs: durationMs3,
|
|
39411
|
-
advisoryFindings: advisoryFindings.length > 0 ? toReviewFindings(advisoryFindings) : undefined,
|
|
39412
|
-
cost: llmCost
|
|
39413
|
-
};
|
|
39414
|
-
}
|
|
39415
|
-
const durationMs2 = Date.now() - startTime;
|
|
39416
|
-
logger?.info("review", "Semantic review passed (all findings below blocking threshold)", {
|
|
39562
|
+
if (!opResult.passed && allFindings.length === 0) {
|
|
39563
|
+
logger?.warn("review", "Semantic review fail-closed: blocking findings dropped (acIndex invalid)", {
|
|
39417
39564
|
storyId: story.id,
|
|
39418
|
-
durationMs
|
|
39565
|
+
durationMs
|
|
39419
39566
|
});
|
|
39420
39567
|
recordSemanticAudit({
|
|
39421
39568
|
runtime,
|
|
@@ -39425,29 +39572,23 @@ ${dropSummary}`,
|
|
|
39425
39572
|
featureName,
|
|
39426
39573
|
parsed: true,
|
|
39427
39574
|
failOpen: false,
|
|
39428
|
-
passed:
|
|
39575
|
+
passed: false,
|
|
39429
39576
|
blockingThreshold: threshold,
|
|
39430
|
-
result: {
|
|
39431
|
-
passed: true,
|
|
39432
|
-
findings: llmFindingsToReviewFindings(sanitizedParsed.findings, { source: "semantic-review" })
|
|
39433
|
-
},
|
|
39577
|
+
result: { passed: false, findings: [] },
|
|
39434
39578
|
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "semantic-review" }) : undefined
|
|
39435
39579
|
});
|
|
39436
39580
|
return {
|
|
39437
39581
|
check: "semantic",
|
|
39438
|
-
success:
|
|
39582
|
+
success: false,
|
|
39439
39583
|
command: "",
|
|
39440
|
-
exitCode:
|
|
39441
|
-
output:
|
|
39442
|
-
durationMs
|
|
39584
|
+
exitCode: 1,
|
|
39585
|
+
output: 'Semantic review failed: blocking finding(s) were dropped \u2014 acIndex was missing or out of range. The model emitted "passed: false" without valid AC attribution.',
|
|
39586
|
+
durationMs,
|
|
39443
39587
|
advisoryFindings: advisoryFindings.length > 0 ? toReviewFindings(advisoryFindings) : undefined,
|
|
39444
39588
|
cost: llmCost
|
|
39445
39589
|
};
|
|
39446
39590
|
}
|
|
39447
|
-
|
|
39448
|
-
if (sanitizedParsed.passed) {
|
|
39449
|
-
logger?.info("review", "Semantic review passed", { storyId: story.id, durationMs });
|
|
39450
|
-
}
|
|
39591
|
+
logger?.info("review", "Semantic review passed", { storyId: story.id, durationMs });
|
|
39451
39592
|
recordSemanticAudit({
|
|
39452
39593
|
runtime,
|
|
39453
39594
|
workdir,
|
|
@@ -39456,20 +39597,20 @@ ${dropSummary}`,
|
|
|
39456
39597
|
featureName,
|
|
39457
39598
|
parsed: true,
|
|
39458
39599
|
failOpen: false,
|
|
39459
|
-
passed:
|
|
39600
|
+
passed: true,
|
|
39460
39601
|
blockingThreshold: threshold,
|
|
39461
39602
|
result: {
|
|
39462
|
-
passed:
|
|
39463
|
-
findings: llmFindingsToReviewFindings(
|
|
39603
|
+
passed: true,
|
|
39604
|
+
findings: llmFindingsToReviewFindings(allFindings, { source: "semantic-review" })
|
|
39464
39605
|
},
|
|
39465
39606
|
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "semantic-review" }) : undefined
|
|
39466
39607
|
});
|
|
39467
39608
|
return {
|
|
39468
39609
|
check: "semantic",
|
|
39469
|
-
success:
|
|
39610
|
+
success: true,
|
|
39470
39611
|
command: "",
|
|
39471
|
-
exitCode:
|
|
39472
|
-
output:
|
|
39612
|
+
exitCode: 0,
|
|
39613
|
+
output: allFindings.length === 0 ? "Semantic review passed" : "Semantic review passed (all findings were advisory \u2014 below blocking threshold)",
|
|
39473
39614
|
durationMs,
|
|
39474
39615
|
advisoryFindings: advisoryFindings.length > 0 ? toReviewFindings(advisoryFindings) : undefined,
|
|
39475
39616
|
cost: llmCost
|
|
@@ -39486,12 +39627,10 @@ var init_semantic = __esm(() => {
|
|
|
39486
39627
|
init_semantic_review();
|
|
39487
39628
|
init_prompts();
|
|
39488
39629
|
init_test_runners();
|
|
39489
|
-
init_ac_quote_validator();
|
|
39490
39630
|
init_diff_utils();
|
|
39491
39631
|
init_finding_projection();
|
|
39492
39632
|
init_review_audit();
|
|
39493
39633
|
init_semantic_debate();
|
|
39494
|
-
init_semantic_evidence();
|
|
39495
39634
|
init_semantic_helpers();
|
|
39496
39635
|
_semanticDeps = {
|
|
39497
39636
|
createDebateRunner: (opts) => new DebateRunner(opts),
|
|
@@ -41818,6 +41957,38 @@ async function callOp(ctx, op, input) {
|
|
|
41818
41957
|
const rawOutput = outcome.result.output;
|
|
41819
41958
|
const totalCost = outcome.result.estimatedCostUsd ?? 0;
|
|
41820
41959
|
if (!rawOutput) {
|
|
41960
|
+
if (maxRetriesExceeded) {
|
|
41961
|
+
getSafeLogger()?.error("callop", "Op retry budget exhausted (empty output)", {
|
|
41962
|
+
storyId: ctx.storyId,
|
|
41963
|
+
opName: op.name,
|
|
41964
|
+
site: "run",
|
|
41965
|
+
totalAttempts: MAX_COMPLETE_RETRY_ATTEMPTS + 1
|
|
41966
|
+
});
|
|
41967
|
+
throw new NaxError(`callOp[${op.name}]: CALL_OP_MAX_RETRIES \u2014 exceeded MAX_COMPLETE_RETRY_ATTEMPTS (${MAX_COMPLETE_RETRY_ATTEMPTS})`, "CALL_OP_MAX_RETRIES", { stage: op.stage, storyId: ctx.storyId });
|
|
41968
|
+
}
|
|
41969
|
+
if (retryFallback !== undefined) {
|
|
41970
|
+
if (typeof retryFallback !== "object" || retryFallback === null) {
|
|
41971
|
+
throw new NaxError(`callOp[${op.name}]: exhaustedFallback returned a non-object (${typeof retryFallback}); fallback must be a plain object`, "CALL_OP_INVALID_FALLBACK", { stage: op.stage, storyId: ctx.storyId });
|
|
41972
|
+
}
|
|
41973
|
+
getSafeLogger()?.warn("callop", "Returning exhaustedFallback on empty output", {
|
|
41974
|
+
storyId: ctx.storyId,
|
|
41975
|
+
opName: op.name,
|
|
41976
|
+
agentName: dispatchAgent
|
|
41977
|
+
});
|
|
41978
|
+
return { ...retryFallback, estimatedCostUsd: totalCost };
|
|
41979
|
+
}
|
|
41980
|
+
if (op.recover) {
|
|
41981
|
+
const verifyCtx = makeVerifyCtx(buildCtx);
|
|
41982
|
+
const recovered = await op.recover(input, verifyCtx);
|
|
41983
|
+
if (recovered !== null) {
|
|
41984
|
+
getSafeLogger()?.warn("callop", "Recovered from empty output via op.recover", {
|
|
41985
|
+
storyId: ctx.storyId,
|
|
41986
|
+
opName: op.name,
|
|
41987
|
+
agentName: dispatchAgent
|
|
41988
|
+
});
|
|
41989
|
+
return recovered;
|
|
41990
|
+
}
|
|
41991
|
+
}
|
|
41821
41992
|
throw new NaxError(`callOp[${op.name}]: agent returned no output`, "CALL_OP_NO_OUTPUT", {
|
|
41822
41993
|
stage: op.stage,
|
|
41823
41994
|
storyId: ctx.storyId,
|
|
@@ -51966,18 +52137,32 @@ function phasePassed(opName, output) {
|
|
|
51966
52137
|
});
|
|
51967
52138
|
return true;
|
|
51968
52139
|
}
|
|
52140
|
+
function isFinding(value) {
|
|
52141
|
+
return typeof value === "object" && value !== null && typeof value.source === "string" && value.source.length > 0;
|
|
52142
|
+
}
|
|
51969
52143
|
function extractPhaseFindings(output) {
|
|
51970
52144
|
if (output === null || output === undefined || typeof output !== "object") {
|
|
51971
52145
|
return [];
|
|
51972
52146
|
}
|
|
51973
52147
|
const record2 = output;
|
|
51974
|
-
const
|
|
52148
|
+
const rawArray = Array.isArray(record2.normalizedFindings) ? record2.normalizedFindings : Array.isArray(record2.findings) ? record2.findings : [];
|
|
52149
|
+
const findings = rawArray.filter(isFinding);
|
|
51975
52150
|
const success2 = "success" in record2 ? record2.success === true : ("passed" in record2) ? record2.passed === true : findings.length === 0;
|
|
51976
52151
|
return success2 ? [] : findings;
|
|
51977
52152
|
}
|
|
51978
|
-
function
|
|
52153
|
+
function shouldSkipPhaseForRectification(phase, state, phaseOutputs) {
|
|
52154
|
+
if (phase.kind !== "full-suite-gate")
|
|
52155
|
+
return false;
|
|
52156
|
+
const verifierName = state.verifier?.slot.op.name;
|
|
52157
|
+
if (!verifierName)
|
|
52158
|
+
return false;
|
|
52159
|
+
return phaseExplicitlyPassed(phaseOutputs[verifierName]);
|
|
52160
|
+
}
|
|
52161
|
+
function gatherRectificationFindings(phaseOutputs, phases, state) {
|
|
51979
52162
|
const findings = [];
|
|
51980
52163
|
for (const phase of phases) {
|
|
52164
|
+
if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
|
|
52165
|
+
continue;
|
|
51981
52166
|
findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
|
|
51982
52167
|
}
|
|
51983
52168
|
return findings;
|
|
@@ -51993,6 +52178,21 @@ function collectRectificationPhases(state) {
|
|
|
51993
52178
|
state.adversarialReview
|
|
51994
52179
|
].filter((phase) => phase !== undefined);
|
|
51995
52180
|
}
|
|
52181
|
+
function phasesToRevalidate(strategiesRun, allPhases) {
|
|
52182
|
+
const sourceFiltered = allPhases.filter((p) => p.kind !== "verifier");
|
|
52183
|
+
if (!strategiesRun || strategiesRun.length === 0)
|
|
52184
|
+
return sourceFiltered;
|
|
52185
|
+
const unknown2 = strategiesRun.some((name) => STRATEGY_TO_REVALIDATION_PHASES[name] === undefined);
|
|
52186
|
+
if (unknown2)
|
|
52187
|
+
return sourceFiltered;
|
|
52188
|
+
const needed = new Set;
|
|
52189
|
+
for (const name of strategiesRun) {
|
|
52190
|
+
for (const kind of STRATEGY_TO_REVALIDATION_PHASES[name] ?? []) {
|
|
52191
|
+
needed.add(kind);
|
|
52192
|
+
}
|
|
52193
|
+
}
|
|
52194
|
+
return sourceFiltered.filter((p) => needed.has(p.kind));
|
|
52195
|
+
}
|
|
51996
52196
|
function toReviewDecisionPayload(opName, output) {
|
|
51997
52197
|
if (output === null || output === undefined || typeof output !== "object")
|
|
51998
52198
|
return null;
|
|
@@ -52148,7 +52348,7 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
|
|
|
52148
52348
|
if (ctx.runtime.signal?.aborted) {
|
|
52149
52349
|
return {};
|
|
52150
52350
|
}
|
|
52151
|
-
const initialFindings = gatherRectificationFindings(phaseOutputs, validationPhases);
|
|
52351
|
+
const initialFindings = gatherRectificationFindings(phaseOutputs, validationPhases, state);
|
|
52152
52352
|
if (initialFindings.length === 0) {
|
|
52153
52353
|
return {};
|
|
52154
52354
|
}
|
|
@@ -52168,13 +52368,22 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
|
|
|
52168
52368
|
validate: async (_validateCtx, opts) => {
|
|
52169
52369
|
if (ctx.runtime.signal?.aborted)
|
|
52170
52370
|
return [];
|
|
52171
|
-
const lite = opts?.mode === "lite";
|
|
52371
|
+
const lite = (opts?.mode ?? "full") === "lite";
|
|
52372
|
+
const phases = phasesToRevalidate(opts?.strategiesRun, validationPhases);
|
|
52373
|
+
getSafeLogger()?.debug("story-orchestrator", "rectification validate scope", {
|
|
52374
|
+
storyId: ctx.storyId,
|
|
52375
|
+
mode: opts?.mode ?? "full",
|
|
52376
|
+
strategiesRun: opts?.strategiesRun,
|
|
52377
|
+
phasesSelected: phases.map((p) => p.kind)
|
|
52378
|
+
});
|
|
52172
52379
|
const findings = [];
|
|
52173
|
-
for (const phase of
|
|
52380
|
+
for (const phase of phases) {
|
|
52174
52381
|
if (lite && phase.kind === "full-suite-gate") {
|
|
52175
52382
|
continue;
|
|
52176
52383
|
}
|
|
52177
52384
|
await runPhase(ctx, phase.slot, phaseCosts, phaseOutputs);
|
|
52385
|
+
if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
|
|
52386
|
+
continue;
|
|
52178
52387
|
findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
|
|
52179
52388
|
}
|
|
52180
52389
|
return findings;
|
|
@@ -52321,7 +52530,7 @@ class StoryOrchestratorBuilder {
|
|
|
52321
52530
|
return new ExecutionPlan(ctx, { ...this.state }, opts.isThreeSession ?? false);
|
|
52322
52531
|
}
|
|
52323
52532
|
}
|
|
52324
|
-
var _storyOrchestratorDeps, TDD_OP_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY;
|
|
52533
|
+
var _storyOrchestratorDeps, TDD_OP_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY, STRATEGY_TO_REVALIDATION_PHASES;
|
|
52325
52534
|
var init_story_orchestrator = __esm(() => {
|
|
52326
52535
|
init_errors();
|
|
52327
52536
|
init_findings();
|
|
@@ -52359,6 +52568,20 @@ var init_story_orchestrator = __esm(() => {
|
|
|
52359
52568
|
"semantic-review": "semanticReview",
|
|
52360
52569
|
"adversarial-review": "adversarialReview"
|
|
52361
52570
|
};
|
|
52571
|
+
STRATEGY_TO_REVALIDATION_PHASES = {
|
|
52572
|
+
"mechanical-lintfix": ["lint-check"],
|
|
52573
|
+
"mechanical-formatfix": ["lint-check"],
|
|
52574
|
+
"autofix-implementer": [
|
|
52575
|
+
"lint-check",
|
|
52576
|
+
"typecheck-check",
|
|
52577
|
+
"full-suite-gate",
|
|
52578
|
+
"verify-scoped",
|
|
52579
|
+
"semantic-review",
|
|
52580
|
+
"adversarial-review"
|
|
52581
|
+
],
|
|
52582
|
+
"autofix-test-writer": ["lint-check", "typecheck-check", "full-suite-gate", "verify-scoped", "adversarial-review"],
|
|
52583
|
+
"full-suite-rectify": ["lint-check", "typecheck-check", "full-suite-gate", "verify-scoped", "semantic-review"]
|
|
52584
|
+
};
|
|
52362
52585
|
});
|
|
52363
52586
|
|
|
52364
52587
|
// src/execution/build-plan-for-strategy.ts
|
|
@@ -52551,6 +52774,7 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
52551
52774
|
blockingThreshold: ctx.config.review.blockingThreshold
|
|
52552
52775
|
} : undefined;
|
|
52553
52776
|
const adversarialReviewInput = ctx.config.review?.enabled === true && ctx.config.review.checks?.includes("adversarial") && ctx.config.review.adversarial ? {
|
|
52777
|
+
workdir: ctx.workdir,
|
|
52554
52778
|
story,
|
|
52555
52779
|
adversarialConfig: ctx.config.review.adversarial,
|
|
52556
52780
|
mode: ctx.config.review.adversarial.diffMode,
|
|
@@ -56844,7 +57068,7 @@ var package_default;
|
|
|
56844
57068
|
var init_package = __esm(() => {
|
|
56845
57069
|
package_default = {
|
|
56846
57070
|
name: "@nathapp/nax",
|
|
56847
|
-
version: "0.67.
|
|
57071
|
+
version: "0.67.10",
|
|
56848
57072
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
56849
57073
|
type: "module",
|
|
56850
57074
|
bin: {
|
|
@@ -56939,8 +57163,8 @@ var init_version = __esm(() => {
|
|
|
56939
57163
|
NAX_VERSION = package_default.version;
|
|
56940
57164
|
NAX_COMMIT = (() => {
|
|
56941
57165
|
try {
|
|
56942
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
56943
|
-
return "
|
|
57166
|
+
if (/^[0-9a-f]{6,10}$/.test("1d0ef5ac"))
|
|
57167
|
+
return "1d0ef5ac";
|
|
56944
57168
|
} catch {}
|
|
56945
57169
|
try {
|
|
56946
57170
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|