@attalabs/vinaya 0.4.3 → 0.4.4

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 (170) hide show
  1. package/aeg-root/enforcement.md +1 -1
  2. package/aeg-root/state-machine.md +1 -1
  3. package/dist/checks/bin/check-branch-topology.js +44 -31
  4. package/dist/checks/bin/check-brief-shape.js +44 -31
  5. package/dist/checks/bin/check-closes-n.js +44 -31
  6. package/dist/checks/bin/check-coherence.js +44 -31
  7. package/dist/checks/bin/check-dead-branch-push.js +44 -31
  8. package/dist/checks/bin/check-dispatch-readiness.js +44 -31
  9. package/dist/checks/bin/check-doc-coverage-push.js +221 -34
  10. package/dist/checks/bin/check-doc-coverage.js +221 -34
  11. package/dist/checks/bin/check-first-push-dispatch.js +44 -31
  12. package/dist/checks/bin/check-issue-assignment.js +44 -31
  13. package/dist/checks/bin/check-no-disk-state.js +44 -31
  14. package/dist/checks/bin/check-reader-resolvable-prose.js +44 -31
  15. package/dist/checks/bin/check-registry-gates.js +44 -31
  16. package/dist/checks/bin/check-review-gate.js +222 -36
  17. package/dist/checks/bin/check-single-plan-pr.js +44 -31
  18. package/dist/checks/bin/check-test-plan.js +44 -31
  19. package/dist/index.js +116 -34
  20. package/package.json +1 -1
  21. package/studio-standalone/.worktrees/fix/bump-0.4.4/.vinaya/projects.md +63 -0
  22. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/aeg-manual-flow.md +216 -0
  23. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/archivist-tranche-archivist.md +92 -0
  24. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/brief-developer.md +140 -0
  25. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/developer-reviewer.md +106 -0
  26. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/planner-brief.md +130 -0
  27. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/reviewer-archivist.md +96 -0
  28. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/contracts/tranche-archivist-planner.md +116 -0
  29. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/coordination.md +293 -0
  30. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/documentation-coherence.md +65 -0
  31. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/enforcement.md +161 -0
  32. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/glossary.md +36 -0
  33. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/process.md +371 -0
  34. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/reviewer-prompt.md +68 -0
  35. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/archivist.md +167 -0
  36. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/brief-author.md +108 -0
  37. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/developer.md +429 -0
  38. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/planner.md +285 -0
  39. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/principal.md +107 -0
  40. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/reviewer.md +130 -0
  41. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/security.md +121 -0
  42. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/roles/tranche-archivist.md +257 -0
  43. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/aeg/SKILL.md +90 -0
  44. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/aeg-roles/SKILL.md +58 -0
  45. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/skills/brief-authoring/SKILL.md +497 -0
  46. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/state-machine.md +656 -0
  47. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/brief-template.md +103 -0
  48. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/issue-rationale-template.md +35 -0
  49. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/templates/pr-report-template.md +68 -0
  50. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranche-model.md +306 -0
  51. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-coherence-v1.md +55 -0
  52. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-coherence-v1.tokens.md +13 -0
  53. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-consolidation.md +28 -0
  54. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-hardening.md +80 -0
  55. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-ui-v2.md +168 -0
  56. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-governance-ui-v2.tokens.md +18 -0
  57. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-studio-cleanup.md +37 -0
  58. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-ui-v1.md +176 -0
  59. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/aeg-ui-v1.tokens.md +17 -0
  60. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-agents-v2.md +35 -0
  61. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-agents-v2.tokens.md +11 -0
  62. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/herald-onto-engine.md +99 -0
  63. package/studio-standalone/.worktrees/fix/bump-0.4.4/aeg-root/tranches/completed/vada-agents-v2.md +220 -0
  64. package/studio-standalone/.worktrees/fix/bump-0.4.4/apps/vinaya/cli/tests/fixtures/checks/vinaya.config.json +9 -0
  65. package/studio-standalone/.worktrees/fix/bump-0.4.4/node_modules/@attalabs/vinaya/tests/fixtures/checks/vinaya.config.json +9 -0
  66. package/studio-standalone/.worktrees/fix/bump-0.4.4/vinaya.config.json +36 -0
  67. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/.vinaya/projects.md +63 -0
  68. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/aeg-manual-flow.md +216 -0
  69. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/archivist-tranche-archivist.md +92 -0
  70. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/brief-developer.md +140 -0
  71. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/developer-reviewer.md +106 -0
  72. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/planner-brief.md +130 -0
  73. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/reviewer-archivist.md +96 -0
  74. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/contracts/tranche-archivist-planner.md +116 -0
  75. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/coordination.md +293 -0
  76. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/documentation-coherence.md +65 -0
  77. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/enforcement.md +161 -0
  78. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/glossary.md +36 -0
  79. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/process.md +371 -0
  80. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/reviewer-prompt.md +68 -0
  81. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/archivist.md +167 -0
  82. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/brief-author.md +108 -0
  83. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/developer.md +429 -0
  84. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/planner.md +285 -0
  85. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/principal.md +107 -0
  86. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/reviewer.md +130 -0
  87. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/security.md +121 -0
  88. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/roles/tranche-archivist.md +257 -0
  89. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/aeg/SKILL.md +90 -0
  90. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/aeg-roles/SKILL.md +58 -0
  91. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/skills/brief-authoring/SKILL.md +497 -0
  92. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/state-machine.md +656 -0
  93. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/brief-template.md +103 -0
  94. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/issue-rationale-template.md +35 -0
  95. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/templates/pr-report-template.md +68 -0
  96. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranche-model.md +306 -0
  97. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-coherence-v1.md +55 -0
  98. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-coherence-v1.tokens.md +13 -0
  99. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-consolidation.md +28 -0
  100. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-hardening.md +80 -0
  101. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-ui-v2.md +168 -0
  102. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-governance-ui-v2.tokens.md +18 -0
  103. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-studio-cleanup.md +37 -0
  104. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-ui-v1.md +176 -0
  105. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/aeg-ui-v1.tokens.md +17 -0
  106. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-agents-v2.md +35 -0
  107. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-agents-v2.tokens.md +11 -0
  108. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/herald-onto-engine.md +99 -0
  109. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/aeg-root/tranches/completed/vada-agents-v2.md +220 -0
  110. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/apps/vinaya/cli/tests/fixtures/checks/vinaya.config.json +9 -0
  111. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/node_modules/@attalabs/vinaya/tests/fixtures/checks/vinaya.config.json +9 -0
  112. package/studio-standalone/.worktrees/fix/check-lifecycle-phase/vinaya.config.json +36 -0
  113. package/studio-standalone/_node_modules/@atta/vinaya-cli/aeg-root/enforcement.md +1 -1
  114. package/studio-standalone/_node_modules/@atta/vinaya-cli/aeg-root/state-machine.md +1 -1
  115. package/studio-standalone/_node_modules/@attalabs/vinaya/aeg-root/enforcement.md +1 -1
  116. package/studio-standalone/_node_modules/@attalabs/vinaya/aeg-root/state-machine.md +1 -1
  117. package/studio-standalone/apps/vinaya/cli/aeg-root/enforcement.md +1 -1
  118. package/studio-standalone/apps/vinaya/cli/aeg-root/state-machine.md +1 -1
  119. package/studio-standalone/apps/vinaya/web/.next/BUILD_ID +1 -1
  120. package/studio-standalone/apps/vinaya/web/.next/build-manifest.json +3 -3
  121. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/cli/page.js.nft.json +1 -1
  122. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/config/page.js.nft.json +1 -1
  123. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/cli/page.js.nft.json +1 -1
  124. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/harness/page.js.nft.json +1 -1
  125. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(standalone)/state-machine/page.js.nft.json +1 -1
  126. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(with-sidebar)/[...slug]/page.js.nft.json +1 -1
  127. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/(with-sidebar)/reference/page.js.nft.json +1 -1
  128. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/docs/page.js.nft.json +1 -1
  129. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/install/page.js.nft.json +1 -1
  130. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/page.js.nft.json +1 -1
  131. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/roadmap/page.js.nft.json +1 -1
  132. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/archive/page.js.nft.json +1 -1
  133. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/brief/page.js.nft.json +1 -1
  134. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/develop/page.js.nft.json +1 -1
  135. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/overview/page.js.nft.json +1 -1
  136. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/page.js.nft.json +1 -1
  137. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/plan/page.js.nft.json +1 -1
  138. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/quick/page.js.nft.json +1 -1
  139. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/review/page.js.nft.json +1 -1
  140. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/security/page.js.nft.json +1 -1
  141. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/start/wrap-up/page.js.nft.json +1 -1
  142. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/state-machine/page.js.nft.json +1 -1
  143. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/the-harness/page.js.nft.json +1 -1
  144. package/studio-standalone/apps/vinaya/web/.next/server/app/(site)/the-studio/page.js.nft.json +1 -1
  145. package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  146. package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.html +1 -1
  147. package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.rsc +1 -1
  148. package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  149. package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  150. package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  151. package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  152. package/studio-standalone/apps/vinaya/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  153. package/studio-standalone/apps/vinaya/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  154. package/studio-standalone/apps/vinaya/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
  155. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  156. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/docs/[...slug]/page.js.nft.json +1 -1
  157. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/docs/page.js.nft.json +1 -1
  158. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/page.js.nft.json +1 -1
  159. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  160. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  161. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  162. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  163. package/studio-standalone/apps/vinaya/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  164. package/studio-standalone/apps/vinaya/web/.next/server/chunks/ssr/[root-of-the-server]__0kqmrho._.js +1 -1
  165. package/studio-standalone/apps/vinaya/web/.next/server/chunks/ssr/[root-of-the-server]__1dxaovd._.js +2 -2
  166. package/studio-standalone/apps/vinaya/web/.next/server/middleware-build-manifest.js +3 -3
  167. package/studio-standalone/apps/vinaya/web/.next/server/pages/500.html +1 -1
  168. /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_buildManifest.js +0 -0
  169. /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_clientMiddlewareManifest.js +0 -0
  170. /package/studio-standalone/apps/vinaya/web/.next/static/{Afs41Lu9uNQ-T6uC-tm4_ → mSHYKKSLd91iaLw52dYpD}/_ssgManifest.js +0 -0
