@attalabs/vinaya 0.19.3 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +7 -0
  2. package/aeg-root/contracts/archivist-tranche-archivist.md +2 -2
  3. package/aeg-root/contracts/tranche-archivist-planner.md +8 -8
  4. package/aeg-root/enforcement.md +6 -4
  5. package/aeg-root/process.md +5 -5
  6. package/aeg-root/roles/archivist.md +9 -10
  7. package/aeg-root/roles/brief-author.md +1 -1
  8. package/aeg-root/roles/developer.md +1 -1
  9. package/aeg-root/roles/planner.md +1 -1
  10. package/aeg-root/roles/principal.md +1 -1
  11. package/aeg-root/roles/tranche-archivist.md +3 -16
  12. package/aeg-root/skills/aeg/SKILL.md +30 -1
  13. package/aeg-root/skills/aeg-roles/SKILL.md +1 -1
  14. package/aeg-root/skills/brief-authoring/SKILL.md +2 -2
  15. package/aeg-root/state-machine.md +8 -6
  16. package/aeg-root/task-model.md +1 -1
  17. package/aeg-root/templates/pr-report-template.md +4 -0
  18. package/dist/checks/bin/check-body-bare-digits.js +192 -27
  19. package/dist/checks/bin/check-branch-topology.js +518 -11
  20. package/dist/checks/bin/check-brief-shape.js +104 -11
  21. package/dist/checks/bin/check-closes-n.js +518 -11
  22. package/dist/checks/bin/check-coherence.js +526 -12
  23. package/dist/checks/bin/check-dead-branch-push.js +104 -11
  24. package/dist/checks/bin/check-dispatch-readiness.js +621 -14
  25. package/dist/checks/bin/check-doc-coverage-push.js +170 -20
  26. package/dist/checks/bin/check-doc-coverage.js +170 -20
  27. package/dist/checks/bin/check-doctrine-portability.js +112 -12
  28. package/dist/checks/bin/check-evidence-fresh.js +213 -20
  29. package/dist/checks/bin/check-first-push-dispatch.js +526 -12
  30. package/dist/checks/bin/check-issue-assignment.js +518 -11
  31. package/dist/checks/bin/check-main-branch-refusal.js +3724 -0
  32. package/dist/checks/bin/check-no-disk-state.js +104 -11
  33. package/dist/checks/bin/check-reader-resolvable-prose.js +186 -17
  34. package/dist/checks/bin/check-registry-gates.js +185 -16
  35. package/dist/checks/bin/check-retired-vocabulary.js +185 -16
  36. package/dist/checks/bin/check-review-gate.js +112 -12
  37. package/dist/checks/bin/check-single-plan-pr.js +104 -11
  38. package/dist/checks/bin/check-test-plan.js +104 -11
  39. package/dist/checks/bin/check-workspace-escape.js +104 -11
  40. package/dist/index.js +664 -56
  41. package/package.json +1 -1
  42. package/studio-standalone/_node_modules/@attalabs/aeg-core/bin/verify-coherence.ts +1089 -0
  43. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  44. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  45. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  46. package/studio-standalone/apps/vinaya-studio/web/.next/required-server-files.json +5 -0
  47. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  48. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  49. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  50. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  51. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  52. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  53. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  54. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  55. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  56. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  57. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js +1 -1
  58. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
  59. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  60. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  61. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  63. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  66. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  67. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
  72. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  81. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  82. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  83. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/{[externals]__0pvgf28._.js → [externals]__1agj1ww._.js} +2 -2
  84. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__02a-3g8._.js +1 -1
  85. 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
  86. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0053k9k._.js +1 -1
  87. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
  88. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
  89. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
  90. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__03jepya._.js → [root-of-the-server]__16cuydh._.js} +1 -1
  91. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
  92. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
  93. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
  94. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
  95. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
  96. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
  97. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
  98. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  99. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  100. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  101. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
  102. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3noqvds-2bvrd.js → 0ea8-8nopz29h.js} +1 -1
  103. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0la0hhmjprdxm.css +1 -0
  104. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1lk7h-0buf4ab.js +1 -0
  105. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3gehliafvmjo9.js → 2twnwe77d4n-m.js} +1 -1
  106. package/studio-standalone/apps/vinaya-studio/web/server.js +1 -1
  107. package/aeg-root/coordination.md +0 -292
  108. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/2iysedx-n06xc.js +0 -1
  109. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/42wxpzjhw7oy4.css +0 -1
  110. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5Lv83SnT--7YJDjSbxona → b2VfZK2AItZwlghK_pUN0}/_buildManifest.js +0 -0
  111. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5Lv83SnT--7YJDjSbxona → b2VfZK2AItZwlghK_pUN0}/_clientMiddlewareManifest.js +0 -0
  112. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5Lv83SnT--7YJDjSbxona → b2VfZK2AItZwlghK_pUN0}/_ssgManifest.js +0 -0
