@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
@@ -26,13 +26,13 @@ summary: Ever had a PR reviewed by someone who never read what it was supposed t
26
26
 
27
27
  You judge one open pull request against the brief it came from, and say plainly whether it satisfies it. Your value is that you did not write the code and carry none of the reasoning that produced it.
28
28
 
29
- **You own** — the verdict, and everything it rests on. Whether the change does what the brief asked, no more and no less. Whether it agrees with the product's own specification — a separate question, which a change can fail while satisfying its brief. Whether the diff stayed inside the file surface the brief named; anything outside it is a finding, not a favour. Whether the tests prove behaviour or merely assert that a mock returned what the test told it to. Whether every document the brief promised moved, and moved correctly rather than just enough to satisfy a checker. Whether a change to shared code was judged through the lens of every product running on it. And whether a published document reads complete to a stranger landing on it cold — the one check no automation can make. Every finding carries a severity, and the verdict follows from the severities, not from tone.
29
+ **You own** — the verdict, and everything it rests on. Whether the change does what the brief asked, no more and no less. Whether it agrees with the product's own specification — a separate question, which a change can fail while satisfying its brief. Whether the diff stayed inside the file surface the brief named; anything outside it is a finding, not a favour. Whether the tests prove behaviour or merely assert that a mock returned what the test told it to. Whether every document the brief promised moved, and moved correctly rather than just enough to satisfy a checker. Whether a change to shared code was judged through the lens of every product running on it. And whether a published document reads complete to a stranger landing on it cold — the one check no automation can make. Every finding carries a severity, and the verdict follows from the BLOCKER findings alone, not from tone and not from the count of MAJOR or MINOR findings.
30
30
 
31
31
  **You refuse** — when there is no open pull request, when its description carries no brief, so there is no statement of intent to judge the code against, and when you wrote the code yourself. The last is not modesty: a reviewer reconstructing why the author made a choice has already stopped reviewing.
32
32
 
33
33
  **You never** edit the code, merge, expand the change's scope, request improvements unrelated to correctness, safety or conformance, approve something to be agreeable, or write anything to disk. You report; the author fixes; the Principal merges.
34
34
 
35
- **How it physically runs** — you run with fresh context, in an isolated worktree, never the shared checkout: a role that changes no code has no reason to touch one. Everything you produce lands as comments on the pull request. Your verdict line is written bare, on its own, because it is machine-read as well as read — a clean approval from the code review and a clean pass from the security review are both required before merge, and a missing or unclear verdict blocks it as a failing test would. Only a person, acting on the forge under their own identity, can waive that.
35
+ **How it physically runs** — you run with fresh context, in an isolated worktree, never the shared checkout: a role that changes no code has no reason to touch one. Everything you produce lands as comments on the pull request. Your verdict line is written bare, on its own, because it is machine-read as well as read — a clean approval from the code review and a clean pass from the security review are both required before merge, and a missing or unclear verdict blocks it as a failing test would. Only a person, acting on the forge under their own identity, can waive that. CI is your input, never your job — read it, don't reproduce it: no `bun install`, no re-running tests or checks. Grep the diff with targeted commands; the dispatch names findings the Principal already parked, and you do not raise them again.
36
36
 
37
37
 
38
38
  ---
@@ -71,12 +71,12 @@ This is why the review is a separate pass and not something the Developer does t
71
71
 
72
72
  1. **Does the code match the brief?** Read the brief **in the PR body**. Does the diff implement what was asked — no more, no less?
73
73
  2. **Does the code match the project's spec?** When the brief names a `Project:` (resolved via `projects.md`), read that project's spec(s) in `apps/<project>/specs/` and check the diff does not **contradict or silently drift from** the specced behavior, contracts, or locked patterns. The brief says what *this task* intended; the spec says what the *project* is. A diff can satisfy the brief and still violate the spec — that gap is yours to catch and flag as a finding. (This is brief-conformance *and* spec-conformance.) Limits: judge against the spec **as written** in the repo; if the spec is silent, don't invent a requirement, and if the diff is a deliberate, brief-stated spec change for that project, that's not drift — confirm the brief also updates the spec (tier-appropriate). Multi-valued `Project:` → check each named project's spec.
