@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
@@ -5,17 +5,17 @@ import { execFileSync as execFileSync4 } from "node:child_process";
5
5
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
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))
@@ -3574,6 +3667,7 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
3574
3667
  }
3575
3668
  // src/lib/diff-evidence.ts
3576
3669
  import { execFileSync as execFileSync2 } from "node:child_process";
3670
+ import { join } from "node:path";
3577
3671
  function fileDiffAgainst(ref, path) {
3578
3672
  let out;
3579
3673
  try {
@@ -3586,6 +3680,55 @@ function fileDiffAgainst(ref, path) {
3586
3680
  }
3587
3681
  return out === "" ? null : out;
3588
3682
  }
3683
+ function revParse(ref) {
3684
+ try {
3685
+ return execFileSync2("git", ["rev-parse", "--verify", ref], {
3686
+ encoding: "utf8",
3687
+ stdio: ["ignore", "pipe", "pipe"]
3688
+ }).trim();
3689
+ } catch {
3690
+ return null;
3691
+ }
3692
+ }
3693
+ function repoRoot() {
3694
+ try {
3695
+ return execFileSync2("git", ["rev-parse", "--show-toplevel"], {
3696
+ encoding: "utf8",
3697
+ stdio: ["ignore", "pipe", "pipe"]
3698
+ }).trim();
3699
+ } catch {
3700
+ return null;
3701
+ }
3702
+ }
3703
+ function changedFiles(base) {
3704
+ let out;
3705
+ try {
3706
+ out = execFileSync2("git", ["diff", "--name-only", `${base}...HEAD`], {
3707
+ encoding: "utf8",
3708
+ stdio: ["ignore", "pipe", "pipe"]
3709
+ }).trim();
3710
+ } catch {
3711
+ return null;
3712
+ }
3713
+ return out === "" ? [] : out.split(`
3714
+ `).map((s) => s.trim()).filter(Boolean);
3715
+ }
3716
+ function resolveChangedFiles(base = process.env.BASE_SHA || "origin/main") {
3717
+ const root = repoRoot();
3718
+ if (root === null)
3719
+ return null;
3720
+ const head = revParse("HEAD");
3721
+ for (const ref of [base, "main"]) {
3722
+ const resolved = revParse(ref);
3723
+ if (resolved === null || resolved === head)
3724
+ continue;
3725
+ const relPaths = changedFiles(ref);
3726
+ if (relPaths === null)
3727
+ continue;
3728
+ return relPaths.map((p) => join(root, p));
3729
+ }
3730
+ return null;
3731
+ }
3589
3732
 
3590
3733
  // src/checks/contract.ts
3591
3734
  var CHECK_SCHEMA_VERSION = 1;
@@ -3598,7 +3741,7 @@ function emitCheckError(error) {
3598
3741
  import { execFileSync as execFileSync3 } from "node:child_process";
3599
3742
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3600
3743
  import { homedir } from "node:os";
3601
- import { dirname, join } from "node:path";
3744
+ import { dirname, join as join2 } from "node:path";
3602
3745
  import { z } from "zod";
3603
3746
 
3604
3747
  // src/lib/agent-vendors.ts
@@ -3687,8 +3830,15 @@ function isSafeRepoRelPath(p) {
3687
3830
  var SafeRepoRelPath = z.string().refine(isSafeRepoRelPath, {
3688
3831
  message: "must be a repo-root-relative path with no `..` segment or absolute root"
3689
3832
  });
3833
+ var CANONICAL_HOOK_BLOCK_PREFIXES = [".git/", ".husky/", ".vinaya/hooks/", ".claude/hooks/"];
3834
+ function isCanonicalHookBlockPath(p) {
3835
+ return CANONICAL_HOOK_BLOCK_PREFIXES.some((prefix) => p.startsWith(prefix) && p.length > prefix.length);
3836
+ }
3837
+ var ManagedHookBlockPath = SafeRepoRelPath.refine(isCanonicalHookBlockPath, {
3838
+ message: `must start with one of ${CANONICAL_HOOK_BLOCK_PREFIXES.join(", ")} (byte-exact, case-sensitive)`
3839
+ });
3690
3840
  var ManagedBlockRecordSchema = z.object({
3691
- path: SafeRepoRelPath,
3841
+ path: ManagedHookBlockPath,
3692
3842
  marker: z.string(),
3693
3843
  comment: z.enum(["hash", "html"])
3694
3844
  });
@@ -3719,16 +3869,16 @@ var VinayaConfigSchema = z.object({
3719
3869
  legacySlugDir: z.string().min(1).optional()
3720
3870
  }).optional()
3721
3871
  });
3722
- var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
3723
- var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
3872
+ var GLOBAL_VINAYA_HOME = join2(homedir(), ".vinaya");
3873
+ var GLOBAL_CONFIG_PATH = join2(GLOBAL_VINAYA_HOME, "config.json");
3724
3874
  var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
3725
3875
  function findLocalConfig() {
3726
3876
  let dir = process.cwd();
3727
3877
  while (true) {
3728
- const candidate = join(dir, LOCAL_CONFIG_FILENAME);
3878
+ const candidate = join2(dir, LOCAL_CONFIG_FILENAME);
3729
3879
  if (existsSync(candidate))
3730
3880
  return candidate;
3731
- if (existsSync(join(dir, ".git")))
3881
+ if (existsSync(join2(dir, ".git")))
3732
3882
  return null;
3733
3883
  const parent = dirname(dir);
3734
3884
  if (parent === dir)
@@ -3871,7 +4021,7 @@ function git(args) {
3871
4021
  return "";
3872
4022
  }
3873
4023
  }
3874
- function changedFiles(base) {
4024
+ function changedFiles2(base) {
3875
4025
  return git(["diff", "--name-only", `${base}...HEAD`]).split(`
3876
4026
  `).map((s) => s.trim()).filter(Boolean);
3877
4027
  }
@@ -3908,10 +4058,10 @@ function main() {
3908
4058
  }
3909
4059
  const base = process.env.BASE_SHA || "origin/main";
3910
4060
  let ref = base;
3911
- let changed = changedFiles(ref);
4061
+ let changed = changedFiles2(ref);
3912
4062
  if (changed.length === 0) {
3913
4063
  ref = "main";
3914
- changed = changedFiles(ref);
4064
+ changed = changedFiles2(ref);
3915
4065
  }
3916
4066
  if (changed.length === 0)
3917
4067
  process.exit(0);
@@ -5,17 +5,17 @@ import { execFileSync as execFileSync4 } from "node:child_process";
5
5
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
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))
@@ -3574,6 +3667,7 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
3574
3667
  }
