@attalabs/vinaya 0.21.0 → 0.23.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 (211) hide show
  1. package/README.md +15 -4
  2. package/aeg-root/contracts/archivist-tranche-archivist.md +2 -2
  3. package/aeg-root/contracts/brief-developer.md +1 -0
  4. package/aeg-root/contracts/developer-reviewer.md +3 -3
  5. package/aeg-root/contracts/reviewer-archivist.md +3 -3
  6. package/aeg-root/enforcement.md +28 -21
  7. package/aeg-root/process.md +8 -4
  8. package/aeg-root/roles/archivist.md +2 -2
  9. package/aeg-root/roles/brief-author.md +9 -3
  10. package/aeg-root/roles/developer.md +63 -31
  11. package/aeg-root/roles/planner.md +2 -2
  12. package/aeg-root/roles/principal.md +14 -0
  13. package/aeg-root/roles/reviewer.md +32 -15
  14. package/aeg-root/roles/security.md +15 -5
  15. package/aeg-root/skills/aeg/SKILL.md +9 -5
  16. package/aeg-root/skills/aeg-roles/SKILL.md +2 -2
  17. package/aeg-root/skills/brief-authoring/SKILL.md +39 -27
  18. package/aeg-root/state-machine.md +9 -11
  19. package/aeg-root/templates/brief-template.md +6 -6
  20. package/aeg-root/templates/pr-report-template.md +12 -7
  21. package/aeg-root/tranche-model.md +9 -5
  22. package/dist/checks/bin/check-body-bare-digits.js +667 -148
  23. package/dist/checks/bin/check-branch-topology.js +714 -149
  24. package/dist/checks/bin/check-brief-shape.js +704 -147
  25. package/dist/checks/bin/check-changeset-coverage.js +1046 -166
  26. package/dist/checks/bin/check-closes-n.js +714 -149
  27. package/dist/checks/bin/check-coherence.js +729 -156
  28. package/dist/checks/bin/check-dead-branch-push.js +663 -144
  29. package/dist/checks/bin/check-dispatch-readiness.js +728 -155
  30. package/dist/checks/bin/check-doc-coverage-push.js +838 -261
  31. package/dist/checks/bin/check-doc-coverage.js +838 -261
  32. package/dist/checks/bin/check-doctrine-no-procedures.js +4794 -0
  33. package/dist/checks/bin/check-doctrine-portability.js +799 -155
  34. package/dist/checks/bin/check-evidence-fresh.js +1132 -206
  35. package/dist/checks/bin/check-exec-bits.js +4931 -0
  36. package/dist/checks/bin/check-first-push-dispatch.js +716 -151
  37. package/dist/checks/bin/check-issue-assignment.js +714 -149
  38. package/dist/checks/bin/check-main-branch-refusal.js +663 -144
  39. package/dist/checks/bin/check-no-disk-state.js +663 -144
  40. package/dist/checks/bin/check-pr-report-density.js +4461 -0
  41. package/dist/checks/bin/check-quoted-command.js +741 -166
  42. package/dist/checks/bin/check-reader-resolvable-prose.js +768 -173
  43. package/dist/checks/bin/check-registry-gates.js +726 -154
  44. package/dist/checks/bin/check-retired-vocabulary.js +760 -165
  45. package/dist/checks/bin/check-review-gate.js +783 -148
  46. package/dist/checks/bin/check-single-plan-pr.js +663 -144
  47. package/dist/checks/bin/check-test-plan.js +664 -145
  48. package/dist/checks/bin/check-token-collection-wired.js +665 -146
  49. package/dist/checks/bin/check-token-report.js +4509 -0
  50. package/dist/checks/bin/check-workspace-escape.js +1129 -183
  51. package/dist/index.js +8458 -5403
  52. package/package.json +1 -1
  53. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/actions.ts +173 -0
  54. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/anchored-region.ts +113 -0
  55. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/archive-task.ts +206 -0
  56. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/baseline-capture.ts +65 -0
  57. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/blast-radius-domains.ts +192 -0
  58. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/branch-topology-gate.ts +85 -0
  59. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-validation.ts +511 -0
  60. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/claude-code-transcript.ts +460 -0
  61. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/coherence-checks.ts +787 -0
  62. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dead-branch-push-audit.ts +55 -0
  63. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dead-branch-push-guard.ts +77 -0
  64. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/derive-section7.ts +66 -0
  65. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/derive-tranche.ts +94 -0
  66. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/diagram-model.ts +372 -0
  67. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/direct-main-push.ts +39 -0
  68. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dispatch-gate.ts +224 -0
  69. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doc-owners.ts +314 -0
  70. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/build-doc-nav.ts +38 -0
  71. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/docs-coherence.ts +136 -0
  72. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/index.ts +29 -0
  73. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/legacy-anchors.ts +48 -0
  74. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/nav-helpers.ts +17 -0
  75. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/node-route.ts +134 -0
  76. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/parse-doc.ts +43 -0
  77. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/published-prose.ts +306 -0
  78. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/surfaced-manifest.ts +89 -0
  79. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/types.ts +33 -0
  80. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-portability.ts +170 -0
  81. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-source.ts +23 -0
  82. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/ensure-label.ts +28 -0
  83. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/file-classify.ts +51 -0
  84. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/first-push-dispatch-gate.ts +80 -0
  85. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/gate-audience.ts +168 -0
  86. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/index.ts +301 -0
  87. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/issue-assignment.ts +102 -0
  88. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/issue-validation.ts +746 -0
  89. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/leftover-detection.ts +68 -0
  90. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/local-anchor-coverage.ts +245 -0
  91. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/main-branch-refusal.ts +64 -0
  92. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/manifest-validity.ts +81 -0
  93. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/markdown-table.ts +76 -0
  94. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/metering-io-guard.ts +119 -0
  95. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/milestone-validation.ts +240 -0
  96. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/no-disk-state.ts +50 -0
  97. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-ledger.ts +77 -0
  98. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-registry.ts +105 -0
  99. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-token-report.ts +165 -0
  100. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-tranche.ts +183 -0
  101. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/pr-tier.ts +81 -0
  102. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/premise-check.ts +125 -0
  103. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/quoted-command.ts +275 -0
  104. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/reader-resolvable-prose.ts +320 -0
  105. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-checks.ts +255 -0
  106. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-parse.ts +164 -0
  107. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-scaffold.ts +216 -0
  108. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/report-tokens.ts +261 -0
  109. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/retired-vocabulary.ts +163 -0
  110. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/review-gate.ts +269 -0
  111. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/single-plan-pr.ts +73 -0
  112. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/state-machine-model.ts +269 -0
  113. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/state-source.ts +14 -0
  114. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/status-block.ts +8 -0
  115. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/sum-ledger.ts +26 -0
  116. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/symbol-collisions.ts +78 -0
  117. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-gate.ts +104 -0
  118. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-section.ts +65 -0
  119. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/types.ts +174 -0
  120. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/verdict-extraction.ts +140 -0
  121. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/vocabulary-citation.ts +114 -0
  122. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/waiver-label.ts +52 -0
  123. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/workspace-escape.ts +172 -0
  124. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  125. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  126. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  127. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  128. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  129. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  130. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  131. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  132. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  133. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  134. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  135. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  136. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  137. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
  138. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  139. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  140. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  141. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  142. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  143. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  144. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  145. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  146. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  147. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  148. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  149. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  150. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
  151. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  152. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  153. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  154. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  155. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  156. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  157. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  158. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  159. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  160. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  161. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  162. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__02a-3g8._.js +1 -1
  163. 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
  164. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0053k9k._.js +1 -1
  165. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
  166. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__02c71kv._.js +1 -1
  167. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
  168. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
  169. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
  170. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0ozbaq0._.js → [root-of-the-server]__1mcitst._.js} +1 -1
  171. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
  172. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
  173. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
  174. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
  175. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0o54suy._.js +1 -1
  176. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1-6rzip._.js +1 -1
  177. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +1 -1
  178. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1mrtj0f._.js +1 -1
  179. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
  180. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_06it6s-._.js +1 -1
  181. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
  182. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_animate_components_index_ts_186fje1._.js +1 -1
  183. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_brutal_components_index_ts_0n_lcc4._.js +1 -1
  184. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_retro_components_index_ts_0wvpm_z._.js +1 -1
  185. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_libraries_retro_components_index_ts_1_cfi48._.js +1 -1
  186. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  187. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  188. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  189. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
  190. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/00pi8vhg8w6gi.js +1 -0
  191. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0r4i_ks9z02bw.js → 03q0q9n6-xah8.js} +1 -1
  192. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2_k6j1o9q5nn4.js → 0jer_drkl1e4r.js} +4 -4
  193. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0vc2u252q5q6o.js +1 -0
  194. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1k916ih3p4nsg.js → 13g16cu00g570.js} +1 -1
  195. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2hmannd4bjhzy.js → 1sfxfunirkcr6.js} +1 -1
  196. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1t2kft7bxzuxn.js → 206ajg8f1a-_h.js} +1 -1
  197. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1hfhxjy577l5d.js → 20x-t0a0v129z.js} +1 -1
  198. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{25kbt5k-xb2a5.js → 279qq4twinc97.js} +1 -1
  199. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{112g08xpx3kro.js → 2ka8dg687auhj.js} +1 -1
  200. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/2ou_81ahqw31e.js +1 -0
  201. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0up5x3jg-cwov.js → 2rn89uwtf2lwc.js} +1 -1
  202. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3mqu_uhluy19i.css → 3qc67qhcvbg0o.css} +1 -1
  203. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1yqs2zgvwa4p1.js → 3zugx9esh2x51.js} +1 -1
  204. package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
  205. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0_jnwbarv-cqk.js +0 -1
  206. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1ybrihl5_aocy.js +0 -1
  207. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/3r5efmleneaco.js +0 -1
  208. /package/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/{aeg-core → vinaya/studio-standalone/_node_modules/@attalabs/aeg-core}/bin/verify-coherence.ts +0 -0
  209. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → 5xy_GA7G5KRuE3HDumIiw}/_buildManifest.js +0 -0
  210. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → 5xy_GA7G5KRuE3HDumIiw}/_clientMiddlewareManifest.js +0 -0
  211. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{crNCHQ9uAgKOYC6DKkZma → 5xy_GA7G5KRuE3HDumIiw}/_ssgManifest.js +0 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Live derivation of `checkBlastRadiusScope`'s collision-domain list.
