@attalabs/vinaya 0.19.0 → 0.19.2

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 (93) hide show
  1. package/README.md +37 -1
  2. package/aeg-root/contracts/architect-planner.md +1 -1
  3. package/aeg-root/enforcement.md +3 -2
  4. package/aeg-root/milestone-model.md +75 -0
  5. package/aeg-root/roles/architect.md +4 -4
  6. package/aeg-root/skills/aeg/SKILL.md +1 -1
  7. package/aeg-root/task-model.md +45 -0
  8. package/aeg-root/tranche-model.md +16 -11
  9. package/dist/checks/bin/check-body-bare-digits.js +204 -15
  10. package/dist/checks/bin/check-branch-topology.js +116 -13
  11. package/dist/checks/bin/check-brief-shape.js +116 -13
  12. package/dist/checks/bin/check-closes-n.js +116 -13
  13. package/dist/checks/bin/check-coherence.js +207 -18
  14. package/dist/checks/bin/check-dead-branch-push.js +116 -13
  15. package/dist/checks/bin/check-dispatch-readiness.js +204 -15
  16. package/dist/checks/bin/check-doc-coverage-push.js +208 -19
  17. package/dist/checks/bin/check-doc-coverage.js +208 -19
  18. package/dist/checks/bin/check-evidence-fresh.js +116 -13
  19. package/dist/checks/bin/check-first-push-dispatch.js +204 -15
  20. package/dist/checks/bin/check-issue-assignment.js +116 -13
  21. package/dist/checks/bin/check-no-disk-state.js +116 -13
  22. package/dist/checks/bin/check-reader-resolvable-prose.js +410 -36
  23. package/dist/checks/bin/check-registry-gates.js +116 -13
  24. package/dist/checks/bin/check-retired-vocabulary.js +3595 -0
  25. package/dist/checks/bin/check-review-gate.js +204 -15
  26. package/dist/checks/bin/check-single-plan-pr.js +116 -13
  27. package/dist/checks/bin/check-test-plan.js +116 -13
  28. package/dist/index.js +2362 -1602
  29. package/package.json +1 -1
  30. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  31. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  32. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  33. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  34. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  35. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  36. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  37. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  38. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  39. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  40. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  41. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
  42. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  43. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  44. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  45. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  46. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  47. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  48. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  49. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  50. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  51. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  52. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  53. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  54. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
  55. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  56. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  57. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  58. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  59. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  60. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  61. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  63. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  66. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__0e95dv5._.js +1 -1
  67. 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
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__029-1ch._.js +1 -1
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0ulzsom._.js → [root-of-the-server]__0h3web3._.js} +1 -1
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0q56ohl._.js +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1_ojzp1._.js +1 -1
  72. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1d_8nm4._.js +1 -1
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1zkwtx8._.js +1 -1
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__210ehg9._.js +1 -1
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_00yjcv1._.js +1 -1
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0rix02i._.js +1 -1
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_18-d2be._.js +1 -1
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +5 -5
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1gw6vc9._.js +1 -1
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
  81. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  82. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  83. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  84. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
  85. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2r36w820aqwb9.js → 1hko4y648-9sa.js} +1 -1
  86. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3ocvtlhgckh81.js → 20f41k165euzy.js} +1 -1
  87. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2xoclb4g7d9n7.js → 3mhcu_-shkfgs.js} +1 -1
  88. package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
  89. package/templates/noop-check.template.ts +18 -0
  90. package/templates/role.template.md +20 -0
  91. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{RISz5nirLr1mUfMqzSaFS → Ye7cOzO7rtvyiBouNOFES}/_buildManifest.js +0 -0
  92. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{RISz5nirLr1mUfMqzSaFS → Ye7cOzO7rtvyiBouNOFES}/_clientMiddlewareManifest.js +0 -0
  93. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{RISz5nirLr1mUfMqzSaFS → Ye7cOzO7rtvyiBouNOFES}/_ssgManifest.js +0 -0
@@ -562,6 +562,12 @@ function factsFromLegacyMilestone(milestone) {
562
562
  lifecycle: milestone.state === "closed" ? "complete" : "active"
563
563
  };
564
564
  }