@@ -6,17 +6,17 @@ import { existsSync as existsSync3, readdirSync, readFileSync, statSync } from "
6
6
  import matter2 from "gray-matter";
7
7
  // ../../packages/aeg-core/src/gate-audience.ts
8
8
  var GATE_AUDIENCE = {
9
- "check-branch-topology": { shippedAs: "branch-topology" },
10
- "check-first-push-dispatch": { shippedAs: "first-push-dispatch" },
11
- "check-no-disk-state": { shippedAs: "no-disk-state" },
12
- "verify-brief": { shippedAs: "brief-shape" },
13
- "verify-coherence": { shippedAs: "coherence" },
14
- "verify-dispatch": { shippedAs: "dispatch-readiness" },
15
- "verify-docs": { shippedAs: ["doc-coverage", "doc-coverage-push"] },
16
- "verify-registry": { shippedAs: "registry-gates" },
17
- "verify-review-gate": { shippedAs: "review-gate" },
18
- "verify-single-plan-pr": { shippedAs: "single-plan-pr" },
19
- "verify-test-plan": { shippedAs: "test-plan" },
9
+ "check-branch-topology": { shippedAs: "branch-topology", ring: 0 },
10
+ "check-first-push-dispatch": { shippedAs: "first-push-dispatch", ring: 0 },
11
+ "check-no-disk-state": { shippedAs: "no-disk-state", ring: 0 },
12
+ "verify-brief": { shippedAs: "brief-shape", ring: 0 },
13
+ "verify-coherence": { shippedAs: "coherence", ring: 0 },
14
+ "verify-dispatch": { shippedAs: "dispatch-readiness", ring: 0 },
15
+ "verify-docs": { shippedAs: ["doc-coverage", "doc-coverage-push"], ring: 0 },
16
+ "verify-registry": { shippedAs: "registry-gates", ring: 0 },
17
+ "verify-review-gate": { shippedAs: "review-gate", ring: 1 },
18
+ "verify-single-plan-pr": { shippedAs: "single-plan-pr", ring: 0 },
19
+ "verify-test-plan": { shippedAs: "test-plan", ring: 1 },
20
20
  "check-direct-main-push": {
21
21
  internal: "Reaches adopters through `vinaya audit --only=direct-push`, not the check registry: it is a ring-2 sweep over merge history keyed on `GITHUB_SHA`, run by the generated archivist job on push to the default branch. It has no diff to key on, so there is nothing for `vinaya check` to run it against."
22
22
  },
@@ -328,6 +328,13 @@ var LABELS = [
328
328
  form: "literal",
329
329
  carries: "Execution is halted pending an external unblock; wins over every other derived status."
330
330
  },
331
+ {
332
+ key: "backlog",
333
+ id: "vinaya/backlog",
334
+ category: "state",
335
+ form: "literal",
336
+ carries: "The Issue is deliberately unplanned — belongs to no tranche and is excluded from dispatch, until a Planner promotes it."
337
+ },
331
338
  {
332
339
  key: "tier-0",
333
340
  id: "vinaya/tier:0",
@@ -1986,7 +1993,59 @@ function overrideActive(opts) {
1986
1993
  return false;
1987
1994
  }
1988
1995
  // ../../packages/aeg-core/src/premise-check.ts
1996
+ import { createHash } from "node:crypto";
1989
1997
  var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
1998
+ function isPremiseHeader(line) {
1999
+ const stripped = line.replace(/[*#]/g, "").trim();
2000
+ return /^premise\s*:?$/i.test(stripped);
2001
+ }
2002
+ var PREMISE_LINE = /^[-*]\s*(\S+)\s+(contains|absent|sha256)\s*:\s*(.+)$/i;
2003
+ function parsePremiseBlock(prBody) {
2004
+ const searchIn = anchoredRegion(prBody, "PREMISE") ?? prBody;
2005
+ const lines = searchIn.split(/\r?\n/);
2006
+ const assertions = [];
2007
+ let inBlock = false;
2008
+ for (const raw of lines) {
2009
+ const line = raw.trim();
2010
+ if (!inBlock) {
2011
+ if (isPremiseHeader(line))
2012
+ inBlock = true;
2013
+ continue;
2014
+ }
2015
+ if (line === "")
2016
+ break;
2017
+ const m = line.match(PREMISE_LINE);
2018
+ if (!m)
2019
+ break;
2020
+ const [, path, kindRaw, value] = m;
2021
+ const kind = kindRaw.toLowerCase();
2022
+ if (!ASSERTION_KINDS.has(kind))
2023
+ continue;
2024
+ assertions.push({ kind, path, value: value.trim() });
2025
+ }
2026
+ return assertions;
2027
+ }
2028
+ function checkPremises(assertions, fileReader) {
2029
+ const failures = [];
2030
+ for (const a of assertions) {
2031
+ const content = fileReader(a.path);
2032
+ if (content === null) {
2033
+ failures.push(`premise-check: ${a.path} does not exist on disk (premise asserted \`${a.kind}: ${a.value}\`) — the surface moved since this brief was authored; re-dig before proceeding.`);
2034
+ continue;
2035
+ }
2036
+ if (a.kind === "contains" && !content.includes(a.value)) {
2037
+ failures.push(`premise-check: ${a.path} no longer contains "${a.value}" — the premise this brief pinned has moved; re-dig before proceeding.`);
2038
+ } else if (a.kind === "absent" && content.includes(a.value)) {
2039
+ failures.push(`premise-check: ${a.path} now contains "${a.value}", but the brief pinned it absent — the premise has moved; re-dig before proceeding.`);
2040
+ } else if (a.kind === "sha256") {
2041
+ const actual = createHash("sha256").update(content).digest("hex");
2042
+ if (actual !== a.value.toLowerCase()) {
2043
+ failures.push(`premise-check: ${a.path} sha256 mismatch (brief pinned ${a.value}, file is now ${actual}) — the file changed since this brief was authored; re-dig before proceeding.`);
2044
+ }
2045
+ }
2046
+ }
2047
+ return { pass: failures.length === 0, failures };
2048
+ }
1990
2049
 
1991
2050
  // ../../packages/aeg-core/src/test-plan-section.ts
1992
2051
  var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
@@ -2790,6 +2849,7 @@ function checkG1(rows, existsFn) {
2790
2849
  }
2791
2850
  return { check: "G1", status: findings.length > 0 ? "fail" : "pass", findings };
2792
2851
  }
2852
+ var SCAFFOLD_PLACEHOLDER = "[undocumented — fill in why]";
2793
2853
  function checkG2(rows, candidateFiles) {
2794
2854
  const implementations = new Set(rows.map((r) => r.implementation).filter((p) => p !== ""));
2795
2855
  const findings = [];
@@ -2801,6 +2861,16 @@ function checkG2(rows, candidateFiles) {
2801
2861
  });
2802
2862
  }
2803
2863
  }
2864
+ for (const row of rows) {
2865
+ const carriesPlaceholder = [row.summary, row.description, row.spec].some((cell) => cell === SCAFFOLD_PLACEHOLDER);
2866
+ if (carriesPlaceholder) {
2867
+ findings.push({
2868
+ row: row.action,
2869
+ path: row.implementation,
2870
+ reason: `${row.ring} row "${row.action}" still carries the scaffold placeholder marker — the why is owed`
2871
+ });
2872
+ }
2873
+ }
2804
2874
  return { check: "G2", status: findings.length > 0 ? "info" : "pass", findings };
2805
2875
  }