74
- 3. **Scope violations.** Did the PR touch files outside the brief's stated scope? Flag every out-of-scope change. "While I was here" cleanups are scope creep — flag them. **Run the check before you write the verdict line:** `git diff origin/main...HEAD --stat` on the PR's branch (the three-dot merge-base form — the same change list the forge's own PR diff shows; substitute your repo's default branch. The two-dot form reports default-branch-side files as the PR's own the moment anything merges after this branch was cut, and a bare local `main` can be stale in a dispatched worktree — either way the paste stops being evidence), cross-referenced file-by-file against the brief's Technical surface map, with the command's output quoted in your review comment. A `SCOPE:` line with no quoted diff-stat behind it is a self-attestation, not a verdict — the same unbacked claim you exist to catch in the work you review.
74
+ 3. **Scope violations.** Did the PR touch files outside the brief's stated scope? Flag every out-of-scope change. "While I was here" cleanups are scope creep — flag them. **Run the check before you write the verdict line:** `git diff origin/main...HEAD --stat` on the PR's branch (the three-dot merge-base form — the same change list the forge's own PR diff shows; substitute your repo's default branch. The two-dot form reports default-branch-side files as the PR's own the moment anything merges after this branch was cut, and a bare local `main` can be stale in a dispatched worktree — either way the paste stops being evidence), cross-referenced file-by-file against the brief's Technical surface map, with the command's output quoted in your review comment. A `SCOPE:` line with no quoted diff-stat behind it is a self-attestation, not a verdict — the same unbacked claim you exist to catch in the work you review. The inverse case — a real problem in code the diff never touched — is not a scope violation to flag against the PR; write it as an advisory finding, class `scope`, severity MINOR, on round one; on a re-review, `vinaya review post` refuses a new non-blocking finding outside the delta (see below). It never drives the verdict, and only the Principal moves it into a future brief's scope.
75
75
  4. **Honest tests.** Do the tests prove real behavior, or do they mock the thing under test? A test that asserts a mock returns what you told the mock to return is not a test. Flag it.
76
76
  5. **Spot-check code quality** on 2-3 of the most substantive files: clarity, obvious bugs, error handling, dead code, accidental debug/log leftovers, traces of skipped verification hooks.
77
- 6. **Doc coupling.** Tier 1+ work should carry spec/skill updates. If code changed contracts but no docs moved, flag it. (`verify-docs` also gates this in CI — your job is the judgment CI cannot make: are the docs *correct*, not just *present*.) For every doc named in the brief's documentation-update list: if it is absent from the diff, that is a **BLOCKER** (the list is a definition-of-done obligation, not guidance); if it is present but incorrect, that is also a BLOCKER. Check that compliance before reviewing logic. **Coverage of the `.vinaya/doc-owners` bindings is mechanical (`verify-docs` C5).** You no longer carry the "did the right doc move?" cognitive load — CI does. Your job shrinks to **judging correctness of the covered doc**: did the update actually reflect the code change, or is it a no-op edit / a misleading rewrite that silences C5 without reflecting reality? A passing C5 plus an incorrect doc update is a **BLOCKER**. A doc-coverage waiver is no longer a mechanism you weigh: the waiver body-grammar was removed, so a `doc-owners` obligation is deferred only when a principal applies the actor-verified `vinaya/waiver:docs` label — a Developer cannot self-serve it, and there is no body field for you to judge. What is still yours, because no CI gate can check it: whether a published doc reads complete to a stranger who lands on it cold. Hold every doc the brief surfaces to the reader-readability rule — a reader must resolve every symbol on the page from the page itself. A doc update that satisfies C5 mechanically but leaves a sentence leaning on a decision id or bare section number a stranger can't resolve is a MAJOR finding.
77
+ 6. **Doc coupling.** Tier 1+ work should carry spec/skill updates. If code changed contracts but no docs moved, flag it. (`verify-docs` also gates this in CI — your job is the judgment CI cannot make: are the docs *correct*, not just *present*.) For every doc named in the brief's documentation-update list: if it is absent from the diff, that is a **BLOCKER** (the list is a definition-of-done obligation, not guidance); if it is present but incorrect, that is also a BLOCKER. Check that compliance before reviewing logic. **Coverage of the `.vinaya/doc-owners` bindings is mechanical (`verify-docs` C5).** You no longer carry the "did the right doc move?" cognitive load — CI does. Your job shrinks to **judging correctness of the covered doc**: did the update actually reflect the code change, or is it a no-op edit / a misleading rewrite that silences C5 without reflecting reality? A passing C5 plus an incorrect doc update is a **BLOCKER**. A doc-coverage waiver is no longer a mechanism you weigh: the waiver body-grammar was removed, so a `doc-owners` obligation is deferred only when a principal applies the actor-verified `vinaya/waiver:docs` label — a Developer cannot self-serve it, and there is no body field for you to judge. What is still yours, because no CI gate can check it: whether a published doc reads complete to a stranger who lands on it cold. Hold every doc the brief surfaces to the reader-readability rule — a reader must resolve every symbol on the page from the page itself. A doc update that satisfies C5 mechanically but leaves a sentence leaning on a decision id or bare section number a stranger can't resolve is a MINOR finding — reader-readability is never a BLOCKER.
78
78
  7. **Multi-project reach.** If the PR's brief lists more than one `Project:`, review through each project's lens — the change's blast radius spans all of them. Confirm a shared-package change (e.g. a shared `core`/`engine` package) doesn't silently break a consumer the brief didn't mention. **Before asserting blast-radius coverage is complete** — required whenever the brief lists more than one `Project:`, or the diff touches a path under a shared collision domain (live-derived `packages/*` workspace members, built-in cross-cutting defaults, plus any `vinaya.config.json` `blastRadius.extraDomains` entries) even on a single-project brief; see `contracts/planner-brief.md` for the full domain-list derivation — run the consumer check for each touched shared package and quote its output in your review comment: `git grep -l '@attalabs/<pkg>' -- 'package.json' '*/package.json'` (this repo's form — substitute the touched package's published name; the two pathspecs are both needed, since `'*/package.json'` alone skips a repo-root manifest; use `git grep`, not `rg`, which silently skips gitignored doc trees). A consumer list you never generated is a consumer list you guessed. This applies to these two verdict fields only — the other checks keep their existing shape; evidence-on-everything is the "flag everything, get ignored" failure in another costume.
79
- 8. **Register and slop, in any reader-facing prose the diff adds or edits.** Two other defects in this same family — an unresolvable citation, and a coined term used without a definition — are checked mechanically now, not by you. This one still isn't, and it is a checkable property, not a stylistic preference: does a sentence narrate the work episode instead of stating the durable fact ("this fixes the bug from the last review," "I checked every case," a first-person aside) where a stranger reading the page later has no session to place it in? Does a padding adjective ("robust," "seamless," "comprehensive") carry no concrete referent a reader could verify? Flag the sentence and say what's wrong with it, the same way you'd flag a bug — this is not the taste-based-rewrite exclusion below; it fires only on a nameable defect (narration, unearned padding), never on a phrasing you'd merely have chosen differently.
79
+ 8. **Register and slop, in any reader-facing prose the diff adds or edits.** Two other defects in this same family — an unresolvable citation, and a coined term used without a definition — are checked mechanically now, not by you. This one still isn't, and it is a checkable property, not a stylistic preference: does a sentence narrate the work episode instead of stating the durable fact ("this fixes the bug from the last review," "I checked every case," a first-person aside) where a stranger reading the page later has no session to place it in? Does a padding adjective ("robust," "seamless," "comprehensive") carry no concrete referent a reader could verify? Flag the sentence and say what's wrong with it, the same way you'd flag a bug — this is not the taste-based-rewrite exclusion below; it fires only on a nameable defect (narration, unearned padding), never on a phrasing you'd merely have chosen differently. Every finding under this check is MINOR.
80
80
 
81
81
  ## What you do NOT do
82
82
 
@@ -93,7 +93,7 @@ This is why the review is a separate pass and not something the Developer does t
93
93
 
94
94
  ## Output format
95
95
 
96
- **Run `vinaya review post --role code-reviewer` with this data; do not hand-type a verdict comment.** The `VERDICT:` line is bare — no bold, no heading, no blockquote — it is machine-read by the pre-merge review gate. So is the `Judged head:` line immediately below it: the gate binds your verdict to the exact commit you reviewed, and a verdict that does not cover the PR's current head does not count as clean, however clean its `VERDICT:` value is (`review-gate.ts`). Free-typing this shape into `gh pr comment` is no longer the sanctioned path — a decorated heading or a bolded/blockquoted line the gate's line-anchored parser cannot see reaches the forge looking correct to a human reader and is invisible to `verify-review-gate.ts`, with no pointer back to what was wrong until CI goes red. `vinaya review post` resolves the PR's real head itself (`gh pr view --json headRefOid` — never a self-reported sha), renders every structural line from your validated inputs, posts the comment, and refuses to exit 0 unless its own post re-parses clean through the exact same `extractCodeReviewVerdict` function the gate calls:
96
+ **Run `vinaya review post --role code-reviewer` with this data; do not hand-type a verdict comment.** The `VERDICT:` line is bare — no bold, no heading, no blockquote — it is machine-read by the pre-merge review gate. So is the `Judged head:` line immediately below it: the gate binds your verdict to the exact commit you reviewed, and a verdict that does not cover the PR's current head does not count as clean, however clean its `VERDICT:` value is (`review-gate.ts`). A verdict also holds for a later head whose patch identity equals the judged head's: the gate compares `git diff <base>...<sha> | git patch-id --stable` on both sides, so a merge from the main branch or a rebase that leaves the PR's own patch untouched keeps your verdict alive rather than costing a round to re-cast it over changes you already read. That comparison ignores whitespace, so a whitespace-only push also keeps your verdict; any change to non-whitespace content does not, and comes back to you. Free-typing this shape into `gh pr comment` is no longer the sanctioned path — a decorated heading or a bolded/blockquoted line the gate's line-anchored parser cannot see reaches the forge looking correct to a human reader and is invisible to `verify-review-gate.ts`, with no pointer back to what was wrong until CI goes red. `vinaya review post` resolves the PR's real head itself (`gh pr view --json headRefOid` — never a self-reported sha), renders every structural line from your validated inputs, posts the comment, and refuses to exit 0 unless its own post re-parses clean through the exact same `extractCodeReviewVerdict` function the gate calls:
97
97
 
98
98
  ```
99
99
  vinaya review post --role code-reviewer --pr <n> --verdict APPROVE|REQUEST_CHANGES \
@@ -102,7 +102,7 @@ vinaya review post --role code-reviewer --pr <n> --verdict APPROVE|REQUEST_CHANG
102
102
  --task-id <task-id> --model <model> --tokens-in <n|-> --tokens-out <n|-> --cost <text|->
103
103
  ```
104
104
 
105
- The findings file is one finding per line, `SEVERITY|file:line|description` (`|`-delimited: `file:line` already contains a colon), severity one of `BLOCKER|MAJOR|MINOR`. Omit `--findings-file` for zero findings. The command renders this exact shape (kept here so a human or a debugging agent can still read what it produces — this is documentation, not something to write by hand):
105
+ The findings file is one finding per line, `SEVERITY|file:line|description` (`|`-delimited: `file:line` already contains a colon), severity one of `BLOCKER|MAJOR|MINOR`. The `description` field begins with the finding's id and class, `F<n> <class>: <what is wrong>` — class is one of `correctness`, `type-safety`, `performance`, `resource-leak`, `maintainability`, `scope`, `test-honesty`, `doc-correctness`, or `other:<slug>` when none fits. This is free text that carries no `|` character inside the existing field, not a grammar change. Omit `--findings-file` for zero findings. The command renders this exact shape (kept here so a human or a debugging agent can still read what it produces — this is documentation, not something to write by hand):
106
106
 
107
107
  ```
108
108
  VERDICT: APPROVE | REQUEST CHANGES
@@ -113,7 +113,7 @@ BRIEF CONFORMANCE: [does it do what the brief asked? 1-2 sentences]
113
113
  SPEC CONFORMANCE: [does it agree with the Product spec? "n/a — no Product named" | "clean" | drift listed in findings]
114
114
 
115
115
  FINDINGS (ordered by severity):
116
- 1. [BLOCKER|MAJOR|MINOR] <file:line> — <what's wrong and why it matters>
116
+ 1. [BLOCKER|MAJOR|MINOR] <file:line> — F<n> <class>: <what's wrong and why it matters>
117
117
  2. ...
118
118
 
119
119
  SCOPE: [clean | N out-of-scope changes listed in findings]
@@ -121,19 +121,36 @@ TESTS: [honest | issues listed in findings]
121
121
  DOCS: [tier-appropriate | missing items listed in findings]
122
122
  ```
123
123
 
124
- `vinaya review post` also refuses before posting anything if you pass a BLOCKER finding together with `--verdict APPROVE` — that contradiction is caught mechanically, not left to review.
124
+ `vinaya review post` also refuses before posting anything if you pass a BLOCKER finding together with `--verdict APPROVE` — that contradiction is caught mechanically, not left to review. Before its own post reaches the forge, it refuses to post anything the gate would misread: it runs the exact same `VERDICT:`/`Judged head:` extraction the merge gate uses over the rendered comment, and requires exactly the intended verdict to come back. Free text in a finding, a conformance field, or `--scope-evidence-file` can say `VERDICT` or span multiple lines without risk — the extraction reads only a comment's first three lines, which are always this command's own structural lines, never a caller field.
125
125
 
126
- - **BLOCKER** — must fix before merge (wrong behavior, scope violation, dishonest test, missing required doc, **spec contradiction**).
127
- - **MAJOR** — should fix before merge (likely bug, weak error handling, **spec drift that isn't an outright contradiction**).
128
- - **MINOR** — note it; Developer's discretion.
126
+ - **BLOCKER** — blocks merge. Wrong behavior; a dishonest test; a document the brief's documentation-update list names that is absent from the diff or states the changed behavior backwards; a scope violation; a **spec contradiction**.
127
+ - **MAJOR** — surfaced, never blocks. A likely bug, weak error handling, spec drift short of contradiction, a wrong sentence in a document the brief did not name. Listed in the verdict, shown to the Principal at the go (the Principal's decision, before merge, on whether any surfaced finding blocks this change), published in the record — the Principal decides whether a surfaced finding blocks this change.
128
+ - **MINOR** — noted; Developer's discretion. Every register and slop finding (check 8) and every reader-readability finding (check 6) is at most MINOR.
129
129
 
130
130
  The `SCOPE:` line, and any blast-radius assertion under check 7, are evidence-backed claims: each may be written only after its named check has run — `git diff origin/main...HEAD --stat` for scope, the consumer grep for multi-project reach — with the output quoted in the same review comment the verdict lands in: a fenced block directly below the verdict block, so evidence sits in one predictable place. The other verdict lines carry no such requirement.
131
131
 
132
- If you have only MINOR findings, VERDICT is APPROVE. Any BLOCKER REQUEST CHANGES. (A REQUEST CHANGES sets the PR's review decision to `CHANGES_REQUESTED`, which is the derived `changes-requested` status — no one writes it down.)
132
+ VERDICT is `REQUEST CHANGES` if and only if at least one BLOCKER finding exists. Otherwise VERDICT is `APPROVE`, with every MAJOR and MINOR finding still listed under FINDINGS — an APPROVE is not silence about them, it is a statement that none of them blocks. (A REQUEST CHANGES sets the PR's review decision to `CHANGES_REQUESTED`, which is the derived `changes-requested` status — no one writes it down.) You do not type that decision by hand: `vinaya review post` derives it from the findings file you pass it — REQUEST CHANGES iff a BLOCKER is present, APPROVE otherwise — and renders the bare `VERDICT:` line and the `Judged head:` binding itself. `--verdict` is optional; if you pass one anyway, the command refuses before posting anything when it disagrees with the derivation, naming the derived value. It refuses to exit 0 unless its own post re-parses clean through the gate's extractors. The severity you assign to each finding is caller-asserted and not checked — the derivation trusts your severities, not your arithmetic.
133
+
134
+ A re-review (a fresh-context reviewer invoked again after the Developer pushes fixes) does two things, in order. First, it reports the state of every prior id — `F1`, `F2`, … — before listing any new finding, one of exactly `open`, `fix-claimed`, `reproduced`, or `resolved` per id, confirmed by re-checking the artifact, never by assuming a push means a fix. Write that state directly in the finding's own description, `F<n> <class> <state>: <text>` — that is what `vinaya review post` reads back on the next round to confirm every prior id is still accounted for; a findings file that drops a prior id with no state token is refused before posting. An id is assigned once, when a finding is first reported, and never renumbered; rewording a finding's description does not create a new id. The prior ids and the previously judged head are read from the prior verdict comment on the PR: its FINDINGS list and its `Judged head:` line. Second, round two is delta-only for every non-blocking severity: it judges only the lines changed since the previously judged head, and `vinaya review post` refuses a MAJOR or MINOR finding whose `file:line` falls outside that diff. A BLOCKER outside the delta still drives the verdict on any round and is always accepted. A prior BLOCKER you mark `resolved` keeps its BLOCKER severity in the record but no longer drives the verdict — `vinaya review post` derives the verdict only from findings not marked `resolved`; mark `fix-claimed` or `reproduced` instead if it is not actually fixed. After round two the Principal decides; there is no round three unless the Principal orders it.
133
135
 
134
136
  ## Escalation
135
137
 
136
- If you discover something that needs a decision above review authority the brief itself was wrong, the work requires a Type 1 (irreversible) decision nobody made, or the diff is right but the **spec is wrong/stale** and should change say so explicitly under FINDINGS as `[ESCALATE] severity:strategy` or `[ESCALATE] severity:product`. Do not resolve it yourself; route it to the Planner or Principal. (A spec that needs updating is a strategy escalation, not a reason to fail the PR.)
138
+ If you discover something that needs a decision above review authority, post it with `vinaya review post --escalate <class> --summary <text>` never as a finding inside a REQUEST CHANGES. An escalation is its own review outcome: it renders `ESCALATE: <class>`, never a `VERDICT:` line, and the command refuses it alongside `--verdict` or alongside any blocking finding in the same findings file. Three classes:
139
+
140
+ - `authority` — the decision is above review authority outright; you have no basis to rule on it.
141
+ - `strategy` — the brief assumes an approach the codebase has gone a different way on, or a required edit sits outside the brief's stated surface but is genuine blast radius of the change. Do not demand the out-of-surface edit yourself and then also flag it as scope creep in the same verdict — pick one: it is either in scope (name it) or it is a strategy escalation, never both.
142
+ - `product` — the work requires a Type 1 (irreversible) decision nobody made, or the diff is right but the **spec is wrong/stale** and should change. (A spec that needs updating is a `product` escalation, not a reason to fail the PR.)
143
+
144
+ Do not resolve it yourself; route it to the Planner or Principal.
145
+
146
+ ## Brief review mode
147
+
148
+ Before dispatch — a separate, time-boxed pass, not the post-dispatch code review above — a fresh-context Reviewer reads the whole brief and returns one line: `BRIEF: READY` or `BRIEF: NOT READY`. Under five minutes. Findings come in exactly two classes, nothing else:
149
+
150
+ - `contradiction` — two sentences in the brief that cannot both hold.
151
+ - `design-hole` — the design the brief specifies can be defeated by the party it constrains, or fails on an input the brief never named.
152
+
153
+ `BRIEF: NOT READY` returns the brief to its author (the Brief Author or Planner) rather than letting it proceed to dispatch — it is not a code review, and it carries no finding outside the two classes above.
137
154
 
138
155
  ## Where you sit in the process
139
156
 
@@ -143,4 +160,4 @@ Phase 10 (Review) in `process.md`. The order is: **code-reviewer pass (you) →
143
160
 
144
161
  ## Turn-end: report your tokens in the verdict comment
145
162
 
146
- You do not append your own row to `aeg-root/tranches/<name>.tokens.md` — you have no branch to write it on, and self-append was retired for every role. Instead, `vinaya review post`'s `--task-id`/`--model`/`--tokens-in`/`--tokens-out`/`--cost` flags render the closing one-line token report as part of the same posted comment: `Tokens: <task-id>: review — Reviewer — <model> — in/out/cost`. Review normally runs **operator-metered** — on a host that exposes no usage figure to the agent — so pass `-` (a literal hyphen, not this doc's `—`) for `--tokens-in`/`--tokens-out`/`--cost` when unknown; that host capability is the one sanctioned reason for a blank token cell (`tranche-model.md` §12), never inconvenience, and you never estimate. If your host does expose your own usage to you, pass the real figures instead. The per-task Archivist collects this report at close-out and appends the row to the ledger — see `roles/archivist.md`. A re-review (after the Developer pushes fixes) reports again — run `vinaya review post` again rather than editing the prior comment.
163
+ You do not append your own row to `aeg-root/tranches/<name>.tokens.md` — you have no branch to write it on, and self-append was retired for every role. Instead, `vinaya review post`'s `--task-id`/`--model`/`--tokens-in`/`--tokens-out`/`--cost` flags render the closing one-line token report as part of the same posted comment: `Tokens: <task-id>: review — Reviewer — <model> — in/out/cost`. Review normally runs **operator-metered** — on a host that exposes no usage figure to the agent — so pass `-` (a literal hyphen, not this doc's `—`) for `--tokens-in`/`--tokens-out`/`--cost` when unknown; that host capability is the one sanctioned reason for a blank token cell (`tranche-model.md` §12), never inconvenience, and you never estimate. If your host does expose your own usage to you, pass the real figures instead. The per-task Archivist collects this report at close-out and appends the row to the ledger — see `roles/archivist.md`. A re-review (after the Developer pushes fixes) reports again, following the re-review rule under [Output format](#output-format) above — run `vinaya review post` again rather than editing the prior comment.
@@ -31,7 +31,7 @@ You ask one question of an open pull request that a correctness review does not:
31
31
 
32
32
  **You never** fix what you find, merge, write status, weaken a finding to be agreeable, or quote a discovered secret in full — you name where it lives and enough characters to identify it, so the report does not become the second leak. A finding that implies a product or architecture decision is routed upward, not designed around by you.
33
33
 
34
- **How it physically runs** — you run with fresh context, in an isolated worktree, never the shared checkout, and everything you produce lands as comments on the pull request. Your verdict line is written bare, on its own, because it is machine-read and blocking: the change cannot merge without a clean pass from you and a clean approval from the code review. Only a person, acting on the forge under their own identity, can waive that for a single change.
34
+ **How it physically runs** — you run with fresh context, in an isolated worktree, never the shared checkout, and everything you produce lands as comments on the pull request. Your verdict line is written bare, on its own, because it is machine-read and blocking: the change cannot merge without a clean pass from you and a clean approval from the code review. Only a person, acting on the forge under their own identity, can waive that for a single change. The mechanical gate (CI) is your input, never your job: read its result, do not reproduce it — no `bun install`, no re-running the test suite, no re-running the check suite. Read and grep the diff with targeted commands; the dispatch that invoked you names any finding the Principal has already parked, and you do not raise those again.
35
35
 
36
36
 
37
37
  ---
@@ -62,7 +62,7 @@ Read the brief from the PR body first — it tells you what the change is *suppo
62
62
 
63
63
  ## What you check
64
64
 
65
- 1. **Secret / credential leakage.** No API keys, tokens, passwords, connection strings, or private keys in committed files — including test fixtures, `.env` examples with real values, and inline comments. Run a real secret scanner over the branch's full commit range in addition to your own read of the diff, never instead of it and paste its actual output (the scan summary and any findings, secrets redacted) into your verdict comment: without that paste, the `SECRETS:` line may not be written. As with the config scanner below, the scanner's output is input to your judgment, never the verdict a ruleset is shape-aware, so a plaintext password or an off-shape credential can ride through a clean scan that your read of the diff must still catch. Flag anything that looks like a live credential. If the scanner is unavailable in your environment, write exactly that in the verdict in place of the `SECRETS:` claim and route the gap to the Principal — never write `SECRETS: none found` unscanned. *(In this repo the scanner is gitleaks `gitleaks git --redact -v --log-opts "origin/main..HEAD"`, run from the PR branch's worktree; install via `brew install gitleaks` or a release binary from github.com/gitleaks/gitleaks. It is plan-independent — no GitHub feature has to be enabled — `--redact` keeps the pasted output from becoming the second leak, and the range form catches a secret committed and then removed in a later commit, which a tip-diff read misses.)*
65
+ 1. **Secret / credential leakage.** No API keys, tokens, passwords, connection strings, or private keys in committed files — including test fixtures, `.env` examples with real values, and inline comments. **Mechanical scan retired the manual re-run:** the same tool and range (`gitleaks git --redact --log-opts "origin/main..HEAD"`) now runs pre-review as the required `atta-labs/secret-scan` check (`vinaya.config.json`) it gates the PR (a finding fails CI, blocks merge) and its findings are visible on the check run, so re-running the identical command by hand and pasting its output here would only reproduce what CI already reports. Do not run it yourself; trust the check's pass/fail instead. What is NOT retired: your own read of the diff for anything the scanner's ruleset is shape-blind to a plaintext password, a bespoke internal token format, or an off-shape credential can still ride through a clean scan. Flag anything that looks like a live credential from that read. If the mechanical check is missing from the PR's status checks entirely (not merely passing), write exactly that in the verdict and route the gap to the Principal — never write `SECRETS: none found` on the strength of a check you didn't confirm ran.
66
66
  2. **BYOK / crypto handling.** Where the repo handles user-supplied provider keys, flag any code path that logs a decrypted key, stores a key in plaintext, sends a key to a client, or bypasses the crypto layer. *(In this repo: server-side envelope-encrypted BYOK via `@atta/crypto`; the old browser-only/passkey model is retired — flag references to it.)*
67
67
  3. **Auth / permissions.** Auth-provider misconfig, routes that should require auth but don't, cookie-scope errors, over-broad CORS, privilege escalation. *(Read the repo's own auth surface: the SSO cookie scope of the shared provider, and any product running a separate auth app.)*
68
68
  4. **MCP / agent tooling exposure.** A real surface wherever the repo exposes agent tooling: hosted MCP servers, agent definitions, and hooks. Flag a tool that is newly exposed without auth, a hook that runs untrusted input, an MCP config that points at an unintended target, or an agent granted broader tools than its job needs. *(In this repo: the hosted Vāda MCP and the `.claude/` agent/skill/hook configs.)*
@@ -87,7 +87,7 @@ When the PR touches agent/skill/hook definitions, MCP configs, or anything under
87
87
 
88
88
  ## Output format
89
89
 
90
- **Run `vinaya review post --role security` with this data; do not hand-type a verdict comment.** The `VERDICT:` line is bare — no bold, no heading, no blockquote — it is machine-read by the pre-merge review gate. So is the `Judged head:` line immediately below it: the gate binds your verdict to the exact commit you reviewed, and a verdict that does not cover the PR's current head does not count as clean, however clean its `VERDICT:` value is (`review-gate.ts`). Free-typing this shape into `gh pr comment` is no longer the sanctioned path — a decorated heading or a bolded/blockquoted line the gate's line-anchored parser cannot see reaches the forge looking correct to a human reader and is invisible to `verify-review-gate.ts`, with no pointer back to what was wrong until CI goes red. `vinaya review post` resolves the PR's real head itself (`gh pr view --json headRefOid` — never a self-reported sha), renders every structural line from your validated inputs, posts the comment, and refuses to exit 0 unless its own post re-parses clean through the exact same `extractSecurityReviewVerdict` function the gate calls:
90
+ **Run `vinaya review post --role security` with this data; do not hand-type a verdict comment.** The `VERDICT:` line is bare — no bold, no heading, no blockquote — it is machine-read by the pre-merge review gate. So is the `Judged head:` line immediately below it: the gate binds your verdict to the exact commit you reviewed, and a verdict that does not cover the PR's current head does not count as clean, however clean its `VERDICT:` value is (`review-gate.ts`). A verdict also holds for a later head whose patch identity equals the judged head's: the gate compares `git diff <base>...<sha> | git patch-id --stable` on both sides, so a merge from the main branch or a rebase that leaves the PR's own patch untouched keeps your verdict alive rather than costing a round to re-cast it over changes you already read. That comparison ignores whitespace, so a whitespace-only push also keeps your verdict; any change to non-whitespace content does not, and comes back to you. Free-typing this shape into `gh pr comment` is no longer the sanctioned path — a decorated heading or a bolded/blockquoted line the gate's line-anchored parser cannot see reaches the forge looking correct to a human reader and is invisible to `verify-review-gate.ts`, with no pointer back to what was wrong until CI goes red. `vinaya review post` resolves the PR's real head itself (`gh pr view --json headRefOid` — never a self-reported sha), renders every structural line from your validated inputs, posts the comment, and refuses to exit 0 unless its own post re-parses clean through the exact same `extractSecurityReviewVerdict` function the gate calls:
91
91
 
92
92
  ```
93
93
  vinaya review post --role security --pr <n> --verdict PASS|FAIL \
@@ -111,17 +111,27 @@ CONFIG SCAN: [not applicable | clean | findings folded in above]
111
111
  SECRETS: [none found | listed above, redacted]
112
112
  ```
113
113
 
114
+ Before its own post reaches the forge, `vinaya review post` refuses to post anything the gate would misread: it runs the exact same `VERDICT:`/`Judged head:` extraction the merge gate uses over the rendered comment, and requires exactly the intended verdict to come back. Free text in a finding, `--config-scan`, or `--secrets` can say `VERDICT` or span multiple lines without risk — the extraction reads only a comment's first three lines, which are always this command's own structural lines, never a caller field.
115
+
114
116
  - **CRITICAL** — leaked live credential, auth bypass, key sent to client. Any CRITICAL → FAIL.
115
117
  - **HIGH** — likely exploitable misconfig or injection surface.
116
118
  - **MEDIUM/LOW** — hardening notes.
117
119
 
118
- Any CRITICAL or HIGH → VERDICT FAIL. Only MEDIUM/LOW → PASS with notes. `vinaya review post` refuses before posting anything if you pass a CRITICAL/HIGH finding together with `--verdict PASS`that contradiction is caught mechanically, not left to review.
120
+ Any CRITICAL or HIGH → VERDICT FAIL. Only MEDIUM/LOW → PASS with notes. You do not type that decision by hand: `vinaya review post` derives it from the findings file you pass it — FAIL iff a CRITICAL or HIGH is present, PASS otherwise and refuses before posting anything if `--verdict` disagrees with the derivation, naming the derived value.
121
+
122
+ A re-pass after the Developer's fixes follows the same re-review rule as the code role: report the state of every prior id (`open`, `fix-claimed`, `reproduced`, `resolved`) in the finding's own description, `F<n> <class> <state>: <text>`, before listing anything new — `vinaya review post` refuses a findings file that drops a prior id with no state token. Round two is delta-only for MEDIUM and LOW: a MEDIUM/LOW finding whose `file:line` falls outside the diff since the previously judged head is refused. A CRITICAL or HIGH outside the delta still drives the verdict on any round and is always accepted. A prior CRITICAL/HIGH you mark `resolved` keeps its severity in the record but no longer drives the verdict — `vinaya review post` derives the verdict only from findings not marked `resolved`; mark `fix-claimed` or `reproduced` instead if it is not actually fixed.
119
123
 
120
124
  The `SECRETS:` line is evidence-backed, not asserted: the secret scanner's pasted output (check 1) must appear in the verdict comment above it — necessary evidence that the scan ran, never sufficient on its own, since the judgment half of check 1 still stands behind the claim. `SECRETS: none found` with no scan output pasted is an unbacked self-attestation — the exact claim this check exists to catch in others' work, not to commit in your own. `vinaya review post` mechanizes this: passing `--secrets "none found"` without `--secrets-evidence-file <path>` (the actual pasted scanner output) is refused outright.
121
125
 
122
126
  ## Escalation
123
127
 
124
- A security finding that implies a product/architecture decision (e.g., "the whole BYOK flow needs rethinking") is `[ESCALATE] severity:product` route to Principal, do not design the fix yourself.
128
+ If you discover something that needs a decision above review authority, post it with `vinaya review post --escalate <class> --summary <text>` — never as a finding inside a FAIL. An escalation is its own review outcome: it renders `ESCALATE: <class>`, never a `VERDICT:` line, and the command refuses it alongside `--verdict` or alongside any CRITICAL/HIGH finding in the same findings file. Three classes:
129
+
130
+ - `authority` — the decision is above review authority outright; you have no basis to rule on it.
131
+ - `strategy` — the brief assumes an approach the codebase has gone a different way on, or a required edit sits outside the brief's stated surface but is genuine blast radius of the change.
132
+ - `product` — a security finding that implies a product/architecture decision (e.g., "the whole BYOK flow needs rethinking").
133
+
134
+ Do not design the fix yourself; route it to the Planner or Principal.
125
135
 
126
136
  ## Where you sit in the process
127
137
 
@@ -4,7 +4,7 @@ sidebar_title: Operating Model (aeg)
4
4
  description: The front door to Agentic Execution Governance (AEG) — the operating model every agent works inside. Load at the start of ANY session in this repo, before doing anything substantive, regardless of role. Covers what AEG is, the four truth domains, forge-derived status, the tranche topology file, where the plan vs the flow vs governance live, the dispatch gates, the brief, the anti-regression rules, the orient-from-root layout (`aeg-root/` model + `aeg-project/` state), and the model-vs-product distinction. Ends by routing to the aeg-roles skill and the reading order. Does NOT cover role specifics (see aeg-roles + roles/*.md) or brief authoring (see brief-authoring).
5
5
  ---
6
6
 
7
- <!-- CANONICAL SOURCE. This file is the canonical home of the `aeg` skill, inside the AEG unit (aeg-root/skills/). provides for an agent-specific GENERATED VIEW under .claude/skills/ (or another agent's equivalent), rebuilt from this file rather than authored by hand — but no such generator exists yet, and this repo has no generated view of this skill: agents are pointed at aeg-root/ directly (root CLAUDE.md). Edit THIS file; if a generator is ever built, regenerate rather than hand-editing its output. -->
7
+ <!-- CANONICAL SOURCE. This file is the canonical home of the `aeg` skill, inside the AEG unit (aeg-root/skills/). provides for an agent-specific GENERATED VIEW under `.claude/skills/` (or another agent's equivalent), rebuilt from this file rather than authored by hand — but no such generator exists yet, and this repo has no generated view of this skill: agents are pointed at aeg-root/ directly (this repo's root agent-context file). Edit THIS file; if a generator is ever built, regenerate rather than hand-editing its output. -->
8
8
 
9
9
  # AEG — the operating model (front door)
10
10
 
@@ -12,14 +12,14 @@ description: The front door to Agentic Execution Governance (AEG) — the operat
12
12
 
13
13
  AEG = **Agentic Execution Governance.** It is a small set of accountable roles coordinating AI agents through briefs, independent review, and blocking escalation. It is **governance + orchestration of delegated AI execution** — it is *not* project management: there is no plan, timeline, or resource tracking inside AEG (that lives in the backlogs / a company tool, outside the flow).
14
14
 
15
- AEG is **agent-agnostic and tool-agnostic.** The roles below describe *what an agent must do*, not which agent does it — any capable coding agent (Claude Code, Codex, or another) can take a role by reading its doc. The model names no vendor as a dependency.
15
+ AEG is **agent-agnostic and tool-agnostic.** The roles below describe *what an agent must do*, not which agent does it — any capable coding agent can take a role by reading its doc. The model names no vendor as a dependency.
16
16
 
17
17
  ---
18
18
 
19
19
  ## 1. AEG is two things sharing one name (don't confuse them)
20
20
 
21
21
  - **AEG the model** — this operating model: the governance/flow constitution. It lives at repo-root `aeg-root/` (the model exists once, at the root only) and governs the whole repo. *This skill is the model.*
22
- - **AEG the product** — a deployed UI that *visualizes* a repo's AEG execution, plus the CLI that lays the AEG structure into any repo. That product is **Vinaya**; in this repo it lives at `apps/vinaya/` (the earlier `apps/aeg` app was superseded by it and deleted).
22
+ - **AEG the product** — a deployed UI (**Studio**) that *visualizes* a repo's AEG execution, plus the CLI that lays the AEG structure into any repo. That product is **Vinaya**. The CLI and Studio are maintained as separate source trees, in separate repositories an adopter installing Vinaya gets the CLI; Studio, where it runs, is a hosted or self-run separate deployment, not something this project's own repo layout says anything about.
23
23
 
24
24
  When someone says "AEG," default to the model unless the context is clearly the product (the UI, the website, the scaffolder).
25
25
 
@@ -93,9 +93,11 @@ After this skill, load in order: **`aeg-roles`** (routes you to your role doc)
93
93
 
94
94
  Execution state is **derived from the forge, never read from a file** — there is no state file, no status doc, no hand-maintained state Issue. (`coordination.md`, which once carried a session-start protocol plus a pinned per-project state-Issue layer, is retired: its queries cited label names that don't exist in any adopter, and the state-Issue layer duplicated what Milestones and tranche labels already derive — the one live instance drifted stale and was closed.) Substitute your repo's label namespace — the queries below use this repo's `vinaya/` prefix:
95
95
 
96
- **"What's active?"**
96
+ **"What's active?"** — two independent queries, not a sequence:
97
97
  ```bash
98
98
  gh issue list --label "vinaya/tranche:<slug>" --state open
99
+ ```
100
+ ```bash
99
101
  gh pr list --state open
100
102
  ```
101
103
 
@@ -104,9 +106,11 @@ gh pr list --state open
104
106
  gh issue list --label "vinaya/blocked" --state open
105
107
  ```
106
108
 
107
- **"What needs the Principal?"**
109
+ **"What needs the Principal?"** — two independent queries, not a sequence:
108
110
  ```bash
109
111
  gh issue list --label "vinaya/needs:principal-input" --state open
112
+ ```
113
+ ```bash
110
114
  gh pr list --label "vinaya/needs:principal-input" --state open
111
115
  ```
112
116
 
@@ -4,7 +4,7 @@ sidebar_title: Router (aeg-roles)
4
4
  description: The role router for AEG. Load right after the aeg skill to determine which AEG role you are from your invocation environment and open the one role doc that governs you. Covers role determination, a one-line job + entry gate per role, and the authority boundaries (who may mutate what, who escalates, who never reviews their own work). This is a ROUTER — it points to aeg-root/roles/*.md for the full spec of each role and never reproduces them. Load when you need to know "which role am I and which doc do I open."
5
5
  ---
6
6
 
7
- <!-- CANONICAL SOURCE. This file is the canonical home of the `aeg-roles` skill, inside the AEG unit (aeg-root/skills/). provides for an agent-specific GENERATED VIEW under .claude/skills/ (or another agent's equivalent), rebuilt from this file rather than authored by hand — but no such generator exists yet, and this repo has no generated view of this skill: agents are pointed at aeg-root/ directly (root CLAUDE.md). Edit THIS file; if a generator is ever built, regenerate rather than hand-editing its output. -->
7
+ <!-- CANONICAL SOURCE. This file is the canonical home of the `aeg-roles` skill, inside the AEG unit (aeg-root/skills/). provides for an agent-specific GENERATED VIEW under `.claude/skills/` (or another agent's equivalent), rebuilt from this file rather than authored by hand — but no such generator exists yet, and this repo has no generated view of this skill: agents are pointed at aeg-root/ directly (this repo's root agent-context file). Edit THIS file; if a generator is ever built, regenerate rather than hand-editing its output. -->
8
8
 
9
9
  # AEG roles — the router
10
10
 
@@ -29,7 +29,7 @@ Role is determined by **how you were invoked** — the *kind* of surface and the
29
29
  | **Closing out a finished tranche** (the Principal has declared it done) | **Tranche Archivist** | `roles/tranche-archivist.md` |
30
30
  | The human directing the work | **Principal** | `roles/principal.md` |
31
31
 
32
- *(The "coding-agent surface" is whatever CLI/IDE agent the team uses — e.g. Claude Code, Codex, or another. The "chat / planning surface" is whatever conversational agent the team uses. The role is the same regardless; the surface kind is the signal.)*
32
+ *(The "coding-agent surface" is whatever CLI/IDE agent the team uses. The "chat / planning surface" is whatever conversational agent the team uses. The role is the same regardless; the surface kind is the signal.)*
33
33
 
34
34
  Always also skim `roles/principal.md` to know what sits in the Principal's seat (ratification, Type 1 authority).
35
35
 
@@ -4,7 +4,7 @@ sidebar_title: Brief Authoring
4
4
  description: Rules for authoring task briefs dispatched to Developer agents. Load when writing or reviewing a brief. Covers the Brief Author's conversational protocol, required sections, inheriting the Planner's rationale via the planner-brief contract, the contract-conformance checklist, the mandatory technical-dependency / tech-surface-map / agent-selection-with-reasoning sections, the optional Ticket/Project fields, model selection, the model integration (tier field, principal_delegate, Type 1/2 declaration, lock acknowledgment), the mandatory worktree-first step, the brief-lands-in-the-PR-body rule, the standing autonomy clause, the explicit documentation-update list, the post-PR review passes, and anti-patterns.
5
5
  ---
6
6
 
7
- <!-- CANONICAL SOURCE. This file is the canonical home of the `brief-authoring` skill, inside the AEG unit (aeg-root/skills/). provides for an agent-specific GENERATED VIEW under .claude/skills/ (or another agent's equivalent), rebuilt from this file rather than authored by hand — but no such generator exists yet, and this repo has no generated view of this skill: agents are pointed at aeg-root/ directly (root CLAUDE.md). Edit THIS file; if a generator is ever built, regenerate rather than hand-editing its output. -->
7
+ <!-- CANONICAL SOURCE. This file is the canonical home of the `brief-authoring` skill, inside the AEG unit (aeg-root/skills/). provides for an agent-specific GENERATED VIEW under `.claude/skills/` (or another agent's equivalent), rebuilt from this file rather than authored by hand — but no such generator exists yet, and this repo has no generated view of this skill: agents are pointed at aeg-root/ directly (this repo's root agent-context file). Edit THIS file; if a generator is ever built, regenerate rather than hand-editing its output. -->
8
8
 
9
9
  # Brief Authoring Rules
10
10
 
@@ -30,6 +30,8 @@ The Brief Author's stages — name them, and say which you're in:
30
30
 
31
31
  2. **Dig** — the deep pass for the *perishable* detail (current signatures, exact file list, final model pick). Narrate the load-bearing reads: *"Reading `llm.ts` now to get the current vendor-branch shape for the surface map."* If the dig **contradicts** the rationale (boundary moved, sizing broke), STOP and say so — that's a `severity:strategy` escalation back to the Planner, announced, not a silent fix.
32
32
 
33
+ **First Dig step: render the mechanical skeleton.** Run `vinaya brief render <tranche> <n> --surfaces <glob,...>` before digging anything by hand (task 12). It fills every section a program can derive — the header's `Project:`/`Tier:`/`Closes #N`, the Step 0 worktree line, the dispatch-gate pre-flight line, §4's file list with consumer packages and a `sha256` premise pin per file, §7 from the doc-owners derivation, and every remaining section from the Issue's eight-field rationale — straight from the forge and the tree. It refuses, naming the missing fact, when a derived section cannot be derived at all. What remains after this is the judgment: the sections it could not derive, and confirming what it did derive still matches the current code (the rest of the Dig, below).
34
+
33
35
  **Mechanized pre-authoring gate.** Before beginning the rest of the Dig, run `vinaya check dispatch-readiness` from the task branch. It mechanically re-derives the precondition checks below — row-existence, Issue-existence, prior-tranche archival — directly from a freshly-fetched `origin/main` and the live forge, and prints the exact failing predicate by name. **Known gap:** its prior-tranche-archival predicate always reports empty — confirm that one by hand regardless of what it prints. A `NOT READY` result is the same STOP this section describes below — read the printed blocker and act on it; do not re-derive the fact by hand. The manual `gh`/`jq` procedures that follow remain as the **why** (what each precondition means, and how to verify it by hand if the check is ever unavailable) — they are no longer the primary workflow. This exists because four Developer agents independently re-derived, and stopped on, the exact same archival fact from scratch during the 2026-07-02/03 dispatch wave, at real token cost, hours after it first became true — a fact any of these checks answers deterministically in seconds. **This gate now also runs mechanically** — the `first-push-dispatch` check, wired into every adopter's generated CI and managed `.git/hooks/pre-push`, invokes the same derivation on a task branch's first push — but running it yourself here, before the Dig, remains the cheaper, earlier catch: it stops you before any work is spent, not after. (2026-07-13: prior-task archival — the row-adjacency check formerly listed here — was removed from this composed gate; see check (c) below, now superseded.) **On this repo's toolchain**, `bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n>` runs the unabridged derivation, including the real prior-tranche-archival predicate.
34
36
 
35
37
  **Read obligation — complete during Dig, before Draft:** As part of the Dig, identify any specs/skills/docs relevant to this task's code surface and read them. This obligation is conditional — if no docs exist for this surface, it is trivially satisfied. The Planner's "Docs to keep coherent" rationale field is the starting point; your own reading may surface additional docs the Planner missed. Then:
@@ -132,10 +134,12 @@ Before a brief is dispatchable, confirm **every one of the seven Planner fields
132
134
  - [ ] **Row-existence and Issue-existence preconditions** → does the task's row exist at all in the tranche topology file, read from a freshly-fetched `origin/main`? If not, the plan PR hasn't merged — **STOP** and do not author the brief. If the row exists, does its Issue column carry a real GitHub Issue number (not `#TBD`, not blank)? If not, the task is backlog — **STOP** and surface the need for the Planner to cut the Issue before proceeding. A brief cannot carry `Closes #N` without a real N. (Mirrors Developer entry gate items 3 and 7; catches it one stage earlier, during Dig.)
133
135
  - [ ] ~~**Task-status coherence precondition** → for every in-scope prior task, do all three predicates hold: Issue closed, PR merged to main, provenance block present?~~ **SUPERSEDED** — no longer a checklist item; the prior-task archival bar is removed as a hard-STOP. (Mirrors Developer entry gate item 5, prior-tranche-archival, which remains live; item 4 is the superseded one.)
134
136
  - [ ] **Read obligation + §7 populated from reading** → did you identify and read the relevant specs/skills/docs for this task's code surface during the Dig? Does §7 name every doc this task will make incoherent (or state "No doc updates required" if none)? A §7 populated from memory rather than from reading is malformed — the Brief Author's reading is what makes the DoD obligation trustworthy.
137
+ - [ ] **No behavioural claim about code outside `Premise:` or a fenced command** → every sentence in the brief asserting what code does, checks, refuses, reads, or returns is either a `Premise:` pin or a fenced command with its executed output pasted beneath it (§2's rule).
138
+ - [ ] **No multi-step command sequence described in prose** → any sequence of shell steps the brief prescribes is one named `vinaya` command, or, where that command doesn't exist yet, a statement of that fact plus the Issue that will build it.
135
139
 
136
- Plus the brief's own structural gates: worktree Step 0 present; `Tier:` declared; doc-update list non-empty for Tier 1+; **Test Plan (§9) present and tagged** — either `Test Plan: unit-tests-only` (and §4 has no runtime surface) or a checkbox list with at least one `[agent]` or `[principal]` item per reachable surface kind; the standing autonomy clause present in §11; no `[NEEDS CLARIFICATION]` left unresolved. When all boxes tick, announce it (protocol step 4/6) and the brief is dispatchable.
140
+ Plus the brief's own structural gates: worktree Step 0 present; `Tier:` declared; doc-update list non-empty for Tier 1+; **Test Plan (§9) present and shaped correctly** — either `Test Plan: unit-tests-only` (and §4 has no runtime surface) or a fenced `[agent]` command list (task 12 — one command per line, `→ <observable>` on each) plus, when a Principal-runnable path is also reachable, at least one `[principal]` checkbox item; the standing autonomy clause present in §11; no `[NEEDS CLARIFICATION]` left unresolved. When all boxes tick, announce it (protocol step 4/6) and the brief is dispatchable.
137
141
 
138
- **The structural half of that paragraph is mechanical — run it, don't eyeball it:** the `brief-shape` check — `PR_BODY="$(cat brief.md)" vinaya check brief-shape`, wired into every adopter's generated CI and runnable standalone the same way pre-PR (protocol step 4). On this repo's toolchain the same check is also reachable as `bun packages/aeg-core/bin/verify-brief.ts --body-file <brief.md>`. The judgment items above it stay human; the presence items below it are exactly what the gate checks. Note the gate applies **whatever the branch is** — a standalone `fix/*` brief is graded identically to a `task/*` one, because it is equally a brief (the `fix/*` bypass that used to skip it let a fix brief ship with no §7 list).
142
+ **The structural half of that paragraph is mechanical — run it, don't eyeball it:** the `brief-shape` check — `PR_BODY="$(cat brief.md)" vinaya check brief-shape`, wired into every adopter's generated CI and runnable standalone the same way pre-PR (protocol step 4). On this repo's toolchain the same check is also reachable as `bun packages/aeg-core/bin/verify-brief.ts --body-file <brief.md>`. The judgment items above it stay human; the presence items below it are exactly what the gate checks. Note the gate applies **whatever the branch is** — a standalone `fix/*` brief is graded identically to a `task/*` one, because it is equally a brief (the `fix/*` bypass that used to skip it let a fix brief ship with no §7 list). `aeg-root/roles/brief-author.md`'s entry gate names this same split explicitly: items 2 and 3 there are tranche-only and simply do not apply to a `fix/*` brief, items 1 and 4 govern a `fix/*` brief too, and the entry gate's own standalone-fix path covers what a `fix/*` brief does instead of the tranche route.
139
143
 
140
144
  ---
141
145
 
@@ -146,7 +150,7 @@ Plus the brief's own structural gates: worktree Step 0 present; `Tier:` declared
146
150
  ### 1. Header block
147
151
 
148
152
  ```
149
- **For:** [model + environment, e.g., "Sonnet (a coding-agent CLI on a dev machine, interactive session)"]
153
+ **For:** [model + environment, e.g., "your-model (a coding-agent CLI on a dev machine, interactive session)"]
150
154
  **Reason:** [why this model/environment was chosen — see "Agent/model selection" below]
151
155
  **Owner:** [who owns the task — the Principal, by default]
152
156
  **Goal:** [one sentence: what ships]
@@ -164,6 +168,10 @@ Full background the executor needs:
164
168
  - Relevant decisions already made (link the pull request that made each)
165
169
  - **The Planner's rationale for this task** (inherited via the contract — boundary, blast radius, traps, stop conditions). Carry it forward; the executor must see the planner's reasoning, not just the goal.
166
170
 
171
+ **A brief never asserts what code does, checks, refuses, reads, or returns — including here in §2.** A fact the brief's reasoning depends on takes exactly one of two forms: a `Premise:` pin (see the Premise pins section under §4), which `verify-dispatch --premise` re-asserts before Step 0; or a fenced command in §5 or §6 followed immediately by a fenced block holding the output the Brief Author obtained by running it before dispatch — the Developer re-runs the command and compares before writing anything that depends on it. A command with no executed output beneath it is a claim in disguise, not evidence. Naming a file, a symbol, or a location is allowed ("`review-post.ts` is in surface", "the refusal lives near line 645"); asserting its behavior is not ("`review-post.ts` refuses X"). The second becomes a command instead: "run `grep -n refuse apps/cli/src/commands/review-post.ts`, read every hit, and write doctrine from what the hits say." If a command's actual output contradicts a sentence already in the brief, that is a brief defect — the Developer stops (`severity: strategy`) rather than transcribing the sentence into doctrine.
172
+
173
+ The same discipline covers a multi-step command sequence: a document never describes one in prose — it is one `vinaya` command, and the document names it. Where the command does not exist yet, the document says so and names the Issue that will build it, instead of spelling out the steps.
174
+
167
175
  Length: as long as needed. This section prevents the executor re-deriving architecture that's already decided.
168
176
 
169
177
  ### 3. Technical dependencies (mandatory — the "what must already exist" map)
@@ -213,6 +221,7 @@ Exactly three assertion kinds — `contains:<literal-substring>`, `absent:<liter
213
221
  - **A Tier 0 brief with zero runtime/code surface has nothing to pin** — omit the `Premise:` block entirely (mirrors the Test Plan's `unit-tests-only` exemption, §9).
214
222
  - **Do not pin more than a handful of facts** — this is a targeted stale-premise detector, not a full pre-flight snapshot of the surface.
215
223
  - **This is a Brief-Author-only field — the Planner does not emit a premise-candidate field in the rationale.** Premises are perishable, file-content-level detail (current signatures, current constants), squarely the Brief Author's half of the Planner/Brief Author division of labor (see "Start from the Planner's rationale" above) — not a durable conclusion the Planner should be pinning at plan time, when the file content is more likely to have moved by dispatch.
224
+ - **A pin, or a fenced command with its executed output pasted beneath it, is the only form a behavioural fact about code may take anywhere in the brief — prose is not a third form.** See the rule in §2.
216
225
 
217
226
  ### 5. Pre-flight checks
218
227
 
@@ -238,7 +247,7 @@ After the worktree exists, verify: working dir clean (`git status`); branch corr
238
247
 
239
248
  ### 6. Numbered parts with numbered tasks
240
249
 
241
- Break work into Parts (major areas) and numbered tasks within each. Each task specifies: exact files to create/modify (from the Section 4 surface map); exact function/type signatures (not prose); constraints (no auto-remove, no extra tools, no UI in V0); verification steps. Do NOT leave implementation details to the executor's judgment unless you explicitly trust it and say so.
250
+ Break work into Parts (major areas) and numbered tasks within each. Each task specifies: exact files to create/modify (from the Section 4 surface map); exact function/type signatures (not prose); constraints (no auto-remove, no extra tools, no UI in V0); verification steps. Do NOT leave implementation details to the executor's judgment unless you explicitly trust it and say so. A Part that depends on a fact about current code opens with the fenced command that establishes it, followed by the output the Brief Author obtained running it before dispatch — not a description of what the command should show (see §2's rule). A Part that prescribes a multi-step command sequence was executed once by the Brief Author before dispatch, on a scratch branch or PR, with what happened pasted beneath it.
242
251
 
243
252
  ### 7. Documentation-update list (explicit, tier-tied)
244
253
 
@@ -265,10 +274,10 @@ These are the **static** gates — they prove the code compiles, lints, types, t
265
274
 
266
275
  **The Test Plan is a required brief field.** It is the *runtime* counterpart to §8's static gates: the named, executable observations that prove the shipped change actually works against a booted app, not just that it compiles. The Verification phase (`aeg-root/roles/developer.md` § Verification) consumes this section directly — without a Test Plan, Verification has nothing to run and the merge gate is undefined.
267
276
 
268
- Every Test Plan item carries one of two tags, by who can structurally execute it:
277
+ The Test Plan splits in two, by who can structurally execute it:
269
278
 
270
- - **`[agent]`**non-auth, scriptable items the dispatched Developer-agent runs against the booted app: SSRF rejections, route response shapes, parse-error responses, render smoke, malformed-input behavior. Each item names a concrete observable (HTTP status + body, a console line, a DOM node) and the exact command/curl that produces it. Verification pastes the actual output as evidenceparaphrase is not evidence.
271
- - **`[principal]`** — auth-gated, key-dependent, or visual items only the Principal can run in a real signed-in browser: a signed-in BYOK audit returning a CLEAN report, a ModelPicker render behind Clerk, a visual confirmation that a card lands in the right column. Each item names what the Principal does and what they should observe. The Principal ticks the box.
279
+ - **`[agent]` half** a fenced list of commands (task 12; Principal ruling: an agent never ticks a box or edits a PR body), one per line, each ending in `→ <observable>`: SSRF rejections, route response shapes, parse-error responses, render smoke, malformed-input behavior, all scriptable against the booted app with no human auth. `vinaya pr report` runs every line in this fence from the PR head and writes the command plus its actual output into the `AEG:EVIDENCE` block there is no checkbox for this half at all, and nothing for the Developer to paste by hand.
280
+ - **`[principal]` half** — auth-gated, key-dependent, or visual items only the Principal can run in a real signed-in browser: a signed-in BYOK audit returning a CLEAN report, a ModelPicker render behind Clerk, a visual confirmation that a card lands in the right column. Each item names what the Principal does and what they should observe, as a `- [ ] **[principal]**` checkbox — the ONLY checkbox form left in a Test Plan. The Principal ticks it.
272
281
 
273
282
  Pure-logic tasks (a parser, a sum function, a markdown normaliser — no API route, no page, no server action) declare:
274
283
 
@@ -280,25 +289,28 @@ This is a **first-class allowed value**, not an empty skip — it is the explici
280
289
 
281
290
  A well-formed Test Plan looks like:
282
291
 
283
- ```
292
+ ````
284
293
  **Test Plan:**
285
- - [ ] **[agent]** SSRF: `curl -X POST .../api/resolve-input -d '{"url":"http://10.0.0.1"}'` → 400 "URL rejected"
286
- - [ ] **[agent]** Malformed upload: `.md` with binary bytes → 400 "Parse error: …"
287
- - [ ] **[agent]** Route smoke: `GET /api/audit/health` 200 `{"ok":true}`
294
+ ```
295
+ curl -X POST .../api/resolve-input -d '{"url":"http://10.0.0.1"}' → 400 "URL rejected"
296
+ .md upload with binary bytes 400 "Parse error: "
297
+ curl .../api/audit/health → 200 `{"ok":true}`
298
+ ```
288
299
  - [ ] **[principal]** Sign in → upload a CV (PDF) → run audit → CLEAN report with grade A/B/C/D
289
300
  - [ ] **[principal]** ModelPicker renders in `/settings`; switching persists across a refresh
290
- ```
301
+ ````
291
302
 
292
- The unchecked boxes are the merge gate: an unticked `[agent]` box means the Developer has not yet posted the evidence comment; an unticked `[principal]` box means the Principal has not yet verified in the browser. A PR with an unticked box is not mergeable.
303
+ The gate before merge is: the `AEG:EVIDENCE` block's `[agent]` group matches a fresh recompute at the PR head (`evidence-fresh`), and every `[principal]` box is ticked. A PR failing either is not mergeable.
293
304
 
294
305
  #### Authoring rules
295
306
 
296
- - **Every brief with runtime surface has a Test Plan with at least one `[agent]` item and at least one `[principal]` item when both kinds of paths are reachable.** A brief that touches an API route (= an `[agent]`-runnable surface) AND a page behind Clerk (= a `[principal]`-runnable surface) lists both. A brief that touches only one of those lists only that kind.
297
- - **A Test Plan is `unit-tests-only` if and only if the §4 Technical Surface Map has no runtime surface in it** — no API route, no page, no server action, no `runtime`-marked file. (If §4 lists, say, an API route file, you cannot declare `unit-tests-only`.) The two fields are coupled; `vinaya pr create`/`vinaya pr edit` mechanically reject a body that declares `Test Plan: unit-tests-only` while also carrying a tagged `- [ ]`/`- [x]` checkbox item (`checkTestPlanExclusivity`) — not just cross-checked in prose.
298
- - **Items name concrete observables, not properties.** "The audit works" is not a test plan item. "Sign in upload `tests/fixtures/cv-anna.pdf` → audit returns a `MatchReport` with `grade` in `A|B|C|D` and `signals.length > 0`" is.
299
- - **`[agent]` items must be scriptable from the dispatched-agent surface** — they need no human auth, no Principal-stored BYOK keys, no human eyes on a render. If an item needs any of those, it is `[principal]`. Mis-tagging an `[agent]` item that actually requires auth is the failure mode the Verification phase exists to remove (`roles/developer.md` § Verification); the Brief Author owns the tagging.
300
- - **The Principal cannot tick `[agent]` boxes and the agent cannot tick `[principal]` boxes.** This asymmetry is the whole shape of the gate (mirror of the chat-vs-terminal token capture). A brief that pretends one actor can satisfy the other's half is malformed.
307
+ - **Every brief with runtime surface has a fenced `[agent]` command list, and at least one `[principal]` item when a Principal-runnable path is also reachable.** A brief that touches an API route (= `[agent]`-runnable) AND a page behind Clerk (= `[principal]`-runnable) lists both. A brief that touches only one of those lists only that kind.
308
+ - **A Test Plan is `unit-tests-only` if and only if the §4 Technical Surface Map has no runtime surface in it** — no API route, no page, no server action, no `runtime`-marked file. (If §4 lists, say, an API route file, you cannot declare `unit-tests-only`.) The two fields are coupled; `vinaya pr create`/`vinaya pr edit` mechanically reject a body that declares `Test Plan: unit-tests-only` while also carrying either shape of Test Plan content (`checkTestPlanExclusivity`) — not just cross-checked in prose.
309
+ - **Fenced-list commands name concrete observables, not properties.** "The audit works" is not a test plan item. "`curl` the audit endpoint with `tests/fixtures/cv-anna.pdf` → a `MatchReport` with `grade` in `A|B|C|D` and `signals.length > 0`" is.
310
+ - **`[agent]` fenced commands must be scriptable from the dispatched-agent surface** — they need no human auth, no Principal-stored BYOK keys, no human eyes on a render. If a check needs any of those, it belongs in the `[principal]` half instead. Mis-placing an auth-gated check in the fenced list is the failure mode the Verification phase exists to remove (`roles/developer.md` § Verification); the Brief Author owns the split.
311
+ - **The Principal cannot satisfy the `[agent]` fence and the agent cannot tick `[principal]` boxes.** This asymmetry is the whole shape of the gate (mirror of the chat-vs-terminal token capture). A brief that pretends one actor can satisfy the other's half is malformed.
301
312
  - **If there is no principal-runnable surface, omit the `[principal]` item entirely — never write a placeholder like `**[principal]** None`.** An untickable placeholder box blocks the merge gate forever; Brief Validation mechanically rejects it (`checkPrincipalPlaceholder`, `packages/aeg-core/src/brief-validation.ts`).
313
+ - **A body opened before the rollout constant may still carry checkbox `[agent]` items** — grandfathered below `AGENT_BOXES_REFUSED_SINCE_PR`. Every brief authored now uses the fenced-list shape; `brief-shape` refuses a checkbox `[agent]` item on a new PR.
302
314
 
303
315
  #### Where the Test Plan lives in the brief
304
316
 
@@ -322,7 +334,7 @@ What the executor must NOT do: off-limits branches/paths (the out-of-surface set
322
334
 
323
335
  Every brief's Constraints section includes this clause, word for word:
324
336
 
325
- > **Autonomy:** Do not stop to ask clarifying questions. For any ambiguity not covered by a Section 10 stop condition, choose the most reasonable option consistent with this brief, record the choice in the PR body, and continue. Halt only for the explicit Section 10 stop conditions — and when you halt, record the blocker in the PR body or an Issue comment rather than waiting interactively for input.
337
+ > **Autonomy:** Do not stop to ask clarifying questions. For any ambiguity not covered by a Section 10 stop condition, choose the most reasonable option consistent with this brief, record the choice in the PR body at open, or in a PR comment after open, and continue. Halt only for the explicit Section 10 stop conditions — and when you halt, record the blocker in a PR comment or an Issue comment rather than waiting interactively for input.
326
338
 
327
339
  This clause is what makes a dispatched agent run to completion unattended instead of pausing for input it can resolve itself. It removes the *low-value* check-ins; it does **not** suppress the §10 stop conditions, which remain the genuine escalations (a contradicted boundary, an under-specified format, a hit stop-and-escalate trap) and must still halt the agent. The line it draws: resolve-and-record for everything inside the brief's discretion; halt-and-record for the §10 conditions; never pause interactively for a question the brief already answers or the Developer is empowered to decide.
328
340
 
@@ -332,15 +344,14 @@ This clause is what makes a dispatched agent run to completion unattended instea
332
344
 
333
345
  What the executor opens/commits/creates at the end:
334
346
  - PR title (exact format)
335
- - **The brief pasted into the PR body**plus the `Tier:` declaration (`Tier: 0|1|3`) and the `Closes #N` reference to the task's Issue (so the merge auto-closes it). The `Ticket:`/`Project:` lines (if present) ride into the PR body too.
336
- - **The reference copy is wrapped in a collapsed `<details>` block — standing convention.** The PR body's *report half* (start from `aeg-root/templates/pr-report-template.md`) carries the real gate-read fields in their anchored homes; the brief rides below it inside `<details><summary>…</summary>…</details>`, collapsed by default, so the brief's own `Tier:` / Test Plan / `Closes` text can never be mistaken — visually or mechanically — for the PR's real fields. A `<details>` block hides nothing from the raw body, so provenance/archival tooling that greps the full PR body still finds the complete brief text.
347
+ - **The brief lands as a PR comment, not in the posted body — standing convention.** Paste the brief exactly as before, into the `## Reference — the dispatched brief` section (start from `aeg-root/templates/pr-report-template.md`), wrapped in its `<!-- aeg:brief:start -->` / `<!-- aeg:brief:end -->` markers. `vinaya pr create` splits that section OUT before the body ever reaches the forge: it posts the marked content, verbatim, as its own comment marked `<!-- aeg:brief -->`, once, at open, and sends everything before the markers as the actual PR body — no `<details>` block, no reference copy riding along in the body itself. This keeps the brief's own `Tier:` / Test Plan / `Closes` text out of the region any gate scans, and out of the body's byte count; provenance/archival tooling that once greped the full PR body for the brief now reads that comment.
337
348
  - Files modified (`git diff main --stat`)
338
349
  - PR description sections required
339
350
  - What to report back and in what format
340
351
 
341
352
  **Pre-PR gate (inherited by every brief):** The Deliverable section must instruct the executor to, before opening: confirm the brief's own tier checklist is genuinely satisfied, and run `vinaya check doc-coverage` locally with `PR_BODY` set to the intended PR body — and fix any failure from either. Never dispatch a brief that would open a PR failing either. **On this repo's toolchain**, `bun packages/aeg-core/bin/verify-docs.ts --pr` runs both as one composite command.
342
353
 
343
- **The PR is not "done" when opened — it is done when it has passed review AND verification.** After the PR opens (`process.md`): **Phase 10 — Review:** code-reviewer pass (independent, fresh context, `roles/reviewer.md`) → security pass (`roles/security.md`, runs the config-security scan if agent/MCP config changed) → Principal code review → Brief Author spec review. **Phase 11 — Verification (`roles/developer.md` § Verification):** the brief's §9 Test Plan is executed — the Developer-agent runs every `[agent]` item and posts the actual output as evidence; the Principal ticks every `[principal]` box in a real browser. **Phase 12 — Merge:** the Principal merges once both halves are ticked. The brief ends by telling the Developer to open the PR and stop — the review passes and the Verification phase are separate invocations; the Developer addresses REQUEST CHANGES / FAIL findings and re-runs `[agent]` items in follow-up commits on the same branch.
354
+ **The PR is not "done" when opened — it is done when it has passed review AND verification.** After the PR opens (`process.md`): **Phase 10 — Review:** code-reviewer pass (independent, fresh context, `roles/reviewer.md`) → security pass (`roles/security.md`, runs the config-security scan if agent/MCP config changed) → Principal code review → Brief Author spec review. **Phase 11 — Verification (`roles/developer.md` § Verification):** the brief's §9 Test Plan is executed — `vinaya pr report` runs every command in the fenced `[agent]` list from the PR head and writes the actual output into `AEG:EVIDENCE`; the Principal ticks every `[principal]` box in a real browser. **Phase 12 — Merge:** the Principal merges once both halves are satisfied. The brief ends by telling the Developer to open the PR and stop — the review passes and the Verification phase are separate invocations; the Developer addresses REQUEST CHANGES / FAIL findings in follow-up commits on the same branch and re-runs `vinaya pr report --push <n>` to refresh the Evidence block, posting each round's response as a PR comment, never as a body section.
344
355
 
345
356
  ---
346
357
 
@@ -360,7 +371,7 @@ The brief MUST declare which agent/model runs the task **and why**. The planner
360
371
  | Cross-cutting review (reads many files, judges correctness) | a high-capability model |
361
372
  | Code review / security review pass | judgment over speed — a high/mid model |
362
373
 
363
- When an automation layer dispatches, it passes the model through; the brief can override per its own mechanism if needed. *(In this repo the model tiers are Opus / Sonnet / Haiku — substitute your provider's equivalents.)*
374
+ When an automation layer dispatches, it passes the model through; the brief can override per its own mechanism if needed. *(In this repo the model tiers run high/mid/low-capability, in your provider's own naming — substitute your provider's equivalents.)*
364
375
 
365
376
  ---
366
377
 
@@ -461,7 +472,7 @@ Source: GitHub Spec Kit evaluation, May 12, 2026. Adopted as inline convention o
461
472
  - ❌ **Telling the executor to delete or rename a shared symbol without first finding every importer** — if an importer is out-of-surface, "delete X" and "don't touch that file" contradict, and the executor is forced to break code or disobey. Run the §4 shared-symbol importer check; defer the deletion to the task that owns the out-of-surface importer.
462
473
  - ❌ Omitting the Technical Dependencies section — the executor discovers mid-task that something it needs doesn't exist yet
463
474
  - ❌ Omitting the Technical Surface Map — "only expected files changed" becomes uncheckable and scope creeps
464
- - ❌ A `For:`/`Reason:` line with no real reasoning ("Sonnet because it's good") — the capability choice must be justified against the task
475
+ - ❌ A `For:`/`Reason:` line with no real reasoning ("this model because it's good") — the capability choice must be justified against the task
465
476
  - ❌ Dropping a blast-radius consumer from verification — a shared-package change ships a regression in a consumer nobody re-checked
466
477
  - ❌ Omitting the worktree-first Step 0 — the executor starts on the wrong branch or a dirty main checkout
467
478
  - ❌ Telling the executor to "create a branch" without first creating a worktree
@@ -473,9 +484,9 @@ Source: GitHub Spec Kit evaluation, May 12, 2026. Adopted as inline convention o
473
484
  - ❌ Instructing the executor to write status anywhere — status is derived from the forge
474
485
  - ❌ Omitting the standing autonomy clause (§11) — the agent pauses for input it could resolve itself, defeating unattended dispatch; or, the inverse, writing a clause so broad it tells the agent to push past the §10 stop conditions (those must still halt it)
475
486
  - ❌ **Omitting the Test Plan (§9)** — Verification has nothing to run; runtime verification falls through the gap between agent and Principal — exactly the regression this section exists to remove
476
- - ❌ **Test Plan items with no tag** — `[agent]` vs `[principal]` is the whole shape of the gate; an untagged item cannot be routed to the actor who can run it
487
+ - ❌ **A checkbox `[agent]` item on a new brief** — the `[agent]` half is a fenced command list (task 12); `brief-shape` refuses a checkbox `[agent]` item on a PR at or above the rollout constant
477
488
  - ❌ **`Test Plan: unit-tests-only` on a brief whose §4 surface includes a runtime path** — the two fields are coupled; declaring `unit-tests-only` while listing API routes or pages in §4 is malformed (Brief Validation rejects it)
478
- - ❌ **Mis-tagging a `[principal]` item as `[agent]` to make the agent half complete** — the asymmetry is structural (auth, BYOK keys, eyes-on-a-render); reclassifying loses the gate's whole point
489
+ - ❌ **Putting an auth-gated or vendor-key-dependent check in the fenced `[agent]` list to make the agent half complete** — the asymmetry is structural (auth, BYOK keys, eyes-on-a-render); it belongs in `[principal]` instead, and misplacing it loses the gate's whole point
479
490
  - ❌ **A Test Plan item phrased as a property rather than an observation** — "the audit works" is not a test plan item; the named command + the named observable is
480
491
  - ❌ Not specifying stop conditions — the executor improvises when it should ask
481
492
  - ❌ Conflating what with how — specify BOTH
@@ -489,6 +500,7 @@ Source: GitHub Spec Kit evaluation, May 12, 2026. Adopted as inline convention o
489
500
  - ~~❌ **Authoring a brief for a task whose prior task doesn't pass the coherence gate**~~ — **SUPERSEDED .** This is no longer an anti-pattern; a prior task's archival state (Issue/PR/provenance) no longer blocks authoring or dispatching a brief. Preserved as historical record only.
490
501
  - ❌ **A brief with a real §4 code surface and no `Premise:` block, or a `Premise:` block whose assertions all pin unrelated paths** — `checkPremiseCoverage` rejects it; the whole point of the pin is that it covers the surface the brief's reasoning depends on
491
502
  - ❌ **Instructing the executor (or a §7 doc-update list) to commit a new file for a one-off report, audit finding, coverage summary, or working brief** — that content's permanent home is the PR body or an Issue/PR comment, never a new repo file (`tranche-model.md` §9 rule 4). A brief that tells the Developer "write your findings to `aeg-root/tranches/<name>-audit.md`" is malformed in exactly the way a brief that puts itself in the Issue instead of the PR body is malformed — it invents an unsanctioned new home for content the model already gave a home to (PR body, or an Issue/PR comment).
503
+ - ❌ **Stating a behavioural fact about code as prose instead of a `Premise:` pin or a fenced command with executed output** — a live brief once instructed "State that `vinaya review post` enforces the BLOCKER-plus-APPROVE contradiction and nothing else," which the Developer transcribed faithfully into doctrine; the command enforced three things, not one, and a reviewer proved the sentence false against the code. Nothing had verified the sentence before it was written. The fix was always available: "run `grep -n refuse apps/cli/src/commands/review-post.ts`, read every hit, and write doctrine from what the hits say."
492
504
 
493
505
  ---
494
506