@attalabs/vinaya 0.22.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.
- package/README.md +13 -3
- package/aeg-root/contracts/archivist-tranche-archivist.md +2 -2
- package/aeg-root/contracts/brief-developer.md +1 -0
- package/aeg-root/contracts/developer-reviewer.md +3 -3
- package/aeg-root/contracts/reviewer-archivist.md +3 -3
- package/aeg-root/enforcement.md +26 -20
- package/aeg-root/process.md +8 -4
- package/aeg-root/roles/archivist.md +2 -2
- package/aeg-root/roles/brief-author.md +9 -3
- package/aeg-root/roles/developer.md +63 -31
- package/aeg-root/roles/planner.md +1 -1
- package/aeg-root/roles/principal.md +14 -0
- package/aeg-root/roles/reviewer.md +32 -15
- package/aeg-root/roles/security.md +15 -5
- package/aeg-root/skills/aeg/SKILL.md +9 -5
- package/aeg-root/skills/aeg-roles/SKILL.md +2 -2
- package/aeg-root/skills/brief-authoring/SKILL.md +39 -27
- package/aeg-root/state-machine.md +9 -11
- package/aeg-root/templates/brief-template.md +6 -6
- package/aeg-root/templates/pr-report-template.md +10 -7
- package/aeg-root/tranche-model.md +6 -2
- package/dist/checks/bin/check-body-bare-digits.js +552 -139
- package/dist/checks/bin/check-branch-topology.js +603 -144
- package/dist/checks/bin/check-brief-shape.js +593 -142
- package/dist/checks/bin/check-changeset-coverage.js +935 -161
- package/dist/checks/bin/check-closes-n.js +603 -144
- package/dist/checks/bin/check-coherence.js +614 -147
- package/dist/checks/bin/check-dead-branch-push.js +552 -139
- package/dist/checks/bin/check-dispatch-readiness.js +612 -145
- package/dist/checks/bin/check-doc-coverage-push.js +689 -218
- package/dist/checks/bin/check-doc-coverage.js +689 -218
- package/dist/checks/bin/check-doctrine-no-procedures.js +4794 -0
- package/dist/checks/bin/check-doctrine-portability.js +684 -146
- package/dist/checks/bin/check-evidence-fresh.js +994 -174
- package/dist/checks/bin/check-exec-bits.js +4931 -0
- package/dist/checks/bin/check-first-push-dispatch.js +603 -144
- package/dist/checks/bin/check-issue-assignment.js +603 -144
- package/dist/checks/bin/check-main-branch-refusal.js +552 -139
- package/dist/checks/bin/check-no-disk-state.js +552 -139
- package/dist/checks/bin/check-pr-report-density.js +4461 -0
- package/dist/checks/bin/check-quoted-command.js +621 -155
- package/dist/checks/bin/check-reader-resolvable-prose.js +617 -154
- package/dist/checks/bin/check-registry-gates.js +595 -144
- package/dist/checks/bin/check-retired-vocabulary.js +617 -154
- package/dist/checks/bin/check-review-gate.js +670 -141
- package/dist/checks/bin/check-single-plan-pr.js +552 -139
- package/dist/checks/bin/check-test-plan.js +553 -140
- package/dist/checks/bin/check-token-collection-wired.js +552 -139
- package/dist/checks/bin/check-token-report.js +552 -139
- package/dist/checks/bin/check-workspace-escape.js +985 -145
- package/dist/index.js +8500 -5518
- package/package.json +1 -1
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/actions.ts +173 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/anchored-region.ts +113 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/archive-task.ts +206 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/baseline-capture.ts +65 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/blast-radius-domains.ts +192 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/branch-topology-gate.ts +85 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-validation.ts +511 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/claude-code-transcript.ts +460 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/coherence-checks.ts +787 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dead-branch-push-audit.ts +55 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dead-branch-push-guard.ts +77 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/derive-section7.ts +66 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/derive-tranche.ts +94 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/diagram-model.ts +372 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/direct-main-push.ts +39 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dispatch-gate.ts +224 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doc-owners.ts +314 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/build-doc-nav.ts +38 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/docs-coherence.ts +136 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/index.ts +29 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/legacy-anchors.ts +48 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/nav-helpers.ts +17 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/node-route.ts +134 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/parse-doc.ts +43 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/published-prose.ts +306 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/surfaced-manifest.ts +89 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/types.ts +33 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-portability.ts +170 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-source.ts +23 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/ensure-label.ts +28 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/file-classify.ts +51 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/first-push-dispatch-gate.ts +80 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/gate-audience.ts +168 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/index.ts +301 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/issue-assignment.ts +102 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/issue-validation.ts +746 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/leftover-detection.ts +68 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/local-anchor-coverage.ts +245 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/main-branch-refusal.ts +64 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/manifest-validity.ts +81 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/markdown-table.ts +76 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/metering-io-guard.ts +119 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/milestone-validation.ts +240 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/no-disk-state.ts +50 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-ledger.ts +77 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-registry.ts +105 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-token-report.ts +165 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-tranche.ts +183 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/pr-tier.ts +81 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/premise-check.ts +125 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/quoted-command.ts +275 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/reader-resolvable-prose.ts +320 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-checks.ts +255 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-parse.ts +164 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-scaffold.ts +216 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/report-tokens.ts +261 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/retired-vocabulary.ts +163 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/review-gate.ts +269 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/single-plan-pr.ts +73 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/state-machine-model.ts +269 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/state-source.ts +14 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/status-block.ts +8 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/sum-ledger.ts +26 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/symbol-collisions.ts +78 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-gate.ts +104 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-section.ts +65 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/types.ts +174 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/verdict-extraction.ts +140 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/vocabulary-citation.ts +114 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/waiver-label.ts +52 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/workspace-escape.ts +172 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__02a-3g8._.js +1 -1
- 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
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0053k9k._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__069-_41._.js → [root-of-the-server]__1mcitst._.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{37hnluhzj9bei.js → 0jer_drkl1e4r.js} +4 -4
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{267o-tsrnuwnv.js → 20x-t0a0v129z.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1hufpuody6vjv.js → 2ou_81ahqw31e.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
- /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
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{Fmyc42qzLwFcWWHLLNy-G → 5xy_GA7G5KRuE3HDumIiw}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{Fmyc42qzLwFcWWHLLNy-G → 5xy_GA7G5KRuE3HDumIiw}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{Fmyc42qzLwFcWWHLLNy-G → 5xy_GA7G5KRuE3HDumIiw}/_ssgManifest.js +0 -0
|
@@ -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.
|
|
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`
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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., "
|
|
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
|
-
|
|
277
|
+
The Test Plan splits in two, by who can structurally execute it:
|
|
269
278
|
|
|
270
|
-
- **`[agent]
|
|
271
|
-
- **`[principal]
|
|
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
|
-
|
|
286
|
-
-
|
|
287
|
-
|
|
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
|
|
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
|
|
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
|
|
298
|
-
- **
|
|
299
|
-
- **`[agent]`
|
|
300
|
-
- **The Principal cannot
|
|
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
|
|
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
|
|
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 —
|
|
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
|
|
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 ("
|
|
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
|
-
- ❌ **
|
|
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
|
-
- ❌ **
|
|
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
|
|
|
@@ -149,7 +149,7 @@ The Reviewer role has two specializations — code review (`roles/reviewer.md`)
|
|
|
149
149
|
- **Write:** PR review verdicts and review comments only (a Class 2 object) — **nothing to disk**. The verdict is the structured block in the role doc (`APPROVE | REQUEST CHANGES` for code, with a `SPEC CONFORMANCE` line; `PASS | FAIL` for security). A REQUEST CHANGES sets the PR's review decision, which is the derived `changes-requested` status — the Reviewer writes no status field. **Plus a one-line token report** in the same verdict comment — numeric cells `—` when the role is **operator-metered** — the host exposes no usage figure to the agent — which is the reviewing role's usual case and the one sanctioned reason for a blank token cell (`tranche-model.md` §12). The per-task Archivist reads this report and appends the ledger row (`tranches/<name>.tokens.md`) at close-out (§13 append-only artifacts; `tranche-model.md` §12).
|
|
150
150
|
- **Cannot:** edit code, specs, skills, PM docs; mutate labels; or merge. The Reviewer reports; the Developer remediates; the Principal merges.
|
|
151
151
|
- **Independence:** fresh context (a separate invocation), never reviewing work it authored. This is the whole point.
|
|
152
|
-
- **Escalation:** a
|
|
152
|
+
- **Escalation:** a concern that exceeds review authority is posted via `--escalate authority | strategy | product` — its own review outcome, never a finding — and routed to the Planner (`strategy`) or Principal (`authority`/`product`).
|
|
153
153
|
|
|
154
154
|
Because the Reviewer never mutates a canonical artifact, it has no column. Its position is Phase 10 (`process.md`): code-reviewer pass → security pass → Principal code review → Brief Author spec review → **Phase 11 Verification (`roles/developer.md` § Verification)** → merge.
|
|
155
155
|
|
|
@@ -233,7 +233,7 @@ When a Developer reaches a decision not covered by the brief, it escalates throu
|
|
|
233
233
|
|
|
234
234
|
**`severity: product`** — requires a Principal decision. Rare; reserved for Type 1 decisions discovered during execution. Adds `vinaya/needs:principal-input`. If the Principal is present, they decide and reply; if not, the item stays labeled `vinaya/needs:principal-input` and the Developer terminates, resuming via a follow-up dispatch after the window.
|
|
235
235
|
|
|
236
|
-
While blocked, the task carries a `vinaya/blocked` label (the one status with no native forge fact). The Reviewer
|
|
236
|
+
While blocked, the task carries a `vinaya/blocked` label (the one status with no native forge fact). The Reviewer's own `--escalate authority | strategy | product` outcome uses this same class vocabulary.
|
|
237
237
|
|
|
238
238
|
### Type 1 decisions during execution
|
|
239
239
|
|
|
@@ -305,11 +305,11 @@ The lowest-commitment way to run AEG: read-only over a team's existing process.
|
|
|
305
305
|
- **Typecheck, tests** — standard CI gates; always blocking.
|
|
306
306
|
- **Issue template / no forbidden fields** — a required Issue template + a CI check reject planning metadata (priority/estimates/points) on task Issues, keeping them execution-only.
|
|
307
307
|
- **Brief validation** — the Archivist's `brief-validation` job runs `packages/aeg-core/bin/verify-brief.ts` against the PR body and checks presence of every required brief section (Tier, `For:` model attribution, `Project:` — both read from the PR body's header block, before the first `##` heading, the same region the post-merge Archivist's provenance assembly reads — tagged Test Plan, surface map, doc-update list, worktree Step 0, stop conditions, autonomy clause, `Closes #N`); flags malformed briefs (`vinaya/needs:brief-correction`) and fails CI. **The trigger is the body, not the branch (`fix/brief-gate-nontask`):** the gate runs when the branch is `task/<tranche>/<n>` **or** the body is brief-shaped (`isBriefShaped` — ≥2 of surface map / doc-update list / stop conditions / autonomy clause, matched on `stripCode`'d text so a brief *quoted inside a fence* stays exempt). Bodies that are neither still bypass — that exemption is for an ordinary non-AEG PR (a one-line dependency bump) which carries no brief and must not be forced to grow one. The old branch-only bypass was the wrong proxy for it: a standalone `fix/*` brief **is** a brief, and it skipped every section check — confirmed live on `fix/studio-tranche-href`, which shipped with no §7 documentation-update list because `checkDocUpdateList`, the checker that exists for exactly that, never ran. `Closes #N` remains **task-branch-only** (`BriefSectionsOptions.requireClosesN`): a standalone fix brief has no task Issue to close, and a `plan/*` PR is *forbidden* to carry one by the plan-PR guard below — requiring it there would make the two gates jointly unsatisfiable. The same validator also runs at **authoring time** as the `brief-shape` check — `PR_BODY="$(cat brief.md)" vinaya check brief-shape` (on this repo's toolchain, also `bun packages/aeg-core/bin/verify-brief.ts --body-file <brief.md>`) — before a PR or even a branch exists, so a Brief Author gates a brief before dispatch rather than after the Developer has done the work (`skills/brief-authoring/SKILL.md` protocol step 4); with no `BRANCH`, the branch is read from the brief's own Step 0 `git worktree add … -b` line. **Includes the plan-PR Closes guard**: a `plan/*` branch whose PR body carries `Closes #N` fails CI before the non-task bypass even runs — a plan PR creates Issues, it does not resolve one (`roles/planner.md`); this closed a confirmed pattern of plan PRs prematurely closing task Issues on merge. **Real**, now the `Brief Validation` step (9/9) of the AEG gate suite job in `.github/workflows/forge-lifecycle.yml`. Presence-only — it cannot judge whether a Test Plan item is truly scriptable or whether a declared `unit-tests-only` is justified by the surface map; those remain Reviewer + Verification judgment. Same enforcement substrate as above.
|
|
308
|
-
- **Per-task Archivist close-out** — `.github/workflows/archivist.yml::post-merge` (`packages/aeg-core/bin/archive-task.ts`) runs on every push to `main`, resolves the merge commit's PR via `gh api repos/{owner}/{repo}/commits/{sha}/pulls`, and — for task-branch PRs only — assembles and posts the Archivist provenance block (`roles/archivist.md` item 8) and explicitly closes the task's Issue, confirming the closed state before exiting. Idempotent **per PR**, not per Issue (an Issue can legitimately accrue multiple merged PRs over its life; idempotency never spans PRs): skips silently if the PR already carries a provenance comment. Skips silently on non-task branches (`plan/*`, `fix/*`, …). Fails loud (non-zero exit) on any `gh`/permission error — never a silent no-op. Real, installed with `contents: read`, `issues: write`, `pull-requests: write` permissions. Does not automate the Tranche Archivist or items 2–7 of per-task close-out (docs coherence, `docs-index.md`, token ledger) — those remain dispatched-Archivist judgment work.
|
|
308
|
+
- **Per-task Archivist close-out** — `.github/workflows/vinaya-archivist.yml::post-merge` (`packages/aeg-core/bin/archive-task.ts`) runs on every push to `main`, resolves the merge commit's PR via `gh api repos/{owner}/{repo}/commits/{sha}/pulls`, and — for task-branch PRs only — assembles and posts the Archivist provenance block (`roles/archivist.md` item 8) and explicitly closes the task's Issue, confirming the closed state before exiting. Idempotent **per PR**, not per Issue (an Issue can legitimately accrue multiple merged PRs over its life; idempotency never spans PRs): skips silently if the PR already carries a provenance comment. Skips silently on non-task branches (`plan/*`, `fix/*`, …). Fails loud (non-zero exit) on any `gh`/permission error — never a silent no-op. Real, installed with `contents: read`, `issues: write`, `pull-requests: write` permissions. Does not automate the Tranche Archivist or items 2–7 of per-task close-out (docs coherence, `docs-index.md`, token ledger) — those remain dispatched-Archivist judgment work.
|
|
309
309
|
- **Manifest integrity** — `verify-docs --full` and the coherence oracle validate the doc-owners manifest: pointer existence (M1), glob syntax (M2 advisory), and duplicate globs (M3). There is no decision-number sequencing: the log it validated is gone.
|
|
310
310
|
- **Closes #N gate** — task-branch PRs must declare `Closes #<its-issue>` in the PR body; absence fails CI. Non-task branches bypass this forward direction automatically. Real, installed at `.github/workflows/forge-lifecycle.yml::closes-n-gate`. Same enforcement substrate as above. **Forge-native-tranche fix (`fix/closes-n-forge-native`):** the gate's scoped `loadTrancheFiles(null, onlySlug)` call discovers which tranches exist by listing `aeg-root/tranches/*.md` filenames — a tranche with zero topology file never entered that enumeration, so the forge derivation was never invoked for it despite the tranche already being fully Milestone-capable, and the gate failed every such PR with a misleading "no topology file found." Fixed by falling back to a direct forge derivation (the Milestone-existence check plus the file-and-forge composition, today `indexTrancheMilestonesAsync` + `mergeFileTopology`) when the requested `onlySlug` isn't found via files, gated on an actual open Milestone existing so an unrecognized branch slug still fails honestly — the scoped-path counterpart to `verify-dispatch.ts`'s `otherActiveTrancheSlugs` fix. **Reverse direction (`fix/closes-n-reverse`):** a `Closes #N` that resolves to a real AEG task Issue (title matches the `[<tranche-slug>] <task-id>...` convention and carries a `vinaya/tranche:<slug>` label) now requires the branch to actually be named `task/<tranche-slug>/<task-id>`, regardless of what the branch itself is called — closing the blind spot that let a mis-named branch implement a real task Issue with zero forge-visible status. One batched forge query (`fetchTaskIssueRefs`) resolves each referenced Issue's task identity before `checkClosesN` runs. **Code-span hardening (`fix/closes-gate-hardening`):** both the pre-merge gate (`checkClosesN` in `brief-validation.ts`) and the coherence-side parse (`extractClosesReferences` in `coherence-checks.ts`) now `stripCode` the body before matching the closing keyword, as GitHub's own auto-close parser ignores `Closes #N` inside a code span or fenced block. Inline spans of **any backtick-run length** are covered (`` `x` ``, `` ``x`` ``, …) via CommonMark's `(`+)…\1` matched-run rule — the double-backtick form was a false-green in the first cut (peeled as two empty spans). Fenced blocks are matched by a line scanner that pairs a fence with its own closer by **character and run length**: `~~~` tilde fences, info strings (```` ```js ````), and runs longer than three (```` `````` ````) all strip correctly, and an unclosed fence runs to end of body as GitHub renders it — the earlier `` /```[\s\S]*?```/g `` regex missed all three. The keyword set matches GitHub's own: `close`/`closes`/`closed`, `fix`/`fixes`/`fixed`, `resolve`/`resolves`/`resolved`. Before this, a body whose only `Closes #N` was backticked passed the gate **green** yet merged **without** closing its Issue, then read red on every open PR via A3 `auto-close-misfire`; "verify-docs green" now implies "GitHub will auto-close" for fenced + inline-code forms. 4-space **indented** code blocks are stripped too, conservatively: a ≥4-column-indented run counts as code only when it follows a blank line *and* is not inside a list — since within a list item that indentation is the item's own content indent, which GitHub *does* auto-close (blanking it would be a false-red, the brief's over-strip stop condition). The strip runs on the **whole body, before any region is sliced out of it** — never on a slice. Every rule in it is block-structural (a fence pairs with its own closer; an indented run is code only after a blank line and outside list context), so a fragment strips differently from the same text in place: stripping the sliced `AEG:CLOSES` region blanked an anchor indented inside a list item — list content GitHub *does* auto-close — and the Archivist's `extractIssue` returned no Issue, stranding it on merge exactly as before. Markers are HTML comments and survive the strip, so selecting the region from stripped text loses nothing and subsumes the decoy protection: a decoy anchor inside code never survives to be sliced. The same grammar governs `maskCode`, the index-preserving variant `anchoredRegion` runs to find the `AEG:*` markers themselves — it is **upstream** of every `stripCode` call, so while it stayed on the naive fence/inline regexes a decoy `AEG:CLOSES` anchor inside a tilde fence, a ≥4-backtick fence, a double-backtick span, or an indented block won the region outright and the gate resolved a **wrong** Issue number (worse than the strandings above: the post-merge Archivist's `extractIssue` would explicitly close an unrelated Issue). Both now delegate to one pair of scanners, differing only in what they emit per code line — nothing for `stripCode`, same-length filler for `maskCode` — so a divergence is a compile-level impossibility rather than a convention. This hardens all five anchored fields (`CLOSES`, `PROJECT`, `TIER`, `PREMISE`, `TEST-PLAN`) at once, not just the closing reference. `stripCode` normalises `\r\n`/`\r` to `\n` before any of these scanners run: the fence scanners anchor per line, and JS's `.`/`$` never match `\r`, so a CRLF body opened no fence at all and let a fenced `Closes #N` walk free — the same false-green along a new axis, and it hit exactly the web-UI-authored bodies this CI backstop exists for (HTML normalises textarea newlines to CRLF on submit). The closing-keyword separator is **bounded** (`\s{0,8}:?\s{0,8}`, identical in both parsers): two adjacent unbounded `\s*` groups backtrack quadratically on `closes` + long whitespace + no `#` — ~2.0 s at GitHub's 65,536-char body cap, run twice on the fail path — where the bound is 0.1 ms. **Known residual:** a genuine indented code block *nested inside a list* is therefore left unstripped — the deliberately safe direction of that trade. A `Closes #N` surviving only inside code fails with an actionable message pointing at a bare reference in the `AEG:CLOSES` anchor. `stripCode` is the one shared stripper, exported from `anchored-region.ts` (no duplicated regex).
|
|
311
311
|
- *(The practitioner-facing map of every enforcement mechanism — prevention, detection, audit — lives in `aeg-root/enforcement.md`; this section remains the normative gate registry.)*
|
|
312
|
-
- **Tool-layer forge gates** — the earliest enforcement point: a
|
|
312
|
+
- **Tool-layer forge gates (ring 0)** — the earliest enforcement point: a tool-interception hook, wired into the agent's own host so it runs before any raw forge-mutating call reaches GitHub, denies raw `gh pr create`/`gh pr edit --body*`/`gh issue create`/`gh issue edit --body*` (and `gh api` creation POSTs), directing agents to the validated wrappers `packages/aeg-core/bin/open-pr.ts` (runs verify-brief + verify-docs `--pr` + the Closes #N gate locally, calls `gh` only on green) and `bin/open-issue.ts` (a task Issue with a `vinaya/tranche:*` label must carry the full eight-field Planner rationale — `checkIssueRationale`, planner-brief contract, **and pass three content checks on what those fields say, `checkBlastRadiusScope` (the declared surface may not reach a shared collision domain — live-derived `packages/*` workspace members, built-in cross-cutting defaults, plus any `vinaya.config.json` `blastRadius.extraDomains` entries — that no declared project owns, absent a second **registered** project or a `blast-radius-ack:` line), `checkNoBriefContent` (no brief-shaped section in the Issue), `checkRationaleNamesDocs` (the rationale names a concrete doc/skill path, or the `no-doc-surface` sentinel). `checkConflictCompleteness` warns on an undeclared collision-domain overlap and never blocks**). Prevention, not detection: a malformed PR/Issue body is refused at the agent's own tool call and never reaches the forge; the CI gates below re-run the identical aeg-core checks purely as a backstop for non-hook writers. Also enforced at the same layer: title grammar (`checkForgeTitle`, both wrappers), the single-plan-PR guard (`checkSinglePlanPr` — a diff touching a tranche's topology file is refused when another OPEN PR already touches that same tranche's topology file), `gh api` PATCH/curl write-method denies, and a `.husky/pre-push` gate refusing `task/<tranche>/<id>` pushes whose id has no topology row (mechanical). On this repo's shipped reference host, this hook type is a `PreToolUse` hook (`.claude/hooks/check-forge-gates.sh`, wired in `.claude/settings.json`) — one instance of the pattern, not the concept itself; see `tranche-model.md` §12 for how this doctrine names its one concrete example. Operational rule: restart running agent sessions after merging hook/settings changes — hooks load at session start. Same mechanism as skill-check enforcement and the T9 merge gate.
|
|
313
313
|
- **Single-plan-PR CI backstop** — `checkSinglePlanPr` (`packages/aeg-core/src/single-plan-pr.ts`) was extracted from `open-pr.ts` (previously private to that wrapper) so the identical predicate could also run forge-side: `.github/workflows/forge-lifecycle.yml::single-plan-pr-gate` re-fetches this PR's touched files plus every other open PR's touched files and fails CI on the same violation the ring-0 hook refuses locally. Closes the gap where a PR opened directly via the GitHub web UI bypasses `open-pr.ts` entirely. No-ops (never fires) for an ordinary task-branch PR, since its diff never touches a tranche topology file. **Dormant in this repo entirely, as of the forge-native cutover:** a plan is now a Milestone plus labeled Issues, and `aeg-root/tranches/` holds no active topology file for a diff to collide over. The guard is kept, not deleted, because it is correct and live for any repo that does keep plans as files — but nothing here can trip it, and a gate that cannot fire should say so rather than read as active protection. One implementation, two enforcement points — no second copy of the predicate.
|
|
314
314
|
- **Coherence oracle (A1/A2/A3/T1/T2/T3/D1/M1/M3)** — `packages/aeg-core/bin/verify-coherence.ts` runs against every PR and genuinely blocks CI — the CLI's own exit code, non-zero on any `fail`-status check, is what the `coherence-gate` job exits with. Failures in A1 (closed-without-merge), A2 (archived-without-provenance), A3 (auto-close-misfire), T1 (phantom-issue-ref), T2 (orphan-task — **plan PRs only, see below**), T3 (tbd-in-active-tranche), D1 (dispatched-on-unmet-deps), M1 (manifest-dangling), and M3 (manifest-duplicate-glob) fail CI. L1–L5 and M2 are advisory (info-only) — every `checkL*` returns `status: info`, so a premature-archive, lifecycle-hygiene, Milestone-attachment-drift, or open-Milestone-all-closed finding is surfaced for a human to investigate but never fails CI. On A1 failures the relevant Issues receive the `vinaya/incoherent` label (Section 14). Real, installed at `.github/workflows/forge-lifecycle.yml::coherence-gate`. Same enforcement substrate as above. **The job's repo-state inputs (topology files, tranche list) are read from a freshly-fetched `origin/main` — not the checkout's `refs/pull/N/merge`, which GitHub materializes lazily and can lag behind main (5+ false-red cycles, 2026-07-03/04). A plan PR's own topology diff still reads from its head ref.**
|
|
315
315
|
- **Planner→Brief rationale completeness (R1)** — the same coherence oracle's **R1** check re-runs `checkIssueRationale` **and `checkProjectsRegistered`** (`packages/aeg-core`) against every open task Issue's body, batched per active tranche alongside T2. A non-grandfathered Issue missing any of the eight `contracts/planner-brief.md` rationale fields — or whose `Project:` field names a project with no row in the project registry — fails CI. Paired with the ring-0 creation gate (`bin/open-issue.ts`, same tool-layer-forge-gates row above) — R1 is the continuous half, the hook is the point-of-creation half; one grammar, two enforcement points (`aeg-root/enforcement.md`). Pre- Issues are grandfathered by explicit Issue number (`R1_GRANDFATHERED_ISSUES`), reported `info`, never blocking — see Section 15b. **Real.** Moves this seam's rationale-completeness half from Trusted (below) to Enforced; the "role doc matches contract prose" half of contract conformance remains Trusted.
|
|
@@ -613,13 +613,11 @@ Sibling to `verify-docs.ts`/`verify-coherence.ts`, same thin-CLI-shim discipline
|
|
|
613
613
|
|
|
614
614
|
**The default-mode composite ships as the `dispatch-readiness` check** (`vinaya check dispatch-readiness`, branch-scoped) — see `enforcement.md`'s dispatch row for its known parity gap (prior-tranche-archival always reports empty). The `--premise`/`--simulate`/`--check-baseline` modes below have no shipped `vinaya` equivalent yet.
|
|
615
615
|
|
|
616
|
-
**Usage (this repo's toolchain)
|
|
617
|
-
|
|
618
|
-
bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n>
|
|
619
|
-
bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n> --
|
|
620
|
-
bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n> --
|
|
621
|
-
bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n> --check-baseline <file>
|
|
622
|
-
```
|
|
616
|
+
**Usage (this repo's toolchain)** — four independent invocation forms, not a sequence:
|
|
617
|
+
- Default mode: `bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n>`
|
|
618
|
+
- Premise re-assertion: `bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n> --premise <body-file>`
|
|
619
|
+
- Simulate mode: `bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n> --simulate <body-file>`
|
|
620
|
+
- Baseline compare: `bun packages/aeg-core/bin/verify-dispatch.ts <tranche> <n> --check-baseline <file>`
|
|
623
621
|
|
|
624
622
|
**Default mode composes three checks:**
|
|
625
623
|
|
|
@@ -9,7 +9,7 @@ The brief itself carries no anchor comments: it rides into the PR body as the *r
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
**For:** [model + environment, e.g. "
|
|
12
|
+
**For:** [model + environment, e.g. "your-model (coding-agent CLI on a dev machine, dispatched locally, unattended)"]
|
|
13
13
|
**Reason:** [why this capability level fits this task — real reasoning against the task, not "because it's good"]
|
|
14
14
|
**Owner:** [who owns the task — the Principal, by default]
|
|
15
15
|
**Goal:** [one sentence: what ships]
|
|
@@ -22,7 +22,7 @@ You are the AEG Developer. Read `aeg-root/roles/developer.md` first[, then the h
|
|
|
22
22
|
|
|
23
23
|
- **Tranche:** [`tranche-slug`], task [n], Issue #[N]. Branch `task/[tranche-slug]/[n]`. `Depends-on: [—|ids]`, `Conflicts-with: [—|ids]`. Confirm `READY TO DISPATCH` at your own Step 0.
|
|
24
24
|
- **Read Issue #[N] in full** for the complete rationale — do not re-derive it.
|
|
25
|
-
- [CONTEXT — the Planner's rationale carried forward (boundary, blast radius, traps), what was previously validated, what is settled and must not be re-litigated, and everything your own Dig confirmed about the current surface. If it isn't in the brief, it doesn't exist.]
|
|
25
|
+
- [CONTEXT — the Planner's rationale carried forward (boundary, blast radius, traps), what was previously validated, what is settled and must not be re-litigated, and everything your own Dig confirmed about the current surface. If it isn't in the brief, it doesn't exist. No behavioural fact about code belongs here as prose — a `Premise:` pin or a fenced command with its executed output is the only form (skill §2's rule).]
|
|
26
26
|
|
|
27
27
|
## 3. Technical dependencies
|
|
28
28
|
|
|
@@ -58,9 +58,9 @@ git worktree add .worktrees/task/[tranche-slug]/[n] -b task/[tranche-slug]/[n] o
|
|
|
58
58
|
|
|
59
59
|
On any failure: STOP and report.
|
|
60
60
|
|
|
61
|
-
## 6. Numbered parts — commit
|
|
61
|
+
## 6. Numbered parts — commit after EACH part; push once, before opening the PR
|
|
62
62
|
|
|
63
|
-
1. **Part 1:** [exact files + exact function/type signatures + constraints — not prose]
|
|
63
|
+
1. **Part 1:** [exact files + exact function/type signatures + constraints — not prose. A Part that depends on a fact about current code opens with the fenced command that establishes it, followed by the executed output (skill §2's rule).]
|
|
64
64
|
2. **Part 2:** [next bounded unit of work]
|
|
65
65
|
|
|
66
66
|
## 7. Documentation-update list
|
|
@@ -69,7 +69,7 @@ On any failure: STOP and report.
|
|
|
69
69
|
|
|
70
70
|
## 8. Verification before claiming done
|
|
71
71
|
|
|
72
|
-
- [the repo's static gates, by command — this repo: `bun run typecheck`, `bun run test
|
|
72
|
+
- [the repo's static gates, by command — this repo: `bun run typecheck`, lint, build; `bunx turbo test --affected` per Part — the full `bun run test` suite is CI's to run, on the one push, never the Developer's to run locally]
|
|
73
73
|
- [every blast-radius consumer named in §4 re-verified, by name]
|
|
74
74
|
- `roles/developer.md`'s tier checklist genuinely satisfied, and `PR_BODY="$(cat <body-file>)" vinaya check doc-coverage` green. (On this repo's toolchain, `PR_BODY="$(cat <body-file>)" bun packages/aeg-core/bin/verify-docs.ts --pr` runs both as one command.)
|
|
75
75
|
|
|
@@ -90,7 +90,7 @@ STOP and report if: pre-flight fails; [the Planner's stop-and-escalate condition
|
|
|
90
90
|
- [forbidden patterns for this task — deferred features, off-limits paths]
|
|
91
91
|
- Never write status anywhere; never add execution metadata to the tranche file.
|
|
92
92
|
|
|
93
|
-
> **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
|
|
93
|
+
> **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.
|
|
94
94
|
|
|
95
95
|
## 12. Deliverable
|
|
96
96
|
|
|
@@ -7,7 +7,7 @@ sidebar_title: "Template: PR report"
|
|
|
7
7
|
|
|
8
8
|
**The anchor comments are load-bearing.** Each gate-read field — `Closes #N`, `Project:`, `Tier:`, the Test Plan section, the Premise block, the Evidence block — sits inside an AEG anchor pair (an HTML comment pair, invisible on the rendered PR). When an anchor pair for a field is present, every gate reads that field **exclusively from inside the pair**, ignoring identical-looking text anywhere else in the body — a pasted reference brief, a quoted example, a duplicate section can no longer be mistaken for the real field. Bodies without anchors remain fully recognized (prose recognition is the compatibility fallback) for every field **except Evidence**, which has no prose fallback — it is never hand-typed. Use at most one anchor pair per field. Keep the anchors when you fill this in.
|
|
9
9
|
|
|
10
|
-
**The `AEG:PREMISE` anchor is not optional when the brief carried a `Premise:` block.** Without it, `premise-recheck` scans the *whole* body for anything premise-shaped —
|
|
10
|
+
**The `AEG:PREMISE` anchor is not optional when the brief carried a `Premise:` block.** Without it, `premise-recheck` scans the *whole* body for anything premise-shaped — and re-asserts those against the code you just changed. A premise pinning the *pre-fix* state will correctly fail once your fix lands, because the pin describes what you just changed away from. Put a fresh, post-fix, currently-true assertion inside `<!-- AEG:PREMISE:START -->` / `<!-- AEG:PREMISE:END -->` so the re-check asserts something true of the shipped diff, not the brief's stale snapshot — this holds even though the brief's own original pins no longer live in the *posted* body at all: `pr create` splits the `## Reference` section (below) out into the separate `aeg:brief` PR comment before the body ever reaches the forge.
|
|
11
11
|
|
|
12
12
|
**No bare digit outside a fenced block.** `body-bare-digits` (CI) refuses a countable claim — a test count, a file count, a timing figure, "N passed" — written loose in a sentence anywhere in this body. A digit is exempt for exactly one reason: it sits inside an inline code span or a fenced/indented code block (`` `N` `` or a fenced block), or inside `Closes #N`/`Project:` (this header block) / `Tier:` (under `## Scope`) / `Evidence` (under `## Evidence`), correctly placed under its own documented section. **Nowhere else** — including inside `Premise`/`Test plan` (both scanned exactly like ordinary prose, no anchor exemption at all — evidence there, byte counts, exit codes all need their own backticks too), an Issue/PR reference, a date, a version, a file path, or a section number: any of those now needs its own backticks (`` `#N` ``, `` `2026-08-18` ``, `` `0.12.0` ``) the same as any other digit. Write the number inside a fenced block or backticks, or don't write it bare at all.
|
|
13
13
|
|
|
@@ -29,7 +29,7 @@ Closes #[N]
|
|
|
29
29
|
## Test plan
|
|
30
30
|
|
|
31
31
|
<!-- AEG:TEST-PLAN:START -->
|
|
32
|
-
- [ ] **[agent]** [item carried from the brief's §9 — tick only after
|
|
32
|
+
- [ ] **[agent]** [item carried from the brief's §9 — tick only after running it; the tick is the only mark this line ever carries, never the pasted command output, which goes in the round comment headed `Head: <sha>` instead]
|
|
33
33
|
- [ ] **[principal]** [item carried from the brief's §9 — the Principal ticks after verifying in a real browser/session]
|
|
34
34
|
<!-- AEG:TEST-PLAN:END -->
|
|
35
35
|
|
|
@@ -40,7 +40,7 @@ Closes #[N]
|
|
|
40
40
|
- [path/inside/the/shipped/diff.ts] contains: [a literal substring that is TRUE of the code AFTER your fix — never the brief's original pre-fix pin]
|
|
41
41
|
<!-- AEG:PREMISE:END -->
|
|
42
42
|
|
|
43
|
-
[Omit this whole section — anchors and all — only when §4 of the brief had no real code surface (a Tier 0 doc-only or planning-only change). Any brief with a `Premise:` block gets a fresh one here; do not
|
|
43
|
+
[Omit this whole section — anchors and all — only when §4 of the brief had no real code surface (a Tier 0 doc-only or planning-only change). Any brief with a `Premise:` block gets a fresh one here; do not rely on the brief's original block as a substitute — `pr create` splits it into the separate `aeg:brief` PR comment, never the posted body, and the re-check reads this anchored section, not that comment.]
|
|
44
44
|
|
|
45
45
|
## Evidence
|
|
46
46
|
|
|
@@ -70,11 +70,14 @@ The block opens with `Head:` and a `Summary:` line — a file and line count der
|
|
|
70
70
|
| [task-id]: develop | Developer | [model] | [exact in] | [exact out] | [cost] | [YYYY-MM-DD] |
|
|
71
71
|
<!-- AEG:TOKENS:END -->
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
---
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
<!-- aeg:brief:start -->
|
|
76
|
+
## Reference — the dispatched brief
|
|
77
77
|
|
|
78
78
|
[paste the entire dispatched brief here, verbatim]
|
|
79
|
+
<!-- aeg:brief:end -->
|
|
80
|
+
|
|
81
|
+
**`pr create` splits this section out — never sends it to the forge as body text.** Everything from the `aeg:brief:start` marker to `aeg:brief:end` — this whole `## Reference` section — is extracted and posted as its own PR comment marked `<!-- aeg:brief -->`, once, at open. The body `gh pr create` actually receives ends at the divider above it; paste the brief here exactly as before, the split is mechanical, not a change to what you author.
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
**This body is written once, at open.** After the PR is open the Developer changes nothing outside the `AEG:EVIDENCE` anchor and one appended `AEG:TOKENS` row. The Principal's `[principal]` ticks are the Principal's writes and must survive every Developer edit. A round's response, its re-run evidence, and any disclosure the brief didn't anticipate are PR comments, never edits to this body.
|