@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
@@ -1641,6 +1641,52 @@ var systemEnv3 = {
1641
1641
  ...process.env,
1642
1642
  PATH: [process.env.PATH, "/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin"].filter(Boolean).join(":")
1643
1643
  };
1644
+ var defaultExec = () => execFileAsync3("git", ["remote", "get-url", "origin"], { env: systemEnv3, timeout: 5000 });
1645
+ var cached;
1646
+ var inflight;
1647
+ async function resolveRepo(exec = defaultExec) {
1648
+ if (cached !== undefined)
1649
+ return cached;
1650
+ const fromEnv = process.env.AEG_REPO;
1651
+ if (fromEnv) {
1652
+ const parsed = parseOwnerRepo(fromEnv);
1653
+ if (parsed) {
1654
+ cached = parsed;
1655
+ return cached;
1656
+ }
1657
+ }
1658
+ if (inflight)
1659
+ return inflight;
1660
+ inflight = (async () => {
1661
+ try {
1662
+ const { stdout } = await exec();
1663
+ cached = parseGitRemoteUrl(stdout.trim());
1664
+ return cached;
1665
+ } catch (err) {
1666
+ const message = err instanceof Error ? err.message : String(err);
1667
+ console.warn(`[aeg-forge-state] resolveRepo: git remote lookup failed (will retry): ${message}`);
1668
+ return null;
1669
+ } finally {
1670
+ inflight = undefined;
1671
+ }
1672
+ })();
1673
+ return inflight;
1674
+ }
1675
+ function parseGitRemoteUrl(url) {
1676
+ const ssh = url.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
1677
+ if (ssh?.[1] && ssh[2])
1678
+ return { owner: ssh[1], repo: ssh[2] };
1679
+ const https = url.match(/^https?:\/\/(?:[^@]+@)?github\.com\/([^/]+)\/(.+?)(?:\.git)?\/?$/);
1680
+ if (https?.[1] && https[2])
1681
+ return { owner: https[1], repo: https[2] };
1682
+ return null;
1683
+ }
1684
+ function parseOwnerRepo(value) {
1685
+ const match = value.match(/^([^/]+)\/(.+)$/);
1686
+ if (!match?.[1] || !match[2])
1687
+ return null;
1688
+ return { owner: match[1], repo: match[2] };
1689
+ }
1644
1690
  // ../../packages/aeg-core/src/anchored-region.ts
1645
1691
  function anchoredRegionBounds(body, field) {
1646
1692
  const masked = maskCode(body);
@@ -1951,6 +1997,9 @@ function parseInlineFieldList(section) {
1951
1997
  var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
1952
1998
  var OBJECTIVES_VERSION_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Objectives version:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
1953
1999
  var RULING_ORDINAL_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Ruling ordinal:\s*(\d+)(?!\d)/im;
2000
+ var BRIEF_HASH_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Brief hash:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
2001
+ var POLICY_DIGEST_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Policy digest:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
2002
+ var BASE_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged base:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
1954
2003
  function firstFiveLines(comment) {
1955
2004
  return comment.split(`
1956
2005
  `).slice(0, 5).join(`
@@ -1973,6 +2022,35 @@ function extractRulingOrdinal(comment) {
1973
2022
  const m = firstSevenLines(comment).match(RULING_ORDINAL_PATTERN);
1974
2023
  return m ? Number.parseInt(m[1], 10) : null;
1975
2024
  }
2025
+ function firstElevenLines(comment) {
2026
+ return comment.split(`
2027
+ `).slice(0, 11).join(`
2028
+ `);
2029
+ }
2030
+ function extractBriefHash(comment) {
2031
+ const m = firstElevenLines(comment).match(BRIEF_HASH_PATTERN);
2032
+ return m ? m[1].toLowerCase() : null;
2033
+ }
2034
+ function extractPolicyDigest(comment) {
2035
+ const m = firstElevenLines(comment).match(POLICY_DIGEST_PATTERN);
2036
+ return m ? m[1].toLowerCase() : null;
2037
+ }
2038
+ function firstThirteenLines(comment) {
2039
+ return comment.split(`
2040
+ `).slice(0, 13).join(`
2041
+ `);
2042
+ }
2043
+ function extractBaseSha(comment) {
2044
+ const m = firstThirteenLines(comment).match(BASE_SHA_PATTERN);
2045
+ return m ? m[1].toLowerCase() : null;
2046
+ }
2047
+ var FINDING_SEVERITY_LINE = /^\d+\.\s+\[([A-Z][A-Z]*)\]\s+(.+?)\s+—/gm;
2048
+ function extractFindingSeverities(comment) {
2049
+ return [...comment.matchAll(FINDING_SEVERITY_LINE)].map((m) => ({
2050
+ severity: m[1],
2051
+ location: m[2]
2052
+ }));
2053
+ }
1976
2054
  function extractVerdict(comments, valuePattern, missingLabel) {
1977
2055
  const candidates = comments.filter((c) => valuePattern.test(c));
1978
2056
  if (candidates.length === 0) {
@@ -1981,6 +2059,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
1981
2059
  headSha: null,
1982
2060
  objectivesVersion: null,
1983
2061
  rulingOrdinal: null,
2062
+ briefHash: null,
2063
+ policyDigest: null,
2064
+ baseSha: null,
2065
+ findingSeverities: [],
1984
2066
  danglingNote: `no ${missingLabel} verdict comment found on this PR`
1985
2067
  };
1986
2068
  }
@@ -1992,6 +2074,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
1992
2074
  headSha: null,
1993
2075
  objectivesVersion: null,
1994
2076
  rulingOrdinal: null,
2077
+ briefHash: null,
2078
+ policyDigest: null,
2079
+ baseSha: null,
2080
+ findingSeverities: [],
1995
2081
  danglingNote: `the most recent ${missingLabel} verdict comment carries a VERDICT-shaped line outside the first-five-line read window`
1996
2082
  };
1997
2083
  }
@@ -2000,6 +2086,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
2000
2086
  headSha: extractHeadSha(latest),
2001
2087
  objectivesVersion: extractObjectivesVersion(latest),
2002
2088
  rulingOrdinal: extractRulingOrdinal(latest),
2089
+ briefHash: extractBriefHash(latest),
2090
+ policyDigest: extractPolicyDigest(latest),
2091
+ baseSha: extractBaseSha(latest),
2092
+ findingSeverities: extractFindingSeverities(latest),
2003
2093
  danglingNote: null
2004
2094
  };
2005
2095
  }
@@ -2335,6 +2425,53 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
2335
2425
  }
2336
2426
  return out;
2337
2427
  }
2428
+ // ../../packages/aeg-core/src/review-policy.ts
2429
+ var CODE_REVIEW_SEVERITY_ORDER = ["BLOCKER", "MAJOR", "MINOR"];
2430
+ var SECURITY_SEVERITY_ORDER = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
2431
+ var DEFAULT_MAX_ROUNDS = 3;
2432
+ var DEFAULT_REVIEW_POLICY = {
2433
+ codeReviewThreshold: "BLOCKER",
2434
+ securityThreshold: "HIGH",
2435
+ maxRounds: DEFAULT_MAX_ROUNDS
2436
+ };
2437
+ var FILE_SHAPED_LOCATION = /\.[a-zA-Z0-9]{1,10}(:\d+)?\s*$/;
2438
+ var PROSE_LOCATION_PATTERNS = [/\bpr\s*body\b/i, /\bcomment\b/i];
2439
+ var ROLE_FILE_LOCATION = /(^|\/)aeg-root\/roles\//i;
2440
+ function isProseLocation(location) {
2441
+ if (ROLE_FILE_LOCATION.test(location))
2442
+ return true;
2443
+ if (FILE_SHAPED_LOCATION.test(location))
2444
+ return false;
2445
+ return PROSE_LOCATION_PATTERNS.some((pattern) => pattern.test(location));
2446
+ }
2447
+ var PROSE_CAP_SEVERITY = "MINOR";
2448
+ function blockingSeverities(scale, threshold) {
2449
+ const idx = scale.indexOf(threshold);
2450
+ if (idx === -1) {
2451
+ throw new Error(`blockingSeverities: threshold "${threshold}" is not one of ${scale.join(" > ")}`);
2452
+ }
2453
+ return scale.slice(0, idx + 1);
2454
+ }
2455
+ function evaluateReviewFindings(findings, scale, threshold) {
2456
+ const blocking = new Set(blockingSeverities(scale, threshold));
2457
+ const blockingFindings = findings.filter((f) => {
2458
+ if (!scale.includes(f.severity)) {
2459
+ throw new Error(`evaluateReviewFindings: severity "${f.severity}" is not one of ${scale.join(" > ")}`);
2460
+ }
2461
+ const effectiveSeverity = f.location !== undefined && isProseLocation(f.location) ? PROSE_CAP_SEVERITY : f.severity;
2462
+ return blocking.has(effectiveSeverity);
2463
+ });
2464
+ return { outcome: blockingFindings.length > 0 ? "blocked" : "clean", blockingFindings };
2465
+ }
2466
+ function evaluateCodeReview(findings, policy) {
2467
+ return evaluateReviewFindings(findings, CODE_REVIEW_SEVERITY_ORDER, policy.codeReviewThreshold);
2468
+ }
2469
+ function evaluateSecurityReview(findings, policy) {
2470
+ return evaluateReviewFindings(findings, SECURITY_SEVERITY_ORDER, policy.securityThreshold);
2471
+ }
2472
+ function isKnownSeverity(scale, value) {
2473
+ return scale.includes(value);
2474
+ }
2338
2475
  // ../../packages/aeg-core/src/pr-tier.ts
2339
2476
  var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
2340
2477
  function readTierFromPrBody(prBody) {
@@ -2705,7 +2842,7 @@ function checkForField(prBody) {
2705
2842
  ]
2706
2843
  };
2707
2844
  }
2708
- function checkClosesN(prBody) {
2845
+ function checkClosesNPresence(prBody) {
2709
2846
  const closesPattern = /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s{0,8}:?\s{0,8}#\d+/i;
2710
2847
  if (closesPattern.test(stripCode(prBody))) {
2711
2848
  return { status: "pass", errors: [] };
@@ -2737,10 +2874,22 @@ var COMMIT_TYPES = [
2737
2874
  "Test"
2738
2875
  ];
2739
2876
  var COMMIT_TYPE_STYLE = new RegExp(`^(${COMMIT_TYPES.join("|")})(\\([a-z0-9-]+\\))?: \\S`);
2877
+ function checkForgeTitle(title) {
2878
+ const taskStyle = /^\[[a-z0-9._-]+\] \S+ — \S/;
2879
+ if (COMMIT_TYPE_STYLE.test(title) || taskStyle.test(title))
2880
+ return { status: "pass", errors: [] };
2881
+ return {
2882
+ status: "fail",
2883
+ errors: [
2884
+ `brief-validation title: "${title}" matches neither title grammar — expected \`Type: description\` / \`Type(scope): description\` (commitlint types + Plan) or \`[tranche] id — description\` (task form).`
2885
+ ]
2886
+ };
2887
+ }
2740
2888
  var BRIEF_SHAPE_MARKERS = [checkSurfaceMap, checkDocUpdateList, checkStopConditions, checkAutonomyClause];
2741
2889
  var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
2890
+ var TASK_ISSUE_BRANCH_PATTERN = /^task\/issue-\d+$/;
2742
2891
  function isTaskBranch(branch) {
2743
- return TASK_BRANCH_PATTERN.test(branch);
2892
+ return TASK_BRANCH_PATTERN.test(branch) || TASK_ISSUE_BRANCH_PATTERN.test(branch);
2744
2893
  }
2745
2894
  function isBriefShaped(prBody) {
2746
2895
  const stripped = stripCode(prBody);
@@ -2862,8 +3011,9 @@ function packagesNamedIn(text) {
2862
3011
  }
2863
3012
  function hasTestPathForConsumer(text, consumerDir) {
2864
3013
  const escaped = consumerDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2865
- const re = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
2866
- return re.test(text);
3014
+ const filePathRe = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
3015
+ const testDirRe = new RegExp(`${escaped}\\/(?:[\\w-]+\\/)*(?:tests|specs)(?:\\/|\\b)`);
3016
+ return filePathRe.test(text) || testDirRe.test(text);
2867
3017
  }
2868
3018
  function checkConsumerTests(prBody, consumersOf) {
2869
3019
  const section4 = extractNumberedSection(prBody, 4);
@@ -2967,7 +3117,7 @@ function checkBriefSections(prBody, readTier, options = {}) {
2967
3117
  checkConsumerTests(prBody, consumersOf),
2968
3118
  checkDefeatCases(prBody),
2969
3119
  ...issueObjectives !== undefined ? [checkObjectivesCopy(prBody, issueObjectives), checkObjectivesCoverage(prBody)] : [],
2970
- ...requireClosesN ? [checkClosesN(prBody)] : []
3120
+ ...requireClosesN ? [checkClosesNPresence(prBody)] : []
2971
3121
  ];
2972
3122
  return { errors: results.flatMap((r) => r.errors) };
2973
3123
  }
@@ -3257,6 +3407,28 @@ function topLevelSectionText(body, headingName) {
3257
3407
  const next = /^##[ \t]/m.exec(afterHeading);
3258
3408
  return next ? afterHeading.slice(0, next.index) : afterHeading;
3259
3409
  }
3410
+ function partHasBacktickedPath(text) {
3411
+ let i = 0;
3412
+ while (i < text.length) {
3413
+ const start = text.indexOf("`", i);
3414
+ if (start === -1)
3415
+ return false;
3416
+ const end = text.indexOf("`", start + 1);
3417
+ if (end === -1)
3418
+ return false;
3419
+ if (text.slice(start + 1, end).includes("/"))
3420
+ return true;
3421
+ i = end + 1;
3422
+ }
3423
+ return false;
3424
+ }
3425
+ var PART_MIN_WORDS_OUTSIDE_BACKTICKS = 3;
3426
+ function stripPartBackticks(text) {
3427
+ return text.replace(/`[^`\n]*`/g, " ");
3428
+ }
3429
+ function partWordCount(text) {
3430
+ return text.split(/\s+/).filter((w) => /[a-z]/i.test(w)).length;
3431
+ }
3260
3432
  function looksLikeFilePath(entry2) {
3261
3433
  const stripped = entry2.replace(/\/\*\*?$/, "");
3262
3434
  const lastSegment = stripped.split("/").pop() ?? stripped;
@@ -3297,6 +3469,18 @@ function globCoversPath(glob, path) {
3297
3469
  const p = path.replace(/\/+$/, "");
3298
3470
  return g === p || g.startsWith(`${p}/`) || p.startsWith(`${g}/`);
3299
3471
  }
3472
+ function checkSurfaceGlobsResolve(body, resolvesToFile) {
3473
+ const surface = parseIssueSurface(body);
3474
+ if (!surface.ok)
3475
+ return { status: "pass", errors: [] };
3476
+ const errors = [];
3477
+ for (const glob of surface.value.in) {
3478
+ if (!resolvesToFile(glob)) {
3479
+ 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.`);
3480
+ }
3481
+ }
3482
+ return { status: errors.length > 0 ? "fail" : "pass", errors };
3483
+ }
3300
3484
  function checkSurfaceScope(changedFiles, outGlobs) {
3301
3485
  if (outGlobs.length === 0)
3302
3486
  return { ok: true };
@@ -3308,9 +3492,77 @@ function checkSurfaceScope(changedFiles, outGlobs) {
3308
3492
  }
3309
3493
  return violations.length > 0 ? { ok: false, violations } : { ok: true };
3310
3494
  }
