@attalabs/vinaya 0.27.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.
Files changed (48) hide show
  1. package/README.md +4 -3
  2. package/aeg-root/enforcement.md +4 -4
  3. package/aeg-root/roles/developer.md +23 -17
  4. package/aeg-root/roles/planner.md +2 -0
  5. package/aeg-root/roles/principal.md +4 -0
  6. package/aeg-root/roles/reviewer.md +3 -3
  7. package/aeg-root/roles/security.md +3 -3
  8. package/dist/checks/bin/check-body-bare-digits.js +915 -240
  9. package/dist/checks/bin/check-branch-topology.js +820 -180
  10. package/dist/checks/bin/check-brief-shape.js +915 -240
  11. package/dist/checks/bin/check-changeset-coverage.js +1534 -262
  12. package/dist/checks/bin/check-closes-n.js +824 -184
  13. package/dist/checks/bin/check-coherence.js +984 -265
  14. package/dist/checks/bin/check-dead-branch-push.js +805 -176
  15. package/dist/checks/bin/check-dispatch-readiness.js +1046 -276
  16. package/dist/checks/bin/check-doc-coverage-push.js +1530 -258
  17. package/dist/checks/bin/check-doc-coverage.js +1532 -260
  18. package/dist/checks/bin/check-doctrine-no-procedures.js +915 -240
  19. package/dist/checks/bin/check-doctrine-portability.js +1529 -257
  20. package/dist/checks/bin/check-evidence-fresh.js +1875 -258
  21. package/dist/checks/bin/check-exec-bits.js +1527 -255
  22. package/dist/checks/bin/check-first-push-dispatch.js +932 -246
  23. package/dist/checks/bin/check-issue-assignment.js +822 -182
  24. package/dist/checks/bin/check-issue-milestone-attach.js +5734 -0
  25. package/dist/checks/bin/check-issue-objectives-numbering.js +5736 -0
  26. package/dist/checks/bin/check-issue-parts-coverage.js +5736 -0
  27. package/dist/checks/bin/check-issue-surface-globs.js +6910 -0
  28. package/dist/checks/bin/check-issue-title-grammar.js +5736 -0
  29. package/dist/checks/bin/check-issue-tranche-label.js +5736 -0
  30. package/dist/checks/bin/check-main-branch-refusal.js +805 -176
  31. package/dist/checks/bin/check-no-disk-state.js +805 -176
  32. package/dist/checks/bin/check-pr-premise-reassert.js +915 -240
  33. package/dist/checks/bin/check-pr-report-density.js +805 -176
  34. package/dist/checks/bin/check-quoted-command.js +1508 -255
  35. package/dist/checks/bin/check-reader-resolvable-prose.js +1512 -259
  36. package/dist/checks/bin/check-registry-gates.js +892 -176
  37. package/dist/checks/bin/check-retired-vocabulary.js +1506 -253
  38. package/dist/checks/bin/check-review-gate.js +1000 -245
  39. package/dist/checks/bin/check-single-plan-pr.js +805 -176
  40. package/dist/checks/bin/check-surface-scope.js +830 -182
  41. package/dist/checks/bin/check-test-plan.js +834 -189
  42. package/dist/checks/bin/check-token-collection-wired.js +805 -176
  43. package/dist/checks/bin/check-token-report.js +805 -176
  44. package/dist/checks/bin/check-workspace-escape.js +1525 -253
  45. package/dist/index.js +9835 -5597
  46. package/dist/lib/pre-push-changed-files.js +57 -0
  47. package/dist/lib/pre-push-select-tests.js +1473 -0
  48. package/package.json +4 -2
@@ -3,9 +3,9 @@ import { createRequire } from "node:module";
3
3
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // src/checks/bin/check-changeset-coverage.ts
6
- import { execFileSync as execFileSync5 } from "node:child_process";
6
+ import { execFileSync as execFileSync6 } from "node:child_process";
7
7
  import { readdirSync, readFileSync as readFileSync3 } from "node:fs";
8
- import { join as join3, relative as relative2 } from "node:path";
8
+ import { join as join5, relative as relative2 } from "node:path";
9
9
  // ../../packages/aeg-core/src/gate-audience.ts
10
10
  var GATE_AUDIENCE = {
11
11
  "check-branch-topology": { shippedAs: "branch-topology", ring: 0 },
@@ -1956,6 +1956,8 @@ function parseInlineFieldList(section) {
1956
1956
  var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
1957
1957
  var OBJECTIVES_VERSION_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Objectives version:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
1958
1958
  var RULING_ORDINAL_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Ruling ordinal:\s*(\d+)(?!\d)/im;
1959
+ var BRIEF_HASH_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Brief hash:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
1960
+ var POLICY_DIGEST_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Policy digest:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
1959
1961
  function firstFiveLines(comment) {
1960
1962
  return comment.split(`
1961
1963
  `).slice(0, 5).join(`
@@ -1978,6 +1980,26 @@ function extractRulingOrdinal(comment) {
1978
1980
  const m = firstSevenLines(comment).match(RULING_ORDINAL_PATTERN);
1979
1981
  return m ? Number.parseInt(m[1], 10) : null;
1980
1982
  }
1983
+ function firstElevenLines(comment) {
1984
+ return comment.split(`
1985
+ `).slice(0, 11).join(`
1986
+ `);
1987
+ }
1988
+ function extractBriefHash(comment) {
1989
+ const m = firstElevenLines(comment).match(BRIEF_HASH_PATTERN);
1990
+ return m ? m[1].toLowerCase() : null;
1991
+ }
1992
+ function extractPolicyDigest(comment) {
1993
+ const m = firstElevenLines(comment).match(POLICY_DIGEST_PATTERN);
1994
+ return m ? m[1].toLowerCase() : null;
1995
+ }
1996
+ var FINDING_SEVERITY_LINE = /^\d+\.\s+\[([A-Z][A-Z]*)\]\s+(.+?)\s+—/gm;
1997
+ function extractFindingSeverities(comment) {
1998
+ return [...comment.matchAll(FINDING_SEVERITY_LINE)].map((m) => ({
1999
+ severity: m[1],
2000
+ location: m[2]
2001
+ }));
2002
+ }
1981
2003
  function extractVerdict(comments, valuePattern, missingLabel) {
1982
2004
  const candidates = comments.filter((c) => valuePattern.test(c));
1983
2005
  if (candidates.length === 0) {
@@ -1986,6 +2008,9 @@ function extractVerdict(comments, valuePattern, missingLabel) {
1986
2008
  headSha: null,
1987
2009
  objectivesVersion: null,
1988
2010
  rulingOrdinal: null,
2011
+ briefHash: null,
2012
+ policyDigest: null,
2013
+ findingSeverities: [],
1989
2014
  danglingNote: `no ${missingLabel} verdict comment found on this PR`
1990
2015
  };
1991
2016
  }
@@ -1997,6 +2022,9 @@ function extractVerdict(comments, valuePattern, missingLabel) {
1997
2022
  headSha: null,
1998
2023
  objectivesVersion: null,
1999
2024
  rulingOrdinal: null,
2025
+ briefHash: null,
2026
+ policyDigest: null,
2027
+ findingSeverities: [],
2000
2028
  danglingNote: `the most recent ${missingLabel} verdict comment carries a VERDICT-shaped line outside the first-five-line read window`
2001
2029
  };
2002
2030
  }
@@ -2005,6 +2033,9 @@ function extractVerdict(comments, valuePattern, missingLabel) {
2005
2033
  headSha: extractHeadSha(latest),
2006
2034
  objectivesVersion: extractObjectivesVersion(latest),
2007
2035
  rulingOrdinal: extractRulingOrdinal(latest),
2036
+ briefHash: extractBriefHash(latest),
2037
+ policyDigest: extractPolicyDigest(latest),
2038
+ findingSeverities: extractFindingSeverities(latest),
2008
2039
  danglingNote: null
2009
2040
  };
2010
2041
  }
@@ -2340,6 +2371,53 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
2340
2371
  }
2341
2372
  return out;
2342
2373
  }
2374
+ // ../../packages/aeg-core/src/review-policy.ts
2375
+ var CODE_REVIEW_SEVERITY_ORDER = ["BLOCKER", "MAJOR", "MINOR"];
2376
+ var SECURITY_SEVERITY_ORDER = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
2377
+ var DEFAULT_MAX_ROUNDS = 3;
2378
+ var DEFAULT_REVIEW_POLICY = {
2379
+ codeReviewThreshold: "BLOCKER",
2380
+ securityThreshold: "HIGH",
2381
+ maxRounds: DEFAULT_MAX_ROUNDS
2382
+ };
2383
+ var FILE_SHAPED_LOCATION = /\.[a-zA-Z0-9]{1,10}(:\d+)?\s*$/;
2384
+ var PROSE_LOCATION_PATTERNS = [/\bpr\s*body\b/i, /\bcomment\b/i];
2385
+ var ROLE_FILE_LOCATION = /(^|\/)aeg-root\/roles\//i;
2386
+ function isProseLocation(location) {
2387
+ if (ROLE_FILE_LOCATION.test(location))
2388
+ return true;
2389
+ if (FILE_SHAPED_LOCATION.test(location))
2390
+ return false;
2391
+ return PROSE_LOCATION_PATTERNS.some((pattern) => pattern.test(location));
2392
+ }
2393
+ var PROSE_CAP_SEVERITY = "MINOR";
2394
+ function blockingSeverities(scale, threshold) {
2395
+ const idx = scale.indexOf(threshold);
2396
+ if (idx === -1) {
2397
+ throw new Error(`blockingSeverities: threshold "${threshold}" is not one of ${scale.join(" > ")}`);
2398
+ }
2399
+ return scale.slice(0, idx + 1);
2400
+ }
2401
+ function evaluateReviewFindings(findings, scale, threshold) {
2402
+ const blocking = new Set(blockingSeverities(scale, threshold));
2403
+ const blockingFindings = findings.filter((f) => {
2404
+ if (!scale.includes(f.severity)) {
2405
+ throw new Error(`evaluateReviewFindings: severity "${f.severity}" is not one of ${scale.join(" > ")}`);
2406
+ }
2407
+ const effectiveSeverity = f.location !== undefined && isProseLocation(f.location) ? PROSE_CAP_SEVERITY : f.severity;
2408
+ return blocking.has(effectiveSeverity);
2409
+ });
2410
+ return { outcome: blockingFindings.length > 0 ? "blocked" : "clean", blockingFindings };
2411
+ }
2412
+ function evaluateCodeReview(findings, policy) {
2413
+ return evaluateReviewFindings(findings, CODE_REVIEW_SEVERITY_ORDER, policy.codeReviewThreshold);
2414
+ }
2415
+ function evaluateSecurityReview(findings, policy) {
2416
+ return evaluateReviewFindings(findings, SECURITY_SEVERITY_ORDER, policy.securityThreshold);
2417
+ }
2418
+ function isKnownSeverity(scale, value) {
2419
+ return scale.includes(value);
2420
+ }
2343
2421
  // ../../packages/aeg-core/src/pr-tier.ts
2344
2422
  var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
2345
2423
  function readTierFromPrBody(prBody) {
@@ -2710,7 +2788,7 @@ function checkForField(prBody) {
2710
2788
  ]
2711
2789
  };
2712
2790
  }
2713
- function checkClosesN(prBody) {
2791
+ function checkClosesNPresence(prBody) {
2714
2792
  const closesPattern = /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s{0,8}:?\s{0,8}#\d+/i;
2715
2793
  if (closesPattern.test(stripCode(prBody))) {
2716
2794
  return { status: "pass", errors: [] };
@@ -2742,10 +2820,22 @@ var COMMIT_TYPES = [
2742
2820
  "Test"
2743
2821
  ];
2744
2822
  var COMMIT_TYPE_STYLE = new RegExp(`^(${COMMIT_TYPES.join("|")})(\\([a-z0-9-]+\\))?: \\S`);
2823
+ function checkForgeTitle(title) {
2824
+ const taskStyle = /^\[[a-z0-9._-]+\] \S+ — \S/;
2825
+ if (COMMIT_TYPE_STYLE.test(title) || taskStyle.test(title))
2826
+ return { status: "pass", errors: [] };
2827
+ return {
2828
+ status: "fail",
2829
+ errors: [
2830
+ `brief-validation title: "${title}" matches neither title grammar — expected \`Type: description\` / \`Type(scope): description\` (commitlint types + Plan) or \`[tranche] id — description\` (task form).`
2831
+ ]
2832
+ };
2833
+ }
2745
2834
  var BRIEF_SHAPE_MARKERS = [checkSurfaceMap, checkDocUpdateList, checkStopConditions, checkAutonomyClause];
2746
2835
  var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
2836
+ var TASK_ISSUE_BRANCH_PATTERN = /^task\/issue-\d+$/;
2747
2837
  function isTaskBranch(branch) {
2748
- return TASK_BRANCH_PATTERN.test(branch);
2838
+ return TASK_BRANCH_PATTERN.test(branch) || TASK_ISSUE_BRANCH_PATTERN.test(branch);
2749
2839
  }
2750
2840
  function isBriefShaped(prBody) {
2751
2841
  const stripped = stripCode(prBody);
@@ -2867,8 +2957,9 @@ function packagesNamedIn(text) {
2867
2957
  }
2868
2958
  function hasTestPathForConsumer(text, consumerDir) {
2869
2959
  const escaped = consumerDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2870
- const re = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
2871
- return re.test(text);
2960
+ const filePathRe = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
2961
+ const testDirRe = new RegExp(`${escaped}\\/(?:[\\w-]+\\/)*(?:tests|specs)(?:\\/|\\b)`);
2962
+ return filePathRe.test(text) || testDirRe.test(text);
2872
2963
  }
2873
2964
  function checkConsumerTests(prBody, consumersOf) {
2874
2965
  const section4 = extractNumberedSection(prBody, 4);
@@ -2972,7 +3063,7 @@ function checkBriefSections(prBody, readTier, options = {}) {
2972
3063
  checkConsumerTests(prBody, consumersOf),
2973
3064
  checkDefeatCases(prBody),
2974
3065
  ...issueObjectives !== undefined ? [checkObjectivesCopy(prBody, issueObjectives), checkObjectivesCoverage(prBody)] : [],
2975
- ...requireClosesN ? [checkClosesN(prBody)] : []
3066
+ ...requireClosesN ? [checkClosesNPresence(prBody)] : []
2976
3067
  ];
2977
3068
  return { errors: results.flatMap((r) => r.errors) };
2978
3069
  }
@@ -3262,6 +3353,28 @@ function topLevelSectionText(body, headingName) {
3262
3353
  const next = /^##[ \t]/m.exec(afterHeading);
3263
3354
  return next ? afterHeading.slice(0, next.index) : afterHeading;
3264
3355
  }
3356
+ function partHasBacktickedPath(text) {
3357
+ let i = 0;
3358
+ while (i < text.length) {
3359
+ const start = text.indexOf("`", i);
3360
+ if (start === -1)
3361
+ return false;
3362
+ const end = text.indexOf("`", start + 1);
3363
+ if (end === -1)
3364
+ return false;
3365
+ if (text.slice(start + 1, end).includes("/"))
3366
+ return true;
3367
+ i = end + 1;
3368
+ }
3369
+ return false;
3370
+ }
3371
+ var PART_MIN_WORDS_OUTSIDE_BACKTICKS = 3;
3372
+ function stripPartBackticks(text) {
3373
+ return text.replace(/`[^`\n]*`/g, " ");
3374
+ }
3375
+ function partWordCount(text) {
3376
+ return text.split(/\s+/).filter((w) => /[a-z]/i.test(w)).length;
3377
+ }
3265
3378
  function looksLikeFilePath(entry2) {
3266
3379
  const stripped = entry2.replace(/\/\*\*?$/, "");
3267
3380
  const lastSegment = stripped.split("/").pop() ?? stripped;
@@ -3302,6 +3415,18 @@ function globCoversPath(glob, path) {
3302
3415
  const p = path.replace(/\/+$/, "");
3303
3416
  return g === p || g.startsWith(`${p}/`) || p.startsWith(`${g}/`);
3304
3417
  }
3418
+ function checkSurfaceGlobsResolve(body, resolvesToFile) {
3419
+ const surface = parseIssueSurface(body);
3420
+ if (!surface.ok)
3421
+ return { status: "pass", errors: [] };
3422
+ const errors = [];
3423
+ for (const glob of surface.value.in) {
3424
+ if (!resolvesToFile(glob)) {
3425
+ 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.`);
3426
+ }
3427
+ }
3428
+ return { status: errors.length > 0 ? "fail" : "pass", errors };
3429
+ }
3305
3430
  function checkSurfaceScope(changedFiles, outGlobs) {
3306
3431
  if (outGlobs.length === 0)
3307
3432
  return { ok: true };
@@ -3313,9 +3438,77 @@ function checkSurfaceScope(changedFiles, outGlobs) {
3313
3438
  }
3314
3439
  return violations.length > 0 ? { ok: false, violations } : { ok: true };
3315
3440
  }
