@attalabs/vinaya 0.26.0 → 0.28.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/README.md +6 -3
- package/aeg-root/enforcement.md +5 -5
- package/aeg-root/milestone-model.md +2 -0
- package/aeg-root/process.md +1 -1
- package/aeg-root/roles/developer.md +23 -17
- package/aeg-root/roles/planner.md +4 -0
- package/aeg-root/roles/principal.md +8 -2
- package/aeg-root/roles/reviewer.md +9 -5
- package/aeg-root/roles/security.md +9 -5
- package/dist/checks/bin/check-body-bare-digits.js +1038 -257
- package/dist/checks/bin/check-branch-topology.js +963 -199
- package/dist/checks/bin/check-brief-shape.js +1276 -203
- package/dist/checks/bin/check-changeset-coverage.js +1677 -281
- package/dist/checks/bin/check-closes-n.js +967 -203
- package/dist/checks/bin/check-coherence.js +1127 -284
- package/dist/checks/bin/check-dead-branch-push.js +910 -193
- package/dist/checks/bin/check-dispatch-readiness.js +1189 -295
- package/dist/checks/bin/check-doc-coverage-push.js +1673 -277
- package/dist/checks/bin/check-doc-coverage.js +1675 -279
- package/dist/checks/bin/check-doctrine-no-procedures.js +1020 -257
- package/dist/checks/bin/check-doctrine-portability.js +1672 -276
- package/dist/checks/bin/check-evidence-fresh.js +2526 -322
- package/dist/checks/bin/check-exec-bits.js +1670 -274
- package/dist/checks/bin/check-first-push-dispatch.js +1075 -265
- package/dist/checks/bin/check-issue-assignment.js +965 -201
- package/dist/checks/bin/check-issue-milestone-attach.js +5734 -0
- package/dist/checks/bin/check-issue-objectives-numbering.js +5736 -0
- package/dist/checks/bin/check-issue-parts-coverage.js +5736 -0
- package/dist/checks/bin/check-issue-surface-globs.js +6910 -0
- package/dist/checks/bin/check-issue-title-grammar.js +5736 -0
- package/dist/checks/bin/check-issue-tranche-label.js +5736 -0
- package/dist/checks/bin/check-main-branch-refusal.js +910 -193
- package/dist/checks/bin/check-no-disk-state.js +910 -193
- package/dist/checks/bin/check-pr-premise-reassert.js +1020 -257
- package/dist/checks/bin/check-pr-report-density.js +910 -193
- package/dist/checks/bin/check-quoted-command.js +1651 -274
- package/dist/checks/bin/check-reader-resolvable-prose.js +1655 -278
- package/dist/checks/bin/check-registry-gates.js +997 -193
- package/dist/checks/bin/check-retired-vocabulary.js +1649 -272
- package/dist/checks/bin/check-review-gate.js +1163 -316
- package/dist/checks/bin/check-single-plan-pr.js +910 -193
- package/dist/checks/bin/check-surface-scope.js +973 -201
- package/dist/checks/bin/check-test-plan.js +939 -206
- package/dist/checks/bin/check-token-collection-wired.js +910 -193
- package/dist/checks/bin/check-token-report.js +910 -193
- package/dist/checks/bin/check-workspace-escape.js +1668 -272
- package/dist/index.js +10602 -5352
- package/dist/lib/pre-push-changed-files.js +57 -0
- package/dist/lib/pre-push-select-tests.js +1473 -0
- package/package.json +4 -2
|
@@ -3,8 +3,8 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// src/checks/bin/check-quoted-command.ts
|
|
6
|
-
import { existsSync as
|
|
7
|
-
import { join as
|
|
6
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync } from "node:fs";
|
|
7
|
+
import { join as join6, relative as relative2, resolve as resolve3 } from "node:path";
|
|
8
8
|
// ../../packages/aeg-core/src/gate-audience.ts
|
|
9
9
|
var GATE_AUDIENCE = {
|
|
10
10
|
"check-branch-topology": { shippedAs: "branch-topology", ring: 0 },
|
|
@@ -304,7 +304,7 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
304
304
|
"--state",
|
|
305
305
|
"all",
|
|
306
306
|
"--json",
|
|
307
|
-
"number,title,body,state,labels,milestone",
|
|
307
|
+
"number,title,body,state,labels,milestone,stateReason",
|
|
308
308
|
"--limit",
|
|
309
309
|
"200"
|
|
310
310
|
];
|
|
@@ -650,14 +650,19 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
650
650
|
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
651
651
|
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
652
652
|
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
653
|
-
function
|
|
654
|
-
const text = stripCode(description, { inlineSpans: "keep" });
|
|
653
|
+
function intentsSection(text) {
|
|
655
654
|
const start = text.match(INTENTS_HEADING);
|
|
656
655
|
if (!start || start.index === undefined)
|
|
657
|
-
return
|
|
656
|
+
return null;
|
|
658
657
|
const rest = text.slice(start.index + start[0].length);
|
|
659
658
|
const next = rest.match(NEXT_HEADING);
|
|
660
|
-
|
|
659
|
+
return rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
660
|
+
}
|
|
661
|
+
function intentGoalForSlug(description, slug) {
|
|
662
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
663
|
+
const section = intentsSection(text);
|
|
664
|
+
if (section === null)
|
|
665
|
+
return "";
|
|
661
666
|
for (const line of section.split(`
|
|
662
667
|
`)) {
|
|
663
668
|
const trimmed = line.trim();
|
|
@@ -1949,6 +1954,9 @@ function parseInlineFieldList(section) {
|
|
|
1949
1954
|
// ../../packages/aeg-core/src/verdict-extraction.ts
|
|
1950
1955
|
var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
|
|
1951
1956
|
var OBJECTIVES_VERSION_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Objectives version:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
|
|
1957
|
+
var RULING_ORDINAL_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Ruling ordinal:\s*(\d+)(?!\d)/im;
|
|
1958
|
+
var BRIEF_HASH_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Brief hash:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
|
|
1959
|
+
var POLICY_DIGEST_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Policy digest:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
|
|
1952
1960
|
function firstFiveLines(comment) {
|
|
1953
1961
|
return comment.split(`
|
|
1954
1962
|
`).slice(0, 5).join(`
|
|
@@ -1962,6 +1970,35 @@ function extractObjectivesVersion(comment) {
|
|
|
1962
1970
|
const m = firstFiveLines(comment).match(OBJECTIVES_VERSION_PATTERN);
|
|
1963
1971
|
return m ? m[1].toLowerCase() : null;
|
|
1964
1972
|
}
|
|
1973
|
+
function firstSevenLines(comment) {
|
|
1974
|
+
return comment.split(`
|
|
1975
|
+
`).slice(0, 7).join(`
|
|
1976
|
+
`);
|
|
1977
|
+
}
|
|
1978
|
+
function extractRulingOrdinal(comment) {
|
|
1979
|
+
const m = firstSevenLines(comment).match(RULING_ORDINAL_PATTERN);
|
|
1980
|
+
return m ? Number.parseInt(m[1], 10) : null;
|
|
1981
|
+
}
|
|
1982
|
+
function firstElevenLines(comment) {
|
|
1983
|
+
return comment.split(`
|
|
1984
|
+
`).slice(0, 11).join(`
|
|
1985
|
+
`);
|
|
1986
|
+
}
|
|
1987
|
+
function extractBriefHash(comment) {
|
|
1988
|
+
const m = firstElevenLines(comment).match(BRIEF_HASH_PATTERN);
|
|
1989
|
+
return m ? m[1].toLowerCase() : null;
|
|
1990
|
+
}
|
|
1991
|
+
function extractPolicyDigest(comment) {
|
|
1992
|
+
const m = firstElevenLines(comment).match(POLICY_DIGEST_PATTERN);
|
|
1993
|
+
return m ? m[1].toLowerCase() : null;
|
|
1994
|
+
}
|
|
1995
|
+
var FINDING_SEVERITY_LINE = /^\d+\.\s+\[([A-Z][A-Z]*)\]\s+(.+?)\s+—/gm;
|
|
1996
|
+
function extractFindingSeverities(comment) {
|
|
1997
|
+
return [...comment.matchAll(FINDING_SEVERITY_LINE)].map((m) => ({
|
|
1998
|
+
severity: m[1],
|
|
1999
|
+
location: m[2]
|
|
2000
|
+
}));
|
|
2001
|
+
}
|
|
1965
2002
|
function extractVerdict(comments, valuePattern, missingLabel) {
|
|
1966
2003
|
const candidates = comments.filter((c) => valuePattern.test(c));
|
|
1967
2004
|
if (candidates.length === 0) {
|
|
@@ -1969,6 +2006,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
1969
2006
|
value: `no ${missingLabel} pass was run before merge — DANGLING, see below`,
|
|
1970
2007
|
headSha: null,
|
|
1971
2008
|
objectivesVersion: null,
|
|
2009
|
+
rulingOrdinal: null,
|
|
2010
|
+
briefHash: null,
|
|
2011
|
+
policyDigest: null,
|
|
2012
|
+
findingSeverities: [],
|
|
1972
2013
|
danglingNote: `no ${missingLabel} verdict comment found on this PR`
|
|
1973
2014
|
};
|
|
1974
2015
|
}
|
|
@@ -1979,6 +2020,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
1979
2020
|
value: `the most recent ${missingLabel} comment's VERDICT line is not within its first five lines — DANGLING, see below`,
|
|
1980
2021
|
headSha: null,
|
|
1981
2022
|
objectivesVersion: null,
|
|
2023
|
+
rulingOrdinal: null,
|
|
2024
|
+
briefHash: null,
|
|
2025
|
+
policyDigest: null,
|
|
2026
|
+
findingSeverities: [],
|
|
1982
2027
|
danglingNote: `the most recent ${missingLabel} verdict comment carries a VERDICT-shaped line outside the first-five-line read window`
|
|
1983
2028
|
};
|
|
1984
2029
|
}
|
|
@@ -1986,6 +2031,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
1986
2031
|
value: m[1].toUpperCase().replace(/[_-]/g, " "),
|
|
1987
2032
|
headSha: extractHeadSha(latest),
|
|
1988
2033
|
objectivesVersion: extractObjectivesVersion(latest),
|
|
2034
|
+
rulingOrdinal: extractRulingOrdinal(latest),
|
|
2035
|
+
briefHash: extractBriefHash(latest),
|
|
2036
|
+
policyDigest: extractPolicyDigest(latest),
|
|
2037
|
+
findingSeverities: extractFindingSeverities(latest),
|
|
1989
2038
|
danglingNote: null
|
|
1990
2039
|
};
|
|
1991
2040
|
}
|
|
@@ -2321,6 +2370,53 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
|
|
|
2321
2370
|
}
|
|
2322
2371
|
return out;
|
|
2323
2372
|
}
|
|
2373
|
+
// ../../packages/aeg-core/src/review-policy.ts
|
|
2374
|
+
var CODE_REVIEW_SEVERITY_ORDER = ["BLOCKER", "MAJOR", "MINOR"];
|
|
2375
|
+
var SECURITY_SEVERITY_ORDER = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
|
|
2376
|
+
var DEFAULT_MAX_ROUNDS = 3;
|
|
2377
|
+
var DEFAULT_REVIEW_POLICY = {
|
|
2378
|
+
codeReviewThreshold: "BLOCKER",
|
|
2379
|
+
securityThreshold: "HIGH",
|
|
2380
|
+
maxRounds: DEFAULT_MAX_ROUNDS
|
|
2381
|
+
};
|
|
2382
|
+
var FILE_SHAPED_LOCATION = /\.[a-zA-Z0-9]{1,10}(:\d+)?\s*$/;
|
|
2383
|
+
var PROSE_LOCATION_PATTERNS = [/\bpr\s*body\b/i, /\bcomment\b/i];
|
|
2384
|
+
var ROLE_FILE_LOCATION = /(^|\/)aeg-root\/roles\//i;
|
|
2385
|
+
function isProseLocation(location) {
|
|
2386
|
+
if (ROLE_FILE_LOCATION.test(location))
|
|
2387
|
+
return true;
|
|
2388
|
+
if (FILE_SHAPED_LOCATION.test(location))
|
|
2389
|
+
return false;
|
|
2390
|
+
return PROSE_LOCATION_PATTERNS.some((pattern) => pattern.test(location));
|
|
2391
|
+
}
|
|
2392
|
+
var PROSE_CAP_SEVERITY = "MINOR";
|
|
2393
|
+
function blockingSeverities(scale, threshold) {
|
|
2394
|
+
const idx = scale.indexOf(threshold);
|
|
2395
|
+
if (idx === -1) {
|
|
2396
|
+
throw new Error(`blockingSeverities: threshold "${threshold}" is not one of ${scale.join(" > ")}`);
|
|
2397
|
+
}
|
|
2398
|
+
return scale.slice(0, idx + 1);
|
|
2399
|
+
}
|
|
2400
|
+
function evaluateReviewFindings(findings, scale, threshold) {
|
|
2401
|
+
const blocking = new Set(blockingSeverities(scale, threshold));
|
|
2402
|
+
const blockingFindings = findings.filter((f) => {
|
|
2403
|
+
if (!scale.includes(f.severity)) {
|
|
2404
|
+
throw new Error(`evaluateReviewFindings: severity "${f.severity}" is not one of ${scale.join(" > ")}`);
|
|
2405
|
+
}
|
|
2406
|
+
const effectiveSeverity = f.location !== undefined && isProseLocation(f.location) ? PROSE_CAP_SEVERITY : f.severity;
|
|
2407
|
+
return blocking.has(effectiveSeverity);
|
|
2408
|
+
});
|
|
2409
|
+
return { outcome: blockingFindings.length > 0 ? "blocked" : "clean", blockingFindings };
|
|
2410
|
+
}
|
|
2411
|
+
function evaluateCodeReview(findings, policy) {
|
|
2412
|
+
return evaluateReviewFindings(findings, CODE_REVIEW_SEVERITY_ORDER, policy.codeReviewThreshold);
|
|
2413
|
+
}
|
|
2414
|
+
function evaluateSecurityReview(findings, policy) {
|
|
2415
|
+
return evaluateReviewFindings(findings, SECURITY_SEVERITY_ORDER, policy.securityThreshold);
|
|
2416
|
+
}
|
|
2417
|
+
function isKnownSeverity(scale, value) {
|
|
2418
|
+
return scale.includes(value);
|
|
2419
|
+
}
|
|
2324
2420
|
// ../../packages/aeg-core/src/pr-tier.ts
|
|
2325
2421
|
var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
|
|
2326
2422
|
function readTierFromPrBody(prBody) {
|
|
@@ -2347,6 +2443,9 @@ import { createHash as createHash2 } from "node:crypto";
|
|
|
2347
2443
|
var HEADING_RE = /^##[ \t]*Objectives[ \t]*$/im;
|
|
2348
2444
|
var NEXT_HEADING_RE = /^##[ \t]/m;
|
|
2349
2445
|
var OBJECTIVE_LINE_RE = /^O(\d+)\.[ \t]*(.*)$/;
|
|
2446
|
+
function maskedForHeadingSearch(body) {
|
|
2447
|
+
return maskDetailsBlocks(maskCode(body));
|
|
2448
|
+
}
|
|
2350
2449
|
function hasBacktickedPath(text) {
|
|
2351
2450
|
let i = 0;
|
|
2352
2451
|
while (i < text.length) {
|
|
@@ -2369,16 +2468,22 @@ function stripObjectiveBackticks(text) {
|
|
|
2369
2468
|
function wordCount(text) {
|
|
2370
2469
|
return text.split(/\s+/).filter((w) => /[a-z]/i.test(w)).length;
|
|
2371
2470
|
}
|
|
2372
|
-
function
|
|
2373
|
-
const
|
|
2471
|
+
function objectivesSectionBounds(body) {
|
|
2472
|
+
const masked = maskedForHeadingSearch(body);
|
|
2473
|
+
const heading = HEADING_RE.exec(masked);
|
|
2374
2474
|
if (!heading)
|
|
2375
2475
|
return null;
|
|
2376
|
-
const
|
|
2476
|
+
const start = heading.index + heading[0].length;
|
|
2477
|
+
const afterHeading = masked.slice(start);
|
|
2377
2478
|
const next = NEXT_HEADING_RE.exec(afterHeading);
|
|
2378
|
-
return next ?
|
|
2479
|
+
return { start, end: next ? start + next.index : body.length };
|
|
2480
|
+
}
|
|
2481
|
+
function objectivesSectionText(body) {
|
|
2482
|
+
const bounds = objectivesSectionBounds(body);
|
|
2483
|
+
return bounds === null ? null : body.slice(bounds.start, bounds.end);
|
|
2379
2484
|
}
|
|
2380
2485
|
function hasObjectivesHeading(body) {
|
|
2381
|
-
return HEADING_RE.test(body);
|
|
2486
|
+
return HEADING_RE.test(maskedForHeadingSearch(body));
|
|
2382
2487
|
}
|
|
2383
2488
|
function objectivesOf(body) {
|
|
2384
2489
|
const section = objectivesSectionText(body);
|
|
@@ -2438,6 +2543,15 @@ function isIssueNotFoundError(err) {
|
|
|
2438
2543
|
`);
|
|
2439
2544
|
return /could not resolve to an (?:issue|pull request)|\b404\b|not found/i.test(haystack);
|
|
2440
2545
|
}
|
|
2546
|
+
function resolveObjectivesSource(prBody, issue, cutoverIssue) {
|
|
2547
|
+
if (issue !== null && issue < cutoverIssue)
|
|
2548
|
+
return { kind: "none" };
|
|
2549
|
+
if (issue !== null)
|
|
2550
|
+
return { kind: "issue", issue };
|
|
2551
|
+
if (hasObjectivesHeading(prBody))
|
|
2552
|
+
return { kind: "body" };
|
|
2553
|
+
return { kind: "none" };
|
|
2554
|
+
}
|
|
2441
2555
|
|
|
2442
2556
|
// ../../packages/aeg-core/src/premise-check.ts
|
|
2443
2557
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -2673,7 +2787,7 @@ function checkForField(prBody) {
|
|
|
2673
2787
|
]
|
|
2674
2788
|
};
|
|
2675
2789
|
}
|
|
2676
|
-
function
|
|
2790
|
+
function checkClosesNPresence(prBody) {
|
|
2677
2791
|
const closesPattern = /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s{0,8}:?\s{0,8}#\d+/i;
|
|
2678
2792
|
if (closesPattern.test(stripCode(prBody))) {
|
|
2679
2793
|
return { status: "pass", errors: [] };
|
|
@@ -2705,10 +2819,22 @@ var COMMIT_TYPES = [
|
|
|
2705
2819
|
"Test"
|
|
2706
2820
|
];
|
|
2707
2821
|
var COMMIT_TYPE_STYLE = new RegExp(`^(${COMMIT_TYPES.join("|")})(\\([a-z0-9-]+\\))?: \\S`);
|
|
2822
|
+
function checkForgeTitle(title) {
|
|
2823
|
+
const taskStyle = /^\[[a-z0-9._-]+\] \S+ — \S/;
|
|
2824
|
+
if (COMMIT_TYPE_STYLE.test(title) || taskStyle.test(title))
|
|
2825
|
+
return { status: "pass", errors: [] };
|
|
2826
|
+
return {
|
|
2827
|
+
status: "fail",
|
|
2828
|
+
errors: [
|
|
2829
|
+
`brief-validation title: "${title}" matches neither title grammar — expected \`Type: description\` / \`Type(scope): description\` (commitlint types + Plan) or \`[tranche] id — description\` (task form).`
|
|
2830
|
+
]
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2708
2833
|
var BRIEF_SHAPE_MARKERS = [checkSurfaceMap, checkDocUpdateList, checkStopConditions, checkAutonomyClause];
|
|
2709
2834
|
var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
|
|
2835
|
+
var TASK_ISSUE_BRANCH_PATTERN = /^task\/issue-\d+$/;
|
|
2710
2836
|
function isTaskBranch(branch) {
|
|
2711
|
-
return TASK_BRANCH_PATTERN.test(branch);
|
|
2837
|
+
return TASK_BRANCH_PATTERN.test(branch) || TASK_ISSUE_BRANCH_PATTERN.test(branch);
|
|
2712
2838
|
}
|
|
2713
2839
|
function isBriefShaped(prBody) {
|
|
2714
2840
|
const stripped = stripCode(prBody);
|
|
@@ -2830,8 +2956,9 @@ function packagesNamedIn(text) {
|
|
|
2830
2956
|
}
|
|
2831
2957
|
function hasTestPathForConsumer(text, consumerDir) {
|
|
2832
2958
|
const escaped = consumerDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2833
|
-
const
|
|
2834
|
-
|
|
2959
|
+
const filePathRe = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
|
|
2960
|
+
const testDirRe = new RegExp(`${escaped}\\/(?:[\\w-]+\\/)*(?:tests|specs)(?:\\/|\\b)`);
|
|
2961
|
+
return filePathRe.test(text) || testDirRe.test(text);
|
|
2835
2962
|
}
|
|
2836
2963
|
function checkConsumerTests(prBody, consumersOf) {
|
|
2837
2964
|
const section4 = extractNumberedSection(prBody, 4);
|
|
@@ -2935,21 +3062,44 @@ function checkBriefSections(prBody, readTier, options = {}) {
|
|
|
2935
3062
|
checkConsumerTests(prBody, consumersOf),
|
|
2936
3063
|
checkDefeatCases(prBody),
|
|
2937
3064
|
...issueObjectives !== undefined ? [checkObjectivesCopy(prBody, issueObjectives), checkObjectivesCoverage(prBody)] : [],
|
|
2938
|
-
...requireClosesN ? [
|
|
3065
|
+
...requireClosesN ? [checkClosesNPresence(prBody)] : []
|
|
2939
3066
|
];
|
|
2940
3067
|
return { errors: results.flatMap((r) => r.errors) };
|
|
2941
3068
|
}
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
`
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
3069
|
+
function contentAfterNLines(body, n) {
|
|
3070
|
+
let idx = -1;
|
|
3071
|
+
for (let i = 0;i < n; i++) {
|
|
3072
|
+
idx = body.indexOf(`
|
|
3073
|
+
`, idx + 1);
|
|
3074
|
+
if (idx === -1)
|
|
3075
|
+
return "";
|
|
3076
|
+
}
|
|
3077
|
+
return body.slice(idx + 1);
|
|
3078
|
+
}
|
|
3079
|
+
var BRIEF_MARKER_LINE_RE = /^<!-- aeg:brief:v(\d+) -->$/;
|
|
3080
|
+
function parseBriefMarkerVersion(firstLine) {
|
|
3081
|
+
const m = BRIEF_MARKER_LINE_RE.exec(firstLine.trim());
|
|
3082
|
+
if (!m)
|
|
3083
|
+
return null;
|
|
3084
|
+
const version = Number.parseInt(m[1], 10);
|
|
3085
|
+
return Number.isInteger(version) && version >= 1 ? version : null;
|
|
3086
|
+
}
|
|
3087
|
+
function frozenBriefContent(body, version) {
|
|
3088
|
+
return contentAfterNLines(body, version === 1 ? 2 : 3);
|
|
3089
|
+
}
|
|
3090
|
+
function resolveNewestFrozenBrief(comments, allowlist) {
|
|
3091
|
+
let best = null;
|
|
3092
|
+
for (const c of comments) {
|
|
3093
|
+
if (!isPrincipal(c.author, allowlist))
|
|
3094
|
+
continue;
|
|
3095
|
+
const version = parseBriefMarkerVersion(c.body.split(`
|
|
3096
|
+
`)[0] ?? "");
|
|
3097
|
+
if (version === null)
|
|
3098
|
+
continue;
|
|
3099
|
+
if (best === null || version > best.version)
|
|
3100
|
+
best = { ...c, version };
|
|
3101
|
+
}
|
|
3102
|
+
return best === null ? null : { ...best, content: frozenBriefContent(best.body, best.version) };
|
|
2953
3103
|
}
|
|
2954
3104
|
// ../../packages/aeg-core/src/doctrine-portability.ts
|
|
2955
3105
|
var DEFAULT_SHIPS_PREFIX = "aeg-root/";
|
|
@@ -3202,6 +3352,28 @@ function topLevelSectionText(body, headingName) {
|
|
|
3202
3352
|
const next = /^##[ \t]/m.exec(afterHeading);
|
|
3203
3353
|
return next ? afterHeading.slice(0, next.index) : afterHeading;
|
|
3204
3354
|
}
|
|
3355
|
+
function partHasBacktickedPath(text) {
|
|
3356
|
+
let i = 0;
|
|
3357
|
+
while (i < text.length) {
|
|
3358
|
+
const start = text.indexOf("`", i);
|
|
3359
|
+
if (start === -1)
|
|
3360
|
+
return false;
|
|
3361
|
+
const end = text.indexOf("`", start + 1);
|
|
3362
|
+
if (end === -1)
|
|
3363
|
+
return false;
|
|
3364
|
+
if (text.slice(start + 1, end).includes("/"))
|
|
3365
|
+
return true;
|
|
3366
|
+
i = end + 1;
|
|
3367
|
+
}
|
|
3368
|
+
return false;
|
|
3369
|
+
}
|
|
3370
|
+
var PART_MIN_WORDS_OUTSIDE_BACKTICKS = 3;
|
|
3371
|
+
function stripPartBackticks(text) {
|
|
3372
|
+
return text.replace(/`[^`\n]*`/g, " ");
|
|
3373
|
+
}
|
|
3374
|
+
function partWordCount(text) {
|
|
3375
|
+
return text.split(/\s+/).filter((w) => /[a-z]/i.test(w)).length;
|
|
3376
|
+
}
|
|
3205
3377
|
function looksLikeFilePath(entry2) {
|
|
3206
3378
|
const stripped = entry2.replace(/\/\*\*?$/, "");
|
|
3207
3379
|
const lastSegment = stripped.split("/").pop() ?? stripped;
|
|
@@ -3242,6 +3414,18 @@ function globCoversPath(glob, path) {
|
|
|
3242
3414
|
const p = path.replace(/\/+$/, "");
|
|
3243
3415
|
return g === p || g.startsWith(`${p}/`) || p.startsWith(`${g}/`);
|
|
3244
3416
|
}
|
|
3417
|
+
function checkSurfaceGlobsResolve(body, resolvesToFile) {
|
|
3418
|
+
const surface = parseIssueSurface(body);
|
|
3419
|
+
if (!surface.ok)
|
|
3420
|
+
return { status: "pass", errors: [] };
|
|
3421
|
+
const errors = [];
|
|
3422
|
+
for (const glob of surface.value.in) {
|
|
3423
|
+
if (!resolvesToFile(glob)) {
|
|
3424
|
+
errors.push(`issue-validation Surface: \`${glob}\` in \`## Surface\`'s \`in:\` list matches no tracked file — a Surface that cannot resolve cannot render a brief's file list.`);
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
return { status: errors.length > 0 ? "fail" : "pass", errors };
|
|
3428
|
+
}
|
|
3245
3429
|
function checkSurfaceScope(changedFiles, outGlobs) {
|
|
3246
3430
|
if (outGlobs.length === 0)
|
|
3247
3431
|
return { ok: true };
|
|
@@ -3253,9 +3437,77 @@ function checkSurfaceScope(changedFiles, outGlobs) {
|
|
|
3253
3437
|
}
|
|
3254
3438
|
return violations.length > 0 ? { ok: false, violations } : { ok: true };
|
|
3255
3439
|
}
|
|
3440
|
+
var ISSUE_PART_LINE_RE = /^Part\s+(\d+)\s*\(([^)]*)\)\s*[-—–]\s*(.*)$/i;
|
|
3441
|
+
function parseIssueParts(body) {
|
|
3442
|
+
const section = topLevelSectionText(body, "Parts");
|
|
3443
|
+
if (section === null)
|
|
3444
|
+
return { ok: false, errors: ["no `## Parts` heading found in the body."] };
|
|
3445
|
+
const lines = section.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
|
|
3446
|
+
const parts = [];
|
|
3447
|
+
const errors = [];
|
|
3448
|
+
for (const line of lines) {
|
|
3449
|
+
const m = ISSUE_PART_LINE_RE.exec(line);
|
|
3450
|
+
if (!m) {
|
|
3451
|
+
errors.push(`"${line}" is not a well-formed Parts line — expected \`Part <n> (<refs>) — <outcome>\`.`);
|
|
3452
|
+
continue;
|
|
3453
|
+
}
|
|
3454
|
+
const n = Number.parseInt(m[1], 10);
|
|
3455
|
+
const refs = m[2];
|
|
3456
|
+
const text = m[3].trim();
|
|
3457
|
+
if (text.length === 0) {
|
|
3458
|
+
errors.push(`Part ${n} has no outcome text after the dash — every Part states one observable outcome.`);
|
|
3459
|
+
continue;
|
|
3460
|
+
}
|
|
3461
|
+
if (partHasBacktickedPath(text) && partWordCount(stripPartBackticks(text)) < PART_MIN_WORDS_OUTSIDE_BACKTICKS) {
|
|
3462
|
+
errors.push(`Part ${n} is little more than a file path — a Part names an outcome and symbols, never a bare path.`);
|
|
3463
|
+
continue;
|
|
3464
|
+
}
|
|
3465
|
+
const objectiveIds = [...refs.matchAll(/O(\d+)/g)].map((r) => Number.parseInt(r[1], 10));
|
|
3466
|
+
parts.push({ n, objectiveIds, text });
|
|
3467
|
+
}
|
|
3468
|
+
if (parts.length === 0) {
|
|
3469
|
+
errors.push("the `## Parts` section has no well-formed `Part <n> (<refs>) — <outcome>` lines.");
|
|
3470
|
+
}
|
|
3471
|
+
if (errors.length > 0)
|
|
3472
|
+
return { ok: false, errors };
|
|
3473
|
+
return { ok: true, value: parts };
|
|
3474
|
+
}
|
|
3475
|
+
function checkPartsCiteDefinedObjectives(body) {
|
|
3476
|
+
const parts = parseIssueParts(body);
|
|
3477
|
+
const objectives = objectivesOf(body);
|
|
3478
|
+
if (!parts.ok || !objectives.ok)
|
|
3479
|
+
return { status: "pass", errors: [] };
|
|
3480
|
+
const definedIds = new Set(objectives.objectives.map((o) => Number.parseInt(o.id.slice(1), 10)));
|
|
3481
|
+
const errors = [];
|
|
3482
|
+
for (const part of parts.value) {
|
|
3483
|
+
for (const objectiveId of part.objectiveIds) {
|
|
3484
|
+
if (!definedIds.has(objectiveId)) {
|
|
3485
|
+
errors.push(`issue-validation Parts: Part ${part.n} cites O${objectiveId}, which the Issue's own \`## Objectives\` section does not define.`);
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
return { status: errors.length > 0 ? "fail" : "pass", errors };
|
|
3490
|
+
}
|
|
3256
3491
|
function isTaskIssueLabelSet(labels) {
|
|
3257
3492
|
return hasLabel("tranche", labels);
|
|
3258
3493
|
}
|
|
3494
|
+
function checkTrancheLabelPresence(_body, _labels) {
|
|
3495
|
+
return { status: "pass", errors: [] };
|
|
3496
|
+
}
|
|
3497
|
+
function checkMilestoneAttach(labels, currentMilestoneTitle, resolvedMilestoneTitle) {
|
|
3498
|
+
if (!isTaskIssueLabelSet(labels))
|
|
3499
|
+
return { status: "pass", errors: [] };
|
|
3500
|
+
if (resolvedMilestoneTitle === null)
|
|
3501
|
+
return { status: "pass", errors: [] };
|
|
3502
|
+
if (currentMilestoneTitle === resolvedMilestoneTitle)
|
|
3503
|
+
return { status: "pass", errors: [] };
|
|
3504
|
+
return {
|
|
3505
|
+
status: "fail",
|
|
3506
|
+
errors: [
|
|
3507
|
+
`issue-validation milestone attach: this task Issue's tranche label resolves to Milestone "${resolvedMilestoneTitle}", but its live Milestone is ${currentMilestoneTitle === null ? "unset" : `"${currentMilestoneTitle}"`} — attach it to "${resolvedMilestoneTitle}".`
|
|
3508
|
+
]
|
|
3509
|
+
};
|
|
3510
|
+
}
|
|
3259
3511
|
var TYPE_LABEL_IDS = LABELS.filter((l) => l.category === "type").map((l) => l.id);
|
|
3260
3512
|
function isControlCodePoint(codePoint) {
|
|
3261
3513
|
return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
|
|
@@ -3320,6 +3572,19 @@ function checkProjectsRegistered(body, _labels, registeredNames) {
|
|
|
3320
3572
|
var DOC_PATH_RE = /(?:(?:aeg-root|apps|packages|specs|docs|tools|\.claude|\.github)\/[\w./@-]*\.(?:md|mdx)|\.claude\/(?:skills|rules)\/[\w./-]+|\b(?:docs-index|decisions|projects|state-machine|enforcement|process|README|CLAUDE)\.md\b|\b[\w-]+-(?:spec|decisions|backlog)\.md\b)/i;
|
|
3321
3573
|
var DOC_PATH_RE_GLOBAL = new RegExp(DOC_PATH_RE.source, "gi");
|
|
3322
3574
|
|
|
3575
|
+
// ../../packages/aeg-core/src/task-branch-identity.ts
|
|
3576
|
+
var ISSUE_BRANCH_PATTERN = /^task\/issue-(\d+)$/;
|
|
3577
|
+
var TRANCHE_BRANCH_PATTERN = /^task\/([^/]+)\/([^/]+)$/;
|
|
3578
|
+
function parseTaskBranchIdentity(branch) {
|
|
3579
|
+
const issueMatch = ISSUE_BRANCH_PATTERN.exec(branch);
|
|
3580
|
+
if (issueMatch)
|
|
3581
|
+
return { kind: "issue", issueNumber: Number(issueMatch[1]) };
|
|
3582
|
+
const trancheMatch = TRANCHE_BRANCH_PATTERN.exec(branch);
|
|
3583
|
+
if (trancheMatch)
|
|
3584
|
+
return { kind: "tranche", tranche: trancheMatch[1], taskId: trancheMatch[2] };
|
|
3585
|
+
return null;
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3323
3588
|
// ../../packages/aeg-core/src/coherence-checks.ts
|
|
3324
3589
|
var COHERENCE_ENFORCED_FROM = "2026-07-01";
|
|
3325
3590
|
function isGrandfathered(isoDate) {
|
|
@@ -3340,6 +3605,7 @@ function checkA1(entries, principalAllowlist = PRINCIPAL_ALLOWLIST) {
|
|
|
3340
3605
|
if (handClosed)
|
|
3341
3606
|
continue;
|
|
3342
3607
|
failures.push({
|
|
3608
|
+
code: "closed-without-merge",
|
|
3343
3609
|
issue: e.task.issue,
|
|
3344
3610
|
tranche: e.trancheSlug,
|
|
3345
3611
|
task: e.task.id,
|
|
@@ -3364,6 +3630,7 @@ function checkA3(entries) {
|
|
|
3364
3630
|
continue;
|
|
3365
3631
|
if (e.facts.prState === "merged" && e.facts.issueState !== "closed") {
|
|
3366
3632
|
failures.push({
|
|
3633
|
+
code: "auto-close-misfire",
|
|
3367
3634
|
issue: e.task.issue,
|
|
3368
3635
|
tranche: e.trancheSlug,
|
|
3369
3636
|
task: e.task.id,
|
|
@@ -3388,6 +3655,7 @@ function checkT1(entries) {
|
|
|
3388
3655
|
continue;
|
|
3389
3656
|
if (e.facts === undefined) {
|
|
3390
3657
|
failures.push({
|
|
3658
|
+
code: "phantom-issue-ref",
|
|
3391
3659
|
issue: e.task.issue,
|
|
3392
3660
|
tranche: e.trancheSlug,
|
|
3393
3661
|
task: e.task.id,
|
|
@@ -3406,6 +3674,7 @@ function checkT2(openIssuesBySlug, topologyIssuesBySlug, ciTrancheSlug) {
|
|
|
3406
3674
|
for (const num of openNums) {
|
|
3407
3675
|
if (!topologySet.has(num)) {
|
|
3408
3676
|
failures.push({
|
|
3677
|
+
code: "orphan-task",
|
|
3409
3678
|
issue: num,
|
|
3410
3679
|
tranche: slug,
|
|
3411
3680
|
reason: `Issue #${num} is open and labeled ${trancheLabel(slug)} but does not appear in the topology file`
|
|
@@ -3440,6 +3709,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
|
|
|
3440
3709
|
continue;
|
|
3441
3710
|
if (forgeUnavailableSlugs?.has(e.trancheSlug)) {
|
|
3442
3711
|
failures.push({
|
|
3712
|
+
code: "tbd-in-active-tranche",
|
|
3443
3713
|
issue: null,
|
|
3444
3714
|
tranche: e.trancheSlug,
|
|
3445
3715
|
task: e.task.id,
|
|
@@ -3449,6 +3719,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
|
|
|
3449
3719
|
continue;
|
|
3450
3720
|
}
|
|
3451
3721
|
failures.push({
|
|
3722
|
+
code: "tbd-in-active-tranche",
|
|
3452
3723
|
issue: null,
|
|
3453
3724
|
tranche: e.trancheSlug,
|
|
3454
3725
|
task: e.task.id,
|
|
@@ -3481,6 +3752,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
|
|
|
3481
3752
|
const sameIssue = depEntry.task.issue !== null && e.task.issue !== null && depEntry.task.issue === e.task.issue;
|
|
3482
3753
|
if (sameTask || sameIssue) {
|
|
3483
3754
|
failures.push({
|
|
3755
|
+
code: "d1-self-dependency",
|
|
3484
3756
|
issue: e.task.issue,
|
|
3485
3757
|
tranche: e.trancheSlug,
|
|
3486
3758
|
task: e.task.id,
|
|
@@ -3492,6 +3764,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
|
|
|
3492
3764
|
const depClosed = depFacts?.issueState === "closed";
|
|
3493
3765
|
if (!depClosed) {
|
|
3494
3766
|
failures.push({
|
|
3767
|
+
code: "dispatched-on-unmet-deps",
|
|
3495
3768
|
issue: e.task.issue,
|
|
3496
3769
|
tranche: e.trancheSlug,
|
|
3497
3770
|
task: e.task.id,
|
|
@@ -3517,11 +3790,13 @@ function checkR1(issuesBySlug, grandfatheredIssues, registeredNames = []) {
|
|
|
3517
3790
|
const errors = [
|
|
3518
3791
|
...checkIssueRationale(issue.body).errors,
|
|
3519
3792
|
...checkProjectsRegistered(issue.body, issue.labels, registeredNames).errors,
|
|
3520
|
-
...checkIssueObjectives(issue.body, issue.number).errors
|
|
3793
|
+
...checkIssueObjectives(issue.body, issue.number).errors,
|
|
3794
|
+
...checkPartsCiteDefinedObjectives(issue.body).errors
|
|
3521
3795
|
];
|
|
3522
3796
|
if (errors.length === 0)
|
|
3523
3797
|
continue;
|
|
3524
3798
|
failures.push({
|
|
3799
|
+
code: "missing-rationale-field",
|
|
3525
3800
|
issue: issue.number,
|
|
3526
3801
|
tranche: slug,
|
|
3527
3802
|
reason: `Issue #${issue.number} fails the rationale gate: ${errors.join(" | ")}`,
|
|
@@ -3550,6 +3825,7 @@ function checkL1(files, entriesBySlug) {
|
|
|
3550
3825
|
const allClosed = withFacts.every((e) => e.facts?.issueState === "closed");
|
|
3551
3826
|
if (allClosed) {
|
|
3552
3827
|
failures.push({
|
|
3828
|
+
code: "archive-recommended",
|
|
3553
3829
|
tranche: f.slug,
|
|
3554
3830
|
reason: "Active tranche has no open task-Issues — consider archiving to completed/"
|
|
3555
3831
|
});
|
|
@@ -3581,27 +3857,38 @@ function extractClosesReferences(prBody) {
|
|
|
3581
3857
|
}
|
|
3582
3858
|
return referenced;
|
|
3583
3859
|
}
|
|
3584
|
-
function
|
|
3860
|
+
function checkClosesNTopology(branch, prBody, trancheFiles, taskIssueRefs) {
|
|
3585
3861
|
const referenced = extractClosesReferences(prBody);
|
|
3586
3862
|
if (taskIssueRefs) {
|
|
3587
3863
|
for (const n of referenced) {
|
|
3588
|
-
const
|
|
3589
|
-
if (!
|
|
3864
|
+
const ref2 = taskIssueRefs.get(n);
|
|
3865
|
+
if (!ref2)
|
|
3590
3866
|
continue;
|
|
3591
|
-
const expectedBranch = `task/${
|
|
3867
|
+
const expectedBranch = `task/${ref2.trancheSlug}/${ref2.taskId}`;
|
|
3592
3868
|
if (branch !== expectedBranch) {
|
|
3593
3869
|
return {
|
|
3594
3870
|
ok: false,
|
|
3595
|
-
message: `closes-n-reverse: branch "${branch}" closes #${n} (task ${
|
|
3871
|
+
message: `closes-n-reverse: branch "${branch}" closes #${n} (task ${ref2.taskId} of tranche "${ref2.trancheSlug}") but is not named "${expectedBranch}" — rename the branch and re-push, or if this work is intentionally outside AEG's dispatch flow, remove the Closes reference.`
|
|
3596
3872
|
};
|
|
3597
3873
|
}
|
|
3598
3874
|
}
|
|
3599
3875
|
}
|
|
3600
|
-
const
|
|
3601
|
-
if (!
|
|
3876
|
+
const ref = parseTaskBranchIdentity(branch);
|
|
3877
|
+
if (!ref)
|
|
3602
3878
|
return { ok: true };
|
|
3603
|
-
|
|
3604
|
-
|
|
3879
|
+
if (ref.kind === "issue") {
|
|
3880
|
+
const expectedIssue2 = ref.issueNumber;
|
|
3881
|
+
if (!referenced.has(expectedIssue2)) {
|
|
3882
|
+
return {
|
|
3883
|
+
ok: false,
|
|
3884
|
+
expectedIssue: expectedIssue2,
|
|
3885
|
+
message: `closes-n: PR body does not contain \`Closes #${expectedIssue2}\` (required for branch "${branch}"). Add it to the PR body Summary section.`
|
|
3886
|
+
};
|
|
3887
|
+
}
|
|
3888
|
+
return { ok: true, expectedIssue: expectedIssue2 };
|
|
3889
|
+
}
|
|
3890
|
+
const trancheSlug = ref.tranche;
|
|
3891
|
+
const taskId = ref.taskId;
|
|
3605
3892
|
const trancheFile = trancheFiles.find((f) => f.slug === trancheSlug);
|
|
3606
3893
|
if (!trancheFile) {
|
|
3607
3894
|
return {
|
|
@@ -3653,29 +3940,67 @@ function extractIssue(body) {
|
|
|
3653
3940
|
const issue = headerNums.length > 0 ? headerNums[0] : bodyNums[0];
|
|
3654
3941
|
return { issue, extraIssues: bodyNums.filter((n) => n !== issue), outsideHeader: headerNums.length === 0 };
|
|
3655
3942
|
}
|
|
3656
|
-
// ../../packages/aeg-core/src/review-
|
|
3657
|
-
|
|
3658
|
-
|
|
3943
|
+
// ../../packages/aeg-core/src/review-input-manifest.ts
|
|
3944
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
3945
|
+
function briefHash(brief) {
|
|
3946
|
+
return createHash4("sha256").update(`${brief}
|
|
3947
|
+
`).digest("hex");
|
|
3948
|
+
}
|
|
3949
|
+
function policyDigest(policy) {
|
|
3950
|
+
return createHash4("sha256").update(JSON.stringify({ codeReviewThreshold: policy.codeReviewThreshold, securityThreshold: policy.securityThreshold })).digest("hex");
|
|
3951
|
+
}
|
|
3952
|
+
function isBoundToHead(echoed, headSha) {
|
|
3953
|
+
if (!echoed.headSha)
|
|
3659
3954
|
return false;
|
|
3660
|
-
return headSha.toLowerCase().startsWith(
|
|
3955
|
+
return headSha.toLowerCase().startsWith(echoed.headSha.toLowerCase());
|
|
3661
3956
|
}
|
|
3662
|
-
function isBoundByPatchIdentity(
|
|
3663
|
-
if (patchIdOf === undefined || !
|
|
3957
|
+
function isBoundByPatchIdentity(echoed, headSha, patchIdOf) {
|
|
3958
|
+
if (patchIdOf === undefined || !echoed.headSha)
|
|
3664
3959
|
return false;
|
|
3665
|
-
const judged = patchIdOf(
|
|
3960
|
+
const judged = patchIdOf(echoed.headSha);
|
|
3666
3961
|
const current = patchIdOf(headSha);
|
|
3667
3962
|
if (judged === null || current === null)
|
|
3668
3963
|
return false;
|
|
3669
3964
|
return judged === current;
|
|
3670
3965
|
}
|
|
3671
|
-
function isBoundToPatch(
|
|
3672
|
-
return isBoundToHead(
|
|
3966
|
+
function isBoundToPatch(echoed, headSha, patchIdOf) {
|
|
3967
|
+
return isBoundToHead(echoed, headSha) || isBoundByPatchIdentity(echoed, headSha, patchIdOf);
|
|
3673
3968
|
}
|
|
3674
|
-
function isBoundToObjectives(
|
|
3969
|
+
function isBoundToObjectives(echoed, currentVersion) {
|
|
3675
3970
|
if (currentVersion === null)
|
|
3676
3971
|
return true;
|
|
3677
|
-
return
|
|
3972
|
+
return echoed.objectivesVersion === currentVersion;
|
|
3973
|
+
}
|
|
3974
|
+
function isBoundToRulings(echoed, currentOrdinal) {
|
|
3975
|
+
if (echoed.rulingOrdinal === null)
|
|
3976
|
+
return currentOrdinal === 0;
|
|
3977
|
+
return echoed.rulingOrdinal === currentOrdinal;
|
|
3978
|
+
}
|
|
3979
|
+
function isBoundToBriefHash(echoed, currentHash) {
|
|
3980
|
+
if (currentHash === null)
|
|
3981
|
+
return true;
|
|
3982
|
+
return echoed.briefHash === currentHash;
|
|
3678
3983
|
}
|
|
3984
|
+
function isBoundToPolicy(echoed, currentDigest) {
|
|
3985
|
+
return echoed.policyDigest === currentDigest;
|
|
3986
|
+
}
|
|
3987
|
+
function compareManifest(echoed, current, patchIdOf) {
|
|
3988
|
+
const head = isBoundToPatch(echoed, current.headSha, patchIdOf);
|
|
3989
|
+
const briefHashBound = isBoundToBriefHash(echoed, current.briefHash);
|
|
3990
|
+
const objectivesVersion2 = isBoundToObjectives(echoed, current.objectivesVersion);
|
|
3991
|
+
const rulingOrdinal = isBoundToRulings(echoed, current.rulingOrdinal);
|
|
3992
|
+
const policyDigestBound = isBoundToPolicy(echoed, current.policyDigest);
|
|
3993
|
+
return {
|
|
3994
|
+
bound: head && briefHashBound && objectivesVersion2 && rulingOrdinal && policyDigestBound,
|
|
3995
|
+
head,
|
|
3996
|
+
briefHash: briefHashBound,
|
|
3997
|
+
objectivesVersion: objectivesVersion2,
|
|
3998
|
+
rulingOrdinal,
|
|
3999
|
+
policyDigest: policyDigestBound
|
|
4000
|
+
};
|
|
4001
|
+
}
|
|
4002
|
+
|
|
4003
|
+
// ../../packages/aeg-core/src/review-gate.ts
|
|
3679
4004
|
function checkReviewGate(input) {
|
|
3680
4005
|
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
3681
4006
|
const waived = isWaiverLabelActorVerified({
|
|
@@ -3698,13 +4023,55 @@ function checkReviewGate(input) {
|
|
|
3698
4023
|
const verifiedBodies = verified.map((c) => c.body);
|
|
3699
4024
|
const codeReview = extractCodeReviewVerdict(verifiedBodies);
|
|
3700
4025
|
const security = extractSecurityReviewVerdict(verifiedBodies);
|
|
3701
|
-
const
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
4026
|
+
const policy = input.policy ?? DEFAULT_REVIEW_POLICY;
|
|
4027
|
+
let codeReviewPolicyEvaluation;
|
|
4028
|
+
let securityPolicyEvaluation;
|
|
4029
|
+
try {
|
|
4030
|
+
codeReviewPolicyEvaluation = evaluateCodeReview(codeReview.findingSeverities, policy);
|
|
4031
|
+
securityPolicyEvaluation = evaluateSecurityReview(security.findingSeverities, policy);
|
|
4032
|
+
} catch (err) {
|
|
4033
|
+
return {
|
|
4034
|
+
verdict: "fail",
|
|
4035
|
+
reason: `a verdict comment carries a finding severity this repository's policy does not recognize: ${err instanceof Error ? err.message : String(err)}`,
|
|
4036
|
+
waived: false
|
|
4037
|
+
};
|
|
4038
|
+
}
|
|
4039
|
+
const codeReviewTextClean = codeReview.value === "APPROVE";
|
|
4040
|
+
const securityTextClean = security.value === "PASS";
|
|
4041
|
+
const codeReviewPolicyClean = codeReviewPolicyEvaluation.outcome === "clean";
|
|
4042
|
+
const securityPolicyClean = securityPolicyEvaluation.outcome === "clean";
|
|
4043
|
+
const codeReviewClean = codeReviewTextClean && codeReviewPolicyClean;
|
|
4044
|
+
const securityClean = securityTextClean && securityPolicyClean;
|
|
4045
|
+
const currentManifest = {
|
|
4046
|
+
headSha: input.headSha,
|
|
4047
|
+
briefHash: input.briefHash ?? null,
|
|
4048
|
+
objectivesVersion: input.objectivesVersion,
|
|
4049
|
+
rulingOrdinal: input.rulingOrdinal,
|
|
4050
|
+
policyDigest: policyDigest(policy)
|
|
4051
|
+
};
|
|
4052
|
+
const codeReviewEchoed = {
|
|
4053
|
+
headSha: codeReview.headSha,
|
|
4054
|
+
briefHash: codeReview.briefHash,
|
|
4055
|
+
objectivesVersion: codeReview.objectivesVersion,
|
|
4056
|
+
rulingOrdinal: codeReview.rulingOrdinal,
|
|
4057
|
+
policyDigest: codeReview.policyDigest
|
|
4058
|
+
};
|
|
4059
|
+
const securityEchoed = {
|
|
4060
|
+
headSha: security.headSha,
|
|
4061
|
+
briefHash: security.briefHash,
|
|
4062
|
+
objectivesVersion: security.objectivesVersion,
|
|
4063
|
+
rulingOrdinal: security.rulingOrdinal,
|
|
4064
|
+
policyDigest: security.policyDigest
|
|
4065
|
+
};
|
|
4066
|
+
const codeReviewBinding = compareManifest(codeReviewEchoed, currentManifest, input.patchIdOf);
|
|
4067
|
+
const securityBinding = compareManifest(securityEchoed, currentManifest, input.patchIdOf);
|
|
4068
|
+
const codeReviewBound = codeReviewBinding.head;
|
|
4069
|
+
const securityBound = securityBinding.head;
|
|
4070
|
+
const codeReviewObjectivesBound = codeReviewBinding.objectivesVersion;
|
|
4071
|
+
const securityObjectivesBound = securityBinding.objectivesVersion;
|
|
4072
|
+
const codeReviewRulingsBound = codeReviewBinding.rulingOrdinal;
|
|
4073
|
+
const securityRulingsBound = securityBinding.rulingOrdinal;
|
|
4074
|
+
if (codeReviewClean && codeReviewBinding.bound && securityClean && securityBinding.bound && mechanicalChecksClean) {
|
|
3708
4075
|
return {
|
|
3709
4076
|
verdict: "pass",
|
|
3710
4077
|
reason: `code-reviewer verdict is a clean APPROVE and security-review verdict is a clean PASS, both covering head ${input.headSha}, and every reported mechanical check is green.`,
|
|
@@ -3712,19 +4079,35 @@ function checkReviewGate(input) {
|
|
|
3712
4079
|
};
|
|
3713
4080
|
}
|
|
3714
4081
|
const problems = [];
|
|
3715
|
-
if (!
|
|
4082
|
+
if (!codeReviewTextClean) {
|
|
3716
4083
|
problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
|
|
4084
|
+
} else if (!codeReviewPolicyClean) {
|
|
4085
|
+
problems.push(`code-reviewer verdict says APPROVE but carries a finding (${codeReviewPolicyEvaluation.blockingFindings.map((f) => f.severity).join(", ")}) at or above this repository's code-review policy threshold (${policy.codeReviewThreshold}) — a reviewer's own APPROVE never overrides policy`);
|
|
3717
4086
|
} else if (!codeReviewBound) {
|
|
3718
4087
|
problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
3719
4088
|
} else if (!codeReviewObjectivesBound) {
|
|
3720
4089
|
problems.push(`the newest code-review verdict was cast against objectives version ${codeReview.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
|
|
3721
|
-
}
|
|
3722
|
-
|
|
4090
|
+
} else if (!codeReviewRulingsBound) {
|
|
4091
|
+
problems.push(`the newest code-review verdict was cast against ruling ordinal ${codeReview.rulingOrdinal ?? "none"}, a newer ruling (ruling ${input.rulingOrdinal}) is now posted on this PR`);
|
|
4092
|
+
} else if (!codeReviewBinding.briefHash) {
|
|
4093
|
+
problems.push(`the newest code-review verdict was cast against brief hash ${codeReview.briefHash ?? "none"}, the frozen brief's current hash is ${currentManifest.briefHash ?? "none"}`);
|
|
4094
|
+
} else if (!codeReviewBinding.policyDigest) {
|
|
4095
|
+
problems.push(`the newest code-review verdict was cast against review policy digest ${codeReview.policyDigest ?? "none"}, this repository's current policy digest is ${currentManifest.policyDigest}`);
|
|
4096
|
+
}
|
|
4097
|
+
if (!securityTextClean) {
|
|
3723
4098
|
problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
|
|
4099
|
+
} else if (!securityPolicyClean) {
|
|
4100
|
+
problems.push(`security-review verdict says PASS but carries a finding (${securityPolicyEvaluation.blockingFindings.map((f) => f.severity).join(", ")}) at or above this repository's security policy threshold (${policy.securityThreshold}) — a reviewer's own PASS never overrides policy`);
|
|
3724
4101
|
} else if (!securityBound) {
|
|
3725
4102
|
problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
3726
4103
|
} else if (!securityObjectivesBound) {
|
|
3727
4104
|
problems.push(`the newest security-review verdict was cast against objectives version ${security.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
|
|
4105
|
+
} else if (!securityRulingsBound) {
|
|
4106
|
+
problems.push(`the newest security-review verdict was cast against ruling ordinal ${security.rulingOrdinal ?? "none"}, a newer ruling (ruling ${input.rulingOrdinal}) is now posted on this PR`);
|
|
4107
|
+
} else if (!securityBinding.briefHash) {
|
|
4108
|
+
problems.push(`the newest security-review verdict was cast against brief hash ${security.briefHash ?? "none"}, the frozen brief's current hash is ${currentManifest.briefHash ?? "none"}`);
|
|
4109
|
+
} else if (!securityBinding.policyDigest) {
|
|
4110
|
+
problems.push(`the newest security-review verdict was cast against review policy digest ${security.policyDigest ?? "none"}, this repository's current policy digest is ${currentManifest.policyDigest}`);
|
|
3728
4111
|
}
|
|
3729
4112
|
if (!mechanicalChecksClean) {
|
|
3730
4113
|
problems.push(reportedMechanicalChecks.length === 0 ? "no mechanical checks have reported for this head yet" : `mechanical check(s) not green: ${reportedMechanicalChecks.filter((c) => c.bucket !== "pass").map((c) => `${c.name} (${c.bucket})`).join(", ")}`);
|
|
@@ -3741,6 +4124,24 @@ var DEFAULT_RELEASE_ACTOR = "github-actions[bot]";
|
|
|
3741
4124
|
function isChangesetsReleasePr(branch, author, expectedAuthor) {
|
|
3742
4125
|
return branch === CHANGESET_RELEASE_BRANCH && author === expectedAuthor;
|
|
3743
4126
|
}
|
|
4127
|
+
// ../../packages/aeg-core/src/ruling-ordinal.ts
|
|
4128
|
+
var RULING_MARKER_ORDINAL = /^<!-- aeg:principal:ruling:\d+-(\d+) -->$/;
|
|
4129
|
+
function newestPrincipalRulingOrdinal(comments, allowlist) {
|
|
4130
|
+
let best = 0;
|
|
4131
|
+
for (const c of comments) {
|
|
4132
|
+
if (!isPrincipal(c.author, allowlist))
|
|
4133
|
+
continue;
|
|
4134
|
+
const firstLine = (c.body.split(`
|
|
4135
|
+
`)[0] ?? "").trim();
|
|
4136
|
+
const m = RULING_MARKER_ORDINAL.exec(firstLine);
|
|
4137
|
+
if (!m)
|
|
4138
|
+
continue;
|
|
4139
|
+
const k = Number.parseInt(m[1], 10);
|
|
4140
|
+
if (k > best)
|
|
4141
|
+
best = k;
|
|
4142
|
+
}
|
|
4143
|
+
return best;
|
|
4144
|
+
}
|
|
3744
4145
|
// ../../packages/aeg-core/src/markdown-table.ts
|
|
3745
4146
|
function splitRow(line) {
|
|
3746
4147
|
const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
@@ -4398,42 +4799,45 @@ function checkDispatchReadiness(input) {
|
|
|
4398
4799
|
const { trancheSlug, task } = input;
|
|
4399
4800
|
const taskLabel = `task ${task.id} (tranche ${trancheSlug})`;
|
|
4400
4801
|
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
4401
|
-
const
|
|
4802
|
+
const blockerDetails = [];
|
|
4803
|
+
const push = (blockerClass, message) => {
|
|
4804
|
+
blockerDetails.push({ class: blockerClass, message });
|
|
4805
|
+
};
|
|
4402
4806
|
if (task.issue === null) {
|
|
4403
|
-
|
|
4807
|
+
push("issue-existence", `dispatch-gate issue-existence: ${taskLabel} has no Issue (#TBD or blank) in the topology — not dispatchable until the Planner cuts the Issue.`);
|
|
4404
4808
|
} else if (input.issue === null) {
|
|
4405
|
-
|
|
4809
|
+
push("issue-existence", `dispatch-gate issue-existence: ${taskLabel} names Issue #${task.issue}, but it does not resolve to a real GitHub Issue (phantom reference).`);
|
|
4406
4810
|
}
|
|
4407
4811
|
if (input.issue !== null && !input.issueRationalePass) {
|
|
4408
|
-
|
|
4812
|
+
push("rationale", `dispatch-gate rationale: Issue #${input.issue.number} for ${taskLabel} fails the rationale gate (checkIssueRationale) — the Planner must complete the eight-field rationale before this task is dispatchable.`);
|
|
4409
4813
|
}
|
|
4410
4814
|
for (const dep of input.dependsOn) {
|
|
4411
4815
|
if (isSelfDependency(dep, task, input.issue)) {
|
|
4412
4816
|
const issueStr = input.issue !== null ? `#${input.issue.number}` : "?";
|
|
4413
|
-
|
|
4817
|
+
push("internal-self-dependency", `dispatch-gate INTERNAL: parsed a self-dependency for task ${task.id} (${issueStr}) — this is a parser bug in parseRationaleDeps, not a real dependency. Please report it upstream. Re-run once the rationale is corrected or the fix ships.`);
|
|
4414
4818
|
continue;
|
|
4415
4819
|
}
|
|
4416
4820
|
if (dep.resolved === false) {
|
|
4417
|
-
|
|
4821
|
+
push("depends-on-unresolvable", `dispatch-gate depends-on: ${taskLabel} depends on "${dep.id}", which is UNRESOLVABLE — the resolver could not find a matching tranche/task/Issue for this edge (not a claim about merge status). Not dispatchable until the edge is corrected.`);
|
|
4418
4822
|
continue;
|
|
4419
4823
|
}
|
|
4420
4824
|
if (!dep.merged && !isHandClosedByRecognizedPrincipal(dep, principalAllowlist)) {
|
|
4421
4825
|
const issueStr = dep.issue !== null ? ` (#${dep.issue})` : "";
|
|
4422
|
-
|
|
4826
|
+
push("depends-on-not-merged", `dispatch-gate depends-on: ${taskLabel} depends on ${dep.id}${issueStr}, whose PR is not merged yet — not dispatchable, it serializes behind it.`);
|
|
4423
4827
|
}
|
|
4424
4828
|
}
|
|
4425
4829
|
for (const c of input.conflictsWith) {
|
|
4426
4830
|
if (c.openOrInFlight) {
|
|
4427
4831
|
const issueStr = c.issue !== null ? ` (#${c.issue})` : "";
|
|
4428
|
-
|
|
4832
|
+
push("conflicts-with", `dispatch-gate conflicts-with: ${taskLabel} conflicts with ${c.id}${issueStr}, whose PR is open or in-flight — not dispatchable until it merges.`);
|
|
4429
4833
|
}
|
|
4430
4834
|
}
|
|
4431
4835
|
for (const proj of input.priorTrancheArchival) {
|
|
4432
4836
|
if (proj.priorTrancheSlug !== null && !proj.archived) {
|
|
4433
|
-
|
|
4837
|
+
push("prior-tranche-archival", `dispatch-gate prior-tranche-archival: project \`${proj.project}\`'s previous tranche \`${proj.priorTrancheSlug}\` is not archived — the Tranche Archivist must run before new work on this product.`);
|
|
4434
4838
|
}
|
|
4435
4839
|
}
|
|
4436
|
-
return { ready:
|
|
4840
|
+
return { ready: blockerDetails.length === 0, blockers: blockerDetails.map((b) => b.message), blockerDetails };
|
|
4437
4841
|
}
|
|
4438
4842
|
// ../../packages/aeg-core/src/single-plan-pr.ts
|
|
4439
4843
|
function trancheSlugFromTopologyPath(path) {
|
|
@@ -4535,6 +4939,91 @@ function checkBranchTopology(input) {
|
|
|
4535
4939
|
reason: `Branch \`${branch}\` matches topology row \`${taskId}\` in ${topoPath}.`
|
|
4536
4940
|
};
|
|
4537
4941
|
}
|
|
4942
|
+
// ../../packages/aeg-core/src/task-tools.ts
|
|
4943
|
+
import { z } from "zod";
|
|
4944
|
+
var TASK_TOOL_ERROR_KINDS = [
|
|
4945
|
+
"validation",
|
|
4946
|
+
"authority",
|
|
4947
|
+
"precondition",
|
|
4948
|
+
"capability",
|
|
4949
|
+
"infrastructure",
|
|
4950
|
+
"cancellation",
|
|
4951
|
+
"timeout",
|
|
4952
|
+
"uncertain_effect"
|
|
4953
|
+
];
|
|
4954
|
+
var TaskToolErrorSchema = z.object({
|
|
4955
|
+
kind: z.enum(TASK_TOOL_ERROR_KINDS),
|
|
4956
|
+
message: z.string().min(1),
|
|
4957
|
+
detail: z.string().optional()
|
|
4958
|
+
});
|
|
4959
|
+
var TaskToolRefSchema = z.union([
|
|
4960
|
+
z.object({ tranche: z.string().min(1), id: z.string().min(1) }),
|
|
4961
|
+
z.object({ issue: z.number().int().positive() })
|
|
4962
|
+
]);
|
|
4963
|
+
var MAX_PAGE_LIMIT = 100;
|
|
4964
|
+
var PageRequestSchema = z.object({
|
|
4965
|
+
cursor: z.string().optional(),
|
|
4966
|
+
limit: z.number().int().positive().max(MAX_PAGE_LIMIT).optional()
|
|
4967
|
+
});
|
|
4968
|
+
var FreshnessSchema = z.enum(["fresh", "stale", "unknown"]);
|
|
4969
|
+
var ObservedSchema = z.object({
|
|
4970
|
+
observedAt: z.string(),
|
|
4971
|
+
freshness: FreshnessSchema
|
|
4972
|
+
});
|
|
4973
|
+
var TaskStatusInputSchema = z.object({
|
|
4974
|
+
task: TaskToolRefSchema.optional()
|
|
4975
|
+
}).merge(PageRequestSchema);
|
|
4976
|
+
var TaskStatusItemSchema = z.object({
|
|
4977
|
+
task: TaskToolRefSchema,
|
|
4978
|
+
issue: z.number().int().positive(),
|
|
4979
|
+
pr: z.number().int().positive().nullable(),
|
|
4980
|
+
state: z.string()
|
|
4981
|
+
}).merge(ObservedSchema);
|
|
4982
|
+
var TaskStatusResultSchema = z.object({
|
|
4983
|
+
items: z.array(TaskStatusItemSchema),
|
|
4984
|
+
nextCursor: z.string().nullable()
|
|
4985
|
+
});
|
|
4986
|
+
var RequestedAuthoritySchema = z.enum(["planner", "principal", "operator", "self"]);
|
|
4987
|
+
var EscalationInputsSchema = z.object({
|
|
4988
|
+
task: z.number().int().positive(),
|
|
4989
|
+
round: z.number().int().nonnegative(),
|
|
4990
|
+
head: z.string(),
|
|
4991
|
+
branch: z.string(),
|
|
4992
|
+
prNumber: z.number().int().positive()
|
|
4993
|
+
});
|
|
4994
|
+
var EscalationEvidenceSchema = z.object({
|
|
4995
|
+
round: z.number().int().nonnegative(),
|
|
4996
|
+
reviewer: z.string().nullable(),
|
|
4997
|
+
security: z.string().nullable()
|
|
4998
|
+
});
|
|
4999
|
+
var TaskEscalationReadInputSchema = z.object({
|
|
5000
|
+
task: TaskToolRefSchema
|
|
5001
|
+
}).merge(PageRequestSchema);
|
|
5002
|
+
var TaskEscalationPacketSchema = z.object({
|
|
5003
|
+
reason: z.string(),
|
|
5004
|
+
detail: z.string().nullable(),
|
|
5005
|
+
inputs: EscalationInputsSchema.nullable(),
|
|
5006
|
+
evidence: EscalationEvidenceSchema.nullable(),
|
|
5007
|
+
attemptedRecovery: z.string(),
|
|
5008
|
+
requestedAuthority: RequestedAuthoritySchema,
|
|
5009
|
+
permittedNextActions: z.array(z.string())
|
|
5010
|
+
}).merge(ObservedSchema);
|
|
5011
|
+
var TaskEscalationReadResultSchema = z.object({
|
|
5012
|
+
items: z.array(TaskEscalationPacketSchema),
|
|
5013
|
+
nextCursor: z.string().nullable()
|
|
5014
|
+
}).merge(ObservedSchema);
|
|
5015
|
+
var TaskStartInputSchema = z.object({
|
|
5016
|
+
tranche: z.string().min(1),
|
|
5017
|
+
id: z.string().min(1)
|
|
5018
|
+
});
|
|
5019
|
+
var TaskResumeInputSchema = z.object({
|
|
5020
|
+
task: TaskToolRefSchema
|
|
5021
|
+
});
|
|
5022
|
+
var TaskCancelInputSchema = z.object({
|
|
5023
|
+
task: TaskToolRefSchema,
|
|
5024
|
+
reason: z.string().min(1)
|
|
5025
|
+
});
|
|
5026
|
+
var NoResultSchema = z.never();
|
|
4538
5027
|
// ../../packages/aeg-core/src/first-push-dispatch-gate.ts
|
|
4539
5028
|
function parseTaskBranch(branch) {
|
|
4540
5029
|
const m = /^task\/([^/]+)\/([^/]+)$/.exec(branch);
|
|
@@ -4618,7 +5107,6 @@ function decideIssueAssignment(input) {
|
|
|
4618
5107
|
};
|
|
4619
5108
|
}
|
|
4620
5109
|
// ../../packages/aeg-core/src/test-plan-gate.ts
|
|
4621
|
-
var TASK_BRANCH_PATTERN2 = /^task\/[^/]+\/[^/]+$/;
|
|
4622
5110
|
function evaluateTestPlanGate(body, branch) {
|
|
4623
5111
|
if (!body) {
|
|
4624
5112
|
return {
|
|
@@ -4631,7 +5119,7 @@ function evaluateTestPlanGate(body, branch) {
|
|
|
4631
5119
|
}
|
|
4632
5120
|
const located = locateTestPlanSection(body);
|
|
4633
5121
|
if (!located.found) {
|
|
4634
|
-
if (
|
|
5122
|
+
if (parseTaskBranchIdentity(branch) !== null) {
|
|
4635
5123
|
return {
|
|
4636
5124
|
verdict: "fail",
|
|
4637
5125
|
messages: [
|
|
@@ -4759,7 +5247,7 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
|
|
|
4759
5247
|
return findings;
|
|
4760
5248
|
}
|
|
4761
5249
|
// ../../packages/aeg-core/src/log/schema.ts
|
|
4762
|
-
import { z } from "zod";
|
|
5250
|
+
import { z as z2 } from "zod";
|
|
4763
5251
|
var ROLE_VALUES = [
|
|
4764
5252
|
"planner",
|
|
4765
5253
|
"developer",
|
|
@@ -4769,136 +5257,172 @@ var ROLE_VALUES = [
|
|
|
4769
5257
|
"archivist",
|
|
4770
5258
|
"architect"
|
|
4771
5259
|
];
|
|
4772
|
-
var RoleSchema =
|
|
5260
|
+
var RoleSchema = z2.enum(ROLE_VALUES);
|
|
4773
5261
|
var HOST_VALUES = ["hook", "ci", "cli", "loop"];
|
|
4774
|
-
var HostSchema =
|
|
5262
|
+
var HostSchema = z2.enum(HOST_VALUES);
|
|
4775
5263
|
var RUN_ID_PATTERN = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
4776
|
-
var
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
doctrine: z.string(),
|
|
5264
|
+
var headerMetaCore = {
|
|
5265
|
+
ts: z2.string(),
|
|
5266
|
+
run_id: z2.string().regex(RUN_ID_PATTERN),
|
|
5267
|
+
seq: z2.number().int().nonnegative(),
|
|
5268
|
+
repo: z2.string().nullable(),
|
|
5269
|
+
vinaya: z2.string(),
|
|
5270
|
+
doctrine: z2.string(),
|
|
4784
5271
|
host: HostSchema,
|
|
4785
|
-
machine:
|
|
5272
|
+
machine: z2.string()
|
|
5273
|
+
};
|
|
5274
|
+
var HeaderMetaV1Schema = z2.object({
|
|
5275
|
+
schema: z2.literal(1),
|
|
5276
|
+
...headerMetaCore
|
|
5277
|
+
}).strict();
|
|
5278
|
+
var LineageSchema = z2.object({
|
|
5279
|
+
run: z2.string().nullable(),
|
|
5280
|
+
attempt: z2.number().int().nullable(),
|
|
5281
|
+
parent: z2.string().nullable()
|
|
5282
|
+
}).strict();
|
|
5283
|
+
var InputVersionsSchema = z2.object({
|
|
5284
|
+
objectives_version: z2.string().nullable(),
|
|
5285
|
+
brief_hash: z2.string().nullable(),
|
|
5286
|
+
ruling_ordinal: z2.number().int().nullable(),
|
|
5287
|
+
policy_digest: z2.string().nullable()
|
|
4786
5288
|
}).strict();
|
|
4787
|
-
var
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
5289
|
+
var ProvenanceSchema = z2.enum(["parent_attributed", "env_correlated", "self_reported", "unavailable"]);
|
|
5290
|
+
var HeaderMetaV2Schema = z2.object({
|
|
5291
|
+
schema: z2.literal(2),
|
|
5292
|
+
...headerMetaCore,
|
|
5293
|
+
event_id: z2.string().min(1),
|
|
5294
|
+
process_id: z2.string().min(1),
|
|
5295
|
+
actor_id: z2.string().nullable(),
|
|
5296
|
+
lineage: LineageSchema,
|
|
5297
|
+
input_versions: InputVersionsSchema,
|
|
5298
|
+
provenance: ProvenanceSchema
|
|
4794
5299
|
}).strict();
|
|
4795
|
-
var
|
|
5300
|
+
var HeaderMetaSchema = z2.discriminatedUnion("schema", [HeaderMetaV1Schema, HeaderMetaV2Schema]);
|
|
5301
|
+
var SubjectSchema = z2.object({
|
|
5302
|
+
issue: z2.number().int().nullable(),
|
|
5303
|
+
pr: z2.number().int().optional(),
|
|
5304
|
+
sha: z2.string().optional(),
|
|
5305
|
+
role: z2.union([RoleSchema, z2.literal("unattributed")]),
|
|
5306
|
+
round: z2.number().int().optional(),
|
|
5307
|
+
objectives_version: z2.string().optional()
|
|
5308
|
+
}).strict();
|
|
5309
|
+
var HeaderSchema = z2.object({
|
|
4796
5310
|
meta: HeaderMetaSchema,
|
|
4797
5311
|
subject: SubjectSchema
|
|
4798
5312
|
}).strict();
|
|
4799
5313
|
var envelopeTail = {
|
|
4800
|
-
duration_ms:
|
|
4801
|
-
payload:
|
|
5314
|
+
duration_ms: z2.number().nonnegative().optional(),
|
|
5315
|
+
payload: z2.object({}).strict()
|
|
4802
5316
|
};
|
|
4803
|
-
var
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
5317
|
+
var ReviewFindingSchema = z2.object({
|
|
5318
|
+
id: z2.string(),
|
|
5319
|
+
severity: z2.string(),
|
|
5320
|
+
state: z2.string().optional(),
|
|
5321
|
+
severity_scale: z2.string().optional(),
|
|
5322
|
+
policy_treatment: z2.enum(["blocking", "non_blocking", "unavailable"]).optional(),
|
|
5323
|
+
confidence: z2.number().min(0).max(1).optional(),
|
|
5324
|
+
confidence_scale: z2.string().optional(),
|
|
5325
|
+
confidence_source: z2.string().optional()
|
|
5326
|
+
}).strict();
|
|
5327
|
+
var DispatchOutcomeSchema = z2.discriminatedUnion("type", [
|
|
5328
|
+
z2.object({ type: z2.literal("pr_opened"), pr: z2.number().int(), head: z2.string() }).strict(),
|
|
5329
|
+
z2.object({
|
|
5330
|
+
type: z2.literal("round_pushed"),
|
|
5331
|
+
pr: z2.number().int(),
|
|
5332
|
+
head: z2.string(),
|
|
5333
|
+
comment_id: z2.number().int()
|
|
4810
5334
|
}).strict(),
|
|
4811
|
-
|
|
4812
|
-
type:
|
|
4813
|
-
verdict:
|
|
4814
|
-
head:
|
|
4815
|
-
comment_id:
|
|
4816
|
-
objectives:
|
|
4817
|
-
findings:
|
|
5335
|
+
z2.object({
|
|
5336
|
+
type: z2.literal("verdict"),
|
|
5337
|
+
verdict: z2.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
|
|
5338
|
+
head: z2.string(),
|
|
5339
|
+
comment_id: z2.number().int(),
|
|
5340
|
+
objectives: z2.array(z2.object({ id: z2.string(), met: z2.boolean() }).strict()),
|
|
5341
|
+
findings: z2.array(ReviewFindingSchema)
|
|
4818
5342
|
}).strict(),
|
|
4819
|
-
|
|
4820
|
-
type:
|
|
4821
|
-
class:
|
|
4822
|
-
comment_id:
|
|
5343
|
+
z2.object({
|
|
5344
|
+
type: z2.literal("escalation"),
|
|
5345
|
+
class: z2.enum(["authority", "strategy", "product"]),
|
|
5346
|
+
comment_id: z2.number().int()
|
|
4823
5347
|
}).strict(),
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
5348
|
+
z2.object({ type: z2.literal("brief"), comment_id: z2.number().int(), hash: z2.string() }).strict(),
|
|
5349
|
+
z2.object({ type: z2.literal("plan"), issues: z2.array(z2.number().int()) }).strict(),
|
|
5350
|
+
z2.object({ type: z2.literal("archive"), provenance_comment_id: z2.number().int() }).strict()
|
|
4827
5351
|
]);
|
|
4828
5352
|
var dispatchShared = {
|
|
4829
5353
|
meta: HeaderMetaSchema,
|
|
4830
5354
|
subject: SubjectSchema,
|
|
4831
|
-
kind:
|
|
5355
|
+
kind: z2.literal("dispatch"),
|
|
4832
5356
|
...envelopeTail,
|
|
4833
5357
|
target_role: RoleSchema,
|
|
4834
|
-
model:
|
|
4835
|
-
round:
|
|
4836
|
-
effect_id:
|
|
5358
|
+
model: z2.string(),
|
|
5359
|
+
round: z2.number().int().optional(),
|
|
5360
|
+
effect_id: z2.string()
|
|
4837
5361
|
};
|
|
4838
|
-
var dispatchUsageField =
|
|
4839
|
-
var DispatchEventSchema =
|
|
4840
|
-
|
|
4841
|
-
|
|
5362
|
+
var dispatchUsageField = z2.object({ input: z2.number().nonnegative(), output: z2.number().nonnegative() }).strict().nullable();
|
|
5363
|
+
var DispatchEventSchema = z2.discriminatedUnion("event", [
|
|
5364
|
+
z2.object({ ...dispatchShared, event: z2.literal("dispatched"), prompt_hash: z2.string() }).strict(),
|
|
5365
|
+
z2.object({
|
|
4842
5366
|
...dispatchShared,
|
|
4843
|
-
event:
|
|
5367
|
+
event: z2.literal("outcome_received"),
|
|
4844
5368
|
outcome: DispatchOutcomeSchema,
|
|
4845
5369
|
usage: dispatchUsageField
|
|
4846
5370
|
}).strict(),
|
|
4847
|
-
|
|
5371
|
+
z2.object({
|
|
4848
5372
|
...dispatchShared,
|
|
4849
|
-
event:
|
|
4850
|
-
reason:
|
|
5373
|
+
event: z2.literal("dispatch_failed"),
|
|
5374
|
+
reason: z2.enum(["timeout", "crash", "refused", "unattributed_write"]),
|
|
4851
5375
|
usage: dispatchUsageField
|
|
4852
5376
|
}).strict()
|
|
4853
5377
|
]);
|
|
4854
5378
|
var loopShared = {
|
|
4855
5379
|
meta: HeaderMetaSchema,
|
|
4856
5380
|
subject: SubjectSchema,
|
|
4857
|
-
kind:
|
|
5381
|
+
kind: z2.literal("dev_review_loop"),
|
|
4858
5382
|
...envelopeTail,
|
|
4859
|
-
loop_id:
|
|
5383
|
+
loop_id: z2.string()
|
|
4860
5384
|
};
|
|
4861
|
-
var DevReviewLoopEventSchema =
|
|
4862
|
-
|
|
5385
|
+
var DevReviewLoopEventSchema = z2.discriminatedUnion("event", [
|
|
5386
|
+
z2.object({
|
|
4863
5387
|
...loopShared,
|
|
4864
|
-
event:
|
|
4865
|
-
task:
|
|
4866
|
-
policy:
|
|
4867
|
-
max_rounds:
|
|
4868
|
-
reviewers:
|
|
4869
|
-
models:
|
|
5388
|
+
event: z2.literal("loop_started"),
|
|
5389
|
+
task: z2.number().int(),
|
|
5390
|
+
policy: z2.object({
|
|
5391
|
+
max_rounds: z2.number().int().nonnegative(),
|
|
5392
|
+
reviewers: z2.array(RoleSchema),
|
|
5393
|
+
models: z2.record(RoleSchema, z2.string())
|
|
4870
5394
|
}).strict()
|
|
4871
5395
|
}).strict(),
|
|
4872
|
-
|
|
4873
|
-
|
|
5396
|
+
z2.object({ ...loopShared, event: z2.literal("round_started"), round: z2.number().int(), base_head: z2.string() }).strict(),
|
|
5397
|
+
z2.object({
|
|
4874
5398
|
...loopShared,
|
|
4875
|
-
event:
|
|
4876
|
-
round:
|
|
4877
|
-
head:
|
|
4878
|
-
green:
|
|
5399
|
+
event: z2.literal("gate_result_read"),
|
|
5400
|
+
round: z2.number().int(),
|
|
5401
|
+
head: z2.string(),
|
|
5402
|
+
green: z2.boolean()
|
|
4879
5403
|
}).strict(),
|
|
4880
|
-
|
|
5404
|
+
z2.object({
|
|
4881
5405
|
...loopShared,
|
|
4882
|
-
event:
|
|
4883
|
-
round:
|
|
4884
|
-
head:
|
|
4885
|
-
all_approve:
|
|
4886
|
-
blockers:
|
|
5406
|
+
event: z2.literal("verdicts_read"),
|
|
5407
|
+
round: z2.number().int(),
|
|
5408
|
+
head: z2.string(),
|
|
5409
|
+
all_approve: z2.boolean(),
|
|
5410
|
+
blockers: z2.number().int().nonnegative()
|
|
4887
5411
|
}).strict(),
|
|
4888
|
-
|
|
5412
|
+
z2.object({
|
|
4889
5413
|
...loopShared,
|
|
4890
|
-
event:
|
|
4891
|
-
round:
|
|
4892
|
-
open:
|
|
4893
|
-
resolved:
|
|
4894
|
-
new:
|
|
4895
|
-
recurring:
|
|
5414
|
+
event: z2.literal("findings_compared"),
|
|
5415
|
+
round: z2.number().int(),
|
|
5416
|
+
open: z2.array(z2.string()),
|
|
5417
|
+
resolved: z2.array(z2.string()),
|
|
5418
|
+
new: z2.array(z2.string()),
|
|
5419
|
+
recurring: z2.array(z2.string())
|
|
4896
5420
|
}).strict(),
|
|
4897
|
-
|
|
5421
|
+
z2.object({
|
|
4898
5422
|
...loopShared,
|
|
4899
|
-
event:
|
|
4900
|
-
round:
|
|
4901
|
-
condition:
|
|
5423
|
+
event: z2.literal("stop_condition_met"),
|
|
5424
|
+
round: z2.number().int(),
|
|
5425
|
+
condition: z2.enum([
|
|
4902
5426
|
"green",
|
|
4903
5427
|
"max_rounds",
|
|
4904
5428
|
"no_progress",
|
|
@@ -4908,42 +5432,49 @@ var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
|
|
|
4908
5432
|
"reappearance"
|
|
4909
5433
|
])
|
|
4910
5434
|
}).strict(),
|
|
4911
|
-
|
|
5435
|
+
z2.object({
|
|
4912
5436
|
...loopShared,
|
|
4913
|
-
event:
|
|
4914
|
-
round:
|
|
4915
|
-
reason:
|
|
5437
|
+
event: z2.literal("paused"),
|
|
5438
|
+
round: z2.number().int(),
|
|
5439
|
+
reason: z2.enum(["escalation", "principal_item", "refreeze_needed"])
|
|
4916
5440
|
}).strict(),
|
|
4917
|
-
|
|
5441
|
+
z2.object({
|
|
4918
5442
|
...loopShared,
|
|
4919
|
-
event:
|
|
4920
|
-
round:
|
|
4921
|
-
by:
|
|
5443
|
+
event: z2.literal("resumed"),
|
|
5444
|
+
round: z2.number().int(),
|
|
5445
|
+
by: z2.literal("principal")
|
|
4922
5446
|
}).strict(),
|
|
4923
|
-
|
|
5447
|
+
z2.object({
|
|
4924
5448
|
...loopShared,
|
|
4925
|
-
event:
|
|
4926
|
-
round:
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
files_changed: z.number().int().nonnegative(),
|
|
4930
|
-
insertions: z.number().int().nonnegative(),
|
|
4931
|
-
deletions: z.number().int().nonnegative(),
|
|
4932
|
-
wall_ms: z.number().nonnegative(),
|
|
4933
|
-
outcome: z.enum(["green", "changes_requested", "escalated"])
|
|
5449
|
+
event: z2.literal("unpushed_work_resume"),
|
|
5450
|
+
round: z2.number().int(),
|
|
5451
|
+
branch: z2.string(),
|
|
5452
|
+
detail: z2.string()
|
|
4934
5453
|
}).strict(),
|
|
4935
|
-
|
|
5454
|
+
z2.object({
|
|
4936
5455
|
...loopShared,
|
|
4937
|
-
event:
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
5456
|
+
event: z2.literal("round_ended"),
|
|
5457
|
+
round: z2.number().int(),
|
|
5458
|
+
base_head: z2.string(),
|
|
5459
|
+
head: z2.string(),
|
|
5460
|
+
files_changed: z2.number().int().nonnegative(),
|
|
5461
|
+
insertions: z2.number().int().nonnegative(),
|
|
5462
|
+
deletions: z2.number().int().nonnegative(),
|
|
5463
|
+
wall_ms: z2.number().nonnegative(),
|
|
5464
|
+
outcome: z2.enum(["green", "changes_requested", "escalated"])
|
|
5465
|
+
}).strict(),
|
|
5466
|
+
z2.object({
|
|
5467
|
+
...loopShared,
|
|
5468
|
+
event: z2.literal("journal_finalized"),
|
|
5469
|
+
rounds: z2.number().int().nonnegative(),
|
|
5470
|
+
total_wall_ms: z2.number().nonnegative(),
|
|
5471
|
+
time_to_green_ms: z2.number().nonnegative().nullable(),
|
|
5472
|
+
files_changed_total: z2.number().int().nonnegative(),
|
|
5473
|
+
final_head: z2.string(),
|
|
5474
|
+
result: z2.enum(["merged_ready", "stopped"])
|
|
4944
5475
|
}).strict()
|
|
4945
5476
|
]);
|
|
4946
|
-
var ForgeOpSchema =
|
|
5477
|
+
var ForgeOpSchema = z2.enum([
|
|
4947
5478
|
"pr.create",
|
|
4948
5479
|
"pr.comment",
|
|
4949
5480
|
"pr.body.replace",
|
|
@@ -4957,24 +5488,210 @@ var ForgeOpSchema = z.enum([
|
|
|
4957
5488
|
"label.add",
|
|
4958
5489
|
"label.remove"
|
|
4959
5490
|
]);
|
|
4960
|
-
var ForgeWriteTargetSchema =
|
|
4961
|
-
issue:
|
|
4962
|
-
pr:
|
|
5491
|
+
var ForgeWriteTargetSchema = z2.object({
|
|
5492
|
+
issue: z2.number().int().optional(),
|
|
5493
|
+
pr: z2.number().int().optional()
|
|
4963
5494
|
}).strict();
|
|
4964
5495
|
var forgeWriteShared = {
|
|
4965
5496
|
meta: HeaderMetaSchema,
|
|
4966
5497
|
subject: SubjectSchema,
|
|
4967
|
-
kind:
|
|
5498
|
+
kind: z2.literal("forge_write"),
|
|
4968
5499
|
...envelopeTail,
|
|
4969
5500
|
op: ForgeOpSchema,
|
|
4970
5501
|
target: ForgeWriteTargetSchema
|
|
4971
5502
|
};
|
|
4972
|
-
var ForgeWriteEventSchema =
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
5503
|
+
var ForgeWriteEventSchema = z2.discriminatedUnion("event", [
|
|
5504
|
+
z2.object({ ...forgeWriteShared, event: z2.literal("validated") }).strict(),
|
|
5505
|
+
z2.object({ ...forgeWriteShared, event: z2.literal("refused"), reason: z2.string() }).strict(),
|
|
5506
|
+
z2.object({ ...forgeWriteShared, event: z2.literal("written"), comment_ids: z2.array(z2.string()) }).strict()
|
|
5507
|
+
]);
|
|
5508
|
+
var GateOutcomeSchema = z2.enum([
|
|
5509
|
+
"pass",
|
|
5510
|
+
"fail",
|
|
5511
|
+
"wait",
|
|
5512
|
+
"skip",
|
|
5513
|
+
"invalid_input",
|
|
5514
|
+
"unavailable_dependency",
|
|
5515
|
+
"timeout",
|
|
5516
|
+
"cancelled"
|
|
5517
|
+
]);
|
|
5518
|
+
var gateShared = {
|
|
5519
|
+
meta: HeaderMetaSchema,
|
|
5520
|
+
subject: SubjectSchema,
|
|
5521
|
+
kind: z2.literal("gate"),
|
|
5522
|
+
...envelopeTail,
|
|
5523
|
+
check: z2.string(),
|
|
5524
|
+
check_version: z2.string().nullable(),
|
|
5525
|
+
policy_version: z2.string().nullable(),
|
|
5526
|
+
input_fingerprint: z2.string().nullable()
|
|
5527
|
+
};
|
|
5528
|
+
var GateEventSchema = z2.discriminatedUnion("event", [
|
|
5529
|
+
z2.object({
|
|
5530
|
+
...gateShared,
|
|
5531
|
+
event: z2.literal("checked"),
|
|
5532
|
+
outcome: GateOutcomeSchema,
|
|
5533
|
+
reason: z2.string().optional()
|
|
5534
|
+
}).strict()
|
|
4976
5535
|
]);
|
|
4977
|
-
var
|
|
5536
|
+
var OperationResultSchema = z2.enum(["ok", "error", "refused", "timeout", "cancelled", "unavailable"]);
|
|
5537
|
+
var operationShared = {
|
|
5538
|
+
meta: HeaderMetaSchema,
|
|
5539
|
+
subject: SubjectSchema,
|
|
5540
|
+
kind: z2.literal("operation"),
|
|
5541
|
+
...envelopeTail,
|
|
5542
|
+
operation: z2.string(),
|
|
5543
|
+
target: z2.string().nullable()
|
|
5544
|
+
};
|
|
5545
|
+
var OperationEventSchema = z2.discriminatedUnion("event", [
|
|
5546
|
+
z2.object({
|
|
5547
|
+
...operationShared,
|
|
5548
|
+
event: z2.literal("completed"),
|
|
5549
|
+
result: OperationResultSchema,
|
|
5550
|
+
error_class: z2.string().nullable()
|
|
5551
|
+
}).strict()
|
|
5552
|
+
]);
|
|
5553
|
+
var UsageUnitsSchema = z2.object({
|
|
5554
|
+
input: z2.number().nonnegative().nullable(),
|
|
5555
|
+
output: z2.number().nonnegative().nullable(),
|
|
5556
|
+
cache: z2.number().nonnegative().nullable()
|
|
5557
|
+
}).strict();
|
|
5558
|
+
var usageShared = {
|
|
5559
|
+
meta: HeaderMetaSchema,
|
|
5560
|
+
subject: SubjectSchema,
|
|
5561
|
+
kind: z2.literal("usage"),
|
|
5562
|
+
...envelopeTail,
|
|
5563
|
+
model: z2.string().nullable(),
|
|
5564
|
+
source: z2.string(),
|
|
5565
|
+
semantics: z2.enum(["cumulative", "delta"])
|
|
5566
|
+
};
|
|
5567
|
+
var UsageEventSchema = z2.discriminatedUnion("event", [
|
|
5568
|
+
z2.object({
|
|
5569
|
+
...usageShared,
|
|
5570
|
+
event: z2.literal("observed"),
|
|
5571
|
+
units: UsageUnitsSchema,
|
|
5572
|
+
unknown_reason: z2.string().nullable()
|
|
5573
|
+
}).strict()
|
|
5574
|
+
]);
|
|
5575
|
+
var RoleAttemptOutcomeSchema = z2.enum([
|
|
5576
|
+
"completed",
|
|
5577
|
+
"incomplete",
|
|
5578
|
+
"infrastructure_failed",
|
|
5579
|
+
"cancelled",
|
|
5580
|
+
"timed_out",
|
|
5581
|
+
"capability_refused"
|
|
5582
|
+
]);
|
|
5583
|
+
var roleAttemptShared = {
|
|
5584
|
+
meta: HeaderMetaSchema,
|
|
5585
|
+
subject: SubjectSchema,
|
|
5586
|
+
kind: z2.literal("role_attempt"),
|
|
5587
|
+
...envelopeTail,
|
|
5588
|
+
actor: z2.string().nullable(),
|
|
5589
|
+
attempt: z2.number().int().nullable()
|
|
5590
|
+
};
|
|
5591
|
+
var RoleAttemptEventSchema = z2.discriminatedUnion("event", [
|
|
5592
|
+
z2.object({
|
|
5593
|
+
...roleAttemptShared,
|
|
5594
|
+
event: z2.literal("attempted"),
|
|
5595
|
+
outcome: RoleAttemptOutcomeSchema,
|
|
5596
|
+
usage: dispatchUsageField
|
|
5597
|
+
}).strict()
|
|
5598
|
+
]);
|
|
5599
|
+
var handoffShared = {
|
|
5600
|
+
meta: HeaderMetaSchema,
|
|
5601
|
+
subject: SubjectSchema,
|
|
5602
|
+
kind: z2.literal("handoff"),
|
|
5603
|
+
...envelopeTail,
|
|
5604
|
+
class: z2.enum(["authority", "strategy", "product"]),
|
|
5605
|
+
reason: z2.string()
|
|
5606
|
+
};
|
|
5607
|
+
var HandoffEventSchema = z2.discriminatedUnion("event", [
|
|
5608
|
+
z2.object({
|
|
5609
|
+
...handoffShared,
|
|
5610
|
+
event: z2.literal("raised"),
|
|
5611
|
+
requested_decision: z2.string().nullable()
|
|
5612
|
+
}).strict(),
|
|
5613
|
+
z2.object({
|
|
5614
|
+
...handoffShared,
|
|
5615
|
+
event: z2.literal("resolved"),
|
|
5616
|
+
resolution: z2.string().nullable(),
|
|
5617
|
+
resolved_by: z2.string().nullable()
|
|
5618
|
+
}).strict()
|
|
5619
|
+
]);
|
|
5620
|
+
var EffectTargetSchema = z2.object({
|
|
5621
|
+
kind: z2.string(),
|
|
5622
|
+
ref: z2.string()
|
|
5623
|
+
}).strict();
|
|
5624
|
+
var effectShared = {
|
|
5625
|
+
meta: HeaderMetaSchema,
|
|
5626
|
+
subject: SubjectSchema,
|
|
5627
|
+
kind: z2.literal("effect"),
|
|
5628
|
+
...envelopeTail,
|
|
5629
|
+
effect_id: z2.string(),
|
|
5630
|
+
target: EffectTargetSchema
|
|
5631
|
+
};
|
|
5632
|
+
var EffectEventSchema = z2.discriminatedUnion("event", [
|
|
5633
|
+
z2.object({ ...effectShared, event: z2.literal("attempted") }).strict(),
|
|
5634
|
+
z2.object({ ...effectShared, event: z2.literal("observed"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict(),
|
|
5635
|
+
z2.object({ ...effectShared, event: z2.literal("verified"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict()
|
|
5636
|
+
]);
|
|
5637
|
+
var LogEventSchema = z2.union([
|
|
5638
|
+
DispatchEventSchema,
|
|
5639
|
+
DevReviewLoopEventSchema,
|
|
5640
|
+
ForgeWriteEventSchema,
|
|
5641
|
+
GateEventSchema,
|
|
5642
|
+
OperationEventSchema,
|
|
5643
|
+
UsageEventSchema,
|
|
5644
|
+
RoleAttemptEventSchema,
|
|
5645
|
+
HandoffEventSchema,
|
|
5646
|
+
EffectEventSchema
|
|
5647
|
+
]);
|
|
5648
|
+
// ../../packages/aeg-core/src/dev-review-loop/journal-reconstruction.ts
|
|
5649
|
+
var STOPPED_CONDITIONS = new Set(["confidence", "reappearance", "no_progress", "max_rounds"]);
|
|
5650
|
+
// ../../packages/aeg-core/src/control-store/records.ts
|
|
5651
|
+
import { z as z3 } from "zod";
|
|
5652
|
+
var isoTimestamp = z3.string().min(1);
|
|
5653
|
+
var taskId = z3.number().int().positive();
|
|
5654
|
+
var epochNumber = z3.number().int().nonnegative();
|
|
5655
|
+
var RunRecordSchema = z3.object({
|
|
5656
|
+
version: z3.literal(1),
|
|
5657
|
+
kind: z3.literal("run"),
|
|
5658
|
+
task: taskId,
|
|
5659
|
+
runId: z3.string().min(1),
|
|
5660
|
+
pid: z3.number().int().positive(),
|
|
5661
|
+
host: z3.string().min(1),
|
|
5662
|
+
startedAt: isoTimestamp
|
|
5663
|
+
}).strict();
|
|
5664
|
+
var InputRecordSchema = z3.object({
|
|
5665
|
+
version: z3.literal(1),
|
|
5666
|
+
kind: z3.literal("input"),
|
|
5667
|
+
task: taskId,
|
|
5668
|
+
runId: z3.string().min(1),
|
|
5669
|
+
source: z3.union([z3.literal("fresh"), z3.literal("resume")]),
|
|
5670
|
+
pr: z3.number().int().positive().nullable(),
|
|
5671
|
+
round: z3.number().int().nonnegative(),
|
|
5672
|
+
recordedAt: isoTimestamp
|
|
5673
|
+
}).strict();
|
|
5674
|
+
var OwnershipRecordSchema = z3.object({
|
|
5675
|
+
version: z3.literal(1),
|
|
5676
|
+
kind: z3.literal("ownership"),
|
|
5677
|
+
task: taskId,
|
|
5678
|
+
epoch: epochNumber,
|
|
5679
|
+
ownerId: z3.string().min(1),
|
|
5680
|
+
pid: z3.number().int().positive(),
|
|
5681
|
+
host: z3.string().min(1),
|
|
5682
|
+
acquiredAt: isoTimestamp
|
|
5683
|
+
}).strict();
|
|
5684
|
+
var TransitionRecordSchema = z3.object({
|
|
5685
|
+
version: z3.literal(1),
|
|
5686
|
+
kind: z3.literal("transition"),
|
|
5687
|
+
task: taskId,
|
|
5688
|
+
epoch: epochNumber,
|
|
5689
|
+
seq: z3.number().int().nonnegative(),
|
|
5690
|
+
from: z3.string().min(1),
|
|
5691
|
+
to: z3.string().min(1),
|
|
5692
|
+
detail: z3.string().optional(),
|
|
5693
|
+
at: isoTimestamp
|
|
5694
|
+
}).strict();
|
|
4978
5695
|
// src/commands/doctrine.ts
|
|
4979
5696
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
4980
5697
|
import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
|
|
@@ -5033,27 +5750,29 @@ import { execFileSync as execFileSync3 } from "node:child_process";
|
|
|
5033
5750
|
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, realpathSync, writeFileSync } from "node:fs";
|
|
5034
5751
|
import { homedir } from "node:os";
|
|
5035
5752
|
import { dirname as dirname3, join as join3, resolve } from "node:path";
|
|
5036
|
-
import { z as
|
|
5753
|
+
import { z as z4 } from "zod";
|
|
5037
5754
|
|
|
5038
5755
|
// src/lib/agent-vendors.ts
|
|
5039
5756
|
var AGENT_VENDORS = ["skills", "claude", "gemini"];
|
|
5040
5757
|
|
|
5041
5758
|
// src/lib/config.ts
|
|
5042
|
-
var EnvEntrySchema =
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5759
|
+
var EnvEntrySchema = z4.union([
|
|
5760
|
+
z4.literal(true),
|
|
5761
|
+
z4.object({ optional: z4.literal(true) }),
|
|
5762
|
+
z4.object({ anyOf: z4.array(z4.string()).min(2) }),
|
|
5763
|
+
z4.string()
|
|
5047
5764
|
]);
|
|
5048
|
-
var CheckEntrySchema =
|
|
5049
|
-
run:
|
|
5050
|
-
scope:
|
|
5051
|
-
include:
|
|
5052
|
-
args:
|
|
5053
|
-
timeoutMs:
|
|
5054
|
-
env:
|
|
5055
|
-
requiresOpenPr:
|
|
5056
|
-
ownWorkflow:
|
|
5765
|
+
var CheckEntrySchema = z4.object({
|
|
5766
|
+
run: z4.string(),
|
|
5767
|
+
scope: z4.enum(["diff", "full"]),
|
|
5768
|
+
include: z4.array(z4.string()).optional(),
|
|
5769
|
+
args: z4.array(z4.string()).optional(),
|
|
5770
|
+
timeoutMs: z4.number().optional(),
|
|
5771
|
+
env: z4.record(z4.string(), EnvEntrySchema).optional(),
|
|
5772
|
+
requiresOpenPr: z4.boolean().optional(),
|
|
5773
|
+
ownWorkflow: z4.boolean().optional(),
|
|
5774
|
+
principalOwed: z4.literal(true).optional(),
|
|
5775
|
+
validates: z4.enum(["body", "issue"]).optional()
|
|
5057
5776
|
}).superRefine((entry2, ctx) => {
|
|
5058
5777
|
if (!entry2.env)
|
|
5059
5778
|
return;
|
|
@@ -5063,25 +5782,26 @@ var CheckEntrySchema = z2.object({
|
|
|
5063
5782
|
const members = value.anyOf;
|
|
5064
5783
|
if (new Set(members).size !== members.length) {
|
|
5065
5784
|
ctx.addIssue({
|
|
5066
|
-
code:
|
|
5785
|
+
code: z4.ZodIssueCode.custom,
|
|
5067
5786
|
message: `env.${key}.anyOf has duplicate members`,
|
|
5068
5787
|
path: ["env", key, "anyOf"]
|
|
5069
5788
|
});
|
|
5070
5789
|
}
|
|
5071
5790
|
if (!members.includes(key)) {
|
|
5072
5791
|
ctx.addIssue({
|
|
5073
|
-
code:
|
|
5792
|
+
code: z4.ZodIssueCode.custom,
|
|
5074
5793
|
message: `env.${key}.anyOf must include "${key}" itself as a member`,
|
|
5075
5794
|
path: ["env", key, "anyOf"]
|
|
5076
5795
|
});
|
|
5077
5796
|
}
|
|
5078
5797
|
}
|
|
5079
5798
|
});
|
|
5080
|
-
var RoleEntrySchema =
|
|
5081
|
-
contract:
|
|
5799
|
+
var RoleEntrySchema = z4.object({
|
|
5800
|
+
contract: z4.string().refine((p) => p.includes("/"), {
|
|
5082
5801
|
message: 'must be a path (contain at least one "/"), not a bare filename'
|
|
5083
5802
|
})
|
|
5084
5803
|
});
|
|
5804
|
+
var MAX_REPORT_COMMAND_TIMEOUT_MS = 3600000;
|
|
5085
5805
|
var BRIEF_BUILTINS = [
|
|
5086
5806
|
"tier",
|
|
5087
5807
|
"testPlan",
|
|
@@ -5101,17 +5821,17 @@ var BRIEF_BUILTINS = [
|
|
|
5101
5821
|
"briefSections",
|
|
5102
5822
|
"milestoneShape"
|
|
5103
5823
|
];
|
|
5104
|
-
var BriefSectionSchema =
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5824
|
+
var BriefSectionSchema = z4.union([
|
|
5825
|
+
z4.object({ builtin: z4.enum(BRIEF_BUILTINS) }),
|
|
5826
|
+
z4.object({ heading: z4.string().min(1), name: z4.string().optional() }),
|
|
5827
|
+
z4.object({ field: z4.string().min(1), name: z4.string().optional() }),
|
|
5828
|
+
z4.object({ phrase: z4.string().min(1), name: z4.string().optional() })
|
|
5109
5829
|
]);
|
|
5110
|
-
var BriefSchemaSchema =
|
|
5111
|
-
pr:
|
|
5112
|
-
issue:
|
|
5113
|
-
milestone:
|
|
5114
|
-
ack:
|
|
5830
|
+
var BriefSchemaSchema = z4.object({
|
|
5831
|
+
pr: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
|
|
5832
|
+
issue: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
|
|
5833
|
+
milestone: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
|
|
5834
|
+
ack: z4.array(z4.enum(BRIEF_BUILTINS)).optional()
|
|
5115
5835
|
});
|
|
5116
5836
|
function isSafeRepoRelPath(p) {
|
|
5117
5837
|
if (p.length === 0)
|
|
@@ -5120,7 +5840,7 @@ function isSafeRepoRelPath(p) {
|
|
|
5120
5840
|
return false;
|
|
5121
5841
|
return p.split(/[\\/]/).every((seg) => seg !== ".." && seg !== "");
|
|
5122
5842
|
}
|
|
5123
|
-
var SafeRepoRelPath =
|
|
5843
|
+
var SafeRepoRelPath = z4.string().refine(isSafeRepoRelPath, {
|
|
5124
5844
|
message: "must be a repo-root-relative path with no `..` segment or absolute root"
|
|
5125
5845
|
});
|
|
5126
5846
|
var CANONICAL_HOOK_BLOCK_PREFIXES = [".git/", ".husky/", ".vinaya/hooks/", ".claude/hooks/"];
|
|
@@ -5130,22 +5850,22 @@ function isCanonicalHookBlockPath(p) {
|
|
|
5130
5850
|
var ManagedHookBlockPath = SafeRepoRelPath.refine(isCanonicalHookBlockPath, {
|
|
5131
5851
|
message: `must start with one of ${CANONICAL_HOOK_BLOCK_PREFIXES.join(", ")} (byte-exact, case-sensitive)`
|
|
5132
5852
|
});
|
|
5133
|
-
var ManagedBlockRecordSchema =
|
|
5853
|
+
var ManagedBlockRecordSchema = z4.object({
|
|
5134
5854
|
path: ManagedHookBlockPath,
|
|
5135
|
-
marker:
|
|
5136
|
-
comment:
|
|
5855
|
+
marker: z4.string(),
|
|
5856
|
+
comment: z4.enum(["hash", "html"])
|
|
5137
5857
|
});
|
|
5138
|
-
var ManagedManifestSchema =
|
|
5139
|
-
version:
|
|
5140
|
-
files:
|
|
5141
|
-
blocks:
|
|
5142
|
-
labels:
|
|
5143
|
-
agents:
|
|
5858
|
+
var ManagedManifestSchema = z4.object({
|
|
5859
|
+
version: z4.number().int().positive(),
|
|
5860
|
+
files: z4.array(SafeRepoRelPath),
|
|
5861
|
+
blocks: z4.array(ManagedBlockRecordSchema),
|
|
5862
|
+
labels: z4.array(z4.string()),
|
|
5863
|
+
agents: z4.array(z4.enum(AGENT_VENDORS)).optional()
|
|
5144
5864
|
});
|
|
5145
|
-
var ProjectEntrySchema =
|
|
5146
|
-
name:
|
|
5147
|
-
description:
|
|
5148
|
-
path:
|
|
5865
|
+
var ProjectEntrySchema = z4.object({
|
|
5866
|
+
name: z4.string().min(1),
|
|
5867
|
+
description: z4.string().min(1).optional(),
|
|
5868
|
+
path: z4.string().min(1).optional()
|
|
5149
5869
|
});
|
|
5150
5870
|
function parseTokensCollectDeclaration(value) {
|
|
5151
5871
|
const m = value.trim().match(/^(\S+)\s+(\S+)$/);
|
|
@@ -5156,34 +5876,55 @@ function parseTokensCollectDeclaration(value) {
|
|
|
5156
5876
|
return null;
|
|
5157
5877
|
return { interpreter, script };
|
|
5158
5878
|
}
|
|
5159
|
-
var VinayaConfigSchema =
|
|
5160
|
-
rings:
|
|
5161
|
-
ring1_forgeWriteInterception:
|
|
5162
|
-
ring2_asyncAudits:
|
|
5879
|
+
var VinayaConfigSchema = z4.object({
|
|
5880
|
+
rings: z4.object({
|
|
5881
|
+
ring1_forgeWriteInterception: z4.boolean(),
|
|
5882
|
+
ring2_asyncAudits: z4.boolean()
|
|
5163
5883
|
}).optional(),
|
|
5164
|
-
checks:
|
|
5165
|
-
roles:
|
|
5884
|
+
checks: z4.record(z4.string(), CheckEntrySchema).optional(),
|
|
5885
|
+
roles: z4.record(z4.string(), RoleEntrySchema).optional(),
|
|
5166
5886
|
briefSchema: BriefSchemaSchema.optional(),
|
|
5167
5887
|
managed: ManagedManifestSchema.optional(),
|
|
5168
|
-
principals:
|
|
5169
|
-
releaseActor:
|
|
5170
|
-
ci:
|
|
5171
|
-
tokens:
|
|
5172
|
-
collect:
|
|
5888
|
+
principals: z4.array(z4.string()).min(1).optional(),
|
|
5889
|
+
releaseActor: z4.string().min(1).optional(),
|
|
5890
|
+
ci: z4.object({ setup: z4.string().min(1) }).optional(),
|
|
5891
|
+
tokens: z4.object({
|
|
5892
|
+
collect: z4.string().min(1).refine((v) => parseTokensCollectDeclaration(v) !== null, {
|
|
5173
5893
|
message: 'tokens.collect must be exactly "<interpreter> <repo-relative-script-path>" — two whitespace-separated tokens, no flags, no shell syntax, no quoting'
|
|
5174
5894
|
})
|
|
5175
5895
|
}).optional(),
|
|
5176
|
-
blastRadius:
|
|
5177
|
-
proseGates:
|
|
5178
|
-
doctrineRoot:
|
|
5179
|
-
readerFacingPrefix:
|
|
5180
|
-
readerFacingSuffix:
|
|
5181
|
-
legacySlugDir:
|
|
5896
|
+
blastRadius: z4.object({ extraDomains: z4.array(z4.string()).optional() }).optional(),
|
|
5897
|
+
proseGates: z4.object({
|
|
5898
|
+
doctrineRoot: z4.string().min(1).optional(),
|
|
5899
|
+
readerFacingPrefix: z4.string().min(1).optional(),
|
|
5900
|
+
readerFacingSuffix: z4.string().min(1).optional(),
|
|
5901
|
+
legacySlugDir: z4.string().min(1).optional()
|
|
5902
|
+
}).optional(),
|
|
5903
|
+
projects: z4.array(ProjectEntrySchema).optional(),
|
|
5904
|
+
dispatch: z4.object({
|
|
5905
|
+
timeoutMs: z4.number().int().positive().optional(),
|
|
5906
|
+
killGraceMs: z4.number().int().positive().optional(),
|
|
5907
|
+
agent: z4.enum(["claude", "codex", "gemini"]).optional()
|
|
5908
|
+
}).optional(),
|
|
5909
|
+
reviewPolicy: z4.object({
|
|
5910
|
+
codeReviewThreshold: z4.string().min(1).optional(),
|
|
5911
|
+
securityThreshold: z4.string().min(1).optional(),
|
|
5912
|
+
maxRounds: z4.number().optional()
|
|
5182
5913
|
}).optional(),
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5914
|
+
prePush: z4.object({
|
|
5915
|
+
alwaysRun: z4.array(z4.string()).optional()
|
|
5916
|
+
}).optional(),
|
|
5917
|
+
report: z4.object({
|
|
5918
|
+
commandTimeoutMs: z4.number().int().positive().optional()
|
|
5919
|
+
}).superRefine((report, ctx) => {
|
|
5920
|
+
const commandTimeoutMs = report.commandTimeoutMs;
|
|
5921
|
+
if (commandTimeoutMs !== undefined && commandTimeoutMs > MAX_REPORT_COMMAND_TIMEOUT_MS) {
|
|
5922
|
+
ctx.addIssue({
|
|
5923
|
+
code: z4.ZodIssueCode.custom,
|
|
5924
|
+
path: ["commandTimeoutMs"],
|
|
5925
|
+
message: "must be at most 3600000 (1 hour)"
|
|
5926
|
+
});
|
|
5927
|
+
}
|
|
5187
5928
|
}).optional()
|
|
5188
5929
|
});
|
|
5189
5930
|
var GLOBAL_VINAYA_HOME = join3(homedir(), ".vinaya");
|
|
@@ -5258,6 +5999,28 @@ function resolvePrincipalAllowlist(config) {
|
|
|
5258
5999
|
function resolveReleaseActor(config) {
|
|
5259
6000
|
return config?.releaseActor ?? DEFAULT_RELEASE_ACTOR;
|
|
5260
6001
|
}
|
|
6002
|
+
function resolveReviewPolicy(config) {
|
|
6003
|
+
const raw = config?.reviewPolicy;
|
|
6004
|
+
if (!raw)
|
|
6005
|
+
return DEFAULT_REVIEW_POLICY;
|
|
6006
|
+
const codeReviewThreshold = raw.codeReviewThreshold ?? DEFAULT_REVIEW_POLICY.codeReviewThreshold;
|
|
6007
|
+
if (!isKnownSeverity(CODE_REVIEW_SEVERITY_ORDER, codeReviewThreshold)) {
|
|
6008
|
+
throw new Error(`vinaya.config.json: reviewPolicy.codeReviewThreshold "${codeReviewThreshold}" is not one of ${CODE_REVIEW_SEVERITY_ORDER.join(" > ")} — fix the config, this never falls back to a default.`);
|
|
6009
|
+
}
|
|
6010
|
+
const securityThreshold = raw.securityThreshold ?? DEFAULT_REVIEW_POLICY.securityThreshold;
|
|
6011
|
+
if (!isKnownSeverity(SECURITY_SEVERITY_ORDER, securityThreshold)) {
|
|
6012
|
+
throw new Error(`vinaya.config.json: reviewPolicy.securityThreshold "${securityThreshold}" is not one of ${SECURITY_SEVERITY_ORDER.join(" > ")} — fix the config, this never falls back to a default.`);
|
|
6013
|
+
}
|
|
6014
|
+
const maxRounds = raw.maxRounds ?? DEFAULT_REVIEW_POLICY.maxRounds;
|
|
6015
|
+
if (!Number.isInteger(maxRounds) || maxRounds < 1) {
|
|
6016
|
+
throw new Error(`vinaya.config.json: reviewPolicy.maxRounds "${maxRounds}" is not a positive integer — fix the config, this never falls back to a default.`);
|
|
6017
|
+
}
|
|
6018
|
+
return {
|
|
6019
|
+
codeReviewThreshold,
|
|
6020
|
+
securityThreshold,
|
|
6021
|
+
maxRounds
|
|
6022
|
+
};
|
|
6023
|
+
}
|
|
5261
6024
|
function trustAnchorRepo() {
|
|
5262
6025
|
const wellFormed = (slug) => /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
|
|
5263
6026
|
const fromRunner = process.env.GITHUB_REPOSITORY?.trim();
|
|
@@ -5345,8 +6108,11 @@ function emitCheckError(error) {
|
|
|
5345
6108
|
}
|
|
5346
6109
|
|
|
5347
6110
|
// src/lib/diff-evidence.ts
|
|
6111
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
6112
|
+
import { join as join5, relative, resolve as resolve2 } from "node:path";
|
|
6113
|
+
|
|
6114
|
+
// src/lib/brief-assembly.ts
|
|
5348
6115
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
5349
|
-
import { join as join4, relative, resolve as resolve2 } from "node:path";
|
|
5350
6116
|
|
|
5351
6117
|
// ../../packages/sources/src/commands.ts
|
|
5352
6118
|
var COMMANDS = [
|
|
@@ -5468,14 +6234,52 @@ var COMMANDS = [
|
|
|
5468
6234
|
},
|
|
5469
6235
|
{
|
|
5470
6236
|
name: "task dispatch",
|
|
5471
|
-
description: "
|
|
6237
|
+
description: "Deprecated — render, pin, and post the brief on the Issue as the frozen original; start the developer",
|
|
5472
6238
|
flags: [
|
|
5473
6239
|
{ flag: "--agent <claude|codex|gemini>", description: "Start the developer through dispatchRole once posted" }
|
|
5474
6240
|
],
|
|
5475
6241
|
details: [
|
|
5476
6242
|
"Renders the brief from the Issue and the tree (the same assembly `brief render` uses) and posts it once as an Issue comment whose first line is `<!-- aeg:brief:v1 -->` and whose second line is `Brief hash: <sha256>` — the hash covers only the body below those two lines, so any reader recomputes it. Refuses outright, naming the existing comment's URL, when a `v1` comment already exists on the Issue — the brief is frozen by design, never overwritten or silently reissued.",
|
|
5477
6243
|
"With `--agent`, starts the Developer through `dispatchRole` when `apps/cli/src/lib/dispatch.ts` exports it; otherwise prints the rendered brief and the manual dispatch instruction and exits `0` — a soft dependency, never a hard block.",
|
|
5478
|
-
"Principal-only, with or without `--agent`: refuses before any render, forge read, or post when the authenticated `gh` identity is not on the Principal allowlist (or cannot be resolved at all) — dispatching is the `todo → in-flight` transition, not a general-purpose comment poster."
|
|
6244
|
+
"Principal-only, with or without `--agent`: refuses before any render, forge read, or post when the authenticated `gh` identity is not on the Principal allowlist (or cannot be resolved at all) — dispatching is the `todo → in-flight` transition, not a general-purpose comment poster.",
|
|
6245
|
+
"Deprecated in favor of `task brief` (preparation only) and `task run` (the full unattended loop) — kept for a documented compatibility window while callers migrate."
|
|
6246
|
+
],
|
|
6247
|
+
status: "shipped"
|
|
6248
|
+
},
|
|
6249
|
+
{
|
|
6250
|
+
name: "task brief",
|
|
6251
|
+
description: "Render and freeze the brief as the Issue's original comment — preparation only, starts nobody",
|
|
6252
|
+
details: [
|
|
6253
|
+
"The preparation half of `task dispatch`, extracted so it is callable on its own: resolves the task's Issue, renders the brief, refuses on any gap, refuses when a frozen brief already exists, and posts it once as the same `aeg:brief:v1` Issue comment `task dispatch` posts. Starts no agent under any circumstances — there is no `--agent` flag here at all.",
|
|
6254
|
+
"Successor to `task dispatch` for the preparation step; the full unattended run (preparation, then the developer, then the review loop) is `task run`."
|
|
6255
|
+
],
|
|
6256
|
+
status: "shipped"
|
|
6257
|
+
},
|
|
6258
|
+
{
|
|
6259
|
+
name: "task run",
|
|
6260
|
+
description: "One command from a planned Issue to a reviewed pull request — exactly one developer started",
|
|
6261
|
+
flags: [
|
|
6262
|
+
{
|
|
6263
|
+
flag: "--agent <claude|codex|gemini>",
|
|
6264
|
+
description: "Vendor for the developer and both reviewers this run dispatches"
|
|
6265
|
+
}
|
|
6266
|
+
],
|
|
6267
|
+
details: [
|
|
6268
|
+
"Composes `task brief`'s own preparation (`prepareTask`) with `dev-review-loop` (`devReviewLoop`) — nothing else. Preparation starts no agent; the loop's own round 1 reads the frozen brief off the Issue and is the only place a developer is ever dispatched from a fresh task, so exactly one developer is started by construction.",
|
|
6269
|
+
"A brief already frozen on the Issue is reused, never re-posted — the second `task dispatch`/`task brief` call this composes around does not fail the whole run, it just skips straight to running the loop. A task whose Issue refuses preparation (a missing brief section, an unmet dispatch gate) is refused before any agent starts, with nothing posted.",
|
|
6270
|
+
"Refuses when the frozen brief's developer branch already has an open pull request — the old `task dispatch` followed by `task run` cannot start two developers this way.",
|
|
6271
|
+
"Exit and printed summary distinguish a published, reviewed pull request (exit `0`, the PR URL) from a pause (exit `1`, with the exact `vinaya dev-review-loop --resume <pr>` command to continue), a usage/argv error (exit `2`), and any other failure (exit `3`) — never sharing `1` with a pause, so an unattended host tells them apart from the exit code alone. A run that pauses is resumed with the loop's own existing `--resume <pr>` flag, never a flag on this command."
|
|
6272
|
+
],
|
|
6273
|
+
status: "shipped"
|
|
6274
|
+
},
|
|
6275
|
+
{
|
|
6276
|
+
name: "task status",
|
|
6277
|
+
description: "Every open task with a frozen brief, its pull request, and whether its loop is running, paused, or published",
|
|
6278
|
+
flags: [{ flag: "--json", description: "Enveloped JSON output (schema: 1)" }],
|
|
6279
|
+
details: [
|
|
6280
|
+
"Read-only: one `gh issue list` for every open task Issue across every tranche (title/label resolved through the same `resolveTaskIssueRef` `list-tasks.ts` already uses), the open pull request per branch, and the driver pid record / pause record / publish effect markers under `<outboxRoot>/dev-review-loop/<task>/` — never a `ps` scan, never a re-parse of posted verdict comments to decide `published`.",
|
|
6281
|
+
"`running` names the driver's pid (`review-validity-v1` task 7's pid record); `paused` names the reason from the pause record; `published` means the newest round's reviewer and security verdict effect markers both read `posted`; `no driver` is the fallback when none of the above holds.",
|
|
6282
|
+
"`vinaya task status <tranche> <n>` narrows to one task and adds the last round's held or published verdict lines (`round-<n>-reviewer.md`/`round-<n>-security.md`, whichever their outbox carries) plus the exact `vinaya dev-review-loop --resume <pr>` command when paused."
|
|
5479
6283
|
],
|
|
5480
6284
|
status: "shipped"
|
|
5481
6285
|
},
|
|
@@ -5683,6 +6487,15 @@ var COMMANDS = [
|
|
|
5683
6487
|
],
|
|
5684
6488
|
status: "shipped"
|
|
5685
6489
|
},
|
|
6490
|
+
{
|
|
6491
|
+
name: "milestone status",
|
|
6492
|
+
description: "Print each of a Milestone's declared tranche intents with its derived lifecycle and issue counts",
|
|
6493
|
+
flags: [{ flag: "--json", description: "Enveloped JSON output (schema: 1)" }],
|
|
6494
|
+
details: [
|
|
6495
|
+
"Read-only — writes nothing. For each `- <slug>: …` line in the Milestone's `### Tranche intents` section, prints the tranche's lifecycle (`planned`/`active`/`complete`) and its labeled Issues' counts (merged, open, not planned), all derived from the forge. Refuses if `<n>` isn't a real Milestone in this repo, or if the forge is unreachable."
|
|
6496
|
+
],
|
|
6497
|
+
status: "shipped"
|
|
6498
|
+
},
|
|
5686
6499
|
{
|
|
5687
6500
|
name: "review status",
|
|
5688
6501
|
description: "Print the review loop's own state for a PR, and its branch's distance from the base",
|
|
@@ -5979,10 +6792,10 @@ function createForgeSource(config) {
|
|
|
5979
6792
|
};
|
|
5980
6793
|
}
|
|
5981
6794
|
// ../../packages/sources/src/select-source.ts
|
|
5982
|
-
import { z as
|
|
5983
|
-
var StateSourceConfigSchema =
|
|
5984
|
-
|
|
5985
|
-
|
|
6795
|
+
import { z as z5 } from "zod";
|
|
6796
|
+
var StateSourceConfigSchema = z5.discriminatedUnion("kind", [
|
|
6797
|
+
z5.object({ kind: z5.literal("forge"), owner: z5.string(), repo: z5.string() }),
|
|
6798
|
+
z5.object({ kind: z5.literal("file"), root: z5.string().optional() })
|
|
5986
6799
|
]);
|
|
5987
6800
|
// src/checks/edge-resolve.ts
|
|
5988
6801
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
@@ -6102,6 +6915,570 @@ async function resolveEdge(id, taskById, factsByTaskId, repo, resolveSibling = d
|
|
|
6102
6915
|
};
|
|
6103
6916
|
}
|
|
6104
6917
|
|
|
6918
|
+
// src/lib/brief-assembly.ts
|
|
6919
|
+
function git(args) {
|
|
6920
|
+
try {
|
|
6921
|
+
return execFileSync5("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
6922
|
+
} catch {
|
|
6923
|
+
return "";
|
|
6924
|
+
}
|
|
6925
|
+
}
|
|
6926
|
+
function expandGlob(glob) {
|
|
6927
|
+
const out = git(["ls-files", "--", glob]);
|
|
6928
|
+
return out.split(`
|
|
6929
|
+
`).map((s) => s.trim()).filter(Boolean);
|
|
6930
|
+
}
|
|
6931
|
+
var DRAFT_ISSUE_SENTINEL = Number.MAX_SAFE_INTEGER;
|
|
6932
|
+
|
|
6933
|
+
// src/checks/registry.ts
|
|
6934
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
6935
|
+
import { join as join4 } from "node:path";
|
|
6936
|
+
var DIST_BIN_DIR = join4(packageRoot(import.meta.url), "dist", "checks", "bin");
|
|
6937
|
+
var SRC_BIN_DIR = join4(packageRoot(import.meta.url), "src", "checks", "bin");
|
|
6938
|
+
var BIN_DIR = existsSync4(DIST_BIN_DIR) ? DIST_BIN_DIR : SRC_BIN_DIR;
|
|
6939
|
+
var BIN_EXT = BIN_DIR === DIST_BIN_DIR ? ".js" : ".ts";
|
|
6940
|
+
function bin(name) {
|
|
6941
|
+
return join4(BIN_DIR, `${name}${BIN_EXT}`);
|
|
6942
|
+
}
|
|
6943
|
+
var REGISTRY = [
|
|
6944
|
+
[
|
|
6945
|
+
{
|
|
6946
|
+
name: "brief-shape",
|
|
6947
|
+
validates: "body",
|
|
6948
|
+
run: bin("check-brief-shape"),
|
|
6949
|
+
scope: "diff",
|
|
6950
|
+
timeoutMs: 15000,
|
|
6951
|
+
env: {
|
|
6952
|
+
PR_BODY: { optional: true },
|
|
6953
|
+
BRANCH: { optional: true },
|
|
6954
|
+
PR_NUMBER: { optional: true },
|
|
6955
|
+
GITHUB_TOKEN: { optional: true },
|
|
6956
|
+
GH_TOKEN: { optional: true }
|
|
6957
|
+
}
|
|
6958
|
+
},
|
|
6959
|
+
0
|
|
6960
|
+
],
|
|
6961
|
+
[
|
|
6962
|
+
{
|
|
6963
|
+
name: "pr-report-density",
|
|
6964
|
+
validates: "body",
|
|
6965
|
+
run: bin("check-pr-report-density"),
|
|
6966
|
+
scope: "diff",
|
|
6967
|
+
timeoutMs: 15000,
|
|
6968
|
+
env: {
|
|
6969
|
+
PR_BODY: { optional: true }
|
|
6970
|
+
}
|
|
6971
|
+
},
|
|
6972
|
+
0
|
|
6973
|
+
],
|
|
6974
|
+
[
|
|
6975
|
+
{
|
|
6976
|
+
name: "doc-coverage",
|
|
6977
|
+
validates: "body",
|
|
6978
|
+
run: bin("check-doc-coverage"),
|
|
6979
|
+
scope: "diff",
|
|
6980
|
+
timeoutMs: 15000,
|
|
6981
|
+
env: {
|
|
6982
|
+
BASE_SHA: { optional: true },
|
|
6983
|
+
PR_BODY: { optional: true },
|
|
6984
|
+
PR_BODY_FILE: { optional: true },
|
|
6985
|
+
PR_NUMBER: { optional: true },
|
|
6986
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
6987
|
+
GITHUB_TOKEN: { optional: true },
|
|
6988
|
+
GH_TOKEN: { optional: true }
|
|
6989
|
+
}
|
|
6990
|
+
},
|
|
6991
|
+
0
|
|
6992
|
+
],
|
|
6993
|
+
[
|
|
6994
|
+
{
|
|
6995
|
+
name: "coherence",
|
|
6996
|
+
run: bin("check-coherence"),
|
|
6997
|
+
scope: "full",
|
|
6998
|
+
timeoutMs: 30000,
|
|
6999
|
+
env: {
|
|
7000
|
+
AEG_REPO: { optional: true },
|
|
7001
|
+
BRANCH: { optional: true },
|
|
7002
|
+
GITHUB_TOKEN: { optional: true },
|
|
7003
|
+
GH_TOKEN: { optional: true }
|
|
7004
|
+
}
|
|
7005
|
+
},
|
|
7006
|
+
0
|
|
7007
|
+
],
|
|
7008
|
+
[
|
|
7009
|
+
{
|
|
7010
|
+
name: "pr-premise-reassert",
|
|
7011
|
+
validates: "body",
|
|
7012
|
+
run: bin("check-pr-premise-reassert"),
|
|
7013
|
+
scope: "diff",
|
|
7014
|
+
timeoutMs: 15000,
|
|
7015
|
+
env: {
|
|
7016
|
+
PR_BODY: { optional: true }
|
|
7017
|
+
}
|
|
7018
|
+
},
|
|
7019
|
+
0
|
|
7020
|
+
],
|
|
7021
|
+
[
|
|
7022
|
+
{
|
|
7023
|
+
name: "dispatch-readiness",
|
|
7024
|
+
run: bin("check-dispatch-readiness"),
|
|
7025
|
+
scope: "full",
|
|
7026
|
+
timeoutMs: 30000,
|
|
7027
|
+
env: {
|
|
7028
|
+
AEG_REPO: { optional: true },
|
|
7029
|
+
BRANCH: { optional: true },
|
|
7030
|
+
GITHUB_TOKEN: { optional: true },
|
|
7031
|
+
GH_TOKEN: { optional: true },
|
|
7032
|
+
PREMISE_FILE: { optional: true }
|
|
7033
|
+
}
|
|
7034
|
+
},
|
|
7035
|
+
0
|
|
7036
|
+
],
|
|
7037
|
+
[
|
|
7038
|
+
{
|
|
7039
|
+
name: "closes-n",
|
|
7040
|
+
validates: "body",
|
|
7041
|
+
run: bin("check-closes-n"),
|
|
7042
|
+
scope: "diff",
|
|
7043
|
+
timeoutMs: 15000,
|
|
7044
|
+
requiresOpenPr: true,
|
|
7045
|
+
env: {
|
|
7046
|
+
BRANCH: { optional: true },
|
|
7047
|
+
PR_BODY: { optional: true },
|
|
7048
|
+
AEG_REPO: { optional: true },
|
|
7049
|
+
GITHUB_TOKEN: { optional: true },
|
|
7050
|
+
GH_TOKEN: { optional: true }
|
|
7051
|
+
}
|
|
7052
|
+
},
|
|
7053
|
+
1
|
|
7054
|
+
],
|
|
7055
|
+
[
|
|
7056
|
+
{
|
|
7057
|
+
name: "single-plan-pr",
|
|
7058
|
+
run: bin("check-single-plan-pr"),
|
|
7059
|
+
scope: "diff",
|
|
7060
|
+
timeoutMs: 15000,
|
|
7061
|
+
env: {
|
|
7062
|
+
BASE_SHA: { optional: true },
|
|
7063
|
+
PR_NUMBER: { optional: true },
|
|
7064
|
+
GITHUB_TOKEN: { optional: true },
|
|
7065
|
+
GH_TOKEN: { optional: true }
|
|
7066
|
+
}
|
|
7067
|
+
},
|
|
7068
|
+
0
|
|
7069
|
+
],
|
|
7070
|
+
[
|
|
7071
|
+
{
|
|
7072
|
+
name: "surface-scope",
|
|
7073
|
+
run: bin("check-surface-scope"),
|
|
7074
|
+
scope: "diff",
|
|
7075
|
+
timeoutMs: 15000,
|
|
7076
|
+
env: {
|
|
7077
|
+
AEG_REPO: { optional: true },
|
|
7078
|
+
BASE_SHA: { optional: true },
|
|
7079
|
+
BRANCH: { optional: true },
|
|
7080
|
+
GITHUB_TOKEN: { optional: true },
|
|
7081
|
+
GH_TOKEN: { optional: true }
|
|
7082
|
+
}
|
|
7083
|
+
},
|
|
7084
|
+
0
|
|
7085
|
+
],
|
|
7086
|
+
[
|
|
7087
|
+
{
|
|
7088
|
+
name: "test-plan",
|
|
7089
|
+
validates: "body",
|
|
7090
|
+
run: bin("check-test-plan"),
|
|
7091
|
+
scope: "diff",
|
|
7092
|
+
timeoutMs: 15000,
|
|
7093
|
+
requiresOpenPr: true,
|
|
7094
|
+
principalOwed: true,
|
|
7095
|
+
env: {
|
|
7096
|
+
PR_BODY: { optional: true },
|
|
7097
|
+
BRANCH: { optional: true }
|
|
7098
|
+
}
|
|
7099
|
+
},
|
|
7100
|
+
1
|
|
7101
|
+
],
|
|
7102
|
+
[
|
|
7103
|
+
{
|
|
7104
|
+
name: "body-bare-digits",
|
|
7105
|
+
validates: "body",
|
|
7106
|
+
run: bin("check-body-bare-digits"),
|
|
7107
|
+
scope: "diff",
|
|
7108
|
+
timeoutMs: 15000,
|
|
7109
|
+
requiresOpenPr: true,
|
|
7110
|
+
ownWorkflow: true,
|
|
7111
|
+
env: {
|
|
7112
|
+
PR_BODY: { optional: true },
|
|
7113
|
+
PR_NUMBER: { optional: true },
|
|
7114
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
7115
|
+
GITHUB_TOKEN: { optional: true },
|
|
7116
|
+
GH_TOKEN: { optional: true }
|
|
7117
|
+
}
|
|
7118
|
+
},
|
|
7119
|
+
1
|
|
7120
|
+
],
|
|
7121
|
+
[
|
|
7122
|
+
{
|
|
7123
|
+
name: "token-report",
|
|
7124
|
+
validates: "body",
|
|
7125
|
+
run: bin("check-token-report"),
|
|
7126
|
+
scope: "diff",
|
|
7127
|
+
timeoutMs: 15000,
|
|
7128
|
+
requiresOpenPr: true,
|
|
7129
|
+
env: {
|
|
7130
|
+
PR_BODY: { optional: true },
|
|
7131
|
+
BRANCH: { optional: true },
|
|
7132
|
+
CLAUDE_PROJECT_DIR: { optional: true },
|
|
7133
|
+
CLAUDE_CODE_SESSION_ID: { optional: true }
|
|
7134
|
+
}
|
|
7135
|
+
},
|
|
7136
|
+
1
|
|
7137
|
+
],
|
|
7138
|
+
[
|
|
7139
|
+
{
|
|
7140
|
+
name: "no-disk-state",
|
|
7141
|
+
run: bin("check-no-disk-state"),
|
|
7142
|
+
scope: "diff",
|
|
7143
|
+
timeoutMs: 15000,
|
|
7144
|
+
env: { BASE_SHA: { optional: true } }
|
|
7145
|
+
},
|
|
7146
|
+
0
|
|
7147
|
+
],
|
|
7148
|
+
[
|
|
7149
|
+
{
|
|
7150
|
+
name: "registry-gates",
|
|
7151
|
+
run: bin("check-registry-gates"),
|
|
7152
|
+
scope: "full",
|
|
7153
|
+
timeoutMs: 30000,
|
|
7154
|
+
env: {
|
|
7155
|
+
AEG_REPO: { optional: true },
|
|
7156
|
+
GITHUB_TOKEN: { optional: true },
|
|
7157
|
+
GH_TOKEN: { optional: true }
|
|
7158
|
+
}
|
|
7159
|
+
},
|
|
7160
|
+
0
|
|
7161
|
+
],
|
|
7162
|
+
[
|
|
7163
|
+
{
|
|
7164
|
+
name: "review-gate",
|
|
7165
|
+
run: bin("check-review-gate"),
|
|
7166
|
+
scope: "full",
|
|
7167
|
+
timeoutMs: 30000,
|
|
7168
|
+
ownWorkflow: true,
|
|
7169
|
+
env: {
|
|
7170
|
+
PR_NUMBER: { optional: true },
|
|
7171
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
7172
|
+
GITHUB_TOKEN: { optional: true },
|
|
7173
|
+
GH_TOKEN: { optional: true }
|
|
7174
|
+
}
|
|
7175
|
+
},
|
|
7176
|
+
1
|
|
7177
|
+
],
|
|
7178
|
+
[
|
|
7179
|
+
{
|
|
7180
|
+
name: "branch-topology",
|
|
7181
|
+
run: bin("check-branch-topology"),
|
|
7182
|
+
scope: "full",
|
|
7183
|
+
timeoutMs: 30000,
|
|
7184
|
+
env: {
|
|
7185
|
+
BRANCH: { optional: true },
|
|
7186
|
+
AEG_REPO: { optional: true },
|
|
7187
|
+
GITHUB_TOKEN: { optional: true },
|
|
7188
|
+
GH_TOKEN: { optional: true }
|
|
7189
|
+
}
|
|
7190
|
+
},
|
|
7191
|
+
0
|
|
7192
|
+
],
|
|
7193
|
+
[
|
|
7194
|
+
{
|
|
7195
|
+
name: "dead-branch-push",
|
|
7196
|
+
run: bin("check-dead-branch-push"),
|
|
7197
|
+
scope: "full",
|
|
7198
|
+
timeoutMs: 30000,
|
|
7199
|
+
env: {
|
|
7200
|
+
BRANCH: { optional: true },
|
|
7201
|
+
GITHUB_TOKEN: { optional: true },
|
|
7202
|
+
GH_TOKEN: { optional: true }
|
|
7203
|
+
}
|
|
7204
|
+
},
|
|
7205
|
+
0
|
|
7206
|
+
],
|
|
7207
|
+
[
|
|
7208
|
+
{
|
|
7209
|
+
name: "first-push-dispatch",
|
|
7210
|
+
run: bin("check-first-push-dispatch"),
|
|
7211
|
+
scope: "full",
|
|
7212
|
+
timeoutMs: 30000,
|
|
7213
|
+
env: {
|
|
7214
|
+
BRANCH: { optional: true },
|
|
7215
|
+
AEG_REPO: { optional: true },
|
|
7216
|
+
GITHUB_TOKEN: { optional: true },
|
|
7217
|
+
GH_TOKEN: { optional: true }
|
|
7218
|
+
}
|
|
7219
|
+
},
|
|
7220
|
+
0
|
|
7221
|
+
],
|
|
7222
|
+
[
|
|
7223
|
+
{
|
|
7224
|
+
name: "doc-coverage-push",
|
|
7225
|
+
validates: "body",
|
|
7226
|
+
run: bin("check-doc-coverage-push"),
|
|
7227
|
+
scope: "diff",
|
|
7228
|
+
timeoutMs: 15000,
|
|
7229
|
+
env: {
|
|
7230
|
+
OVERRIDE_DOCS: { optional: true },
|
|
7231
|
+
BASE_SHA: { optional: true },
|
|
7232
|
+
PR_BODY: { optional: true },
|
|
7233
|
+
PR_BODY_FILE: { optional: true },
|
|
7234
|
+
PR_LABELS: { optional: true },
|
|
7235
|
+
WAIVER_LABEL_ACTOR: { optional: true },
|
|
7236
|
+
GITHUB_REPOSITORY: { optional: true },
|
|
7237
|
+
GITHUB_TOKEN: { optional: true },
|
|
7238
|
+
GH_TOKEN: { optional: true }
|
|
7239
|
+
}
|
|
7240
|
+
},
|
|
7241
|
+
0
|
|
7242
|
+
],
|
|
7243
|
+
[
|
|
7244
|
+
{
|
|
7245
|
+
name: "issue-assignment",
|
|
7246
|
+
run: bin("check-issue-assignment"),
|
|
7247
|
+
scope: "full",
|
|
7248
|
+
timeoutMs: 30000,
|
|
7249
|
+
env: {
|
|
7250
|
+
AEG_REPO: { optional: true },
|
|
7251
|
+
BRANCH: { optional: true },
|
|
7252
|
+
GITHUB_TOKEN: { optional: true },
|
|
7253
|
+
GH_TOKEN: { optional: true }
|
|
7254
|
+
}
|
|
7255
|
+
},
|
|
7256
|
+
0
|
|
7257
|
+
],
|
|
7258
|
+
[
|
|
7259
|
+
{
|
|
7260
|
+
name: "evidence-fresh",
|
|
7261
|
+
validates: "body",
|
|
7262
|
+
run: bin("check-evidence-fresh"),
|
|
7263
|
+
scope: "diff",
|
|
7264
|
+
timeoutMs: 15000,
|
|
7265
|
+
requiresOpenPr: true,
|
|
7266
|
+
env: {
|
|
7267
|
+
PR_NUMBER: { optional: true },
|
|
7268
|
+
PR_BODY: { optional: true },
|
|
7269
|
+
BASE_SHA: { optional: true },
|
|
7270
|
+
GITHUB_TOKEN: { optional: true },
|
|
7271
|
+
GH_TOKEN: { optional: true }
|
|
7272
|
+
}
|
|
7273
|
+
},
|
|
7274
|
+
1
|
|
7275
|
+
],
|
|
7276
|
+
[
|
|
7277
|
+
{
|
|
7278
|
+
name: "reader-resolvable-prose",
|
|
7279
|
+
run: bin("check-reader-resolvable-prose"),
|
|
7280
|
+
scope: "full",
|
|
7281
|
+
timeoutMs: 30000,
|
|
7282
|
+
env: {},
|
|
7283
|
+
include: [
|
|
7284
|
+
"aeg-root/**/*.md",
|
|
7285
|
+
"apps/cli/src/**",
|
|
7286
|
+
".github/workflows/**",
|
|
7287
|
+
".vinaya/**",
|
|
7288
|
+
"apps/cli/README.md",
|
|
7289
|
+
"packages/sources/README.md"
|
|
7290
|
+
]
|
|
7291
|
+
},
|
|
7292
|
+
0
|
|
7293
|
+
],
|
|
7294
|
+
[
|
|
7295
|
+
{
|
|
7296
|
+
name: "retired-vocabulary",
|
|
7297
|
+
run: bin("check-retired-vocabulary"),
|
|
7298
|
+
scope: "full",
|
|
7299
|
+
timeoutMs: 30000,
|
|
7300
|
+
env: {},
|
|
7301
|
+
include: ["aeg-root/**/*.md"]
|
|
7302
|
+
},
|
|
7303
|
+
0
|
|
7304
|
+
],
|
|
7305
|
+
[
|
|
7306
|
+
{
|
|
7307
|
+
name: "doctrine-portability",
|
|
7308
|
+
run: bin("check-doctrine-portability"),
|
|
7309
|
+
scope: "full",
|
|
7310
|
+
timeoutMs: 30000,
|
|
7311
|
+
env: { BASE_SHA: { optional: true } },
|
|
7312
|
+
include: ["aeg-root/**/*.md"]
|
|
7313
|
+
},
|
|
7314
|
+
0
|
|
7315
|
+
],
|
|
7316
|
+
[
|
|
7317
|
+
{
|
|
7318
|
+
name: "doctrine-no-procedures",
|
|
7319
|
+
run: bin("check-doctrine-no-procedures"),
|
|
7320
|
+
scope: "full",
|
|
7321
|
+
timeoutMs: 30000,
|
|
7322
|
+
env: {},
|
|
7323
|
+
include: ["aeg-root/**/*.md"]
|
|
7324
|
+
},
|
|
7325
|
+
0
|
|
7326
|
+
],
|
|
7327
|
+
[
|
|
7328
|
+
{
|
|
7329
|
+
name: "exec-bits",
|
|
7330
|
+
run: bin("check-exec-bits"),
|
|
7331
|
+
scope: "diff",
|
|
7332
|
+
timeoutMs: 30000,
|
|
7333
|
+
env: {}
|
|
7334
|
+
},
|
|
7335
|
+
0
|
|
7336
|
+
],
|
|
7337
|
+
[
|
|
7338
|
+
{
|
|
7339
|
+
name: "workspace-escape",
|
|
7340
|
+
run: bin("check-workspace-escape"),
|
|
7341
|
+
scope: "full",
|
|
7342
|
+
timeoutMs: 30000,
|
|
7343
|
+
env: {},
|
|
7344
|
+
include: ["aeg-root/**/*.md"]
|
|
7345
|
+
},
|
|
7346
|
+
0
|
|
7347
|
+
],
|
|
7348
|
+
[
|
|
7349
|
+
{
|
|
7350
|
+
name: "changeset-coverage",
|
|
7351
|
+
run: bin("check-changeset-coverage"),
|
|
7352
|
+
scope: "diff",
|
|
7353
|
+
timeoutMs: 15000,
|
|
7354
|
+
env: {}
|
|
7355
|
+
},
|
|
7356
|
+
0
|
|
7357
|
+
],
|
|
7358
|
+
[
|
|
7359
|
+
{
|
|
7360
|
+
name: "quoted-command",
|
|
7361
|
+
run: bin("check-quoted-command"),
|
|
7362
|
+
scope: "diff",
|
|
7363
|
+
timeoutMs: 15000,
|
|
7364
|
+
env: {}
|
|
7365
|
+
},
|
|
7366
|
+
0
|
|
7367
|
+
],
|
|
7368
|
+
[
|
|
7369
|
+
{
|
|
7370
|
+
name: "main-branch-refusal",
|
|
7371
|
+
run: bin("check-main-branch-refusal"),
|
|
7372
|
+
scope: "full",
|
|
7373
|
+
timeoutMs: 15000,
|
|
7374
|
+
env: { VINAYA_PUSH_REFS: { optional: true } }
|
|
7375
|
+
},
|
|
7376
|
+
0
|
|
7377
|
+
],
|
|
7378
|
+
[
|
|
7379
|
+
{
|
|
7380
|
+
name: "token-collection-wired",
|
|
7381
|
+
run: bin("check-token-collection-wired"),
|
|
7382
|
+
scope: "full",
|
|
7383
|
+
timeoutMs: 15000,
|
|
7384
|
+
env: {
|
|
7385
|
+
CLAUDE_PROJECT_DIR: { optional: true },
|
|
7386
|
+
CLAUDE_CODE_SESSION_ID: { optional: true }
|
|
7387
|
+
}
|
|
7388
|
+
},
|
|
7389
|
+
0
|
|
7390
|
+
],
|
|
7391
|
+
[
|
|
7392
|
+
{
|
|
7393
|
+
name: "issue-title-grammar",
|
|
7394
|
+
run: bin("check-issue-title-grammar"),
|
|
7395
|
+
validates: "issue",
|
|
7396
|
+
scope: "full",
|
|
7397
|
+
ownWorkflow: true,
|
|
7398
|
+
timeoutMs: 15000,
|
|
7399
|
+
env: { ISSUE_TITLE: { optional: true } }
|
|
7400
|
+
},
|
|
7401
|
+
1
|
|
7402
|
+
],
|
|
7403
|
+
[
|
|
7404
|
+
{
|
|
7405
|
+
name: "issue-objectives-numbering",
|
|
7406
|
+
run: bin("check-issue-objectives-numbering"),
|
|
7407
|
+
validates: "issue",
|
|
7408
|
+
scope: "full",
|
|
7409
|
+
ownWorkflow: true,
|
|
7410
|
+
timeoutMs: 15000,
|
|
7411
|
+
env: { ISSUE_BODY: { optional: true }, ISSUE_NUMBER: { optional: true } }
|
|
7412
|
+
},
|
|
7413
|
+
1
|
|
7414
|
+
],
|
|
7415
|
+
[
|
|
7416
|
+
{
|
|
7417
|
+
name: "issue-parts-coverage",
|
|
7418
|
+
run: bin("check-issue-parts-coverage"),
|
|
7419
|
+
validates: "issue",
|
|
7420
|
+
scope: "full",
|
|
7421
|
+
ownWorkflow: true,
|
|
7422
|
+
timeoutMs: 15000,
|
|
7423
|
+
env: { ISSUE_BODY: { optional: true } }
|
|
7424
|
+
},
|
|
7425
|
+
1
|
|
7426
|
+
],
|
|
7427
|
+
[
|
|
7428
|
+
{
|
|
7429
|
+
name: "issue-surface-globs",
|
|
7430
|
+
run: bin("check-issue-surface-globs"),
|
|
7431
|
+
validates: "issue",
|
|
7432
|
+
scope: "full",
|
|
7433
|
+
ownWorkflow: true,
|
|
7434
|
+
timeoutMs: 15000,
|
|
7435
|
+
env: { ISSUE_BODY: { optional: true } }
|
|
7436
|
+
},
|
|
7437
|
+
1
|
|
7438
|
+
],
|
|
7439
|
+
[
|
|
7440
|
+
{
|
|
7441
|
+
name: "issue-tranche-label",
|
|
7442
|
+
run: bin("check-issue-tranche-label"),
|
|
7443
|
+
validates: "issue",
|
|
7444
|
+
scope: "full",
|
|
7445
|
+
ownWorkflow: true,
|
|
7446
|
+
timeoutMs: 15000,
|
|
7447
|
+
env: { ISSUE_BODY: { optional: true }, ISSUE_LABELS: { optional: true } }
|
|
7448
|
+
},
|
|
7449
|
+
1
|
|
7450
|
+
],
|
|
7451
|
+
[
|
|
7452
|
+
{
|
|
7453
|
+
name: "issue-milestone-attach",
|
|
7454
|
+
run: bin("check-issue-milestone-attach"),
|
|
7455
|
+
validates: "issue",
|
|
7456
|
+
scope: "full",
|
|
7457
|
+
ownWorkflow: true,
|
|
7458
|
+
timeoutMs: 15000,
|
|
7459
|
+
env: {
|
|
7460
|
+
ISSUE_LABELS: { optional: true },
|
|
7461
|
+
CURRENT_MILESTONE_TITLE: { optional: true },
|
|
7462
|
+
RESOLVED_MILESTONE_TITLE: { optional: true }
|
|
7463
|
+
}
|
|
7464
|
+
},
|
|
7465
|
+
1
|
|
7466
|
+
]
|
|
7467
|
+
];
|
|
7468
|
+
function coreCheckRegistry() {
|
|
7469
|
+
return REGISTRY.map(([spec]) => spec);
|
|
7470
|
+
}
|
|
7471
|
+
var CORE_CHECK_RING = Object.fromEntries(REGISTRY.map(([spec, ring]) => [spec.name, ring]));
|
|
7472
|
+
|
|
7473
|
+
// src/checks/runner.ts
|
|
7474
|
+
var activeKillers = new Set;
|
|
7475
|
+
|
|
7476
|
+
// src/lib/forge-write.ts
|
|
7477
|
+
var INFORMATIONAL_DISPATCH_BLOCKER_CLASSES = new Set([
|
|
7478
|
+
"depends-on-not-merged",
|
|
7479
|
+
"conflicts-with"
|
|
7480
|
+
]);
|
|
7481
|
+
|
|
6105
7482
|
// src/commands/review-post.ts
|
|
6106
7483
|
function parseChangedLineRanges(diffOutput) {
|
|
6107
7484
|
const result = {};
|
|
@@ -6133,7 +7510,7 @@ function parseChangedLineRanges(diffOutput) {
|
|
|
6133
7510
|
function fileDiffAgainst(ref, path) {
|
|
6134
7511
|
let out;
|
|
6135
7512
|
try {
|
|
6136
|
-
out =
|
|
7513
|
+
out = execFileSync6("git", ["diff", `${ref}...HEAD`, "--", path], {
|
|
6137
7514
|
encoding: "utf8",
|
|
6138
7515
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6139
7516
|
}).trim();
|
|
@@ -6144,7 +7521,7 @@ function fileDiffAgainst(ref, path) {
|
|
|
6144
7521
|
}
|
|
6145
7522
|
function revParse(ref) {
|
|
6146
7523
|
try {
|
|
6147
|
-
return
|
|
7524
|
+
return execFileSync6("git", ["rev-parse", "--verify", ref], {
|
|
6148
7525
|
encoding: "utf8",
|
|
6149
7526
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6150
7527
|
}).trim();
|
|
@@ -6154,7 +7531,7 @@ function revParse(ref) {
|
|
|
6154
7531
|
}
|
|
6155
7532
|
function repoRoot() {
|
|
6156
7533
|
try {
|
|
6157
|
-
return
|
|
7534
|
+
return execFileSync6("git", ["rev-parse", "--show-toplevel"], {
|
|
6158
7535
|
encoding: "utf8",
|
|
6159
7536
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6160
7537
|
}).trim();
|
|
@@ -6165,7 +7542,7 @@ function repoRoot() {
|
|
|
6165
7542
|
function changedFiles(base) {
|
|
6166
7543
|
let out;
|
|
6167
7544
|
try {
|
|
6168
|
-
out =
|
|
7545
|
+
out = execFileSync6("git", ["diff", "--name-only", `${base}...HEAD`], {
|
|
6169
7546
|
encoding: "utf8",
|
|
6170
7547
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6171
7548
|
}).trim();
|
|
@@ -6190,7 +7567,7 @@ function resolveDiff(base = process.env.BASE_SHA || "origin/main") {
|
|
|
6190
7567
|
const relPaths = changedFiles(ref);
|
|
6191
7568
|
if (relPaths === null)
|
|
6192
7569
|
continue;
|
|
6193
|
-
return { base: ref, root, files: relPaths.map((p) =>
|
|
7570
|
+
return { base: ref, root, files: relPaths.map((p) => join5(root, p)) };
|
|
6194
7571
|
}
|
|
6195
7572
|
return null;
|
|
6196
7573
|
}
|
|
@@ -6236,7 +7613,7 @@ function collect(dir, out = []) {
|
|
|
6236
7613
|
return out;
|
|
6237
7614
|
}
|
|
6238
7615
|
for (const name of entries) {
|
|
6239
|
-
const full =
|
|
7616
|
+
const full = join6(dir, name);
|
|
6240
7617
|
let isDir;
|
|
6241
7618
|
try {
|
|
6242
7619
|
isDir = statSync(full).isDirectory();
|
|
@@ -6279,8 +7656,8 @@ function main() {
|
|
|
6279
7656
|
continue;
|
|
6280
7657
|
if (!isValidCitedFilePath(quote.citedFile))
|
|
6281
7658
|
continue;
|
|
6282
|
-
const abs =
|
|
6283
|
-
if (
|
|
7659
|
+
const abs = join6(root, quote.citedFile);
|
|
7660
|
+
if (existsSync5(abs) && statSync(abs).isFile()) {
|
|
6284
7661
|
citedFileContents.set(quote.citedFile, readFileSync4(abs, "utf8"));
|
|
6285
7662
|
}
|
|
6286
7663
|
}
|