@attalabs/vinaya 0.27.0 → 0.29.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 (143) hide show
  1. package/README.md +5 -4
  2. package/aeg-root/contracts/planner-developer.md +4 -1
  3. package/aeg-root/contracts/planner-operator.md +86 -0
  4. package/aeg-root/contracts/principal-operator.md +88 -0
  5. package/aeg-root/enforcement.md +4 -4
  6. package/aeg-root/roles/developer.md +25 -18
  7. package/aeg-root/roles/operator.md +133 -0
  8. package/aeg-root/roles/planner.md +6 -0
  9. package/aeg-root/roles/principal.md +4 -0
  10. package/aeg-root/roles/reviewer.md +3 -3
  11. package/aeg-root/roles/security.md +3 -3
  12. package/aeg-root/skills/aeg-context-packets/SKILL.md +123 -0
  13. package/aeg-root/skills/aeg-context-packets/examples/operator-start.md +30 -0
  14. package/aeg-root/templates/brief-template.md +6 -2
  15. package/dist/checks/bin/check-body-bare-digits.js +1275 -240
  16. package/dist/checks/bin/check-branch-topology.js +1207 -180
  17. package/dist/checks/bin/check-brief-shape.js +1279 -243
  18. package/dist/checks/bin/check-changeset-coverage.js +2176 -264
  19. package/dist/checks/bin/check-closes-n.js +1211 -184
  20. package/dist/checks/bin/check-coherence.js +1378 -265
  21. package/dist/checks/bin/check-dead-branch-push.js +1158 -176
  22. package/dist/checks/bin/check-dispatch-readiness.js +1440 -276
  23. package/dist/checks/bin/check-doc-coverage-push.js +2171 -259
  24. package/dist/checks/bin/check-doc-coverage.js +2173 -261
  25. package/dist/checks/bin/check-doctrine-no-procedures.js +1275 -240
  26. package/dist/checks/bin/check-doctrine-portability.js +2171 -259
  27. package/dist/checks/bin/check-evidence-fresh.js +2613 -347
  28. package/dist/checks/bin/check-exec-bits.js +2169 -257
  29. package/dist/checks/bin/check-first-push-dispatch.js +1326 -246
  30. package/dist/checks/bin/check-issue-assignment.js +1209 -182
  31. package/dist/checks/bin/check-issue-milestone-attach.js +6087 -0
  32. package/dist/checks/bin/check-issue-objectives-numbering.js +6089 -0
  33. package/dist/checks/bin/check-issue-parts-coverage.js +6089 -0
  34. package/dist/checks/bin/check-issue-surface-globs.js +7304 -0
  35. package/dist/checks/bin/check-issue-title-grammar.js +6089 -0
  36. package/dist/checks/bin/check-issue-tranche-label.js +6089 -0
  37. package/dist/checks/bin/check-main-branch-refusal.js +1158 -176
  38. package/dist/checks/bin/check-no-disk-state.js +1158 -176
  39. package/dist/checks/bin/check-pr-premise-reassert.js +1275 -240
  40. package/dist/checks/bin/check-pr-report-density.js +1158 -176
  41. package/dist/checks/bin/check-quoted-command.js +2150 -257
  42. package/dist/checks/bin/check-reader-resolvable-prose.js +2153 -260
  43. package/dist/checks/bin/check-registry-gates.js +1245 -176
  44. package/dist/checks/bin/check-retired-vocabulary.js +2148 -255
  45. package/dist/checks/bin/check-review-gate.js +1375 -245
  46. package/dist/checks/bin/check-single-plan-pr.js +1158 -176
  47. package/dist/checks/bin/check-surface-scope.js +1217 -182
  48. package/dist/checks/bin/check-test-plan.js +1187 -189
  49. package/dist/checks/bin/check-token-collection-wired.js +1158 -176
  50. package/dist/checks/bin/check-token-report.js +1171 -179
  51. package/dist/checks/bin/check-workspace-escape.js +2167 -255
  52. package/dist/index.js +17322 -8709
  53. package/dist/lib/pre-push-changed-files.js +57 -0
  54. package/dist/lib/pre-push-select-tests.js +1616 -0
  55. package/package.json +4 -2
  56. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  57. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  58. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  59. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error/page.js +2 -1
  60. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  61. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  63. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  66. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  67. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js +8 -7
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  72. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js +8 -7
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js +9 -8
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  81. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js +9 -8
  82. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  83. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  84. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  85. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js +8 -7
  86. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  87. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  88. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +16 -4
  89. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js +10 -8
  90. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  91. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  92. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  93. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js +8 -7
  94. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  95. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  96. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  97. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js +8 -7
  98. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  99. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  100. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  101. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js +9 -8
  102. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  103. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  104. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/1q96_modules_@clerk_nextjs_dist_esm_app-router_client_keyless-creator-reader_0lom2js.js +1 -1
  105. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__08f5pba._.js +3 -0
  106. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__1o_0tjy._.js → [root-of-the-server]__0h9yhwx._.js} +2 -2
  107. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0053k9k._.js → [root-of-the-server]__0ls23oh._.js} +3 -2
  108. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0puovz5._.js → [root-of-the-server]__0nye8tb._.js} +3 -2
  109. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__18kqy4q._.js → [root-of-the-server]__0tfykr-._.js} +2 -2
  110. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0o771t1._.js → [root-of-the-server]__0th3gyp._.js} +3 -2
  111. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1-zcufa._.js +51 -0
  112. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0p8q38b._.js → [root-of-the-server]__11svemm._.js} +1 -1
  113. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__02c71kv._.js → [root-of-the-server]__140m1i_._.js} +2 -2
  114. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1bh2awk._.js +3 -0
  115. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0112h-k._.js → [root-of-the-server]__1gjqmhq._.js} +3 -2
  116. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1qmxez3._.js +4 -0
  117. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1r47dr7._.js +28 -0
  118. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
  119. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_01fv4fj._.js +1 -1
  120. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0gvm3og._.js → _096f46i._.js} +3 -2
  121. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0lwxg63._.js → _0af2one._.js} +3 -2
  122. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_1n0cnq-._.js → _0zf4d27._.js} +45 -2
  123. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_03x_w6q._.js → _1-wo68i._.js} +3 -2
  124. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_projects_[name]_tranches_[slug]_05ufo8i._.js +1 -12
  125. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1wdusod._.js +3 -0
  126. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{node_modules_1vo08dj._.js → node_modules_@clerk_nextjs_dist_esm_app-router_server-actions_1x7vfhn.js} +3 -4
  127. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_next_1khj-jh._.js +3 -0
  128. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  129. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  130. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  131. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +17 -5
  132. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3_9xytdmiv1xi.js → 25f3-jtiv8p5n.js} +4 -4
  133. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0bn8c8v5q429o.js → 27-6ym7lp2v8o.js} +1 -1
  134. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3-6a3tinbdb-7.js → 3daxns3o--9me.js} +1 -1
  135. package/studio-standalone/apps/vinaya-studio/web/tsconfig.json +12 -0
  136. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0z6dav-._.js +0 -51
  137. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__13rrmhr._.js +0 -3
  138. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__17h4sy8._.js +0 -45
  139. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +0 -3
  140. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_next_17sz44y._.js +0 -3
  141. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_buildManifest.js +0 -0
  142. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_clientMiddlewareManifest.js +0 -0
  143. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_ssgManifest.js +0 -0
@@ -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";
7
- import { readdirSync, readFileSync as readFileSync3 } from "node:fs";
8
- import { join as join3, relative as relative2 } from "node:path";
6
+ import { execFileSync as execFileSync7 } from "node:child_process";
7
+ import { readdirSync, readFileSync as readFileSync4 } from "node:fs";
8
+ import { join as join6, 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 },
@@ -1646,6 +1646,52 @@ var systemEnv3 = {
1646
1646
  ...process.env,
1647
1647
  PATH: [process.env.PATH, "/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin"].filter(Boolean).join(":")
1648
1648
  };
1649
+ var defaultExec = () => execFileAsync3("git", ["remote", "get-url", "origin"], { env: systemEnv3, timeout: 5000 });
1650
+ var cached;
1651
+ var inflight;
1652
+ async function resolveRepo(exec = defaultExec) {
1653
+ if (cached !== undefined)
1654
+ return cached;
1655
+ const fromEnv = process.env.AEG_REPO;
1656
+ if (fromEnv) {
1657
+ const parsed = parseOwnerRepo(fromEnv);
1658
+ if (parsed) {
1659
+ cached = parsed;
1660
+ return cached;
1661
+ }
1662
+ }
1663
+ if (inflight)
1664
+ return inflight;
1665
+ inflight = (async () => {
1666
+ try {
1667
+ const { stdout } = await exec();
1668
+ cached = parseGitRemoteUrl(stdout.trim());
1669
+ return cached;
1670
+ } catch (err) {
1671
+ const message = err instanceof Error ? err.message : String(err);
1672
+ console.warn(`[aeg-forge-state] resolveRepo: git remote lookup failed (will retry): ${message}`);
1673
+ return null;
1674
+ } finally {
1675
+ inflight = undefined;
1676
+ }
1677
+ })();
1678
+ return inflight;
1679
+ }
1680
+ function parseGitRemoteUrl(url) {
1681
+ const ssh = url.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
1682
+ if (ssh?.[1] && ssh[2])
1683
+ return { owner: ssh[1], repo: ssh[2] };
1684
+ const https = url.match(/^https?:\/\/(?:[^@]+@)?github\.com\/([^/]+)\/(.+?)(?:\.git)?\/?$/);
1685
+ if (https?.[1] && https[2])
1686
+ return { owner: https[1], repo: https[2] };
1687
+ return null;
1688
+ }
1689
+ function parseOwnerRepo(value) {
1690
+ const match = value.match(/^([^/]+)\/(.+)$/);
1691
+ if (!match?.[1] || !match[2])
1692
+ return null;
1693
+ return { owner: match[1], repo: match[2] };
1694
+ }
1649
1695
  // ../../packages/aeg-core/src/anchored-region.ts
1650
1696
  function anchoredRegionBounds(body, field) {
1651
1697
  const masked = maskCode(body);
@@ -1956,6 +2002,9 @@ function parseInlineFieldList(section) {
1956
2002
  var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
1957
2003
  var OBJECTIVES_VERSION_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Objectives version:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
1958
2004
  var RULING_ORDINAL_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Ruling ordinal:\s*(\d+)(?!\d)/im;
2005
+ var BRIEF_HASH_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Brief hash:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
2006
+ var POLICY_DIGEST_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Policy digest:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
2007
+ var BASE_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged base:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
1959
2008
  function firstFiveLines(comment) {
1960
2009
  return comment.split(`
1961
2010
  `).slice(0, 5).join(`
@@ -1978,6 +2027,35 @@ function extractRulingOrdinal(comment) {
1978
2027
  const m = firstSevenLines(comment).match(RULING_ORDINAL_PATTERN);
1979
2028
  return m ? Number.parseInt(m[1], 10) : null;
1980
2029
  }
2030
+ function firstElevenLines(comment) {
2031
+ return comment.split(`
2032
+ `).slice(0, 11).join(`
2033
+ `);
2034
+ }
2035
+ function extractBriefHash(comment) {
2036
+ const m = firstElevenLines(comment).match(BRIEF_HASH_PATTERN);
2037
+ return m ? m[1].toLowerCase() : null;
2038
+ }
2039
+ function extractPolicyDigest(comment) {
2040
+ const m = firstElevenLines(comment).match(POLICY_DIGEST_PATTERN);
2041
+ return m ? m[1].toLowerCase() : null;
2042
+ }
2043
+ function firstThirteenLines(comment) {
2044
+ return comment.split(`
2045
+ `).slice(0, 13).join(`
2046
+ `);
2047
+ }
2048
+ function extractBaseSha(comment) {
2049
+ const m = firstThirteenLines(comment).match(BASE_SHA_PATTERN);
2050
+ return m ? m[1].toLowerCase() : null;
2051
+ }
2052
+ var FINDING_SEVERITY_LINE = /^\d+\.\s+\[([A-Z][A-Z]*)\]\s+(.+?)\s+—/gm;
2053
+ function extractFindingSeverities(comment) {
2054
+ return [...comment.matchAll(FINDING_SEVERITY_LINE)].map((m) => ({
2055
+ severity: m[1],
2056
+ location: m[2]
2057
+ }));
2058
+ }
1981
2059
  function extractVerdict(comments, valuePattern, missingLabel) {
1982
2060
  const candidates = comments.filter((c) => valuePattern.test(c));
1983
2061
  if (candidates.length === 0) {
@@ -1986,6 +2064,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
1986
2064
  headSha: null,
1987
2065
  objectivesVersion: null,
1988
2066
  rulingOrdinal: null,
2067
+ briefHash: null,
2068
+ policyDigest: null,
2069
+ baseSha: null,
2070
+ findingSeverities: [],
1989
2071
  danglingNote: `no ${missingLabel} verdict comment found on this PR`
1990
2072
  };
1991
2073
  }
@@ -1997,6 +2079,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
1997
2079
  headSha: null,
1998
2080
  objectivesVersion: null,
1999
2081
  rulingOrdinal: null,
2082
+ briefHash: null,
2083
+ policyDigest: null,
2084
+ baseSha: null,
2085
+ findingSeverities: [],
2000
2086
  danglingNote: `the most recent ${missingLabel} verdict comment carries a VERDICT-shaped line outside the first-five-line read window`
2001
2087
  };
2002
2088
  }
@@ -2005,6 +2091,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
2005
2091
  headSha: extractHeadSha(latest),
2006
2092
  objectivesVersion: extractObjectivesVersion(latest),
2007
2093
  rulingOrdinal: extractRulingOrdinal(latest),
2094
+ briefHash: extractBriefHash(latest),
2095
+ policyDigest: extractPolicyDigest(latest),
2096
+ baseSha: extractBaseSha(latest),
2097
+ findingSeverities: extractFindingSeverities(latest),
2008
2098
  danglingNote: null
2009
2099
  };
2010
2100
  }
@@ -2340,6 +2430,53 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
2340
2430
  }
2341
2431
  return out;
2342
2432
  }
2433
+ // ../../packages/aeg-core/src/review-policy.ts
2434
+ var CODE_REVIEW_SEVERITY_ORDER = ["BLOCKER", "MAJOR", "MINOR"];
2435
+ var SECURITY_SEVERITY_ORDER = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
2436
+ var DEFAULT_MAX_ROUNDS = 3;
2437
+ var DEFAULT_REVIEW_POLICY = {
2438
+ codeReviewThreshold: "BLOCKER",
2439
+ securityThreshold: "HIGH",
2440
+ maxRounds: DEFAULT_MAX_ROUNDS
2441
+ };
2442
+ var FILE_SHAPED_LOCATION = /\.[a-zA-Z0-9]{1,10}(:\d+)?\s*$/;
2443
+ var PROSE_LOCATION_PATTERNS = [/\bpr\s*body\b/i, /\bcomment\b/i];
2444
+ var ROLE_FILE_LOCATION = /(^|\/)aeg-root\/roles\//i;
2445
+ function isProseLocation(location) {
2446
+ if (ROLE_FILE_LOCATION.test(location))
2447
+ return true;
2448
+ if (FILE_SHAPED_LOCATION.test(location))
2449
+ return false;
2450
+ return PROSE_LOCATION_PATTERNS.some((pattern) => pattern.test(location));
2451
+ }
2452
+ var PROSE_CAP_SEVERITY = "MINOR";
2453
+ function blockingSeverities(scale, threshold) {
2454
+ const idx = scale.indexOf(threshold);
2455
+ if (idx === -1) {
2456
+ throw new Error(`blockingSeverities: threshold "${threshold}" is not one of ${scale.join(" > ")}`);
2457
+ }
2458
+ return scale.slice(0, idx + 1);
2459
+ }
2460
+ function evaluateReviewFindings(findings, scale, threshold) {
2461
+ const blocking = new Set(blockingSeverities(scale, threshold));
2462
+ const blockingFindings = findings.filter((f) => {
2463
+ if (!scale.includes(f.severity)) {
2464
+ throw new Error(`evaluateReviewFindings: severity "${f.severity}" is not one of ${scale.join(" > ")}`);
2465
+ }
2466
+ const effectiveSeverity = f.location !== undefined && isProseLocation(f.location) ? PROSE_CAP_SEVERITY : f.severity;
2467
+ return blocking.has(effectiveSeverity);
2468
+ });
2469
+ return { outcome: blockingFindings.length > 0 ? "blocked" : "clean", blockingFindings };
2470
+ }
2471
+ function evaluateCodeReview(findings, policy) {
2472
+ return evaluateReviewFindings(findings, CODE_REVIEW_SEVERITY_ORDER, policy.codeReviewThreshold);
2473
+ }
2474
+ function evaluateSecurityReview(findings, policy) {
2475
+ return evaluateReviewFindings(findings, SECURITY_SEVERITY_ORDER, policy.securityThreshold);
2476
+ }
2477
+ function isKnownSeverity(scale, value) {
2478
+ return scale.includes(value);
2479
+ }
2343
2480
  // ../../packages/aeg-core/src/pr-tier.ts
2344
2481
  var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
2345
2482
  function readTierFromPrBody(prBody) {
@@ -2710,7 +2847,7 @@ function checkForField(prBody) {
2710
2847
  ]
2711
2848
  };
2712
2849
  }
2713
- function checkClosesN(prBody) {
2850
+ function checkClosesNPresence(prBody) {
2714
2851
  const closesPattern = /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s{0,8}:?\s{0,8}#\d+/i;
2715
2852
  if (closesPattern.test(stripCode(prBody))) {
2716
2853
  return { status: "pass", errors: [] };
@@ -2742,10 +2879,22 @@ var COMMIT_TYPES = [
2742
2879
  "Test"
2743
2880
  ];
2744
2881
  var COMMIT_TYPE_STYLE = new RegExp(`^(${COMMIT_TYPES.join("|")})(\\([a-z0-9-]+\\))?: \\S`);
2882
+ function checkForgeTitle(title) {
2883
+ const taskStyle = /^\[[a-z0-9._-]+\] \S+ — \S/;
2884
+ if (COMMIT_TYPE_STYLE.test(title) || taskStyle.test(title))
2885
+ return { status: "pass", errors: [] };
2886
+ return {
2887
+ status: "fail",
2888
+ errors: [
2889
+ `brief-validation title: "${title}" matches neither title grammar — expected \`Type: description\` / \`Type(scope): description\` (commitlint types + Plan) or \`[tranche] id — description\` (task form).`
2890
+ ]
2891
+ };
2892
+ }
2745
2893
  var BRIEF_SHAPE_MARKERS = [checkSurfaceMap, checkDocUpdateList, checkStopConditions, checkAutonomyClause];
2746
2894
  var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
2895
+ var TASK_ISSUE_BRANCH_PATTERN = /^task\/issue-\d+$/;
2747
2896
  function isTaskBranch(branch) {
2748
- return TASK_BRANCH_PATTERN.test(branch);
2897
+ return TASK_BRANCH_PATTERN.test(branch) || TASK_ISSUE_BRANCH_PATTERN.test(branch);
2749
2898
  }
2750
2899
  function isBriefShaped(prBody) {
2751
2900
  const stripped = stripCode(prBody);
@@ -2867,8 +3016,9 @@ function packagesNamedIn(text) {
2867
3016
  }
2868
3017
  function hasTestPathForConsumer(text, consumerDir) {
2869
3018
  const escaped = consumerDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2870
- const re = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
2871
- return re.test(text);
3019
+ const filePathRe = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
3020
+ const testDirRe = new RegExp(`${escaped}\\/(?:[\\w-]+\\/)*(?:tests|specs)(?:\\/|\\b)`);
3021
+ return filePathRe.test(text) || testDirRe.test(text);
2872
3022
  }
2873
3023
  function checkConsumerTests(prBody, consumersOf) {
2874
3024
  const section4 = extractNumberedSection(prBody, 4);
@@ -2972,7 +3122,7 @@ function checkBriefSections(prBody, readTier, options = {}) {
2972
3122
  checkConsumerTests(prBody, consumersOf),
2973
3123
  checkDefeatCases(prBody),
2974
3124
  ...issueObjectives !== undefined ? [checkObjectivesCopy(prBody, issueObjectives), checkObjectivesCoverage(prBody)] : [],
2975
- ...requireClosesN ? [checkClosesN(prBody)] : []
3125
+ ...requireClosesN ? [checkClosesNPresence(prBody)] : []
2976
3126
  ];
2977
3127
  return { errors: results.flatMap((r) => r.errors) };
2978
3128
  }
@@ -3262,6 +3412,28 @@ function topLevelSectionText(body, headingName) {
3262
3412
  const next = /^##[ \t]/m.exec(afterHeading);
3263
3413
  return next ? afterHeading.slice(0, next.index) : afterHeading;
3264
3414
  }
3415
+ function partHasBacktickedPath(text) {
3416
+ let i = 0;
3417
+ while (i < text.length) {
3418
+ const start = text.indexOf("`", i);
3419
+ if (start === -1)
3420
+ return false;
3421
+ const end = text.indexOf("`", start + 1);
3422
+ if (end === -1)
3423
+ return false;
3424
+ if (text.slice(start + 1, end).includes("/"))
3425
+ return true;
3426
+ i = end + 1;
3427
+ }
3428
+ return false;
3429
+ }
3430
+ var PART_MIN_WORDS_OUTSIDE_BACKTICKS = 3;
3431
+ function stripPartBackticks(text) {
3432
+ return text.replace(/`[^`\n]*`/g, " ");
3433
+ }
3434
+ function partWordCount(text) {
3435
+ return text.split(/\s+/).filter((w) => /[a-z]/i.test(w)).length;
3436
+ }
3265
3437
  function looksLikeFilePath(entry2) {
3266
3438
  const stripped = entry2.replace(/\/\*\*?$/, "");
3267
3439
  const lastSegment = stripped.split("/").pop() ?? stripped;
@@ -3302,6 +3474,18 @@ function globCoversPath(glob, path) {
3302
3474
  const p = path.replace(/\/+$/, "");
3303
3475
  return g === p || g.startsWith(`${p}/`) || p.startsWith(`${g}/`);
3304
3476
  }
3477
+ function checkSurfaceGlobsResolve(body, resolvesToFile) {
3478
+ const surface = parseIssueSurface(body);
3479
+ if (!surface.ok)
3480
+ return { status: "pass", errors: [] };
3481
+ const errors = [];
3482
+ for (const glob of surface.value.in) {
3483
+ if (!resolvesToFile(glob)) {
3484
+ 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.`);
3485
+ }
3486
+ }
3487
+ return { status: errors.length > 0 ? "fail" : "pass", errors };
3488
+ }
3305
3489
  function checkSurfaceScope(changedFiles, outGlobs) {
3306
3490
  if (outGlobs.length === 0)
3307
3491
  return { ok: true };
@@ -3313,9 +3497,77 @@ function checkSurfaceScope(changedFiles, outGlobs) {
3313
3497
  }
3314
3498
  return violations.length > 0 ? { ok: false, violations } : { ok: true };
3315
3499
  }