565
+ function resolveLegacyFacts(milestone, labelIssues) {
566
+ if (milestone.state === "closed" && labelIssues.length > 0) {
567
+ return { goal: milestone.description ?? "", lifecycle: lifecycleFromIssues(labelIssues) };
568
+ }
569
+ return factsFromLegacyMilestone(milestone);
570
+ }
565
571
  function lifecycleFromIssues(issues) {
566
572
  if (issues.length === 0)
567
573
  return "planned";
@@ -578,9 +584,9 @@ function goalFromMilestones(milestones, slug) {
578
584
  function findMilestoneForSlug(owner, repo, slug) {
579
585
  const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
580
586
  const legacy = matchesLegacyMilestone(milestones, slug);
581
- if (legacy)
582
- return factsFromLegacyMilestone(legacy);
583
587
  const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
588
+ if (legacy)
589
+ return resolveLegacyFacts(legacy, issues);
584
590
  return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
585
591
  }
586
592
 
@@ -2767,16 +2773,18 @@ function checkDeadBranchPush(input) {
2767
2773
  }
2768
2774
  // ../../packages/aeg-core/src/reader-resolvable-prose.ts
2769
2775
  var SHIPS_PREFIX = "aeg-root/";
2770
- var SHIPS_ARCHIVE_PREFIX = "aeg-root/tranches/completed/";
2776
+ function shipsArchivePrefix(shipsPrefix) {
2777
+ return `${shipsPrefix}tranches/completed/`;
2778
+ }
2771
2779
  function isSpecFile2(path) {
2772
2780
  return path.startsWith("apps/") && path.includes("/specs/") && path.endsWith(".md");
2773
2781
  }
2774
2782
  function isClaudeMdFile(path) {
2775
2783
  return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
2776
2784
  }
2777
- function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix) {
2778
- if (path.startsWith(SHIPS_PREFIX)) {
2779
- return path.startsWith(SHIPS_ARCHIVE_PREFIX) ? "internal" : "ships";
2785
+ function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
2786
+ if (path.startsWith(shipsPrefix)) {
2787
+ return path.startsWith(shipsArchivePrefix(shipsPrefix)) ? "internal" : "ships";
2780
2788
  }
2781
2789
  if (path.startsWith(readerFacingPrefix) && path.endsWith(readerFacingSuffix)) {
2782
2790
  return "reader-facing";
@@ -2811,7 +2819,7 @@ function legacySlugPattern(legacySlugs) {
2811
2819
  const alternation = legacySlugs.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
2812
2820
  return new RegExp(`(^|[^a-zA-Z0-9\\n-])(${alternation})([^a-zA-Z0-9\\n-]|$)`, "g");
2813
2821
  }
2814
- function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
2822
+ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
2815
2823
  const findings = [];
2816
2824
  const legacyPattern = legacySlugPattern(legacySlugs);
2817
2825
  const patterns = [
@@ -2820,7 +2828,7 @@ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuff
2820
2828
  ...legacyPattern ? [{ pattern: legacyPattern, what: "an internal tranche slug", group: 2 }] : []
2821
2829
  ];
2822
2830
  for (const file of files) {
2823
- const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
2831
+ const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
2824
2832
  if (!cls || !SWEPT_CLASSES.has(cls))
2825
2833
  continue;
2826
2834
  const scrubbed = stripNonProse(file.path, file.content);
@@ -2866,10 +2874,10 @@ function definesOrLinksGlossary(content, term) {
2866
2874
  return true;
2867
2875
  return /docs\/glossary|glossary\.md/i.test(content);
2868
2876
  }
2869
- function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix) {
2877
+ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
2870
2878
  const findings = [];
2871
2879
  for (const file of files) {
2872
- const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
2880
+ const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
2873
2881
  if (!cls || !SWEPT_CLASSES.has(cls))
2874
2882
  continue;
2875
2883
  const scrubbed = stripNonProse(file.path, file.content);
@@ -2888,10 +2896,10 @@ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, read
2888
2896
  }
2889
2897
  return findings;
2890
2898
  }
2891
- function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
2899
+ function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
2892
2900
  return [
2893
- ...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs),
2894
- ...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix)
2901
+ ...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs, shipsPrefix),
2902
+ ...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix)
2895
2903
  ];
2896
2904
  }
2897
2905
  function parseGlossaryTerms(glossaryContent) {
@@ -2905,6 +2913,101 @@ function parseGlossaryTerms(glossaryContent) {
2905
2913
  }
2906
2914
  return terms;
2907
2915
  }