3441
+ var ISSUE_PART_LINE_RE = /^Part\s+(\d+)\s*\(([^)]*)\)\s*[-—–]\s*(.*)$/i;
3442
+ function parseIssueParts(body) {
3443
+ const section = topLevelSectionText(body, "Parts");
3444
+ if (section === null)
3445
+ return { ok: false, errors: ["no `## Parts` heading found in the body."] };
3446
+ const lines = section.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
3447
+ const parts = [];
3448
+ const errors = [];
3449
+ for (const line of lines) {
3450
+ const m = ISSUE_PART_LINE_RE.exec(line);
3451
+ if (!m) {
3452
+ errors.push(`"${line}" is not a well-formed Parts line — expected \`Part <n> (<refs>) — <outcome>\`.`);
3453
+ continue;
3454
+ }
3455
+ const n = Number.parseInt(m[1], 10);
3456
+ const refs = m[2];
3457
+ const text = m[3].trim();
3458
+ if (text.length === 0) {
3459
+ errors.push(`Part ${n} has no outcome text after the dash — every Part states one observable outcome.`);
3460
+ continue;
3461
+ }
3462
+ if (partHasBacktickedPath(text) && partWordCount(stripPartBackticks(text)) < PART_MIN_WORDS_OUTSIDE_BACKTICKS) {
3463
+ errors.push(`Part ${n} is little more than a file path — a Part names an outcome and symbols, never a bare path.`);
3464
+ continue;
3465
+ }
3466
+ const objectiveIds = [...refs.matchAll(/O(\d+)/g)].map((r) => Number.parseInt(r[1], 10));
3467
+ parts.push({ n, objectiveIds, text });
3468
+ }
3469
+ if (parts.length === 0) {
3470
+ errors.push("the `## Parts` section has no well-formed `Part <n> (<refs>) — <outcome>` lines.");
3471
+ }
3472
+ if (errors.length > 0)
3473
+ return { ok: false, errors };
3474
+ return { ok: true, value: parts };
3475
+ }
3476
+ function checkPartsCiteDefinedObjectives(body) {
3477
+ const parts = parseIssueParts(body);
3478
+ const objectives = objectivesOf(body);
3479
+ if (!parts.ok || !objectives.ok)
3480
+ return { status: "pass", errors: [] };
3481
+ const definedIds = new Set(objectives.objectives.map((o) => Number.parseInt(o.id.slice(1), 10)));
3482
+ const errors = [];
3483
+ for (const part of parts.value) {
3484
+ for (const objectiveId of part.objectiveIds) {
3485
+ if (!definedIds.has(objectiveId)) {
3486
+ errors.push(`issue-validation Parts: Part ${part.n} cites O${objectiveId}, which the Issue's own \`## Objectives\` section does not define.`);
3487
+ }
3488
+ }
3489
+ }
3490
+ return { status: errors.length > 0 ? "fail" : "pass", errors };
3491
+ }
3316
3492
  function isTaskIssueLabelSet(labels) {
3317
3493
  return hasLabel("tranche", labels);
3318
3494
  }
3495
+ function checkTrancheLabelPresence(_body, _labels) {
3496
+ return { status: "pass", errors: [] };
3497
+ }
3498
+ function checkMilestoneAttach(labels, currentMilestoneTitle, resolvedMilestoneTitle) {
3499
+ if (!isTaskIssueLabelSet(labels))
3500
+ return { status: "pass", errors: [] };
3501
+ if (resolvedMilestoneTitle === null)
3502
+ return { status: "pass", errors: [] };
3503
+ if (currentMilestoneTitle === resolvedMilestoneTitle)
3504
+ return { status: "pass", errors: [] };
3505
+ return {
3506
+ status: "fail",
3507
+ errors: [
3508
+ `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}".`
3509
+ ]
3510
+ };
3511
+ }
3319
3512
  var TYPE_LABEL_IDS = LABELS.filter((l) => l.category === "type").map((l) => l.id);