3
+ *
4
+ * The list used to be 100% hand-authored in `.aeg/packages` (see that file's
5
+ * own header for the doctrine this module now mechanizes). Two of its three
6
+ * sections are derivable or defaultable, and this module produces both,
7
+ * pure — every filesystem read is injected by the caller (`open-issue.ts`),
8
+ * so this stays testable against a literal fixture with no disk I/O.
9
+ *
10
+ * 1. **`packages/*` workspace domains** (`deriveWorkspacePackageDomains`) —
11
+ * every workspace member (from `package.json`'s `workspaces` array, or
12
+ * `pnpm-workspace.yaml`'s `packages:` list — pnpm does not honor a
13
+ * `workspaces` key in `package.json` at all, so both sources are read and
14
+ * combined by the caller before this function ever sees them) that
15
+ * resolves under `packages/` is a shared collision domain BY CONSTRUCTION
16
+ * (this repo's own doctrine, `.aeg/packages`'s header). A workspace member
17
+ * three directories deep (`packages/agents/vada-fusion`) still collapses
18
+ * to its top-level directory (`packages/agents`) — the domain is the
19
+ * directory, not the individual package, because that is the granularity
20
+ * every existing static list (this repo's own, attalabs') actually uses: a
21
+ * monorepo's `packages/agents/*` sub-packages share one collision domain,
22
+ * not four. A leading `!` negates an entry (npm/yarn/pnpm's own workspace
23
+ * negation syntax) — resolved the same way, then subtracted from the
24
+ * positive matches before collapsing, so an adopter's own excluded
25
+ * directory is never derived as a domain.
26
+ * 2. **Built-in cross-cutting defaults** (`deriveBuiltinCrossCuttingDefaults`)
27
+ * — lockfile, monorepo config, CI, git hooks. Not derivable from workspace
28
+ * structure, but detectable by convention: presence-check a fixed
29
+ * candidate list rather than assuming any one of them exists.
30
+ *
31
+ * Neither function reads `.aeg/packages` or `vinaya.config.json`'s
32
+ * `blastRadius.extraDomains` — those stay additive, read by the caller and
33
+ * unioned on top (see `open-issue.ts`'s `readSharedPackages`).
34
+ */
35
+
36
+ /**
37
+ * Resolves one workspace-glob entry (from either `package.json`'s
38
+ * `workspaces` array or `pnpm-workspace.yaml`'s `packages:` list — same
39
+ * grammar, different file) to the workspace member path(s) it names. Supports
40
+ * the one glob shape every package manager's workspaces field actually uses
41
+ * in practice — a trailing `/*` naming an immediate-children directory
42
+ * (`"packages/*"`, `"apps/*"`) — via the injected `listDirs`, which the
43
+ * caller resolves against the real filesystem. A literal entry with no
44
+ * trailing `/*` (attalabs' own `package.json` lists every member explicitly,
45
+ * no globs at all) passes through unchanged. Any other `*` position is not a
46
+ * real-world workspaces shape and is dropped rather than guessed at — this
47
+ * applies identically whether the entry came in positive or negated (the
48
+ * caller strips the leading `!` before calling this).
49
+ */
50
+ function resolveWorkspaceEntry(entry: string, listDirs: (dir: string) => string[]): string[] {
51
+ if (entry.endsWith('/*')) {
52
+ const baseDir = entry.slice(0, -2)
53
+ return listDirs(baseDir).map((name) => `${baseDir}/${name}`)
54
+ }
55
+ if (entry.includes('*')) return []
56
+ return [entry]
57
+ }
58
+
59
+ /**
60
+ * Every `packages/*` workspace member, collapsed to its top-level directory
61
+ * under `packages/` and deduplicated. A member outside `packages/` (an
62
+ * `apps/*` entry, a root-level `tools/admin`) is not a `packages/*` domain
63
+ * and is dropped — those are within a single project's own path or covered
64
+ * by the cross-cutting defaults, never a shared-package collision domain.
65
+ *
66
+ * A `!`-prefixed entry (npm/yarn/pnpm workspace negation) is resolved the
67
+ * same way as a positive entry, and every member it resolves to is excluded
68
+ * from the positive result BEFORE collapsing — so `["packages/*",
69
+ * "!packages/legacy"]` never derives `packages/legacy`, but a negation that
70
+ * excludes only one member of a many-member directory (e.g. one nested
71
+ * package under `packages/agents`) still leaves that directory's domain
72
+ * derived from its remaining members, which is correct: the shared directory
73
+ * is still a real collision domain for whoever touches it.
74
+ *
75
+ * `listDirs(dir)` returns the immediate child directory NAMES of `dir`
76
+ * (repo-relative, forward-slashed, no leading `packages/`) — the caller's
77
+ * job is filesystem access; this function only reads its return value.
78
+ */
79
+ export function deriveWorkspacePackageDomains(workspaces: string[], listDirs: (dir: string) => string[]): string[] {
80
+ const positive = workspaces.filter((entry) => !entry.startsWith('!'))
81
+ const negative = workspaces.filter((entry) => entry.startsWith('!')).map((entry) => entry.slice(1))
82
+
83
+ const excluded = new Set<string>()
84
+ for (const entry of negative) {
85
+ for (const member of resolveWorkspaceEntry(entry, listDirs)) excluded.add(member)
86
+ }
87
+
88
+ const domains = new Set<string>()
89
+ for (const entry of positive) {
90
+ for (const member of resolveWorkspaceEntry(entry, listDirs)) {
91
+ if (excluded.has(member)) continue
92
+ const segments = member.split('/')
93
+ if (segments[0] !== 'packages' || segments.length < 2) continue
94
+ domains.add(`packages/${segments[1]}`)
95
+ }
96
+ }
97
+ return [...domains].sort()
98
+ }
99
+
100
+ /**
101
+ * Hand-rolled parser for `pnpm-workspace.yaml`'s `packages:` list — NOT a
102
+ * general YAML parser, deliberately: the field is always a flat list of
103
+ * glob/literal strings, never nested structure, so pulling in a full YAML
104
+ * dependency for one narrow shape would be the wrong tool (same reasoning as
105
+ * this repo's other hand-rolled parsers, e.g. `parse-registry.ts` for
106
+ * markdown tables). Handles both forms pnpm's own docs show:
107
+ *
108
+ * ```yaml
109
+ * packages:
110
+ * - 'packages/*'
111
+ * - 'apps/*'
112
+ * - '!packages/legacy'
113
+ * ```
114
+ * ```yaml
115
+ * packages: ['packages/*', 'apps/*', '!packages/legacy']
116
+ * ```
117
+ *
118
+ * Entries may be single- or double-quoted or bare; a trailing `# comment` on
119
+ * a line is stripped. A file this cannot parse (nested anchors, multi-line
120
+ * scalars, no `packages:` key at all) returns `[]` — the same
121
+ * dormant-if-unreadable seam every other input to this module uses, never a
122
+ * throw.
123
+ */
124
+ export function parsePnpmWorkspaceYaml(content: string): string[] {
125
+ const unquote = (s: string): string => {
126
+ const t = s.trim()
127
+ if (t.length >= 2 && ((t[0] === "'" && t.at(-1) === "'") || (t[0] === '"' && t.at(-1) === '"'))) {
128
+ return t.slice(1, -1)
129
+ }
130
+ return t
131
+ }
132
+
133
+ const inlineMatch = content.match(/^packages:\s*\[(.*)\]\s*$/m)
134
+ if (inlineMatch) {
135
+ return (inlineMatch[1] ?? '')
136
+ .split(',')
137
+ .map(unquote)
138
+ .filter((s) => s.length > 0)
139
+ }
140
+
141
+ const entries: string[] = []
142
+ let inBlock = false
143
+ for (const rawLine of content.split('\n')) {
144
+ const line = rawLine.replace(/#.*$/, '')
145
+ if (/^packages:\s*$/.test(line)) {
146
+ inBlock = true
147
+ continue
148
+ }
149
+ if (!inBlock) continue
150
+ const itemMatch = line.match(/^\s+-\s*(.+?)\s*$/)
151
+ if (itemMatch?.[1]) {
152
+ entries.push(unquote(itemMatch[1]))
153
+ continue
154
+ }
155
+ if (line.trim().length === 0) continue
156
+ break // next top-level key ends the packages: block
157
+ }
158
+ return entries
159
+ }
160
+
161
+ /**
162
+ * The built-in cross-cutting candidates, in the fixed order every derived
163
+ * list reports them — the same order the doctrine names them
164
+ * (`aeg-root/tranche-model.md` §5) and the order attalabs' own static
165
+ * `.aeg/packages` already lists them in, so a diff against that file reads
166
+ * as a true empty diff rather than a reordering.
167
+ *
168
+ * Exactly one of the four lockfile names is expected to exist per repo — all
169
+ * four are checked, deliberately, rather than assuming one: a repo mid-
170
+ * migration between package managers, or one this module has never seen,
171
+ * should still get whichever lockfile is actually on disk rather than none.
172
+ */
173
+ export const CROSS_CUTTING_CANDIDATES = [
174
+ 'bun.lock',
175
+ 'package-lock.json',
176
+ 'pnpm-lock.yaml',
177
+ 'yarn.lock',
178
+ 'turbo.json',
179
+ 'biome.json',
180
+ 'tsconfig.json',
181
+ '.github/workflows',
182
+ '.husky'
183
+ ] as const
184
+
185
+ /**
186
+ * Presence-checks `CROSS_CUTTING_CANDIDATES` and returns whichever exist.
187
+ * `exists(path)` is injected — the caller resolves it against the real
188
+ * repo root (`existsSync(join(REPO_ROOT, path))`).
189
+ */
190
+ export function deriveBuiltinCrossCuttingDefaults(exists: (path: string) => boolean): string[] {
191
+ return CROSS_CUTTING_CANDIDATES.filter((path) => exists(path))
192
+ }
@@ -0,0 +1,85 @@
1
+ import type { Tranche } from './types'
2
+
3
+ /**
4
+ * Branch↔topology gate (aeg-governance-hardening task 32, #399). Pure — no
5
+ * `fs`, no shell-outs. The CLI shim (`bin/check-branch-topology.ts`) derives
6
+ * the tranche from the forge (`@attalabs/aeg-forge-state`, task
7
+ * aeg-forge-state-v1 3a) and passes the result (or `null` when no tranche
8
+ * data could be derived) in here.
9
+ *
10
+ * Closes the logic fork: `.husky/pre-push` used to answer "does this
11
+ * branch's task-id suffix have a topology row?" with a hand-rolled
12
+ * `grep -qE "^\|[[:space:]]*${id}[[:space:]]*\|"` against the tranche
13
+ * file — a bash reimplementation of the table-parsing that `parseTranche`
14
+ * used to do here, and that forge-derivation now does instead. Row
15
+ * membership is `topology.tasks`, and the refusal messages are byte-identical
16
+ * to the inline ones the hook printed before.
17
+ */
18
+
19
+ export type BranchTopologyInput = {
20
+ /** The full branch name being pushed — used verbatim in refusal messages. */
21
+ branch: string
22
+ /** Tranche slug extracted from the branch (segment 2). */
23
+ tranche: string
24
+ /** Task id extracted from the branch (segment 3). */
25
+ taskId: string
26
+ /** Repo-relative topology path — used verbatim in refusal messages. */
27
+ topoPath: string
28
+ /** Forge-derived tranche data, or `null` when none could be derived. */
29
+ topology: Tranche | null
30
+ }
31
+
32
+ export type BranchTopologyVerdict = 'allow' | 'refuse'
33
+
34
+ export type BranchTopologyResult = { verdict: BranchTopologyVerdict; reason: string }
35
+
36
+ /**
37
+ * Mirror the hook's original field extraction exactly: its shell `case`
38
+ * pattern — `task/` followed by two wildcard segments, where the shell `*`
39
+ * also matches `/` and the empty string — decided whether the check
40
+ * applied, and `cut -d/ -f2` / `-f3` picked the tranche and task id;
41
+ * segments beyond the third were ignored, exactly as `cut` ignored them.
42
+ * Returns `null` when the branch would not have matched that `case`
43
+ * pattern, i.e. when the hook would have skipped the check entirely.
44
+ */
45
+ export function taskBranchTopologyFields(branch: string): { tranche: string; taskId: string } | null {
46
+ if (!/^task\/.*\/.*$/.test(branch)) return null
47
+ const parts = branch.split('/')
48
+ return { tranche: parts[1] ?? '', taskId: parts[2] ?? '' }
49
+ }
50
+
51
+ /**
52
+ * `allow` — the topology file exists and `parseTranche` finds a Tasks-table
53
+ * row whose `#` column literal-equals the branch's task-id suffix.
54
+ * `refuse` — the tranche file is missing, or no row matches
55
+ *. Reasons are byte-identical to the hook's pre-task-32
56
+ * inline messages, so a refused push reads exactly as before.
57
+ */
58
+ export function checkBranchTopology(input: BranchTopologyInput): BranchTopologyResult {
59
+ const { branch, tranche, taskId, topoPath, topology } = input
60
+
61
+ if (topology === null) {
62
+ return {
63
+ verdict: 'refuse',
64
+ reason:
65
+ `✖ pre-push: branch \`${branch}\` names tranche \`${tranche}\`, but ${topoPath} does not exist.\n` +
66
+ ' A task branch must belong to a real tranche.'
67
+ }
68
+ }
69
+
70
+ const hasRow = topology?.tasks.some((t) => t.id === taskId) ?? false
71
+ if (!hasRow) {
72
+ return {
73
+ verdict: 'refuse',
74
+ reason:
75
+ `✖ pre-push: branch \`${branch}\` — no row with \`#\` = \`${taskId}\` in ${topoPath}.\n` +
76
+ " The branch suffix must literal-match the topology's # column.\n" +
77
+ " If the plan PR adding this row hasn't merged yet, merge it first."
78
+ }
79
+ }
80
+
81
+ return {
82
+ verdict: 'allow',
83
+ reason: `Branch \`${branch}\` matches topology row \`${taskId}\` in ${topoPath}.`
84
+ }
85
+ }