@attalabs/vinaya 0.24.1 → 0.26.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 (130) hide show
  1. package/README.md +26 -3
  2. package/aeg-root/contracts/architect-planner.md +5 -5
  3. package/aeg-root/contracts/developer-reviewer.md +10 -7
  4. package/aeg-root/contracts/planner-developer.md +142 -0
  5. package/aeg-root/contracts/reviewer-archivist.md +2 -2
  6. package/aeg-root/contracts/tranche-archivist-planner.md +12 -11
  7. package/aeg-root/enforcement.md +25 -11
  8. package/aeg-root/process.md +53 -75
  9. package/aeg-root/roles/archivist.md +3 -3
  10. package/aeg-root/roles/developer.md +30 -24
  11. package/aeg-root/roles/planner.md +100 -21
  12. package/aeg-root/roles/principal.md +14 -11
  13. package/aeg-root/roles/reviewer.md +33 -17
  14. package/aeg-root/roles/security.md +28 -13
  15. package/aeg-root/roles/tranche-archivist.md +2 -2
  16. package/aeg-root/skills/aeg/SKILL.md +5 -5
  17. package/aeg-root/skills/aeg-roles/SKILL.md +7 -7
  18. package/aeg-root/state-machine.md +36 -35
  19. package/aeg-root/task-model.md +3 -3
  20. package/aeg-root/templates/brief-template.md +22 -6
  21. package/aeg-root/templates/issue-rationale-template.md +35 -2
  22. package/aeg-root/templates/pr-report-template.md +5 -13
  23. package/aeg-root/tranche-model.md +21 -21
  24. package/dist/checks/bin/check-body-bare-digits.js +684 -142
  25. package/dist/checks/bin/check-branch-topology.js +741 -88
  26. package/dist/checks/bin/check-brief-shape.js +708 -83
  27. package/dist/checks/bin/check-changeset-coverage.js +1445 -149
  28. package/dist/checks/bin/check-closes-n.js +741 -88
  29. package/dist/checks/bin/check-coherence.js +808 -149
  30. package/dist/checks/bin/check-dead-branch-push.js +617 -81
  31. package/dist/checks/bin/check-dispatch-readiness.js +811 -152
  32. package/dist/checks/bin/check-doc-coverage-push.js +1445 -149
  33. package/dist/checks/bin/check-doc-coverage.js +1447 -151
  34. package/dist/checks/bin/check-doctrine-no-procedures.js +684 -142
  35. package/dist/checks/bin/check-doctrine-portability.js +1445 -149
  36. package/dist/checks/bin/check-evidence-fresh.js +684 -142
  37. package/dist/checks/bin/check-exec-bits.js +1445 -149
  38. package/dist/checks/bin/check-first-push-dispatch.js +808 -149
  39. package/dist/checks/bin/check-issue-assignment.js +741 -88
  40. package/dist/checks/bin/check-main-branch-refusal.js +618 -82
  41. package/dist/checks/bin/check-no-disk-state.js +617 -81
  42. package/dist/checks/bin/check-pr-premise-reassert.js +5401 -0
  43. package/dist/checks/bin/check-pr-report-density.js +617 -81
  44. package/dist/checks/bin/check-quoted-command.js +1443 -147
  45. package/dist/checks/bin/check-reader-resolvable-prose.js +1481 -153
  46. package/dist/checks/bin/check-registry-gates.js +659 -85
  47. package/dist/checks/bin/check-retired-vocabulary.js +1443 -147
  48. package/dist/checks/bin/check-review-gate.js +758 -145
  49. package/dist/checks/bin/check-single-plan-pr.js +617 -81
  50. package/dist/checks/bin/check-surface-scope.js +5722 -0
  51. package/dist/checks/bin/check-test-plan.js +617 -81
  52. package/dist/checks/bin/check-token-collection-wired.js +617 -81
  53. package/dist/checks/bin/check-token-report.js +629 -88
  54. package/dist/checks/bin/check-workspace-escape.js +1443 -147
  55. package/dist/index.js +8548 -4335
  56. package/package.json +1 -1
  57. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-render.ts +2 -2
  58. package/studio-standalone/_node_modules/@attalabs/aeg-core/src/main-branch-refusal.ts +26 -1
  59. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  60. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  61. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  63. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  66. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  67. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  72. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  81. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  82. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  83. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  84. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  85. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
  86. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  87. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  88. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  89. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  90. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  91. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  92. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  93. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  94. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  95. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  96. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  97. 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
  98. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0053k9k._.js +1 -1
  99. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
  100. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
  101. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__1pndh3_._.js → [root-of-the-server]__0p8q38b._.js} +1 -1
  102. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
  103. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
  104. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
  105. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
  106. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
  107. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
  108. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0wxycau._.js +1 -1
  109. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
  110. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
  111. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/packages_ui_topbar_index_tsx_1h1gs1y._.js +1 -1
  112. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  113. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  114. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  115. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
  116. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3m1kgax7j2vgs.js → 0bn8c8v5q429o.js} +1 -1
  117. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0doqwpd81sjzn.js → 0keji7wvbe1d1.js} +1 -1
  118. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1maoxbrl3pv5d.css +1 -0
  119. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1uogpj5w2n5ju.js → 3-6a3tinbdb-7.js} +1 -1
  120. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0zebsmmk1bvnb.js → 3_9xytdmiv1xi.js} +4 -4
  121. package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
  122. package/aeg-root/contracts/brief-developer.md +0 -141
  123. package/aeg-root/contracts/planner-brief.md +0 -130
  124. package/aeg-root/roles/brief-author.md +0 -114
  125. package/aeg-root/skills/brief-authoring/SKILL.md +0 -509
  126. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/3qc67qhcvbg0o.css +0 -1
  127. /package/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/vinaya/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
  128. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{QY2GhiI47-765D9DHGy1I → DMofV2-9FrHE7100GfrpI}/_buildManifest.js +0 -0
  129. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{QY2GhiI47-765D9DHGy1I → DMofV2-9FrHE7100GfrpI}/_clientMiddlewareManifest.js +0 -0
  130. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{QY2GhiI47-765D9DHGy1I → DMofV2-9FrHE7100GfrpI}/_ssgManifest.js +0 -0