3320
3513
  function isControlCodePoint(codePoint) {
3321
3514
  return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
@@ -3380,6 +3573,19 @@ function checkProjectsRegistered(body, _labels, registeredNames) {
3380
3573
  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;
3381
3574
  var DOC_PATH_RE_GLOBAL = new RegExp(DOC_PATH_RE.source, "gi");
3382
3575
 
3576
+ // ../../packages/aeg-core/src/task-branch-identity.ts
3577
+ var ISSUE_BRANCH_PATTERN = /^task\/issue-(\d+)$/;
3578
+ var TRANCHE_BRANCH_PATTERN = /^task\/([^/]+)\/([^/]+)$/;
3579
+ function parseTaskBranchIdentity(branch) {
3580
+ const issueMatch = ISSUE_BRANCH_PATTERN.exec(branch);
3581
+ if (issueMatch)
3582
+ return { kind: "issue", issueNumber: Number(issueMatch[1]) };
3583
+ const trancheMatch = TRANCHE_BRANCH_PATTERN.exec(branch);
3584
+ if (trancheMatch)
3585
+ return { kind: "tranche", tranche: trancheMatch[1], taskId: trancheMatch[2] };
3586
+ return null;
3587
+ }
3588
+
3383
3589
  // ../../packages/aeg-core/src/coherence-checks.ts
3384
3590
  var COHERENCE_ENFORCED_FROM = "2026-07-01";
3385
3591
  function isGrandfathered(isoDate) {
@@ -3400,6 +3606,7 @@ function checkA1(entries, principalAllowlist = PRINCIPAL_ALLOWLIST) {
3400
3606
  if (handClosed)
3401
3607
  continue;
3402
3608
  failures.push({
3609
+ code: "closed-without-merge",
3403
3610
  issue: e.task.issue,
3404
3611
  tranche: e.trancheSlug,
3405
3612
  task: e.task.id,
@@ -3424,6 +3631,7 @@ function checkA3(entries) {
3424
3631
  continue;
3425
3632
  if (e.facts.prState === "merged" && e.facts.issueState !== "closed") {
3426
3633
  failures.push({
3634
+ code: "auto-close-misfire",
3427
3635
  issue: e.task.issue,
3428
3636
  tranche: e.trancheSlug,
3429
3637
  task: e.task.id,
@@ -3448,6 +3656,7 @@ function checkT1(entries) {
3448
3656
  continue;
3449
3657
  if (e.facts === undefined) {
3450
3658
  failures.push({
3659
+ code: "phantom-issue-ref",
3451
3660
  issue: e.task.issue,
3452
3661
  tranche: e.trancheSlug,
3453
3662
  task: e.task.id,
@@ -3466,6 +3675,7 @@ function checkT2(openIssuesBySlug, topologyIssuesBySlug, ciTrancheSlug) {
3466
3675
  for (const num of openNums) {
3467
3676
  if (!topologySet.has(num)) {
3468
3677
  failures.push({
3678
+ code: "orphan-task",
3469
3679
  issue: num,
3470
3680
  tranche: slug,
3471
3681
  reason: `Issue #${num} is open and labeled ${trancheLabel(slug)} but does not appear in the topology file`
@@ -3500,6 +3710,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
3500
3710
  continue;
3501
3711
  if (forgeUnavailableSlugs?.has(e.trancheSlug)) {
3502
3712
  failures.push({
3713
+ code: "tbd-in-active-tranche",
3503
3714
  issue: null,
3504
3715
  tranche: e.trancheSlug,
3505
3716
  task: e.task.id,
@@ -3509,6 +3720,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
3509
3720
  continue;
3510
3721
  }
3511
3722
  failures.push({
3723
+ code: "tbd-in-active-tranche",
3512
3724
  issue: null,
3513
3725
  tranche: e.trancheSlug,
3514
3726
  task: e.task.id,
@@ -3541,6 +3753,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
3541
3753
  const sameIssue = depEntry.task.issue !== null && e.task.issue !== null && depEntry.task.issue === e.task.issue;
3542
3754
  if (sameTask || sameIssue) {
3543
3755
  failures.push({
3756
+ code: "d1-self-dependency",
3544
3757
  issue: e.task.issue,
3545
3758
  tranche: e.trancheSlug,
3546
3759
  task: e.task.id,
@@ -3552,6 +3765,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
3552
3765
  const depClosed = depFacts?.issueState === "closed";
3553
3766
  if (!depClosed) {
3554
3767
  failures.push({
3768
+ code: "dispatched-on-unmet-deps",
3555
3769
  issue: e.task.issue,
3556
3770
  tranche: e.trancheSlug,
3557
3771
  task: e.task.id,
@@ -3577,11 +3791,13 @@ function checkR1(issuesBySlug, grandfatheredIssues, registeredNames = []) {
3577
3791
  const errors = [
3578
3792
  ...checkIssueRationale(issue.body).errors,
3579
3793
  ...checkProjectsRegistered(issue.body, issue.labels, registeredNames).errors,
3580
- ...checkIssueObjectives(issue.body, issue.number).errors
3794
+ ...checkIssueObjectives(issue.body, issue.number).errors,
3795
+ ...checkPartsCiteDefinedObjectives(issue.body).errors
3581
3796
  ];
3582
3797
  if (errors.length === 0)
3583
3798
  continue;
3584
3799
  failures.push({
3800
+ code: "missing-rationale-field",
3585
3801
  issue: issue.number,
3586
3802
  tranche: slug,
3587
3803
  reason: `Issue #${issue.number} fails the rationale gate: ${errors.join(" | ")}`,
@@ -3610,6 +3826,7 @@ function checkL1(files, entriesBySlug) {
3610
3826
  const allClosed = withFacts.every((e) => e.facts?.issueState === "closed");
3611
3827
  if (allClosed) {
3612
3828
  failures.push({
3829
+ code: "archive-recommended",
3613
3830
  tranche: f.slug,
3614
3831
  reason: "Active tranche has no open task-Issues — consider archiving to completed/"
3615
3832
  });
@@ -3641,27 +3858,38 @@ function extractClosesReferences(prBody) {
3641
3858
  }
3642
3859
  return referenced;
3643
3860
  }
3644
- function checkClosesN2(branch, prBody, trancheFiles, taskIssueRefs) {
3861
+ function checkClosesNTopology(branch, prBody, trancheFiles, taskIssueRefs) {
3645
3862
  const referenced = extractClosesReferences(prBody);
3646
3863
  if (taskIssueRefs) {
3647
3864
  for (const n of referenced) {
3648
- const ref = taskIssueRefs.get(n);
3649
- if (!ref)
3865
+ const ref2 = taskIssueRefs.get(n);
3866
+ if (!ref2)
3650
3867
  continue;
3651
- const expectedBranch = `task/${ref.trancheSlug}/${ref.taskId}`;
3868
+ const expectedBranch = `task/${ref2.trancheSlug}/${ref2.taskId}`;
3652
3869
  if (branch !== expectedBranch) {
3653
3870
  return {
3654
3871
  ok: false,
3655
- message: `closes-n-reverse: branch "${branch}" closes #${n} (task ${ref.taskId} of tranche "${ref.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.`
3872
+ 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.`
3656
3873
  };
3657
3874
  }
3658
3875
  }
3659
3876
  }
3660
- const m = branch.match(/^task\/([^/]+)\/([^/]+)$/);
3661
- if (!m)
3877
+ const ref = parseTaskBranchIdentity(branch);
3878
+ if (!ref)
3662
3879
  return { ok: true };
3663
- const trancheSlug = m[1];
3664
- const taskId = m[2];
3880
+ if (ref.kind === "issue") {
3881
+ const expectedIssue2 = ref.issueNumber;
3882
+ if (!referenced.has(expectedIssue2)) {
3883
+ return {
3884
+ ok: false,
3885
+ expectedIssue: expectedIssue2,
3886
+ message: `closes-n: PR body does not contain \`Closes #${expectedIssue2}\` (required for branch "${branch}"). Add it to the PR body Summary section.`
3887
+ };
3888
+ }
3889
+ return { ok: true, expectedIssue: expectedIssue2 };
3890
+ }
3891
+ const trancheSlug = ref.tranche;
3892
+ const taskId = ref.taskId;
3665
3893
  const trancheFile = trancheFiles.find((f) => f.slug === trancheSlug);
3666
3894
  if (!trancheFile) {
3667
3895
  return {
@@ -3713,34 +3941,67 @@ function extractIssue(body) {
3713
3941
  const issue = headerNums.length > 0 ? headerNums[0] : bodyNums[0];
3714
3942
  return { issue, extraIssues: bodyNums.filter((n) => n !== issue), outsideHeader: headerNums.length === 0 };
3715
3943
  }
3716
- // ../../packages/aeg-core/src/review-gate.ts
3717
- function isBoundToHead(extraction, headSha) {
3718
- if (!extraction.headSha)
3944
+ // ../../packages/aeg-core/src/review-input-manifest.ts
3945
+ import { createHash as createHash4 } from "node:crypto";
3946
+ function briefHash(brief) {
3947
+ return createHash4("sha256").update(`${brief}
3948
+ `).digest("hex");
3949
+ }
3950
+ function policyDigest(policy) {
3951
+ return createHash4("sha256").update(JSON.stringify({ codeReviewThreshold: policy.codeReviewThreshold, securityThreshold: policy.securityThreshold })).digest("hex");
3952
+ }
3953
+ function isBoundToHead(echoed, headSha) {
3954
+ if (!echoed.headSha)
3719
3955
  return false;
3720
- return headSha.toLowerCase().startsWith(extraction.headSha.toLowerCase());
3956
+ return headSha.toLowerCase().startsWith(echoed.headSha.toLowerCase());
3721
3957
  }
3722
- function isBoundByPatchIdentity(extraction, headSha, patchIdOf) {
3723
- if (patchIdOf === undefined || !extraction.headSha)
3958
+ function isBoundByPatchIdentity(echoed, headSha, patchIdOf) {
3959
+ if (patchIdOf === undefined || !echoed.headSha)
3724
3960
  return false;
3725
- const judged = patchIdOf(extraction.headSha);
3961
+ const judged = patchIdOf(echoed.headSha);
3726
3962
  const current = patchIdOf(headSha);
3727
3963
  if (judged === null || current === null)
3728
3964
  return false;
3729
3965
  return judged === current;
3730
3966
  }
3731
- function isBoundToPatch(extraction, headSha, patchIdOf) {
3732
- return isBoundToHead(extraction, headSha) || isBoundByPatchIdentity(extraction, headSha, patchIdOf);
3967
+ function isBoundToPatch(echoed, headSha, patchIdOf) {
3968
+ return isBoundToHead(echoed, headSha) || isBoundByPatchIdentity(echoed, headSha, patchIdOf);
3733
3969
  }
3734
- function isBoundToObjectives(extraction, currentVersion) {
3970
+ function isBoundToObjectives(echoed, currentVersion) {
3735
3971
  if (currentVersion === null)
3736
3972
  return true;
3737
- return extraction.objectivesVersion === currentVersion;
3973
+ return echoed.objectivesVersion === currentVersion;
3738
3974
  }
3739
- function isBoundToRulings(extraction, currentOrdinal) {
3740
- if (extraction.rulingOrdinal === null)
3975
+ function isBoundToRulings(echoed, currentOrdinal) {
3976
+ if (echoed.rulingOrdinal === null)
3741
3977
  return currentOrdinal === 0;
3742
- return extraction.rulingOrdinal === currentOrdinal;
3978
+ return echoed.rulingOrdinal === currentOrdinal;
3979
+ }
3980
+ function isBoundToBriefHash(echoed, currentHash) {
3981
+ if (currentHash === null)
3982
+ return true;
3983
+ return echoed.briefHash === currentHash;
3743
3984
  }
3985
+ function isBoundToPolicy(echoed, currentDigest) {
3986
+ return echoed.policyDigest === currentDigest;
3987
+ }
3988
+ function compareManifest(echoed, current, patchIdOf) {
3989
+ const head = isBoundToPatch(echoed, current.headSha, patchIdOf);
3990
+ const briefHashBound = isBoundToBriefHash(echoed, current.briefHash);
3991
+ const objectivesVersion2 = isBoundToObjectives(echoed, current.objectivesVersion);
3992
+ const rulingOrdinal = isBoundToRulings(echoed, current.rulingOrdinal);
3993
+ const policyDigestBound = isBoundToPolicy(echoed, current.policyDigest);
3994
+ return {
3995
+ bound: head && briefHashBound && objectivesVersion2 && rulingOrdinal && policyDigestBound,
3996
+ head,
3997
+ briefHash: briefHashBound,
3998
+ objectivesVersion: objectivesVersion2,
3999
+ rulingOrdinal,
4000
+ policyDigest: policyDigestBound
4001
+ };
4002
+ }
4003
+
4004
+ // ../../packages/aeg-core/src/review-gate.ts
3744
4005
  function checkReviewGate(input) {
3745
4006
  const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
3746
4007
  const waived = isWaiverLabelActorVerified({
@@ -3763,15 +4024,55 @@ function checkReviewGate(input) {
3763
4024
  const verifiedBodies = verified.map((c) => c.body);
3764
4025
  const codeReview = extractCodeReviewVerdict(verifiedBodies);
3765
4026
  const security = extractSecurityReviewVerdict(verifiedBodies);
3766
- const codeReviewClean = codeReview.value === "APPROVE";
3767
- const securityClean = security.value === "PASS";
3768
- const codeReviewBound = isBoundToPatch(codeReview, input.headSha, input.patchIdOf);
3769
- const securityBound = isBoundToPatch(security, input.headSha, input.patchIdOf);
3770
- const codeReviewObjectivesBound = isBoundToObjectives(codeReview, input.objectivesVersion);
3771
- const securityObjectivesBound = isBoundToObjectives(security, input.objectivesVersion);
3772
- const codeReviewRulingsBound = isBoundToRulings(codeReview, input.rulingOrdinal);
3773
- const securityRulingsBound = isBoundToRulings(security, input.rulingOrdinal);
3774
- if (codeReviewClean && codeReviewBound && codeReviewObjectivesBound && codeReviewRulingsBound && securityClean && securityBound && securityObjectivesBound && securityRulingsBound && mechanicalChecksClean) {
4027
+ const policy = input.policy ?? DEFAULT_REVIEW_POLICY;
4028
+ let codeReviewPolicyEvaluation;
4029
+ let securityPolicyEvaluation;
4030
+ try {
4031
+ codeReviewPolicyEvaluation = evaluateCodeReview(codeReview.findingSeverities, policy);
4032
+ securityPolicyEvaluation = evaluateSecurityReview(security.findingSeverities, policy);
4033
+ } catch (err) {
4034
+ return {
4035
+ verdict: "fail",
4036
+ reason: `a verdict comment carries a finding severity this repository's policy does not recognize: ${err instanceof Error ? err.message : String(err)}`,
4037
+ waived: false
4038
+ };
4039
+ }
4040
+ const codeReviewTextClean = codeReview.value === "APPROVE";
4041
+ const securityTextClean = security.value === "PASS";
4042
+ const codeReviewPolicyClean = codeReviewPolicyEvaluation.outcome === "clean";
4043
+ const securityPolicyClean = securityPolicyEvaluation.outcome === "clean";
4044
+ const codeReviewClean = codeReviewTextClean && codeReviewPolicyClean;
4045
+ const securityClean = securityTextClean && securityPolicyClean;
4046
+ const currentManifest = {
4047
+ headSha: input.headSha,
4048
+ briefHash: input.briefHash ?? null,
4049
+ objectivesVersion: input.objectivesVersion,
4050
+ rulingOrdinal: input.rulingOrdinal,
4051
+ policyDigest: policyDigest(policy)
4052
+ };
4053
+ const codeReviewEchoed = {
4054
+ headSha: codeReview.headSha,
4055
+ briefHash: codeReview.briefHash,
4056
+ objectivesVersion: codeReview.objectivesVersion,
4057
+ rulingOrdinal: codeReview.rulingOrdinal,
4058
+ policyDigest: codeReview.policyDigest
4059
+ };
4060
+ const securityEchoed = {
4061
+ headSha: security.headSha,
4062
+ briefHash: security.briefHash,
4063
+ objectivesVersion: security.objectivesVersion,
4064
+ rulingOrdinal: security.rulingOrdinal,
4065
+ policyDigest: security.policyDigest
4066
+ };
4067
+ const codeReviewBinding = compareManifest(codeReviewEchoed, currentManifest, input.patchIdOf);
4068
+ const securityBinding = compareManifest(securityEchoed, currentManifest, input.patchIdOf);
4069
+ const codeReviewBound = codeReviewBinding.head;
4070
+ const securityBound = securityBinding.head;
4071
+ const codeReviewObjectivesBound = codeReviewBinding.objectivesVersion;
4072
+ const securityObjectivesBound = securityBinding.objectivesVersion;
4073
+ const codeReviewRulingsBound = codeReviewBinding.rulingOrdinal;
4074
+ const securityRulingsBound = securityBinding.rulingOrdinal;
4075
+ if (codeReviewClean && codeReviewBinding.bound && securityClean && securityBinding.bound && mechanicalChecksClean) {
3775
4076
  return {
3776
4077
  verdict: "pass",
3777
4078
  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.`,
@@ -3779,23 +4080,35 @@ function checkReviewGate(input) {
3779
4080
  };
3780
4081
  }
3781
4082
  const problems = [];
3782
- if (!codeReviewClean) {
4083
+ if (!codeReviewTextClean) {
3783
4084
  problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
4085
+ } else if (!codeReviewPolicyClean) {
4086
+ 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`);
3784
4087
  } else if (!codeReviewBound) {
3785
4088
  problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
3786
4089
  } else if (!codeReviewObjectivesBound) {
3787
4090
  problems.push(`the newest code-review verdict was cast against objectives version ${codeReview.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
3788
4091
  } else if (!codeReviewRulingsBound) {
3789
4092
  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`);
4093
+ } else if (!codeReviewBinding.briefHash) {
4094
+ 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"}`);
4095
+ } else if (!codeReviewBinding.policyDigest) {
4096
+ 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}`);
3790
4097
  }
3791
- if (!securityClean) {
4098
+ if (!securityTextClean) {
3792
4099
  problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
4100
+ } else if (!securityPolicyClean) {
4101
+ 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`);
3793
4102
  } else if (!securityBound) {
3794
4103
  problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
3795
4104
  } else if (!securityObjectivesBound) {
3796
4105
  problems.push(`the newest security-review verdict was cast against objectives version ${security.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
3797
4106
  } else if (!securityRulingsBound) {
3798
4107
  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`);
4108
+ } else if (!securityBinding.briefHash) {
4109
+ 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"}`);
4110
+ } else if (!securityBinding.policyDigest) {
4111
+ 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}`);
3799
4112
  }
3800
4113
  if (!mechanicalChecksClean) {
3801
4114
  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(", ")}`);
@@ -4487,42 +4800,45 @@ function checkDispatchReadiness(input) {
4487
4800
  const { trancheSlug, task } = input;
4488
4801
  const taskLabel = `task ${task.id} (tranche ${trancheSlug})`;
4489
4802
  const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
4490
- const blockers = [];
4803
+ const blockerDetails = [];
4804
+ const push = (blockerClass, message) => {
4805
+ blockerDetails.push({ class: blockerClass, message });
4806
+ };
4491
4807
  if (task.issue === null) {
4492
- blockers.push(`dispatch-gate issue-existence: ${taskLabel} has no Issue (#TBD or blank) in the topology — not dispatchable until the Planner cuts the Issue.`);
4808
+ 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.`);
4493
4809
  } else if (input.issue === null) {
4494
- blockers.push(`dispatch-gate issue-existence: ${taskLabel} names Issue #${task.issue}, but it does not resolve to a real GitHub Issue (phantom reference).`);
4810
+ push("issue-existence", `dispatch-gate issue-existence: ${taskLabel} names Issue #${task.issue}, but it does not resolve to a real GitHub Issue (phantom reference).`);
4495
4811
  }
4496
4812
  if (input.issue !== null && !input.issueRationalePass) {
4497
- blockers.push(`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.`);
4813
+ 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.`);
4498
4814
  }
4499
4815
  for (const dep of input.dependsOn) {
4500
4816
  if (isSelfDependency(dep, task, input.issue)) {
4501
4817
  const issueStr = input.issue !== null ? `#${input.issue.number}` : "?";
4502
- blockers.push(`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.`);
4818
+ 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.`);
4503
4819
  continue;
4504
4820
  }
4505
4821
  if (dep.resolved === false) {
4506
- blockers.push(`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.`);
4822
+ 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.`);
4507
4823
  continue;
4508
4824
  }
4509
4825
  if (!dep.merged && !isHandClosedByRecognizedPrincipal(dep, principalAllowlist)) {
4510
4826
  const issueStr = dep.issue !== null ? ` (#${dep.issue})` : "";
4511
- blockers.push(`dispatch-gate depends-on: ${taskLabel} depends on ${dep.id}${issueStr}, whose PR is not merged yet — not dispatchable, it serializes behind it.`);
4827
+ 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.`);
4512
4828
  }
4513
4829
  }
4514
4830
  for (const c of input.conflictsWith) {
4515
4831
  if (c.openOrInFlight) {
4516
4832
  const issueStr = c.issue !== null ? ` (#${c.issue})` : "";
4517
- blockers.push(`dispatch-gate conflicts-with: ${taskLabel} conflicts with ${c.id}${issueStr}, whose PR is open or in-flight — not dispatchable until it merges.`);
4833
+ 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.`);
4518
4834
  }
4519
4835
  }
4520
4836
  for (const proj of input.priorTrancheArchival) {
4521
4837
  if (proj.priorTrancheSlug !== null && !proj.archived) {
4522
- blockers.push(`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.`);
4838
+ 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.`);
4523
4839
  }
4524
4840
  }
4525
- return { ready: blockers.length === 0, blockers };
4841
+ return { ready: blockerDetails.length === 0, blockers: blockerDetails.map((b) => b.message), blockerDetails };
4526
4842
  }
4527
4843
  // ../../packages/aeg-core/src/single-plan-pr.ts
4528
4844
  function trancheSlugFromTopologyPath(path) {
@@ -4624,6 +4940,91 @@ function checkBranchTopology(input) {
4624
4940
  reason: `Branch \`${branch}\` matches topology row \`${taskId}\` in ${topoPath}.`
4625
4941
  };
4626
4942
  }
4943
+ // ../../packages/aeg-core/src/task-tools.ts
4944
+ import { z } from "zod";
4945
+ var TASK_TOOL_ERROR_KINDS = [
4946
+ "validation",
4947
+ "authority",
4948
+ "precondition",
4949
+ "capability",
4950
+ "infrastructure",
4951
+ "cancellation",
4952
+ "timeout",
4953
+ "uncertain_effect"
4954
+ ];
4955
+ var TaskToolErrorSchema = z.object({
4956
+ kind: z.enum(TASK_TOOL_ERROR_KINDS),
4957
+ message: z.string().min(1),
4958
+ detail: z.string().optional()
4959
+ });
4960
+ var TaskToolRefSchema = z.union([
4961
+ z.object({ tranche: z.string().min(1), id: z.string().min(1) }),
4962
+ z.object({ issue: z.number().int().positive() })
4963
+ ]);
4964
+ var MAX_PAGE_LIMIT = 100;
4965
+ var PageRequestSchema = z.object({
4966
+ cursor: z.string().optional(),
4967
+ limit: z.number().int().positive().max(MAX_PAGE_LIMIT).optional()
4968
+ });
4969
+ var FreshnessSchema = z.enum(["fresh", "stale", "unknown"]);
4970
+ var ObservedSchema = z.object({
4971
+ observedAt: z.string(),
4972
+ freshness: FreshnessSchema
4973
+ });
4974
+ var TaskStatusInputSchema = z.object({
4975
+ task: TaskToolRefSchema.optional()
4976
+ }).merge(PageRequestSchema);
4977
+ var TaskStatusItemSchema = z.object({
4978
+ task: TaskToolRefSchema,
4979
+ issue: z.number().int().positive(),
4980
+ pr: z.number().int().positive().nullable(),
4981
+ state: z.string()
4982
+ }).merge(ObservedSchema);
4983
+ var TaskStatusResultSchema = z.object({
4984
+ items: z.array(TaskStatusItemSchema),
4985
+ nextCursor: z.string().nullable()
4986
+ });
4987
+ var RequestedAuthoritySchema = z.enum(["planner", "principal", "operator", "self"]);
4988
+ var EscalationInputsSchema = z.object({
4989
+ task: z.number().int().positive(),
4990
+ round: z.number().int().nonnegative(),
4991
+ head: z.string(),
4992
+ branch: z.string(),
4993
+ prNumber: z.number().int().positive()
4994
+ });
4995
+ var EscalationEvidenceSchema = z.object({
4996
+ round: z.number().int().nonnegative(),
4997
+ reviewer: z.string().nullable(),
4998
+ security: z.string().nullable()
4999
+ });
5000
+ var TaskEscalationReadInputSchema = z.object({
5001
+ task: TaskToolRefSchema
5002
+ }).merge(PageRequestSchema);
5003
+ var TaskEscalationPacketSchema = z.object({
5004
+ reason: z.string(),
5005
+ detail: z.string().nullable(),
5006
+ inputs: EscalationInputsSchema.nullable(),
5007
+ evidence: EscalationEvidenceSchema.nullable(),
5008
+ attemptedRecovery: z.string(),
5009
+ requestedAuthority: RequestedAuthoritySchema,
5010
+ permittedNextActions: z.array(z.string())
5011
+ }).merge(ObservedSchema);
5012
+ var TaskEscalationReadResultSchema = z.object({
5013
+ items: z.array(TaskEscalationPacketSchema),
5014
+ nextCursor: z.string().nullable()
5015
+ }).merge(ObservedSchema);
5016
+ var TaskStartInputSchema = z.object({
5017
+ tranche: z.string().min(1),
5018
+ id: z.string().min(1)
5019
+ });
5020
+ var TaskResumeInputSchema = z.object({
5021
+ task: TaskToolRefSchema
5022
+ });
5023
+ var TaskCancelInputSchema = z.object({
5024
+ task: TaskToolRefSchema,
5025
+ reason: z.string().min(1)
5026
+ });
5027
+ var NoResultSchema = z.never();
4627
5028
  // ../../packages/aeg-core/src/first-push-dispatch-gate.ts
4628
5029
  function parseTaskBranch(branch) {
4629
5030
  const m = /^task\/([^/]+)\/([^/]+)$/.exec(branch);
@@ -4707,7 +5108,6 @@ function decideIssueAssignment(input) {
4707
5108
  };
4708
5109
  }
4709
5110
  // ../../packages/aeg-core/src/test-plan-gate.ts
4710
- var TASK_BRANCH_PATTERN2 = /^task\/[^/]+\/[^/]+$/;
4711
5111
  function evaluateTestPlanGate(body, branch) {
4712
5112
  if (!body) {
4713
5113
  return {
@@ -4720,7 +5120,7 @@ function evaluateTestPlanGate(body, branch) {
4720
5120
  }
4721
5121
  const located = locateTestPlanSection(body);
4722
5122
  if (!located.found) {
4723
- if (TASK_BRANCH_PATTERN2.test(branch)) {
5123
+ if (parseTaskBranchIdentity(branch) !== null) {
4724
5124
  return {
4725
5125
  verdict: "fail",
4726
5126
  messages: [
@@ -4848,7 +5248,7 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
4848
5248
  return findings;
4849
5249
  }
4850
5250
  // ../../packages/aeg-core/src/log/schema.ts
4851
- import { z } from "zod";
5251
+ import { z as z2 } from "zod";
4852
5252
  var ROLE_VALUES = [
4853
5253
  "planner",
4854
5254
  "developer",
@@ -4858,136 +5258,172 @@ var ROLE_VALUES = [
4858
5258
  "archivist",
4859
5259
  "architect"
4860
5260
  ];
4861
- var RoleSchema = z.enum(ROLE_VALUES);
5261
+ var RoleSchema = z2.enum(ROLE_VALUES);
4862
5262
  var HOST_VALUES = ["hook", "ci", "cli", "loop"];
4863
- var HostSchema = z.enum(HOST_VALUES);
5263
+ var HostSchema = z2.enum(HOST_VALUES);
4864
5264
  var RUN_ID_PATTERN = /^[A-Za-z0-9_.-]{1,128}$/;
4865
- var HeaderMetaSchema = z.object({
4866
- schema: z.literal(1),
4867
- ts: z.string(),
4868
- run_id: z.string().regex(RUN_ID_PATTERN),
4869
- seq: z.number().int().nonnegative(),
4870
- repo: z.string().nullable(),
4871
- vinaya: z.string(),
4872
- doctrine: z.string(),
5265
+ var headerMetaCore = {
5266
+ ts: z2.string(),
5267
+ run_id: z2.string().regex(RUN_ID_PATTERN),
5268
+ seq: z2.number().int().nonnegative(),
5269
+ repo: z2.string().nullable(),
5270
+ vinaya: z2.string(),
5271
+ doctrine: z2.string(),
4873
5272
  host: HostSchema,
4874
- machine: z.string()
5273
+ machine: z2.string()
5274
+ };
5275
+ var HeaderMetaV1Schema = z2.object({
5276
+ schema: z2.literal(1),
5277
+ ...headerMetaCore
5278
+ }).strict();
5279
+ var LineageSchema = z2.object({
5280
+ run: z2.string().nullable(),
5281
+ attempt: z2.number().int().nullable(),
5282
+ parent: z2.string().nullable()
4875
5283
  }).strict();
4876
- var SubjectSchema = z.object({
4877
- issue: z.number().int().nullable(),
4878
- pr: z.number().int().optional(),
4879
- sha: z.string().optional(),
4880
- role: z.union([RoleSchema, z.literal("unattributed")]),
4881
- round: z.number().int().optional(),
4882
- objectives_version: z.string().optional()
5284
+ var InputVersionsSchema = z2.object({
5285
+ objectives_version: z2.string().nullable(),
5286
+ brief_hash: z2.string().nullable(),
5287
+ ruling_ordinal: z2.number().int().nullable(),
5288
+ policy_digest: z2.string().nullable()
4883
5289
  }).strict();
4884
- var HeaderSchema = z.object({
5290
+ var ProvenanceSchema = z2.enum(["parent_attributed", "env_correlated", "self_reported", "unavailable"]);
5291
+ var HeaderMetaV2Schema = z2.object({
5292
+ schema: z2.literal(2),
5293
+ ...headerMetaCore,
5294
+ event_id: z2.string().min(1),
5295
+ process_id: z2.string().min(1),
5296
+ actor_id: z2.string().nullable(),
5297
+ lineage: LineageSchema,
5298
+ input_versions: InputVersionsSchema,
5299
+ provenance: ProvenanceSchema
5300
+ }).strict();
5301
+ var HeaderMetaSchema = z2.discriminatedUnion("schema", [HeaderMetaV1Schema, HeaderMetaV2Schema]);
5302
+ var SubjectSchema = z2.object({
5303
+ issue: z2.number().int().nullable(),
5304
+ pr: z2.number().int().optional(),
5305
+ sha: z2.string().optional(),
5306
+ role: z2.union([RoleSchema, z2.literal("unattributed")]),
5307
+ round: z2.number().int().optional(),
5308
+ objectives_version: z2.string().optional()
5309
+ }).strict();
5310
+ var HeaderSchema = z2.object({
4885
5311
  meta: HeaderMetaSchema,
4886
5312
  subject: SubjectSchema
4887
5313
  }).strict();
4888
5314
  var envelopeTail = {
4889
- duration_ms: z.number().nonnegative().optional(),
4890
- payload: z.object({}).strict()
5315
+ duration_ms: z2.number().nonnegative().optional(),
5316
+ payload: z2.object({}).strict()
4891
5317
  };
4892
- var DispatchOutcomeSchema = z.discriminatedUnion("type", [
4893
- z.object({ type: z.literal("pr_opened"), pr: z.number().int(), head: z.string() }).strict(),
4894
- z.object({
4895
- type: z.literal("round_pushed"),
4896
- pr: z.number().int(),
4897
- head: z.string(),
4898
- comment_id: z.number().int()
5318
+ var ReviewFindingSchema = z2.object({
5319
+ id: z2.string(),
5320
+ severity: z2.string(),
5321
+ state: z2.string().optional(),
5322
+ severity_scale: z2.string().optional(),
5323
+ policy_treatment: z2.enum(["blocking", "non_blocking", "unavailable"]).optional(),
5324
+ confidence: z2.number().min(0).max(1).optional(),
5325
+ confidence_scale: z2.string().optional(),
5326
+ confidence_source: z2.string().optional()
5327
+ }).strict();
5328
+ var DispatchOutcomeSchema = z2.discriminatedUnion("type", [
5329
+ z2.object({ type: z2.literal("pr_opened"), pr: z2.number().int(), head: z2.string() }).strict(),
5330
+ z2.object({
5331
+ type: z2.literal("round_pushed"),
5332
+ pr: z2.number().int(),
5333
+ head: z2.string(),
5334
+ comment_id: z2.number().int()
4899
5335
  }).strict(),
4900
- z.object({
4901
- type: z.literal("verdict"),
4902
- verdict: z.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
4903
- head: z.string(),
4904
- comment_id: z.number().int(),
4905
- objectives: z.array(z.object({ id: z.string(), met: z.boolean() }).strict()),
4906
- findings: z.array(z.object({ id: z.string(), severity: z.string(), state: z.string().optional() }).strict())
5336
+ z2.object({
5337
+ type: z2.literal("verdict"),
5338
+ verdict: z2.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
5339
+ head: z2.string(),
5340
+ comment_id: z2.number().int(),
5341
+ objectives: z2.array(z2.object({ id: z2.string(), met: z2.boolean() }).strict()),
5342
+ findings: z2.array(ReviewFindingSchema)
4907
5343
  }).strict(),
4908
- z.object({
4909
- type: z.literal("escalation"),
4910
- class: z.enum(["authority", "strategy", "product"]),
4911
- comment_id: z.number().int()
5344
+ z2.object({
5345
+ type: z2.literal("escalation"),
5346
+ class: z2.enum(["authority", "strategy", "product"]),
5347
+ comment_id: z2.number().int()
4912
5348
  }).strict(),
4913
- z.object({ type: z.literal("brief"), comment_id: z.number().int(), hash: z.string() }).strict(),
4914
- z.object({ type: z.literal("plan"), issues: z.array(z.number().int()) }).strict(),
4915
- z.object({ type: z.literal("archive"), provenance_comment_id: z.number().int() }).strict()
5349
+ z2.object({ type: z2.literal("brief"), comment_id: z2.number().int(), hash: z2.string() }).strict(),
5350
+ z2.object({ type: z2.literal("plan"), issues: z2.array(z2.number().int()) }).strict(),
5351
+ z2.object({ type: z2.literal("archive"), provenance_comment_id: z2.number().int() }).strict()
4916
5352
  ]);
4917
5353
  var dispatchShared = {
4918
5354
  meta: HeaderMetaSchema,
4919
5355
  subject: SubjectSchema,
4920
- kind: z.literal("dispatch"),
5356
+ kind: z2.literal("dispatch"),
4921
5357
  ...envelopeTail,
4922
5358
  target_role: RoleSchema,
4923
- model: z.string(),
4924
- round: z.number().int().optional(),
4925
- effect_id: z.string()
5359
+ model: z2.string(),
5360
+ round: z2.number().int().optional(),
5361
+ effect_id: z2.string()
4926
5362
  };
4927
- var dispatchUsageField = z.object({ input: z.number().nonnegative(), output: z.number().nonnegative() }).strict().nullable();
4928
- var DispatchEventSchema = z.discriminatedUnion("event", [
4929
- z.object({ ...dispatchShared, event: z.literal("dispatched"), prompt_hash: z.string() }).strict(),
4930
- z.object({
5363
+ var dispatchUsageField = z2.object({ input: z2.number().nonnegative(), output: z2.number().nonnegative() }).strict().nullable();
5364
+ var DispatchEventSchema = z2.discriminatedUnion("event", [
5365
+ z2.object({ ...dispatchShared, event: z2.literal("dispatched"), prompt_hash: z2.string() }).strict(),
5366
+ z2.object({
4931
5367
  ...dispatchShared,
4932
- event: z.literal("outcome_received"),
5368
+ event: z2.literal("outcome_received"),
4933
5369
  outcome: DispatchOutcomeSchema,
4934
5370
  usage: dispatchUsageField
4935
5371
  }).strict(),
4936
- z.object({
5372
+ z2.object({
4937
5373
  ...dispatchShared,
4938
- event: z.literal("dispatch_failed"),
4939
- reason: z.enum(["timeout", "crash", "refused", "unattributed_write"]),
5374
+ event: z2.literal("dispatch_failed"),
5375
+ reason: z2.enum(["timeout", "crash", "refused", "unattributed_write"]),
4940
5376
  usage: dispatchUsageField
4941
5377
  }).strict()
4942
5378
  ]);
4943
5379
  var loopShared = {
4944
5380
  meta: HeaderMetaSchema,
4945
5381
  subject: SubjectSchema,
4946
- kind: z.literal("dev_review_loop"),
5382
+ kind: z2.literal("dev_review_loop"),
4947
5383
  ...envelopeTail,
4948
- loop_id: z.string()
5384
+ loop_id: z2.string()
4949
5385
  };
4950
- var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
4951
- z.object({
5386
+ var DevReviewLoopEventSchema = z2.discriminatedUnion("event", [
5387
+ z2.object({
4952
5388
  ...loopShared,
4953
- event: z.literal("loop_started"),
4954
- task: z.number().int(),
4955
- policy: z.object({
4956
- max_rounds: z.number().int().nonnegative(),
4957
- reviewers: z.array(RoleSchema),
4958
- models: z.record(RoleSchema, z.string())
5389
+ event: z2.literal("loop_started"),
5390
+ task: z2.number().int(),
5391
+ policy: z2.object({
5392
+ max_rounds: z2.number().int().nonnegative(),
5393
+ reviewers: z2.array(RoleSchema),
5394
+ models: z2.record(RoleSchema, z2.string())
4959
5395
  }).strict()
4960
5396
  }).strict(),
4961
- z.object({ ...loopShared, event: z.literal("round_started"), round: z.number().int(), base_head: z.string() }).strict(),
4962
- z.object({
5397
+ z2.object({ ...loopShared, event: z2.literal("round_started"), round: z2.number().int(), base_head: z2.string() }).strict(),
5398
+ z2.object({
4963
5399
  ...loopShared,
4964
- event: z.literal("gate_result_read"),
4965
- round: z.number().int(),
4966
- head: z.string(),
4967
- green: z.boolean()
5400
+ event: z2.literal("gate_result_read"),
5401
+ round: z2.number().int(),
5402
+ head: z2.string(),
5403
+ green: z2.boolean()
4968
5404
  }).strict(),
4969
- z.object({
5405
+ z2.object({
4970
5406
  ...loopShared,
4971
- event: z.literal("verdicts_read"),
4972
- round: z.number().int(),
4973
- head: z.string(),
4974
- all_approve: z.boolean(),
4975
- blockers: z.number().int().nonnegative()
5407
+ event: z2.literal("verdicts_read"),
5408
+ round: z2.number().int(),
5409
+ head: z2.string(),
5410
+ all_approve: z2.boolean(),
5411
+ blockers: z2.number().int().nonnegative()
4976
5412
  }).strict(),
4977
- z.object({
5413
+ z2.object({
4978
5414
  ...loopShared,
4979
- event: z.literal("findings_compared"),
4980
- round: z.number().int(),
4981
- open: z.array(z.string()),
4982
- resolved: z.array(z.string()),
4983
- new: z.array(z.string()),
4984
- recurring: z.array(z.string())
5415
+ event: z2.literal("findings_compared"),
5416
+ round: z2.number().int(),
5417
+ open: z2.array(z2.string()),
5418
+ resolved: z2.array(z2.string()),
5419
+ new: z2.array(z2.string()),
5420
+ recurring: z2.array(z2.string())
4985
5421
  }).strict(),
4986
- z.object({
5422
+ z2.object({
4987
5423
  ...loopShared,
4988
- event: z.literal("stop_condition_met"),
4989
- round: z.number().int(),
4990
- condition: z.enum([
5424
+ event: z2.literal("stop_condition_met"),
5425
+ round: z2.number().int(),
5426
+ condition: z2.enum([
4991
5427
  "green",
4992
5428
  "max_rounds",
4993
5429
  "no_progress",
@@ -4997,42 +5433,49 @@ var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
4997
5433
  "reappearance"
4998
5434
  ])
4999
5435
  }).strict(),
5000
- z.object({
5436
+ z2.object({
5437
+ ...loopShared,
5438
+ event: z2.literal("paused"),
5439
+ round: z2.number().int(),
5440
+ reason: z2.enum(["escalation", "principal_item", "refreeze_needed"])
5441
+ }).strict(),
5442
+ z2.object({
5001
5443
  ...loopShared,
5002
- event: z.literal("paused"),
5003
- round: z.number().int(),
5004
- reason: z.enum(["escalation", "principal_item", "refreeze_needed"])
5444
+ event: z2.literal("resumed"),
5445
+ round: z2.number().int(),
5446
+ by: z2.literal("principal")
5005
5447
  }).strict(),
5006
- z.object({
5448
+ z2.object({
5007
5449
  ...loopShared,
5008
- event: z.literal("resumed"),
5009
- round: z.number().int(),
5010
- by: z.literal("principal")
5450
+ event: z2.literal("unpushed_work_resume"),
5451
+ round: z2.number().int(),
5452
+ branch: z2.string(),
5453
+ detail: z2.string()
5011
5454
  }).strict(),
5012
- z.object({
5455
+ z2.object({
5013
5456
  ...loopShared,
5014
- event: z.literal("round_ended"),
5015
- round: z.number().int(),
5016
- base_head: z.string(),
5017
- head: z.string(),
5018
- files_changed: z.number().int().nonnegative(),
5019
- insertions: z.number().int().nonnegative(),
5020
- deletions: z.number().int().nonnegative(),
5021
- wall_ms: z.number().nonnegative(),
5022
- outcome: z.enum(["green", "changes_requested", "escalated"])
5457
+ event: z2.literal("round_ended"),
5458
+ round: z2.number().int(),
5459
+ base_head: z2.string(),
5460
+ head: z2.string(),
5461
+ files_changed: z2.number().int().nonnegative(),
5462
+ insertions: z2.number().int().nonnegative(),
5463
+ deletions: z2.number().int().nonnegative(),
5464
+ wall_ms: z2.number().nonnegative(),
5465
+ outcome: z2.enum(["green", "changes_requested", "escalated"])
5023
5466
  }).strict(),
5024
- z.object({
5467
+ z2.object({
5025
5468
  ...loopShared,
5026
- event: z.literal("journal_finalized"),
5027
- rounds: z.number().int().nonnegative(),
5028
- total_wall_ms: z.number().nonnegative(),
5029
- time_to_green_ms: z.number().nonnegative().nullable(),
5030
- files_changed_total: z.number().int().nonnegative(),
5031
- final_head: z.string(),
5032
- result: z.enum(["merged_ready", "stopped"])
5469
+ event: z2.literal("journal_finalized"),
5470
+ rounds: z2.number().int().nonnegative(),
5471
+ total_wall_ms: z2.number().nonnegative(),
5472
+ time_to_green_ms: z2.number().nonnegative().nullable(),
5473
+ files_changed_total: z2.number().int().nonnegative(),
5474
+ final_head: z2.string(),
5475
+ result: z2.enum(["merged_ready", "stopped"])
5033
5476
  }).strict()
5034
5477
  ]);
5035
- var ForgeOpSchema = z.enum([
5478
+ var ForgeOpSchema = z2.enum([
5036
5479
  "pr.create",
5037
5480
  "pr.comment",
5038
5481
  "pr.body.replace",
@@ -5046,54 +5489,242 @@ var ForgeOpSchema = z.enum([
5046
5489
  "label.add",
5047
5490
  "label.remove"
5048
5491
  ]);
5049
- var ForgeWriteTargetSchema = z.object({
5050
- issue: z.number().int().optional(),
5051
- pr: z.number().int().optional()
5492
+ var ForgeWriteTargetSchema = z2.object({
5493
+ issue: z2.number().int().optional(),
5494
+ pr: z2.number().int().optional()
5052
5495
  }).strict();
5053
5496
  var forgeWriteShared = {
5054
5497
  meta: HeaderMetaSchema,
5055
5498
  subject: SubjectSchema,
5056
- kind: z.literal("forge_write"),
5499
+ kind: z2.literal("forge_write"),
5057
5500
  ...envelopeTail,
5058
5501
  op: ForgeOpSchema,
5059
5502
  target: ForgeWriteTargetSchema
5060
5503
  };
5061
- var ForgeWriteEventSchema = z.discriminatedUnion("event", [
5062
- z.object({ ...forgeWriteShared, event: z.literal("validated") }).strict(),
5063
- z.object({ ...forgeWriteShared, event: z.literal("refused"), reason: z.string() }).strict(),
5064
- z.object({ ...forgeWriteShared, event: z.literal("written"), comment_ids: z.array(z.string()) }).strict()
5504
+ var ForgeWriteEventSchema = z2.discriminatedUnion("event", [
5505
+ z2.object({ ...forgeWriteShared, event: z2.literal("validated") }).strict(),
5506
+ z2.object({ ...forgeWriteShared, event: z2.literal("refused"), reason: z2.string() }).strict(),
5507
+ z2.object({ ...forgeWriteShared, event: z2.literal("written"), comment_ids: z2.array(z2.string()) }).strict()
5508
+ ]);
5509
+ var GateOutcomeSchema = z2.enum([
5510
+ "pass",
5511
+ "fail",
5512
+ "wait",
5513
+ "skip",
5514
+ "invalid_input",
5515
+ "unavailable_dependency",
5516
+ "timeout",
5517
+ "cancelled"
5518
+ ]);
5519
+ var gateShared = {
5520
+ meta: HeaderMetaSchema,
5521
+ subject: SubjectSchema,
5522
+ kind: z2.literal("gate"),
5523
+ ...envelopeTail,
5524
+ check: z2.string(),
5525
+ check_version: z2.string().nullable(),
5526
+ policy_version: z2.string().nullable(),
5527
+ input_fingerprint: z2.string().nullable()
5528
+ };
5529
+ var GateEventSchema = z2.discriminatedUnion("event", [
5530
+ z2.object({
5531
+ ...gateShared,
5532
+ event: z2.literal("checked"),
5533
+ outcome: GateOutcomeSchema,
5534
+ reason: z2.string().optional()
5535
+ }).strict()
5536
+ ]);
5537
+ var OperationResultSchema = z2.enum(["ok", "error", "refused", "timeout", "cancelled", "unavailable"]);
5538
+ var operationShared = {
5539
+ meta: HeaderMetaSchema,
5540
+ subject: SubjectSchema,
5541
+ kind: z2.literal("operation"),
5542
+ ...envelopeTail,
5543
+ operation: z2.string(),
5544
+ target: z2.string().nullable()
5545
+ };
5546
+ var OperationEventSchema = z2.discriminatedUnion("event", [
5547
+ z2.object({
5548
+ ...operationShared,
5549
+ event: z2.literal("completed"),
5550
+ result: OperationResultSchema,
5551
+ error_class: z2.string().nullable()
5552
+ }).strict()
5065
5553
  ]);
5066
- var LogEventSchema = z.union([DispatchEventSchema, DevReviewLoopEventSchema, ForgeWriteEventSchema]);
5554
+ var UsageUnitsSchema = z2.object({
5555
+ input: z2.number().nonnegative().nullable(),
5556
+ output: z2.number().nonnegative().nullable(),
5557
+ cache: z2.number().nonnegative().nullable()
5558
+ }).strict();
5559
+ var usageShared = {
5560
+ meta: HeaderMetaSchema,
5561
+ subject: SubjectSchema,
5562
+ kind: z2.literal("usage"),
5563
+ ...envelopeTail,
5564
+ model: z2.string().nullable(),
5565
+ source: z2.string(),
5566
+ semantics: z2.enum(["cumulative", "delta"])
5567
+ };
5568
+ var UsageEventSchema = z2.discriminatedUnion("event", [
5569
+ z2.object({
5570
+ ...usageShared,
5571
+ event: z2.literal("observed"),
5572
+ units: UsageUnitsSchema,
5573
+ unknown_reason: z2.string().nullable()
5574
+ }).strict()
5575
+ ]);
5576
+ var RoleAttemptOutcomeSchema = z2.enum([
5577
+ "completed",
5578
+ "incomplete",
5579
+ "infrastructure_failed",
5580
+ "cancelled",
5581
+ "timed_out",
5582
+ "capability_refused"
5583
+ ]);
5584
+ var roleAttemptShared = {
5585
+ meta: HeaderMetaSchema,
5586
+ subject: SubjectSchema,
5587
+ kind: z2.literal("role_attempt"),
5588
+ ...envelopeTail,
5589
+ actor: z2.string().nullable(),
5590
+ attempt: z2.number().int().nullable()
5591
+ };
5592
+ var RoleAttemptEventSchema = z2.discriminatedUnion("event", [
5593
+ z2.object({
5594
+ ...roleAttemptShared,
5595
+ event: z2.literal("attempted"),
5596
+ outcome: RoleAttemptOutcomeSchema,
5597
+ usage: dispatchUsageField
5598
+ }).strict()
5599
+ ]);
5600
+ var handoffShared = {
5601
+ meta: HeaderMetaSchema,
5602
+ subject: SubjectSchema,
5603
+ kind: z2.literal("handoff"),
5604
+ ...envelopeTail,
5605
+ class: z2.enum(["authority", "strategy", "product"]),
5606
+ reason: z2.string()
5607
+ };
5608
+ var HandoffEventSchema = z2.discriminatedUnion("event", [
5609
+ z2.object({
5610
+ ...handoffShared,
5611
+ event: z2.literal("raised"),
5612
+ requested_decision: z2.string().nullable()
5613
+ }).strict(),
5614
+ z2.object({
5615
+ ...handoffShared,
5616
+ event: z2.literal("resolved"),
5617
+ resolution: z2.string().nullable(),
5618
+ resolved_by: z2.string().nullable()
5619
+ }).strict()
5620
+ ]);
5621
+ var EffectTargetSchema = z2.object({
5622
+ kind: z2.string(),
5623
+ ref: z2.string()
5624
+ }).strict();
5625
+ var effectShared = {
5626
+ meta: HeaderMetaSchema,
5627
+ subject: SubjectSchema,
5628
+ kind: z2.literal("effect"),
5629
+ ...envelopeTail,
5630
+ effect_id: z2.string(),
5631
+ target: EffectTargetSchema
5632
+ };
5633
+ var EffectEventSchema = z2.discriminatedUnion("event", [
5634
+ z2.object({ ...effectShared, event: z2.literal("attempted") }).strict(),
5635
+ z2.object({ ...effectShared, event: z2.literal("observed"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict(),
5636
+ z2.object({ ...effectShared, event: z2.literal("verified"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict()
5637
+ ]);
5638
+ var LogEventSchema = z2.union([
5639
+ DispatchEventSchema,
5640
+ DevReviewLoopEventSchema,
5641
+ ForgeWriteEventSchema,
5642
+ GateEventSchema,
5643
+ OperationEventSchema,
5644
+ UsageEventSchema,
5645
+ RoleAttemptEventSchema,
5646
+ HandoffEventSchema,
5647
+ EffectEventSchema
5648
+ ]);
5649
+ // ../../packages/aeg-core/src/dev-review-loop/journal-reconstruction.ts
5650
+ var STOPPED_CONDITIONS = new Set(["confidence", "reappearance", "no_progress", "max_rounds"]);
5651
+ // ../../packages/aeg-core/src/control-store/records.ts
5652
+ import { z as z3 } from "zod";
5653
+ var isoTimestamp = z3.string().min(1);
5654
+ var taskId = z3.number().int().positive();
5655
+ var epochNumber = z3.number().int().nonnegative();
5656
+ var RunRecordSchema = z3.object({
5657
+ version: z3.literal(1),
5658
+ kind: z3.literal("run"),
5659
+ task: taskId,
5660
+ runId: z3.string().min(1),
5661
+ pid: z3.number().int().positive(),
5662
+ host: z3.string().min(1),
5663
+ startedAt: isoTimestamp
5664
+ }).strict();
5665
+ var InputRecordSchema = z3.object({
5666
+ version: z3.literal(1),
5667
+ kind: z3.literal("input"),
5668
+ task: taskId,
5669
+ runId: z3.string().min(1),
5670
+ source: z3.union([z3.literal("fresh"), z3.literal("resume")]),
5671
+ pr: z3.number().int().positive().nullable(),
5672
+ round: z3.number().int().nonnegative(),
5673
+ recordedAt: isoTimestamp
5674
+ }).strict();
5675
+ var OwnershipRecordSchema = z3.object({
5676
+ version: z3.literal(1),
5677
+ kind: z3.literal("ownership"),
5678
+ task: taskId,
5679
+ epoch: epochNumber,
5680
+ ownerId: z3.string().min(1),
5681
+ pid: z3.number().int().positive(),
5682
+ host: z3.string().min(1),
5683
+ acquiredAt: isoTimestamp
5684
+ }).strict();
5685
+ var TransitionRecordSchema = z3.object({
5686
+ version: z3.literal(1),
5687
+ kind: z3.literal("transition"),
5688
+ task: taskId,
5689
+ epoch: epochNumber,
5690
+ seq: z3.number().int().nonnegative(),
5691
+ from: z3.string().min(1),
5692
+ to: z3.string().min(1),
5693
+ detail: z3.string().optional(),
5694
+ at: isoTimestamp
5695
+ }).strict();
5067
5696
  // src/lib/diff-evidence.ts
5068
- import { execFileSync as execFileSync4 } from "node:child_process";
5069
- import { join as join2, relative, resolve as resolve2 } from "node:path";
5697
+ import { execFileSync as execFileSync5 } from "node:child_process";
5698
+ import { join as join4, relative, resolve as resolve2 } from "node:path";
5070
5699
 
5071
5700
  // src/lib/config.ts
5072
5701
  import { execFileSync as execFileSync2 } from "node:child_process";
5073
5702
  import { existsSync, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "node:fs";
5074
5703
  import { homedir } from "node:os";
5075
5704
  import { dirname, join, resolve } from "node:path";
5076
- import { z as z2 } from "zod";
5705
+ import { z as z4 } from "zod";
5077
5706
 
5078
5707
  // src/lib/agent-vendors.ts
5079
5708
  var AGENT_VENDORS = ["skills", "claude", "gemini"];
5080
5709
 
5081
5710
  // src/lib/config.ts
5082
- var EnvEntrySchema = z2.union([
5083
- z2.literal(true),
5084
- z2.object({ optional: z2.literal(true) }),
5085
- z2.object({ anyOf: z2.array(z2.string()).min(2) }),
5086
- z2.string()
5711
+ var EnvEntrySchema = z4.union([
5712
+ z4.literal(true),
5713
+ z4.object({ optional: z4.literal(true) }),
5714
+ z4.object({ anyOf: z4.array(z4.string()).min(2) }),
5715
+ z4.string()
5087
5716
  ]);
5088
- var CheckEntrySchema = z2.object({
5089
- run: z2.string(),
5090
- scope: z2.enum(["diff", "full"]),
5091
- include: z2.array(z2.string()).optional(),
5092
- args: z2.array(z2.string()).optional(),
5093
- timeoutMs: z2.number().optional(),
5094
- env: z2.record(z2.string(), EnvEntrySchema).optional(),
5095
- requiresOpenPr: z2.boolean().optional(),
5096
- ownWorkflow: z2.boolean().optional()
5717
+ var CheckEntrySchema = z4.object({
5718
+ run: z4.string(),
5719
+ scope: z4.enum(["diff", "full"]),
5720
+ include: z4.array(z4.string()).optional(),
5721
+ args: z4.array(z4.string()).optional(),
5722
+ timeoutMs: z4.number().optional(),
5723
+ env: z4.record(z4.string(), EnvEntrySchema).optional(),
5724
+ requiresOpenPr: z4.boolean().optional(),
5725
+ ownWorkflow: z4.boolean().optional(),
5726
+ principalOwed: z4.literal(true).optional(),
5727
+ validates: z4.enum(["body", "issue"]).optional()
5097
5728
  }).superRefine((entry2, ctx) => {
5098
5729
  if (!entry2.env)
5099
5730
  return;
@@ -5103,25 +5734,26 @@ var CheckEntrySchema = z2.object({
5103
5734
  const members = value.anyOf;
5104
5735
  if (new Set(members).size !== members.length) {
5105
5736
  ctx.addIssue({
5106
- code: z2.ZodIssueCode.custom,
5737
+ code: z4.ZodIssueCode.custom,
5107
5738
  message: `env.${key}.anyOf has duplicate members`,
5108
5739
  path: ["env", key, "anyOf"]
5109
5740
  });
5110
5741
  }
5111
5742
  if (!members.includes(key)) {
5112
5743
  ctx.addIssue({
5113
- code: z2.ZodIssueCode.custom,
5744
+ code: z4.ZodIssueCode.custom,
5114
5745
  message: `env.${key}.anyOf must include "${key}" itself as a member`,
5115
5746
  path: ["env", key, "anyOf"]
5116
5747
  });
5117
5748
  }
5118
5749
  }
5119
5750
  });
5120
- var RoleEntrySchema = z2.object({
5121
- contract: z2.string().refine((p) => p.includes("/"), {
5751
+ var RoleEntrySchema = z4.object({
5752
+ contract: z4.string().refine((p) => p.includes("/"), {
5122
5753
  message: 'must be a path (contain at least one "/"), not a bare filename'
5123
5754
  })
5124
5755
  });
5756
+ var MAX_REPORT_COMMAND_TIMEOUT_MS = 3600000;
5125
5757
  var BRIEF_BUILTINS = [
5126
5758
  "tier",
5127
5759
  "testPlan",
@@ -5141,17 +5773,17 @@ var BRIEF_BUILTINS = [
5141
5773
  "briefSections",
5142
5774
  "milestoneShape"
5143
5775
  ];
5144
- var BriefSectionSchema = z2.union([
5145
- z2.object({ builtin: z2.enum(BRIEF_BUILTINS) }),
5146
- z2.object({ heading: z2.string().min(1), name: z2.string().optional() }),
5147
- z2.object({ field: z2.string().min(1), name: z2.string().optional() }),
5148
- z2.object({ phrase: z2.string().min(1), name: z2.string().optional() })
5776
+ var BriefSectionSchema = z4.union([
5777
+ z4.object({ builtin: z4.enum(BRIEF_BUILTINS) }),
5778
+ z4.object({ heading: z4.string().min(1), name: z4.string().optional() }),
5779
+ z4.object({ field: z4.string().min(1), name: z4.string().optional() }),
5780
+ z4.object({ phrase: z4.string().min(1), name: z4.string().optional() })
5149
5781
  ]);
5150
- var BriefSchemaSchema = z2.object({
5151
- pr: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
5152
- issue: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
5153
- milestone: z2.object({ sections: z2.array(BriefSectionSchema) }).optional(),
5154
- ack: z2.array(z2.enum(BRIEF_BUILTINS)).optional()
5782
+ var BriefSchemaSchema = z4.object({
5783
+ pr: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
5784
+ issue: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
5785
+ milestone: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
5786
+ ack: z4.array(z4.enum(BRIEF_BUILTINS)).optional()
5155
5787
  });
5156
5788
  function isSafeRepoRelPath(p) {
5157
5789
  if (p.length === 0)
@@ -5160,7 +5792,7 @@ function isSafeRepoRelPath(p) {
5160
5792
  return false;
5161
5793
  return p.split(/[\\/]/).every((seg) => seg !== ".." && seg !== "");
5162
5794
  }
5163
- var SafeRepoRelPath = z2.string().refine(isSafeRepoRelPath, {
5795
+ var SafeRepoRelPath = z4.string().refine(isSafeRepoRelPath, {
5164
5796
  message: "must be a repo-root-relative path with no `..` segment or absolute root"
5165
5797
  });
5166
5798
  var CANONICAL_HOOK_BLOCK_PREFIXES = [".git/", ".husky/", ".vinaya/hooks/", ".claude/hooks/"];
@@ -5170,22 +5802,22 @@ function isCanonicalHookBlockPath(p) {
5170
5802
  var ManagedHookBlockPath = SafeRepoRelPath.refine(isCanonicalHookBlockPath, {
5171
5803
  message: `must start with one of ${CANONICAL_HOOK_BLOCK_PREFIXES.join(", ")} (byte-exact, case-sensitive)`
5172
5804
  });
5173
- var ManagedBlockRecordSchema = z2.object({
5805
+ var ManagedBlockRecordSchema = z4.object({
5174
5806
  path: ManagedHookBlockPath,
5175
- marker: z2.string(),
5176
- comment: z2.enum(["hash", "html"])
5807
+ marker: z4.string(),
5808
+ comment: z4.enum(["hash", "html"])
5177
5809
  });
5178
- var ManagedManifestSchema = z2.object({
5179
- version: z2.number().int().positive(),
5180
- files: z2.array(SafeRepoRelPath),
5181
- blocks: z2.array(ManagedBlockRecordSchema),
5182
- labels: z2.array(z2.string()),
5183
- agents: z2.array(z2.enum(AGENT_VENDORS)).optional()
5810
+ var ManagedManifestSchema = z4.object({
5811
+ version: z4.number().int().positive(),
5812
+ files: z4.array(SafeRepoRelPath),
5813
+ blocks: z4.array(ManagedBlockRecordSchema),
5814
+ labels: z4.array(z4.string()),
5815
+ agents: z4.array(z4.enum(AGENT_VENDORS)).optional()
5184
5816
  });
5185
- var ProjectEntrySchema = z2.object({
5186
- name: z2.string().min(1),
5187
- description: z2.string().min(1).optional(),
5188
- path: z2.string().min(1).optional()
5817
+ var ProjectEntrySchema = z4.object({
5818
+ name: z4.string().min(1),
5819
+ description: z4.string().min(1).optional(),
5820
+ path: z4.string().min(1).optional()
5189
5821
  });
5190
5822
  function parseTokensCollectDeclaration(value) {
5191
5823
  const m = value.trim().match(/^(\S+)\s+(\S+)$/);
@@ -5196,34 +5828,55 @@ function parseTokensCollectDeclaration(value) {
5196
5828
  return null;
5197
5829
  return { interpreter, script };
5198
5830
  }
5199
- var VinayaConfigSchema = z2.object({
5200
- rings: z2.object({
5201
- ring1_forgeWriteInterception: z2.boolean(),
5202
- ring2_asyncAudits: z2.boolean()
5831
+ var VinayaConfigSchema = z4.object({
5832
+ rings: z4.object({
5833
+ ring1_forgeWriteInterception: z4.boolean(),
5834
+ ring2_asyncAudits: z4.boolean()
5203
5835
  }).optional(),
5204
- checks: z2.record(z2.string(), CheckEntrySchema).optional(),
5205
- roles: z2.record(z2.string(), RoleEntrySchema).optional(),
5836
+ checks: z4.record(z4.string(), CheckEntrySchema).optional(),
5837
+ roles: z4.record(z4.string(), RoleEntrySchema).optional(),
5206
5838
  briefSchema: BriefSchemaSchema.optional(),
5207
5839
  managed: ManagedManifestSchema.optional(),
5208
- principals: z2.array(z2.string()).min(1).optional(),
5209
- releaseActor: z2.string().min(1).optional(),
5210
- ci: z2.object({ setup: z2.string().min(1) }).optional(),
5211
- tokens: z2.object({
5212
- collect: z2.string().min(1).refine((v) => parseTokensCollectDeclaration(v) !== null, {
5840
+ principals: z4.array(z4.string()).min(1).optional(),
5841
+ releaseActor: z4.string().min(1).optional(),
5842
+ ci: z4.object({ setup: z4.string().min(1) }).optional(),
5843
+ tokens: z4.object({
5844
+ collect: z4.string().min(1).refine((v) => parseTokensCollectDeclaration(v) !== null, {
5213
5845
  message: 'tokens.collect must be exactly "<interpreter> <repo-relative-script-path>" — two whitespace-separated tokens, no flags, no shell syntax, no quoting'
5214
5846
  })
5215
5847
  }).optional(),
5216
- blastRadius: z2.object({ extraDomains: z2.array(z2.string()).optional() }).optional(),
5217
- proseGates: z2.object({
5218
- doctrineRoot: z2.string().min(1).optional(),
5219
- readerFacingPrefix: z2.string().min(1).optional(),
5220
- readerFacingSuffix: z2.string().min(1).optional(),
5221
- legacySlugDir: z2.string().min(1).optional()
5848
+ blastRadius: z4.object({ extraDomains: z4.array(z4.string()).optional() }).optional(),
5849
+ proseGates: z4.object({
5850
+ doctrineRoot: z4.string().min(1).optional(),
5851
+ readerFacingPrefix: z4.string().min(1).optional(),
5852
+ readerFacingSuffix: z4.string().min(1).optional(),
5853
+ legacySlugDir: z4.string().min(1).optional()
5222
5854
  }).optional(),
5223
- projects: z2.array(ProjectEntrySchema).optional(),
5224
- dispatch: z2.object({
5225
- timeoutMs: z2.number().int().positive().optional(),
5226
- agent: z2.enum(["claude", "codex", "gemini"]).optional()
5855
+ projects: z4.array(ProjectEntrySchema).optional(),
5856
+ dispatch: z4.object({
5857
+ timeoutMs: z4.number().int().positive().optional(),
5858
+ killGraceMs: z4.number().int().positive().optional(),
5859
+ agent: z4.enum(["claude", "codex", "gemini"]).optional()
5860
+ }).optional(),
5861
+ reviewPolicy: z4.object({
5862
+ codeReviewThreshold: z4.string().min(1).optional(),
5863
+ securityThreshold: z4.string().min(1).optional(),
5864
+ maxRounds: z4.number().optional()
5865
+ }).optional(),
5866
+ prePush: z4.object({
5867
+ alwaysRun: z4.array(z4.string()).optional()
5868
+ }).optional(),
5869
+ report: z4.object({
5870
+ commandTimeoutMs: z4.number().int().positive().optional()
5871
+ }).superRefine((report, ctx) => {
5872
+ const commandTimeoutMs = report.commandTimeoutMs;
5873
+ if (commandTimeoutMs !== undefined && commandTimeoutMs > MAX_REPORT_COMMAND_TIMEOUT_MS) {
5874
+ ctx.addIssue({
5875
+ code: z4.ZodIssueCode.custom,
5876
+ path: ["commandTimeoutMs"],
5877
+ message: "must be at most 3600000 (1 hour)"
5878
+ });
5879
+ }
5227
5880
  }).optional()
5228
5881
  });
5229
5882
  var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
@@ -5298,6 +5951,28 @@ function resolvePrincipalAllowlist(config) {
5298
5951
  function resolveReleaseActor(config) {
5299
5952
  return config?.releaseActor ?? DEFAULT_RELEASE_ACTOR;
5300
5953
  }
5954
+ function resolveReviewPolicy(config) {
5955
+ const raw = config?.reviewPolicy;
5956
+ if (!raw)
5957
+ return DEFAULT_REVIEW_POLICY;
5958
+ const codeReviewThreshold = raw.codeReviewThreshold ?? DEFAULT_REVIEW_POLICY.codeReviewThreshold;
5959
+ if (!isKnownSeverity(CODE_REVIEW_SEVERITY_ORDER, codeReviewThreshold)) {
5960
+ 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.`);
5961
+ }
5962
+ const securityThreshold = raw.securityThreshold ?? DEFAULT_REVIEW_POLICY.securityThreshold;
5963
+ if (!isKnownSeverity(SECURITY_SEVERITY_ORDER, securityThreshold)) {
5964
+ 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.`);
5965
+ }
5966
+ const maxRounds = raw.maxRounds ?? DEFAULT_REVIEW_POLICY.maxRounds;
5967
+ if (!Number.isInteger(maxRounds) || maxRounds < 1) {
5968
+ throw new Error(`vinaya.config.json: reviewPolicy.maxRounds "${maxRounds}" is not a positive integer — fix the config, this never falls back to a default.`);
5969
+ }
5970
+ return {
5971
+ codeReviewThreshold,
5972
+ securityThreshold,
5973
+ maxRounds
5974
+ };
5975
+ }
5301
5976
  function trustAnchorRepo() {
5302
5977
  const wellFormed = (slug) => /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
5303
5978
  const fromRunner = process.env.GITHUB_REPOSITORY?.trim();
@@ -5377,6 +6052,9 @@ function loadConfig() {
5377
6052
  }
5378
6053
  var TOKENS_COLLECT_TRUST_PATH = join(GLOBAL_VINAYA_HOME, "tokens-collect-trust.json");
5379
6054
 
6055
+ // src/lib/brief-assembly.ts
6056
+ import { execFileSync as execFileSync4 } from "node:child_process";
6057
+
5380
6058
  // ../../packages/sources/src/commands.ts
5381
6059
  var COMMANDS = [
5382
6060
  {
@@ -5535,6 +6213,17 @@ var COMMANDS = [
5535
6213
  ],
5536
6214
  status: "shipped"
5537
6215
  },
6216
+ {
6217
+ name: "task status",
6218
+ description: "Every open task with a frozen brief, its pull request, and whether its loop is running, paused, or published",
6219
+ flags: [{ flag: "--json", description: "Enveloped JSON output (schema: 1)" }],
6220
+ details: [
6221
+ "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`.",
6222
+ "`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.",
6223
+ "`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."
6224
+ ],
6225
+ status: "shipped"
6226
+ },
5538
6227
  {
5539
6228
  name: "pr create",
5540
6229
  description: "Open a pull request after full brief-schema validation",
@@ -6044,10 +6733,10 @@ function createForgeSource(config) {
6044
6733
  };
6045
6734
  }
6046
6735
  // ../../packages/sources/src/select-source.ts
6047
- import { z as z3 } from "zod";
6048
- var StateSourceConfigSchema = z3.discriminatedUnion("kind", [
6049
- z3.object({ kind: z3.literal("forge"), owner: z3.string(), repo: z3.string() }),
6050
- z3.object({ kind: z3.literal("file"), root: z3.string().optional() })
6736
+ import { z as z5 } from "zod";
6737
+ var StateSourceConfigSchema = z5.discriminatedUnion("kind", [
6738
+ z5.object({ kind: z5.literal("forge"), owner: z5.string(), repo: z5.string() }),
6739
+ z5.object({ kind: z5.literal("file"), root: z5.string().optional() })
6051
6740
  ]);
6052
6741
  // src/checks/edge-resolve.ts
6053
6742
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -6167,6 +6856,580 @@ async function resolveEdge(id, taskById, factsByTaskId, repo, resolveSibling = d
6167
6856
  };
6168
6857
  }
6169
6858
 
6859
+ // src/lib/brief-assembly.ts
6860
+ function git(args) {
6861
+ try {
6862
+ return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
6863
+ } catch {
6864
+ return "";
6865
+ }
6866
+ }
6867
+ function expandGlob(glob) {
6868
+ const out = git(["ls-files", "--", glob]);
6869
+ return out.split(`
6870
+ `).map((s) => s.trim()).filter(Boolean);
6871
+ }
6872
+ var DRAFT_ISSUE_SENTINEL = Number.MAX_SAFE_INTEGER;
6873
+
6874
+ // src/checks/registry.ts
6875
+ import { existsSync as existsSync3 } from "node:fs";
6876
+ import { join as join3 } from "node:path";
6877
+
6878
+ // src/lib/package-root.ts
6879
+ import { existsSync as existsSync2 } from "node:fs";
6880
+ import { dirname as dirname2, join as join2 } from "node:path";
6881
+ import { fileURLToPath } from "node:url";
6882
+ function packageRoot(moduleUrl) {
6883
+ let dir = dirname2(fileURLToPath(moduleUrl));
6884
+ while (!existsSync2(join2(dir, "package.json"))) {
6885
+ if (existsSync2(join2(dir, ".git")))
6886
+ break;
6887
+ const parent = dirname2(dir);
6888
+ if (parent === dir)
6889
+ break;
6890
+ dir = parent;
6891
+ }
6892
+ return dir;
6893
+ }
6894
+
6895
+ // src/checks/registry.ts
6896
+ var DIST_BIN_DIR = join3(packageRoot(import.meta.url), "dist", "checks", "bin");
6897
+ var SRC_BIN_DIR = join3(packageRoot(import.meta.url), "src", "checks", "bin");
6898
+ var BIN_DIR = existsSync3(DIST_BIN_DIR) ? DIST_BIN_DIR : SRC_BIN_DIR;
6899
+ var BIN_EXT = BIN_DIR === DIST_BIN_DIR ? ".js" : ".ts";
6900
+ function bin(name) {
6901
+ return join3(BIN_DIR, `${name}${BIN_EXT}`);
6902
+ }
6903
+ var REGISTRY = [
6904
+ [
6905
+ {
6906
+ name: "brief-shape",
6907
+ validates: "body",
6908
+ run: bin("check-brief-shape"),
6909
+ scope: "diff",
6910
+ timeoutMs: 15000,
6911
+ env: {
6912
+ PR_BODY: { optional: true },
6913
+ BRANCH: { optional: true },
6914
+ PR_NUMBER: { optional: true },
6915
+ GITHUB_TOKEN: { optional: true },
6916
+ GH_TOKEN: { optional: true }
6917
+ }
6918
+ },
6919
+ 0
6920
+ ],
6921
+ [
6922
+ {
6923
+ name: "pr-report-density",
6924
+ validates: "body",
6925
+ run: bin("check-pr-report-density"),
6926
+ scope: "diff",
6927
+ timeoutMs: 15000,
6928
+ env: {
6929
+ PR_BODY: { optional: true }
6930
+ }
6931
+ },
6932
+ 0
6933
+ ],
6934
+ [
6935
+ {
6936
+ name: "doc-coverage",
6937
+ validates: "body",
6938
+ run: bin("check-doc-coverage"),
6939
+ scope: "diff",
6940
+ timeoutMs: 15000,
6941
+ env: {
6942
+ BASE_SHA: { optional: true },
6943
+ PR_BODY: { optional: true },
6944
+ PR_BODY_FILE: { optional: true },
6945
+ PR_NUMBER: { optional: true },
6946
+ GITHUB_REPOSITORY: { optional: true },
6947
+ GITHUB_TOKEN: { optional: true },
6948
+ GH_TOKEN: { optional: true }
6949
+ }
6950
+ },
6951
+ 0
6952
+ ],
6953
+ [
6954
+ {
6955
+ name: "coherence",
6956
+ run: bin("check-coherence"),
6957
+ scope: "full",
6958
+ timeoutMs: 30000,
6959
+ env: {
6960
+ AEG_REPO: { optional: true },
6961
+ BRANCH: { optional: true },
6962
+ GITHUB_TOKEN: { optional: true },
6963
+ GH_TOKEN: { optional: true }
6964
+ }
6965
+ },
6966
+ 0
6967
+ ],
6968
+ [
6969
+ {
6970
+ name: "pr-premise-reassert",
6971
+ validates: "body",
6972
+ run: bin("check-pr-premise-reassert"),
6973
+ scope: "diff",
6974
+ timeoutMs: 15000,
6975
+ env: {
6976
+ PR_BODY: { optional: true }
6977
+ }
6978
+ },
6979
+ 0
6980
+ ],
6981
+ [
6982
+ {
6983
+ name: "dispatch-readiness",
6984
+ run: bin("check-dispatch-readiness"),
6985
+ scope: "full",
6986
+ timeoutMs: 30000,
6987
+ env: {
6988
+ AEG_REPO: { optional: true },
6989
+ BRANCH: { optional: true },
6990
+ GITHUB_TOKEN: { optional: true },
6991
+ GH_TOKEN: { optional: true },
6992
+ PREMISE_FILE: { optional: true }
6993
+ }
6994
+ },
6995
+ 0
6996
+ ],
6997
+ [
6998
+ {
6999
+ name: "closes-n",
7000
+ validates: "body",
7001
+ run: bin("check-closes-n"),
7002
+ scope: "diff",
7003
+ timeoutMs: 15000,
7004
+ requiresOpenPr: true,
7005
+ env: {
7006
+ BRANCH: { optional: true },
7007
+ PR_BODY: { optional: true },
7008
+ AEG_REPO: { optional: true },
7009
+ GITHUB_TOKEN: { optional: true },
7010
+ GH_TOKEN: { optional: true }
7011
+ }
7012
+ },
7013
+ 1
7014
+ ],
7015
+ [
7016
+ {
7017
+ name: "single-plan-pr",
7018
+ run: bin("check-single-plan-pr"),
7019
+ scope: "diff",
7020
+ timeoutMs: 15000,
7021
+ env: {
7022
+ BASE_SHA: { optional: true },
7023
+ PR_NUMBER: { optional: true },
7024
+ GITHUB_TOKEN: { optional: true },
7025
+ GH_TOKEN: { optional: true }
7026
+ }
7027
+ },
7028
+ 0
7029
+ ],
7030
+ [
7031
+ {
7032
+ name: "surface-scope",
7033
+ run: bin("check-surface-scope"),
7034
+ scope: "diff",
7035
+ timeoutMs: 15000,
7036
+ env: {
7037
+ AEG_REPO: { optional: true },
7038
+ BASE_SHA: { optional: true },
7039
+ BRANCH: { optional: true },
7040
+ GITHUB_TOKEN: { optional: true },
7041
+ GH_TOKEN: { optional: true }
7042
+ }
7043
+ },
7044
+ 0
7045
+ ],
7046
+ [
7047
+ {
7048
+ name: "test-plan",
7049
+ validates: "body",
7050
+ run: bin("check-test-plan"),
7051
+ scope: "diff",
7052
+ timeoutMs: 15000,
7053
+ requiresOpenPr: true,
7054
+ principalOwed: true,
7055
+ env: {
7056
+ PR_BODY: { optional: true },
7057
+ BRANCH: { optional: true }
7058
+ }
7059
+ },
7060
+ 1
7061
+ ],
7062
+ [
7063
+ {
7064
+ name: "body-bare-digits",
7065
+ validates: "body",
7066
+ run: bin("check-body-bare-digits"),
7067
+ scope: "diff",
7068
+ timeoutMs: 15000,
7069
+ requiresOpenPr: true,
7070
+ ownWorkflow: true,
7071
+ env: {
7072
+ PR_BODY: { optional: true },
7073
+ PR_NUMBER: { optional: true },
7074
+ GITHUB_REPOSITORY: { optional: true },
7075
+ GITHUB_TOKEN: { optional: true },
7076
+ GH_TOKEN: { optional: true }
7077
+ }
7078
+ },
7079
+ 1
7080
+ ],
7081
+ [
7082
+ {
7083
+ name: "token-report",
7084
+ validates: "body",
7085
+ run: bin("check-token-report"),
7086
+ scope: "diff",
7087
+ timeoutMs: 15000,
7088
+ requiresOpenPr: true,
7089
+ env: {
7090
+ PR_BODY: { optional: true },
7091
+ BRANCH: { optional: true },
7092
+ CLAUDE_PROJECT_DIR: { optional: true },
7093
+ CLAUDE_CODE_SESSION_ID: { optional: true }
7094
+ }
7095
+ },
7096
+ 1
7097
+ ],
7098
+ [
7099
+ {
7100
+ name: "no-disk-state",
7101
+ run: bin("check-no-disk-state"),
7102
+ scope: "diff",
7103
+ timeoutMs: 15000,
7104
+ env: { BASE_SHA: { optional: true } }
7105
+ },
7106
+ 0
7107
+ ],
7108
+ [
7109
+ {
7110
+ name: "registry-gates",
7111
+ run: bin("check-registry-gates"),
7112
+ scope: "full",
7113
+ timeoutMs: 30000,
7114
+ env: {
7115
+ AEG_REPO: { optional: true },
7116
+ GITHUB_TOKEN: { optional: true },
7117
+ GH_TOKEN: { optional: true }
7118
+ }
7119
+ },
7120
+ 0
7121
+ ],
7122
+ [
7123
+ {
7124
+ name: "review-gate",
7125
+ run: bin("check-review-gate"),
7126
+ scope: "full",
7127
+ timeoutMs: 30000,
7128
+ ownWorkflow: true,
7129
+ env: {
7130
+ PR_NUMBER: { optional: true },
7131
+ GITHUB_REPOSITORY: { optional: true },
7132
+ GITHUB_TOKEN: { optional: true },
7133
+ GH_TOKEN: { optional: true }
7134
+ }
7135
+ },
7136
+ 1
7137
+ ],
7138
+ [
7139
+ {
7140
+ name: "branch-topology",
7141
+ run: bin("check-branch-topology"),
7142
+ scope: "full",
7143
+ timeoutMs: 30000,
7144
+ env: {
7145
+ BRANCH: { optional: true },
7146
+ AEG_REPO: { optional: true },
7147
+ GITHUB_TOKEN: { optional: true },
7148
+ GH_TOKEN: { optional: true }
7149
+ }
7150
+ },
7151
+ 0
7152
+ ],
7153
+ [
7154
+ {
7155
+ name: "dead-branch-push",
7156
+ run: bin("check-dead-branch-push"),
7157
+ scope: "full",
7158
+ timeoutMs: 30000,
7159
+ env: {
7160
+ BRANCH: { optional: true },
7161
+ GITHUB_TOKEN: { optional: true },
7162
+ GH_TOKEN: { optional: true }
7163
+ }
7164
+ },
7165
+ 0
7166
+ ],
7167
+ [
7168
+ {
7169
+ name: "first-push-dispatch",
7170
+ run: bin("check-first-push-dispatch"),
7171
+ scope: "full",
7172
+ timeoutMs: 30000,
7173
+ env: {
7174
+ BRANCH: { optional: true },
7175
+ AEG_REPO: { optional: true },
7176
+ GITHUB_TOKEN: { optional: true },
7177
+ GH_TOKEN: { optional: true }
7178
+ }
7179
+ },
7180
+ 0
7181
+ ],
7182
+ [
7183
+ {
7184
+ name: "doc-coverage-push",
7185
+ validates: "body",
7186
+ run: bin("check-doc-coverage-push"),
7187
+ scope: "diff",
7188
+ timeoutMs: 15000,
7189
+ env: {
7190
+ OVERRIDE_DOCS: { optional: true },
7191
+ BASE_SHA: { optional: true },
7192
+ PR_BODY: { optional: true },
7193
+ PR_BODY_FILE: { optional: true },
7194
+ PR_LABELS: { optional: true },
7195
+ WAIVER_LABEL_ACTOR: { optional: true },
7196
+ GITHUB_REPOSITORY: { optional: true },
7197
+ GITHUB_TOKEN: { optional: true },
7198
+ GH_TOKEN: { optional: true }
7199
+ }
7200
+ },
7201
+ 0
7202
+ ],
7203
+ [
7204
+ {
7205
+ name: "issue-assignment",
7206
+ run: bin("check-issue-assignment"),
7207
+ scope: "full",
7208
+ timeoutMs: 30000,
7209
+ env: {
7210
+ AEG_REPO: { optional: true },
7211
+ BRANCH: { optional: true },
7212
+ GITHUB_TOKEN: { optional: true },
7213
+ GH_TOKEN: { optional: true }
7214
+ }
7215
+ },
7216
+ 0
7217
+ ],
7218
+ [
7219
+ {
7220
+ name: "evidence-fresh",
7221
+ validates: "body",
7222
+ run: bin("check-evidence-fresh"),
7223
+ scope: "diff",
7224
+ timeoutMs: 15000,
7225
+ requiresOpenPr: true,
7226
+ env: {
7227
+ PR_NUMBER: { optional: true },
7228
+ PR_BODY: { optional: true },
7229
+ BASE_SHA: { optional: true },
7230
+ GITHUB_TOKEN: { optional: true },
7231
+ GH_TOKEN: { optional: true }
7232
+ }
7233
+ },
7234
+ 1
7235
+ ],
7236
+ [
7237
+ {
7238
+ name: "reader-resolvable-prose",
7239
+ run: bin("check-reader-resolvable-prose"),
7240
+ scope: "full",
7241
+ timeoutMs: 30000,
7242
+ env: {},
7243
+ include: [
7244
+ "aeg-root/**/*.md",
7245
+ "apps/cli/src/**",
7246
+ ".github/workflows/**",
7247
+ ".vinaya/**",
7248
+ "apps/cli/README.md",
7249
+ "packages/sources/README.md"
7250
+ ]
7251
+ },
7252
+ 0
7253
+ ],
7254
+ [
7255
+ {
7256
+ name: "retired-vocabulary",
7257
+ run: bin("check-retired-vocabulary"),
7258
+ scope: "full",
7259
+ timeoutMs: 30000,
7260
+ env: {},
7261
+ include: ["aeg-root/**/*.md"]
7262
+ },
7263
+ 0
7264
+ ],
7265
+ [
7266
+ {
7267
+ name: "doctrine-portability",
7268
+ run: bin("check-doctrine-portability"),
7269
+ scope: "full",
7270
+ timeoutMs: 30000,
7271
+ env: { BASE_SHA: { optional: true } },
7272
+ include: ["aeg-root/**/*.md"]
7273
+ },
7274
+ 0
7275
+ ],
7276
+ [
7277
+ {
7278
+ name: "doctrine-no-procedures",
7279
+ run: bin("check-doctrine-no-procedures"),
7280
+ scope: "full",
7281
+ timeoutMs: 30000,
7282
+ env: {},
7283
+ include: ["aeg-root/**/*.md"]
7284
+ },
7285
+ 0
7286
+ ],
7287
+ [
7288
+ {
7289
+ name: "exec-bits",
7290
+ run: bin("check-exec-bits"),
7291
+ scope: "diff",
7292
+ timeoutMs: 30000,
7293
+ env: {}
7294
+ },
7295
+ 0
7296
+ ],
7297
+ [
7298
+ {
7299
+ name: "workspace-escape",
7300
+ run: bin("check-workspace-escape"),
7301
+ scope: "full",
7302
+ timeoutMs: 30000,
7303
+ env: {},
7304
+ include: ["aeg-root/**/*.md"]
7305
+ },
7306
+ 0
7307
+ ],
7308
+ [
7309
+ {
7310
+ name: "changeset-coverage",
7311
+ run: bin("check-changeset-coverage"),
7312
+ scope: "diff",
7313
+ timeoutMs: 15000,
7314
+ env: {}
7315
+ },
7316
+ 0
7317
+ ],
7318
+ [
7319
+ {
7320
+ name: "quoted-command",
7321
+ run: bin("check-quoted-command"),
7322
+ scope: "diff",
7323
+ timeoutMs: 15000,
7324
+ env: {}
7325
+ },
7326
+ 0
7327
+ ],
7328
+ [
7329
+ {
7330
+ name: "main-branch-refusal",
7331
+ run: bin("check-main-branch-refusal"),
7332
+ scope: "full",
7333
+ timeoutMs: 15000,
7334
+ env: { VINAYA_PUSH_REFS: { optional: true } }
7335
+ },
7336
+ 0
7337
+ ],
7338
+ [
7339
+ {
7340
+ name: "token-collection-wired",
7341
+ run: bin("check-token-collection-wired"),
7342
+ scope: "full",
7343
+ timeoutMs: 15000,
7344
+ env: {
7345
+ CLAUDE_PROJECT_DIR: { optional: true },
7346
+ CLAUDE_CODE_SESSION_ID: { optional: true }
7347
+ }
7348
+ },
7349
+ 0
7350
+ ],
7351
+ [
7352
+ {
7353
+ name: "issue-title-grammar",
7354
+ run: bin("check-issue-title-grammar"),
7355
+ validates: "issue",
7356
+ scope: "full",
7357
+ ownWorkflow: true,
7358
+ timeoutMs: 15000,
7359
+ env: { ISSUE_TITLE: { optional: true } }
7360
+ },
7361
+ 1
7362
+ ],
7363
+ [
7364
+ {
7365
+ name: "issue-objectives-numbering",
7366
+ run: bin("check-issue-objectives-numbering"),
7367
+ validates: "issue",
7368
+ scope: "full",
7369
+ ownWorkflow: true,
7370
+ timeoutMs: 15000,
7371
+ env: { ISSUE_BODY: { optional: true }, ISSUE_NUMBER: { optional: true } }
7372
+ },
7373
+ 1
7374
+ ],
7375
+ [
7376
+ {
7377
+ name: "issue-parts-coverage",
7378
+ run: bin("check-issue-parts-coverage"),
7379
+ validates: "issue",
7380
+ scope: "full",
7381
+ ownWorkflow: true,
7382
+ timeoutMs: 15000,
7383
+ env: { ISSUE_BODY: { optional: true } }
7384
+ },
7385
+ 1
7386
+ ],
7387
+ [
7388
+ {
7389
+ name: "issue-surface-globs",
7390
+ run: bin("check-issue-surface-globs"),
7391
+ validates: "issue",
7392
+ scope: "full",
7393
+ ownWorkflow: true,
7394
+ timeoutMs: 15000,
7395
+ env: { ISSUE_BODY: { optional: true } }
7396
+ },
7397
+ 1
7398
+ ],
7399
+ [
7400
+ {
7401
+ name: "issue-tranche-label",
7402
+ run: bin("check-issue-tranche-label"),
7403
+ validates: "issue",
7404
+ scope: "full",
7405
+ ownWorkflow: true,
7406
+ timeoutMs: 15000,
7407
+ env: { ISSUE_BODY: { optional: true }, ISSUE_LABELS: { optional: true } }
7408
+ },
7409
+ 1
7410
+ ],
7411
+ [
7412
+ {
7413
+ name: "issue-milestone-attach",
7414
+ run: bin("check-issue-milestone-attach"),
7415
+ validates: "issue",
7416
+ scope: "full",
7417
+ ownWorkflow: true,
7418
+ timeoutMs: 15000,
7419
+ env: {
7420
+ ISSUE_LABELS: { optional: true },
7421
+ CURRENT_MILESTONE_TITLE: { optional: true },
7422
+ RESOLVED_MILESTONE_TITLE: { optional: true }
7423
+ }
7424
+ },
7425
+ 1
7426
+ ]
7427
+ ];
7428
+ function coreCheckRegistry() {
7429
+ return REGISTRY.map(([spec]) => spec);
7430
+ }
7431
+ var CORE_CHECK_RING = Object.fromEntries(REGISTRY.map(([spec, ring]) => [spec.name, ring]));
7432
+
6170
7433
  // src/checks/contract.ts
6171
7434
  var CHECK_SCHEMA_VERSION = 1;
6172
7435
  function emitCheckError(error) {
@@ -6174,6 +7437,15 @@ function emitCheckError(error) {
6174
7437
  `);
6175
7438
  }
6176
7439
 
7440
+ // src/checks/runner.ts
7441
+ var activeKillers = new Set;
7442
+
7443
+ // src/lib/forge-write.ts
7444
+ var INFORMATIONAL_DISPATCH_BLOCKER_CLASSES = new Set([
7445
+ "depends-on-not-merged",
7446
+ "conflicts-with"
7447
+ ]);
7448
+
6177
7449
  // src/commands/review-post.ts
6178
7450
  function parseChangedLineRanges(diffOutput) {
6179
7451
  const result = {};
@@ -6205,7 +7477,7 @@ function parseChangedLineRanges(diffOutput) {
6205
7477
  function fileDiffAgainst(ref, path) {
6206
7478
  let out;
6207
7479
  try {
6208
- out = execFileSync4("git", ["diff", `${ref}...HEAD`, "--", path], {
7480
+ out = execFileSync5("git", ["diff", `${ref}...HEAD`, "--", path], {
6209
7481
  encoding: "utf8",
6210
7482
  stdio: ["ignore", "pipe", "pipe"]
6211
7483
  }).trim();
@@ -6216,7 +7488,7 @@ function fileDiffAgainst(ref, path) {
6216
7488
  }
6217
7489
  function revParse(ref) {
6218
7490
  try {
6219
- return execFileSync4("git", ["rev-parse", "--verify", ref], {
7491
+ return execFileSync5("git", ["rev-parse", "--verify", ref], {
6220
7492
  encoding: "utf8",
6221
7493
  stdio: ["ignore", "pipe", "pipe"]
6222
7494
  }).trim();
@@ -6226,7 +7498,7 @@ function revParse(ref) {
6226
7498
  }
6227
7499
  function repoRoot() {
6228
7500
  try {
6229
- return execFileSync4("git", ["rev-parse", "--show-toplevel"], {
7501
+ return execFileSync5("git", ["rev-parse", "--show-toplevel"], {
6230
7502
  encoding: "utf8",
6231
7503
  stdio: ["ignore", "pipe", "pipe"]
6232
7504
  }).trim();
@@ -6237,7 +7509,7 @@ function repoRoot() {
6237
7509
  function changedFiles(base) {
6238
7510
  let out;
6239
7511
  try {
6240
- out = execFileSync4("git", ["diff", "--name-only", `${base}...HEAD`], {
7512
+ out = execFileSync5("git", ["diff", "--name-only", `${base}...HEAD`], {
6241
7513
  encoding: "utf8",
6242
7514
  stdio: ["ignore", "pipe", "pipe"]
6243
7515
  }).trim();
@@ -6262,7 +7534,7 @@ function resolveDiff(base = process.env.BASE_SHA || "origin/main") {
6262
7534
  const relPaths = changedFiles(ref);
6263
7535
  if (relPaths === null)
6264
7536
  continue;
6265
- return { base: ref, root, files: relPaths.map((p) => join2(root, p)) };
7537
+ return { base: ref, root, files: relPaths.map((p) => join4(root, p)) };
6266
7538
  }
6267
7539
  return null;
6268
7540
  }
@@ -6361,18 +7633,18 @@ function evaluateChangesetCoverage(fixedGroup, changedFiles2, isReleaseBranch) {
6361
7633
 
6362
7634
  // src/checks/bin/check-changeset-coverage.ts
6363
7635
  var CHECK_NAME = "changeset-coverage";
6364
- function git(args) {
7636
+ function git2(args) {
6365
7637
  try {
6366
- return execFileSync5("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
7638
+ return execFileSync6("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
6367
7639
  } catch {
6368
7640
  return "";
6369
7641
  }
6370
7642
  }
6371
7643
  function currentBranch() {
6372
- return git(["symbolic-ref", "--quiet", "--short", "HEAD"]);
7644
+ return git2(["symbolic-ref", "--quiet", "--short", "HEAD"]);
6373
7645
  }
6374
7646
  function defaultBranch() {
6375
- const ref = git(["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"]);
7647
+ const ref = git2(["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"]);
6376
7648
  return ref.startsWith("origin/") ? ref.slice("origin/".length) : "";
6377
7649
  }
6378
7650
  function toPosix(p) {
@@ -6401,18 +7673,18 @@ function childDirs(absoluteDir) {
6401
7673
  function candidateMemberDirs(root, pattern) {
6402
7674
  if (pattern.endsWith("/*")) {
6403
7675
  const prefix = pattern.slice(0, -2);
6404
- return childDirs(join3(root, prefix)).map((name) => `${prefix}/${name}`);
7676
+ return childDirs(join5(root, prefix)).map((name) => `${prefix}/${name}`);
6405
7677
  }
6406
7678
  if (!pattern.includes("*"))
6407
7679
  return [pattern];
6408
7680
  return [];
6409
7681
  }
6410
7682
  function resolveWorkspaceMembers(root) {
6411
- const rootPkg = readPackageJson(join3(root, "package.json"));
7683
+ const rootPkg = readPackageJson(join5(root, "package.json"));
6412
7684
  const members = new Map;
6413
7685
  for (const pattern of workspacePatterns(rootPkg)) {
6414
7686
  for (const dir of candidateMemberDirs(root, pattern)) {
6415
- const pkg = readPackageJson(join3(root, dir, "package.json"));
7687
+ const pkg = readPackageJson(join5(root, dir, "package.json"));
6416
7688
  const name = pkg?.name;
6417
7689
  const files = pkg?.files;
6418
7690
  if (typeof name !== "string" || !Array.isArray(files))
@@ -6423,7 +7695,7 @@ function resolveWorkspaceMembers(root) {
6423
7695
  return members;
6424
7696
  }
6425
7697
  function fixedGroupNames(root) {
6426
- const pkg = readPackageJson(join3(root, ".changeset", "config.json"));
7698
+ const pkg = readPackageJson(join5(root, ".changeset", "config.json"));
6427
7699
  const fixed = pkg?.fixed;
6428
7700
  if (!Array.isArray(fixed))
6429
7701
  return [];
@@ -6451,7 +7723,7 @@ function main() {
6451
7723
  process.exit(0);
6452
7724
  }
6453
7725
  const changedFiles2 = changedAbs.map((p) => toPosix(relative2(root, p)));
6454
- const branch = git(["rev-parse", "--abbrev-ref", "HEAD"]);
7726
+ const branch = git2(["rev-parse", "--abbrev-ref", "HEAD"]);
6455
7727
  const isReleaseBranch = branch === CHANGESET_RELEASE_BRANCH;
6456
7728
  const workspaceMembers = resolveWorkspaceMembers(root);
6457
7729
  const fixedGroup = fixedGroupNames(root).map((name) => {