@@ -2,7 +2,7 @@
2
2
  // @bun
3
3
 
4
4
  // src/checks/bin/check-doc-coverage.ts
5
- import { execFileSync as execFileSync2 } from "child_process";
5
+ import { execFileSync as execFileSync3 } from "child_process";
6
6
  import { existsSync, readFileSync } from "fs";
7
7
  // ../../../packages/aeg-core/src/anchored-region.ts
8
8
  function maskCode(body) {
@@ -1453,12 +1453,16 @@ function isCodeFile(p) {
1453
1453
  var WAIVER_LABEL = label("waiver-docs");
1454
1454
  var WAIVER_LABEL_REVIEW = label("waiver-review");
1455
1455
  var PRINCIPAL_ALLOWLIST = ["daniboomerang"];
1456
+ function isPrincipal(login, principalAllowlist) {
1457
+ if (login === null)
1458
+ return false;
1459
+ const normalized = login.toLowerCase();
1460
+ return principalAllowlist.some((p) => p.toLowerCase() === normalized);
1461
+ }
1456
1462
  function isWaiverLabelActorVerified(opts) {
1457
1463
  if (!opts.labels.includes(opts.label))
1458
1464
  return false;
1459
- if (opts.labelActor === null)
1460
- return false;
1461
- return opts.principalAllowlist.includes(opts.labelActor);
1465
+ return isPrincipal(opts.labelActor, opts.principalAllowlist);
1462
1466
  }
1463
1467
 
1464
1468
  // ../../../packages/aeg-core/src/doc-owners.ts
@@ -1646,6 +1650,27 @@ function overrideActive(opts) {
1646
1650
  // ../../../packages/aeg-core/src/premise-check.ts
1647
1651
  var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
1648
1652
 
1653
+ // ../../../packages/aeg-core/src/test-plan-section.ts
1654
+ var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
1655
+ var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
1656
+ var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
1657
+ function locateTestPlanSection(body) {
1658
+ const region = anchoredRegion(body, "TEST-PLAN");
1659
+ if (region !== null)
1660
+ return { found: true, section: region };
1661
+ const headingMatch = HEADING_FORM_RE.exec(body);
1662
+ const match = headingMatch ?? INLINE_FORM_RE.exec(body);
1663
+ if (!match || match.index === undefined)
1664
+ return { found: false };
1665
+ const sectionBody = body.slice(match.index);
1666
+ const firstLineEnd = sectionBody.indexOf(`
1667
+ `);
1668
+ const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
1669
+ const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
1670
+ const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
1671
+ return { found: true, section: sectionBody.slice(0, sectionEnd) };
1672
+ }
1673
+
1649
1674
  // ../../../packages/aeg-core/src/brief-validation.ts
1650
1675
  function headerRegion(prBody) {
1651
1676
  const m = prBody.match(/^##\s/m);
@@ -1684,10 +1709,15 @@ function checkTierField(prBody, readTier) {
1684
1709
  };
1685
1710
  }
1686
1711
  var TEST_PLAN_UNIT_TESTS_ONLY_RE = /(?:\*\*)?Test Plan(?:\*\*)?\s*:\s*(?:\*\*)?\s*unit-tests-only/i;
1712
+ function testPlanRegion(prBody) {
1713
+ const located = locateTestPlanSection(prBody);
1714
+ return located.found ? located.section : prBody;
1715
+ }
1687
1716
  function checkTestPlan(prBody) {
1688
- if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(prBody))
1717
+ const region = testPlanRegion(prBody);
1718
+ if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
1689
1719
  return { status: "pass", errors: [] };
1690
- if (/\*\*\[(?:agent|principal)\]\*\*/.test(prBody))
1720
+ if (/\*\*\[(?:agent|principal)\]\*\*/.test(region))
1691
1721
  return { status: "pass", errors: [] };
1692
1722
  return {
1693
1723
  status: "fail",
@@ -1697,9 +1727,10 @@ function checkTestPlan(prBody) {
1697
1727
  };
1698
1728
  }
1699
1729
  function checkTestPlanExclusivity(prBody) {
1700
- if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(prBody))
1730
+ const region = testPlanRegion(prBody);
1731
+ if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
1701
1732
  return { status: "pass", errors: [] };
1702
- if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(prBody)) {
1733
+ if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(region)) {
1703
1734
  return {
1704
1735
  status: "fail",
1705
1736
  errors: [
@@ -1710,8 +1741,9 @@ function checkTestPlanExclusivity(prBody) {
1710
1741
  return { status: "pass", errors: [] };
1711
1742
  }
1712
1743
  function checkPrincipalPlaceholder(prBody) {
1744
+ const region = testPlanRegion(prBody);
1713
1745
  const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
1714
- for (const m of prBody.matchAll(lineRe)) {
1746
+ for (const m of region.matchAll(lineRe)) {
1715
1747
  const content = m[1] ?? "";
1716
1748
  if (/^\s*None\b/i.test(content)) {
1717
1749
  return {
@@ -2159,11 +2191,12 @@ function isReviewGateExemptBranch(branch) {
2159
2191
  return branch.startsWith("plan/");
2160
2192
  }
2161
2193
  function checkReviewGate(input) {
2194
+ const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
2162
2195
  const waived = isWaiverLabelActorVerified({
2163
2196
  label: WAIVER_LABEL_REVIEW,
2164
2197
  labels: input.labels,
2165
2198
  labelActor: input.waiverLabelActor,
2166
- principalAllowlist: PRINCIPAL_ALLOWLIST
2199
+ principalAllowlist
2167
2200
  });
2168
2201
  if (waived) {
2169
2202
  return {
@@ -2172,8 +2205,8 @@ function checkReviewGate(input) {
2172
2205
  waived: true
2173
2206
  };
2174
2207
  }
2175
- const verified = input.comments.filter((c) => c.author !== null && PRINCIPAL_ALLOWLIST.includes(c.author));
2176
- const ignoredCount = input.comments.filter((c) => (c.author === null || !PRINCIPAL_ALLOWLIST.includes(c.author)) && c.body.includes("VERDICT")).length;
2208
+ const verified = input.comments.filter((c) => isPrincipal(c.author, principalAllowlist));
2209
+ const ignoredCount = input.comments.filter((c) => !isPrincipal(c.author, principalAllowlist) && c.body.includes("VERDICT")).length;
2177
2210
  const verifiedBodies = verified.map((c) => c.body);
2178
2211
  const codeReview = extractCodeReviewVerdict(verifiedBodies);
2179
2212
  const security = extractSecurityReviewVerdict(verifiedBodies);
@@ -2726,26 +2759,6 @@ function decideIssueAssignment(input) {
2726
2759
  reason: `First push of \`${branch}\` — assigning Issue #${issue} to @${login} (the authenticated pusher).`
2727
2760
  };
2728
2761
  }
2729
- // ../../../packages/aeg-core/src/test-plan-section.ts
2730
- var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
2731
- var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
2732
- var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
2733
- function locateTestPlanSection(body) {
2734
- const region = anchoredRegion(body, "TEST-PLAN");
2735
- if (region !== null)
2736
- return { found: true, section: region };
2737
- const headingMatch = HEADING_FORM_RE.exec(body);
2738
- const match = headingMatch ?? INLINE_FORM_RE.exec(body);
2739
- if (!match || match.index === undefined)
2740
- return { found: false };
2741
- const sectionBody = body.slice(match.index);
2742
- const firstLineEnd = sectionBody.indexOf(`
2743
- `);
2744
- const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
2745
- const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
2746
- const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
2747
- return { found: true, section: sectionBody.slice(0, sectionEnd) };
2748
- }
2749
2762
  // ../../../packages/aeg-core/src/test-plan-gate.ts
2750
2763
  var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
2751
2764
  function evaluateTestPlanGate(body, branch) {
@@ -2817,11 +2830,183 @@ function emitCheckError(error) {
2817
2830
  `);
2818
2831
  }
2819
2832
 
2833
+ // src/lib/config.ts
2834
+ import { execFileSync as execFileSync2 } from "node:child_process";
2835
+ import { homedir } from "node:os";
2836
+ import { dirname, join } from "node:path";
2837
+ import { z } from "zod";
2838
+ var EnvEntrySchema = z.union([
2839
+ z.literal(true),
2840
+ z.object({ optional: z.literal(true) }),
2841
+ z.object({ anyOf: z.array(z.string()).min(2) }),
2842
+ z.string()
2843
+ ]);
2844
+ var CheckEntrySchema = z.object({
2845
+ run: z.string(),
2846
+ scope: z.enum(["diff", "full"]),
2847
+ include: z.array(z.string()).optional(),
2848
+ args: z.array(z.string()).optional(),
2849
+ timeoutMs: z.number().optional(),
2850
+ env: z.record(z.string(), EnvEntrySchema).optional(),
2851
+ requiresOpenPr: z.boolean().optional()
2852
+ }).superRefine((entry2, ctx) => {
2853
+ if (!entry2.env)
2854
+ return;
2855
+ for (const [key, value] of Object.entries(entry2.env)) {
2856
+ if (typeof value !== "object" || value === null || !("anyOf" in value))
2857
+ continue;
2858
+ const members = value.anyOf;
2859
+ if (new Set(members).size !== members.length) {
2860
+ ctx.addIssue({
2861
+ code: z.ZodIssueCode.custom,
2862
+ message: `env.${key}.anyOf has duplicate members`,
2863
+ path: ["env", key, "anyOf"]
2864
+ });
2865
+ }
2866
+ if (!members.includes(key)) {
2867
+ ctx.addIssue({
2868
+ code: z.ZodIssueCode.custom,
2869
+ message: `env.${key}.anyOf must include "${key}" itself as a member`,
2870
+ path: ["env", key, "anyOf"]
2871
+ });
2872
+ }
2873
+ }
2874
+ });
2875
+ var BRIEF_BUILTINS = [
2876
+ "tier",
2877
+ "testPlan",
2878
+ "testPlanExclusivity",
2879
+ "principalPlaceholder",
2880
+ "surfaceMap",
2881
+ "docUpdateList",
2882
+ "worktreeStep0",
2883
+ "stopConditions",
2884
+ "autonomyClause",
2885
+ "project",
2886
+ "for",
2887
+ "closesN",
2888
+ "premiseCoverage",
2889
+ "issueRationale"
2890
+ ];
2891
+ var BriefSectionSchema = z.union([
2892
+ z.object({ builtin: z.enum(BRIEF_BUILTINS) }),
2893
+ z.object({ heading: z.string().min(1), name: z.string().optional() }),
2894
+ z.object({ field: z.string().min(1), name: z.string().optional() }),
2895
+ z.object({ phrase: z.string().min(1), name: z.string().optional() })
2896
+ ]);
2897
+ var BriefSchemaSchema = z.object({
2898
+ pr: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
2899
+ issue: z.object({ sections: z.array(BriefSectionSchema) }).optional()
2900
+ });
2901
+ function isSafeRepoRelPath(p) {
2902
+ if (p.length === 0)
2903
+ return false;
2904
+ if (p.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(p))
2905
+ return false;
2906
+ return p.split(/[\\/]/).every((seg) => seg !== ".." && seg !== "");
2907
+ }
2908
+ var SafeRepoRelPath = z.string().refine(isSafeRepoRelPath, {
2909
+ message: "must be a repo-root-relative path with no `..` segment or absolute root"
2910
+ });
2911
+ var ManagedBlockRecordSchema = z.object({
2912
+ path: SafeRepoRelPath,
2913
+ marker: z.string(),
2914
+ comment: z.enum(["hash", "html"])
2915
+ });
2916
+ var ManagedManifestSchema = z.object({
2917
+ version: z.number().int().positive(),
2918
+ files: z.array(SafeRepoRelPath),
2919
+ blocks: z.array(ManagedBlockRecordSchema),
2920
+ labels: z.array(z.string())
2921
+ });
2922
+ var VinayaConfigSchema = z.object({
2923
+ rings: z.object({
2924
+ ring1_forgeWriteInterception: z.boolean(),
2925
+ ring2_asyncAudits: z.boolean()
2926
+ }).optional(),
2927
+ checks: z.record(z.string(), CheckEntrySchema).optional(),
2928
+ briefSchema: BriefSchemaSchema.optional(),
2929
+ managed: ManagedManifestSchema.optional(),
2930
+ principals: z.array(z.string()).min(1).optional()
2931
+ });
2932
+ var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
2933
+ var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
2934
+ var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
2935
+ function resolvePrincipalAllowlist(config) {
2936
+ return config?.principals ?? PRINCIPAL_ALLOWLIST;
2937
+ }
2938
+ function trustAnchorRepo() {
2939
+ const wellFormed = (slug) => /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
2940
+ const fromRunner = process.env.GITHUB_REPOSITORY?.trim();
2941
+ if (fromRunner) {
2942
+ const validated = wellFormed(fromRunner);
2943
+ if (validated)
2944
+ return validated;
2945
+ }
2946
+ try {
2947
+ const url = execFileSync2("git", ["remote", "get-url", "origin"], {
2948
+ encoding: "utf-8",
2949
+ stdio: ["ignore", "pipe", "pipe"]
2950
+ }).trim();
2951
+ const m = url.match(/github\.com[:/]([^/]+)\/(.+?)(?:\.git)?\/?$/);
2952
+ return m?.[1] && m[2] ? wellFormed(`${m[1]}/${m[2]}`) : null;
2953
+ } catch {
2954
+ return null;
2955
+ }
2956
+ }
2957
+ function ghFetchTrustAnchorConfig() {
2958
+ const repo = trustAnchorRepo();
2959
+ if (!repo)
2960
+ throw new Error("could not resolve repo identity for the trust-anchor read");
2961
+ return execFileSync2("gh", ["api", `repos/${repo}/contents/${LOCAL_CONFIG_FILENAME}`, "--jq", ".content"], {
2962
+ encoding: "utf-8",
2963
+ stdio: ["ignore", "pipe", "pipe"]
2964
+ });
2965
+ }
2966
+ function firstLine(err) {
2967
+ return err?.message?.split(`
2968
+ `)[0] ?? "unknown error";
2969
+ }
2970
+ function isMissingFileError(err) {
2971
+ const stderr = err?.stderr;
2972
+ const haystack = [
2973
+ err?.message ?? "",
2974
+ typeof stderr === "string" ? stderr : stderr?.toString() ?? ""
2975
+ ].join(`
2976
+ `);
2977
+ return /\b404\b|not found/i.test(haystack);
2978
+ }
2979
+ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
2980
+ const warn = (why) => process.stdout.write(`⚠ could not read \`principals\` from the default branch (${why}) — falling back to vinaya's built-in principal allowlist.
2981
+ `);
2982
+ let base64;
2983
+ try {
2984
+ base64 = fetcher().trim();
2985
+ } catch (err) {
2986
+ if (!isMissingFileError(err))
2987
+ warn(firstLine(err));
2988
+ return null;
2989
+ }
2990
+ if (!base64)
2991
+ return null;
2992
+ try {
2993
+ const raw = Buffer.from(base64, "base64").toString("utf-8");
2994
+ const parsed = VinayaConfigSchema.safeParse(JSON.parse(raw));
2995
+ if (parsed.success)
2996
+ return parsed.data;
2997
+ warn("it did not satisfy the config schema");
2998
+ return null;
2999
+ } catch {
3000
+ warn("it was not readable as JSON");
3001
+ return null;
3002
+ }
3003
+ }
3004
+
2820
3005
  // src/checks/bin/check-doc-coverage.ts
2821
3006
  var CHECK_NAME = "doc-coverage";
2822
3007
  function git(args) {
2823
3008
  try {
2824
- return execFileSync2("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
3009
+ return execFileSync3("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
2825
3010
  } catch {
2826
3011
  return "";
2827
3012
  }
@@ -2844,11 +3029,13 @@ function resolvePrBody() {
2844
3029
  }
2845
3030
  function waiverActiveFromEnv() {
2846
3031
  const labels = (process.env.PR_LABELS || "").split(",").map((s) => s.trim()).filter(Boolean);
3032
+ if (!labels.includes(WAIVER_LABEL))
3033
+ return false;
2847
3034
  return isWaiverLabelActorVerified({
2848
3035
  label: WAIVER_LABEL,
2849
3036
  labels,
2850
3037
  labelActor: process.env.WAIVER_LABEL_ACTOR || null,
2851
- principalAllowlist: PRINCIPAL_ALLOWLIST
3038
+ principalAllowlist: resolvePrincipalAllowlist(loadTrustAnchorConfig())
2852
3039
  });
2853
3040
  }
2854
3041
  function main() {
@@ -1451,12 +1451,16 @@ function isCodeFile(p) {
1451
1451
  var WAIVER_LABEL = label("waiver-docs");
1452
1452
  var WAIVER_LABEL_REVIEW = label("waiver-review");
1453
1453
  var PRINCIPAL_ALLOWLIST = ["daniboomerang"];
1454
+ function isPrincipal(login, principalAllowlist) {
1455
+ if (login === null)
1456
+ return false;
1457
+ const normalized = login.toLowerCase();
1458
+ return principalAllowlist.some((p) => p.toLowerCase() === normalized);
1459
+ }
1454
1460
  function isWaiverLabelActorVerified(opts) {
1455
1461
  if (!opts.labels.includes(opts.label))
1456
1462
  return false;
1457
- if (opts.labelActor === null)
1458
- return false;
1459
- return opts.principalAllowlist.includes(opts.labelActor);
1463
+ return isPrincipal(opts.labelActor, opts.principalAllowlist);
1460
1464
  }
1461
1465
 
1462
1466
  // ../../../packages/aeg-core/src/doc-owners.ts
@@ -1644,6 +1648,27 @@ function overrideActive(opts) {
1644
1648
  // ../../../packages/aeg-core/src/premise-check.ts
1645
1649
  var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
1646
1650
 
1651
+ // ../../../packages/aeg-core/src/test-plan-section.ts
1652
+ var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
1653
+ var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
1654
+ var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
1655
+ function locateTestPlanSection(body) {
1656
+ const region = anchoredRegion(body, "TEST-PLAN");
1657
+ if (region !== null)
1658
+ return { found: true, section: region };
1659
+ const headingMatch = HEADING_FORM_RE.exec(body);
1660
+ const match = headingMatch ?? INLINE_FORM_RE.exec(body);
1661
+ if (!match || match.index === undefined)
1662
+ return { found: false };
1663
+ const sectionBody = body.slice(match.index);
1664
+ const firstLineEnd = sectionBody.indexOf(`
1665
+ `);
1666
+ const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
1667
+ const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
1668
+ const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
1669
+ return { found: true, section: sectionBody.slice(0, sectionEnd) };
1670
+ }
1671
+
1647
1672
  // ../../../packages/aeg-core/src/brief-validation.ts
1648
1673
  function headerRegion(prBody) {
1649
1674
  const m = prBody.match(/^##\s/m);
@@ -1682,10 +1707,15 @@ function checkTierField(prBody, readTier) {
1682
1707
  };
1683
1708
  }
1684
1709
  var TEST_PLAN_UNIT_TESTS_ONLY_RE = /(?:\*\*)?Test Plan(?:\*\*)?\s*:\s*(?:\*\*)?\s*unit-tests-only/i;
1710
+ function testPlanRegion(prBody) {
1711
+ const located = locateTestPlanSection(prBody);
1712
+ return located.found ? located.section : prBody;
1713
+ }
1685
1714
  function checkTestPlan(prBody) {
1686
- if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(prBody))
1715
+ const region = testPlanRegion(prBody);
1716
+ if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
1687
1717
  return { status: "pass", errors: [] };
1688
- if (/\*\*\[(?:agent|principal)\]\*\*/.test(prBody))
1718
+ if (/\*\*\[(?:agent|principal)\]\*\*/.test(region))
1689
1719
  return { status: "pass", errors: [] };
1690
1720
  return {
1691
1721
  status: "fail",
@@ -1695,9 +1725,10 @@ function checkTestPlan(prBody) {
1695
1725
  };
1696
1726
  }
1697
1727
  function checkTestPlanExclusivity(prBody) {
1698
- if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(prBody))
1728
+ const region = testPlanRegion(prBody);
1729
+ if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
1699
1730
  return { status: "pass", errors: [] };
1700
- if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(prBody)) {
1731
+ if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(region)) {
1701
1732
  return {
1702
1733
  status: "fail",
1703
1734
  errors: [
@@ -1708,8 +1739,9 @@ function checkTestPlanExclusivity(prBody) {
1708
1739
  return { status: "pass", errors: [] };
1709
1740
  }
1710
1741
  function checkPrincipalPlaceholder(prBody) {
1742
+ const region = testPlanRegion(prBody);
1711
1743
  const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
1712
- for (const m of prBody.matchAll(lineRe)) {
1744
+ for (const m of region.matchAll(lineRe)) {
1713
1745
  const content = m[1] ?? "";
1714
1746
  if (/^\s*None\b/i.test(content)) {
1715
1747
  return {
@@ -2157,11 +2189,12 @@ function isReviewGateExemptBranch(branch) {
2157
2189
  return branch.startsWith("plan/");
2158
2190
  }
2159
2191
  function checkReviewGate(input) {
2192
+ const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
2160
2193
  const waived = isWaiverLabelActorVerified({
2161
2194
  label: WAIVER_LABEL_REVIEW,
2162
2195
  labels: input.labels,
2163
2196
  labelActor: input.waiverLabelActor,
2164
- principalAllowlist: PRINCIPAL_ALLOWLIST
2197
+ principalAllowlist
2165
2198
  });
2166
2199
  if (waived) {
2167
2200
  return {
@@ -2170,8 +2203,8 @@ function checkReviewGate(input) {
2170
2203
  waived: true
2171
2204
  };
2172
2205
  }
2173
- const verified = input.comments.filter((c) => c.author !== null && PRINCIPAL_ALLOWLIST.includes(c.author));
2174
- const ignoredCount = input.comments.filter((c) => (c.author === null || !PRINCIPAL_ALLOWLIST.includes(c.author)) && c.body.includes("VERDICT")).length;
2206
+ const verified = input.comments.filter((c) => isPrincipal(c.author, principalAllowlist));
2207
+ const ignoredCount = input.comments.filter((c) => !isPrincipal(c.author, principalAllowlist) && c.body.includes("VERDICT")).length;
2175
2208
  const verifiedBodies = verified.map((c) => c.body);
2176
2209
  const codeReview = extractCodeReviewVerdict(verifiedBodies);
2177
2210
  const security = extractSecurityReviewVerdict(verifiedBodies);
@@ -2724,26 +2757,6 @@ function decideIssueAssignment(input) {
2724
2757
  reason: `First push of \`${branch}\` — assigning Issue #${issue} to @${login} (the authenticated pusher).`
2725
2758
  };
2726
2759
  }
2727
- // ../../../packages/aeg-core/src/test-plan-section.ts
2728
- var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
2729
- var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
2730
- var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
2731
- function locateTestPlanSection(body) {
2732
- const region = anchoredRegion(body, "TEST-PLAN");
2733
- if (region !== null)
2734
- return { found: true, section: region };
2735
- const headingMatch = HEADING_FORM_RE.exec(body);
2736
- const match = headingMatch ?? INLINE_FORM_RE.exec(body);
2737
- if (!match || match.index === undefined)
2738
- return { found: false };
2739
- const sectionBody = body.slice(match.index);
2740
- const firstLineEnd = sectionBody.indexOf(`
2741
- `);
2742
- const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
2743
- const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
2744
- const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
2745
- return { found: true, section: sectionBody.slice(0, sectionEnd) };
2746
- }
2747
2760
  // ../../../packages/aeg-core/src/test-plan-gate.ts
2748
2761
  var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
2749
2762
  function evaluateTestPlanGate(body, branch) {
@@ -1451,12 +1451,16 @@ function isCodeFile(p) {
1451
1451
  var WAIVER_LABEL = label("waiver-docs");
1452
1452
  var WAIVER_LABEL_REVIEW = label("waiver-review");
1453
1453
  var PRINCIPAL_ALLOWLIST = ["daniboomerang"];
1454
+ function isPrincipal(login, principalAllowlist) {
1455
+ if (login === null)
1456
+ return false;
1457
+ const normalized = login.toLowerCase();
1458
+ return principalAllowlist.some((p) => p.toLowerCase() === normalized);
1459
+ }
1454
1460
  function isWaiverLabelActorVerified(opts) {
1455
1461
  if (!opts.labels.includes(opts.label))
1456
1462
  return false;
1457
- if (opts.labelActor === null)
1458
- return false;
1459
- return opts.principalAllowlist.includes(opts.labelActor);
1463
+ return isPrincipal(opts.labelActor, opts.principalAllowlist);
1460
1464
  }
1461
1465
 
1462
1466
  // ../../../packages/aeg-core/src/doc-owners.ts
@@ -1644,6 +1648,27 @@ function overrideActive(opts) {
1644
1648
  // ../../../packages/aeg-core/src/premise-check.ts
1645
1649
  var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
1646
1650
 
1651
+ // ../../../packages/aeg-core/src/test-plan-section.ts
1652
+ var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
1653
+ var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
1654
+ var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
1655
+ function locateTestPlanSection(body) {
1656
+ const region = anchoredRegion(body, "TEST-PLAN");
1657
+ if (region !== null)
1658
+ return { found: true, section: region };
1659
+ const headingMatch = HEADING_FORM_RE.exec(body);
1660
+ const match = headingMatch ?? INLINE_FORM_RE.exec(body);
1661
+ if (!match || match.index === undefined)
1662
+ return { found: false };
1663
+ const sectionBody = body.slice(match.index);
1664
+ const firstLineEnd = sectionBody.indexOf(`
1665
+ `);
1666
+ const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
1667
+ const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
1668
+ const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
1669
+ return { found: true, section: sectionBody.slice(0, sectionEnd) };
1670
+ }
1671
+
1647
1672
  // ../../../packages/aeg-core/src/brief-validation.ts
1648
1673
  function headerRegion(prBody) {
1649
1674
  const m = prBody.match(/^##\s/m);
@@ -1682,10 +1707,15 @@ function checkTierField(prBody, readTier) {
1682
1707
  };
1683
1708
  }
1684
1709
  var TEST_PLAN_UNIT_TESTS_ONLY_RE = /(?:\*\*)?Test Plan(?:\*\*)?\s*:\s*(?:\*\*)?\s*unit-tests-only/i;
1710
+ function testPlanRegion(prBody) {
1711
+ const located = locateTestPlanSection(prBody);
1712
+ return located.found ? located.section : prBody;
1713
+ }
1685
1714
  function checkTestPlan(prBody) {
1686
- if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(prBody))
1715
+ const region = testPlanRegion(prBody);
1716
+ if (TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
1687
1717
  return { status: "pass", errors: [] };
1688
- if (/\*\*\[(?:agent|principal)\]\*\*/.test(prBody))
1718
+ if (/\*\*\[(?:agent|principal)\]\*\*/.test(region))
1689
1719
  return { status: "pass", errors: [] };
1690
1720
  return {
1691
1721
  status: "fail",
@@ -1695,9 +1725,10 @@ function checkTestPlan(prBody) {
1695
1725
  };
1696
1726
  }
1697
1727
  function checkTestPlanExclusivity(prBody) {
1698
- if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(prBody))
1728
+ const region = testPlanRegion(prBody);
1729
+ if (!TEST_PLAN_UNIT_TESTS_ONLY_RE.test(region))
1699
1730
  return { status: "pass", errors: [] };
1700
- if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(prBody)) {
1731
+ if (/^-\s*\[[ xX]\]\s*\*{2}\[(?:agent|principal)\]\*{2}/im.test(region)) {
1701
1732
  return {
1702
1733
  status: "fail",
1703
1734
  errors: [
@@ -1708,8 +1739,9 @@ function checkTestPlanExclusivity(prBody) {
1708
1739
  return { status: "pass", errors: [] };
1709
1740
  }
1710
1741
  function checkPrincipalPlaceholder(prBody) {
1742
+ const region = testPlanRegion(prBody);
1711
1743
  const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
1712
- for (const m of prBody.matchAll(lineRe)) {
1744
+ for (const m of region.matchAll(lineRe)) {
1713
1745
  const content = m[1] ?? "";
1714
1746
  if (/^\s*None\b/i.test(content)) {
1715
1747
  return {
@@ -2157,11 +2189,12 @@ function isReviewGateExemptBranch(branch) {
2157
2189
  return branch.startsWith("plan/");
2158
2190
  }
2159
2191
  function checkReviewGate(input) {
2192
+ const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
2160
2193
  const waived = isWaiverLabelActorVerified({
2161
2194
  label: WAIVER_LABEL_REVIEW,
2162
2195
  labels: input.labels,
2163
2196
  labelActor: input.waiverLabelActor,
2164
- principalAllowlist: PRINCIPAL_ALLOWLIST
2197
+ principalAllowlist
2165
2198
  });
2166
2199
  if (waived) {
2167
2200
  return {
@@ -2170,8 +2203,8 @@ function checkReviewGate(input) {
2170
2203
  waived: true
2171
2204
  };
2172
2205
  }
2173
- const verified = input.comments.filter((c) => c.author !== null && PRINCIPAL_ALLOWLIST.includes(c.author));
2174
- const ignoredCount = input.comments.filter((c) => (c.author === null || !PRINCIPAL_ALLOWLIST.includes(c.author)) && c.body.includes("VERDICT")).length;
2206
+ const verified = input.comments.filter((c) => isPrincipal(c.author, principalAllowlist));
2207
+ const ignoredCount = input.comments.filter((c) => !isPrincipal(c.author, principalAllowlist) && c.body.includes("VERDICT")).length;
2175
2208
  const verifiedBodies = verified.map((c) => c.body);
2176
2209
  const codeReview = extractCodeReviewVerdict(verifiedBodies);
2177
2210
  const security = extractSecurityReviewVerdict(verifiedBodies);
@@ -2724,26 +2757,6 @@ function decideIssueAssignment(input) {
2724
2757
  reason: `First push of \`${branch}\` — assigning Issue #${issue} to @${login} (the authenticated pusher).`
2725
2758
  };
2726
2759
  }
2727
- // ../../../packages/aeg-core/src/test-plan-section.ts
2728
- var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
2729
- var INLINE_FORM_RE = /^[ \t]*\*{0,2}Test Plan:?\*{0,2}/im;
2730
- var NEXT_SECTION_RE = /\n(?:#{1,3}[ \t]|\*\*[A-Z][^*\n]*:\*\*)/;
2731
- function locateTestPlanSection(body) {
2732
- const region = anchoredRegion(body, "TEST-PLAN");
2733
- if (region !== null)
2734
- return { found: true, section: region };
2735
- const headingMatch = HEADING_FORM_RE.exec(body);
2736
- const match = headingMatch ?? INLINE_FORM_RE.exec(body);
2737
- if (!match || match.index === undefined)
2738
- return { found: false };
2739
- const sectionBody = body.slice(match.index);
2740
- const firstLineEnd = sectionBody.indexOf(`
2741
- `);
2742
- const searchFrom = firstLineEnd === -1 ? sectionBody.length : firstLineEnd + 1;
2743
- const nextMatch = sectionBody.slice(searchFrom).match(NEXT_SECTION_RE);
2744
- const sectionEnd = nextMatch ? searchFrom + (nextMatch.index ?? 0) : sectionBody.length;
2745
- return { found: true, section: sectionBody.slice(0, sectionEnd) };
2746
- }
2747
2760
  // ../../../packages/aeg-core/src/test-plan-gate.ts
2748
2761
  var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
2749
2762
  function evaluateTestPlanGate(body, branch) {