@attalabs/vinaya 0.24.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -3
- package/aeg-root/contracts/architect-planner.md +5 -5
- package/aeg-root/contracts/developer-reviewer.md +10 -7
- package/aeg-root/contracts/planner-developer.md +142 -0
- package/aeg-root/contracts/reviewer-archivist.md +2 -2
- package/aeg-root/contracts/tranche-archivist-planner.md +12 -11
- package/aeg-root/enforcement.md +25 -11
- package/aeg-root/process.md +53 -75
- package/aeg-root/roles/archivist.md +3 -3
- package/aeg-root/roles/developer.md +30 -24
- package/aeg-root/roles/planner.md +100 -21
- package/aeg-root/roles/principal.md +14 -11
- package/aeg-root/roles/reviewer.md +33 -17
- package/aeg-root/roles/security.md +28 -13
- package/aeg-root/roles/tranche-archivist.md +2 -2
- package/aeg-root/skills/aeg/SKILL.md +5 -5
- package/aeg-root/skills/aeg-roles/SKILL.md +7 -7
- package/aeg-root/state-machine.md +36 -35
- package/aeg-root/task-model.md +3 -3
- package/aeg-root/templates/brief-template.md +22 -6
- package/aeg-root/templates/issue-rationale-template.md +35 -2
- package/aeg-root/templates/pr-report-template.md +5 -13
- package/aeg-root/tranche-model.md +21 -21
- package/dist/checks/bin/check-body-bare-digits.js +684 -142
- package/dist/checks/bin/check-branch-topology.js +741 -88
- package/dist/checks/bin/check-brief-shape.js +708 -83
- package/dist/checks/bin/check-changeset-coverage.js +1445 -149
- package/dist/checks/bin/check-closes-n.js +741 -88
- package/dist/checks/bin/check-coherence.js +808 -149
- package/dist/checks/bin/check-dead-branch-push.js +617 -81
- package/dist/checks/bin/check-dispatch-readiness.js +811 -152
- package/dist/checks/bin/check-doc-coverage-push.js +1445 -149
- package/dist/checks/bin/check-doc-coverage.js +1447 -151
- package/dist/checks/bin/check-doctrine-no-procedures.js +684 -142
- package/dist/checks/bin/check-doctrine-portability.js +1445 -149
- package/dist/checks/bin/check-evidence-fresh.js +684 -142
- package/dist/checks/bin/check-exec-bits.js +1445 -149
- package/dist/checks/bin/check-first-push-dispatch.js +808 -149
- package/dist/checks/bin/check-issue-assignment.js +741 -88
- package/dist/checks/bin/check-main-branch-refusal.js +618 -82
- package/dist/checks/bin/check-no-disk-state.js +617 -81
- package/dist/checks/bin/check-pr-premise-reassert.js +5401 -0
- package/dist/checks/bin/check-pr-report-density.js +617 -81
- package/dist/checks/bin/check-quoted-command.js +1443 -147
- package/dist/checks/bin/check-reader-resolvable-prose.js +1481 -153
- package/dist/checks/bin/check-registry-gates.js +659 -85
- package/dist/checks/bin/check-retired-vocabulary.js +1443 -147
- package/dist/checks/bin/check-review-gate.js +758 -145
- package/dist/checks/bin/check-single-plan-pr.js +617 -81
- package/dist/checks/bin/check-surface-scope.js +5722 -0
- package/dist/checks/bin/check-test-plan.js +617 -81
- package/dist/checks/bin/check-token-collection-wired.js +617 -81
- package/dist/checks/bin/check-token-report.js +629 -88
- package/dist/checks/bin/check-workspace-escape.js +1443 -147
- package/dist/index.js +8548 -4335
- package/package.json +1 -1
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-render.ts +2 -2
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/main-branch-refusal.ts +26 -1
- 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/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]__1pndh3_._.js → [root-of-the-server]__0p8q38b._.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]__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/_0wxycau._.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/chunks/ssr/packages_ui_topbar_index_tsx_1h1gs1y._.js +1 -1
- 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/{3m1kgax7j2vgs.js → 0bn8c8v5q429o.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0doqwpd81sjzn.js → 0keji7wvbe1d1.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1maoxbrl3pv5d.css +1 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1uogpj5w2n5ju.js → 3-6a3tinbdb-7.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0zebsmmk1bvnb.js → 3_9xytdmiv1xi.js} +4 -4
- package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
- package/aeg-root/contracts/brief-developer.md +0 -141
- package/aeg-root/contracts/planner-brief.md +0 -130
- package/aeg-root/roles/brief-author.md +0 -114
- package/aeg-root/skills/brief-authoring/SKILL.md +0 -509
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/3qc67qhcvbg0o.css +0 -1
- /package/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/{aeg-core → vinaya/studio-standalone/_node_modules/@attalabs/aeg-core}/bin/verify-coherence.ts +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{QY2GhiI47-765D9DHGy1I → DMofV2-9FrHE7100GfrpI}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{QY2GhiI47-765D9DHGy1I → DMofV2-9FrHE7100GfrpI}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{QY2GhiI47-765D9DHGy1I → DMofV2-9FrHE7100GfrpI}/_ssgManifest.js +0 -0
|
@@ -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 — 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
|
|
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 this body at all: the brief lives on the task Issue, as the frozen `aeg:brief:v1` comment `vinaya task dispatch` posts, and this PR body never carries a copy of it.
|
|
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
|
|
|
@@ -22,9 +22,9 @@ Closes #[N]
|
|
|
22
22
|
**Project:** [project(s), comma-separated, matching the brief]
|
|
23
23
|
<!-- AEG:PROJECT:END -->
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Decisions
|
|
26
26
|
|
|
27
|
-
[
|
|
27
|
+
[one line per choice the brief left open, e.g. `- <choice>: <what you picked and why>` — the alternatives you considered and why you picked yours, so the Principal can reverse a wrong call. Never restate what the diff does; that's the diff's job, not this section's. No verification claims here (no "typecheck passes", no diff stats, no test counts) — those go in the emitted Evidence block below, never typed by hand.]
|
|
28
28
|
|
|
29
29
|
## Test plan
|
|
30
30
|
|
|
@@ -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 rely on the brief's original block as a substitute —
|
|
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 — that block lives on the Issue's `aeg:brief:v1` comment, never in this body, and the re-check reads this anchored section, not that comment.]
|
|
44
44
|
|
|
45
45
|
## Evidence
|
|
46
46
|
|
|
@@ -72,12 +72,4 @@ The block opens with `Head:` and a `Summary:` line — a file and line count der
|
|
|
72
72
|
|
|
73
73
|
---
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
## Reference — the dispatched brief
|
|
77
|
-
|
|
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.
|
|
82
|
-
|
|
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.
|
|
75
|
+
**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. The brief itself never lives here — it is posted once, frozen, as the `aeg:brief:v1` comment on the task Issue (`vinaya task dispatch`); `pr create` refuses a body carrying either legacy `<!-- aeg:brief:start -->`/`<!-- aeg:brief:end -->` marker outright.
|
|
@@ -29,7 +29,7 @@ Every fact in AEG lives in exactly **one** place. Nothing is duplicated; no arti
|
|
|
29
29
|
| **The forge Issue** | Task identity + metadata (project label, ticket link, dependency/conflict references) | Planner (at plan time) |
|
|
30
30
|
| **The thin tranche file** | Planning *topology* only — task→issue mapping, dependency graph, conflict graph, tranche grouping | Planner (at plan time) |
|
|
31
31
|
| **The Git forge** (branch / PR / review / merge state) | All live execution *status* — derived, never stored | the act of working (opening a branch, a PR, a review, a merge) |
|
|
32
|
-
| **The
|
|
32
|
+
| **The task Issue's `aeg:brief:v1` comment** | The just-in-time brief — the task's full execution context | The Planner's dispatch act, once, when work starts (mechanically rendered, never hand-typed) |
|
|
33
33
|
|
|
34
34
|
The cardinal rule, stated once and enforced everywhere below: **the forge holds what is happening; the file and the issue hold the plan. Never copy "what is happening" into the file or the issue.**
|
|
35
35
|
|
|
@@ -39,14 +39,14 @@ The cardinal rule, stated once and enforced everywhere below: **the forge holds
|
|
|
39
39
|
|
|
40
40
|
The roadmap — what to build, why, in what priority — belongs to the company and lives in the company's tool (Jira, Linear, a doc they own). **AEG never holds it.** The moment AEG stores a roadmap it competes with Jira, loses, and creates a second rotting source of truth.
|
|
41
41
|
|
|
42
|
-
What AEG holds is the **tranche**: the bounded set of tasks currently being turned into merged code. The link from roadmap → tranche is a **human** — the Planner
|
|
42
|
+
What AEG holds is the **tranche**: the bounded set of tasks currently being turned into merged code. The link from roadmap → tranche is a **human** — the Planner translating tickets into agent-shaped tasks. There is no file for that link, because the link is a person's judgment.
|
|
43
43
|
|
|
44
44
|
```
|
|
45
45
|
Company roadmap / Jira / project backlog ← NOT in AEG. Reference only. The human reads it.
|
|
46
|
-
│ (human translation — Planner
|
|
46
|
+
│ (human translation — Planner, plan act)
|
|
47
47
|
▼
|
|
48
48
|
Tranche = a set of forge Issues + a thin topology file ← TOP of AEG.
|
|
49
|
-
├─ Task (Issue) ── brief
|
|
49
|
+
├─ Task (Issue) ── brief rendered mechanically at dispatch → posted as the Issue's frozen comment
|
|
50
50
|
├─ Task (Issue)
|
|
51
51
|
└─ … edges (depends-on / conflicts-with) declared in the thin file
|
|
52
52
|
│
|
|
@@ -88,7 +88,7 @@ So: there is **no status column anywhere.** The Developer does not "flip to in-r
|
|
|
88
88
|
|
|
89
89
|
The file held **only** what the forge models poorly: the task→Issue mapping and the dependency/conflict graph. It contains **no status, no PR numbers, no merge dates, no timestamps — nothing the forge already knows. It contains no task prose, no boundary descriptions, no rationale — nothing that belongs on the Issue.** Its task topology was edited only by the Planner, at plan time, so it could not race and could not drift on status (it stored none). The same rule now binds the Milestone and its Issues: the Planner cuts them, and nothing downstream writes status back. The one exception is the tranche's own **lifecycle marker** (active/complete — §12), a single header line the Archivist sets at close-out; this is the tranche's lifecycle, not per-task execution status, and it is set once when the whole tranche ends.
|
|
90
90
|
|
|
91
|
-
**`#TBD` is still forbidden, wherever a task is recorded.** Every task must carry a real forge Issue number. A tranche that contains `#TBD` is an incomplete plan — the Planner has not cut the Issues, which is the canonical plan act. **The Planner's rationale (Boundary, Sizing, Project(s)+blast radius, Dependency rationale, Traps to avoid, Suggested agent-class, Stop-and-escalate) lives on the Issue body.** Nothing outside the Issue repeats the rationale.
|
|
91
|
+
**`#TBD` is still forbidden, wherever a task is recorded.** Every task must carry a real forge Issue number. A tranche that contains `#TBD` is an incomplete plan — the Planner has not cut the Issues, which is the canonical plan act. **The Planner's rationale (Boundary, Sizing, Project(s)+blast radius, Dependency rationale, Traps to avoid, Suggested agent-class, Stop-and-escalate) lives on the Issue body.** Nothing outside the Issue repeats the rationale. The dispatch act's render reads it from the Issue, which is now its only home.
|
|
92
92
|
|
|
93
93
|
`dependsOn`/`conflictsWith` for every active tranche is now genuinely forge-derived, no file fallback anywhere. `completed/*.md` files are never deleted, by design (§11) — the birth rule never applied to them.
|
|
94
94
|
|
|
@@ -99,7 +99,7 @@ Template:
|
|
|
99
99
|
Lifecycle: active ← active | complete (§12). Set to complete by the Archivist when every task is merged.
|
|
100
100
|
|
|
101
101
|
Goal (execution, not roadmap-why): <what ships, end to end>
|
|
102
|
-
Repo: <repo> · Planner
|
|
102
|
+
Repo: <repo> · Planner: <name>
|
|
103
103
|
|
|
104
104
|
## Tasks (topology)
|
|
105
105
|
| # | Task | Issue | Project(s) | Depends-on | Conflicts-with |
|
|
@@ -143,7 +143,7 @@ Two tasks conflict if they touch the same **collision domain** and therefore mus
|
|
|
143
143
|
|
|
144
144
|
## 6. The Planner
|
|
145
145
|
|
|
146
|
-
The **Planner**
|
|
146
|
+
The **Planner** has two acts, same intelligence, two altitudes (`roles/planner.md`). Dispatch act: one task's Issue → a rendered, gate-checked brief. Plan act: intent + a slice of tickets → a whole tranche (a set of Issues + the thin topology file).
|
|
147
147
|
|
|
148
148
|
The Planner's job — the reason the tranche exists — is the relationships a brief-in-isolation can't see: decompose the ticket slice into agent-sized tasks (Issues), declare `depends-on` and `conflicts-with` edges, and decide **split vs. combine** by the **verification-coupling** test:
|
|
149
149
|
|
|
@@ -156,14 +156,14 @@ The Planner writes no briefs (those are just-in-time, §7), writes no status (th
|
|
|
156
156
|
|
|
157
157
|
## 7. Where briefs live
|
|
158
158
|
|
|
159
|
-
The brief is the task's full execution context. It has
|
|
159
|
+
The brief is the task's full execution context. It has one home, and it is not the PR:
|
|
160
160
|
|
|
161
|
-
- **Before
|
|
162
|
-
- **
|
|
161
|
+
- **Before dispatch — nowhere persistent.** It does not exist yet. The task Issue carries the Planner's rationale (durable conclusions, written at plan time), never the brief itself — a brief in the Issue's own body would age, attract edits, and become stale planning documentation.
|
|
162
|
+
- **At dispatch — the task Issue's `aeg:brief:v1` comment, posted once, frozen.** The Planner's dispatch act runs `vinaya task dispatch`, which mechanically renders the brief from the Issue's rationale and judgment sections (consuming the `planner-developer` contract) and posts it as a comment on that same Issue, before the Developer's worktree exists. That comment is the brief's permanent, durable home, attached to exactly the work it governs, and what the Developer, Reviewer, and Archivist all read. It is never carried in the PR body, which holds only the Developer's report; a reference copy may ride along inside a collapsed `<details>` block there, but the frozen comment is the source of truth.
|
|
163
163
|
|
|
164
|
-
Retry
|
|
164
|
+
Retry reads the same frozen comment; no re-render, no rewrite.
|
|
165
165
|
|
|
166
|
-
For who reads and who writes documentation at each seam of this flow (Planner's whole-tranche read,
|
|
166
|
+
For who reads and who writes documentation at each seam of this flow (the Planner's whole-tranche read at plan time, its task-scoped re-read + §7 at dispatch time, Developer's execution, Reviewer's dual check, Archivist's confirmation), see `documentation-coherence.md`.
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
@@ -176,7 +176,7 @@ Two gates make parallel developers safe — both **forge-answerable, zero stored
|
|
|
176
176
|
|
|
177
177
|
With a single principal these rules live in one head; with a team they must be a **lock**, not a whiteboard. In manual mode they are preconditions each Developer checks against the forge before beginning. A dispatch tool can enforce them in code. Either way the conflict is declared at planning time and enforced at dispatch time — never discovered at merge time, which is too late.
|
|
178
178
|
|
|
179
|
-
**v1 honesty:**
|
|
179
|
+
**v1 honesty:** before Step 0, checking these gates is still *trusted, not enforced* — the Developer reads and complies, but nothing mechanically stops starting anyway. By the first push, though, they are mechanically enforced: the `.vinaya/hooks/pre-push` `first-push-dispatch` check runs the same `checkDispatchReadiness` derivation the `dispatch-readiness` check uses, on a task branch's first push, and refuses it outright if the dependency's PR isn't merged or the conflicting sibling's PR is open (it fails open only when the forge itself is unreachable). It shares that check's narrower parity, though — its prior-tranche-archival predicate always reports empty, the same gap `roles/developer.md` documents, so it does not run the full `verify-dispatch.ts` derivation. What remains trusted discipline is catching it earlier, before any work is done, with the unabridged derivation — the hook is the backstop, not the first line.
|
|
180
180
|
|
|
181
181
|
---
|
|
182
182
|
|
|
@@ -187,7 +187,7 @@ The review panel predicted, unanimously, two of the ways teams will accidentally
|
|
|
187
187
|
1. **No execution metadata in the thin file or the Issue.** Never add `status`, `PR #`, `merged date`, `current state`, `assignee history`, or generated collision data to the tranche file. The reason is always reasonable ("just to glance without querying") and it is always wrong — the forge already holds these, and copying them in recreates the racing, drifting, lying status store. **Thin file = topology. Forge = state.** The line is bright; keep it bright. (The tranche's own active/complete lifecycle marker in §12 is **not** an exception to this: it is the tranche's lifecycle set once at close-out, not per-task execution status, and the forge has no native fact for "this whole tranche is done.")
|
|
188
188
|
2. **No dynamic conflict scanner.** Do not build a script that checks out in-flight branches and diffs them to "catch conflicts the Planner missed." It cannot work without a live task→changed-files map — the mutable state we removed. When unsure two tasks collide, **declare the conflict and serialize** (§5). Conservative declaration is the sanctioned answer; a scanner is not.
|
|
189
189
|
3. **No planning metadata on Issues.** No priority, estimates, points, or roadmap fields. Enforced mechanically: a required Issue template (deps, conflicts, project label, ticket link — and nothing else) + a CI check that rejects forbidden fields/labels. Discipline alone will not hold this; the *place to put planning info is removed*, not just discouraged.
|
|
190
|
-
4. **No committed report/scratch files.** Never commit a new repo file whose sole purpose is a one-off report, audit finding, coverage summary, or working brief. The reason is always reasonable ("it's a big deliverable, it deserves its own file," "there's no prior convention, I'll set one") and it is always wrong — that content belongs in the PR body (task-scoped findings) or an Issue/PR comment (findings with no task PR of their own), exactly like a brief's permanent home is
|
|
190
|
+
4. **No committed report/scratch files.** Never commit a new repo file whose sole purpose is a one-off report, audit finding, coverage summary, or working brief. The reason is always reasonable ("it's a big deliverable, it deserves its own file," "there's no prior convention, I'll set one") and it is always wrong — that content belongs in the PR body (task-scoped findings) or an Issue/PR comment (findings with no task PR of their own), exactly like a brief's permanent home is a frozen Issue comment, never the Issue body or a repo file (§7). A committed scratch file recreates the racing, drifting problem the other three rules already forbid, one layer up: it is a fifth truth domain nobody asked for, competing with the forge for where "what happened" lives. This is not hypothetical — it has already happened twice: a 120-row audit deliverable committed as `aeg-root/tranches/<name>.audit.md` broke AEG Studio's tranche loader (which globs every `.md` file in this directory as a tranche), and a full task brief was committed as a permanent file under `aeg-project/briefs/`, contradicting §7's own rule that a brief is pasted, not committed. **Thin file = topology. Forge = state. PR body / Issue comment = findings and briefs.** Sanctioned exceptions: durable reference artifacts (specs, skills, role docs, contracts) and the `.tokens.md` sibling ledgers (§12) — these are pre-existing, separately-governed, durable-by-design; a one-off report is neither.
|
|
191
191
|
|
|
192
192
|
---
|
|
193
193
|
|
|
@@ -213,7 +213,7 @@ The earlier sections describe a single tranche's *internals*. This section cover
|
|
|
213
213
|
- **planned** — the thin file exists and the Issues are cut, but no work has started. Every task is `todo` (open, unassigned — committed tranche work, minimum `todo`). The tranche is a plan ready to execute.
|
|
214
214
|
- **active** — at least one task has an open branch (`in-flight`) or is further along. The tranche is in flight. `Lifecycle: active` in the header.
|
|
215
215
|
- **complete** — **every task's PR is merged** (every task derives to `merged` from the forge). The work is done. At this point — and only this point — the **Archivist** sets `Lifecycle: complete` in the header (one line; the single lifecycle mutation the file ever takes after plan time) and assembles the per-task provenance blocks on the merged PRs. "Complete" is itself **derived** from the forge (all linked PRs merged); the header marker is a convenience flag the Archivist writes once, not a status anyone maintains.
|
|
216
|
-
- **archived** — a
|
|
216
|
+
- **archived** — for a forge-native tranche, the Tranche Archivist **closes the Milestone**; that closed Milestone is the current signal a new tranche's readiness gate reads (`contracts/tranche-archivist-planner.md`). **Legacy exception:** a tranche still carrying a pre-cutover topology file also has that file **moved to `aeg-root/tranches/completed/<name>.md`**, kept (not deleted) for tranches created before the forge-native cutover.
|
|
217
217
|
|
|
218
218
|
### Flow stages — what actually happens, in order
|
|
219
219
|
|
|
@@ -221,7 +221,7 @@ The lifecycle above is the derived-status vocabulary — what Studio reads off t
|
|
|
221
221
|
|
|
222
222
|
1. **Plan** — the Planner turns an intent plus a slice of tickets into the tranche's tasks (Issues) and their `depends-on`/`conflicts-with` edges (§6). No Milestone required.
|
|
223
223
|
2. **Dispatch** — each task runs its own Task flow (`task-model.md` §3: Brief → Code → Review → Verify → Merge → Archive), independently, in parallel wherever `depends-on` allows and the conflict rule (§5) doesn't force a serialization. Deciding *when* each task actually starts is a real act, not an implicit one: today the Principal or a thin dispatch script — this file's own opening note names that actor for every altitude — tomorrow the Atta Engine's scheduler.
|
|
224
|
-
3. **Archive** — once every task has merged, the Tranche Archivist closes out: sets the lifecycle marker
|
|
224
|
+
3. **Archive** — once every task has merged, the Tranche Archivist closes out: closes the Milestone (the legacy exception additionally sets the lifecycle marker and moves the file to `completed/`), flags (does not perform) orphaned branches and worktree removal.
|
|
225
225
|
|
|
226
226
|
### Tranches are never deleted — they are durable history
|
|
227
227
|
|
|
@@ -266,13 +266,13 @@ Append-only. Each row records one role's turn at a phase. Re-entry appends a **n
|
|
|
266
266
|
| Phase | Role | Agent/Model | Tokens in | Tokens out | Cost | Date |
|
|
267
267
|
|-------|------|-------------|-----------|------------|------|------|
|
|
268
268
|
| planning | Planner | claude-opus-4-7 (chat) | — | — | — | 2026-06-13 |
|
|
269
|
-
| 9:
|
|
269
|
+
| 9: dispatch | Planner | claude-opus-4-7 (chat) | — | — | — | 2026-06-15 |
|
|
270
270
|
| 9: develop | Developer | claude-opus-4-7 (CC) | 184327 | 12502 | $3.4781 | 2026-06-15 |
|
|
271
271
|
| 9: review | Reviewer | claude-opus-4-7 (chat) | — | — | — | 2026-06-15 |
|
|
272
272
|
```
|
|
273
273
|
|
|
274
274
|
- **Phase** — free-text. Convention: `<task-id>: <phase>` for per-task work (e.g. `9: develop`, `9: review`), or a bare phase for tranche-wide work (e.g. `planning`). Phase is opaque to the parser; the convention exists so a future view can pivot by task.
|
|
275
|
-
- **Role** — the AEG role doing the work (`Planner`, `
|
|
275
|
+
- **Role** — the AEG role doing the work (`Planner`, `Developer`, `Reviewer`, `Security`, `Archivist`).
|
|
276
276
|
- **Agent/Model** — free text: the role's agent + model, with a short tag for the host surface in parentheses (`claude-opus-4-7 (CC)` for a coding-agent session, `claude-opus-4-7 (chat)` for a conversational one — the tags the archived ledgers already use). Nothing parses the tag; it is there because the surface is what tells a reader which collection capability applied (below), and therefore whether a `—` cell was sanctioned.
|
|
277
277
|
- **Tokens in / Tokens out** — integers from the meter, or `—` for "not yet known."
|
|
278
278
|
- **Cost** — USD as `$X.XXXX`, or `—`. *(V1 honesty: no maintained $/token pricing table for current models ships in this package, so `formatTokensLine` renders this cell as `—` on every row it emits. Historical rows may carry a `$X.XXXX` value supplied by hand or by an earlier table. Tokens are still exact; pricing is a known backlog dependency, not a ledger bug.)*
|
|
@@ -280,7 +280,7 @@ Append-only. Each row records one role's turn at a phase. Re-entry appends a **n
|
|
|
280
280
|
|
|
281
281
|
### The append rule (read this exactly the way you read derived status)
|
|
282
282
|
|
|
283
|
-
- **No role appends its own row on a task branch.** Two live-fire incidents forced this: read-only roles (Reviewer, Security, Planner
|
|
283
|
+
- **No role appends its own row on a task branch.** Two live-fire incidents forced this: read-only roles (Reviewer, Security, Planner) structurally cannot append — they hold no task branch, and some never touch the repo's filesystem at all; and parallel Developer sessions on different tasks collided appending to the same shared `tokens.md` file. Instead, every role **reports** its token spend in the artifact its turn already produces — the PR body ("Token report" section) for a role holding a branch, the verdict comment for a reviewing role, the plan PR or planning report for the Planner (either act) — and the per-task **Archivist appends every row at task close-out**, one row per role-turn, including its own.
|
|
284
284
|
- **Never edit** an existing row. If you discover a mistake, append a new row that supersedes it in prose (or fix the source file in a separate, declared edit — same exception that `state-machine.md` §13 carves for forward-reference fields).
|
|
285
285
|
- **Re-entry appends.** A Developer dispatched for `9: develop`, asked for changes, and re-running for `9: develop` again produces a **second** `9: develop` report, which the Archivist appends as a **second** row — never a sum, never an overwrite. The two rows both count.
|
|
286
286
|
- The **tranche total is `sum(rows)`**, derived at read time, never stored. This is the same philosophy as forge-derived status (don't store the aggregate; sum the immutable entries). A stored total reintroduces the merge-collision + stale-aggregate problem.
|
|
@@ -302,13 +302,13 @@ Token reporting is asymmetric — and any honest design has to encode that, beca
|
|
|
302
302
|
The split is **operator vs. agent, not terminal vs. chat** — a figure a human reads off an interactive prompt or a usage dashboard is not reachable from an unattended agent session (dispatched, automated, no human at the keyboard), whatever kind of surface it runs on. (2026-08-08: retracted — an earlier revision of this section claimed a terminal role reports exact numbers "from `/cost`", an operator-typed slash command in one particular host; no agent session ever could, in that host or any other.)
|
|
303
303
|
|
|
304
304
|
- **Self-metering** — a role whose host exposes the running session's own usage to the agent itself, so the role can collect real figures with no operator step. Typically the Developer, and the Archivist when it runs as automation. The role collects through its host's layer-2 mechanism and reports the exact numbers in its PR body; the Archivist copies them verbatim into the row it appends at close-out. **A self-metering role may not report `—` in the `Tokens in` or `Tokens out` cells** — real figures, or the collection step is broken and *that* is what to report. The `Cost` cell is outside this rule: it reads `—` on every row the shipped renderer emits, for the pricing-table reason given above.
|
|
305
|
-
- **Operator-metered** — a role whose host exposes no usage to the agent, leaving a human the only source of the figure. Typically the Planner
|
|
305
|
+
- **Operator-metered** — a role whose host exposes no usage to the agent, leaving a human the only source of the figure. Typically the Planner (either act), Reviewer and Security, which run in conversational surfaces with no session record the agent can read and no meter it can query. The role **still reports at turn-end** — phase, role, model, date, in its verdict comment or planning report — and leaves the numeric cells as `—` when no figure reached it. The blank is licensed by the **absence of a figure**, not by the role's label: where an operator hands the role real numbers at report time (a route layer 2 explicitly allows), those numbers go in the cells and `—` is not correct. The Archivist copies the report as-is; the **Principal** may later supply the real figures from whatever usage view the host does offer a human, filling a previously-`—` cell (the one narrow forward-reference exception `state-machine.md` §13 allows).
|
|
306
306
|
|
|
307
307
|
**Per-cell optionality is conditioned on host capability, never on convenience.** `—` in a **token** cell is sanctioned in exactly one situation: the host cannot expose the figure to the agent. (The **Cost** cell is separate and is always `—` while this package carries no maintained $/token table — see the Cost bullet above.) It is never a shortcut for a role that could have collected the number, and no role ever estimates a figure or fills in another role's cell — an invented number in an append-only ledger is worse than an honest unknown, because nothing downstream can tell the two apart.
|
|
308
308
|
|
|
309
309
|
Which capability applies is a fact about the **host**, not a fixed property of the role: the same role is self-metering on a harness that exposes usage and operator-metered on one that does not. Read the role names above as today's common case, not as an allocation.
|
|
310
310
|
|
|
311
|
-
Self-metering capture is real, not estimated: the adapter sums the session's own usage records, so a Developer or automated Archivist turn's numbers are exact rather than approximated. Whether it also runs with *no* operator step depends on the host's wiring — where a Stop hook writes a transcript pointer — configured in the repo or in the operator's own host settings — the adapter finds it unaided; with no pointer written, the caller names the transcript with `--transcript <path>`. Either way the figures are read, never guessed. The remaining manual seam is operator-metered roles only — closing it depends on the host giving a session a way to read its own usage, which conversational surfaces generally do not today. **Known gap — now partly closed:** tranche-wide operator-metered turns with no task PR to report into no longer lack a destination across the board. A Planner session outside a plan PR now reports into a comment on the pinned lessons Issue — the existing forge object, never a new one (`roles/planner.md` "Turn-end: report your tokens, don't append them"). A
|
|
311
|
+
Self-metering capture is real, not estimated: the adapter sums the session's own usage records, so a Developer or automated Archivist turn's numbers are exact rather than approximated. Whether it also runs with *no* operator step depends on the host's wiring — where a Stop hook writes a transcript pointer — configured in the repo or in the operator's own host settings — the adapter finds it unaided; with no pointer written, the caller names the transcript with `--transcript <path>`. Either way the figures are read, never guessed. The remaining manual seam is operator-metered roles only — closing it depends on the host giving a session a way to read its own usage, which conversational surfaces generally do not today. **Known gap — now partly closed:** tranche-wide operator-metered turns with no task PR to report into no longer lack a destination across the board. A Planner plan-act session outside a plan PR now reports into a comment on the pinned lessons Issue — the existing forge object, never a new one (`roles/planner.md` "Turn-end: report your tokens, don't append them"). A Planner dispatch-act session already has a destination when a plan PR exists — the same plan PR the plan act reports into — unchanged by this fix. The Archivist's own `<task-id>: archive` row was never actually homeless either: `vinaya archive` folds the Archivist's `Tokens: …` line into the same provenance comment it posts on the merged task PR (`roles/archivist.md` "The provenance block") — a different fact from the narrower Studio live-read caveat that same file still carries, which is about re-deriving ledger totals from a PR's own body/comments, not about where the row is written. What remains genuinely open: a dispatch-act session that ends with no PR of any kind yet to write into — mid-dispatch, before a plan PR exists — still has nowhere durable to report; it falls back to an ephemeral report to the Principal, and that fallback is not fixed here.
|
|
312
312
|
|
|
313
313
|
### The collection adapter AEG ships (one layer-2 instance, not the requirement)
|
|
314
314
|
|