3495
+ var ISSUE_PART_LINE_RE = /^Part\s+(\d+)\s*\(([^)]*)\)\s*[-—–]\s*(.*)$/i;
3496
+ function parseIssueParts(body) {
3497
+ const section = topLevelSectionText(body, "Parts");
3498
+ if (section === null)
3499
+ return { ok: false, errors: ["no `## Parts` heading found in the body."] };
3500
+ const lines = section.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
3501
+ const parts = [];
3502
+ const errors = [];
3503
+ for (const line of lines) {
3504
+ const m = ISSUE_PART_LINE_RE.exec(line);
3505
+ if (!m) {
3506
+ errors.push(`"${line}" is not a well-formed Parts line — expected \`Part <n> (<refs>) — <outcome>\`.`);
3507
+ continue;
3508
+ }
3509
+ const n = Number.parseInt(m[1], 10);
3510
+ const refs = m[2];
3511
+ const text = m[3].trim();
3512
+ if (text.length === 0) {
3513
+ errors.push(`Part ${n} has no outcome text after the dash — every Part states one observable outcome.`);
3514
+ continue;
3515
+ }
3516
+ if (partHasBacktickedPath(text) && partWordCount(stripPartBackticks(text)) < PART_MIN_WORDS_OUTSIDE_BACKTICKS) {
3517
+ errors.push(`Part ${n} is little more than a file path — a Part names an outcome and symbols, never a bare path.`);
3518
+ continue;
3519
+ }
3520
+ const objectiveIds = [...refs.matchAll(/O(\d+)/g)].map((r) => Number.parseInt(r[1], 10));
3521
+ parts.push({ n, objectiveIds, text });
3522
+ }
3523
+ if (parts.length === 0) {
3524
+ errors.push("the `## Parts` section has no well-formed `Part <n> (<refs>) — <outcome>` lines.");
3525
+ }
3526
+ if (errors.length > 0)
3527
+ return { ok: false, errors };
3528
+ return { ok: true, value: parts };
3529
+ }
3530
+ function checkPartsCiteDefinedObjectives(body) {
3531
+ const parts = parseIssueParts(body);
3532
+ const objectives = objectivesOf(body);
3533
+ if (!parts.ok || !objectives.ok)
3534
+ return { status: "pass", errors: [] };
3535
+ const definedIds = new Set(objectives.objectives.map((o) => Number.parseInt(o.id.slice(1), 10)));
3536
+ const errors = [];
3537
+ for (const part of parts.value) {
3538
+ for (const objectiveId of part.objectiveIds) {
3539
+ if (!definedIds.has(objectiveId)) {
3540
+ errors.push(`issue-validation Parts: Part ${part.n} cites O${objectiveId}, which the Issue's own \`## Objectives\` section does not define.`);
3541
+ }
3542
+ }
3543
+ }
3544
+ return { status: errors.length > 0 ? "fail" : "pass", errors };
3545
+ }
3311
3546
  function isTaskIssueLabelSet(labels) {
3312
3547
  return hasLabel("tranche", labels);
3313
3548
  }
3549
+ function checkTrancheLabelPresence(_body, _labels) {
3550
+ return { status: "pass", errors: [] };
3551
+ }
3552
+ function checkMilestoneAttach(labels, currentMilestoneTitle, resolvedMilestoneTitle) {
3553
+ if (!isTaskIssueLabelSet(labels))
3554
+ return { status: "pass", errors: [] };
3555
+ if (resolvedMilestoneTitle === null)
3556
+ return { status: "pass", errors: [] };
3557
+ if (currentMilestoneTitle === resolvedMilestoneTitle)
3558
+ return { status: "pass", errors: [] };
3559
+ return {
3560
+ status: "fail",
3561
+ errors: [
3562
+ `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}".`
3563
+ ]
3564
+ };
3565
+ }
3314
3566
  var TYPE_LABEL_IDS = LABELS.filter((l) => l.category === "type").map((l) => l.id);