3500
+ var ISSUE_PART_LINE_RE = /^Part\s+(\d+)\s*\(([^)]*)\)\s*[-—–]\s*(.*)$/i;
3501
+ function parseIssueParts(body) {
3502
+ const section = topLevelSectionText(body, "Parts");
3503
+ if (section === null)
3504
+ return { ok: false, errors: ["no `## Parts` heading found in the body."] };
3505
+ const lines = section.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
3506
+ const parts = [];
3507
+ const errors = [];
3508
+ for (const line of lines) {
3509
+ const m = ISSUE_PART_LINE_RE.exec(line);
3510
+ if (!m) {
3511
+ errors.push(`"${line}" is not a well-formed Parts line — expected \`Part <n> (<refs>) — <outcome>\`.`);
3512
+ continue;
3513
+ }
3514
+ const n = Number.parseInt(m[1], 10);
3515
+ const refs = m[2];
3516
+ const text = m[3].trim();
3517
+ if (text.length === 0) {
3518
+ errors.push(`Part ${n} has no outcome text after the dash — every Part states one observable outcome.`);
3519
+ continue;
3520
+ }
3521
+ if (partHasBacktickedPath(text) && partWordCount(stripPartBackticks(text)) < PART_MIN_WORDS_OUTSIDE_BACKTICKS) {
3522
+ errors.push(`Part ${n} is little more than a file path — a Part names an outcome and symbols, never a bare path.`);
3523
+ continue;
3524
+ }
3525
+ const objectiveIds = [...refs.matchAll(/O(\d+)/g)].map((r) => Number.parseInt(r[1], 10));
3526
+ parts.push({ n, objectiveIds, text });
3527
+ }
3528
+ if (parts.length === 0) {
3529
+ errors.push("the `## Parts` section has no well-formed `Part <n> (<refs>) — <outcome>` lines.");
3530
+ }
3531
+ if (errors.length > 0)
3532
+ return { ok: false, errors };
3533
+ return { ok: true, value: parts };
3534
+ }
3535
+ function checkPartsCiteDefinedObjectives(body) {
3536
+ const parts = parseIssueParts(body);
3537
+ const objectives = objectivesOf(body);
3538
+ if (!parts.ok || !objectives.ok)
3539
+ return { status: "pass", errors: [] };
3540
+ const definedIds = new Set(objectives.objectives.map((o) => Number.parseInt(o.id.slice(1), 10)));
3541
+ const errors = [];
3542
+ for (const part of parts.value) {
3543
+ for (const objectiveId of part.objectiveIds) {
3544
+ if (!definedIds.has(objectiveId)) {
3545
+ errors.push(`issue-validation Parts: Part ${part.n} cites O${objectiveId}, which the Issue's own \`## Objectives\` section does not define.`);
3546
+ }
3547
+ }
3548
+ }
3549
+ return { status: errors.length > 0 ? "fail" : "pass", errors };
3550
+ }
3316
3551
  function isTaskIssueLabelSet(labels) {
3317
3552
  return hasLabel("tranche", labels);
3318
3553
  }
3554
+ function checkTrancheLabelPresence(_body, _labels) {
3555
+ return { status: "pass", errors: [] };
3556
+ }
3557
+ function checkMilestoneAttach(labels, currentMilestoneTitle, resolvedMilestoneTitle) {
3558
+ if (!isTaskIssueLabelSet(labels))
3559
+ return { status: "pass", errors: [] };
3560
+ if (resolvedMilestoneTitle === null)
3561
+ return { status: "pass", errors: [] };
3562
+ if (currentMilestoneTitle === resolvedMilestoneTitle)
3563
+ return { status: "pass", errors: [] };
3564
+ return {
3565
+ status: "fail",
3566
+ errors: [
3567
+ `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}".`
3568
+ ]
3569
+ };
3570
+ }
3319
3571
  var TYPE_LABEL_IDS = LABELS.filter((l) => l.category === "type").map((l) => l.id);