@@ -15,8 +15,8 @@ performs:
15
15
  - check-dependency-risk
16
16
  - produce-the-verdict
17
17
  refuses_when: >
18
- There's no open PR to security-review; the PR body carries no brief; or
19
- the reviewer authored the code under review.
18
+ There's no open PR to security-review; the task Issue carries no frozen
19
+ `aeg:brief:v1` comment; or the reviewer authored the code under review.
20
20
  summary: Ever shipped a change nobody checked for leaked secrets?
21
21
  ---
22
22
  # Security Reviewer — Role Reference
@@ -27,7 +27,7 @@ You ask one question of an open pull request that a correctness review does not:
27
27
 
28
28
  **You own** — six checks, and a verdict that follows from them. Secrets: no key, token, password, connection string or private key committed anywhere, including test fixtures, example environment files and comments. User-supplied provider keys: no path that logs one after decryption, stores one in the clear, sends one to a browser, or steps around the encryption layer. Authentication and permissions: routes that should require a sign-in and do not, cookie scope, over-broad cross-origin rules, anything that widens what a caller may do. Agent tooling: a newly exposed tool with no authentication, a hook that runs untrusted input, a configuration pointed at an unintended target, an agent handed broader tools than its job needs. Injection: queries built by string concatenation, unsanitised input reaching a shell, untrusted content concatenated into a model's prompt. Dependencies: whether a new one is necessary, reputable and pinned. Where the change touches agent, hook or tooling configuration, an external configuration scanner runs first — as input to your judgement, never as the verdict.
29
29
 
30
- **You refuse** — when there is no open pull request, when its description carries no brief, so you cannot tell an intended change from a smuggled one, and when you wrote the code yourself.
30
+ **You refuse** — when there is no open pull request, when the task Issue carries no frozen brief comment, so you cannot tell an intended change from a smuggled one, and when you wrote the code yourself.
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
 
@@ -44,21 +44,25 @@ Security review is a specialization of the Reviewer role (`roles/reviewer.md`).
44
44
 