3315
3567
  function isControlCodePoint(codePoint) {
3316
3568
  return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
@@ -3375,6 +3627,19 @@ function checkProjectsRegistered(body, _labels, registeredNames) {
3375
3627
  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;
3376
3628
  var DOC_PATH_RE_GLOBAL = new RegExp(DOC_PATH_RE.source, "gi");
3377
3629
 
3630
+ // ../../packages/aeg-core/src/task-branch-identity.ts
3631
+ var ISSUE_BRANCH_PATTERN = /^task\/issue-(\d+)$/;
3632
+ var TRANCHE_BRANCH_PATTERN = /^task\/([^/]+)\/([^/]+)$/;
3633
+ function parseTaskBranchIdentity(branch) {
3634
+ const issueMatch = ISSUE_BRANCH_PATTERN.exec(branch);
3635
+ if (issueMatch)
3636
+ return { kind: "issue", issueNumber: Number(issueMatch[1]) };
3637
+ const trancheMatch = TRANCHE_BRANCH_PATTERN.exec(branch);
3638
+ if (trancheMatch)
3639
+ return { kind: "tranche", tranche: trancheMatch[1], taskId: trancheMatch[2] };
3640
+ return null;
3641
+ }
3642
+
3378
3643
  // ../../packages/aeg-core/src/coherence-checks.ts
3379
3644
  var COHERENCE_ENFORCED_FROM = "2026-07-01";
3380
3645
  function isGrandfathered(isoDate) {
@@ -3395,6 +3660,7 @@ function checkA1(entries, principalAllowlist = PRINCIPAL_ALLOWLIST) {
3395
3660
  if (handClosed)
3396
3661
  continue;
3397
3662
  failures.push({
3663
+ code: "closed-without-merge",
3398
3664
  issue: e.task.issue,
3399
3665
  tranche: e.trancheSlug,
3400
3666
  task: e.task.id,
@@ -3419,6 +3685,7 @@ function checkA3(entries) {
3419
3685
  continue;
3420
3686
  if (e.facts.prState === "merged" && e.facts.issueState !== "closed") {
3421
3687
  failures.push({
3688
+ code: "auto-close-misfire",
3422
3689
  issue: e.task.issue,
3423
3690
  tranche: e.trancheSlug,
3424
3691
  task: e.task.id,
@@ -3443,6 +3710,7 @@ function checkT1(entries) {
3443
3710
  continue;
3444
3711
  if (e.facts === undefined) {
3445
3712
  failures.push({
3713
+ code: "phantom-issue-ref",
3446
3714
  issue: e.task.issue,
3447
3715
  tranche: e.trancheSlug,
3448
3716
  task: e.task.id,
@@ -3461,6 +3729,7 @@ function checkT2(openIssuesBySlug, topologyIssuesBySlug, ciTrancheSlug) {
3461
3729
  for (const num of openNums) {
3462
3730
  if (!topologySet.has(num)) {
3463
3731
  failures.push({
3732
+ code: "orphan-task",
3464
3733
  issue: num,
3465
3734
  tranche: slug,
3466
3735
  reason: `Issue #${num} is open and labeled ${trancheLabel(slug)} but does not appear in the topology file`
@@ -3495,6 +3764,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
3495
3764
  continue;
3496
3765
  if (forgeUnavailableSlugs?.has(e.trancheSlug)) {
3497
3766
  failures.push({
3767
+ code: "tbd-in-active-tranche",
3498
3768
  issue: null,
3499
3769
  tranche: e.trancheSlug,
3500
3770
  task: e.task.id,
@@ -3504,6 +3774,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
3504
3774
  continue;
3505
3775
  }
3506
3776
  failures.push({
3777
+ code: "tbd-in-active-tranche",
3507
3778
  issue: null,
3508
3779
  tranche: e.trancheSlug,
3509
3780
  task: e.task.id,
@@ -3536,6 +3807,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
3536
3807
  const sameIssue = depEntry.task.issue !== null && e.task.issue !== null && depEntry.task.issue === e.task.issue;
3537
3808
  if (sameTask || sameIssue) {
3538
3809
  failures.push({
3810
+ code: "d1-self-dependency",
3539
3811
  issue: e.task.issue,
3540
3812
  tranche: e.trancheSlug,
3541
3813
  task: e.task.id,
@@ -3547,6 +3819,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
3547
3819
  const depClosed = depFacts?.issueState === "closed";
3548
3820
  if (!depClosed) {
3549
3821
  failures.push({
3822
+ code: "dispatched-on-unmet-deps",
3550
3823
  issue: e.task.issue,
3551
3824
  tranche: e.trancheSlug,
3552
3825
  task: e.task.id,
@@ -3572,11 +3845,13 @@ function checkR1(issuesBySlug, grandfatheredIssues, registeredNames = []) {
3572
3845
  const errors = [
3573
3846
  ...checkIssueRationale(issue.body).errors,
3574
3847
  ...checkProjectsRegistered(issue.body, issue.labels, registeredNames).errors,
3575
- ...checkIssueObjectives(issue.body, issue.number).errors
3848
+ ...checkIssueObjectives(issue.body, issue.number).errors,
3849
+ ...checkPartsCiteDefinedObjectives(issue.body).errors
3576
3850
  ];
3577
3851
  if (errors.length === 0)
3578
3852
  continue;
3579
3853
  failures.push({
3854
+ code: "missing-rationale-field",
3580
3855
  issue: issue.number,
3581
3856
  tranche: slug,
3582
3857
  reason: `Issue #${issue.number} fails the rationale gate: ${errors.join(" | ")}`,
@@ -3605,6 +3880,7 @@ function checkL1(files, entriesBySlug) {
3605
3880
  const allClosed = withFacts.every((e) => e.facts?.issueState === "closed");
3606
3881
  if (allClosed) {
3607
3882
  failures.push({
3883
+ code: "archive-recommended",
3608
3884
  tranche: f.slug,
3609
3885
  reason: "Active tranche has no open task-Issues — consider archiving to completed/"
3610
3886
  });
@@ -3636,27 +3912,38 @@ function extractClosesReferences(prBody) {
3636
3912
  }
3637
3913
  return referenced;
3638
3914
  }
3639
- function checkClosesN2(branch, prBody, trancheFiles, taskIssueRefs) {
3915
+ function checkClosesNTopology(branch, prBody, trancheFiles, taskIssueRefs) {
3640
3916
  const referenced = extractClosesReferences(prBody);
3641
3917
  if (taskIssueRefs) {
3642
3918
  for (const n of referenced) {
3643
- const ref = taskIssueRefs.get(n);
3644
- if (!ref)
3919
+ const ref2 = taskIssueRefs.get(n);
3920
+ if (!ref2)
3645
3921
  continue;
3646
- const expectedBranch = `task/${ref.trancheSlug}/${ref.taskId}`;
3922
+ const expectedBranch = `task/${ref2.trancheSlug}/${ref2.taskId}`;
3647
3923
  if (branch !== expectedBranch) {
3648
3924
  return {
3649
3925
  ok: false,
3650
- 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.`
3926
+ 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.`
3651
3927
  };
3652
3928
  }
3653
3929
  }
3654
3930
  }
3655
- const m = branch.match(/^task\/([^/]+)\/([^/]+)$/);
3656
- if (!m)
3931
+ const ref = parseTaskBranchIdentity(branch);
3932
+ if (!ref)
3657
3933
  return { ok: true };
3658
- const trancheSlug = m[1];
3659
- const taskId = m[2];
3934
+ if (ref.kind === "issue") {
3935
+ const expectedIssue2 = ref.issueNumber;
3936
+ if (!referenced.has(expectedIssue2)) {
3937
+ return {
3938
+ ok: false,
3939
+ expectedIssue: expectedIssue2,
3940
+ message: `closes-n: PR body does not contain \`Closes #${expectedIssue2}\` (required for branch "${branch}"). Add it to the PR body Summary section.`
3941
+ };
3942
+ }
3943
+ return { ok: true, expectedIssue: expectedIssue2 };
3944
+ }
3945
+ const trancheSlug = ref.tranche;
3946
+ const taskId = ref.taskId;
3660
3947
  const trancheFile = trancheFiles.find((f) => f.slug === trancheSlug);
3661
3948
  if (!trancheFile) {
3662
3949
  return {
@@ -3708,34 +3995,79 @@ function extractIssue(body) {
3708
3995
  const issue = headerNums.length > 0 ? headerNums[0] : bodyNums[0];
3709
3996
  return { issue, extraIssues: bodyNums.filter((n) => n !== issue), outsideHeader: headerNums.length === 0 };
3710
3997
  }
3711
- // ../../packages/aeg-core/src/review-gate.ts
3712
- function isBoundToHead(extraction, headSha) {
3713
- if (!extraction.headSha)
3998
+ // ../../packages/aeg-core/src/review-input-manifest.ts
3999
+ import { createHash as createHash4 } from "node:crypto";
4000
+ function briefHash(brief) {
4001
+ return createHash4("sha256").update(`${brief}
4002
+ `).digest("hex");
4003
+ }
4004
+ function policyDigest(policy) {
4005
+ return createHash4("sha256").update(JSON.stringify({
4006
+ codeReviewThreshold: policy.codeReviewThreshold,
4007
+ securityThreshold: policy.securityThreshold,
4008
+ maxRounds: policy.maxRounds
4009
+ })).digest("hex");
4010
+ }
4011
+ function isBoundToHead(echoed, headSha) {
4012
+ if (!echoed.headSha)
3714
4013
  return false;
3715
- return headSha.toLowerCase().startsWith(extraction.headSha.toLowerCase());
4014
+ return headSha.toLowerCase().startsWith(echoed.headSha.toLowerCase());
3716
4015
  }
3717
- function isBoundByPatchIdentity(extraction, headSha, patchIdOf) {
3718
- if (patchIdOf === undefined || !extraction.headSha)
4016
+ function isBoundByPatchIdentity(echoed, headSha, patchIdOf) {
4017
+ if (patchIdOf === undefined || !echoed.headSha)
3719
4018
  return false;
3720
- const judged = patchIdOf(extraction.headSha);
4019
+ const judged = patchIdOf(echoed.headSha);
3721
4020
  const current = patchIdOf(headSha);
3722
4021
  if (judged === null || current === null)
3723
4022
  return false;
3724
4023
  return judged === current;
3725
4024
  }
3726
- function isBoundToPatch(extraction, headSha, patchIdOf) {
3727
- return isBoundToHead(extraction, headSha) || isBoundByPatchIdentity(extraction, headSha, patchIdOf);
4025
+ function isBoundToBase(echoed, currentBase) {
4026
+ if (currentBase === null)
4027
+ return true;
4028
+ if (!echoed.baseSha)
4029
+ return false;
4030
+ return currentBase.toLowerCase().startsWith(echoed.baseSha.toLowerCase());
3728
4031
  }
3729
- function isBoundToObjectives(extraction, currentVersion) {
4032
+ function isBoundToObjectives(echoed, currentVersion) {
3730
4033
  if (currentVersion === null)
3731
4034
  return true;
3732
- return extraction.objectivesVersion === currentVersion;
4035
+ return echoed.objectivesVersion === currentVersion;
3733
4036
  }
3734
- function isBoundToRulings(extraction, currentOrdinal) {
3735
- if (extraction.rulingOrdinal === null)
4037
+ function isBoundToRulings(echoed, currentOrdinal) {
4038
+ if (echoed.rulingOrdinal === null)
3736
4039
  return currentOrdinal === 0;
3737
- return extraction.rulingOrdinal === currentOrdinal;
4040
+ return echoed.rulingOrdinal === currentOrdinal;
4041
+ }
4042
+ function isBoundToBriefHash(echoed, currentHash) {
4043
+ if (currentHash === null)
4044
+ return true;
4045
+ return echoed.briefHash === currentHash;
4046
+ }
4047
+ function isBoundToPolicy(echoed, currentDigest) {
4048
+ return echoed.policyDigest === currentDigest;
4049
+ }
4050
+ function compareManifest(echoed, current, patchIdOf) {
4051
+ const exactHead = isBoundToHead(echoed, current.headSha);
4052
+ const patchHead = exactHead ? false : isBoundByPatchIdentity(echoed, current.headSha, patchIdOf);
4053
+ const head = exactHead || patchHead;
4054
+ const base = patchHead ? true : isBoundToBase(echoed, current.baseSha);
4055
+ const briefHashBound = isBoundToBriefHash(echoed, current.briefHash);
4056
+ const objectivesVersion2 = isBoundToObjectives(echoed, current.objectivesVersion);
4057
+ const rulingOrdinal = isBoundToRulings(echoed, current.rulingOrdinal);
4058
+ const policyDigestBound = isBoundToPolicy(echoed, current.policyDigest);
4059
+ return {
4060
+ bound: head && base && briefHashBound && objectivesVersion2 && rulingOrdinal && policyDigestBound,
4061
+ head,
4062
+ base,
4063
+ briefHash: briefHashBound,
4064
+ objectivesVersion: objectivesVersion2,
4065
+ rulingOrdinal,
4066
+ policyDigest: policyDigestBound
4067
+ };
3738
4068
  }
4069
+
4070
+ // ../../packages/aeg-core/src/review-gate.ts
3739
4071
  function checkReviewGate(input) {
3740
4072
  const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
3741
4073
  const waived = isWaiverLabelActorVerified({
@@ -3758,15 +4090,58 @@ function checkReviewGate(input) {
3758
4090
  const verifiedBodies = verified.map((c) => c.body);
3759
4091
  const codeReview = extractCodeReviewVerdict(verifiedBodies);
3760
4092
  const security = extractSecurityReviewVerdict(verifiedBodies);
3761
- const codeReviewClean = codeReview.value === "APPROVE";
3762
- const securityClean = security.value === "PASS";
3763
- const codeReviewBound = isBoundToPatch(codeReview, input.headSha, input.patchIdOf);
3764
- const securityBound = isBoundToPatch(security, input.headSha, input.patchIdOf);
3765
- const codeReviewObjectivesBound = isBoundToObjectives(codeReview, input.objectivesVersion);
3766
- const securityObjectivesBound = isBoundToObjectives(security, input.objectivesVersion);
3767
- const codeReviewRulingsBound = isBoundToRulings(codeReview, input.rulingOrdinal);
3768
- const securityRulingsBound = isBoundToRulings(security, input.rulingOrdinal);
3769
- if (codeReviewClean && codeReviewBound && codeReviewObjectivesBound && codeReviewRulingsBound && securityClean && securityBound && securityObjectivesBound && securityRulingsBound && mechanicalChecksClean) {
4093
+ const policy = input.policy ?? DEFAULT_REVIEW_POLICY;
4094
+ let codeReviewPolicyEvaluation;
4095
+ let securityPolicyEvaluation;
4096
+ try {
4097
+ codeReviewPolicyEvaluation = evaluateCodeReview(codeReview.findingSeverities, policy);
4098
+ securityPolicyEvaluation = evaluateSecurityReview(security.findingSeverities, policy);
4099
+ } catch (err) {
4100
+ return {
4101
+ verdict: "fail",
4102
+ reason: `a verdict comment carries a finding severity this repository's policy does not recognize: ${err instanceof Error ? err.message : String(err)}`,
4103
+ waived: false
4104
+ };
4105
+ }
4106
+ const codeReviewTextClean = codeReview.value === "APPROVE";
4107
+ const securityTextClean = security.value === "PASS";
4108
+ const codeReviewPolicyClean = codeReviewPolicyEvaluation.outcome === "clean";
4109
+ const securityPolicyClean = securityPolicyEvaluation.outcome === "clean";
4110
+ const codeReviewClean = codeReviewTextClean && codeReviewPolicyClean;
4111
+ const securityClean = securityTextClean && securityPolicyClean;
4112
+ const currentManifest = {
4113
+ headSha: input.headSha,
4114
+ baseSha: input.baseSha ?? null,
4115
+ briefHash: input.briefHash ?? null,
4116
+ objectivesVersion: input.objectivesVersion,
4117
+ rulingOrdinal: input.rulingOrdinal,
4118
+ policyDigest: policyDigest(policy)
4119
+ };
4120
+ const codeReviewEchoed = {
4121
+ headSha: codeReview.headSha,
4122
+ baseSha: codeReview.baseSha,
4123
+ briefHash: codeReview.briefHash,
4124
+ objectivesVersion: codeReview.objectivesVersion,
4125
+ rulingOrdinal: codeReview.rulingOrdinal,
4126
+ policyDigest: codeReview.policyDigest
4127
+ };
4128
+ const securityEchoed = {
4129
+ headSha: security.headSha,
4130
+ baseSha: security.baseSha,
4131
+ briefHash: security.briefHash,
4132
+ objectivesVersion: security.objectivesVersion,
4133
+ rulingOrdinal: security.rulingOrdinal,
4134
+ policyDigest: security.policyDigest
4135
+ };
4136
+ const codeReviewBinding = compareManifest(codeReviewEchoed, currentManifest, input.patchIdOf);
4137
+ const securityBinding = compareManifest(securityEchoed, currentManifest, input.patchIdOf);
4138
+ const codeReviewBound = codeReviewBinding.head;
4139
+ const securityBound = securityBinding.head;
4140
+ const codeReviewObjectivesBound = codeReviewBinding.objectivesVersion;
4141
+ const securityObjectivesBound = securityBinding.objectivesVersion;
4142
+ const codeReviewRulingsBound = codeReviewBinding.rulingOrdinal;
4143
+ const securityRulingsBound = securityBinding.rulingOrdinal;
4144
+ if (codeReviewClean && codeReviewBinding.bound && securityClean && securityBinding.bound && mechanicalChecksClean) {
3770
4145
  return {
3771
4146
  verdict: "pass",
3772
4147
  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.`,
@@ -3774,23 +4149,39 @@ function checkReviewGate(input) {
3774
4149
  };
3775
4150
  }
3776
4151
  const problems = [];
3777
- if (!codeReviewClean) {
4152
+ if (!codeReviewTextClean) {
3778
4153
  problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
4154
+ } else if (!codeReviewPolicyClean) {
4155
+ 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`);
3779
4156
  } else if (!codeReviewBound) {
3780
4157
  problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
4158
+ } else if (!codeReviewBinding.base) {
4159
+ 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)`);
3781
4160
  } else if (!codeReviewObjectivesBound) {
3782
4161
  problems.push(`the newest code-review verdict was cast against objectives version ${codeReview.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
3783
4162
  } else if (!codeReviewRulingsBound) {
3784
4163
  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`);
4164
+ } else if (!codeReviewBinding.briefHash) {
4165
+ 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"}`);
4166
+ } else if (!codeReviewBinding.policyDigest) {
4167
+ 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}`);
3785
4168
  }
3786
- if (!securityClean) {
4169
+ if (!securityTextClean) {
3787
4170
  problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
4171
+ } else if (!securityPolicyClean) {
4172
+ 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`);
3788
4173
  } else if (!securityBound) {
3789
4174
  problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
4175
+ } else if (!securityBinding.base) {
4176
+ 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)`);
3790
4177
  } else if (!securityObjectivesBound) {
3791
4178
  problems.push(`the newest security-review verdict was cast against objectives version ${security.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
3792
4179
  } else if (!securityRulingsBound) {
3793
4180
  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`);
4181
+ } else if (!securityBinding.briefHash) {
4182
+ 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"}`);
4183
+ } else if (!securityBinding.policyDigest) {
4184
+ 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}`);
3794
4185
  }
3795
4186
  if (!mechanicalChecksClean) {
3796
4187
  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(", ")}`);
@@ -4482,42 +4873,45 @@ function checkDispatchReadiness(input) {
4482
4873
  const { trancheSlug, task } = input;
4483
4874
  const taskLabel = `task ${task.id} (tranche ${trancheSlug})`;
4484
4875
  const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
4485
- const blockers = [];
4876
+ const blockerDetails = [];
4877
+ const push = (blockerClass, message) => {
4878
+ blockerDetails.push({ class: blockerClass, message });
4879
+ };
4486
4880
  if (task.issue === null) {
4487
- blockers.push(`dispatch-gate issue-existence: ${taskLabel} has no Issue (#TBD or blank) in the topology — not dispatchable until the Planner cuts the Issue.`);
4881
+ 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.`);
4488
4882
  } else if (input.issue === null) {
4489
- blockers.push(`dispatch-gate issue-existence: ${taskLabel} names Issue #${task.issue}, but it does not resolve to a real GitHub Issue (phantom reference).`);
4883
+ push("issue-existence", `dispatch-gate issue-existence: ${taskLabel} names Issue #${task.issue}, but it does not resolve to a real GitHub Issue (phantom reference).`);
4490
4884
  }
4491
4885
  if (input.issue !== null && !input.issueRationalePass) {
4492
- 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.`);
4886
+ 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.`);
4493
4887
  }
4494
4888
  for (const dep of input.dependsOn) {
4495
4889
  if (isSelfDependency(dep, task, input.issue)) {
4496
4890
  const issueStr = input.issue !== null ? `#${input.issue.number}` : "?";
4497
- 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.`);
4891
+ 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.`);
4498
4892
  continue;
4499
4893
  }
4500
4894
  if (dep.resolved === false) {
4501
- 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.`);
4895
+ 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.`);
4502
4896
  continue;
4503
4897
  }
4504
4898
  if (!dep.merged && !isHandClosedByRecognizedPrincipal(dep, principalAllowlist)) {
4505
4899
  const issueStr = dep.issue !== null ? ` (#${dep.issue})` : "";
4506
- blockers.push(`dispatch-gate depends-on: ${taskLabel} depends on ${dep.id}${issueStr}, whose PR is not merged yet — not dispatchable, it serializes behind it.`);
4900
+ 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.`);
4507
4901
  }
4508
4902
  }
4509
4903
  for (const c of input.conflictsWith) {
4510
4904
  if (c.openOrInFlight) {
4511
4905
  const issueStr = c.issue !== null ? ` (#${c.issue})` : "";
4512
- blockers.push(`dispatch-gate conflicts-with: ${taskLabel} conflicts with ${c.id}${issueStr}, whose PR is open or in-flight — not dispatchable until it merges.`);
4906
+ 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.`);
4513
4907
  }
4514
4908
  }
4515
4909
  for (const proj of input.priorTrancheArchival) {
4516
4910
  if (proj.priorTrancheSlug !== null && !proj.archived) {
4517
- 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.`);
4911
+ 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.`);
4518
4912
  }
4519
4913
  }
4520
- return { ready: blockers.length === 0, blockers };
4914
+ return { ready: blockerDetails.length === 0, blockers: blockerDetails.map((b) => b.message), blockerDetails };
4521
4915
  }
4522
4916
  // ../../packages/aeg-core/src/single-plan-pr.ts
4523
4917
  function trancheSlugFromTopologyPath(path) {
@@ -4619,6 +5013,137 @@ function checkBranchTopology(input) {
4619
5013
  reason: `Branch \`${branch}\` matches topology row \`${taskId}\` in ${topoPath}.`
4620
5014
  };
4621
5015
  }
5016
+ // ../../packages/aeg-core/src/task-tools.ts
5017
+ import { z } from "zod";
5018
+ var TASK_TOOL_ERROR_KINDS = [
5019
+ "validation",
5020
+ "authority",
5021
+ "precondition",
5022
+ "capability",
5023
+ "infrastructure",
5024
+ "cancellation",
5025
+ "timeout",
5026
+ "uncertain_effect"
5027
+ ];
5028
+ var TaskToolErrorSchema = z.object({
5029
+ kind: z.enum(TASK_TOOL_ERROR_KINDS),
5030
+ message: z.string().min(1),
5031
+ detail: z.string().optional()
5032
+ });
5033
+ var TaskToolRefSchema = z.union([
5034
+ z.object({ tranche: z.string().min(1), id: z.string().min(1) }).strict(),
5035
+ z.object({ issue: z.number().int().positive() }).strict()
5036
+ ]);
5037
+ var MAX_PAGE_LIMIT = 100;
5038
+ var PageRequestSchema = z.object({
5039
+ cursor: z.string().optional(),
5040
+ limit: z.number().int().positive().max(MAX_PAGE_LIMIT).optional()
5041
+ });
5042
+ var FreshnessSchema = z.enum(["fresh", "stale", "unknown"]);
5043
+ var ObservedSchema = z.object({
5044
+ observedAt: z.string(),
5045
+ freshness: FreshnessSchema
5046
+ });
5047
+ var TaskStatusInputSchema = z.object({
5048
+ task: TaskToolRefSchema.optional()
5049
+ }).merge(PageRequestSchema).strict();
5050
+ var TaskStatusItemSchema = z.object({
5051
+ task: TaskToolRefSchema,
5052
+ issue: z.number().int().positive(),
5053
+ pr: z.number().int().positive().nullable(),
5054
+ state: z.string()
5055
+ }).merge(ObservedSchema);
5056
+ var TaskStatusResultSchema = z.object({
5057
+ items: z.array(TaskStatusItemSchema),
5058
+ nextCursor: z.string().nullable()
5059
+ });
5060
+ var RequestedAuthoritySchema = z.enum(["planner", "principal", "operator", "self"]);
5061
+ var EscalationInputsSchema = z.object({
5062
+ task: z.number().int().positive(),
5063
+ round: z.number().int().nonnegative(),
5064
+ head: z.string(),
5065
+ branch: z.string(),
5066
+ prNumber: z.number().int().positive()
5067
+ });
5068
+ var EscalationEvidenceSchema = z.object({
5069
+ round: z.number().int().nonnegative(),
5070
+ reviewer: z.string().nullable(),
5071
+ security: z.string().nullable()
5072
+ });
5073
+ var EscalationRunIdentitySchema = z.object({
5074
+ runId: z.string(),
5075
+ pid: z.number().int().positive(),
5076
+ host: z.string()
5077
+ });
5078
+ var EscalationInputVersionsSchema = z.object({
5079
+ briefHash: z.string().nullable(),
5080
+ objectivesVersion: z.string().nullable(),
5081
+ rulingOrdinal: z.number().int().nonnegative(),
5082
+ policyDigest: z.string()
5083
+ });
5084
+ var TaskEscalationReadInputSchema = z.object({
5085
+ task: TaskToolRefSchema
5086
+ }).merge(PageRequestSchema).strict();
5087
+ var TaskEscalationPacketSchema = z.object({
5088
+ reason: z.string(),
5089
+ detail: z.string().nullable(),
5090
+ inputs: EscalationInputsSchema.nullable(),
5091
+ evidence: EscalationEvidenceSchema.nullable(),
5092
+ attemptedRecovery: z.string(),
5093
+ requestedAuthority: RequestedAuthoritySchema,
5094
+ permittedNextActions: z.array(z.string()),
5095
+ runIdentity: EscalationRunIdentitySchema.nullable(),
5096
+ inputVersions: EscalationInputVersionsSchema.nullable()
5097
+ }).merge(ObservedSchema);
5098
+ var TaskEscalationReadResultSchema = z.object({
5099
+ items: z.array(TaskEscalationPacketSchema),
5100
+ nextCursor: z.string().nullable()
5101
+ }).merge(ObservedSchema);
5102
+ var TaskStartInputSchema = z.object({
5103
+ tranche: z.string().min(1),
5104
+ id: z.string().min(1)
5105
+ }).strict();
5106
+ var TaskStartResultSchema = z.object({
5107
+ requestId: z.string().min(1),
5108
+ run: z.object({ tranche: z.string().min(1), id: z.string().min(1) }),
5109
+ started: z.boolean(),
5110
+ startedAt: z.string(),
5111
+ mode: z.literal("attended")
5112
+ });
5113
+ var TaskResumeInputSchema = z.object({
5114
+ task: TaskToolRefSchema
5115
+ }).strict();
5116
+ var TaskCancelInputSchema = z.object({
5117
+ task: TaskToolRefSchema,
5118
+ reason: z.string().min(1)
5119
+ }).strict();
5120
+ var TaskResumeResultSchema = z.object({
5121
+ task: z.number().int().positive(),
5122
+ pr: z.number().int().positive(),
5123
+ escalationId: z.string().min(1),
5124
+ outcome: z.enum(["started", "already_resumed"]),
5125
+ authenticatedBy: z.string().min(1),
5126
+ authenticatedFrom: z.string().min(1)
5127
+ });
5128
+ var TaskCancelOutcomeSchema = z.enum(["confirmed", "pending", "uncertain"]);
5129
+ var TaskCancelResultSchema = z.object({
5130
+ task: z.number().int().positive(),
5131
+ pr: z.number().int().positive(),
5132
+ escalationId: z.string().min(1),
5133
+ outcome: TaskCancelOutcomeSchema,
5134
+ authenticatedBy: z.string().min(1),
5135
+ authenticatedFrom: z.string().min(1),
5136
+ fencedEffectKeys: z.array(z.string())
5137
+ });
5138
+ var TASK_TOOL_NAMES = [
5139
+ "task_start",
5140
+ "task_status",
5141
+ "task_escalation_read",
5142
+ "task_resume",
5143
+ "task_cancel"
5144
+ ];
5145
+ var OPERATOR_STATUS_FOLLOW = "task_status_follow";
5146
+ var OPERATOR_TOOL_GRANT = [...TASK_TOOL_NAMES, OPERATOR_STATUS_FOLLOW];
4622
5147
  // ../../packages/aeg-core/src/first-push-dispatch-gate.ts
4623
5148
  function parseTaskBranch(branch) {
4624
5149
  const m = /^task\/([^/]+)\/([^/]+)$/.exec(branch);
@@ -4702,7 +5227,6 @@ function decideIssueAssignment(input) {
4702
5227
  };
4703
5228
  }
4704
5229
  // ../../packages/aeg-core/src/test-plan-gate.ts
4705
- var TASK_BRANCH_PATTERN2 = /^task\/[^/]+\/[^/]+$/;
4706
5230
  function evaluateTestPlanGate(body, branch) {
4707
5231
  if (!body) {
4708
5232
  return {
@@ -4715,7 +5239,7 @@ function evaluateTestPlanGate(body, branch) {
4715
5239
  }
4716
5240
  const located = locateTestPlanSection(body);
4717
5241
  if (!located.found) {
4718
- if (TASK_BRANCH_PATTERN2.test(branch)) {
5242
+ if (parseTaskBranchIdentity(branch) !== null) {
4719
5243
  return {
4720
5244
  verdict: "fail",
4721
5245
  messages: [
@@ -4842,8 +5366,11 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
4842
5366
  }
4843
5367
  return findings;
4844
5368
  }
5369
+ // ../../packages/aeg-core/src/log/envelope.ts
5370
+ import { createHash as createHash5 } from "node:crypto";
5371
+
4845
5372
  // ../../packages/aeg-core/src/log/schema.ts
4846
- import { z } from "zod";
5373
+ import { z as z2 } from "zod";
4847
5374
  var ROLE_VALUES = [
4848
5375
  "planner",
4849
5376
  "developer",
@@ -4853,136 +5380,174 @@ var ROLE_VALUES = [
4853
5380
  "archivist",
4854
5381
  "architect"
4855
5382
  ];
4856
- var RoleSchema = z.enum(ROLE_VALUES);
5383
+ var RoleSchema = z2.enum(ROLE_VALUES);
4857
5384
  var HOST_VALUES = ["hook", "ci", "cli", "loop"];
4858
- var HostSchema = z.enum(HOST_VALUES);
5385
+ var HostSchema = z2.enum(HOST_VALUES);
4859
5386
  var RUN_ID_PATTERN = /^[A-Za-z0-9_.-]{1,128}$/;
4860
- var HeaderMetaSchema = z.object({
4861
- schema: z.literal(1),
4862
- ts: z.string(),
4863
- run_id: z.string().regex(RUN_ID_PATTERN),
4864
- seq: z.number().int().nonnegative(),
4865
- repo: z.string().nullable(),
4866
- vinaya: z.string(),
4867
- doctrine: z.string(),
5387
+ var headerMetaCore = {
5388
+ ts: z2.string(),
5389
+ run_id: z2.string().regex(RUN_ID_PATTERN),
5390
+ seq: z2.number().int().nonnegative(),
5391
+ repo: z2.string().nullable(),
5392
+ vinaya: z2.string(),
5393
+ doctrine: z2.string(),
4868
5394
  host: HostSchema,
4869
- machine: z.string()
5395
+ machine: z2.string()
5396
+ };
5397
+ var HeaderMetaV1Schema = z2.object({
5398
+ schema: z2.literal(1),
5399
+ ...headerMetaCore
4870
5400
  }).strict();
4871
- var SubjectSchema = z.object({
4872
- issue: z.number().int().nullable(),
4873
- pr: z.number().int().optional(),
4874
- sha: z.string().optional(),
4875
- role: z.union([RoleSchema, z.literal("unattributed")]),
4876
- round: z.number().int().optional(),
4877
- objectives_version: z.string().optional()
5401
+ var LineageSchema = z2.object({
5402
+ run: z2.string().nullable(),
5403
+ attempt: z2.number().int().nullable(),
5404
+ parent: z2.string().nullable()
4878
5405
  }).strict();
4879
- var HeaderSchema = z.object({
5406
+ var InputVersionsSchema = z2.object({
5407
+ objectives_version: z2.string().nullable(),
5408
+ brief_hash: z2.string().nullable(),
5409
+ ruling_ordinal: z2.number().int().nullable(),
5410
+ policy_digest: z2.string().nullable()
5411
+ }).strict();
5412
+ var ProvenanceSchema = z2.enum(["parent_attributed", "env_correlated", "self_reported", "unavailable"]);
5413
+ var HeaderMetaV2Schema = z2.object({
5414
+ schema: z2.literal(2),
5415
+ ...headerMetaCore,
5416
+ event_id: z2.string().min(1),
5417
+ process_id: z2.string().min(1),
5418
+ actor_id: z2.string().nullable(),
5419
+ lineage: LineageSchema,
5420
+ input_versions: InputVersionsSchema,
5421
+ provenance: ProvenanceSchema
5422
+ }).strict();
5423
+ var HeaderMetaSchema = z2.discriminatedUnion("schema", [HeaderMetaV1Schema, HeaderMetaV2Schema]);
5424
+ var SubjectSchema = z2.object({
5425
+ issue: z2.number().int().nullable(),
5426
+ pr: z2.number().int().optional(),
5427
+ sha: z2.string().optional(),
5428
+ role: z2.union([RoleSchema, z2.literal("unattributed")]),
5429
+ round: z2.number().int().optional(),
5430
+ objectives_version: z2.string().optional()
5431
+ }).strict();
5432
+ var HeaderSchema = z2.object({
4880
5433
  meta: HeaderMetaSchema,
4881
5434
  subject: SubjectSchema
4882
5435
  }).strict();
4883
5436
  var envelopeTail = {
4884
- duration_ms: z.number().nonnegative().optional(),
4885
- payload: z.object({}).strict()
5437
+ duration_ms: z2.number().nonnegative().optional(),
5438
+ payload: z2.object({}).strict()
4886
5439
  };
4887
- var DispatchOutcomeSchema = z.discriminatedUnion("type", [
4888
- z.object({ type: z.literal("pr_opened"), pr: z.number().int(), head: z.string() }).strict(),
4889
- z.object({
4890
- type: z.literal("round_pushed"),
4891
- pr: z.number().int(),
4892
- head: z.string(),
4893
- comment_id: z.number().int()
5440
+ var ReviewFindingSchema = z2.object({
5441
+ id: z2.string(),
5442
+ severity: z2.string(),
5443
+ state: z2.string().optional(),
5444
+ severity_scale: z2.string().optional(),
5445
+ policy_treatment: z2.enum(["blocking", "non_blocking", "unavailable"]).optional(),
5446
+ confidence: z2.number().min(0).max(1).optional(),
5447
+ confidence_scale: z2.string().optional(),
5448
+ confidence_source: z2.string().optional()
5449
+ }).strict();
5450
+ var DispatchOutcomeSchema = z2.discriminatedUnion("type", [
5451
+ z2.object({ type: z2.literal("pr_opened"), pr: z2.number().int(), head: z2.string() }).strict(),
5452
+ z2.object({
5453
+ type: z2.literal("round_pushed"),
5454
+ pr: z2.number().int(),
5455
+ head: z2.string(),
5456
+ comment_id: z2.number().int()
4894
5457
  }).strict(),
4895
- z.object({
4896
- type: z.literal("verdict"),
4897
- verdict: z.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
4898
- head: z.string(),
4899
- comment_id: z.number().int(),
4900
- objectives: z.array(z.object({ id: z.string(), met: z.boolean() }).strict()),
4901
- findings: z.array(z.object({ id: z.string(), severity: z.string(), state: z.string().optional() }).strict())
5458
+ z2.object({
5459
+ type: z2.literal("verdict"),
5460
+ verdict: z2.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
5461
+ head: z2.string(),
5462
+ comment_id: z2.number().int(),
5463
+ objectives: z2.array(z2.object({ id: z2.string(), met: z2.boolean() }).strict()),
5464
+ findings: z2.array(ReviewFindingSchema)
4902
5465
  }).strict(),
4903
- z.object({
4904
- type: z.literal("escalation"),
4905
- class: z.enum(["authority", "strategy", "product"]),
4906
- comment_id: z.number().int()
5466
+ z2.object({
5467
+ type: z2.literal("escalation"),
5468
+ class: z2.enum(["authority", "strategy", "product"]),
5469
+ comment_id: z2.number().int()
4907
5470
  }).strict(),
4908
- z.object({ type: z.literal("brief"), comment_id: z.number().int(), hash: z.string() }).strict(),
4909
- z.object({ type: z.literal("plan"), issues: z.array(z.number().int()) }).strict(),
4910
- z.object({ type: z.literal("archive"), provenance_comment_id: z.number().int() }).strict()
5471
+ z2.object({ type: z2.literal("brief"), comment_id: z2.number().int(), hash: z2.string() }).strict(),
5472
+ z2.object({ type: z2.literal("plan"), issues: z2.array(z2.number().int()) }).strict(),
5473
+ z2.object({ type: z2.literal("archive"), provenance_comment_id: z2.number().int() }).strict(),
5474
+ z2.object({ type: z2.literal("completed") }).strict()
4911
5475
  ]);
4912
5476
  var dispatchShared = {
4913
5477
  meta: HeaderMetaSchema,
4914
5478
  subject: SubjectSchema,
4915
- kind: z.literal("dispatch"),
5479
+ kind: z2.literal("dispatch"),
4916
5480
  ...envelopeTail,
4917
5481
  target_role: RoleSchema,
4918
- model: z.string(),
4919
- round: z.number().int().optional(),
4920
- effect_id: z.string()
5482
+ model: z2.string(),
5483
+ round: z2.number().int().optional(),
5484
+ effect_id: z2.string()
4921
5485
  };
4922
- var dispatchUsageField = z.object({ input: z.number().nonnegative(), output: z.number().nonnegative() }).strict().nullable();
4923
- var DispatchEventSchema = z.discriminatedUnion("event", [
4924
- z.object({ ...dispatchShared, event: z.literal("dispatched"), prompt_hash: z.string() }).strict(),
4925
- z.object({
5486
+ var dispatchUsageField = z2.object({ input: z2.number().nonnegative(), output: z2.number().nonnegative() }).strict().nullable();
5487
+ var DispatchEventSchema = z2.discriminatedUnion("event", [
5488
+ z2.object({ ...dispatchShared, event: z2.literal("dispatched"), prompt_hash: z2.string() }).strict(),
5489
+ z2.object({
4926
5490
  ...dispatchShared,
4927
- event: z.literal("outcome_received"),
5491
+ event: z2.literal("outcome_received"),
4928
5492
  outcome: DispatchOutcomeSchema,
4929
5493
  usage: dispatchUsageField
4930
5494
  }).strict(),
4931
- z.object({
5495
+ z2.object({
4932
5496
  ...dispatchShared,
4933
- event: z.literal("dispatch_failed"),
4934
- reason: z.enum(["timeout", "crash", "refused", "unattributed_write"]),
5497
+ event: z2.literal("dispatch_failed"),
5498
+ reason: z2.enum(["timeout", "crash", "refused", "unattributed_write"]),
4935
5499
  usage: dispatchUsageField
4936
5500
  }).strict()
4937
5501
  ]);
4938
5502
  var loopShared = {
4939
5503
  meta: HeaderMetaSchema,
4940
5504
  subject: SubjectSchema,
4941
- kind: z.literal("dev_review_loop"),
5505
+ kind: z2.literal("dev_review_loop"),
4942
5506
  ...envelopeTail,
4943
- loop_id: z.string()
5507
+ loop_id: z2.string()
4944
5508
  };
4945
- var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
4946
- z.object({
5509
+ var DevReviewLoopEventSchema = z2.discriminatedUnion("event", [
5510
+ z2.object({
4947
5511
  ...loopShared,
4948
- event: z.literal("loop_started"),
4949
- task: z.number().int(),
4950
- policy: z.object({
4951
- max_rounds: z.number().int().nonnegative(),
4952
- reviewers: z.array(RoleSchema),
4953
- models: z.record(RoleSchema, z.string())
5512
+ event: z2.literal("loop_started"),
5513
+ task: z2.number().int(),
5514
+ policy: z2.object({
5515
+ max_rounds: z2.number().int().nonnegative(),
5516
+ reviewers: z2.array(RoleSchema),
5517
+ models: z2.record(RoleSchema, z2.string())
4954
5518
  }).strict()
4955
5519
  }).strict(),
4956
- z.object({ ...loopShared, event: z.literal("round_started"), round: z.number().int(), base_head: z.string() }).strict(),
4957
- z.object({
5520
+ z2.object({ ...loopShared, event: z2.literal("round_started"), round: z2.number().int(), base_head: z2.string() }).strict(),
5521
+ z2.object({
4958
5522
  ...loopShared,
4959
- event: z.literal("gate_result_read"),
4960
- round: z.number().int(),
4961
- head: z.string(),
4962
- green: z.boolean()
5523
+ event: z2.literal("gate_result_read"),
5524
+ round: z2.number().int(),
5525
+ head: z2.string(),
5526
+ green: z2.boolean()
4963
5527
  }).strict(),
4964
- z.object({
5528
+ z2.object({
4965
5529
  ...loopShared,
4966
- event: z.literal("verdicts_read"),
4967
- round: z.number().int(),
4968
- head: z.string(),
4969
- all_approve: z.boolean(),
4970
- blockers: z.number().int().nonnegative()
5530
+ event: z2.literal("verdicts_read"),
5531
+ round: z2.number().int(),
5532
+ head: z2.string(),
5533
+ all_approve: z2.boolean(),
5534
+ blockers: z2.number().int().nonnegative(),
5535
+ findings: z2.array(ReviewFindingSchema).optional()
4971
5536
  }).strict(),
4972
- z.object({
5537
+ z2.object({
4973
5538
  ...loopShared,
4974
- event: z.literal("findings_compared"),
4975
- round: z.number().int(),
4976
- open: z.array(z.string()),
4977
- resolved: z.array(z.string()),
4978
- new: z.array(z.string()),
4979
- recurring: z.array(z.string())
5539
+ event: z2.literal("findings_compared"),
5540
+ round: z2.number().int(),
5541
+ open: z2.array(z2.string()),
5542
+ resolved: z2.array(z2.string()),
5543
+ new: z2.array(z2.string()),
5544
+ recurring: z2.array(z2.string())
4980
5545
  }).strict(),
4981
- z.object({
5546
+ z2.object({
4982
5547
  ...loopShared,
4983
- event: z.literal("stop_condition_met"),
4984
- round: z.number().int(),
4985
- condition: z.enum([
5548
+ event: z2.literal("stop_condition_met"),
5549
+ round: z2.number().int(),
5550
+ condition: z2.enum([
4986
5551
  "green",
4987
5552
  "max_rounds",
4988
5553
  "no_progress",
@@ -4992,42 +5557,49 @@ var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
4992
5557
  "reappearance"
4993
5558
  ])
4994
5559
  }).strict(),
4995
- z.object({
5560
+ z2.object({
4996
5561
  ...loopShared,
4997
- event: z.literal("paused"),
4998
- round: z.number().int(),
4999
- reason: z.enum(["escalation", "principal_item", "refreeze_needed"])
5562
+ event: z2.literal("paused"),
5563
+ round: z2.number().int(),
5564
+ reason: z2.enum(["escalation", "principal_item", "refreeze_needed"])
5000
5565
  }).strict(),
5001
- z.object({
5566
+ z2.object({
5002
5567
  ...loopShared,
5003
- event: z.literal("resumed"),
5004
- round: z.number().int(),
5005
- by: z.literal("principal")
5568
+ event: z2.literal("resumed"),
5569
+ round: z2.number().int(),
5570
+ by: z2.literal("principal")
5006
5571
  }).strict(),
5007
- z.object({
5572
+ z2.object({
5008
5573
  ...loopShared,
5009
- event: z.literal("round_ended"),
5010
- round: z.number().int(),
5011
- base_head: z.string(),
5012
- head: z.string(),
5013
- files_changed: z.number().int().nonnegative(),
5014
- insertions: z.number().int().nonnegative(),
5015
- deletions: z.number().int().nonnegative(),
5016
- wall_ms: z.number().nonnegative(),
5017
- outcome: z.enum(["green", "changes_requested", "escalated"])
5574
+ event: z2.literal("unpushed_work_resume"),
5575
+ round: z2.number().int(),
5576
+ branch: z2.string(),
5577
+ detail: z2.string()
5018
5578
  }).strict(),
5019
- z.object({
5579
+ z2.object({
5020
5580
  ...loopShared,
5021
- event: z.literal("journal_finalized"),
5022
- rounds: z.number().int().nonnegative(),
5023
- total_wall_ms: z.number().nonnegative(),
5024
- time_to_green_ms: z.number().nonnegative().nullable(),
5025
- files_changed_total: z.number().int().nonnegative(),
5026
- final_head: z.string(),
5027
- result: z.enum(["merged_ready", "stopped"])
5581
+ event: z2.literal("round_ended"),
5582
+ round: z2.number().int(),
5583
+ base_head: z2.string(),
5584
+ head: z2.string(),
5585
+ files_changed: z2.number().int().nonnegative(),
5586
+ insertions: z2.number().int().nonnegative(),
5587
+ deletions: z2.number().int().nonnegative(),
5588
+ wall_ms: z2.number().nonnegative(),
5589
+ outcome: z2.enum(["green", "changes_requested", "escalated"])
5590
+ }).strict(),
5591
+ z2.object({
5592
+ ...loopShared,
5593
+ event: z2.literal("journal_finalized"),
5594
+ rounds: z2.number().int().nonnegative(),
5595
+ total_wall_ms: z2.number().nonnegative(),
5596
+ time_to_green_ms: z2.number().nonnegative().nullable(),
5597
+ files_changed_total: z2.number().int().nonnegative(),
5598
+ final_head: z2.string(),
5599
+ result: z2.enum(["merged_ready", "stopped"])
5028
5600
  }).strict()
5029
5601
  ]);
5030
- var ForgeOpSchema = z.enum([
5602
+ var ForgeOpSchema = z2.enum([
5031
5603
  "pr.create",
5032
5604
  "pr.comment",
5033
5605
  "pr.body.replace",
@@ -5041,24 +5613,434 @@ var ForgeOpSchema = z.enum([
5041
5613
  "label.add",
5042
5614
  "label.remove"
5043
5615
  ]);
5044
- var ForgeWriteTargetSchema = z.object({
5045
- issue: z.number().int().optional(),
5046
- pr: z.number().int().optional()
5616
+ var ForgeWriteTargetSchema = z2.object({
5617
+ issue: z2.number().int().optional(),
5618
+ pr: z2.number().int().optional()
5047
5619
  }).strict();
5048
5620
  var forgeWriteShared = {
5049
5621
  meta: HeaderMetaSchema,
5050
5622
  subject: SubjectSchema,
5051
- kind: z.literal("forge_write"),
5623
+ kind: z2.literal("forge_write"),
5052
5624
  ...envelopeTail,
5053
5625
  op: ForgeOpSchema,
5054
5626
  target: ForgeWriteTargetSchema
5055
5627
  };
5056
- var ForgeWriteEventSchema = z.discriminatedUnion("event", [
5057
- z.object({ ...forgeWriteShared, event: z.literal("validated") }).strict(),
5058
- z.object({ ...forgeWriteShared, event: z.literal("refused"), reason: z.string() }).strict(),
5059
- z.object({ ...forgeWriteShared, event: z.literal("written"), comment_ids: z.array(z.string()) }).strict()
5628
+ var ForgeWriteEventSchema = z2.discriminatedUnion("event", [
5629
+ z2.object({ ...forgeWriteShared, event: z2.literal("validated") }).strict(),
5630
+ z2.object({ ...forgeWriteShared, event: z2.literal("refused"), reason: z2.string() }).strict(),
5631
+ z2.object({ ...forgeWriteShared, event: z2.literal("written"), comment_ids: z2.array(z2.string()) }).strict()
5632
+ ]);
5633
+ var GateOutcomeSchema = z2.enum([
5634
+ "pass",
5635
+ "fail",
5636
+ "wait",
5637
+ "skip",
5638
+ "invalid_input",
5639
+ "unavailable_dependency",
5640
+ "timeout",
5641
+ "cancelled"
5642
+ ]);
5643
+ var gateShared = {
5644
+ meta: HeaderMetaSchema,
5645
+ subject: SubjectSchema,
5646
+ kind: z2.literal("gate"),
5647
+ ...envelopeTail,
5648
+ check: z2.string(),
5649
+ check_version: z2.string().nullable(),
5650
+ policy_version: z2.string().nullable(),
5651
+ input_fingerprint: z2.string().nullable()
5652
+ };
5653
+ var GateEventSchema = z2.discriminatedUnion("event", [
5654
+ z2.object({
5655
+ ...gateShared,
5656
+ event: z2.literal("checked"),
5657
+ outcome: GateOutcomeSchema,
5658
+ reason: z2.string().optional()
5659
+ }).strict()
5660
+ ]);
5661
+ var OperationResultSchema = z2.enum(["ok", "error", "refused", "timeout", "cancelled", "unavailable"]);
5662
+ var operationShared = {
5663
+ meta: HeaderMetaSchema,
5664
+ subject: SubjectSchema,
5665
+ kind: z2.literal("operation"),
5666
+ ...envelopeTail,
5667
+ operation: z2.string(),
5668
+ target: z2.string().nullable()
5669
+ };
5670
+ var OperationEventSchema = z2.discriminatedUnion("event", [
5671
+ z2.object({
5672
+ ...operationShared,
5673
+ event: z2.literal("completed"),
5674
+ result: OperationResultSchema,
5675
+ error_class: z2.string().nullable()
5676
+ }).strict()
5677
+ ]);
5678
+ var UsageUnitsSchema = z2.object({
5679
+ input: z2.number().nonnegative().nullable(),
5680
+ output: z2.number().nonnegative().nullable(),
5681
+ cache: z2.number().nonnegative().nullable()
5682
+ }).strict();
5683
+ var usageShared = {
5684
+ meta: HeaderMetaSchema,
5685
+ subject: SubjectSchema,
5686
+ kind: z2.literal("usage"),
5687
+ ...envelopeTail,
5688
+ model: z2.string().nullable(),
5689
+ source: z2.string(),
5690
+ semantics: z2.enum(["cumulative", "delta"])
5691
+ };
5692
+ var UsageEventSchema = z2.discriminatedUnion("event", [
5693
+ z2.object({
5694
+ ...usageShared,
5695
+ event: z2.literal("observed"),
5696
+ units: UsageUnitsSchema,
5697
+ unknown_reason: z2.string().nullable()
5698
+ }).strict()
5699
+ ]);
5700
+ var RoleAttemptOutcomeSchema = z2.enum([
5701
+ "completed",
5702
+ "incomplete",
5703
+ "infrastructure_failed",
5704
+ "cancelled",
5705
+ "timed_out",
5706
+ "capability_refused"
5060
5707
  ]);
5061
- var LogEventSchema = z.union([DispatchEventSchema, DevReviewLoopEventSchema, ForgeWriteEventSchema]);
5708
+ var roleAttemptShared = {
5709
+ meta: HeaderMetaSchema,
5710
+ subject: SubjectSchema,
5711
+ kind: z2.literal("role_attempt"),
5712
+ ...envelopeTail,
5713
+ actor: z2.string().nullable(),
5714
+ attempt: z2.number().int().nullable(),
5715
+ effect_id: z2.string(),
5716
+ model: z2.string().nullable()
5717
+ };
5718
+ var RoleAttemptEventSchema = z2.discriminatedUnion("event", [
5719
+ z2.object({
5720
+ ...roleAttemptShared,
5721
+ event: z2.literal("attempted"),
5722
+ outcome: RoleAttemptOutcomeSchema,
5723
+ usage: dispatchUsageField
5724
+ }).strict()
5725
+ ]);
5726
+ var handoffShared = {
5727
+ meta: HeaderMetaSchema,
5728
+ subject: SubjectSchema,
5729
+ kind: z2.literal("handoff"),
5730
+ ...envelopeTail,
5731
+ class: z2.enum(["authority", "strategy", "product"]),
5732
+ reason: z2.string()
5733
+ };
5734
+ var HandoffEventSchema = z2.discriminatedUnion("event", [
5735
+ z2.object({
5736
+ ...handoffShared,
5737
+ event: z2.literal("raised"),
5738
+ requested_decision: z2.string().nullable()
5739
+ }).strict(),
5740
+ z2.object({
5741
+ ...handoffShared,
5742
+ event: z2.literal("resolved"),
5743
+ resolution: z2.string().nullable(),
5744
+ resolved_by: z2.string().nullable()
5745
+ }).strict()
5746
+ ]);
5747
+ var EffectTargetSchema = z2.object({
5748
+ kind: z2.string(),
5749
+ ref: z2.string()
5750
+ }).strict();
5751
+ var effectShared = {
5752
+ meta: HeaderMetaSchema,
5753
+ subject: SubjectSchema,
5754
+ kind: z2.literal("effect"),
5755
+ ...envelopeTail,
5756
+ effect_id: z2.string(),
5757
+ target: EffectTargetSchema
5758
+ };
5759
+ var EffectEventSchema = z2.discriminatedUnion("event", [
5760
+ z2.object({ ...effectShared, event: z2.literal("attempted") }).strict(),
5761
+ z2.object({ ...effectShared, event: z2.literal("observed"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict(),
5762
+ z2.object({ ...effectShared, event: z2.literal("verified"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict()
5763
+ ]);
5764
+ var LogEventSchema = z2.union([
5765
+ DispatchEventSchema,
5766
+ DevReviewLoopEventSchema,
5767
+ ForgeWriteEventSchema,
5768
+ GateEventSchema,
5769
+ OperationEventSchema,
5770
+ UsageEventSchema,
5771
+ RoleAttemptEventSchema,
5772
+ HandoffEventSchema,
5773
+ EffectEventSchema
5774
+ ]);
5775
+
5776
+ // ../../packages/aeg-core/src/log/envelope.ts
5777
+ function isRole(value) {
5778
+ return value !== undefined && ROLE_VALUES.includes(value);
5779
+ }
5780
+ function actorIdFromEnv(role) {
5781
+ return role === undefined || role === "" ? null : role;
5782
+ }
5783
+ function lineageFieldFromEnv(value) {
5784
+ return value === undefined || value === "" ? null : value;
5785
+ }
5786
+ function attemptFromEnv(value) {
5787
+ if (value === undefined || value === "")
5788
+ return null;
5789
+ const n = Number(value);
5790
+ return Number.isInteger(n) ? n : null;
5791
+ }
5792
+ function provenanceFor(input) {
5793
+ if (input.provenance)
5794
+ return input.provenance;
5795
+ if (input.env.role || input.env.task)
5796
+ return "env_correlated";
5797
+ return "unavailable";
5798
+ }
5799
+ function issueFromTask(task) {
5800
+ if (task === undefined || task === "")
5801
+ return null;
5802
+ const n = Number(task);
5803
+ return Number.isInteger(n) ? n : null;
5804
+ }
5805
+ function roundFromEnv(round) {
5806
+ if (round === undefined || round === "")
5807
+ return;
5808
+ const n = Number(round);
5809
+ return Number.isInteger(n) ? n : undefined;
5810
+ }
5811
+ function buildHeader(input) {
5812
+ const role = isRole(input.env.role) ? input.env.role : "unattributed";
5813
+ const round = roundFromEnv(input.env.round);
5814
+ const subject = {
5815
+ issue: issueFromTask(input.env.task),
5816
+ role,
5817
+ ...round !== undefined ? { round } : {},
5818
+ ...input.subject ?? {}
5819
+ };
5820
+ return {
5821
+ meta: {
5822
+ schema: 2,
5823
+ ts: input.now.toISOString(),
5824
+ run_id: input.runId,
5825
+ seq: input.seq,
5826
+ repo: input.repo,
5827
+ vinaya: input.vinaya,
5828
+ doctrine: input.doctrine,
5829
+ host: input.host,
5830
+ machine: createHash5("sha256").update(input.hostname).digest("hex"),
5831
+ event_id: input.eventId,
5832
+ process_id: input.processId,
5833
+ actor_id: actorIdFromEnv(input.env.role),
5834
+ lineage: {
5835
+ run: lineageFieldFromEnv(input.env.run),
5836
+ attempt: attemptFromEnv(input.env.attempt),
5837
+ parent: lineageFieldFromEnv(input.env.parent)
5838
+ },
5839
+ input_versions: {
5840
+ objectives_version: input.inputVersions?.objectivesVersion ?? null,
5841
+ brief_hash: input.inputVersions?.briefHash ?? null,
5842
+ ruling_ordinal: input.inputVersions?.rulingOrdinal ?? null,
5843
+ policy_digest: input.inputVersions?.policyDigest ?? null
5844
+ },
5845
+ provenance: provenanceFor(input)
5846
+ },
5847
+ subject
5848
+ };
5849
+ }
5850
+ // ../../packages/aeg-core/src/log/redact.ts
5851
+ var GITHUB_TOKEN_PATTERN = /\b(?:gho_|ghp_|ghs_|ghu_|ghr_|github_pat_)[A-Za-z0-9_]+\b/g;
5852
+ var CLASSIC_GITHUB_PAT_PATTERN = /\b((?:token|GITHUB_TOKEN|PAT|api[_-]?key|api[_-]?token)\s*[:=]\s*)[a-f0-9]{40}\b/gi;
5853
+ var BEARER_TOKEN_PATTERN = /\bBearer\s+\S+/g;
5854
+ var AWS_ACCESS_KEY_PATTERN = /\bAKIA[0-9A-Z]{16}\b/g;
5855
+ var SLACK_TOKEN_PATTERN = /\bxox[baprs]-[0-9A-Za-z-]+\b/g;
5856
+ var STRIPE_KEY_PATTERN = /\b(?:sk|pk|rk)_(?:live|test)_[0-9A-Za-z]{10,}\b/g;
5857
+ var ANTHROPIC_KEY_PATTERN = /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g;
5858
+ var OPENAI_KEY_PATTERN = /\bsk-(?!ant-)[A-Za-z0-9]{20,}\b/g;
5859
+ var NPM_TOKEN_PATTERN = /\bnpm_[A-Za-z0-9]{36}\b/g;
5860
+ var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g;
5861
+ var PEM_BLOCK_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g;
5862
+ var BASIC_AUTH_URL_PATTERN = /(https?:\/\/)[^/\s:@]+:[^/\s@]+@/g;
5863
+ 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;
5864
+ function redactString(value, home) {
5865
+ 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>");
5866
+ if (home.length > 0 && out.startsWith(home)) {
5867
+ const rest = out.slice(home.length);
5868
+ if (rest === "" || rest.startsWith("/"))
5869
+ out = `~${rest}`;
5870
+ }
5871
+ return out;
5872
+ }
5873
+ function redact(value, home) {
5874
+ if (typeof value === "string")
5875
+ return redactString(value, home);
5876
+ if (Array.isArray(value))
5877
+ return value.map((v) => redact(v, home));
5878
+ if (value !== null && typeof value === "object") {
5879
+ const out = {};
5880
+ for (const [k, v] of Object.entries(value)) {
5881
+ out[k] = redact(v, home);
5882
+ }
5883
+ return out;
5884
+ }
5885
+ return value;
5886
+ }
5887
+ // ../../packages/aeg-core/src/log/store.ts
5888
+ function metaOf(obj) {
5889
+ if (obj === null || typeof obj !== "object")
5890
+ return null;
5891
+ const meta = obj.meta;
5892
+ if (meta === null || typeof meta !== "object")
5893
+ return null;
5894
+ return meta;
5895
+ }
5896
+ function recordIdentity(obj) {
5897
+ const meta = metaOf(obj);
5898
+ if (meta === null)
5899
+ return null;
5900
+ const eventId = meta.event_id;
5901
+ if (typeof eventId === "string" && eventId.length > 0)
5902
+ return eventId;
5903
+ const runId = meta.run_id;
5904
+ const seq = meta.seq;
5905
+ if (typeof runId === "string" && runId.length > 0 && typeof seq === "number" && Number.isInteger(seq)) {
5906
+ return `${runId}:${seq}`;
5907
+ }
5908
+ return null;
5909
+ }
5910
+
5911
+ // ../../packages/aeg-core/src/log/artifact.ts
5912
+ var TASK_LOG_ARTIFACT_MAX_BYTES = 8 * 1024 * 1024;
5913
+ // ../../packages/aeg-core/src/dev-review-loop/journal-reconstruction.ts
5914
+ var STOPPED_CONDITIONS = new Set(["confidence", "reappearance", "no_progress", "max_rounds"]);
5915
+ // ../../packages/aeg-core/src/control-store/records.ts
5916
+ import { z as z3 } from "zod";
5917
+ var isoTimestamp = z3.string().min(1);
5918
+ var taskId = z3.number().int().positive();
5919
+ var epochNumber = z3.number().int().nonnegative();
5920
+ var RunRecordSchema = z3.object({
5921
+ version: z3.literal(1),
5922
+ kind: z3.literal("run"),
5923
+ task: taskId,
5924
+ runId: z3.string().min(1),
5925
+ pid: z3.number().int().positive(),
5926
+ host: z3.string().min(1),
5927
+ startedAt: isoTimestamp,
5928
+ childStartedAt: z3.string().min(1).nullable().optional(),
5929
+ childCommand: z3.string().min(1).nullable().optional()
5930
+ }).strict();
5931
+ var InputRecordSchema = z3.object({
5932
+ version: z3.literal(1),
5933
+ kind: z3.literal("input"),
5934
+ task: taskId,
5935
+ runId: z3.string().min(1),
5936
+ source: z3.union([z3.literal("fresh"), z3.literal("resume")]),
5937
+ pr: z3.number().int().positive().nullable(),
5938
+ round: z3.number().int().nonnegative(),
5939
+ recordedAt: isoTimestamp
5940
+ }).strict();
5941
+ var OwnershipRecordSchema = z3.object({
5942
+ version: z3.literal(1),
5943
+ kind: z3.literal("ownership"),
5944
+ task: taskId,
5945
+ epoch: epochNumber,
5946
+ ownerId: z3.string().min(1),
5947
+ pid: z3.number().int().positive(),
5948
+ host: z3.string().min(1),
5949
+ acquiredAt: isoTimestamp
5950
+ }).strict();
5951
+ var TransitionRecordSchema = z3.object({
5952
+ version: z3.literal(1),
5953
+ kind: z3.literal("transition"),
5954
+ task: taskId,
5955
+ epoch: epochNumber,
5956
+ seq: z3.number().int().nonnegative(),
5957
+ from: z3.string().min(1),
5958
+ to: z3.string().min(1),
5959
+ detail: z3.string().optional(),
5960
+ at: isoTimestamp
5961
+ }).strict();
5962
+ var ManifestRecordSchema = z3.object({
5963
+ version: z3.literal(1),
5964
+ kind: z3.literal("manifest"),
5965
+ task: taskId,
5966
+ round: epochNumber,
5967
+ repository: z3.string().min(1),
5968
+ pr: z3.number().int().positive(),
5969
+ branch: z3.string().min(1),
5970
+ baseSha: z3.string().min(1).nullable(),
5971
+ headSha: z3.string().min(1),
5972
+ briefHash: z3.string().min(1).nullable(),
5973
+ objectivesVersion: z3.string().min(1).nullable(),
5974
+ rulingOrdinal: epochNumber,
5975
+ policyDigest: z3.string().min(1),
5976
+ recordedAt: isoTimestamp
5977
+ }).strict();
5978
+ var roundHeadIdentity = z3.object({ round: z3.number().int().positive(), head: z3.string().min(1) }).strict();
5979
+ var LoopBudgetsSchema = z3.object({
5980
+ mechanicalRetries: z3.number().int().nonnegative(),
5981
+ reviewRounds: z3.number().int().nonnegative(),
5982
+ infrastructureRetries: z3.number().int().nonnegative()
5983
+ }).strict();
5984
+ var LoopStateRecordSchema = z3.object({
5985
+ version: z3.literal(1),
5986
+ kind: z3.literal("loop_state"),
5987
+ task: taskId,
5988
+ round: z3.number().int().positive(),
5989
+ phase: z3.string().min(1),
5990
+ pauseReason: z3.string().min(1).nullable(),
5991
+ budgets: LoopBudgetsSchema,
5992
+ heldResult: roundHeadIdentity.nullable(),
5993
+ deliveredFindings: roundHeadIdentity.nullable(),
5994
+ recordedAt: isoTimestamp
5995
+ }).strict();
5996
+ var EffectRecordSchema = z3.object({
5997
+ version: z3.literal(1),
5998
+ kind: z3.literal("effect"),
5999
+ task: taskId,
6000
+ key: z3.string().min(1),
6001
+ operation: z3.string().min(1),
6002
+ target: z3.string().min(1),
6003
+ inputVersion: z3.number().int().nonnegative(),
6004
+ payloadDigest: z3.string().min(1),
6005
+ status: z3.union([z3.literal("started"), z3.literal("verified"), z3.literal("uncertain")]),
6006
+ url: z3.string().optional(),
6007
+ recordedAt: isoTimestamp
6008
+ }).strict();
6009
+ var EscalationRecordSchema = z3.object({
6010
+ version: z3.literal(1),
6011
+ kind: z3.literal("escalation"),
6012
+ task: taskId,
6013
+ escalationId: z3.string().min(1),
6014
+ round: epochNumber,
6015
+ head: z3.string().min(1),
6016
+ branch: z3.string().min(1),
6017
+ pr: z3.number().int().positive().nullable(),
6018
+ runId: z3.string().min(1),
6019
+ pid: z3.number().int().positive(),
6020
+ host: z3.string().min(1),
6021
+ agent: z3.string().min(1).optional(),
6022
+ reason: z3.string().min(1),
6023
+ detail: z3.string().optional(),
6024
+ evidence: z3.string().optional(),
6025
+ attemptedRecovery: z3.string().min(1),
6026
+ requestedDecision: z3.string().min(1),
6027
+ recipient: z3.string().min(1),
6028
+ briefHash: z3.string().min(1).nullable(),
6029
+ objectivesVersion: z3.string().min(1).nullable(),
6030
+ rulingOrdinal: epochNumber,
6031
+ policyDigest: z3.string().min(1),
6032
+ recordedAt: isoTimestamp
6033
+ }).strict();
6034
+ var ResolutionRecordSchema = z3.object({
6035
+ version: z3.literal(1),
6036
+ kind: z3.literal("resolution"),
6037
+ task: taskId,
6038
+ escalationId: z3.string().min(1),
6039
+ decision: z3.union([z3.literal("resume"), z3.literal("cancel")]),
6040
+ authenticatedBy: z3.string().min(1),
6041
+ authenticatedFrom: z3.string().min(1),
6042
+ consumedAt: isoTimestamp
6043
+ }).strict();
5062
6044
  // src/checks/contract.ts
5063
6045
  var CHECK_SCHEMA_VERSION = 1;
5064
6046
  function emitCheckError(error) {