2916
+ // ../../packages/aeg-core/src/retired-vocabulary.ts
2917
+ var RETIRED_PATTERNS = [
2918
+ String.raw`\bD-[0-9]{3}\b`,
2919
+ "D-(###|NNN|nnn|xxx)",
2920
+ "decision (entry|logged)",
2921
+ "decision-log entry",
2922
+ "decision log entry",
2923
+ "decision log(s|ged|ging)?([^a-z]|$)",
2924
+ "decision-log",
2925
+ "decision entr",
2926
+ "decisions? (are |is )?logged",
2927
+ "log entries",
2928
+ String.raw`decisions\.md`,
2929
+ "decisions-legacy",
2930
+ "CONTRADICTION",
2931
+ "assumes Tier 3",
2932
+ "Lock: ?YES",
2933
+ "Lock: ?NO",
2934
+ "lock approvals?",
2935
+ "approves locks",
2936
+ "Conforms to lock",
2937
+ "Challenges lock",
2938
+ "checkDecisionNumbersFresh",
2939
+ String.raw`roles/team-leader\.md`,
2940
+ String.raw`\(,`,
2941
+ String.raw`,\)`,
2942
+ String.raw`\(\.\)`
2943
+ ];
2944
+ var RETIRED_EXEMPT_SUBSTRINGS = [
2945
+ "docs/decisions-legacy.md",
2946
+ "apps/herald-ai/docs/",
2947
+ "apps/vada-ai/docs/",
2948
+ "aeg-root/tranches/completed/",
2949
+ "packages/aeg-core/src/docs/published-prose",
2950
+ "packages/aeg-core/src/retired-vocabulary.test.ts",
2951
+ "packages/aeg-core/src/retired-vocabulary.ts",
2952
+ "/fixtures/",
2953
+ "/node_modules/",
2954
+ "/.next/",
2955
+ "/.turbo/"
2956
+ ];
2957
+ var PATTERN_EXEMPT = {
2958
+ [String.raw`\bD-[0-9]{3}\b`]: ["./CLAUDE.md"],
2959
+ [String.raw`decisions\.md`]: [
2960
+ "docs-index.md",
2961
+ "apps/vada-ai/specs/legacy/README.md",
2962
+ "apps/vada-ai/specs/vada-product-spec.md",
2963
+ "apps/vada-ai/web/CLAUDE.md",
2964
+ "apps/vada-ai/CLAUDE.md"
2965
+ ],
2966
+ "decisions-legacy": [
2967
+ "packages/aeg-core/src/file-classify.ts",
2968
+ "packages/aeg-core/src/file-classify.test.ts",
2969
+ "packages/aeg-core/src/pr-tier.test.ts",
2970
+ "docs-index.md",
2971
+ ".claude/skills/database/SKILL.md",
2972
+ ".claude/skills/vada-architecture/SKILL.md",
2973
+ "apps/vada-ai/specs/vada-byok-principles.md",
2974
+ "apps/vada-ai/web/CLAUDE.md",
2975
+ "apps/vada-ai/CLAUDE.md"
2976
+ ],
2977
+ CONTRADICTION: ["apps/vada-ai/specs/vada-reviewers-spec.md"]
2978
+ };
2979
+ function lineNumbers(content, pattern) {
2980
+ const out = [];
2981
+ const lines = content.split(`
2982
+ `);
2983
+ for (let i = 0;i < lines.length; i++) {
2984
+ if (pattern.test(lines[i] ?? ""))
2985
+ out.push(i + 1);
2986
+ }
2987
+ return out;
2988
+ }
2989
+ function scanRetiredVocabulary(files) {
2990
+ const findings = [];
2991
+ for (const file of files) {
2992
+ if (RETIRED_EXEMPT_SUBSTRINGS.some((e) => file.path.includes(e)))
2993
+ continue;
2994
+ for (const pattern of RETIRED_PATTERNS) {
2995
+ const patternExempt = PATTERN_EXEMPT[pattern] ?? [];
2996
+ if (patternExempt.some((e) => file.path.includes(e)))
2997
+ continue;
2998
+ const re = new RegExp(pattern);
2999
+ for (const line of lineNumbers(file.content, re)) {
3000
+ findings.push({
3001
+ file: file.path,
3002
+ line,
3003
+ pattern,
3004
+ message: `claims a retired AEG mechanism is still live (matches /${pattern}/)`
3005
+ });
3006
+ }
3007
+ }
3008
+ }
3009
+ return findings;
3010
+ }
2908
3011
  // ../../packages/aeg-core/src/dispatch-gate.ts
2909
3012
  function isHandClosedByRecognizedPrincipal(dep, principalAllowlist) {
2910
3013
  return dep.issueState === "closed" && dep.stateReason === "completed" && isPrincipal(dep.closedByActor ?? null, principalAllowlist);
@@ -565,6 +565,12 @@ function factsFromLegacyMilestone(milestone) {
565
565
  lifecycle: milestone.state === "closed" ? "complete" : "active"
566
566
  };
567
567
  }