3575
3668
  // src/lib/diff-evidence.ts
3576
3669
  import { execFileSync as execFileSync2 } from "node:child_process";
3670
+ import { join } from "node:path";
3577
3671
  function fileDiffAgainst(ref, path) {
3578
3672
  let out;
3579
3673
  try {
@@ -3586,6 +3680,55 @@ function fileDiffAgainst(ref, path) {
3586
3680
  }
3587
3681
  return out === "" ? null : out;
3588
3682
  }
3683
+ function revParse(ref) {
3684
+ try {
3685
+ return execFileSync2("git", ["rev-parse", "--verify", ref], {
3686
+ encoding: "utf8",
3687
+ stdio: ["ignore", "pipe", "pipe"]
3688
+ }).trim();
3689
+ } catch {
3690
+ return null;
3691
+ }
3692
+ }
3693
+ function repoRoot() {
3694
+ try {
3695
+ return execFileSync2("git", ["rev-parse", "--show-toplevel"], {
3696
+ encoding: "utf8",
3697
+ stdio: ["ignore", "pipe", "pipe"]
3698
+ }).trim();
3699
+ } catch {
3700
+ return null;
3701
+ }
3702
+ }
3703
+ function changedFiles(base) {
3704
+ let out;
3705
+ try {
3706
+ out = execFileSync2("git", ["diff", "--name-only", `${base}...HEAD`], {
3707
+ encoding: "utf8",
3708
+ stdio: ["ignore", "pipe", "pipe"]
3709
+ }).trim();
3710
+ } catch {
3711
+ return null;
3712
+ }
3713
+ return out === "" ? [] : out.split(`
3714
+ `).map((s) => s.trim()).filter(Boolean);
3715
+ }
3716
+ function resolveChangedFiles(base = process.env.BASE_SHA || "origin/main") {
3717
+ const root = repoRoot();
3718
+ if (root === null)
3719
+ return null;
3720
+ const head = revParse("HEAD");
3721
+ for (const ref of [base, "main"]) {
3722
+ const resolved = revParse(ref);
3723
+ if (resolved === null || resolved === head)
3724
+ continue;
3725
+ const relPaths = changedFiles(ref);
3726
+ if (relPaths === null)
3727
+ continue;
3728
+ return relPaths.map((p) => join(root, p));
3729
+ }
3730
+ return null;
3731
+ }
3589
3732
 
3590
3733
  // src/checks/contract.ts
3591
3734
  var CHECK_SCHEMA_VERSION = 1;
@@ -3598,7 +3741,7 @@ function emitCheckError(error) {
3598
3741
  import { execFileSync as execFileSync3 } from "node:child_process";
3599
3742
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3600
3743
  import { homedir } from "node:os";
3601
- import { dirname, join } from "node:path";
3744
+ import { dirname, join as join2 } from "node:path";
3602
3745
  import { z } from "zod";
3603
3746
 
3604
3747
  // src/lib/agent-vendors.ts
@@ -3687,8 +3830,15 @@ function isSafeRepoRelPath(p) {
3687
3830
  var SafeRepoRelPath = z.string().refine(isSafeRepoRelPath, {
3688
3831
  message: "must be a repo-root-relative path with no `..` segment or absolute root"
3689
3832
  });
3833
+ var CANONICAL_HOOK_BLOCK_PREFIXES = [".git/", ".husky/", ".vinaya/hooks/", ".claude/hooks/"];
3834
+ function isCanonicalHookBlockPath(p) {
3835
+ return CANONICAL_HOOK_BLOCK_PREFIXES.some((prefix) => p.startsWith(prefix) && p.length > prefix.length);
3836
+ }
3837
+ var ManagedHookBlockPath = SafeRepoRelPath.refine(isCanonicalHookBlockPath, {
3838
+ message: `must start with one of ${CANONICAL_HOOK_BLOCK_PREFIXES.join(", ")} (byte-exact, case-sensitive)`
3839
+ });
3690
3840
  var ManagedBlockRecordSchema = z.object({
3691
- path: SafeRepoRelPath,
3841
+ path: ManagedHookBlockPath,
3692
3842
  marker: z.string(),
3693
3843
  comment: z.enum(["hash", "html"])
3694
3844
  });
@@ -3719,16 +3869,16 @@ var VinayaConfigSchema = z.object({
3719
3869
  legacySlugDir: z.string().min(1).optional()
3720
3870
  }).optional()
3721
3871
  });
3722
- var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
3723
- var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
3872
+ var GLOBAL_VINAYA_HOME = join2(homedir(), ".vinaya");
3873
+ var GLOBAL_CONFIG_PATH = join2(GLOBAL_VINAYA_HOME, "config.json");
3724
3874
  var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
3725
3875
  function findLocalConfig() {
3726
3876
  let dir = process.cwd();
3727
3877
  while (true) {
3728
- const candidate = join(dir, LOCAL_CONFIG_FILENAME);
3878
+ const candidate = join2(dir, LOCAL_CONFIG_FILENAME);
3729
3879
  if (existsSync(candidate))
3730
3880
  return candidate;
3731
- if (existsSync(join(dir, ".git")))
3881
+ if (existsSync(join2(dir, ".git")))
3732
3882
  return null;
3733
3883
  const parent = dirname(dir);
3734
3884
  if (parent === dir)
@@ -3871,7 +4021,7 @@ function git(args) {
3871
4021
  return "";
3872
4022
  }
3873
4023
  }
3874
- function changedFiles(base) {
4024
+ function changedFiles2(base) {
3875
4025
  return git(["diff", "--name-only", `${base}...HEAD`]).split(`
3876
4026
  `).map((s) => s.trim()).filter(Boolean);
3877
4027
  }
@@ -3930,10 +4080,10 @@ function waiverActive() {
3930
4080
  function main() {
3931
4081
  const base = process.env.BASE_SHA || "origin/main";
3932
4082
  let ref = base;
3933
- let changed = changedFiles(ref);
4083
+ let changed = changedFiles2(ref);
3934
4084
  if (changed.length === 0) {
3935
4085
  ref = "main";
3936
- changed = changedFiles(ref);
4086
+ changed = changedFiles2(ref);
3937
4087
  }
3938
4088
  if (changed.length === 0) {
3939
4089
  process.exit(0);