2806
2876
  function checkG3(ring0Rows, crossingFiles) {
@@ -3320,6 +3390,29 @@ function isNewDiskStateFile(path, status) {
3320
3390
  return false;
3321
3391
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
3322
3392
  }
3393
+ // ../../packages/aeg-core/src/main-branch-refusal.ts
3394
+ function checkMainBranchRefusal(facts) {
3395
+ const { currentSymbolicBranch, defaultBranch } = facts;
3396
+ if (currentSymbolicBranch === null)
3397
+ return null;
3398
+ if (defaultBranch === null) {
3399
+ return {
3400
+ reason: "default-branch-undetermined",
3401
+ severity: "warning",
3402
+ currentBranch: currentSymbolicBranch,
3403
+ defaultBranch: null
3404
+ };
3405
+ }
3406
+ if (currentSymbolicBranch === defaultBranch) {
3407
+ return {
3408
+ reason: "on-default-branch",
3409
+ severity: "error",
3410
+ currentBranch: currentSymbolicBranch,
3411
+ defaultBranch
3412
+ };
3413
+ }
3414
+ return null;
3415
+ }
3323
3416
  // ../../packages/aeg-core/src/branch-topology-gate.ts
3324
3417
  function taskBranchTopologyFields(branch) {
3325
3418
  if (!/^task\/.*\/.*$/.test(branch))
@@ -3609,8 +3702,8 @@ var BIN_EXT = BIN_DIR === DIST_BIN_DIR ? ".js" : ".ts";
3609
3702
  function bin(name) {
3610
3703
  return join2(BIN_DIR, `${name}${BIN_EXT}`);
3611
3704
  }
3612
- function coreCheckRegistry() {
3613
- return [
3705
+ var REGISTRY = [
3706
+ [
3614
3707
  {
3615
3708
  name: "brief-shape",
3616
3709
  run: bin("check-brief-shape"),
@@ -3621,6 +3714,9 @@ function coreCheckRegistry() {
3621
3714
  BRANCH: { optional: true }
3622
3715
  }
3623
3716
  },
3717
+ 0
3718
+ ],
3719
+ [
3624
3720
  {
3625
3721
  name: "doc-coverage",
3626
3722
  run: bin("check-doc-coverage"),
@@ -3636,6 +3732,9 @@ function coreCheckRegistry() {
3636
3732
  GH_TOKEN: { optional: true }
3637
3733
  }
3638
3734
  },
3735
+ 0
3736
+ ],
3737
+ [
3639
3738
  {
3640
3739
  name: "coherence",
3641
3740
  run: bin("check-coherence"),
@@ -3648,6 +3747,9 @@ function coreCheckRegistry() {
3648
3747
  GH_TOKEN: { optional: true }
3649
3748
  }
3650
3749
  },
3750
+ 0
3751
+ ],
3752
+ [
3651
3753
  {
3652
3754
  name: "dispatch-readiness",
3653
3755
  run: bin("check-dispatch-readiness"),
@@ -3657,9 +3759,13 @@ function coreCheckRegistry() {
3657
3759
  AEG_REPO: { optional: true },
3658
3760
  BRANCH: { optional: true },
3659
3761
  GITHUB_TOKEN: { optional: true },
3660
- GH_TOKEN: { optional: true }
3762
+ GH_TOKEN: { optional: true },
3763
+ PREMISE_FILE: { optional: true }
3661
3764
  }
3662
3765
  },
3766
+ 0
3767
+ ],
3768
+ [
3663
3769
  {
3664
3770
  name: "closes-n",
3665
3771
  run: bin("check-closes-n"),
@@ -3674,6 +3780,9 @@ function coreCheckRegistry() {
3674
3780
  GH_TOKEN: { optional: true }
3675
3781
  }
3676
3782
  },
3783
+ 1
3784
+ ],
3785
+ [
3677
3786
  {
3678
3787
  name: "single-plan-pr",
3679
3788
  run: bin("check-single-plan-pr"),
@@ -3686,6 +3795,9 @@ function coreCheckRegistry() {
3686
3795
  GH_TOKEN: { optional: true }
3687
3796
  }
3688
3797
  },
3798
+ 0
3799
+ ],
3800
+ [
3689
3801
  {
3690
3802
  name: "test-plan",
3691
3803
  run: bin("check-test-plan"),
@@ -3697,6 +3809,9 @@ function coreCheckRegistry() {
3697
3809
  BRANCH: { optional: true }
3698
3810
  }
3699
3811
  },
3812
+ 1
3813
+ ],
3814
+ [
3700
3815
  {
3701
3816
  name: "body-bare-digits",
3702
3817
  run: bin("check-body-bare-digits"),
@@ -3712,6 +3827,9 @@ function coreCheckRegistry() {
3712
3827
  GH_TOKEN: { optional: true }
3713
3828
  }
3714
3829
  },
3830
+ 1
3831
+ ],
3832
+ [
3715
3833
  {
3716
3834
  name: "no-disk-state",
3717
3835
  run: bin("check-no-disk-state"),
@@ -3719,6 +3837,9 @@ function coreCheckRegistry() {
3719
3837
  timeoutMs: 15000,
3720
3838
  env: { BASE_SHA: { optional: true } }
3721
3839
  },
3840
+ 0
3841
+ ],
3842
+ [
3722
3843
  {
3723
3844
  name: "registry-gates",
3724
3845
  run: bin("check-registry-gates"),
@@ -3730,6 +3851,9 @@ function coreCheckRegistry() {
3730
3851
  GH_TOKEN: { optional: true }
3731
3852
  }
3732
3853
  },
3854
+ 0
3855
+ ],
3856
+ [
3733
3857
  {
3734
3858
  name: "review-gate",
3735
3859
  run: bin("check-review-gate"),
@@ -3743,6 +3867,9 @@ function coreCheckRegistry() {
3743
3867
  GH_TOKEN: { optional: true }
3744
3868
  }
3745
3869
  },
3870
+ 1
3871
+ ],
3872
+ [
3746
3873
  {
3747
3874
  name: "branch-topology",
3748
3875
  run: bin("check-branch-topology"),
@@ -3755,6 +3882,9 @@ function coreCheckRegistry() {
3755
3882
  GH_TOKEN: { optional: true }
3756
3883
  }
3757
3884
  },
3885
+ 0
3886
+ ],
3887
+ [
3758
3888
  {
3759
3889
  name: "dead-branch-push",
3760
3890
  run: bin("check-dead-branch-push"),
@@ -3766,6 +3896,9 @@ function coreCheckRegistry() {
3766
3896
  GH_TOKEN: { optional: true }
3767
3897
  }
3768
3898
  },
3899
+ 0
3900
+ ],
3901
+ [
3769
3902
  {
3770
3903
  name: "first-push-dispatch",
3771
3904
  run: bin("check-first-push-dispatch"),
@@ -3778,6 +3911,9 @@ function coreCheckRegistry() {
3778
3911
  GH_TOKEN: { optional: true }
3779
3912
  }
3780
3913
  },
3914
+ 0
3915
+ ],
3916
+ [
3781
3917
  {
3782
3918
  name: "doc-coverage-push",
3783
3919
  run: bin("check-doc-coverage-push"),
@@ -3795,6 +3931,9 @@ function coreCheckRegistry() {
3795
3931
  GH_TOKEN: { optional: true }
3796
3932
  }
3797
3933
  },
3934
+ 0
3935
+ ],
3936
+ [
3798
3937
  {
3799
3938
  name: "issue-assignment",
3800
3939
  run: bin("check-issue-assignment"),
@@ -3807,6 +3946,9 @@ function coreCheckRegistry() {
3807
3946
  GH_TOKEN: { optional: true }
3808
3947
  }
3809
3948
  },
3949
+ 0
3950
+ ],
3951
+ [
3810
3952
  {
3811
3953
  name: "evidence-fresh",
3812
3954
  run: bin("check-evidence-fresh"),
@@ -3821,6 +3963,9 @@ function coreCheckRegistry() {
3821
3963
  GH_TOKEN: { optional: true }
3822
3964
  }
3823
3965
  },
3966
+ 1
3967
+ ],
3968
+ [
3824
3969
  {
3825
3970
  name: "reader-resolvable-prose",
3826
3971
  run: bin("check-reader-resolvable-prose"),
@@ -3828,6 +3973,9 @@ function coreCheckRegistry() {
3828
3973
  timeoutMs: 30000,
3829
3974
  env: {}
3830
3975
  },
3976
+ 0
3977
+ ],
3978
+ [
3831
3979
  {
3832
3980
  name: "retired-vocabulary",
3833
3981
  run: bin("check-retired-vocabulary"),
@@ -3835,6 +3983,9 @@ function coreCheckRegistry() {
3835
3983
  timeoutMs: 30000,
3836
3984
  env: {}
3837
3985
  },
3986
+ 0
3987
+ ],
3988
+ [
3838
3989
  {
3839
3990
  name: "doctrine-portability",
3840
3991
  run: bin("check-doctrine-portability"),
@@ -3842,15 +3993,33 @@ function coreCheckRegistry() {
3842
3993
  timeoutMs: 30000,
3843
3994
  env: { BASE_SHA: { optional: true } }
3844
3995
  },
3996
+ 0
3997
+ ],
3998
+ [
3845
3999
  {
3846
4000
  name: "workspace-escape",
3847
4001
  run: bin("check-workspace-escape"),
3848
4002
  scope: "full",
3849
4003
  timeoutMs: 30000,
3850
4004
  env: {}
3851
- }
3852
- ];
4005
+ },
4006
+ 0
4007
+ ],
4008
+ [
4009
+ {
4010
+ name: "main-branch-refusal",
4011
+ run: bin("check-main-branch-refusal"),
4012
+ scope: "full",
4013
+ timeoutMs: 15000,
4014
+ env: {}
4015
+ },
4016
+ 0
4017
+ ]
4018
+ ];
4019
+ function coreCheckRegistry() {
4020
+ return REGISTRY.map(([spec]) => spec);
3853
4021
  }
4022
+ var CORE_CHECK_RING = Object.fromEntries(REGISTRY.map(([spec, ring]) => [spec.name, ring]));
3854
4023
 
3855
4024
  // src/checks/bin/check-registry-gates.ts
3856
4025
  var CHECK_NAME = "registry-gates";
@@ -2,20 +2,20 @@
2
2
 
3
3
  // src/checks/bin/check-retired-vocabulary.ts
4
4
  import { readdirSync as readdirSync2, readFileSync as readFileSync3, statSync } from "node:fs";
5
- import { join as join4 } from "node:path";
5
+ import { join as join5, resolve } from "node:path";
6
6
  // ../../packages/aeg-core/src/gate-audience.ts
7
7
  var GATE_AUDIENCE = {
8
- "check-branch-topology": { shippedAs: "branch-topology" },
9
- "check-first-push-dispatch": { shippedAs: "first-push-dispatch" },
10
- "check-no-disk-state": { shippedAs: "no-disk-state" },
11
- "verify-brief": { shippedAs: "brief-shape" },
12
- "verify-coherence": { shippedAs: "coherence" },
13
- "verify-dispatch": { shippedAs: "dispatch-readiness" },
14
- "verify-docs": { shippedAs: ["doc-coverage", "doc-coverage-push"] },
15
- "verify-registry": { shippedAs: "registry-gates" },
16
- "verify-review-gate": { shippedAs: "review-gate" },
17
- "verify-single-plan-pr": { shippedAs: "single-plan-pr" },
18
- "verify-test-plan": { shippedAs: "test-plan" },
8
+ "check-branch-topology": { shippedAs: "branch-topology", ring: 0 },
9
+ "check-first-push-dispatch": { shippedAs: "first-push-dispatch", ring: 0 },
10
+ "check-no-disk-state": { shippedAs: "no-disk-state", ring: 0 },
11
+ "verify-brief": { shippedAs: "brief-shape", ring: 0 },
12
+ "verify-coherence": { shippedAs: "coherence", ring: 0 },
13
+ "verify-dispatch": { shippedAs: "dispatch-readiness", ring: 0 },
14
+ "verify-docs": { shippedAs: ["doc-coverage", "doc-coverage-push"], ring: 0 },
15
+ "verify-registry": { shippedAs: "registry-gates", ring: 0 },
16
+ "verify-review-gate": { shippedAs: "review-gate", ring: 1 },
17
+ "verify-single-plan-pr": { shippedAs: "single-plan-pr", ring: 0 },
18
+ "verify-test-plan": { shippedAs: "test-plan", ring: 1 },
19
19
  "check-direct-main-push": {
20
20
  internal: "Reaches adopters through `vinaya audit --only=direct-push`, not the check registry: it is a ring-2 sweep over merge history keyed on `GITHUB_SHA`, run by the generated archivist job on push to the default branch. It has no diff to key on, so there is nothing for `vinaya check` to run it against."
21
21
  },
@@ -327,6 +327,13 @@ var LABELS = [
327
327
  form: "literal",
328
328
  carries: "Execution is halted pending an external unblock; wins over every other derived status."
329
329
  },
330
+ {
331
+ key: "backlog",
332
+ id: "vinaya/backlog",
333
+ category: "state",
334
+ form: "literal",
335
+ carries: "The Issue is deliberately unplanned — belongs to no tranche and is excluded from dispatch, until a Planner promotes it."
336
+ },
330
337
  {
331
338
  key: "tier-0",
332
339
  id: "vinaya/tier:0",
@@ -1985,7 +1992,59 @@ function overrideActive(opts) {
1985
1992
  return false;
1986
1993
  }
1987
1994
  // ../../packages/aeg-core/src/premise-check.ts
1995
+ import { createHash } from "node:crypto";
1988
1996
  var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
1997
+ function isPremiseHeader(line) {
1998
+ const stripped = line.replace(/[*#]/g, "").trim();
1999
+ return /^premise\s*:?$/i.test(stripped);
2000
+ }
2001
+ var PREMISE_LINE = /^[-*]\s*(\S+)\s+(contains|absent|sha256)\s*:\s*(.+)$/i;
2002
+ function parsePremiseBlock(prBody) {
2003
+ const searchIn = anchoredRegion(prBody, "PREMISE") ?? prBody;
2004
+ const lines = searchIn.split(/\r?\n/);
2005
+ const assertions = [];
2006
+ let inBlock = false;
2007
+ for (const raw of lines) {
2008
+ const line = raw.trim();
2009
+ if (!inBlock) {
2010
+ if (isPremiseHeader(line))
2011
+ inBlock = true;
2012
+ continue;
2013
+ }
2014
+ if (line === "")
2015
+ break;
2016
+ const m = line.match(PREMISE_LINE);
2017
+ if (!m)
2018
+ break;
2019
+ const [, path, kindRaw, value] = m;
2020
+ const kind = kindRaw.toLowerCase();
2021
+ if (!ASSERTION_KINDS.has(kind))
2022
+ continue;
2023
+ assertions.push({ kind, path, value: value.trim() });
2024
+ }
2025
+ return assertions;
2026
+ }
2027
+ function checkPremises(assertions, fileReader) {
2028
+ const failures = [];
2029
+ for (const a of assertions) {
2030
+ const content = fileReader(a.path);
2031
+ if (content === null) {
2032
+ failures.push(`premise-check: ${a.path} does not exist on disk (premise asserted \`${a.kind}: ${a.value}\`) — the surface moved since this brief was authored; re-dig before proceeding.`);
2033
+ continue;
2034
+ }
2035
+ if (a.kind === "contains" && !content.includes(a.value)) {
2036
+ failures.push(`premise-check: ${a.path} no longer contains "${a.value}" — the premise this brief pinned has moved; re-dig before proceeding.`);
2037
+ } else if (a.kind === "absent" && content.includes(a.value)) {
2038
+ failures.push(`premise-check: ${a.path} now contains "${a.value}", but the brief pinned it absent — the premise has moved; re-dig before proceeding.`);
2039
+ } else if (a.kind === "sha256") {
2040
+ const actual = createHash("sha256").update(content).digest("hex");
2041
+ if (actual !== a.value.toLowerCase()) {
2042
+ failures.push(`premise-check: ${a.path} sha256 mismatch (brief pinned ${a.value}, file is now ${actual}) — the file changed since this brief was authored; re-dig before proceeding.`);
2043
+ }
2044
+ }
2045
+ }
2046
+ return { pass: failures.length === 0, failures };
2047
+ }
1989
2048
 
1990
2049
  // ../../packages/aeg-core/src/test-plan-section.ts
1991
2050
  var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
@@ -2789,6 +2848,7 @@ function checkG1(rows, existsFn) {
2789
2848
  }
2790
2849
  return { check: "G1", status: findings.length > 0 ? "fail" : "pass", findings };
2791
2850
  }
2851
+ var SCAFFOLD_PLACEHOLDER = "[undocumented — fill in why]";
2792
2852
  function checkG2(rows, candidateFiles) {
2793
2853
  const implementations = new Set(rows.map((r) => r.implementation).filter((p) => p !== ""));
2794
2854
  const findings = [];
@@ -2800,6 +2860,16 @@ function checkG2(rows, candidateFiles) {
2800
2860
  });
2801
2861
  }
2802
2862
  }
2863
+ for (const row of rows) {
2864
+ const carriesPlaceholder = [row.summary, row.description, row.spec].some((cell) => cell === SCAFFOLD_PLACEHOLDER);
2865
+ if (carriesPlaceholder) {
2866
+ findings.push({
2867
+ row: row.action,
2868
+ path: row.implementation,
2869
+ reason: `${row.ring} row "${row.action}" still carries the scaffold placeholder marker — the why is owed`
2870
+ });
2871
+ }
2872
+ }
2803
2873
  return { check: "G2", status: findings.length > 0 ? "info" : "pass", findings };
2804
2874
  }
2805
2875
  function checkG3(ring0Rows, crossingFiles) {
@@ -3319,6 +3389,29 @@ function isNewDiskStateFile(path, status) {
3319
3389
  return false;
3320
3390
  return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
3321
3391
  }
3392
+ // ../../packages/aeg-core/src/main-branch-refusal.ts
3393
+ function checkMainBranchRefusal(facts) {
3394
+ const { currentSymbolicBranch, defaultBranch } = facts;
3395
+ if (currentSymbolicBranch === null)
3396
+ return null;
3397
+ if (defaultBranch === null) {
3398
+ return {
3399
+ reason: "default-branch-undetermined",
3400
+ severity: "warning",
3401
+ currentBranch: currentSymbolicBranch,
3402
+ defaultBranch: null
3403
+ };
3404
+ }
3405
+ if (currentSymbolicBranch === defaultBranch) {
3406
+ return {
3407
+ reason: "on-default-branch",
3408
+ severity: "error",
3409
+ currentBranch: currentSymbolicBranch,
3410
+ defaultBranch
3411
+ };
3412
+ }
3413
+ return null;
3414
+ }
3322
3415
  // ../../packages/aeg-core/src/branch-topology-gate.ts
3323
3416
  function taskBranchTopologyFields(branch) {
3324
3417
  if (!/^task\/.*\/.*$/.test(branch))
@@ -3700,8 +3793,15 @@ function isSafeRepoRelPath(p) {
3700
3793
  var SafeRepoRelPath = z.string().refine(isSafeRepoRelPath, {
3701
3794
  message: "must be a repo-root-relative path with no `..` segment or absolute root"
3702
3795
  });
3796
+ var CANONICAL_HOOK_BLOCK_PREFIXES = [".git/", ".husky/", ".vinaya/hooks/", ".claude/hooks/"];
3797
+ function isCanonicalHookBlockPath(p) {
3798
+ return CANONICAL_HOOK_BLOCK_PREFIXES.some((prefix) => p.startsWith(prefix) && p.length > prefix.length);
3799
+ }
3800
+ var ManagedHookBlockPath = SafeRepoRelPath.refine(isCanonicalHookBlockPath, {
3801
+ message: `must start with one of ${CANONICAL_HOOK_BLOCK_PREFIXES.join(", ")} (byte-exact, case-sensitive)`
3802
+ });
3703
3803
  var ManagedBlockRecordSchema = z.object({
3704
- path: SafeRepoRelPath,
3804
+ path: ManagedHookBlockPath,
3705
3805
  marker: z.string(),
3706
3806
  comment: z.enum(["hash", "html"])
3707
3807
  });
@@ -3882,6 +3982,71 @@ function emitCheckError(error) {
3882
3982
  `);
3883
3983
  }
3884
3984
 
3985
+ // src/lib/diff-evidence.ts
3986
+ import { execFileSync as execFileSync3 } from "node:child_process";
3987
+ import { join as join4 } from "node:path";
3988
+ function fileDiffAgainst(ref, path) {
3989
+ let out;
3990
+ try {
3991
+ out = execFileSync3("git", ["diff", `${ref}...HEAD`, "--", path], {
3992
+ encoding: "utf8",
3993
+ stdio: ["ignore", "pipe", "pipe"]
3994
+ }).trim();
3995
+ } catch {
3996
+ return null;
3997
+ }
3998
+ return out === "" ? null : out;
3999
+ }
4000
+ function revParse(ref) {
4001
+ try {
4002
+ return execFileSync3("git", ["rev-parse", "--verify", ref], {
4003
+ encoding: "utf8",
4004
+ stdio: ["ignore", "pipe", "pipe"]
4005
+ }).trim();
4006
+ } catch {
4007
+ return null;
4008
+ }
4009
+ }
4010
+ function repoRoot() {
4011
+ try {
4012
+ return execFileSync3("git", ["rev-parse", "--show-toplevel"], {
4013
+ encoding: "utf8",
4014
+ stdio: ["ignore", "pipe", "pipe"]
4015
+ }).trim();
4016
+ } catch {
4017
+ return null;
4018
+ }
4019
+ }
4020
+ function changedFiles(base) {
4021
+ let out;
4022
+ try {
4023
+ out = execFileSync3("git", ["diff", "--name-only", `${base}...HEAD`], {
4024
+ encoding: "utf8",
4025
+ stdio: ["ignore", "pipe", "pipe"]
4026
+ }).trim();
4027
+ } catch {
4028
+ return null;
4029
+ }
4030
+ return out === "" ? [] : out.split(`
4031
+ `).map((s) => s.trim()).filter(Boolean);
4032
+ }
4033
+ function resolveChangedFiles(base = process.env.BASE_SHA || "origin/main") {
4034
+ const root = repoRoot();
4035
+ if (root === null)
4036
+ return null;
4037
+ const head = revParse("HEAD");
4038
+ for (const ref of [base, "main"]) {
4039
+ const resolved = revParse(ref);
4040
+ if (resolved === null || resolved === head)
4041
+ continue;
4042
+ const relPaths = changedFiles(ref);
4043
+ if (relPaths === null)
4044
+ continue;
4045
+ return relPaths.map((p) => join4(root, p));
4046
+ }
4047
+ return null;
4048
+ }
4049
+
3885
4050
  // src/checks/bin/check-retired-vocabulary.ts
3886
4051
  var CHECK_NAME = "retired-vocabulary";
3887
4052
  var DOCTRINE_ROOT = loadConfig()?.proseGates?.doctrineRoot ?? resolveDoctrineRoot() ?? "aeg-root";
@@ -3896,7 +4061,7 @@ function collect(dir, out = []) {
3896
4061
  return out;
3897
4062
  }
3898
4063
  for (const name of entries) {
3899
- const full = join4(dir, name);
4064
+ const full = join5(dir, name);
3900
4065
  let isDir;
3901
4066
  try {
3902
4067
  isDir = statSync(full).isDirectory();
@@ -3920,8 +4085,12 @@ function main() {
3920
4085
  const paths = collect(DOCTRINE_ROOT);
3921
4086
  const files = readAll(paths);
3922
4087
  const findings = scanRetiredVocabulary(files);
3923
- console.log(`${CHECK_NAME}: doctrine root "${DOCTRINE_ROOT}"; ${paths.length} file(s) swept; ${findings.length} finding(s)`);
3924
- for (const finding of findings) {
4088
+ const changedFilesList = resolveChangedFiles();
4089
+ const changed = changedFilesList === null ? null : new Set(changedFilesList);
4090
+ const pathBase = repoRoot() ?? process.cwd();
4091
+ const reportable = changed === null ? findings : findings.filter((f) => changed.has(resolve(pathBase, f.file)));
4092
+ console.log(`${CHECK_NAME}: doctrine root "${DOCTRINE_ROOT}"; ${paths.length} file(s) swept; ${findings.length} finding(s), ${reportable.length} in this diff`);
4093
+ for (const finding of reportable) {
3925
4094
  emitCheckError({
3926
4095
  schema: CHECK_SCHEMA_VERSION,
3927
4096
  check: CHECK_NAME,