568
+ function resolveLegacyFacts(milestone, labelIssues) {
569
+ if (milestone.state === "closed" && labelIssues.length > 0) {
570
+ return { goal: milestone.description ?? "", lifecycle: lifecycleFromIssues(labelIssues) };
571
+ }
572
+ return factsFromLegacyMilestone(milestone);
573
+ }
568
574
  function lifecycleFromIssues(issues) {
569
575
  if (issues.length === 0)
570
576
  return "planned";
@@ -581,9 +587,9 @@ function goalFromMilestones(milestones, slug) {
581
587
  function findMilestoneForSlug(owner, repo, slug) {
582
588
  const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
583
589
  const legacy = matchesLegacyMilestone(milestones, slug);
584
- if (legacy)
585
- return factsFromLegacyMilestone(legacy);
586
590
  const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
591
+ if (legacy)
592
+ return resolveLegacyFacts(legacy, issues);
587
593
  return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
588
594
  }
589
595
 
@@ -2770,16 +2776,18 @@ function checkDeadBranchPush(input) {
2770
2776
  }
2771
2777
  // ../../packages/aeg-core/src/reader-resolvable-prose.ts
2772
2778
  var SHIPS_PREFIX = "aeg-root/";
2773
- var SHIPS_ARCHIVE_PREFIX = "aeg-root/tranches/completed/";
2779
+ function shipsArchivePrefix(shipsPrefix) {
2780
+ return `${shipsPrefix}tranches/completed/`;
2781
+ }
2774
2782
  function isSpecFile2(path) {
2775
2783
  return path.startsWith("apps/") && path.includes("/specs/") && path.endsWith(".md");
2776
2784
  }
2777
2785
  function isClaudeMdFile(path) {
2778
2786
  return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
2779
2787
  }
2780
- function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix) {
2781
- if (path.startsWith(SHIPS_PREFIX)) {
2782
- return path.startsWith(SHIPS_ARCHIVE_PREFIX) ? "internal" : "ships";
2788
+ function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
2789
+ if (path.startsWith(shipsPrefix)) {
2790
+ return path.startsWith(shipsArchivePrefix(shipsPrefix)) ? "internal" : "ships";
2783
2791
  }
2784
2792
  if (path.startsWith(readerFacingPrefix) && path.endsWith(readerFacingSuffix)) {
2785
2793
  return "reader-facing";
@@ -2814,7 +2822,7 @@ function legacySlugPattern(legacySlugs) {
2814
2822
  const alternation = legacySlugs.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
2815
2823
  return new RegExp(`(^|[^a-zA-Z0-9\\n-])(${alternation})([^a-zA-Z0-9\\n-]|$)`, "g");
2816
2824
  }
2817
- function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
2825
+ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
2818
2826
  const findings = [];
2819
2827
  const legacyPattern = legacySlugPattern(legacySlugs);
2820
2828
  const patterns = [
@@ -2823,7 +2831,7 @@ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuff
2823
2831
  ...legacyPattern ? [{ pattern: legacyPattern, what: "an internal tranche slug", group: 2 }] : []
2824
2832
  ];
2825
2833
  for (const file of files) {
2826
- const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
2834
+ const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
2827
2835
  if (!cls || !SWEPT_CLASSES.has(cls))
2828
2836
  continue;
2829
2837
  const scrubbed = stripNonProse(file.path, file.content);
@@ -2869,10 +2877,10 @@ function definesOrLinksGlossary(content, term) {
2869
2877
  return true;
2870
2878
  return /docs\/glossary|glossary\.md/i.test(content);
2871
2879
  }
2872
- function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix) {
2880
+ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
2873
2881
  const findings = [];
2874
2882
  for (const file of files) {
2875
- const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
2883
+ const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
2876
2884
  if (!cls || !SWEPT_CLASSES.has(cls))
2877
2885
  continue;
2878
2886
  const scrubbed = stripNonProse(file.path, file.content);
@@ -2891,10 +2899,10 @@ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, read
2891
2899
  }
2892
2900
  return findings;
2893
2901
  }
2894
- function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
2902
+ function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
2895
2903
  return [
2896
- ...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs),
2897
- ...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix)
2904
+ ...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs, shipsPrefix),
2905
+ ...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix)
2898
2906
  ];
2899
2907
  }
2900
2908
  function parseGlossaryTerms(glossaryContent) {
@@ -2908,6 +2916,101 @@ function parseGlossaryTerms(glossaryContent) {
2908
2916
  }
2909
2917
  return terms;
2910
2918
  }