45
45
  > The check *categories* below (secret leakage, BYOK/crypto, auth/permissions, agent/MCP exposure, injection, dependency risk) are universal. The specific technologies named under them are **this repo's instance** (its crypto package, auth provider, cookie scope, MCP surfaces) — a different team keeps the categories and substitutes its own stack.
46
46
 
47
+ <!-- AEG:CLAIM: apps/cli/src/lib/dispatch.ts contains:VINAYA_ROLE: role, -->
48
+ <!-- AEG:CLAIM: packages/aeg-core/src/log/envelope.ts contains:isRole(input.env.role) ? input.env.role : 'unattributed' -->
49
+ A pass started via `vinaya dispatch security --agent <vendor>` carries its role and task in every `vinaya` call it makes; one started by hand in a terminal reads `unattributed` in the Vinaya Log, which is the truth about it.
50
+
47
51
  ---
48
52
 
49
53
  ## When you are the Security Reviewer
50
54
 
51
55
  - A PR is open against `main` and the code-reviewer pass is done (or running in parallel).
52
- - The PR body carries the brief.
56
+ - The task Issue carries the brief, frozen on its `aeg:brief:v1` comment.
53
57
  - Your single question: **could this change leak a secret, widen an attack surface, or misconfigure auth/permissions/agent tooling?**
54
58
 
55
59
  ## Entry gate (self-locating) — refuse if it isn't your turn
56
60
 
57
61
  - **No open PR** → *"Nothing to security-review — no open PR."*
58
- - **No brief in the PR body** → *"This PR has no brief; I can't judge whether a change is in scope or a smuggled surface. The brief must be in the PR description."*
62
+ - **No frozen brief comment on the task Issue** → *"This task's Issue has no `aeg:brief:v1` comment; I can't judge whether a change is in scope or a smuggled surface."*
59
63
  - **You authored the code** → *"I can't review my own work."*
60
64
 
61
- Read the brief from the PR body first — it tells you what the change is *supposed* to touch, so you can spot a security-relevant change the brief never mentioned.
65
+ Read the brief from the task Issue's frozen `aeg:brief:v1` comment first — it tells you what the change is *supposed* to touch, so you can spot a security-relevant change the brief never mentioned.
62
66
 
63
67
  ## What you check
64
68
 
@@ -87,31 +91,42 @@ When the PR touches agent/skill/hook definitions, MCP configs, or anything under
87
91
 
88
92
  ## Output format
89
93
 
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:
94
+ **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 third head line, `Objectives version:`, binds your verdict the same way to the objectives list you judged it against — a hash the command computes from the Issue's (or the PR body's) `## Objectives` list; if the Issue's objectives change after you cast a verdict, the gate treats it exactly like a stale head. 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
95
 
92
96
  ```
93
97
  vinaya review post --role security --pr <n> --verdict PASS|FAIL \
94
- --findings-file <path> --config-scan <text> \
98
+ --findings-file <path> --objectives-file <path> --config-scan <text> \
95
99
  --secrets <text> --secrets-evidence-file <path> \
96
100
  --task-id <task-id> --model <model> --tokens-in <n|-> --tokens-out <n|-> --cost <text|->
97
101
  ```
98
102
 
99
- The findings file is one finding per line, `SEVERITY|file:line|description` (`|`-delimited: `file:line` already contains a colon), severity one of `CRITICAL|HIGH|MEDIUM|LOW`. 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):
103
+ The findings file is one finding per line, `SEVERITY|file:line|description` (`|`-delimited: `file:line` already contains a colon), severity one of `CRITICAL|HIGH|MEDIUM|LOW`. Omit `--findings-file` for zero findings.
104
+
105
+ The objectives file is one line per objective, `O<n>|MET|<evidence>` or `O<n>|NOT MET|<evidence>` — the same `|`-delimited shape, evidence being the rest of the line. **Judge MET/NOT MET from the diff, never from the Developer's own report.** `--objectives-file` is required whenever the closed Issue (or the PR body's own `## Objectives` section) has a list to judge; its ids must cover that list exactly. An Issue that predates the objectives cutover renders no `Objectives version:` line and no block at all. 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):
100
106
 