3320
3572
  function isControlCodePoint(codePoint) {
3321
3573
  return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
@@ -3380,6 +3632,19 @@ function checkProjectsRegistered(body, _labels, registeredNames) {
3380
3632
  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
3633
  var DOC_PATH_RE_GLOBAL = new RegExp(DOC_PATH_RE.source, "gi");
3382
3634
 
3635
+ // ../../packages/aeg-core/src/task-branch-identity.ts
3636
+ var ISSUE_BRANCH_PATTERN = /^task\/issue-(\d+)$/;
3637
+ var TRANCHE_BRANCH_PATTERN = /^task\/([^/]+)\/([^/]+)$/;
3638
+ function parseTaskBranchIdentity(branch) {
3639
+ const issueMatch = ISSUE_BRANCH_PATTERN.exec(branch);
3640
+ if (issueMatch)
3641
+ return { kind: "issue", issueNumber: Number(issueMatch[1]) };
3642
+ const trancheMatch = TRANCHE_BRANCH_PATTERN.exec(branch);
3643
+ if (trancheMatch)
3644
+ return { kind: "tranche", tranche: trancheMatch[1], taskId: trancheMatch[2] };
3645
+ return null;
3646
+ }
3647
+
3383
3648
  // ../../packages/aeg-core/src/coherence-checks.ts
3384
3649
  var COHERENCE_ENFORCED_FROM = "2026-07-01";
3385
3650
  function isGrandfathered(isoDate) {
@@ -3400,6 +3665,7 @@ function checkA1(entries, principalAllowlist = PRINCIPAL_ALLOWLIST) {
3400
3665
  if (handClosed)
3401
3666
  continue;
3402
3667
  failures.push({
3668
+ code: "closed-without-merge",
3403
3669
  issue: e.task.issue,
3404
3670
  tranche: e.trancheSlug,
3405
3671
  task: e.task.id,
@@ -3424,6 +3690,7 @@ function checkA3(entries) {
3424
3690
  continue;
3425
3691
  if (e.facts.prState === "merged" && e.facts.issueState !== "closed") {
3426
3692
  failures.push({
3693
+ code: "auto-close-misfire",
3427
3694
  issue: e.task.issue,
3428
3695
  tranche: e.trancheSlug,
3429
3696
  task: e.task.id,
@@ -3448,6 +3715,7 @@ function checkT1(entries) {
3448
3715
  continue;
3449
3716
  if (e.facts === undefined) {
3450
3717
  failures.push({
3718
+ code: "phantom-issue-ref",
3451
3719
  issue: e.task.issue,
3452
3720
  tranche: e.trancheSlug,
3453
3721
  task: e.task.id,
@@ -3466,6 +3734,7 @@ function checkT2(openIssuesBySlug, topologyIssuesBySlug, ciTrancheSlug) {
3466
3734
  for (const num of openNums) {
3467
3735
  if (!topologySet.has(num)) {
3468
3736
  failures.push({
3737
+ code: "orphan-task",
3469
3738
  issue: num,
3470
3739
  tranche: slug,
3471
3740
  reason: `Issue #${num} is open and labeled ${trancheLabel(slug)} but does not appear in the topology file`
@@ -3500,6 +3769,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
3500
3769
  continue;
3501
3770
  if (forgeUnavailableSlugs?.has(e.trancheSlug)) {
3502
3771
  failures.push({
3772
+ code: "tbd-in-active-tranche",
3503
3773
  issue: null,
3504
3774
  tranche: e.trancheSlug,
3505
3775
  task: e.task.id,
@@ -3509,6 +3779,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
3509
3779
  continue;
3510
3780
  }
3511
3781
  failures.push({
3782
+ code: "tbd-in-active-tranche",
3512
3783
  issue: null,
3513
3784
  tranche: e.trancheSlug,
3514
3785
  task: e.task.id,
@@ -3541,6 +3812,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
3541
3812
  const sameIssue = depEntry.task.issue !== null && e.task.issue !== null && depEntry.task.issue === e.task.issue;
3542
3813
  if (sameTask || sameIssue) {
3543
3814
  failures.push({
3815
+ code: "d1-self-dependency",
3544
3816
  issue: e.task.issue,
3545
3817
  tranche: e.trancheSlug,
3546
3818
  task: e.task.id,
@@ -3552,6 +3824,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
3552
3824
  const depClosed = depFacts?.issueState === "closed";
3553
3825
  if (!depClosed) {
3554
3826
  failures.push({
3827
+ code: "dispatched-on-unmet-deps",
3555
3828
  issue: e.task.issue,
3556
3829
  tranche: e.trancheSlug,
3557
3830
  task: e.task.id,
@@ -3577,11 +3850,13 @@ function checkR1(issuesBySlug, grandfatheredIssues, registeredNames = []) {
3577
3850
  const errors = [
3578
3851
  ...checkIssueRationale(issue.body).errors,
3579
3852
  ...checkProjectsRegistered(issue.body, issue.labels, registeredNames).errors,
3580
- ...checkIssueObjectives(issue.body, issue.number).errors
3853
+ ...checkIssueObjectives(issue.body, issue.number).errors,
3854
+ ...checkPartsCiteDefinedObjectives(issue.body).errors
3581
3855
  ];
3582
3856
  if (errors.length === 0)
3583
3857
  continue;
3584
3858
  failures.push({
3859
+ code: "missing-rationale-field",
3585
3860
  issue: issue.number,
3586
3861
  tranche: slug,
3587
3862
  reason: `Issue #${issue.number} fails the rationale gate: ${errors.join(" | ")}`,
@@ -3610,6 +3885,7 @@ function checkL1(files, entriesBySlug) {
3610
3885
  const allClosed = withFacts.every((e) => e.facts?.issueState === "closed");
3611
3886
  if (allClosed) {
3612
3887
  failures.push({
3888
+ code: "archive-recommended",
3613
3889
  tranche: f.slug,
3614
3890
  reason: "Active tranche has no open task-Issues — consider archiving to completed/"
3615
3891
  });
@@ -3641,27 +3917,38 @@ function extractClosesReferences(prBody) {
3641
3917
  }
3642
3918
  return referenced;
3643
3919
  }
3644
- function checkClosesN2(branch, prBody, trancheFiles, taskIssueRefs) {
3920
+ function checkClosesNTopology(branch, prBody, trancheFiles, taskIssueRefs) {
3645
3921
  const referenced = extractClosesReferences(prBody);
3646
3922
  if (taskIssueRefs) {
3647
3923
  for (const n of referenced) {
3648
- const ref = taskIssueRefs.get(n);
3649
- if (!ref)
3924
+ const ref2 = taskIssueRefs.get(n);
3925
+ if (!ref2)
3650
3926
  continue;
3651
- const expectedBranch = `task/${ref.trancheSlug}/${ref.taskId}`;
3927
+ const expectedBranch = `task/${ref2.trancheSlug}/${ref2.taskId}`;
3652
3928
  if (branch !== expectedBranch) {
3653
3929
  return {
3654
3930
  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.`
3931
+ 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
3932
  };
3657
3933
  }
3658
3934
  }
3659
3935
  }
3660
- const m = branch.match(/^task\/([^/]+)\/([^/]+)$/);
3661
- if (!m)
3936
+ const ref = parseTaskBranchIdentity(branch);
3937
+ if (!ref)
3662
3938
  return { ok: true };
3663
- const trancheSlug = m[1];
3664
- const taskId = m[2];
3939
+ if (ref.kind === "issue") {
3940
+ const expectedIssue2 = ref.issueNumber;
3941
+ if (!referenced.has(expectedIssue2)) {
3942
+ return {
3943
+ ok: false,
3944
+ expectedIssue: expectedIssue2,
3945
+ message: `closes-n: PR body does not contain \`Closes #${expectedIssue2}\` (required for branch "${branch}"). Add it to the PR body Summary section.`
3946
+ };
3947
+ }
3948
+ return { ok: true, expectedIssue: expectedIssue2 };
3949
+ }
3950
+ const trancheSlug = ref.tranche;
3951
+ const taskId = ref.taskId;
3665
3952
  const trancheFile = trancheFiles.find((f) => f.slug === trancheSlug);
3666
3953
  if (!trancheFile) {
3667
3954
  return {
@@ -3713,34 +4000,79 @@ function extractIssue(body) {
3713
4000
  const issue = headerNums.length > 0 ? headerNums[0] : bodyNums[0];
3714
4001
  return { issue, extraIssues: bodyNums.filter((n) => n !== issue), outsideHeader: headerNums.length === 0 };
3715
4002
  }
3716
- // ../../packages/aeg-core/src/review-gate.ts
3717
- function isBoundToHead(extraction, headSha) {
3718
- if (!extraction.headSha)
4003
+ // ../../packages/aeg-core/src/review-input-manifest.ts
4004
+ import { createHash as createHash4 } from "node:crypto";
4005
+ function briefHash(brief) {
4006
+ return createHash4("sha256").update(`${brief}
4007
+ `).digest("hex");
4008
+ }
4009
+ function policyDigest(policy) {
4010
+ return createHash4("sha256").update(JSON.stringify({
4011
+ codeReviewThreshold: policy.codeReviewThreshold,
4012
+ securityThreshold: policy.securityThreshold,
4013
+ maxRounds: policy.maxRounds
4014
+ })).digest("hex");
4015
+ }
4016
+ function isBoundToHead(echoed, headSha) {
4017
+ if (!echoed.headSha)
3719
4018
  return false;
3720
- return headSha.toLowerCase().startsWith(extraction.headSha.toLowerCase());
4019
+ return headSha.toLowerCase().startsWith(echoed.headSha.toLowerCase());
3721
4020
  }
3722
- function isBoundByPatchIdentity(extraction, headSha, patchIdOf) {
3723
- if (patchIdOf === undefined || !extraction.headSha)
4021
+ function isBoundByPatchIdentity(echoed, headSha, patchIdOf) {
4022
+ if (patchIdOf === undefined || !echoed.headSha)
3724
4023
  return false;
3725
- const judged = patchIdOf(extraction.headSha);
4024
+ const judged = patchIdOf(echoed.headSha);
3726
4025
  const current = patchIdOf(headSha);
3727
4026
  if (judged === null || current === null)
3728
4027
  return false;
3729
4028
  return judged === current;
3730
4029
  }
3731
- function isBoundToPatch(extraction, headSha, patchIdOf) {
3732
- return isBoundToHead(extraction, headSha) || isBoundByPatchIdentity(extraction, headSha, patchIdOf);
4030
+ function isBoundToBase(echoed, currentBase) {
4031
+ if (currentBase === null)
4032
+ return true;
4033
+ if (!echoed.baseSha)
4034
+ return false;
4035
+ return currentBase.toLowerCase().startsWith(echoed.baseSha.toLowerCase());
3733
4036
  }
3734
- function isBoundToObjectives(extraction, currentVersion) {
4037
+ function isBoundToObjectives(echoed, currentVersion) {
3735
4038
  if (currentVersion === null)
3736
4039
  return true;
3737
- return extraction.objectivesVersion === currentVersion;
4040
+ return echoed.objectivesVersion === currentVersion;
3738
4041
  }
3739
- function isBoundToRulings(extraction, currentOrdinal) {
3740
- if (extraction.rulingOrdinal === null)
4042
+ function isBoundToRulings(echoed, currentOrdinal) {
4043
+ if (echoed.rulingOrdinal === null)
3741
4044
  return currentOrdinal === 0;
3742
- return extraction.rulingOrdinal === currentOrdinal;
4045
+ return echoed.rulingOrdinal === currentOrdinal;
4046
+ }
4047
+ function isBoundToBriefHash(echoed, currentHash) {
4048
+ if (currentHash === null)
4049
+ return true;
4050
+ return echoed.briefHash === currentHash;
4051
+ }
4052
+ function isBoundToPolicy(echoed, currentDigest) {
4053
+ return echoed.policyDigest === currentDigest;
4054
+ }
4055
+ function compareManifest(echoed, current, patchIdOf) {
4056
+ const exactHead = isBoundToHead(echoed, current.headSha);
4057
+ const patchHead = exactHead ? false : isBoundByPatchIdentity(echoed, current.headSha, patchIdOf);
4058
+ const head = exactHead || patchHead;
4059
+ const base = patchHead ? true : isBoundToBase(echoed, current.baseSha);
4060
+ const briefHashBound = isBoundToBriefHash(echoed, current.briefHash);
4061
+ const objectivesVersion2 = isBoundToObjectives(echoed, current.objectivesVersion);
4062
+ const rulingOrdinal = isBoundToRulings(echoed, current.rulingOrdinal);
4063
+ const policyDigestBound = isBoundToPolicy(echoed, current.policyDigest);
4064
+ return {
4065
+ bound: head && base && briefHashBound && objectivesVersion2 && rulingOrdinal && policyDigestBound,
4066
+ head,
4067
+ base,
4068
+ briefHash: briefHashBound,
4069
+ objectivesVersion: objectivesVersion2,
4070
+ rulingOrdinal,
4071
+ policyDigest: policyDigestBound
4072
+ };
3743
4073
  }
4074
+
4075
+ // ../../packages/aeg-core/src/review-gate.ts
3744
4076
  function checkReviewGate(input) {
3745
4077
  const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
3746
4078
  const waived = isWaiverLabelActorVerified({
@@ -3763,15 +4095,58 @@ function checkReviewGate(input) {
3763
4095
  const verifiedBodies = verified.map((c) => c.body);
3764
4096
  const codeReview = extractCodeReviewVerdict(verifiedBodies);
3765
4097
  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) {
4098
+ const policy = input.policy ?? DEFAULT_REVIEW_POLICY;
4099
+ let codeReviewPolicyEvaluation;
4100
+ let securityPolicyEvaluation;
4101
+ try {
4102
+ codeReviewPolicyEvaluation = evaluateCodeReview(codeReview.findingSeverities, policy);
4103
+ securityPolicyEvaluation = evaluateSecurityReview(security.findingSeverities, policy);
4104
+ } catch (err) {
4105
+ return {
4106
+ verdict: "fail",
4107
+ reason: `a verdict comment carries a finding severity this repository's policy does not recognize: ${err instanceof Error ? err.message : String(err)}`,
4108
+ waived: false
4109
+ };
4110
+ }
4111
+ const codeReviewTextClean = codeReview.value === "APPROVE";
4112
+ const securityTextClean = security.value === "PASS";
4113
+ const codeReviewPolicyClean = codeReviewPolicyEvaluation.outcome === "clean";
4114
+ const securityPolicyClean = securityPolicyEvaluation.outcome === "clean";
4115
+ const codeReviewClean = codeReviewTextClean && codeReviewPolicyClean;
4116
+ const securityClean = securityTextClean && securityPolicyClean;
4117
+ const currentManifest = {
4118
+ headSha: input.headSha,
4119
+ baseSha: input.baseSha ?? null,
4120
+ briefHash: input.briefHash ?? null,
4121
+ objectivesVersion: input.objectivesVersion,
4122
+ rulingOrdinal: input.rulingOrdinal,
4123
+ policyDigest: policyDigest(policy)
4124
+ };
4125
+ const codeReviewEchoed = {
4126
+ headSha: codeReview.headSha,
4127
+ baseSha: codeReview.baseSha,
4128
+ briefHash: codeReview.briefHash,
4129
+ objectivesVersion: codeReview.objectivesVersion,
4130
+ rulingOrdinal: codeReview.rulingOrdinal,
4131
+ policyDigest: codeReview.policyDigest
4132
+ };
4133
+ const securityEchoed = {
4134
+ headSha: security.headSha,
4135
+ baseSha: security.baseSha,
4136
+ briefHash: security.briefHash,
4137
+ objectivesVersion: security.objectivesVersion,
4138
+ rulingOrdinal: security.rulingOrdinal,
4139
+ policyDigest: security.policyDigest
4140
+ };
4141
+ const codeReviewBinding = compareManifest(codeReviewEchoed, currentManifest, input.patchIdOf);
4142
+ const securityBinding = compareManifest(securityEchoed, currentManifest, input.patchIdOf);
4143
+ const codeReviewBound = codeReviewBinding.head;
4144
+ const securityBound = securityBinding.head;
4145
+ const codeReviewObjectivesBound = codeReviewBinding.objectivesVersion;
4146
+ const securityObjectivesBound = securityBinding.objectivesVersion;
4147
+ const codeReviewRulingsBound = codeReviewBinding.rulingOrdinal;
4148
+ const securityRulingsBound = securityBinding.rulingOrdinal;
4149
+ if (codeReviewClean && codeReviewBinding.bound && securityClean && securityBinding.bound && mechanicalChecksClean) {
3775
4150
  return {
3776
4151
  verdict: "pass",
3777
4152
  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 +4154,39 @@ function checkReviewGate(input) {
3779
4154
  };
3780
4155
  }
3781
4156
  const problems = [];
3782
- if (!codeReviewClean) {
4157
+ if (!codeReviewTextClean) {
3783
4158
  problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
4159
+ } else if (!codeReviewPolicyClean) {
4160
+ 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
4161
  } else if (!codeReviewBound) {
3785
4162
  problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
4163
+ } else if (!codeReviewBinding.base) {
4164
+ problems.push(`the newest code-review verdict was cast against base ${codeReview.baseSha ?? "no recorded base"}, the PR's base is now ${currentManifest.baseSha ?? "unresolved"} (a base-only change under an unchanged candidate — same patch text on a new base is not automatically equivalent)`);
3786
4165
  } else if (!codeReviewObjectivesBound) {
3787
4166
  problems.push(`the newest code-review verdict was cast against objectives version ${codeReview.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
3788
4167
  } else if (!codeReviewRulingsBound) {
3789
4168
  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`);
4169
+ } else if (!codeReviewBinding.briefHash) {
4170
+ 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"}`);
4171
+ } else if (!codeReviewBinding.policyDigest) {
4172
+ 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
4173
  }
3791
- if (!securityClean) {
4174
+ if (!securityTextClean) {
3792
4175
  problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
4176
+ } else if (!securityPolicyClean) {
4177
+ 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
4178
  } else if (!securityBound) {
3794
4179
  problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
4180
+ } else if (!securityBinding.base) {
4181
+ problems.push(`the newest security-review verdict was cast against base ${security.baseSha ?? "no recorded base"}, the PR's base is now ${currentManifest.baseSha ?? "unresolved"} (a base-only change under an unchanged candidate — same patch text on a new base is not automatically equivalent)`);
3795
4182
  } else if (!securityObjectivesBound) {
3796
4183
  problems.push(`the newest security-review verdict was cast against objectives version ${security.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
3797
4184
  } else if (!securityRulingsBound) {
3798
4185
  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`);
4186
+ } else if (!securityBinding.briefHash) {
4187
+ 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"}`);
4188
+ } else if (!securityBinding.policyDigest) {
4189
+ 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
4190
  }
3800
4191
  if (!mechanicalChecksClean) {
3801
4192
  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 +4878,45 @@ function checkDispatchReadiness(input) {
4487
4878
  const { trancheSlug, task } = input;
4488
4879
  const taskLabel = `task ${task.id} (tranche ${trancheSlug})`;
4489
4880
  const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
4490
- const blockers = [];
4881
+ const blockerDetails = [];
4882
+ const push = (blockerClass, message) => {
4883
+ blockerDetails.push({ class: blockerClass, message });
4884
+ };
4491
4885
  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.`);
4886
+ 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
4887
  } 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).`);
4888
+ 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
4889
  }
4496
4890
  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.`);
4891
+ 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
4892
  }
4499
4893
  for (const dep of input.dependsOn) {
4500
4894
  if (isSelfDependency(dep, task, input.issue)) {
4501
4895
  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.`);
4896
+ 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
4897
  continue;
4504
4898
  }
4505
4899
  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.`);
4900
+ 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
4901
  continue;
4508
4902
  }
4509
4903
  if (!dep.merged && !isHandClosedByRecognizedPrincipal(dep, principalAllowlist)) {
4510
4904
  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.`);
4905
+ 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
4906
  }
4513
4907
  }
4514
4908
  for (const c of input.conflictsWith) {
4515
4909
  if (c.openOrInFlight) {
4516
4910
  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.`);
4911
+ 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
4912
  }
4519
4913
  }
4520
4914
  for (const proj of input.priorTrancheArchival) {
4521
4915
  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.`);
4916
+ 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
4917
  }
4524
4918
  }
4525
- return { ready: blockers.length === 0, blockers };
4919
+ return { ready: blockerDetails.length === 0, blockers: blockerDetails.map((b) => b.message), blockerDetails };
4526
4920
  }
4527
4921
  // ../../packages/aeg-core/src/single-plan-pr.ts
4528
4922
  function trancheSlugFromTopologyPath(path) {
@@ -4624,6 +5018,137 @@ function checkBranchTopology(input) {
4624
5018
  reason: `Branch \`${branch}\` matches topology row \`${taskId}\` in ${topoPath}.`
4625
5019
  };
4626
5020
  }
5021
+ // ../../packages/aeg-core/src/task-tools.ts
5022
+ import { z } from "zod";
5023
+ var TASK_TOOL_ERROR_KINDS = [
5024
+ "validation",
5025
+ "authority",
5026
+ "precondition",
5027
+ "capability",
5028
+ "infrastructure",
5029
+ "cancellation",
5030
+ "timeout",
5031
+ "uncertain_effect"
5032
+ ];
5033
+ var TaskToolErrorSchema = z.object({
5034
+ kind: z.enum(TASK_TOOL_ERROR_KINDS),
5035
+ message: z.string().min(1),
5036
+ detail: z.string().optional()
5037
+ });
5038
+ var TaskToolRefSchema = z.union([
5039
+ z.object({ tranche: z.string().min(1), id: z.string().min(1) }).strict(),
5040
+ z.object({ issue: z.number().int().positive() }).strict()
5041
+ ]);
5042
+ var MAX_PAGE_LIMIT = 100;
5043
+ var PageRequestSchema = z.object({
5044
+ cursor: z.string().optional(),
5045
+ limit: z.number().int().positive().max(MAX_PAGE_LIMIT).optional()
5046
+ });
5047
+ var FreshnessSchema = z.enum(["fresh", "stale", "unknown"]);
5048
+ var ObservedSchema = z.object({
5049
+ observedAt: z.string(),
5050
+ freshness: FreshnessSchema
5051
+ });
5052
+ var TaskStatusInputSchema = z.object({
5053
+ task: TaskToolRefSchema.optional()
5054
+ }).merge(PageRequestSchema).strict();
5055
+ var TaskStatusItemSchema = z.object({
5056
+ task: TaskToolRefSchema,
5057
+ issue: z.number().int().positive(),
5058
+ pr: z.number().int().positive().nullable(),
5059
+ state: z.string()
5060
+ }).merge(ObservedSchema);
5061
+ var TaskStatusResultSchema = z.object({
5062
+ items: z.array(TaskStatusItemSchema),
5063
+ nextCursor: z.string().nullable()
5064
+ });
5065
+ var RequestedAuthoritySchema = z.enum(["planner", "principal", "operator", "self"]);
5066
+ var EscalationInputsSchema = z.object({
5067
+ task: z.number().int().positive(),
5068
+ round: z.number().int().nonnegative(),
5069
+ head: z.string(),
5070
+ branch: z.string(),
5071
+ prNumber: z.number().int().positive()
5072
+ });
5073
+ var EscalationEvidenceSchema = z.object({
5074
+ round: z.number().int().nonnegative(),
5075
+ reviewer: z.string().nullable(),
5076
+ security: z.string().nullable()
5077
+ });
5078
+ var EscalationRunIdentitySchema = z.object({
5079
+ runId: z.string(),
5080
+ pid: z.number().int().positive(),
5081
+ host: z.string()
5082
+ });
5083
+ var EscalationInputVersionsSchema = z.object({
5084
+ briefHash: z.string().nullable(),
5085
+ objectivesVersion: z.string().nullable(),
5086
+ rulingOrdinal: z.number().int().nonnegative(),
5087
+ policyDigest: z.string()
5088
+ });
5089
+ var TaskEscalationReadInputSchema = z.object({
5090
+ task: TaskToolRefSchema
5091
+ }).merge(PageRequestSchema).strict();
5092
+ var TaskEscalationPacketSchema = z.object({
5093
+ reason: z.string(),
5094
+ detail: z.string().nullable(),
5095
+ inputs: EscalationInputsSchema.nullable(),
5096
+ evidence: EscalationEvidenceSchema.nullable(),
5097
+ attemptedRecovery: z.string(),
5098
+ requestedAuthority: RequestedAuthoritySchema,
5099
+ permittedNextActions: z.array(z.string()),
5100
+ runIdentity: EscalationRunIdentitySchema.nullable(),
5101
+ inputVersions: EscalationInputVersionsSchema.nullable()
5102
+ }).merge(ObservedSchema);
5103
+ var TaskEscalationReadResultSchema = z.object({
5104
+ items: z.array(TaskEscalationPacketSchema),
5105
+ nextCursor: z.string().nullable()
5106
+ }).merge(ObservedSchema);
5107
+ var TaskStartInputSchema = z.object({
5108
+ tranche: z.string().min(1),
5109
+ id: z.string().min(1)
5110
+ }).strict();
5111
+ var TaskStartResultSchema = z.object({
5112
+ requestId: z.string().min(1),
5113
+ run: z.object({ tranche: z.string().min(1), id: z.string().min(1) }),
5114
+ started: z.boolean(),
5115
+ startedAt: z.string(),
5116
+ mode: z.literal("attended")
5117
+ });
5118
+ var TaskResumeInputSchema = z.object({
5119
+ task: TaskToolRefSchema
5120
+ }).strict();
5121
+ var TaskCancelInputSchema = z.object({
5122
+ task: TaskToolRefSchema,
5123
+ reason: z.string().min(1)
5124
+ }).strict();
5125
+ var TaskResumeResultSchema = z.object({
5126
+ task: z.number().int().positive(),
5127
+ pr: z.number().int().positive(),
5128
+ escalationId: z.string().min(1),
5129
+ outcome: z.enum(["started", "already_resumed"]),
5130
+ authenticatedBy: z.string().min(1),
5131
+ authenticatedFrom: z.string().min(1)
5132
+ });
5133
+ var TaskCancelOutcomeSchema = z.enum(["confirmed", "pending", "uncertain"]);
5134
+ var TaskCancelResultSchema = z.object({
5135
+ task: z.number().int().positive(),
5136
+ pr: z.number().int().positive(),
5137
+ escalationId: z.string().min(1),
5138
+ outcome: TaskCancelOutcomeSchema,
5139
+ authenticatedBy: z.string().min(1),
5140
+ authenticatedFrom: z.string().min(1),
5141
+ fencedEffectKeys: z.array(z.string())
5142
+ });
5143
+ var TASK_TOOL_NAMES = [
5144
+ "task_start",
5145
+ "task_status",
5146
+ "task_escalation_read",
5147
+ "task_resume",
5148
+ "task_cancel"
5149
+ ];
5150
+ var OPERATOR_STATUS_FOLLOW = "task_status_follow";
5151
+ var OPERATOR_TOOL_GRANT = [...TASK_TOOL_NAMES, OPERATOR_STATUS_FOLLOW];
4627
5152
  // ../../packages/aeg-core/src/first-push-dispatch-gate.ts
4628
5153
  function parseTaskBranch(branch) {
4629
5154
  const m = /^task\/([^/]+)\/([^/]+)$/.exec(branch);
@@ -4707,7 +5232,6 @@ function decideIssueAssignment(input) {
4707
5232
  };
4708
5233
  }
4709
5234
  // ../../packages/aeg-core/src/test-plan-gate.ts
4710
- var TASK_BRANCH_PATTERN2 = /^task\/[^/]+\/[^/]+$/;
4711
5235
  function evaluateTestPlanGate(body, branch) {
4712
5236
  if (!body) {
4713
5237
  return {
@@ -4720,7 +5244,7 @@ function evaluateTestPlanGate(body, branch) {
4720
5244
  }
4721
5245
  const located = locateTestPlanSection(body);
4722
5246
  if (!located.found) {
4723
- if (TASK_BRANCH_PATTERN2.test(branch)) {
5247
+ if (parseTaskBranchIdentity(branch) !== null) {
4724
5248
  return {
4725
5249
  verdict: "fail",
4726
5250
  messages: [
@@ -4847,8 +5371,11 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
4847
5371
  }
4848
5372
  return findings;
4849
5373
  }
5374
+ // ../../packages/aeg-core/src/log/envelope.ts
5375
+ import { createHash as createHash5 } from "node:crypto";
5376
+
4850
5377
  // ../../packages/aeg-core/src/log/schema.ts
4851
- import { z } from "zod";
5378
+ import { z as z2 } from "zod";
4852
5379
  var ROLE_VALUES = [
4853
5380
  "planner",
4854
5381
  "developer",
@@ -4858,136 +5385,174 @@ var ROLE_VALUES = [
4858
5385
  "archivist",
4859
5386
  "architect"
4860
5387
  ];
4861
- var RoleSchema = z.enum(ROLE_VALUES);
5388
+ var RoleSchema = z2.enum(ROLE_VALUES);
4862
5389
  var HOST_VALUES = ["hook", "ci", "cli", "loop"];
4863
- var HostSchema = z.enum(HOST_VALUES);
5390
+ var HostSchema = z2.enum(HOST_VALUES);
4864
5391
  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(),
5392
+ var headerMetaCore = {
5393
+ ts: z2.string(),
5394
+ run_id: z2.string().regex(RUN_ID_PATTERN),
5395
+ seq: z2.number().int().nonnegative(),
5396
+ repo: z2.string().nullable(),
5397
+ vinaya: z2.string(),
5398
+ doctrine: z2.string(),
4873
5399
  host: HostSchema,
4874
- machine: z.string()
5400
+ machine: z2.string()
5401
+ };
5402
+ var HeaderMetaV1Schema = z2.object({
5403
+ schema: z2.literal(1),
5404
+ ...headerMetaCore
4875
5405
  }).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()
5406
+ var LineageSchema = z2.object({
5407
+ run: z2.string().nullable(),
5408
+ attempt: z2.number().int().nullable(),
5409
+ parent: z2.string().nullable()
4883
5410
  }).strict();
4884
- var HeaderSchema = z.object({
5411
+ var InputVersionsSchema = z2.object({
5412
+ objectives_version: z2.string().nullable(),
5413
+ brief_hash: z2.string().nullable(),
5414
+ ruling_ordinal: z2.number().int().nullable(),
5415
+ policy_digest: z2.string().nullable()
5416
+ }).strict();
5417
+ var ProvenanceSchema = z2.enum(["parent_attributed", "env_correlated", "self_reported", "unavailable"]);
5418
+ var HeaderMetaV2Schema = z2.object({
5419
+ schema: z2.literal(2),
5420
+ ...headerMetaCore,
5421
+ event_id: z2.string().min(1),
5422
+ process_id: z2.string().min(1),
5423
+ actor_id: z2.string().nullable(),
5424
+ lineage: LineageSchema,
5425
+ input_versions: InputVersionsSchema,
5426
+ provenance: ProvenanceSchema
5427
+ }).strict();
5428
+ var HeaderMetaSchema = z2.discriminatedUnion("schema", [HeaderMetaV1Schema, HeaderMetaV2Schema]);
5429
+ var SubjectSchema = z2.object({
5430
+ issue: z2.number().int().nullable(),
5431
+ pr: z2.number().int().optional(),
5432
+ sha: z2.string().optional(),
5433
+ role: z2.union([RoleSchema, z2.literal("unattributed")]),
5434
+ round: z2.number().int().optional(),
5435
+ objectives_version: z2.string().optional()
5436
+ }).strict();
5437
+ var HeaderSchema = z2.object({
4885
5438
  meta: HeaderMetaSchema,
4886
5439
  subject: SubjectSchema
4887
5440
  }).strict();
4888
5441
  var envelopeTail = {
4889
- duration_ms: z.number().nonnegative().optional(),
4890
- payload: z.object({}).strict()
5442
+ duration_ms: z2.number().nonnegative().optional(),
5443
+ payload: z2.object({}).strict()
4891
5444
  };
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()
5445
+ var ReviewFindingSchema = z2.object({
5446
+ id: z2.string(),
5447
+ severity: z2.string(),
5448
+ state: z2.string().optional(),
5449
+ severity_scale: z2.string().optional(),
5450
+ policy_treatment: z2.enum(["blocking", "non_blocking", "unavailable"]).optional(),
5451
+ confidence: z2.number().min(0).max(1).optional(),
5452
+ confidence_scale: z2.string().optional(),
5453
+ confidence_source: z2.string().optional()
5454
+ }).strict();
5455
+ var DispatchOutcomeSchema = z2.discriminatedUnion("type", [
5456
+ z2.object({ type: z2.literal("pr_opened"), pr: z2.number().int(), head: z2.string() }).strict(),
5457
+ z2.object({
5458
+ type: z2.literal("round_pushed"),
5459
+ pr: z2.number().int(),
5460
+ head: z2.string(),
5461
+ comment_id: z2.number().int()
4899
5462
  }).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())
5463
+ z2.object({
5464
+ type: z2.literal("verdict"),
5465
+ verdict: z2.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
5466
+ head: z2.string(),
5467
+ comment_id: z2.number().int(),
5468
+ objectives: z2.array(z2.object({ id: z2.string(), met: z2.boolean() }).strict()),
5469
+ findings: z2.array(ReviewFindingSchema)
4907
5470
  }).strict(),
4908
- z.object({
4909
- type: z.literal("escalation"),
4910
- class: z.enum(["authority", "strategy", "product"]),
4911
- comment_id: z.number().int()
5471
+ z2.object({
5472
+ type: z2.literal("escalation"),
5473
+ class: z2.enum(["authority", "strategy", "product"]),
5474
+ comment_id: z2.number().int()
4912
5475
  }).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()
5476
+ z2.object({ type: z2.literal("brief"), comment_id: z2.number().int(), hash: z2.string() }).strict(),
5477
+ z2.object({ type: z2.literal("plan"), issues: z2.array(z2.number().int()) }).strict(),
5478
+ z2.object({ type: z2.literal("archive"), provenance_comment_id: z2.number().int() }).strict(),
5479
+ z2.object({ type: z2.literal("completed") }).strict()
4916
5480
  ]);
4917
5481
  var dispatchShared = {
4918
5482
  meta: HeaderMetaSchema,
4919
5483
  subject: SubjectSchema,
4920
- kind: z.literal("dispatch"),
5484
+ kind: z2.literal("dispatch"),
4921
5485
  ...envelopeTail,
4922
5486
  target_role: RoleSchema,
4923
- model: z.string(),
4924
- round: z.number().int().optional(),
4925
- effect_id: z.string()
5487
+ model: z2.string(),
5488
+ round: z2.number().int().optional(),
5489
+ effect_id: z2.string()
4926
5490
  };
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({
5491
+ var dispatchUsageField = z2.object({ input: z2.number().nonnegative(), output: z2.number().nonnegative() }).strict().nullable();
5492
+ var DispatchEventSchema = z2.discriminatedUnion("event", [
5493
+ z2.object({ ...dispatchShared, event: z2.literal("dispatched"), prompt_hash: z2.string() }).strict(),
5494
+ z2.object({
4931
5495
  ...dispatchShared,
4932
- event: z.literal("outcome_received"),
5496
+ event: z2.literal("outcome_received"),
4933
5497
  outcome: DispatchOutcomeSchema,
4934
5498
  usage: dispatchUsageField
4935
5499
  }).strict(),
4936
- z.object({
5500
+ z2.object({
4937
5501
  ...dispatchShared,
4938
- event: z.literal("dispatch_failed"),
4939
- reason: z.enum(["timeout", "crash", "refused", "unattributed_write"]),
5502
+ event: z2.literal("dispatch_failed"),
5503
+ reason: z2.enum(["timeout", "crash", "refused", "unattributed_write"]),
4940
5504
  usage: dispatchUsageField
4941
5505
  }).strict()
4942
5506
  ]);
4943
5507
  var loopShared = {
4944
5508
  meta: HeaderMetaSchema,
4945
5509
  subject: SubjectSchema,
4946
- kind: z.literal("dev_review_loop"),
5510
+ kind: z2.literal("dev_review_loop"),
4947
5511
  ...envelopeTail,
4948
- loop_id: z.string()
5512
+ loop_id: z2.string()
4949
5513
  };
4950
- var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
4951
- z.object({
5514
+ var DevReviewLoopEventSchema = z2.discriminatedUnion("event", [
5515
+ z2.object({
4952
5516
  ...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())
5517
+ event: z2.literal("loop_started"),
5518
+ task: z2.number().int(),
5519
+ policy: z2.object({
5520
+ max_rounds: z2.number().int().nonnegative(),
5521
+ reviewers: z2.array(RoleSchema),
5522
+ models: z2.record(RoleSchema, z2.string())
4959
5523
  }).strict()
4960
5524
  }).strict(),
4961
- z.object({ ...loopShared, event: z.literal("round_started"), round: z.number().int(), base_head: z.string() }).strict(),
4962
- z.object({
5525
+ z2.object({ ...loopShared, event: z2.literal("round_started"), round: z2.number().int(), base_head: z2.string() }).strict(),
5526
+ z2.object({
4963
5527
  ...loopShared,
4964
- event: z.literal("gate_result_read"),
4965
- round: z.number().int(),
4966
- head: z.string(),
4967
- green: z.boolean()
5528
+ event: z2.literal("gate_result_read"),
5529
+ round: z2.number().int(),
5530
+ head: z2.string(),
5531
+ green: z2.boolean()
4968
5532
  }).strict(),
4969
- z.object({
5533
+ z2.object({
4970
5534
  ...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()
5535
+ event: z2.literal("verdicts_read"),
5536
+ round: z2.number().int(),
5537
+ head: z2.string(),
5538
+ all_approve: z2.boolean(),
5539
+ blockers: z2.number().int().nonnegative(),
5540
+ findings: z2.array(ReviewFindingSchema).optional()
4976
5541
  }).strict(),
4977
- z.object({
5542
+ z2.object({
4978
5543
  ...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())
5544
+ event: z2.literal("findings_compared"),
5545
+ round: z2.number().int(),
5546
+ open: z2.array(z2.string()),
5547
+ resolved: z2.array(z2.string()),
5548
+ new: z2.array(z2.string()),
5549
+ recurring: z2.array(z2.string())
4985
5550
  }).strict(),
4986
- z.object({
5551
+ z2.object({
4987
5552
  ...loopShared,
4988
- event: z.literal("stop_condition_met"),
4989
- round: z.number().int(),
4990
- condition: z.enum([
5553
+ event: z2.literal("stop_condition_met"),
5554
+ round: z2.number().int(),
5555
+ condition: z2.enum([
4991
5556
  "green",
4992
5557
  "max_rounds",
4993
5558
  "no_progress",
@@ -4997,42 +5562,49 @@ var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
4997
5562
  "reappearance"
4998
5563
  ])
4999
5564
  }).strict(),
5000
- z.object({
5565
+ z2.object({
5001
5566
  ...loopShared,
5002
- event: z.literal("paused"),
5003
- round: z.number().int(),
5004
- reason: z.enum(["escalation", "principal_item", "refreeze_needed"])
5567
+ event: z2.literal("paused"),
5568
+ round: z2.number().int(),
5569
+ reason: z2.enum(["escalation", "principal_item", "refreeze_needed"])
5005
5570
  }).strict(),
5006
- z.object({
5571
+ z2.object({
5007
5572
  ...loopShared,
5008
- event: z.literal("resumed"),
5009
- round: z.number().int(),
5010
- by: z.literal("principal")
5573
+ event: z2.literal("resumed"),
5574
+ round: z2.number().int(),
5575
+ by: z2.literal("principal")
5011
5576
  }).strict(),
5012
- z.object({
5577
+ z2.object({
5013
5578
  ...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"])
5579
+ event: z2.literal("unpushed_work_resume"),
5580
+ round: z2.number().int(),
5581
+ branch: z2.string(),
5582
+ detail: z2.string()
5023
5583
  }).strict(),
5024
- z.object({
5584
+ z2.object({
5025
5585
  ...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"])
5586
+ event: z2.literal("round_ended"),
5587
+ round: z2.number().int(),
5588
+ base_head: z2.string(),
5589
+ head: z2.string(),
5590
+ files_changed: z2.number().int().nonnegative(),
5591
+ insertions: z2.number().int().nonnegative(),
5592
+ deletions: z2.number().int().nonnegative(),
5593
+ wall_ms: z2.number().nonnegative(),
5594
+ outcome: z2.enum(["green", "changes_requested", "escalated"])
5595
+ }).strict(),
5596
+ z2.object({
5597
+ ...loopShared,
5598
+ event: z2.literal("journal_finalized"),
5599
+ rounds: z2.number().int().nonnegative(),
5600
+ total_wall_ms: z2.number().nonnegative(),
5601
+ time_to_green_ms: z2.number().nonnegative().nullable(),
5602
+ files_changed_total: z2.number().int().nonnegative(),
5603
+ final_head: z2.string(),
5604
+ result: z2.enum(["merged_ready", "stopped"])
5033
5605
  }).strict()
5034
5606
  ]);
5035
- var ForgeOpSchema = z.enum([
5607
+ var ForgeOpSchema = z2.enum([
5036
5608
  "pr.create",
5037
5609
  "pr.comment",
5038
5610
  "pr.body.replace",
@@ -5046,54 +5618,466 @@ var ForgeOpSchema = z.enum([
5046
5618
  "label.add",
5047
5619
  "label.remove"
5048
5620
  ]);
5049
- var ForgeWriteTargetSchema = z.object({
5050
- issue: z.number().int().optional(),
5051
- pr: z.number().int().optional()
5621
+ var ForgeWriteTargetSchema = z2.object({
5622
+ issue: z2.number().int().optional(),
5623
+ pr: z2.number().int().optional()
5052
5624
  }).strict();
5053
5625
  var forgeWriteShared = {
5054
5626
  meta: HeaderMetaSchema,
5055
5627
  subject: SubjectSchema,
5056
- kind: z.literal("forge_write"),
5628
+ kind: z2.literal("forge_write"),
5057
5629
  ...envelopeTail,
5058
5630
  op: ForgeOpSchema,
5059
5631
  target: ForgeWriteTargetSchema
5060
5632
  };
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()
5633
+ var ForgeWriteEventSchema = z2.discriminatedUnion("event", [
5634
+ z2.object({ ...forgeWriteShared, event: z2.literal("validated") }).strict(),
5635
+ z2.object({ ...forgeWriteShared, event: z2.literal("refused"), reason: z2.string() }).strict(),
5636
+ z2.object({ ...forgeWriteShared, event: z2.literal("written"), comment_ids: z2.array(z2.string()) }).strict()
5637
+ ]);
5638
+ var GateOutcomeSchema = z2.enum([
5639
+ "pass",
5640
+ "fail",
5641
+ "wait",
5642
+ "skip",
5643
+ "invalid_input",
5644
+ "unavailable_dependency",
5645
+ "timeout",
5646
+ "cancelled"
5647
+ ]);
5648
+ var gateShared = {
5649
+ meta: HeaderMetaSchema,
5650
+ subject: SubjectSchema,
5651
+ kind: z2.literal("gate"),
5652
+ ...envelopeTail,
5653
+ check: z2.string(),
5654
+ check_version: z2.string().nullable(),
5655
+ policy_version: z2.string().nullable(),
5656
+ input_fingerprint: z2.string().nullable()
5657
+ };
5658
+ var GateEventSchema = z2.discriminatedUnion("event", [
5659
+ z2.object({
5660
+ ...gateShared,
5661
+ event: z2.literal("checked"),
5662
+ outcome: GateOutcomeSchema,
5663
+ reason: z2.string().optional()
5664
+ }).strict()
5065
5665
  ]);
5066
- var LogEventSchema = z.union([DispatchEventSchema, DevReviewLoopEventSchema, ForgeWriteEventSchema]);
5666
+ var OperationResultSchema = z2.enum(["ok", "error", "refused", "timeout", "cancelled", "unavailable"]);
5667
+ var operationShared = {
5668
+ meta: HeaderMetaSchema,
5669
+ subject: SubjectSchema,
5670
+ kind: z2.literal("operation"),
5671
+ ...envelopeTail,
5672
+ operation: z2.string(),
5673
+ target: z2.string().nullable()
5674
+ };
5675
+ var OperationEventSchema = z2.discriminatedUnion("event", [
5676
+ z2.object({
5677
+ ...operationShared,
5678
+ event: z2.literal("completed"),
5679
+ result: OperationResultSchema,
5680
+ error_class: z2.string().nullable()
5681
+ }).strict()
5682
+ ]);
5683
+ var UsageUnitsSchema = z2.object({
5684
+ input: z2.number().nonnegative().nullable(),
5685
+ output: z2.number().nonnegative().nullable(),
5686
+ cache: z2.number().nonnegative().nullable()
5687
+ }).strict();
5688
+ var usageShared = {
5689
+ meta: HeaderMetaSchema,
5690
+ subject: SubjectSchema,
5691
+ kind: z2.literal("usage"),
5692
+ ...envelopeTail,
5693
+ model: z2.string().nullable(),
5694
+ source: z2.string(),
5695
+ semantics: z2.enum(["cumulative", "delta"])
5696
+ };
5697
+ var UsageEventSchema = z2.discriminatedUnion("event", [
5698
+ z2.object({
5699
+ ...usageShared,
5700
+ event: z2.literal("observed"),
5701
+ units: UsageUnitsSchema,
5702
+ unknown_reason: z2.string().nullable()
5703
+ }).strict()
5704
+ ]);
5705
+ var RoleAttemptOutcomeSchema = z2.enum([
5706
+ "completed",
5707
+ "incomplete",
5708
+ "infrastructure_failed",
5709
+ "cancelled",
5710
+ "timed_out",
5711
+ "capability_refused"
5712
+ ]);
5713
+ var roleAttemptShared = {
5714
+ meta: HeaderMetaSchema,
5715
+ subject: SubjectSchema,
5716
+ kind: z2.literal("role_attempt"),
5717
+ ...envelopeTail,
5718
+ actor: z2.string().nullable(),
5719
+ attempt: z2.number().int().nullable(),
5720
+ effect_id: z2.string(),
5721
+ model: z2.string().nullable()
5722
+ };
5723
+ var RoleAttemptEventSchema = z2.discriminatedUnion("event", [
5724
+ z2.object({
5725
+ ...roleAttemptShared,
5726
+ event: z2.literal("attempted"),
5727
+ outcome: RoleAttemptOutcomeSchema,
5728
+ usage: dispatchUsageField
5729
+ }).strict()
5730
+ ]);
5731
+ var handoffShared = {
5732
+ meta: HeaderMetaSchema,
5733
+ subject: SubjectSchema,
5734
+ kind: z2.literal("handoff"),
5735
+ ...envelopeTail,
5736
+ class: z2.enum(["authority", "strategy", "product"]),
5737
+ reason: z2.string()
5738
+ };
5739
+ var HandoffEventSchema = z2.discriminatedUnion("event", [
5740
+ z2.object({
5741
+ ...handoffShared,
5742
+ event: z2.literal("raised"),
5743
+ requested_decision: z2.string().nullable()
5744
+ }).strict(),
5745
+ z2.object({
5746
+ ...handoffShared,
5747
+ event: z2.literal("resolved"),
5748
+ resolution: z2.string().nullable(),
5749
+ resolved_by: z2.string().nullable()
5750
+ }).strict()
5751
+ ]);
5752
+ var EffectTargetSchema = z2.object({
5753
+ kind: z2.string(),
5754
+ ref: z2.string()
5755
+ }).strict();
5756
+ var effectShared = {
5757
+ meta: HeaderMetaSchema,
5758
+ subject: SubjectSchema,
5759
+ kind: z2.literal("effect"),
5760
+ ...envelopeTail,
5761
+ effect_id: z2.string(),
5762
+ target: EffectTargetSchema
5763
+ };
5764
+ var EffectEventSchema = z2.discriminatedUnion("event", [
5765
+ z2.object({ ...effectShared, event: z2.literal("attempted") }).strict(),
5766
+ z2.object({ ...effectShared, event: z2.literal("observed"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict(),
5767
+ z2.object({ ...effectShared, event: z2.literal("verified"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict()
5768
+ ]);
5769
+ var LogEventSchema = z2.union([
5770
+ DispatchEventSchema,
5771
+ DevReviewLoopEventSchema,
5772
+ ForgeWriteEventSchema,
5773
+ GateEventSchema,
5774
+ OperationEventSchema,
5775
+ UsageEventSchema,
5776
+ RoleAttemptEventSchema,
5777
+ HandoffEventSchema,
5778
+ EffectEventSchema
5779
+ ]);
5780
+
5781
+ // ../../packages/aeg-core/src/log/envelope.ts
5782
+ function isRole(value) {
5783
+ return value !== undefined && ROLE_VALUES.includes(value);
5784
+ }
5785
+ function actorIdFromEnv(role) {
5786
+ return role === undefined || role === "" ? null : role;
5787
+ }
5788
+ function lineageFieldFromEnv(value) {
5789
+ return value === undefined || value === "" ? null : value;
5790
+ }
5791
+ function attemptFromEnv(value) {
5792
+ if (value === undefined || value === "")
5793
+ return null;
5794
+ const n = Number(value);
5795
+ return Number.isInteger(n) ? n : null;
5796
+ }
5797
+ function provenanceFor(input) {
5798
+ if (input.provenance)
5799
+ return input.provenance;
5800
+ if (input.env.role || input.env.task)
5801
+ return "env_correlated";
5802
+ return "unavailable";
5803
+ }
5804
+ function issueFromTask(task) {
5805
+ if (task === undefined || task === "")
5806
+ return null;
5807
+ const n = Number(task);
5808
+ return Number.isInteger(n) ? n : null;
5809
+ }
5810
+ function roundFromEnv(round) {
5811
+ if (round === undefined || round === "")
5812
+ return;
5813
+ const n = Number(round);
5814
+ return Number.isInteger(n) ? n : undefined;
5815
+ }
5816
+ function buildHeader(input) {
5817
+ const role = isRole(input.env.role) ? input.env.role : "unattributed";
5818
+ const round = roundFromEnv(input.env.round);
5819
+ const subject = {
5820
+ issue: issueFromTask(input.env.task),
5821
+ role,
5822
+ ...round !== undefined ? { round } : {},
5823
+ ...input.subject ?? {}
5824
+ };
5825
+ return {
5826
+ meta: {
5827
+ schema: 2,
5828
+ ts: input.now.toISOString(),
5829
+ run_id: input.runId,
5830
+ seq: input.seq,
5831
+ repo: input.repo,
5832
+ vinaya: input.vinaya,
5833
+ doctrine: input.doctrine,
5834
+ host: input.host,
5835
+ machine: createHash5("sha256").update(input.hostname).digest("hex"),
5836
+ event_id: input.eventId,
5837
+ process_id: input.processId,
5838
+ actor_id: actorIdFromEnv(input.env.role),
5839
+ lineage: {
5840
+ run: lineageFieldFromEnv(input.env.run),
5841
+ attempt: attemptFromEnv(input.env.attempt),
5842
+ parent: lineageFieldFromEnv(input.env.parent)
5843
+ },
5844
+ input_versions: {
5845
+ objectives_version: input.inputVersions?.objectivesVersion ?? null,
5846
+ brief_hash: input.inputVersions?.briefHash ?? null,
5847
+ ruling_ordinal: input.inputVersions?.rulingOrdinal ?? null,
5848
+ policy_digest: input.inputVersions?.policyDigest ?? null
5849
+ },
5850
+ provenance: provenanceFor(input)
5851
+ },
5852
+ subject
5853
+ };
5854
+ }
5855
+ // ../../packages/aeg-core/src/log/redact.ts
5856
+ var GITHUB_TOKEN_PATTERN = /\b(?:gho_|ghp_|ghs_|ghu_|ghr_|github_pat_)[A-Za-z0-9_]+\b/g;
5857
+ var CLASSIC_GITHUB_PAT_PATTERN = /\b((?:token|GITHUB_TOKEN|PAT|api[_-]?key|api[_-]?token)\s*[:=]\s*)[a-f0-9]{40}\b/gi;
5858
+ var BEARER_TOKEN_PATTERN = /\bBearer\s+\S+/g;
5859
+ var AWS_ACCESS_KEY_PATTERN = /\bAKIA[0-9A-Z]{16}\b/g;
5860
+ var SLACK_TOKEN_PATTERN = /\bxox[baprs]-[0-9A-Za-z-]+\b/g;
5861
+ var STRIPE_KEY_PATTERN = /\b(?:sk|pk|rk)_(?:live|test)_[0-9A-Za-z]{10,}\b/g;
5862
+ var ANTHROPIC_KEY_PATTERN = /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g;
5863
+ var OPENAI_KEY_PATTERN = /\bsk-(?!ant-)[A-Za-z0-9]{20,}\b/g;
5864
+ var NPM_TOKEN_PATTERN = /\bnpm_[A-Za-z0-9]{36}\b/g;
5865
+ var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g;
5866
+ var PEM_BLOCK_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g;
5867
+ var BASIC_AUTH_URL_PATTERN = /(https?:\/\/)[^/\s:@]+:[^/\s@]+@/g;
5868
+ var GENERIC_SECRET_ASSIGNMENT_PATTERN = /\b((?:secret|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)\s*[:=]\s*)[A-Za-z0-9+/_=-]{16,}\b/gi;
5869
+ function redactString(value, home) {
5870
+ let out = value.replace(GITHUB_TOKEN_PATTERN, "<redacted>").replace(CLASSIC_GITHUB_PAT_PATTERN, "$1<redacted>").replace(BEARER_TOKEN_PATTERN, "<redacted>").replace(AWS_ACCESS_KEY_PATTERN, "<redacted>").replace(SLACK_TOKEN_PATTERN, "<redacted>").replace(STRIPE_KEY_PATTERN, "<redacted>").replace(ANTHROPIC_KEY_PATTERN, "<redacted>").replace(OPENAI_KEY_PATTERN, "<redacted>").replace(NPM_TOKEN_PATTERN, "<redacted>").replace(JWT_PATTERN, "<redacted>").replace(PEM_BLOCK_PATTERN, "<redacted>").replace(BASIC_AUTH_URL_PATTERN, "$1<redacted>@").replace(GENERIC_SECRET_ASSIGNMENT_PATTERN, "$1<redacted>");
5871
+ if (home.length > 0 && out.startsWith(home)) {
5872
+ const rest = out.slice(home.length);
5873
+ if (rest === "" || rest.startsWith("/"))
5874
+ out = `~${rest}`;
5875
+ }
5876
+ return out;
5877
+ }
5878
+ function redact(value, home) {
5879
+ if (typeof value === "string")
5880
+ return redactString(value, home);
5881
+ if (Array.isArray(value))
5882
+ return value.map((v) => redact(v, home));
5883
+ if (value !== null && typeof value === "object") {
5884
+ const out = {};
5885
+ for (const [k, v] of Object.entries(value)) {
5886
+ out[k] = redact(v, home);
5887
+ }
5888
+ return out;
5889
+ }
5890
+ return value;
5891
+ }
5892
+ // ../../packages/aeg-core/src/log/store.ts
5893
+ function metaOf(obj) {
5894
+ if (obj === null || typeof obj !== "object")
5895
+ return null;
5896
+ const meta = obj.meta;
5897
+ if (meta === null || typeof meta !== "object")
5898
+ return null;
5899
+ return meta;
5900
+ }
5901
+ function recordIdentity(obj) {
5902
+ const meta = metaOf(obj);
5903
+ if (meta === null)
5904
+ return null;
5905
+ const eventId = meta.event_id;
5906
+ if (typeof eventId === "string" && eventId.length > 0)
5907
+ return eventId;
5908
+ const runId = meta.run_id;
5909
+ const seq = meta.seq;
5910
+ if (typeof runId === "string" && runId.length > 0 && typeof seq === "number" && Number.isInteger(seq)) {
5911
+ return `${runId}:${seq}`;
5912
+ }
5913
+ return null;
5914
+ }
5915
+
5916
+ // ../../packages/aeg-core/src/log/artifact.ts
5917
+ var TASK_LOG_ARTIFACT_MAX_BYTES = 8 * 1024 * 1024;
5918
+ // ../../packages/aeg-core/src/dev-review-loop/journal-reconstruction.ts
5919
+ var STOPPED_CONDITIONS = new Set(["confidence", "reappearance", "no_progress", "max_rounds"]);
5920
+ // ../../packages/aeg-core/src/control-store/records.ts
5921
+ import { z as z3 } from "zod";
5922
+ var isoTimestamp = z3.string().min(1);
5923
+ var taskId = z3.number().int().positive();
5924
+ var epochNumber = z3.number().int().nonnegative();
5925
+ var RunRecordSchema = z3.object({
5926
+ version: z3.literal(1),
5927
+ kind: z3.literal("run"),
5928
+ task: taskId,
5929
+ runId: z3.string().min(1),
5930
+ pid: z3.number().int().positive(),
5931
+ host: z3.string().min(1),
5932
+ startedAt: isoTimestamp,
5933
+ childStartedAt: z3.string().min(1).nullable().optional(),
5934
+ childCommand: z3.string().min(1).nullable().optional()
5935
+ }).strict();
5936
+ var InputRecordSchema = z3.object({
5937
+ version: z3.literal(1),
5938
+ kind: z3.literal("input"),
5939
+ task: taskId,
5940
+ runId: z3.string().min(1),
5941
+ source: z3.union([z3.literal("fresh"), z3.literal("resume")]),
5942
+ pr: z3.number().int().positive().nullable(),
5943
+ round: z3.number().int().nonnegative(),
5944
+ recordedAt: isoTimestamp
5945
+ }).strict();
5946
+ var OwnershipRecordSchema = z3.object({
5947
+ version: z3.literal(1),
5948
+ kind: z3.literal("ownership"),
5949
+ task: taskId,
5950
+ epoch: epochNumber,
5951
+ ownerId: z3.string().min(1),
5952
+ pid: z3.number().int().positive(),
5953
+ host: z3.string().min(1),
5954
+ acquiredAt: isoTimestamp
5955
+ }).strict();
5956
+ var TransitionRecordSchema = z3.object({
5957
+ version: z3.literal(1),
5958
+ kind: z3.literal("transition"),
5959
+ task: taskId,
5960
+ epoch: epochNumber,
5961
+ seq: z3.number().int().nonnegative(),
5962
+ from: z3.string().min(1),
5963
+ to: z3.string().min(1),
5964
+ detail: z3.string().optional(),
5965
+ at: isoTimestamp
5966
+ }).strict();
5967
+ var ManifestRecordSchema = z3.object({
5968
+ version: z3.literal(1),
5969
+ kind: z3.literal("manifest"),
5970
+ task: taskId,
5971
+ round: epochNumber,
5972
+ repository: z3.string().min(1),
5973
+ pr: z3.number().int().positive(),
5974
+ branch: z3.string().min(1),
5975
+ baseSha: z3.string().min(1).nullable(),
5976
+ headSha: z3.string().min(1),
5977
+ briefHash: z3.string().min(1).nullable(),
5978
+ objectivesVersion: z3.string().min(1).nullable(),
5979
+ rulingOrdinal: epochNumber,
5980
+ policyDigest: z3.string().min(1),
5981
+ recordedAt: isoTimestamp
5982
+ }).strict();
5983
+ var roundHeadIdentity = z3.object({ round: z3.number().int().positive(), head: z3.string().min(1) }).strict();
5984
+ var LoopBudgetsSchema = z3.object({
5985
+ mechanicalRetries: z3.number().int().nonnegative(),
5986
+ reviewRounds: z3.number().int().nonnegative(),
5987
+ infrastructureRetries: z3.number().int().nonnegative()
5988
+ }).strict();
5989
+ var LoopStateRecordSchema = z3.object({
5990
+ version: z3.literal(1),
5991
+ kind: z3.literal("loop_state"),
5992
+ task: taskId,
5993
+ round: z3.number().int().positive(),
5994
+ phase: z3.string().min(1),
5995
+ pauseReason: z3.string().min(1).nullable(),
5996
+ budgets: LoopBudgetsSchema,
5997
+ heldResult: roundHeadIdentity.nullable(),
5998
+ deliveredFindings: roundHeadIdentity.nullable(),
5999
+ recordedAt: isoTimestamp
6000
+ }).strict();
6001
+ var EffectRecordSchema = z3.object({
6002
+ version: z3.literal(1),
6003
+ kind: z3.literal("effect"),
6004
+ task: taskId,
6005
+ key: z3.string().min(1),
6006
+ operation: z3.string().min(1),
6007
+ target: z3.string().min(1),
6008
+ inputVersion: z3.number().int().nonnegative(),
6009
+ payloadDigest: z3.string().min(1),
6010
+ status: z3.union([z3.literal("started"), z3.literal("verified"), z3.literal("uncertain")]),
6011
+ url: z3.string().optional(),
6012
+ recordedAt: isoTimestamp
6013
+ }).strict();
6014
+ var EscalationRecordSchema = z3.object({
6015
+ version: z3.literal(1),
6016
+ kind: z3.literal("escalation"),
6017
+ task: taskId,
6018
+ escalationId: z3.string().min(1),
6019
+ round: epochNumber,
6020
+ head: z3.string().min(1),
6021
+ branch: z3.string().min(1),
6022
+ pr: z3.number().int().positive().nullable(),
6023
+ runId: z3.string().min(1),
6024
+ pid: z3.number().int().positive(),
6025
+ host: z3.string().min(1),
6026
+ agent: z3.string().min(1).optional(),
6027
+ reason: z3.string().min(1),
6028
+ detail: z3.string().optional(),
6029
+ evidence: z3.string().optional(),
6030
+ attemptedRecovery: z3.string().min(1),
6031
+ requestedDecision: z3.string().min(1),
6032
+ recipient: z3.string().min(1),
6033
+ briefHash: z3.string().min(1).nullable(),
6034
+ objectivesVersion: z3.string().min(1).nullable(),
6035
+ rulingOrdinal: epochNumber,
6036
+ policyDigest: z3.string().min(1),
6037
+ recordedAt: isoTimestamp
6038
+ }).strict();
6039
+ var ResolutionRecordSchema = z3.object({
6040
+ version: z3.literal(1),
6041
+ kind: z3.literal("resolution"),
6042
+ task: taskId,
6043
+ escalationId: z3.string().min(1),
6044
+ decision: z3.union([z3.literal("resume"), z3.literal("cancel")]),
6045
+ authenticatedBy: z3.string().min(1),
6046
+ authenticatedFrom: z3.string().min(1),
6047
+ consumedAt: isoTimestamp
6048
+ }).strict();
5067
6049
  // 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";
6050
+ import { execFileSync as execFileSync6 } from "node:child_process";
6051
+ import { join as join5, relative, resolve as resolve2 } from "node:path";
5070
6052
 
5071
6053
  // src/lib/config.ts
5072
6054
  import { execFileSync as execFileSync2 } from "node:child_process";
5073
6055
  import { existsSync, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "node:fs";
5074
6056
  import { homedir } from "node:os";
5075
6057
  import { dirname, join, resolve } from "node:path";
5076
- import { z as z2 } from "zod";
6058
+ import { z as z4 } from "zod";
5077
6059
 
5078
6060
  // src/lib/agent-vendors.ts
5079
6061
  var AGENT_VENDORS = ["skills", "claude", "gemini"];
5080
6062
 
5081
6063
  // 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()
6064
+ var EnvEntrySchema = z4.union([
6065
+ z4.literal(true),
6066
+ z4.object({ optional: z4.literal(true) }),
6067
+ z4.object({ anyOf: z4.array(z4.string()).min(2) }),
6068
+ z4.string()
5087
6069
  ]);
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()
6070
+ var CheckEntrySchema = z4.object({
6071
+ run: z4.string(),
6072
+ scope: z4.enum(["diff", "full"]),
6073
+ include: z4.array(z4.string()).optional(),
6074
+ args: z4.array(z4.string()).optional(),
6075
+ timeoutMs: z4.number().optional(),
6076
+ env: z4.record(z4.string(), EnvEntrySchema).optional(),
6077
+ requiresOpenPr: z4.boolean().optional(),
6078
+ ownWorkflow: z4.boolean().optional(),
6079
+ principalOwed: z4.literal(true).optional(),
6080
+ validates: z4.enum(["body", "issue"]).optional()
5097
6081
  }).superRefine((entry2, ctx) => {
5098
6082
  if (!entry2.env)
5099
6083
  return;
@@ -5103,25 +6087,26 @@ var CheckEntrySchema = z2.object({
5103
6087
  const members = value.anyOf;
5104
6088
  if (new Set(members).size !== members.length) {
5105
6089
  ctx.addIssue({
5106
- code: z2.ZodIssueCode.custom,
6090
+ code: z4.ZodIssueCode.custom,
5107
6091
  message: `env.${key}.anyOf has duplicate members`,
5108
6092
  path: ["env", key, "anyOf"]
5109
6093
  });
5110
6094
  }
5111
6095
  if (!members.includes(key)) {
5112
6096
  ctx.addIssue({
5113
- code: z2.ZodIssueCode.custom,
6097
+ code: z4.ZodIssueCode.custom,
5114
6098
  message: `env.${key}.anyOf must include "${key}" itself as a member`,
5115
6099
  path: ["env", key, "anyOf"]
5116
6100
  });
5117
6101
  }
5118
6102
  }
5119
6103
  });
5120
- var RoleEntrySchema = z2.object({
5121
- contract: z2.string().refine((p) => p.includes("/"), {
6104
+ var RoleEntrySchema = z4.object({
6105
+ contract: z4.string().refine((p) => p.includes("/"), {
5122
6106
  message: 'must be a path (contain at least one "/"), not a bare filename'
5123
6107
  })
5124
6108
  });
6109
+ var MAX_REPORT_COMMAND_TIMEOUT_MS = 3600000;
5125
6110
  var BRIEF_BUILTINS = [
5126
6111
  "tier",
5127
6112
  "testPlan",
@@ -5141,17 +6126,17 @@ var BRIEF_BUILTINS = [
5141
6126
  "briefSections",
5142
6127
  "milestoneShape"
5143
6128
  ];
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() })
6129
+ var BriefSectionSchema = z4.union([
6130
+ z4.object({ builtin: z4.enum(BRIEF_BUILTINS) }),
6131
+ z4.object({ heading: z4.string().min(1), name: z4.string().optional() }),
6132
+ z4.object({ field: z4.string().min(1), name: z4.string().optional() }),
6133
+ z4.object({ phrase: z4.string().min(1), name: z4.string().optional() })
5149
6134
  ]);
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()
6135
+ var BriefSchemaSchema = z4.object({
6136
+ pr: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
6137
+ issue: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
6138
+ milestone: z4.object({ sections: z4.array(BriefSectionSchema) }).optional(),
6139
+ ack: z4.array(z4.enum(BRIEF_BUILTINS)).optional()
5155
6140
  });
5156
6141
  function isSafeRepoRelPath(p) {
5157
6142
  if (p.length === 0)
@@ -5160,7 +6145,7 @@ function isSafeRepoRelPath(p) {
5160
6145
  return false;
5161
6146
  return p.split(/[\\/]/).every((seg) => seg !== ".." && seg !== "");
5162
6147
  }
5163
- var SafeRepoRelPath = z2.string().refine(isSafeRepoRelPath, {
6148
+ var SafeRepoRelPath = z4.string().refine(isSafeRepoRelPath, {
5164
6149
  message: "must be a repo-root-relative path with no `..` segment or absolute root"
5165
6150
  });
5166
6151
  var CANONICAL_HOOK_BLOCK_PREFIXES = [".git/", ".husky/", ".vinaya/hooks/", ".claude/hooks/"];
@@ -5170,22 +6155,22 @@ function isCanonicalHookBlockPath(p) {
5170
6155
  var ManagedHookBlockPath = SafeRepoRelPath.refine(isCanonicalHookBlockPath, {
5171
6156
  message: `must start with one of ${CANONICAL_HOOK_BLOCK_PREFIXES.join(", ")} (byte-exact, case-sensitive)`
5172
6157
  });
5173
- var ManagedBlockRecordSchema = z2.object({
6158
+ var ManagedBlockRecordSchema = z4.object({
5174
6159
  path: ManagedHookBlockPath,
5175
- marker: z2.string(),
5176
- comment: z2.enum(["hash", "html"])
6160
+ marker: z4.string(),
6161
+ comment: z4.enum(["hash", "html"])
5177
6162
  });
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()
6163
+ var ManagedManifestSchema = z4.object({
6164
+ version: z4.number().int().positive(),
6165
+ files: z4.array(SafeRepoRelPath),
6166
+ blocks: z4.array(ManagedBlockRecordSchema),
6167
+ labels: z4.array(z4.string()),
6168
+ agents: z4.array(z4.enum(AGENT_VENDORS)).optional()
5184
6169
  });
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()
6170
+ var ProjectEntrySchema = z4.object({
6171
+ name: z4.string().min(1),
6172
+ description: z4.string().min(1).optional(),
6173
+ path: z4.string().min(1).optional()
5189
6174
  });
5190
6175
  function parseTokensCollectDeclaration(value) {
5191
6176
  const m = value.trim().match(/^(\S+)\s+(\S+)$/);
@@ -5196,34 +6181,62 @@ function parseTokensCollectDeclaration(value) {
5196
6181
  return null;
5197
6182
  return { interpreter, script };
5198
6183
  }
5199
- var VinayaConfigSchema = z2.object({
5200
- rings: z2.object({
5201
- ring1_forgeWriteInterception: z2.boolean(),
5202
- ring2_asyncAudits: z2.boolean()
6184
+ var VinayaConfigSchema = z4.object({
6185
+ rings: z4.object({
6186
+ ring1_forgeWriteInterception: z4.boolean(),
6187
+ ring2_asyncAudits: z4.boolean()
5203
6188
  }).optional(),
5204
- checks: z2.record(z2.string(), CheckEntrySchema).optional(),
5205
- roles: z2.record(z2.string(), RoleEntrySchema).optional(),
6189
+ checks: z4.record(z4.string(), CheckEntrySchema).optional(),
6190
+ roles: z4.record(z4.string(), RoleEntrySchema).optional(),
5206
6191
  briefSchema: BriefSchemaSchema.optional(),
5207
6192
  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, {
6193
+ principals: z4.array(z4.string()).min(1).optional(),
6194
+ releaseActor: z4.string().min(1).optional(),
6195
+ ci: z4.object({ setup: z4.string().min(1) }).optional(),
6196
+ tokens: z4.object({
6197
+ collect: z4.string().min(1).refine((v) => parseTokensCollectDeclaration(v) !== null, {
5213
6198
  message: 'tokens.collect must be exactly "<interpreter> <repo-relative-script-path>" — two whitespace-separated tokens, no flags, no shell syntax, no quoting'
5214
6199
  })
5215
6200
  }).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()
6201
+ blastRadius: z4.object({ extraDomains: z4.array(z4.string()).optional() }).optional(),
6202
+ proseGates: z4.object({
6203
+ doctrineRoot: z4.string().min(1).optional(),
6204
+ readerFacingPrefix: z4.string().min(1).optional(),
6205
+ readerFacingSuffix: z4.string().min(1).optional(),
6206
+ legacySlugDir: z4.string().min(1).optional()
6207
+ }).optional(),
6208
+ projects: z4.array(ProjectEntrySchema).optional(),
6209
+ dispatch: z4.object({
6210
+ timeoutMs: z4.number().int().positive().optional(),
6211
+ killGraceMs: z4.number().int().positive().optional(),
6212
+ agent: z4.enum(["claude", "codex", "gemini"]).optional()
6213
+ }).optional(),
6214
+ reviewPolicy: z4.object({
6215
+ codeReviewThreshold: z4.string().min(1).optional(),
6216
+ securityThreshold: z4.string().min(1).optional(),
6217
+ maxRounds: z4.number().optional()
5222
6218
  }).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()
6219
+ prePush: z4.object({
6220
+ alwaysRun: z4.array(z4.string()).optional()
6221
+ }).optional(),
6222
+ report: z4.object({
6223
+ commandTimeoutMs: z4.number().int().positive().optional()
6224
+ }).superRefine((report, ctx) => {
6225
+ const commandTimeoutMs = report.commandTimeoutMs;
6226
+ if (commandTimeoutMs !== undefined && commandTimeoutMs > MAX_REPORT_COMMAND_TIMEOUT_MS) {
6227
+ ctx.addIssue({
6228
+ code: z4.ZodIssueCode.custom,
6229
+ path: ["commandTimeoutMs"],
6230
+ message: "must be at most 3600000 (1 hour)"
6231
+ });
6232
+ }
6233
+ }).optional(),
6234
+ logPublish: z4.object({
6235
+ issue: z4.number().int().positive().optional(),
6236
+ pr: z4.number().int().positive().optional(),
6237
+ maxChunksPerFlush: z4.number().int().positive().optional()
6238
+ }).refine((v) => !(v.issue !== undefined && v.pr !== undefined), {
6239
+ message: "logPublish: set at most one of issue/pr, not both"
5227
6240
  }).optional()
5228
6241
  });
5229
6242
  var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
@@ -5298,6 +6311,28 @@ function resolvePrincipalAllowlist(config) {
5298
6311
  function resolveReleaseActor(config) {
5299
6312
  return config?.releaseActor ?? DEFAULT_RELEASE_ACTOR;
5300
6313
  }
6314
+ function resolveReviewPolicy(config) {
6315
+ const raw = config?.reviewPolicy;
6316
+ if (!raw)
6317
+ return DEFAULT_REVIEW_POLICY;
6318
+ const codeReviewThreshold = raw.codeReviewThreshold ?? DEFAULT_REVIEW_POLICY.codeReviewThreshold;
6319
+ if (!isKnownSeverity(CODE_REVIEW_SEVERITY_ORDER, codeReviewThreshold)) {
6320
+ 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.`);
6321
+ }
6322
+ const securityThreshold = raw.securityThreshold ?? DEFAULT_REVIEW_POLICY.securityThreshold;
6323
+ if (!isKnownSeverity(SECURITY_SEVERITY_ORDER, securityThreshold)) {
6324
+ 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.`);
6325
+ }
6326
+ const maxRounds = raw.maxRounds ?? DEFAULT_REVIEW_POLICY.maxRounds;
6327
+ if (!Number.isInteger(maxRounds) || maxRounds < 1) {
6328
+ throw new Error(`vinaya.config.json: reviewPolicy.maxRounds "${maxRounds}" is not a positive integer — fix the config, this never falls back to a default.`);
6329
+ }
6330
+ return {
6331
+ codeReviewThreshold,
6332
+ securityThreshold,
6333
+ maxRounds
6334
+ };
6335
+ }
5301
6336
  function trustAnchorRepo() {
5302
6337
  const wellFormed = (slug) => /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
5303
6338
  const fromRunner = process.env.GITHUB_REPOSITORY?.trim();
@@ -5377,6 +6412,9 @@ function loadConfig() {
5377
6412
  }
5378
6413
  var TOKENS_COLLECT_TRUST_PATH = join(GLOBAL_VINAYA_HOME, "tokens-collect-trust.json");
5379
6414
 
6415
+ // src/lib/brief-assembly.ts
6416
+ import { execFileSync as execFileSync4 } from "node:child_process";
6417
+
5380
6418
  // ../../packages/sources/src/commands.ts
5381
6419
  var COMMANDS = [
5382
6420
  {
@@ -5535,6 +6573,27 @@ var COMMANDS = [
5535
6573
  ],
5536
6574
  status: "shipped"
5537
6575
  },
6576
+ {
6577
+ name: "task status",
6578
+ description: "Every open task with a frozen brief, its pull request, and whether its loop is running, paused, or published",
6579
+ flags: [{ flag: "--json", description: "Enveloped JSON output (schema: 1)" }],
6580
+ details: [
6581
+ "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`.",
6582
+ "`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.",
6583
+ "`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."
6584
+ ],
6585
+ status: "shipped"
6586
+ },
6587
+ {
6588
+ name: "task-tools serve",
6589
+ description: "Run the task-operator MCP tool server over stdio — the command both runtime adapters register",
6590
+ details: [
6591
+ "Exposes the task-operator tool catalog (`packages/aeg-core/src/task-tools.ts`) to an agent runtime as one MCP server speaking newline-delimited JSON-RPC 2.0 (`initialize`/`tools/list`/`tools/call`). Claude registers it through the generated `.mcp.json`; Codex through its documented `~/.codex/config.toml` `[mcp_servers]` table — both point at this same command.",
6592
+ "stdout carries JSON-RPC and nothing else: any stray write from the CLI (a forge-read warning) is redirected to stderr, so the protocol stream is never corrupted.",
6593
+ "`task_status`/`task_escalation_read` read; `task_start` starts a run in attended mode only, requiring an authenticated caller from the invocation context (`VINAYA_MCP_CALLER`) and refusing without one — MCP is a transport, not authorization. `task_resume`/`task_cancel` require the same authenticated caller, plus a current Principal ruling read fresh from the run's own PR — never a caller-supplied approval; `task_resume` triggers the existing `dev-review-loop --resume` continuation exactly once per escalation, and `task_cancel` reports a truthful `confirmed`/`pending`/`uncertain` outcome, idempotently, across repeated calls. No unattended start until the worker-isolation boundary and a capability flag land."
6594
+ ],
6595
+ status: "shipped"
6596
+ },
5538
6597
  {
5539
6598
  name: "pr create",
5540
6599
  description: "Open a pull request after full brief-schema validation",
@@ -5679,6 +6738,30 @@ var COMMANDS = [
5679
6738
  ],
5680
6739
  status: "shipped"
5681
6740
  },
6741
+ {
6742
+ name: "log export-artifact",
6743
+ description: "Copy this run's own local outbox into a file, for the generated task-path workflow's own upload step",
6744
+ flags: [],
6745
+ details: [
6746
+ "Concatenates every `*.ndjson` file under `~/.vinaya/outbox/` into `<dest>`, verbatim — no filtering, no second redaction pass (lines are already redacted at `log()`'s own write boundary). Writes nothing when the outbox is empty, and exits 0 either way: no gate events this run is a legitimate outcome, never a failure.",
6747
+ "Runs inside the generated `vinaya-checks.yml` job, which holds no forge-write credential — this command never calls the forge. Both this step and the `actions/upload-artifact` step after it run `if: always()`, so a cancelled or failed job still exports whatever partial outbox it has."
6748
+ ],
6749
+ status: "shipped"
6750
+ },
6751
+ {
6752
+ name: "log collect-artifact",
6753
+ description: "Validate a downloaded task-log artifact and publish the valid records through the existing flush path",
6754
+ flags: [
6755
+ { flag: "--pr", description: "The pull request this artifact belongs to" },
6756
+ { flag: "--repo", description: "Expected `owner/repo` — a provenance cross-check against each record" }
6757
+ ],
6758
+ details: [
6759
+ "Runs inside the generated `vinaya-task-log-collector.yml` workflow — a `workflow_run`-triggered job on the default branch, holding the write credential the task-path job that produced the artifact never gets. `<path>` is already downloaded by that workflow, scoped to a specific, API-verified run id — a provenance guarantee this command never re-derives from the artifact bytes.",
6760
+ "Never executes, imports, or evaluates the artifact's content: every line is read as text and validated (schema, an 8 MiB whole-artifact size cap, redaction, and a repo cross-check) before anything is trusted. A rejected line becomes a named gap — printed, never a silent drop — and the artifact is never partially trusted past that check into executing anything.",
6761
+ "The valid, re-redacted survivors are appended into the same local outbox `vinaya log flush` would read for that PR's Issue, then published through the existing `flushOutbox` unmodified — reusing its chunking, its `<!-- aeg:log:… -->` marker, and its idempotent-retry read, rather than a second publisher. A retried collector run (a fresh runner, the same forge state) therefore dedupes for free: the marker already on the forge is acknowledged, never re-posted."
6762
+ ],
6763
+ status: "shipped"
6764
+ },
5682
6765
  {
5683
6766
  name: "milestone create",
5684
6767
  description: "Create a GitHub Milestone from a validated body",
@@ -6044,10 +7127,10 @@ function createForgeSource(config) {
6044
7127
  };
6045
7128
  }
6046
7129
  // ../../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() })
7130
+ import { z as z5 } from "zod";
7131
+ var StateSourceConfigSchema = z5.discriminatedUnion("kind", [
7132
+ z5.object({ kind: z5.literal("forge"), owner: z5.string(), repo: z5.string() }),
7133
+ z5.object({ kind: z5.literal("file"), root: z5.string().optional() })
6051
7134
  ]);
6052
7135
  // src/checks/edge-resolve.ts
6053
7136
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -6167,6 +7250,826 @@ async function resolveEdge(id, taskById, factsByTaskId, repo, resolveSibling = d
6167
7250
  };
6168
7251
  }
6169
7252
 
7253
+ // src/lib/brief-assembly.ts
7254
+ function git(args) {
7255
+ try {
7256
+ return execFileSync4("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
7257
+ } catch {
7258
+ return "";
7259
+ }
7260
+ }
7261
+ function expandGlob(glob) {
7262
+ const out = git(["ls-files", "--", glob]);
7263
+ return out.split(`
7264
+ `).map((s) => s.trim()).filter(Boolean);
7265
+ }
7266
+ var DRAFT_ISSUE_SENTINEL = Number.MAX_SAFE_INTEGER;
7267
+
7268
+ // src/checks/registry.ts
7269
+ import { existsSync as existsSync3 } from "node:fs";
7270
+ import { join as join3 } from "node:path";
7271
+
7272
+ // src/lib/package-root.ts
7273
+ import { existsSync as existsSync2 } from "node:fs";
7274
+ import { dirname as dirname2, join as join2 } from "node:path";
7275
+ import { fileURLToPath } from "node:url";
7276
+ function packageRoot(moduleUrl) {
7277
+ let dir = dirname2(fileURLToPath(moduleUrl));
7278
+ while (!existsSync2(join2(dir, "package.json"))) {
7279
+ if (existsSync2(join2(dir, ".git")))
7280
+ break;
7281
+ const parent = dirname2(dir);
7282
+ if (parent === dir)
7283
+ break;
7284
+ dir = parent;
7285
+ }
7286
+ return dir;
7287
+ }
7288
+
7289
+ // src/checks/registry.ts
7290
+ var DIST_BIN_DIR = join3(packageRoot(import.meta.url), "dist", "checks", "bin");
7291
+ var SRC_BIN_DIR = join3(packageRoot(import.meta.url), "src", "checks", "bin");
7292
+ var BIN_DIR = existsSync3(DIST_BIN_DIR) ? DIST_BIN_DIR : SRC_BIN_DIR;
7293
+ var BIN_EXT = BIN_DIR === DIST_BIN_DIR ? ".js" : ".ts";
7294
+ function bin(name) {
7295
+ return join3(BIN_DIR, `${name}${BIN_EXT}`);
7296
+ }
7297
+ var REGISTRY = [
7298
+ [
7299
+ {
7300
+ name: "brief-shape",
7301
+ validates: "body",
7302
+ run: bin("check-brief-shape"),
7303
+ scope: "diff",
7304
+ timeoutMs: 15000,
7305
+ env: {
7306
+ PR_BODY: { optional: true },
7307
+ BRANCH: { optional: true },
7308
+ PR_NUMBER: { optional: true },
7309
+ GITHUB_TOKEN: { optional: true },
7310
+ GH_TOKEN: { optional: true }
7311
+ }
7312
+ },
7313
+ 0
7314
+ ],
7315
+ [
7316
+ {
7317
+ name: "pr-report-density",
7318
+ validates: "body",
7319
+ run: bin("check-pr-report-density"),
7320
+ scope: "diff",
7321
+ timeoutMs: 15000,
7322
+ env: {
7323
+ PR_BODY: { optional: true }
7324
+ }
7325
+ },
7326
+ 0
7327
+ ],
7328
+ [
7329
+ {
7330
+ name: "doc-coverage",
7331
+ validates: "body",
7332
+ run: bin("check-doc-coverage"),
7333
+ scope: "diff",
7334
+ timeoutMs: 15000,
7335
+ env: {
7336
+ BASE_SHA: { optional: true },
7337
+ PR_BODY: { optional: true },
7338
+ PR_BODY_FILE: { optional: true },
7339
+ PR_NUMBER: { optional: true },
7340
+ GITHUB_REPOSITORY: { optional: true },
7341
+ GITHUB_TOKEN: { optional: true },
7342
+ GH_TOKEN: { optional: true }
7343
+ }
7344
+ },
7345
+ 0
7346
+ ],
7347
+ [
7348
+ {
7349
+ name: "coherence",
7350
+ run: bin("check-coherence"),
7351
+ scope: "full",
7352
+ timeoutMs: 30000,
7353
+ env: {
7354
+ AEG_REPO: { optional: true },
7355
+ BRANCH: { optional: true },
7356
+ GITHUB_TOKEN: { optional: true },
7357
+ GH_TOKEN: { optional: true }
7358
+ }
7359
+ },
7360
+ 0
7361
+ ],
7362
+ [
7363
+ {
7364
+ name: "pr-premise-reassert",
7365
+ validates: "body",
7366
+ run: bin("check-pr-premise-reassert"),
7367
+ scope: "diff",
7368
+ timeoutMs: 15000,
7369
+ env: {
7370
+ PR_BODY: { optional: true }
7371
+ }
7372
+ },
7373
+ 0
7374
+ ],
7375
+ [
7376
+ {
7377
+ name: "dispatch-readiness",
7378
+ run: bin("check-dispatch-readiness"),
7379
+ scope: "full",
7380
+ timeoutMs: 30000,
7381
+ env: {
7382
+ AEG_REPO: { optional: true },
7383
+ BRANCH: { optional: true },
7384
+ GITHUB_TOKEN: { optional: true },
7385
+ GH_TOKEN: { optional: true },
7386
+ PREMISE_FILE: { optional: true }
7387
+ }
7388
+ },
7389
+ 0
7390
+ ],
7391
+ [
7392
+ {
7393
+ name: "closes-n",
7394
+ validates: "body",
7395
+ run: bin("check-closes-n"),
7396
+ scope: "diff",
7397
+ timeoutMs: 15000,
7398
+ requiresOpenPr: true,
7399
+ env: {
7400
+ BRANCH: { optional: true },
7401
+ PR_BODY: { optional: true },
7402
+ AEG_REPO: { optional: true },
7403
+ GITHUB_TOKEN: { optional: true },
7404
+ GH_TOKEN: { optional: true }
7405
+ }
7406
+ },
7407
+ 1
7408
+ ],
7409
+ [
7410
+ {
7411
+ name: "single-plan-pr",
7412
+ run: bin("check-single-plan-pr"),
7413
+ scope: "diff",
7414
+ timeoutMs: 15000,
7415
+ env: {
7416
+ BASE_SHA: { optional: true },
7417
+ PR_NUMBER: { optional: true },
7418
+ GITHUB_TOKEN: { optional: true },
7419
+ GH_TOKEN: { optional: true }
7420
+ }
7421
+ },
7422
+ 0
7423
+ ],
7424
+ [
7425
+ {
7426
+ name: "surface-scope",
7427
+ run: bin("check-surface-scope"),
7428
+ scope: "diff",
7429
+ timeoutMs: 15000,
7430
+ env: {
7431
+ AEG_REPO: { optional: true },
7432
+ BASE_SHA: { optional: true },
7433
+ BRANCH: { optional: true },
7434
+ GITHUB_TOKEN: { optional: true },
7435
+ GH_TOKEN: { optional: true }
7436
+ }
7437
+ },
7438
+ 0
7439
+ ],
7440
+ [
7441
+ {
7442
+ name: "test-plan",
7443
+ validates: "body",
7444
+ run: bin("check-test-plan"),
7445
+ scope: "diff",
7446
+ timeoutMs: 15000,
7447
+ requiresOpenPr: true,
7448
+ principalOwed: true,
7449
+ env: {
7450
+ PR_BODY: { optional: true },
7451
+ BRANCH: { optional: true }
7452
+ }
7453
+ },
7454
+ 1
7455
+ ],
7456
+ [
7457
+ {
7458
+ name: "body-bare-digits",
7459
+ validates: "body",
7460
+ run: bin("check-body-bare-digits"),
7461
+ scope: "diff",
7462
+ timeoutMs: 15000,
7463
+ requiresOpenPr: true,
7464
+ ownWorkflow: true,
7465
+ env: {
7466
+ PR_BODY: { optional: true },
7467
+ PR_NUMBER: { optional: true },
7468
+ GITHUB_REPOSITORY: { optional: true },
7469
+ GITHUB_TOKEN: { optional: true },
7470
+ GH_TOKEN: { optional: true }
7471
+ }
7472
+ },
7473
+ 1
7474
+ ],
7475
+ [
7476
+ {
7477
+ name: "token-report",
7478
+ validates: "body",
7479
+ run: bin("check-token-report"),
7480
+ scope: "diff",
7481
+ timeoutMs: 15000,
7482
+ requiresOpenPr: true,
7483
+ env: {
7484
+ PR_BODY: { optional: true },
7485
+ BRANCH: { optional: true },
7486
+ CLAUDE_PROJECT_DIR: { optional: true },
7487
+ CLAUDE_CODE_SESSION_ID: { optional: true }
7488
+ }
7489
+ },
7490
+ 1
7491
+ ],
7492
+ [
7493
+ {
7494
+ name: "no-disk-state",
7495
+ run: bin("check-no-disk-state"),
7496
+ scope: "diff",
7497
+ timeoutMs: 15000,
7498
+ env: { BASE_SHA: { optional: true } }
7499
+ },
7500
+ 0
7501
+ ],
7502
+ [
7503
+ {
7504
+ name: "registry-gates",
7505
+ run: bin("check-registry-gates"),
7506
+ scope: "full",
7507
+ timeoutMs: 30000,
7508
+ env: {
7509
+ AEG_REPO: { optional: true },
7510
+ GITHUB_TOKEN: { optional: true },
7511
+ GH_TOKEN: { optional: true }
7512
+ }
7513
+ },
7514
+ 0
7515
+ ],
7516
+ [
7517
+ {
7518
+ name: "review-gate",
7519
+ run: bin("check-review-gate"),
7520
+ scope: "full",
7521
+ timeoutMs: 30000,
7522
+ ownWorkflow: true,
7523
+ env: {
7524
+ PR_NUMBER: { optional: true },
7525
+ GITHUB_REPOSITORY: { optional: true },
7526
+ GITHUB_TOKEN: { optional: true },
7527
+ GH_TOKEN: { optional: true }
7528
+ }
7529
+ },
7530
+ 1
7531
+ ],
7532
+ [
7533
+ {
7534
+ name: "branch-topology",
7535
+ run: bin("check-branch-topology"),
7536
+ scope: "full",
7537
+ timeoutMs: 30000,
7538
+ env: {
7539
+ BRANCH: { optional: true },
7540
+ AEG_REPO: { optional: true },
7541
+ GITHUB_TOKEN: { optional: true },
7542
+ GH_TOKEN: { optional: true }
7543
+ }
7544
+ },
7545
+ 0
7546
+ ],
7547
+ [
7548
+ {
7549
+ name: "dead-branch-push",
7550
+ run: bin("check-dead-branch-push"),
7551
+ scope: "full",
7552
+ timeoutMs: 30000,
7553
+ env: {
7554
+ BRANCH: { optional: true },
7555
+ GITHUB_TOKEN: { optional: true },
7556
+ GH_TOKEN: { optional: true }
7557
+ }
7558
+ },
7559
+ 0
7560
+ ],
7561
+ [
7562
+ {
7563
+ name: "first-push-dispatch",
7564
+ run: bin("check-first-push-dispatch"),
7565
+ scope: "full",
7566
+ timeoutMs: 30000,
7567
+ env: {
7568
+ BRANCH: { optional: true },
7569
+ AEG_REPO: { optional: true },
7570
+ GITHUB_TOKEN: { optional: true },
7571
+ GH_TOKEN: { optional: true }
7572
+ }
7573
+ },
7574
+ 0
7575
+ ],
7576
+ [
7577
+ {
7578
+ name: "doc-coverage-push",
7579
+ validates: "body",
7580
+ run: bin("check-doc-coverage-push"),
7581
+ scope: "diff",
7582
+ timeoutMs: 15000,
7583
+ env: {
7584
+ OVERRIDE_DOCS: { optional: true },
7585
+ BASE_SHA: { optional: true },
7586
+ PR_BODY: { optional: true },
7587
+ PR_BODY_FILE: { optional: true },
7588
+ PR_LABELS: { optional: true },
7589
+ WAIVER_LABEL_ACTOR: { optional: true },
7590
+ GITHUB_REPOSITORY: { optional: true },
7591
+ GITHUB_TOKEN: { optional: true },
7592
+ GH_TOKEN: { optional: true }
7593
+ }
7594
+ },
7595
+ 0
7596
+ ],
7597
+ [
7598
+ {
7599
+ name: "issue-assignment",
7600
+ run: bin("check-issue-assignment"),
7601
+ scope: "full",
7602
+ timeoutMs: 30000,
7603
+ env: {
7604
+ AEG_REPO: { optional: true },
7605
+ BRANCH: { optional: true },
7606
+ GITHUB_TOKEN: { optional: true },
7607
+ GH_TOKEN: { optional: true }
7608
+ }
7609
+ },
7610
+ 0
7611
+ ],
7612
+ [
7613
+ {
7614
+ name: "evidence-fresh",
7615
+ validates: "body",
7616
+ run: bin("check-evidence-fresh"),
7617
+ scope: "diff",
7618
+ timeoutMs: 15000,
7619
+ requiresOpenPr: true,
7620
+ env: {
7621
+ PR_NUMBER: { optional: true },
7622
+ PR_BODY: { optional: true },
7623
+ BASE_SHA: { optional: true },
7624
+ GITHUB_TOKEN: { optional: true },
7625
+ GH_TOKEN: { optional: true }
7626
+ }
7627
+ },
7628
+ 1
7629
+ ],
7630
+ [
7631
+ {
7632
+ name: "reader-resolvable-prose",
7633
+ run: bin("check-reader-resolvable-prose"),
7634
+ scope: "full",
7635
+ timeoutMs: 30000,
7636
+ env: {},
7637
+ include: [
7638
+ "aeg-root/**/*.md",
7639
+ "apps/cli/src/**",
7640
+ ".github/workflows/**",
7641
+ ".vinaya/**",
7642
+ "apps/cli/README.md",
7643
+ "packages/sources/README.md"
7644
+ ]
7645
+ },
7646
+ 0
7647
+ ],
7648
+ [
7649
+ {
7650
+ name: "retired-vocabulary",
7651
+ run: bin("check-retired-vocabulary"),
7652
+ scope: "full",
7653
+ timeoutMs: 30000,
7654
+ env: {},
7655
+ include: ["aeg-root/**/*.md"]
7656
+ },
7657
+ 0
7658
+ ],
7659
+ [
7660
+ {
7661
+ name: "doctrine-portability",
7662
+ run: bin("check-doctrine-portability"),
7663
+ scope: "full",
7664
+ timeoutMs: 30000,
7665
+ env: { BASE_SHA: { optional: true } },
7666
+ include: ["aeg-root/**/*.md"]
7667
+ },
7668
+ 0
7669
+ ],
7670
+ [
7671
+ {
7672
+ name: "doctrine-no-procedures",
7673
+ run: bin("check-doctrine-no-procedures"),
7674
+ scope: "full",
7675
+ timeoutMs: 30000,
7676
+ env: {},
7677
+ include: ["aeg-root/**/*.md"]
7678
+ },
7679
+ 0
7680
+ ],
7681
+ [
7682
+ {
7683
+ name: "exec-bits",
7684
+ run: bin("check-exec-bits"),
7685
+ scope: "diff",
7686
+ timeoutMs: 30000,
7687
+ env: {}
7688
+ },
7689
+ 0
7690
+ ],
7691
+ [
7692
+ {
7693
+ name: "workspace-escape",
7694
+ run: bin("check-workspace-escape"),
7695
+ scope: "full",
7696
+ timeoutMs: 30000,
7697
+ env: {},
7698
+ include: ["aeg-root/**/*.md"]
7699
+ },
7700
+ 0
7701
+ ],
7702
+ [
7703
+ {
7704
+ name: "changeset-coverage",
7705
+ run: bin("check-changeset-coverage"),
7706
+ scope: "diff",
7707
+ timeoutMs: 15000,
7708
+ env: {}
7709
+ },
7710
+ 0
7711
+ ],
7712
+ [
7713
+ {
7714
+ name: "quoted-command",
7715
+ run: bin("check-quoted-command"),
7716
+ scope: "diff",
7717
+ timeoutMs: 15000,
7718
+ env: {}
7719
+ },
7720
+ 0
7721
+ ],
7722
+ [
7723
+ {
7724
+ name: "main-branch-refusal",
7725
+ run: bin("check-main-branch-refusal"),
7726
+ scope: "full",
7727
+ timeoutMs: 15000,
7728
+ env: { VINAYA_PUSH_REFS: { optional: true } }
7729
+ },
7730
+ 0
7731
+ ],
7732
+ [
7733
+ {
7734
+ name: "token-collection-wired",
7735
+ run: bin("check-token-collection-wired"),
7736
+ scope: "full",
7737
+ timeoutMs: 15000,
7738
+ env: {
7739
+ CLAUDE_PROJECT_DIR: { optional: true },
7740
+ CLAUDE_CODE_SESSION_ID: { optional: true }
7741
+ }
7742
+ },
7743
+ 0
7744
+ ],
7745
+ [
7746
+ {
7747
+ name: "issue-title-grammar",
7748
+ run: bin("check-issue-title-grammar"),
7749
+ validates: "issue",
7750
+ scope: "full",
7751
+ ownWorkflow: true,
7752
+ timeoutMs: 15000,
7753
+ env: { ISSUE_TITLE: { optional: true } }
7754
+ },
7755
+ 1
7756
+ ],
7757
+ [
7758
+ {
7759
+ name: "issue-objectives-numbering",
7760
+ run: bin("check-issue-objectives-numbering"),
7761
+ validates: "issue",
7762
+ scope: "full",
7763
+ ownWorkflow: true,
7764
+ timeoutMs: 15000,
7765
+ env: { ISSUE_BODY: { optional: true }, ISSUE_NUMBER: { optional: true } }
7766
+ },
7767
+ 1
7768
+ ],
7769
+ [
7770
+ {
7771
+ name: "issue-parts-coverage",
7772
+ run: bin("check-issue-parts-coverage"),
7773
+ validates: "issue",
7774
+ scope: "full",
7775
+ ownWorkflow: true,
7776
+ timeoutMs: 15000,
7777
+ env: { ISSUE_BODY: { optional: true } }
7778
+ },
7779
+ 1
7780
+ ],
7781
+ [
7782
+ {
7783
+ name: "issue-surface-globs",
7784
+ run: bin("check-issue-surface-globs"),
7785
+ validates: "issue",
7786
+ scope: "full",
7787
+ ownWorkflow: true,
7788
+ timeoutMs: 15000,
7789
+ env: { ISSUE_BODY: { optional: true } }
7790
+ },
7791
+ 1
7792
+ ],
7793
+ [
7794
+ {
7795
+ name: "issue-tranche-label",
7796
+ run: bin("check-issue-tranche-label"),
7797
+ validates: "issue",
7798
+ scope: "full",
7799
+ ownWorkflow: true,
7800
+ timeoutMs: 15000,
7801
+ env: { ISSUE_BODY: { optional: true }, ISSUE_LABELS: { optional: true } }
7802
+ },
7803
+ 1
7804
+ ],
7805
+ [
7806
+ {
7807
+ name: "issue-milestone-attach",
7808
+ run: bin("check-issue-milestone-attach"),
7809
+ validates: "issue",
7810
+ scope: "full",
7811
+ ownWorkflow: true,
7812
+ timeoutMs: 15000,
7813
+ env: {
7814
+ ISSUE_LABELS: { optional: true },
7815
+ CURRENT_MILESTONE_TITLE: { optional: true },
7816
+ RESOLVED_MILESTONE_TITLE: { optional: true }
7817
+ }
7818
+ },
7819
+ 1
7820
+ ]
7821
+ ];
7822
+ function coreCheckRegistry() {
7823
+ return REGISTRY.map(([spec]) => spec);
7824
+ }
7825
+ var CORE_CHECK_RING = Object.fromEntries(REGISTRY.map(([spec, ring]) => [spec.name, ring]));
7826
+
7827
+ // src/lib/log-sink.ts
7828
+ import { execFileSync as execFileSync5 } from "node:child_process";
7829
+ import { randomUUID } from "node:crypto";
7830
+ import {
7831
+ closeSync as closeSync2,
7832
+ constants as fsConstants2,
7833
+ existsSync as existsSync4,
7834
+ fstatSync as fstatSync2,
7835
+ mkdirSync as mkdirSync2,
7836
+ openSync as openSync2,
7837
+ readFileSync as readFileSync3,
7838
+ renameSync,
7839
+ writeSync
7840
+ } from "node:fs";
7841
+ import { hostname as osHostname, homedir as homedir2 } from "node:os";
7842
+ import { dirname as dirname3, join as join4 } from "node:path";
7843
+ var OUTBOX_MAX_BYTES = 8 * 1024 * 1024;
7844
+ function isEnoent(err) {
7845
+ return typeof err === "object" && err !== null && err.code === "ENOENT";
7846
+ }
7847
+ function resolveDoctrine(cwd, vinayaVersion) {
7848
+ let toplevel;
7849
+ try {
7850
+ toplevel = execFileSync5("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
7851
+ encoding: "utf8",
7852
+ stdio: ["ignore", "pipe", "pipe"]
7853
+ }).trim();
7854
+ } catch (err) {
7855
+ return isEnoent(err) ? "unknown" : vinayaVersion;
7856
+ }
7857
+ if (!existsSync4(join4(toplevel, "aeg-root", "roles")))
7858
+ return vinayaVersion;
7859
+ try {
7860
+ const sha = execFileSync5("git", ["-C", toplevel, "rev-parse", "HEAD:aeg-root"], {
7861
+ encoding: "utf8",
7862
+ stdio: ["ignore", "pipe", "pipe"]
7863
+ }).trim();
7864
+ return `aeg-root@${sha}`;
7865
+ } catch {
7866
+ return vinayaVersion;
7867
+ }
7868
+ }
7869
+ function readVinayaVersion() {
7870
+ try {
7871
+ const pkg = JSON.parse(readFileSync3(join4(packageRoot(import.meta.url), "package.json"), "utf8"));
7872
+ return pkg.version ?? "unknown";
7873
+ } catch {
7874
+ return "unknown";
7875
+ }
7876
+ }
7877
+ var SAFE_PATH_SEGMENT = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
7878
+ function isSafeRepoSegment(segment) {
7879
+ return SAFE_PATH_SEGMENT.test(segment) && !segment.includes("..");
7880
+ }
7881
+ function outboxPathFor(deps, repo, issue) {
7882
+ const dirName = repo ? `${repo.owner}-${repo.repo}` : "unresolved";
7883
+ const fileName = `${issue ?? "none"}.ndjson`;
7884
+ return join4(deps.outboxRoot(), dirName, fileName);
7885
+ }
7886
+ function hostFromEnv(env) {
7887
+ if (env.GITHUB_ACTIONS)
7888
+ return "ci";
7889
+ if (env.VINAYA_HOST === "hook")
7890
+ return "hook";
7891
+ if (env.VINAYA_HOST === "loop")
7892
+ return "loop";
7893
+ return "cli";
7894
+ }
7895
+ function defaultDeps() {
7896
+ return {
7897
+ outboxRoot: () => join4(GLOBAL_VINAYA_HOME, "outbox"),
7898
+ home: () => homedir2(),
7899
+ hostname: () => osHostname(),
7900
+ cwd: () => process.cwd(),
7901
+ now: () => new Date,
7902
+ env: () => process.env,
7903
+ resolveRepo: () => resolveRepo(),
7904
+ vinayaVersion: () => readVinayaVersion(),
7905
+ stderr: (message) => {
7906
+ process.stderr.write(message);
7907
+ },
7908
+ inputVersions: () => {
7909
+ return;
7910
+ }
7911
+ };
7912
+ }
7913
+ var APPEND_OPEN_FLAGS = fsConstants2.O_WRONLY | fsConstants2.O_APPEND | fsConstants2.O_CREAT | fsConstants2.O_NOFOLLOW | fsConstants2.O_NONBLOCK;
7914
+ function guardedAppendOpen(path) {
7915
+ try {
7916
+ return openSync2(path, APPEND_OPEN_FLAGS, 384);
7917
+ } catch {
7918
+ return;
7919
+ }
7920
+ }
7921
+ function reportRotationOverflow(backupPath, warn) {
7922
+ let raw;
7923
+ try {
7924
+ raw = readFileSync3(backupPath, "utf8");
7925
+ } catch {
7926
+ return;
7927
+ }
7928
+ const lines = raw.split(`
7929
+ `).filter((l) => l.length > 0);
7930
+ if (lines.length === 0)
7931
+ return;
7932
+ const droppedIdentities = lines.map((line, i) => {
7933
+ try {
7934
+ return recordIdentity(JSON.parse(line)) ?? `unreadable:${i}`;
7935
+ } catch {
7936
+ return `unreadable:${i}`;
7937
+ }
7938
+ });
7939
+ const diagnostic = { reason: "capacity", dropped: droppedIdentities.length, droppedIdentities };
7940
+ const shown = diagnostic.droppedIdentities.slice(0, 20);
7941
+ const more = diagnostic.dropped > shown.length ? `, +${diagnostic.dropped - shown.length} more` : "";
7942
+ warn(`vinaya: log outbox rotation is overwriting ${backupPath} — ${diagnostic.dropped} record(s) permanently lost: ${shown.join(", ")}${more}
7943
+ `);
7944
+ }
7945
+ function appendLine(path, line, warn) {
7946
+ try {
7947
+ mkdirSync2(dirname3(path), { recursive: true, mode: 448 });
7948
+ let fd = guardedAppendOpen(path);
7949
+ if (fd === undefined) {
7950
+ warn(`vinaya: log outbox target could not be opened (symlink, FIFO, or unwritable) — refusing: ${path}
7951
+ `);
7952
+ return;
7953
+ }
7954
+ let closed = false;
7955
+ try {
7956
+ const stat = fstatSync2(fd);
7957
+ if (!stat.isFile()) {
7958
+ warn(`vinaya: log outbox target is not a regular file — refusing to write: ${path}
7959
+ `);
7960
+ return;
7961
+ }
7962
+ if (stat.size > OUTBOX_MAX_BYTES) {
7963
+ closeSync2(fd);
7964
+ closed = true;
7965
+ const backupPath = path.replace(/\.ndjson$/, ".1.ndjson");
7966
+ reportRotationOverflow(backupPath, warn);
7967
+ renameSync(path, backupPath);
7968
+ const rotated = guardedAppendOpen(path);
7969
+ if (rotated === undefined) {
7970
+ warn(`vinaya: log outbox target could not be reopened after rotation — refusing: ${path}
7971
+ `);
7972
+ return;
7973
+ }
7974
+ fd = rotated;
7975
+ closed = false;
7976
+ }
7977
+ writeSync(fd, line);
7978
+ } finally {
7979
+ if (!closed)
7980
+ closeSync2(fd);
7981
+ }
7982
+ } catch (err) {
7983
+ warn(`vinaya: log outbox write failed — ${err instanceof Error ? err.message : String(err)}
7984
+ `);
7985
+ }
7986
+ }
7987
+ function createLogSink(overrides = {}) {
7988
+ const deps = { ...defaultDeps(), ...overrides };
7989
+ const runId = deps.env().VINAYA_RUN_ID || randomUUID();
7990
+ const processId = randomUUID();
7991
+ let seq = 0;
7992
+ let warned = false;
7993
+ const warnOnce = (message) => {
7994
+ if (warned)
7995
+ return;
7996
+ warned = true;
7997
+ try {
7998
+ deps.stderr(message);
7999
+ } catch {}
8000
+ };
8001
+ let doctrineCache;
8002
+ const doctrine = () => {
8003
+ if (doctrineCache === undefined)
8004
+ doctrineCache = resolveDoctrine(deps.cwd(), deps.vinayaVersion());
8005
+ return doctrineCache;
8006
+ };
8007
+ let resolveRepoCache;
8008
+ const resolveRepoOnce = () => {
8009
+ if (resolveRepoCache === undefined)
8010
+ resolveRepoCache = deps.resolveRepo();
8011
+ return resolveRepoCache;
8012
+ };
8013
+ function log(e) {
8014
+ try {
8015
+ const env = deps.env();
8016
+ const host = hostFromEnv(env);
8017
+ const now = deps.now();
8018
+ const mySeq = seq++;
8019
+ resolveRepoOnce().then((resolved) => {
8020
+ const repo = resolved && isSafeRepoSegment(resolved.owner) && isSafeRepoSegment(resolved.repo) ? resolved : null;
8021
+ const header = buildHeader({
8022
+ now,
8023
+ runId,
8024
+ seq: mySeq,
8025
+ repo: repo ? `${repo.owner}/${repo.repo}` : null,
8026
+ vinaya: deps.vinayaVersion(),
8027
+ doctrine: doctrine(),
8028
+ host,
8029
+ hostname: deps.hostname(),
8030
+ env: {
8031
+ role: env.VINAYA_ROLE,
8032
+ task: env.VINAYA_TASK,
8033
+ round: env.VINAYA_ROUND,
8034
+ run: env.VINAYA_RUN,
8035
+ attempt: env.VINAYA_ATTEMPT,
8036
+ parent: env.VINAYA_PARENT_EVENT
8037
+ },
8038
+ eventId: randomUUID(),
8039
+ processId,
8040
+ inputVersions: deps.inputVersions()
8041
+ });
8042
+ const full = { ...e, ...header };
8043
+ const parsed = LogEventSchema.safeParse(full);
8044
+ if (!parsed.success) {
8045
+ warnOnce(`vinaya: log() refused an invalid payload — ${parsed.error.issues[0]?.message ?? "schema violation"}
8046
+ `);
8047
+ return;
8048
+ }
8049
+ const line = `${JSON.stringify(redact(parsed.data, deps.home()))}
8050
+ `;
8051
+ appendLine(outboxPathFor(deps, repo, header.subject.issue), line, warnOnce);
8052
+ }).catch((err) => {
8053
+ warnOnce(`vinaya: log() failed — ${err instanceof Error ? err.message : String(err)}
8054
+ `);
8055
+ });
8056
+ } catch (err) {
8057
+ warnOnce(`vinaya: log() failed — ${err instanceof Error ? err.message : String(err)}
8058
+ `);
8059
+ }
8060
+ }
8061
+ const warmup = () => {
8062
+ doctrine();
8063
+ const originalWarn = console.warn;
8064
+ console.warn = () => {};
8065
+ resolveRepoOnce().finally(() => {
8066
+ console.warn = originalWarn;
8067
+ });
8068
+ };
8069
+ return { log, runId, warmup };
8070
+ }
8071
+ var defaultSink = createLogSink();
8072
+
6170
8073
  // src/checks/contract.ts
6171
8074
  var CHECK_SCHEMA_VERSION = 1;
6172
8075
  function emitCheckError(error) {
@@ -6174,6 +8077,15 @@ function emitCheckError(error) {
6174
8077
  `);
6175
8078
  }
6176
8079
 
8080
+ // src/checks/runner.ts
8081
+ var activeChecks = new Map;
8082
+
8083
+ // src/lib/forge-write.ts
8084
+ var INFORMATIONAL_DISPATCH_BLOCKER_CLASSES = new Set([
8085
+ "depends-on-not-merged",
8086
+ "conflicts-with"
8087
+ ]);
8088
+
6177
8089
  // src/commands/review-post.ts
6178
8090
  function parseChangedLineRanges(diffOutput) {
6179
8091
  const result = {};
@@ -6205,7 +8117,7 @@ function parseChangedLineRanges(diffOutput) {
6205
8117
  function fileDiffAgainst(ref, path) {
6206
8118
  let out;
6207
8119
  try {
6208
- out = execFileSync4("git", ["diff", `${ref}...HEAD`, "--", path], {
8120
+ out = execFileSync6("git", ["diff", `${ref}...HEAD`, "--", path], {
6209
8121
  encoding: "utf8",
6210
8122
  stdio: ["ignore", "pipe", "pipe"]
6211
8123
  }).trim();
@@ -6216,7 +8128,7 @@ function fileDiffAgainst(ref, path) {
6216
8128
  }
6217
8129
  function revParse(ref) {
6218
8130
  try {
6219
- return execFileSync4("git", ["rev-parse", "--verify", ref], {
8131
+ return execFileSync6("git", ["rev-parse", "--verify", ref], {
6220
8132
  encoding: "utf8",
6221
8133
  stdio: ["ignore", "pipe", "pipe"]
6222
8134
  }).trim();
@@ -6226,7 +8138,7 @@ function revParse(ref) {
6226
8138
  }
6227
8139
  function repoRoot() {
6228
8140
  try {
6229
- return execFileSync4("git", ["rev-parse", "--show-toplevel"], {
8141
+ return execFileSync6("git", ["rev-parse", "--show-toplevel"], {
6230
8142
  encoding: "utf8",
6231
8143
  stdio: ["ignore", "pipe", "pipe"]
6232
8144
  }).trim();
@@ -6237,7 +8149,7 @@ function repoRoot() {
6237
8149
  function changedFiles(base) {
6238
8150
  let out;
6239
8151
  try {
6240
- out = execFileSync4("git", ["diff", "--name-only", `${base}...HEAD`], {
8152
+ out = execFileSync6("git", ["diff", "--name-only", `${base}...HEAD`], {
6241
8153
  encoding: "utf8",
6242
8154
  stdio: ["ignore", "pipe", "pipe"]
6243
8155
  }).trim();
@@ -6262,7 +8174,7 @@ function resolveDiff(base = process.env.BASE_SHA || "origin/main") {
6262
8174
  const relPaths = changedFiles(ref);
6263
8175
  if (relPaths === null)
6264
8176
  continue;
6265
- return { base: ref, root, files: relPaths.map((p) => join2(root, p)) };
8177
+ return { base: ref, root, files: relPaths.map((p) => join5(root, p)) };
6266
8178
  }
6267
8179
  return null;
6268
8180
  }
@@ -6361,18 +8273,18 @@ function evaluateChangesetCoverage(fixedGroup, changedFiles2, isReleaseBranch) {
6361
8273
 
6362
8274
  // src/checks/bin/check-changeset-coverage.ts
6363
8275
  var CHECK_NAME = "changeset-coverage";
6364
- function git(args) {
8276
+ function git2(args) {
6365
8277
  try {
6366
- return execFileSync5("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
8278
+ return execFileSync7("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
6367
8279
  } catch {
6368
8280
  return "";
6369
8281
  }
6370
8282
  }
6371
8283
  function currentBranch() {
6372
- return git(["symbolic-ref", "--quiet", "--short", "HEAD"]);
8284
+ return git2(["symbolic-ref", "--quiet", "--short", "HEAD"]);
6373
8285
  }
6374
8286
  function defaultBranch() {
6375
- const ref = git(["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"]);
8287
+ const ref = git2(["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"]);
6376
8288
  return ref.startsWith("origin/") ? ref.slice("origin/".length) : "";
6377
8289
  }
6378
8290
  function toPosix(p) {
@@ -6380,7 +8292,7 @@ function toPosix(p) {
6380
8292
  }
6381
8293
  function readPackageJson(path) {
6382
8294
  try {
6383
- const parsed = JSON.parse(readFileSync3(path, "utf8"));
8295
+ const parsed = JSON.parse(readFileSync4(path, "utf8"));
6384
8296
  return parsed && typeof parsed === "object" ? parsed : null;
6385
8297
  } catch {
6386
8298
  return null;
@@ -6401,18 +8313,18 @@ function childDirs(absoluteDir) {
6401
8313
  function candidateMemberDirs(root, pattern) {
6402
8314
  if (pattern.endsWith("/*")) {
6403
8315
  const prefix = pattern.slice(0, -2);
6404
- return childDirs(join3(root, prefix)).map((name) => `${prefix}/${name}`);
8316
+ return childDirs(join6(root, prefix)).map((name) => `${prefix}/${name}`);
6405
8317
  }
6406
8318
  if (!pattern.includes("*"))
6407
8319
  return [pattern];
6408
8320
  return [];
6409
8321
  }
6410
8322
  function resolveWorkspaceMembers(root) {
6411
- const rootPkg = readPackageJson(join3(root, "package.json"));
8323
+ const rootPkg = readPackageJson(join6(root, "package.json"));
6412
8324
  const members = new Map;
6413
8325
  for (const pattern of workspacePatterns(rootPkg)) {
6414
8326
  for (const dir of candidateMemberDirs(root, pattern)) {
6415
- const pkg = readPackageJson(join3(root, dir, "package.json"));
8327
+ const pkg = readPackageJson(join6(root, dir, "package.json"));
6416
8328
  const name = pkg?.name;
6417
8329
  const files = pkg?.files;
6418
8330
  if (typeof name !== "string" || !Array.isArray(files))
@@ -6423,7 +8335,7 @@ function resolveWorkspaceMembers(root) {
6423
8335
  return members;
6424
8336
  }
6425
8337
  function fixedGroupNames(root) {
6426
- const pkg = readPackageJson(join3(root, ".changeset", "config.json"));
8338
+ const pkg = readPackageJson(join6(root, ".changeset", "config.json"));
6427
8339
  const fixed = pkg?.fixed;
6428
8340
  if (!Array.isArray(fixed))
6429
8341
  return [];
@@ -6451,7 +8363,7 @@ function main() {
6451
8363
  process.exit(0);
6452
8364
  }
6453
8365
  const changedFiles2 = changedAbs.map((p) => toPosix(relative2(root, p)));
6454
- const branch = git(["rev-parse", "--abbrev-ref", "HEAD"]);
8366
+ const branch = git2(["rev-parse", "--abbrev-ref", "HEAD"]);
6455
8367
  const isReleaseBranch = branch === CHANGESET_RELEASE_BRANCH;
6456
8368
  const workspaceMembers = resolveWorkspaceMembers(root);
6457
8369
  const fixedGroup = fixedGroupNames(root).map((name) => {