2919
+ // ../../packages/aeg-core/src/retired-vocabulary.ts
2920
+ var RETIRED_PATTERNS = [
2921
+ String.raw`\bD-[0-9]{3}\b`,
2922
+ "D-(###|NNN|nnn|xxx)",
2923
+ "decision (entry|logged)",
2924
+ "decision-log entry",
2925
+ "decision log entry",
2926
+ "decision log(s|ged|ging)?([^a-z]|$)",
2927
+ "decision-log",
2928
+ "decision entr",
2929
+ "decisions? (are |is )?logged",
2930
+ "log entries",
2931
+ String.raw`decisions\.md`,
2932
+ "decisions-legacy",
2933
+ "CONTRADICTION",
2934
+ "assumes Tier 3",
2935
+ "Lock: ?YES",
2936
+ "Lock: ?NO",
2937
+ "lock approvals?",
2938
+ "approves locks",
2939
+ "Conforms to lock",
2940
+ "Challenges lock",
2941
+ "checkDecisionNumbersFresh",
2942
+ String.raw`roles/team-leader\.md`,
2943
+ String.raw`\(,`,
2944
+ String.raw`,\)`,
2945
+ String.raw`\(\.\)`
2946
+ ];
2947
+ var RETIRED_EXEMPT_SUBSTRINGS = [
2948
+ "docs/decisions-legacy.md",
2949
+ "apps/herald-ai/docs/",
2950
+ "apps/vada-ai/docs/",
2951
+ "aeg-root/tranches/completed/",
2952
+ "packages/aeg-core/src/docs/published-prose",
2953
+ "packages/aeg-core/src/retired-vocabulary.test.ts",
2954
+ "packages/aeg-core/src/retired-vocabulary.ts",
2955
+ "/fixtures/",
2956
+ "/node_modules/",
2957
+ "/.next/",
2958
+ "/.turbo/"
2959
+ ];
2960
+ var PATTERN_EXEMPT = {
2961
+ [String.raw`\bD-[0-9]{3}\b`]: ["./CLAUDE.md"],
2962
+ [String.raw`decisions\.md`]: [
2963
+ "docs-index.md",
2964
+ "apps/vada-ai/specs/legacy/README.md",
2965
+ "apps/vada-ai/specs/vada-product-spec.md",
2966
+ "apps/vada-ai/web/CLAUDE.md",
2967
+ "apps/vada-ai/CLAUDE.md"
2968
+ ],
2969
+ "decisions-legacy": [
2970
+ "packages/aeg-core/src/file-classify.ts",
2971
+ "packages/aeg-core/src/file-classify.test.ts",
2972
+ "packages/aeg-core/src/pr-tier.test.ts",
2973
+ "docs-index.md",
2974
+ ".claude/skills/database/SKILL.md",
2975
+ ".claude/skills/vada-architecture/SKILL.md",
2976
+ "apps/vada-ai/specs/vada-byok-principles.md",
2977
+ "apps/vada-ai/web/CLAUDE.md",
2978
+ "apps/vada-ai/CLAUDE.md"
2979
+ ],
2980
+ CONTRADICTION: ["apps/vada-ai/specs/vada-reviewers-spec.md"]
2981
+ };
2982
+ function lineNumbers(content, pattern) {
2983
+ const out = [];
2984
+ const lines = content.split(`
2985
+ `);
2986
+ for (let i = 0;i < lines.length; i++) {
2987
+ if (pattern.test(lines[i] ?? ""))
2988
+ out.push(i + 1);
2989
+ }
2990
+ return out;
2991
+ }
2992
+ function scanRetiredVocabulary(files) {
2993
+ const findings = [];
2994
+ for (const file of files) {
2995
+ if (RETIRED_EXEMPT_SUBSTRINGS.some((e) => file.path.includes(e)))
2996
+ continue;
2997
+ for (const pattern of RETIRED_PATTERNS) {
2998
+ const patternExempt = PATTERN_EXEMPT[pattern] ?? [];
2999
+ if (patternExempt.some((e) => file.path.includes(e)))
3000
+ continue;
3001
+ const re = new RegExp(pattern);
3002
+ for (const line of lineNumbers(file.content, re)) {
3003
+ findings.push({
3004
+ file: file.path,
3005
+ line,
3006
+ pattern,
3007
+ message: `claims a retired AEG mechanism is still live (matches /${pattern}/)`
3008
+ });
3009
+ }
3010
+ }
3011
+ }
3012
+ return findings;
3013
+ }
2911
3014
  // ../../packages/aeg-core/src/dispatch-gate.ts
2912
3015
  function isHandClosedByRecognizedPrincipal(dep, principalAllowlist) {
2913
3016
  return dep.issueState === "closed" && dep.stateReason === "completed" && isPrincipal(dep.closedByActor ?? null, principalAllowlist);