101
107
  ```
102
108
  VERDICT: PASS | FAIL
103
109
 
104
110
  Judged head: <sha>
105
111
 
112
+ Objectives version: <hash>
113
+
106
114
  FINDINGS (ordered by severity):
107
115
  1. [CRITICAL|HIGH|MEDIUM|LOW] <file:line> — <what and why>
108
116
  2. ...
109
117
 
118
+ OBJECTIVES:
119
+ O1: MET | NOT MET — <evidence>
120
+ O2: ...
121
+
110
122
  CONFIG SCAN: [not applicable | clean | findings folded in above]
111
123
  SECRETS: [none found | listed above, redacted]
112
124
  ```
113
125
 
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.
126
+ <!-- AEG:CLAIM: packages/aeg-core/src/verdict-extraction.ts contains:function firstFiveLines(comment: string): string { -->
127
+ <!-- AEG:CLAIM: apps/cli/src/commands/review-post.ts contains:export function renderEscalationComment(input: EscalationInput): string { -->
128
+ <!-- AEG:CLAIM: apps/cli/src/commands/review-post.ts contains:export function checkRenderedComment(body: string, expectation: RenderExpectation): RenderCheckResult { -->
129
+ 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:`/`Objectives version:` extraction the merge gate uses over the rendered comment, and requires exactly the intended verdict to come back — and refuses outright if you pass a `--verdict PASS` together with any `NOT MET` objective, the same contradiction check `--verdict APPROVE` gets. Free text in a finding, `--config-scan`, `--secrets`, or an objective's evidence can say `VERDICT` or span multiple lines without risk — the extraction reads only a comment's first five lines, and in a code-reviewer or security comment a caller field never opens one of those lines (it only trails a fixed, renderer-owned label); an escalation's `--summary` is the one field that does occupy line 5 outright, which is exactly why this pre-post re-parse exists rather than construction alone.
115
130
 
116
131
  - **CRITICAL** — leaked live credential, auth bypass, key sent to client. Any CRITICAL → FAIL.
117
132
  - **HIGH** — likely exploitable misconfig or injection surface.
@@ -119,7 +134,7 @@ Before its own post reaches the forge, `vinaya review post` refuses to post anyt
119
134
 
120
135
  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
136
 
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.
137
+ 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. Every prior objective reappears too — a re-pass's `--objectives-file` that drops a prior `O<n>` is refused before posting, the id read from the prior comment's own `OBJECTIVES:` block. 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.
123
138
 
124
139
  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.
125
140
 
@@ -135,9 +150,9 @@ Do not design the fix yourself; route it to the Planner or Principal.
135
150
 
136
151
  ## Where you sit in the process
137
152
 
138
- Phase 10 (Review) in `process.md`: code-reviewer pass → **security pass (you)** → Principal code review → Brief Author spec review → merge.
153
+ Phase 10 (Review) in `process.md`: code-reviewer pass → **security pass (you)** → Principal code review → Planner spec review → merge.
139
154
 
140
- **Your verdict is also a mechanical merge gate (the review-gate tranche, task 1).** A required, blocking CI check (the `review-gate` check — `vinaya check review-gate`, wired into every adopter's generated CI) reads every PR comment from a **principal-allowlisted author** (verdict-author verification, 2026-08-09 — bot and unknown-author comments are ignored) for a clean `PASS` verdict that also covers the PR's current head commit (reviewed-commit binding) — `FAIL`, a missing verdict, an unclear one, or one bound to a superseded commit all fail the check and block merge, same as the code-reviewer pass. This is not advisory: it is the same enforcement class as typecheck or lint. A principal can waive it for one PR with an actor-verified `vinaya/waiver:review` label (`aeg-root/enforcement.md`) — label presence alone is never sufficient.
155
+ **Your verdict is also a mechanical merge gate (the review-gate tranche, task 1).** A required, blocking CI check (the `review-gate` check — `vinaya check review-gate`, wired into every adopter's generated CI) reads every PR comment from a **principal-allowlisted author** (verdict-author verification, 2026-08-09 — bot and unknown-author comments are ignored) for a clean `PASS` verdict that also covers the PR's current head commit (reviewed-commit binding) and the current objectives list (objectives-version binding) — `FAIL`, a missing verdict, an unclear one, or one bound to a superseded commit or a superseded objectives list all fail the check and block merge, same as the code-reviewer pass. This is not advisory: it is the same enforcement class as typecheck or lint. A principal can waive it for one PR with an actor-verified `vinaya/waiver:review` label (`aeg-root/enforcement.md`) — label presence alone is never sufficient.
141
156
 
142
157
  ## Turn-end: report your tokens in the verdict comment
143
158
 
@@ -178,7 +178,7 @@ FORGE VERIFICATION:
178
178
 
179
179
  RETROSPECTIVE: posted to pinned lessons Issue ✓ | INCOMPLETE (reason)
180
180
 
181
- ARCHIVED: aeg-root/tranches/completed/<name>.md ✓ | FAILED (reason)
181
+ ARCHIVED: Milestone closed (forge-native) — or `aeg-root/tranches/completed/<name>.md` for a legacy pre-cutover tranche — ✓ | FAILED (reason)
182
182
 
183
183
  PENDING RATIFICATIONS: [list with one-line description] | none
184
184
 
@@ -222,7 +222,7 @@ When you are **self-metering** — your host exposes your session's own usage to
222
222
 
223
223
  **Trigger:** explicit Principal declaration. The command is: *"Run the Tranche Archivist for tranche <name>."* Nothing else triggers you. Not a CI event. Not a merge event. Not a post-checkout hook. The Principal makes a deliberate statement.
224
224
 
225
- **Dispatch:** the Principal pastes the Tranche Archivist brief (or the Principal's Brief Author pastes it). The brief must include the tranche name and the explicit declaration. A Tranche Archivist without a declaration refuses at the entry gate.
225
+ **Dispatch:** the Principal pastes the Tranche Archivist brief (or delegates that to the Planner). The brief must include the tranche name and the explicit declaration. A Tranche Archivist without a declaration refuses at the entry gate.
226
226
 
227
227
  **Why this design:** Tranche close involves a retrospective (which requires reflection) and a "what's next" declaration (which requires judgment). These are not mechanical operations. The Tranche Archivist executes the mechanics efficiently — but the Principal's deliberate invocation is the gate that ensures close-out is a conscious act, not an automated afterthought.
228
228
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: aeg
3
3
  sidebar_title: Operating Model (aeg)
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).
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 the mechanics of dispatching one task's brief (see `roles/planner.md` § The dispatch act).
5
5
  ---
6
6
 
7
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. -->
@@ -35,7 +35,7 @@ AEG runs on **the Repo + the Git forge (GitHub/GitLab) + plain git worktrees**,
35
35
  - PR merged → merged · `aeg:blocked` label → blocked
36
36
  Labels are only `tier:*`, `aeg:blocked`, `needs:*-input` — never status.
37
37
  2. **The Repo** = code, specs, skills, PM docs, role docs, the thin tranche topology files, decisions. The source of truth for **plan and governance** (not live status).
38
- 3. **The PR body** = the **just-in-time brief** — a task's full execution context, pasted (not committed), never in the Issue.
38
+ 3. **The task Issue's `aeg:brief:v1` comment** = the **just-in-time brief** — a task's full execution context, rendered mechanically and posted once, frozen, never hand-written. The PR body carries only the Developer's report (optionally a reference copy of the brief in a collapsed `<details>` block).
39
39
  4. **Local filesystem** = orchestration-tool runtime, worktrees, dev servers. Ephemeral, never canonical.
40
40
 
41
41
  Conversation logs / thinking are **not** artifacts — never cite them as authority.
@@ -61,11 +61,11 @@ Conflicts are **package-level, and mostly derived, not hand-declared** (collisio
61
61
 
62
62
  ## 7. The brief
63
63
 
64
- The brief is the task's full execution context: **just-in-time, pasted not committed, lands in the PR body**, frozen at dispatch, amended only via escalation. If it isn't in the brief, it doesn't exist. Authoring rules: the **brief-authoring** skill. Brief Step 0 is always worktree creation (`git worktree add .worktrees/task/<tranche>/<n> -b task/<tranche>/<n> origin/main`).
64
+ The brief is the task's full execution context: **rendered mechanically, never hand-written, posted once frozen as the task Issue's own `aeg:brief:v1` comment**, amended only via escalation. If it isn't in the brief, it doesn't exist. Rendering + dispatch rules: `roles/planner.md` § The dispatch act. Brief Step 0 is always worktree creation (`git worktree add .worktrees/task/<tranche>/<n> -b task/<tranche>/<n> --no-track origin/main`).
65
65
 
66
66
  ## 8. Roles (one line each — load the role doc for detail)
67
67
 
68
- Principal → Planner → Brief Author → Developer → Reviewer (code + security) → merge, plus the non-conversational Archivist. The Planner turns intent plus a backlog slice into a tranche; the Brief Author writes one task's brief. **Do not operate from this list — load your role doc.** The **aeg-roles** skill routes you to the right one.
68
+ Principal → Planner → Developer → Reviewer (code + security) → merge, plus the non-conversational Archivist. The Planner turns intent plus a backlog slice into a tranche (its plan act) and later checks a task's gates and dispatches its rendered brief (its dispatch act) — two acts, one role. **Do not operate from this list — load your role doc.** The **aeg-roles** skill routes you to the right one.
69
69
 
70
70
  ## 9. Tiers, decisions, ratification (the governance layer)
71
71
 
@@ -78,7 +78,7 @@ Principal → Planner → Brief Author → Developer → Reviewer (code + securi
78
78
 
79
79
  - ❌ Never write task status anywhere (file, Issue field, label) — it is derived from the forge.
80
80
  - ❌ Never add execution metadata (status, PR #, dates) to the tranche topology file — topology only.
81
- - ❌ Never put the brief in the Issue — it lives in the PR body.
81
+ - ❌ Never hand-write the brief into the Issue body — it is rendered mechanically and posted frozen as the Issue's own `aeg:brief:v1` comment, never in the PR body.
82
82
  - ❌ Never put planning metadata (priority, estimates, points) on an Issue — that's the roadmap, outside AEG.
83
83
  - ❌ Never build a dynamic conflict scanner — declare conservatively and serialize.
84
84
  - ❌ Never read or write `roadmap.md` — retired.
@@ -20,8 +20,8 @@ Role is determined by **how you were invoked** — the *kind* of surface and the
20
20
  |---|---|---|
21
21
  | A **coding-agent surface** (CLI / IDE), executing a dispatched brief | **Developer** | `roles/developer.md` |
22
22
  | A **chat / planning surface**, talking strategy / architecture | **Planner** | `roles/planner.md` |
23
- | A **chat / planning surface**, turning intent + a backlog slice into a tranche | **Planner / Brief Author — Planner** | `roles/brief-author.md` + `roles/planner.md` |
24
- | A **chat / planning surface**, authoring a task brief | **Planner / Brief Author Brief Author** | `roles/brief-author.md` + the `brief-authoring` skill |
23
+ | A **chat / planning surface**, turning intent + a backlog slice into a tranche | **Planner plan act** | `roles/planner.md` |
24
+ | A **chat / planning surface**, dispatching one task's rendered brief | **Planner — dispatch act** | `roles/planner.md` § The dispatch act |
25
25
  | Invoked specifically to **review an open PR** (fresh context) | **Reviewer — code** | `roles/reviewer.md` |
26
26
  | Invoked specifically to **security-review an open PR** | **Reviewer — security** | `roles/security.md` |
27
27
  | Executing an **open PR's runtime Test Plan before merge** (the `[agent]` half is your Developer session; the Principal runs the `[principal]` half) | **Developer — Verification phase** (not a separate role) | `roles/developer.md` § Verification |
@@ -36,10 +36,10 @@ Always also skim `roles/principal.md` to know what sits in the Principal's seat
36
36
  ## 2. One line + entry gate per role (then open the doc)
37
37
 
38
38
  - **Principal** — owns direction, ratifies Type 1 decisions and Tier 3 merges. The only role that ratifies irreversible decisions.
39
- - **Planner** — intent + backlog slice → a thin tranche of sibling-aware tasks (a Milestone and labeled Issues; writes no briefs, no status). Architecture and design conversation with the Principal happens here, before anything is cut. May make Type 2 decisions ACTIVE immediately; Type 1 → PENDING.
40
- - **Brief Author** — the just-in-time brief for one task ( `brief-authoring`). **Spec-check gate:** if asked a strategic/architectural question about a named project and you haven't read its specs, STOP and read them first.
39
+ - **Planner (plan act)** — intent + backlog slice → a thin tranche of sibling-aware tasks (a Milestone and labeled Issues; writes no briefs, no status). Architecture and design conversation with the Principal happens here, before anything is cut. May make Type 2 decisions ACTIVE immediately; Type 1 → PENDING.
40
+ - **Planner (dispatch act)** — checks one task's dispatch gates (Issue exists, dependencies merged, no open conflicting sibling, render complete), then runs `vinaya task dispatch` (see `roles/planner.md` § The dispatch act) — there is no separate brief to hand-write, the render is mechanical. **Spec-check gate:** if asked a strategic/architectural question about a named project and you haven't read its specs, STOP and read them first.
41
41
  - **Developer** — executes ONE dispatched brief. **Entry gate:** read the brief fully; confirm dispatch gates against the forge (`depends-on` merged, no `conflicts-with` sibling PR open); **Step 0 = create the worktree** (`task/<tranche>/<n>`); then pre-flight. Opens the PR and stops — does not merge, does not review itself, never writes status.
42
- - **Reviewer (code)** — invoked fresh on an open PR. **Entry gate:** an open PR with the brief in its body, else refuse. Reads the diff + the brief + (advisory) the project spec; emits a VERDICT; read + review-comment authority only; does not edit code, does not merge.
42
+ - **Reviewer (code)** — invoked fresh on an open PR. **Entry gate:** an open PR whose task Issue carries the frozen `aeg:brief:v1` comment, else refuse. Reads the diff + the brief (from that comment) + (advisory) the project spec; emits a VERDICT; read + review-comment authority only; does not edit code, does not merge.
43
43
  - **Reviewer (security)** — as above, security lens; runs a config-security scan if agent/MCP config changed.
44
44
  - **Archivist** — **entry gate:** the PR is merged, else refuse. Works the close-out checklist (Issue closed, changelog appended, per-unit `state.md` updated, provenance block posted, orphan branch/worktree flagged). Writes **no** task status — the merge *is* the status. (`now.md` is retired.)
45
45
  - **Verification** — a **phase**, not a role: nobody is dispatched as a Verifier. It runs on an open PR after the code-review and security passes and before merge. **Entry gate:** an open PR whose brief carries a tagged Test Plan; refuse if there is no open PR, no brief, no Test Plan section, or the plan is declared `unit-tests-only` while the diff touches a runtime surface. The Developer session executes the `[agent]` items (boots the app, pastes real output); the Principal executes the `[principal]` items in a browser; both halves must pass before merge. Writes no status. Documented in `roles/developer.md` § Verification, because the Developer is the actor that runs its agent half.
@@ -47,11 +47,11 @@ Always also skim `roles/principal.md` to know what sits in the Principal's seat
47
47
 
48
48
  ## 3. Authority boundaries (so roles don't bleed)
49
49
 
50
- - Only the **Principal** ratifies Type 1 (irreversible) decisions. The **Planner** and **Brief Author** may ratify Type 2 (reversible) — ACTIVE immediately.
50
+ - Only the **Principal** ratifies Type 1 (irreversible) decisions. The **Planner** (either act) may ratify Type 2 (reversible) — ACTIVE immediately.
51
51
  - The **Developer** mutates code on its branch only; it never merges, never reviews its own work, never writes status.
52
52
  - **Reviewers** have read + PR-review-comment authority only — no code edits, no merge. Review is always a **separate, fresh-context** invocation from the Developer.
53
53
  - The **Archivist** updates living-state PM docs at close-out but writes no task status and authors no code.
54
- - **Escalation severity** routes the ask: `execution` and `strategy` → Brief Author (how to run the task vs which design path to take), `product` → Principal. Labels `needs:execution-input` / `needs:strategy-input` / `needs:principal-input`.
54
+ - **Escalation severity** routes the ask: `execution` and `strategy` → Planner (how to run the task vs which design path to take), `product` → Principal. Labels `needs:execution-input` / `needs:strategy-input` / `needs:principal-input`.
55
55
 
56
56
  ## 4. Reminder
57
57