@attalabs/vinaya 0.18.0 → 0.19.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.
- package/README.md +37 -1
- package/aeg-root/contracts/architect-planner.md +72 -0
- package/aeg-root/enforcement.md +3 -2
- package/aeg-root/roles/architect.md +91 -0
- package/aeg-root/roles/planner.md +14 -15
- package/aeg-root/tranche-model.md +9 -1
- package/dist/checks/bin/check-body-bare-digits.js +262 -26
- package/dist/checks/bin/check-branch-topology.js +171 -23
- package/dist/checks/bin/check-brief-shape.js +171 -23
- package/dist/checks/bin/check-closes-n.js +171 -23
- package/dist/checks/bin/check-coherence.js +265 -29
- package/dist/checks/bin/check-dead-branch-push.js +171 -23
- package/dist/checks/bin/check-dispatch-readiness.js +329 -53
- package/dist/checks/bin/check-doc-coverage-push.js +266 -30
- package/dist/checks/bin/check-doc-coverage.js +266 -30
- package/dist/checks/bin/check-evidence-fresh.js +171 -23
- package/dist/checks/bin/check-first-push-dispatch.js +330 -54
- package/dist/checks/bin/check-issue-assignment.js +171 -23
- package/dist/checks/bin/check-no-disk-state.js +171 -23
- package/dist/checks/bin/check-reader-resolvable-prose.js +465 -46
- package/dist/checks/bin/check-registry-gates.js +171 -23
- package/dist/checks/bin/check-retired-vocabulary.js +3595 -0
- package/dist/checks/bin/check-review-gate.js +262 -26
- package/dist/checks/bin/check-single-plan-pr.js +171 -23
- package/dist/checks/bin/check-test-plan.js +171 -23
- package/dist/index.js +2959 -1581
- package/package.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__0e95dv5._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/1q96_modules_@clerk_nextjs_dist_esm_app-router_client_keyless-creator-reader_0lom2js.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__029-1ch._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0q56ohl._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0z47hfl._.js → [root-of-the-server]__0xdkvod._.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1_ojzp1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1d_8nm4._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1zkwtx8._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__210ehg9._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_00yjcv1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0rix02i._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_18-d2be._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +5 -5
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1gw6vc9._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{2myi4phnshkfw.js → 1zaotsjjq5o6o.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{415k4k1rf3swg.js → 295mri9sjante.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3z3a3gb6he23i.js → 2opd70pfbc5yx.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
- package/templates/noop-check.template.ts +18 -0
- package/templates/role.template.md +20 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → SG6gXRhit12wl-8HLX9d3}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → SG6gXRhit12wl-8HLX9d3}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{8tXGbArNoU7_MriIVYvN0 → SG6gXRhit12wl-8HLX9d3}/_ssgManifest.js +0 -0
|
@@ -274,6 +274,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
274
274
|
"200"
|
|
275
275
|
];
|
|
276
276
|
}
|
|
277
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
278
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
279
|
+
}
|
|
277
280
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
278
281
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
279
282
|
}
|
|
@@ -289,18 +292,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
289
292
|
return dedupeByNumber(perLabel.flat());
|
|
290
293
|
}
|
|
291
294
|
|
|
292
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
293
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
294
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
295
|
-
const match = milestones.find((m) => m.title === slug);
|
|
296
|
-
if (!match)
|
|
297
|
-
return null;
|
|
298
|
-
return {
|
|
299
|
-
goal: match.description ?? "",
|
|
300
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
295
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
305
296
|
var LABELS = [
|
|
306
297
|
{
|
|
@@ -543,6 +534,66 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
543
534
|
return { trancheSlug, taskId };
|
|
544
535
|
}
|
|
545
536
|
|
|
537
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
538
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
539
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
540
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
541
|
+
function intentGoalForSlug(description, slug) {
|
|
542
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
543
|
+
const start = text.match(INTENTS_HEADING);
|
|
544
|
+
if (!start || start.index === undefined)
|
|
545
|
+
return "";
|
|
546
|
+
const rest = text.slice(start.index + start[0].length);
|
|
547
|
+
const next = rest.match(NEXT_HEADING);
|
|
548
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
549
|
+
for (const line of section.split(`
|
|
550
|
+
`)) {
|
|
551
|
+
const trimmed = line.trim();
|
|
552
|
+
if (trimmed.length === 0)
|
|
553
|
+
continue;
|
|
554
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
555
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
556
|
+
return (m[2] ?? "").trim();
|
|
557
|
+
}
|
|
558
|
+
return "";
|
|
559
|
+
}
|
|
560
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
561
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
562
|
+
}
|
|
563
|
+
function factsFromLegacyMilestone(milestone) {
|
|
564
|
+
return {
|
|
565
|
+
goal: milestone.description ?? "",
|
|
566
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function resolveLegacyFacts(milestone, labelIssues) {
|
|
570
|
+
if (milestone.state === "closed" && labelIssues.length > 0) {
|
|
571
|
+
return { goal: milestone.description ?? "", lifecycle: lifecycleFromIssues(labelIssues) };
|
|
572
|
+
}
|
|
573
|
+
return factsFromLegacyMilestone(milestone);
|
|
574
|
+
}
|
|
575
|
+
function lifecycleFromIssues(issues) {
|
|
576
|
+
if (issues.length === 0)
|
|
577
|
+
return "planned";
|
|
578
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
579
|
+
}
|
|
580
|
+
function goalFromMilestones(milestones, slug) {
|
|
581
|
+
for (const m of milestones) {
|
|
582
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
583
|
+
if (goal)
|
|
584
|
+
return goal;
|
|
585
|
+
}
|
|
586
|
+
return "";
|
|
587
|
+
}
|
|
588
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
589
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
590
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
591
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
592
|
+
if (legacy)
|
|
593
|
+
return resolveLegacyFacts(legacy, issues);
|
|
594
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
595
|
+
}
|
|
596
|
+
|
|
546
597
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
547
598
|
function trancheFromIssues(slug, issues, known) {
|
|
548
599
|
return {
|
|
@@ -2726,16 +2777,18 @@ function checkDeadBranchPush(input) {
|
|
|
2726
2777
|
}
|
|
2727
2778
|
// ../../packages/aeg-core/src/reader-resolvable-prose.ts
|
|
2728
2779
|
var SHIPS_PREFIX = "aeg-root/";
|
|
2729
|
-
|
|
2780
|
+
function shipsArchivePrefix(shipsPrefix) {
|
|
2781
|
+
return `${shipsPrefix}tranches/completed/`;
|
|
2782
|
+
}
|
|
2730
2783
|
function isSpecFile2(path) {
|
|
2731
2784
|
return path.startsWith("apps/") && path.includes("/specs/") && path.endsWith(".md");
|
|
2732
2785
|
}
|
|
2733
2786
|
function isClaudeMdFile(path) {
|
|
2734
2787
|
return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
|
|
2735
2788
|
}
|
|
2736
|
-
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix) {
|
|
2737
|
-
if (path.startsWith(
|
|
2738
|
-
return path.startsWith(
|
|
2789
|
+
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2790
|
+
if (path.startsWith(shipsPrefix)) {
|
|
2791
|
+
return path.startsWith(shipsArchivePrefix(shipsPrefix)) ? "internal" : "ships";
|
|
2739
2792
|
}
|
|
2740
2793
|
if (path.startsWith(readerFacingPrefix) && path.endsWith(readerFacingSuffix)) {
|
|
2741
2794
|
return "reader-facing";
|
|
@@ -2770,7 +2823,7 @@ function legacySlugPattern(legacySlugs) {
|
|
|
2770
2823
|
const alternation = legacySlugs.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
2771
2824
|
return new RegExp(`(^|[^a-zA-Z0-9\\n-])(${alternation})([^a-zA-Z0-9\\n-]|$)`, "g");
|
|
2772
2825
|
}
|
|
2773
|
-
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2826
|
+
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2774
2827
|
const findings = [];
|
|
2775
2828
|
const legacyPattern = legacySlugPattern(legacySlugs);
|
|
2776
2829
|
const patterns = [
|
|
@@ -2779,7 +2832,7 @@ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuff
|
|
|
2779
2832
|
...legacyPattern ? [{ pattern: legacyPattern, what: "an internal tranche slug", group: 2 }] : []
|
|
2780
2833
|
];
|
|
2781
2834
|
for (const file of files) {
|
|
2782
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2835
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2783
2836
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2784
2837
|
continue;
|
|
2785
2838
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2825,10 +2878,10 @@ function definesOrLinksGlossary(content, term) {
|
|
|
2825
2878
|
return true;
|
|
2826
2879
|
return /docs\/glossary|glossary\.md/i.test(content);
|
|
2827
2880
|
}
|
|
2828
|
-
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix) {
|
|
2881
|
+
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2829
2882
|
const findings = [];
|
|
2830
2883
|
for (const file of files) {
|
|
2831
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2884
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2832
2885
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2833
2886
|
continue;
|
|
2834
2887
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2847,10 +2900,10 @@ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, read
|
|
|
2847
2900
|
}
|
|
2848
2901
|
return findings;
|
|
2849
2902
|
}
|
|
2850
|
-
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2903
|
+
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2851
2904
|
return [
|
|
2852
|
-
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs),
|
|
2853
|
-
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix)
|
|
2905
|
+
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs, shipsPrefix),
|
|
2906
|
+
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix)
|
|
2854
2907
|
];
|
|
2855
2908
|
}
|
|
2856
2909
|
function parseGlossaryTerms(glossaryContent) {
|
|
@@ -2864,6 +2917,101 @@ function parseGlossaryTerms(glossaryContent) {
|
|
|
2864
2917
|
}
|
|
2865
2918
|
return terms;
|
|
2866
2919
|
}
|
|
2920
|
+
// ../../packages/aeg-core/src/retired-vocabulary.ts
|
|
2921
|
+
var RETIRED_PATTERNS = [
|
|
2922
|
+
String.raw`\bD-[0-9]{3}\b`,
|
|
2923
|
+
"D-(###|NNN|nnn|xxx)",
|
|
2924
|
+
"decision (entry|logged)",
|
|
2925
|
+
"decision-log entry",
|
|
2926
|
+
"decision log entry",
|
|
2927
|
+
"decision log(s|ged|ging)?([^a-z]|$)",
|
|
2928
|
+
"decision-log",
|
|
2929
|
+
"decision entr",
|
|
2930
|
+
"decisions? (are |is )?logged",
|
|
2931
|
+
"log entries",
|
|
2932
|
+
String.raw`decisions\.md`,
|
|
2933
|
+
"decisions-legacy",
|
|
2934
|
+
"CONTRADICTION",
|
|
2935
|
+
"assumes Tier 3",
|
|
2936
|
+
"Lock: ?YES",
|
|
2937
|
+
"Lock: ?NO",
|
|
2938
|
+
"lock approvals?",
|
|
2939
|
+
"approves locks",
|
|
2940
|
+
"Conforms to lock",
|
|
2941
|
+
"Challenges lock",
|
|
2942
|
+
"checkDecisionNumbersFresh",
|
|
2943
|
+
String.raw`roles/team-leader\.md`,
|
|
2944
|
+
String.raw`\(,`,
|
|
2945
|
+
String.raw`,\)`,
|
|
2946
|
+
String.raw`\(\.\)`
|
|
2947
|
+
];
|
|
2948
|
+
var RETIRED_EXEMPT_SUBSTRINGS = [
|
|
2949
|
+
"docs/decisions-legacy.md",
|
|
2950
|
+
"apps/herald-ai/docs/",
|
|
2951
|
+
"apps/vada-ai/docs/",
|
|
2952
|
+
"aeg-root/tranches/completed/",
|
|
2953
|
+
"packages/aeg-core/src/docs/published-prose",
|
|
2954
|
+
"packages/aeg-core/src/retired-vocabulary.test.ts",
|
|
2955
|
+
"packages/aeg-core/src/retired-vocabulary.ts",
|
|
2956
|
+
"/fixtures/",
|
|
2957
|
+
"/node_modules/",
|
|
2958
|
+
"/.next/",
|
|
2959
|
+
"/.turbo/"
|
|
2960
|
+
];
|
|
2961
|
+
var PATTERN_EXEMPT = {
|
|
2962
|
+
[String.raw`\bD-[0-9]{3}\b`]: ["./CLAUDE.md"],
|
|
2963
|
+
[String.raw`decisions\.md`]: [
|
|
2964
|
+
"docs-index.md",
|
|
2965
|
+
"apps/vada-ai/specs/legacy/README.md",
|
|
2966
|
+
"apps/vada-ai/specs/vada-product-spec.md",
|
|
2967
|
+
"apps/vada-ai/web/CLAUDE.md",
|
|
2968
|
+
"apps/vada-ai/CLAUDE.md"
|
|
2969
|
+
],
|
|
2970
|
+
"decisions-legacy": [
|
|
2971
|
+
"packages/aeg-core/src/file-classify.ts",
|
|
2972
|
+
"packages/aeg-core/src/file-classify.test.ts",
|
|
2973
|
+
"packages/aeg-core/src/pr-tier.test.ts",
|
|
2974
|
+
"docs-index.md",
|
|
2975
|
+
".claude/skills/database/SKILL.md",
|
|
2976
|
+
".claude/skills/vada-architecture/SKILL.md",
|
|
2977
|
+
"apps/vada-ai/specs/vada-byok-principles.md",
|
|
2978
|
+
"apps/vada-ai/web/CLAUDE.md",
|
|
2979
|
+
"apps/vada-ai/CLAUDE.md"
|
|
2980
|
+
],
|
|
2981
|
+
CONTRADICTION: ["apps/vada-ai/specs/vada-reviewers-spec.md"]
|
|
2982
|
+
};
|
|
2983
|
+
function lineNumbers(content, pattern) {
|
|
2984
|
+
const out = [];
|
|
2985
|
+
const lines = content.split(`
|
|
2986
|
+
`);
|
|
2987
|
+
for (let i = 0;i < lines.length; i++) {
|
|
2988
|
+
if (pattern.test(lines[i] ?? ""))
|
|
2989
|
+
out.push(i + 1);
|
|
2990
|
+
}
|
|
2991
|
+
return out;
|
|
2992
|
+
}
|
|
2993
|
+
function scanRetiredVocabulary(files) {
|
|
2994
|
+
const findings = [];
|
|
2995
|
+
for (const file of files) {
|
|
2996
|
+
if (RETIRED_EXEMPT_SUBSTRINGS.some((e) => file.path.includes(e)))
|
|
2997
|
+
continue;
|
|
2998
|
+
for (const pattern of RETIRED_PATTERNS) {
|
|
2999
|
+
const patternExempt = PATTERN_EXEMPT[pattern] ?? [];
|
|
3000
|
+
if (patternExempt.some((e) => file.path.includes(e)))
|
|
3001
|
+
continue;
|
|
3002
|
+
const re = new RegExp(pattern);
|
|
3003
|
+
for (const line of lineNumbers(file.content, re)) {
|
|
3004
|
+
findings.push({
|
|
3005
|
+
file: file.path,
|
|
3006
|
+
line,
|
|
3007
|
+
pattern,
|
|
3008
|
+
message: `claims a retired AEG mechanism is still live (matches /${pattern}/)`
|
|
3009
|
+
});
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
return findings;
|
|
3014
|
+
}
|
|
2867
3015
|
// ../../packages/aeg-core/src/dispatch-gate.ts
|
|
2868
3016
|
function isHandClosedByRecognizedPrincipal(dep, principalAllowlist) {
|
|
2869
3017
|
return dep.issueState === "closed" && dep.stateReason === "completed" && isPrincipal(dep.closedByActor ?? null, principalAllowlist);
|
|
@@ -3119,9 +3267,15 @@ function evaluateTestPlanGate(body, branch) {
|
|
|
3119
3267
|
}
|
|
3120
3268
|
// src/lib/config.ts
|
|
3121
3269
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
3270
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3122
3271
|
import { homedir } from "node:os";
|
|
3123
3272
|
import { dirname, join } from "node:path";
|
|
3124
3273
|
import { z } from "zod";
|
|
3274
|
+
|
|
3275
|
+
// src/lib/agent-vendors.ts
|
|
3276
|
+
var AGENT_VENDORS = ["skills", "claude", "gemini"];
|
|
3277
|
+
|
|
3278
|
+
// src/lib/config.ts
|
|
3125
3279
|
var EnvEntrySchema = z.union([
|
|
3126
3280
|
z.literal(true),
|
|
3127
3281
|
z.object({ optional: z.literal(true) }),
|
|
@@ -3160,6 +3314,11 @@ var CheckEntrySchema = z.object({
|
|
|
3160
3314
|
}
|
|
3161
3315
|
}
|
|
3162
3316
|
});
|
|
3317
|
+
var RoleEntrySchema = z.object({
|
|
3318
|
+
contract: z.string().refine((p) => p.includes("/"), {
|
|
3319
|
+
message: 'must be a path (contain at least one "/"), not a bare filename'
|
|
3320
|
+
})
|
|
3321
|
+
});
|
|
3163
3322
|
var BRIEF_BUILTINS = [
|
|
3164
3323
|
"tier",
|
|
3165
3324
|
"testPlan",
|
|
@@ -3174,7 +3333,8 @@ var BRIEF_BUILTINS = [
|
|
|
3174
3333
|
"for",
|
|
3175
3334
|
"closesN",
|
|
3176
3335
|
"premiseCoverage",
|
|
3177
|
-
"issueRationale"
|
|
3336
|
+
"issueRationale",
|
|
3337
|
+
"milestoneShape"
|
|
3178
3338
|
];
|
|
3179
3339
|
var BriefSectionSchema = z.union([
|
|
3180
3340
|
z.object({ builtin: z.enum(BRIEF_BUILTINS) }),
|
|
@@ -3185,6 +3345,7 @@ var BriefSectionSchema = z.union([
|
|
|
3185
3345
|
var BriefSchemaSchema = z.object({
|
|
3186
3346
|
pr: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3187
3347
|
issue: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3348
|
+
milestone: z.object({ sections: z.array(BriefSectionSchema) }).optional(),
|
|
3188
3349
|
ack: z.array(z.enum(BRIEF_BUILTINS)).optional()
|
|
3189
3350
|
});
|
|
3190
3351
|
function isSafeRepoRelPath(p) {
|
|
@@ -3206,7 +3367,8 @@ var ManagedManifestSchema = z.object({
|
|
|
3206
3367
|
version: z.number().int().positive(),
|
|
3207
3368
|
files: z.array(SafeRepoRelPath),
|
|
3208
3369
|
blocks: z.array(ManagedBlockRecordSchema),
|
|
3209
|
-
labels: z.array(z.string())
|
|
3370
|
+
labels: z.array(z.string()),
|
|
3371
|
+
agents: z.array(z.enum(AGENT_VENDORS)).optional()
|
|
3210
3372
|
});
|
|
3211
3373
|
var VinayaConfigSchema = z.object({
|
|
3212
3374
|
rings: z.object({
|
|
@@ -3214,16 +3376,79 @@ var VinayaConfigSchema = z.object({
|
|
|
3214
3376
|
ring2_asyncAudits: z.boolean()
|
|
3215
3377
|
}).optional(),
|
|
3216
3378
|
checks: z.record(z.string(), CheckEntrySchema).optional(),
|
|
3379
|
+
roles: z.record(z.string(), RoleEntrySchema).optional(),
|
|
3217
3380
|
briefSchema: BriefSchemaSchema.optional(),
|
|
3218
3381
|
managed: ManagedManifestSchema.optional(),
|
|
3219
3382
|
principals: z.array(z.string()).min(1).optional(),
|
|
3220
3383
|
releaseActor: z.string().min(1).optional(),
|
|
3221
3384
|
ci: z.object({ setup: z.string().min(1) }).optional(),
|
|
3222
|
-
blastRadius: z.object({ extraDomains: z.array(z.string()).optional() }).optional()
|
|
3385
|
+
blastRadius: z.object({ extraDomains: z.array(z.string()).optional() }).optional(),
|
|
3386
|
+
proseGates: z.object({
|
|
3387
|
+
doctrineRoot: z.string().min(1).optional(),
|
|
3388
|
+
readerFacingPrefix: z.string().min(1).optional(),
|
|
3389
|
+
readerFacingSuffix: z.string().min(1).optional(),
|
|
3390
|
+
legacySlugDir: z.string().min(1).optional()
|
|
3391
|
+
}).optional()
|
|
3223
3392
|
});
|
|
3224
3393
|
var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");
|
|
3225
3394
|
var GLOBAL_CONFIG_PATH = join(GLOBAL_VINAYA_HOME, "config.json");
|
|
3226
3395
|
var LOCAL_CONFIG_FILENAME = "vinaya.config.json";
|
|
3396
|
+
function findLocalConfig() {
|
|
3397
|
+
let dir = process.cwd();
|
|
3398
|
+
while (true) {
|
|
3399
|
+
const candidate = join(dir, LOCAL_CONFIG_FILENAME);
|
|
3400
|
+
if (existsSync(candidate))
|
|
3401
|
+
return candidate;
|
|
3402
|
+
if (existsSync(join(dir, ".git")))
|
|
3403
|
+
return null;
|
|
3404
|
+
const parent = dirname(dir);
|
|
3405
|
+
if (parent === dir)
|
|
3406
|
+
return null;
|
|
3407
|
+
dir = parent;
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
function configPath() {
|
|
3411
|
+
const local = findLocalConfig();
|
|
3412
|
+
if (local)
|
|
3413
|
+
return local;
|
|
3414
|
+
if (existsSync(GLOBAL_CONFIG_PATH))
|
|
3415
|
+
return GLOBAL_CONFIG_PATH;
|
|
3416
|
+
return null;
|
|
3417
|
+
}
|
|
3418
|
+
function globalChecksIgnoredWarning(path) {
|
|
3419
|
+
return `${path}: "checks" registration in the global config is ignored — checks may only be registered from a repo-local vinaya.config.json.`;
|
|
3420
|
+
}
|
|
3421
|
+
function globalPrincipalsIgnoredWarning(path) {
|
|
3422
|
+
return `${path}: "principals" in the global config is ignored — principals may only be declared from a repo-local vinaya.config.json.`;
|
|
3423
|
+
}
|
|
3424
|
+
function globalRolesIgnoredWarning(path) {
|
|
3425
|
+
return `${path}: "roles" registration in the global config is ignored — roles may only be registered from a repo-local vinaya.config.json.`;
|
|
3426
|
+
}
|
|
3427
|
+
function globalReleaseActorIgnoredWarning(path) {
|
|
3428
|
+
return `${path}: "releaseActor" in the global config is ignored — releaseActor may only be declared from a repo-local vinaya.config.json.`;
|
|
3429
|
+
}
|
|
3430
|
+
function stripGlobalOnlyKeys(config, path) {
|
|
3431
|
+
if (path !== GLOBAL_CONFIG_PATH)
|
|
3432
|
+
return config;
|
|
3433
|
+
let result = config;
|
|
3434
|
+
if (result.checks && Object.keys(result.checks).length > 0) {
|
|
3435
|
+
console.error(`⚠ ${globalChecksIgnoredWarning(path)}`);
|
|
3436
|
+
result = { ...result, checks: undefined };
|
|
3437
|
+
}
|
|
3438
|
+
if (result.roles && Object.keys(result.roles).length > 0) {
|
|
3439
|
+
console.error(`⚠ ${globalRolesIgnoredWarning(path)}`);
|
|
3440
|
+
result = { ...result, roles: undefined };
|
|
3441
|
+
}
|
|
3442
|
+
if (result.principals && result.principals.length > 0) {
|
|
3443
|
+
console.error(`⚠ ${globalPrincipalsIgnoredWarning(path)}`);
|
|
3444
|
+
result = { ...result, principals: undefined };
|
|
3445
|
+
}
|
|
3446
|
+
if (result.releaseActor) {
|
|
3447
|
+
console.error(`⚠ ${globalReleaseActorIgnoredWarning(path)}`);
|
|
3448
|
+
result = { ...result, releaseActor: undefined };
|
|
3449
|
+
}
|
|
3450
|
+
return result;
|
|
3451
|
+
}
|
|
3227
3452
|
function resolvePrincipalAllowlist(config) {
|
|
3228
3453
|
return config?.principals ?? PRINCIPAL_ALLOWLIST;
|
|
3229
3454
|
}
|
|
@@ -3296,6 +3521,17 @@ function loadTrustAnchorConfig(fetcher = ghFetchTrustAnchorConfig) {
|
|
|
3296
3521
|
return null;
|
|
3297
3522
|
}
|
|
3298
3523
|
}
|
|
3524
|
+
function loadConfig() {
|
|
3525
|
+
const path = configPath();
|
|
3526
|
+
if (!path)
|
|
3527
|
+
return null;
|
|
3528
|
+
try {
|
|
3529
|
+
const raw = JSON.parse(readFileSync(path, "utf-8"));
|
|
3530
|
+
return stripGlobalOnlyKeys(VinayaConfigSchema.parse(raw), path);
|
|
3531
|
+
} catch {
|
|
3532
|
+
return null;
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3299
3535
|
|
|
3300
3536
|
// src/checks/contract.ts
|
|
3301
3537
|
var CHECK_SCHEMA_VERSION = 1;
|
|
@@ -273,6 +273,9 @@ function issueListByLabelArgs(owner, repo, label) {
|
|
|
273
273
|
"200"
|
|
274
274
|
];
|
|
275
275
|
}
|
|
276
|
+
function ghIssueListByLabel(owner, repo, label) {
|
|
277
|
+
return JSON.parse(run(issueListByLabelArgs(owner, repo, label)));
|
|
278
|
+
}
|
|
276
279
|
async function ghIssueListByLabelAsync(owner, repo, label) {
|
|
277
280
|
return JSON.parse(await runAsync(issueListByLabelArgs(owner, repo, label)));
|
|
278
281
|
}
|
|
@@ -288,18 +291,6 @@ async function ghIssueListByAnyLabelAsync(owner, repo, labels) {
|
|
|
288
291
|
return dedupeByNumber(perLabel.flat());
|
|
289
292
|
}
|
|
290
293
|
|
|
291
|
-
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
292
|
-
function findMilestoneForSlug(owner, repo, slug) {
|
|
293
|
-
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
294
|
-
const match = milestones.find((m) => m.title === slug);
|
|
295
|
-
if (!match)
|
|
296
|
-
return null;
|
|
297
|
-
return {
|
|
298
|
-
goal: match.description ?? "",
|
|
299
|
-
lifecycle: match.state === "closed" ? "complete" : "active"
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
|
|
303
294
|
// ../../packages/aeg-forge-state/src/labels.ts
|
|
304
295
|
var LABELS = [
|
|
305
296
|
{
|
|
@@ -542,6 +533,66 @@ function resolveTaskIssueRef(title, labels) {
|
|
|
542
533
|
return { trancheSlug, taskId };
|
|
543
534
|
}
|
|
544
535
|
|
|
536
|
+
// ../../packages/aeg-forge-state/src/fetch-milestone.ts
|
|
537
|
+
var INTENTS_HEADING = /^#{1,6}\s*Tranche intents\s*$/im;
|
|
538
|
+
var NEXT_HEADING = /^#{1,6}\s+\S/m;
|
|
539
|
+
var INTENT_BULLET = /^-\s+([a-z0-9][a-z0-9-]*)\s*:\s*(.+)$/i;
|
|
540
|
+
function intentGoalForSlug(description, slug) {
|
|
541
|
+
const text = stripCode(description, { inlineSpans: "keep" });
|
|
542
|
+
const start = text.match(INTENTS_HEADING);
|
|
543
|
+
if (!start || start.index === undefined)
|
|
544
|
+
return "";
|
|
545
|
+
const rest = text.slice(start.index + start[0].length);
|
|
546
|
+
const next = rest.match(NEXT_HEADING);
|
|
547
|
+
const section = rest.slice(0, next && next.index !== undefined ? next.index : rest.length);
|
|
548
|
+
for (const line of section.split(`
|
|
549
|
+
`)) {
|
|
550
|
+
const trimmed = line.trim();
|
|
551
|
+
if (trimmed.length === 0)
|
|
552
|
+
continue;
|
|
553
|
+
const m = trimmed.match(INTENT_BULLET);
|
|
554
|
+
if (m && (m[1] ?? "").toLowerCase() === slug.toLowerCase())
|
|
555
|
+
return (m[2] ?? "").trim();
|
|
556
|
+
}
|
|
557
|
+
return "";
|
|
558
|
+
}
|
|
559
|
+
function matchesLegacyMilestone(milestones, slug) {
|
|
560
|
+
return milestones.find((m) => m.title === slug) ?? null;
|
|
561
|
+
}
|
|
562
|
+
function factsFromLegacyMilestone(milestone) {
|
|
563
|
+
return {
|
|
564
|
+
goal: milestone.description ?? "",
|
|
565
|
+
lifecycle: milestone.state === "closed" ? "complete" : "active"
|
|
566
|
+
};
|
|
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
|
+
}
|
|
574
|
+
function lifecycleFromIssues(issues) {
|
|
575
|
+
if (issues.length === 0)
|
|
576
|
+
return "planned";
|
|
577
|
+
return issues.some((i) => i.state === "OPEN") ? "active" : "complete";
|
|
578
|
+
}
|
|
579
|
+
function goalFromMilestones(milestones, slug) {
|
|
580
|
+
for (const m of milestones) {
|
|
581
|
+
const goal = intentGoalForSlug(m.description ?? "", slug);
|
|
582
|
+
if (goal)
|
|
583
|
+
return goal;
|
|
584
|
+
}
|
|
585
|
+
return "";
|
|
586
|
+
}
|
|
587
|
+
function findMilestoneForSlug(owner, repo, slug) {
|
|
588
|
+
const milestones = ghApiGet(`repos/${owner}/${repo}/milestones?state=all&per_page=100`);
|
|
589
|
+
const legacy = matchesLegacyMilestone(milestones, slug);
|
|
590
|
+
const issues = ghIssueListByLabel(owner, repo, trancheLabel(slug));
|
|
591
|
+
if (legacy)
|
|
592
|
+
return resolveLegacyFacts(legacy, issues);
|
|
593
|
+
return { goal: goalFromMilestones(milestones, slug), lifecycle: lifecycleFromIssues(issues) };
|
|
594
|
+
}
|
|
595
|
+
|
|
545
596
|
// ../../packages/aeg-forge-state/src/derive-from-forge.ts
|
|
546
597
|
function trancheFromIssues(slug, issues, known) {
|
|
547
598
|
return {
|
|
@@ -2725,16 +2776,18 @@ function checkDeadBranchPush(input) {
|
|
|
2725
2776
|
}
|
|
2726
2777
|
// ../../packages/aeg-core/src/reader-resolvable-prose.ts
|
|
2727
2778
|
var SHIPS_PREFIX = "aeg-root/";
|
|
2728
|
-
|
|
2779
|
+
function shipsArchivePrefix(shipsPrefix) {
|
|
2780
|
+
return `${shipsPrefix}tranches/completed/`;
|
|
2781
|
+
}
|
|
2729
2782
|
function isSpecFile2(path) {
|
|
2730
2783
|
return path.startsWith("apps/") && path.includes("/specs/") && path.endsWith(".md");
|
|
2731
2784
|
}
|
|
2732
2785
|
function isClaudeMdFile(path) {
|
|
2733
2786
|
return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
|
|
2734
2787
|
}
|
|
2735
|
-
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix) {
|
|
2736
|
-
if (path.startsWith(
|
|
2737
|
-
return path.startsWith(
|
|
2788
|
+
function classifyProseFile(path, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2789
|
+
if (path.startsWith(shipsPrefix)) {
|
|
2790
|
+
return path.startsWith(shipsArchivePrefix(shipsPrefix)) ? "internal" : "ships";
|
|
2738
2791
|
}
|
|
2739
2792
|
if (path.startsWith(readerFacingPrefix) && path.endsWith(readerFacingSuffix)) {
|
|
2740
2793
|
return "reader-facing";
|
|
@@ -2769,7 +2822,7 @@ function legacySlugPattern(legacySlugs) {
|
|
|
2769
2822
|
const alternation = legacySlugs.map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
2770
2823
|
return new RegExp(`(^|[^a-zA-Z0-9\\n-])(${alternation})([^a-zA-Z0-9\\n-]|$)`, "g");
|
|
2771
2824
|
}
|
|
2772
|
-
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2825
|
+
function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2773
2826
|
const findings = [];
|
|
2774
2827
|
const legacyPattern = legacySlugPattern(legacySlugs);
|
|
2775
2828
|
const patterns = [
|
|
@@ -2778,7 +2831,7 @@ function checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuff
|
|
|
2778
2831
|
...legacyPattern ? [{ pattern: legacyPattern, what: "an internal tranche slug", group: 2 }] : []
|
|
2779
2832
|
];
|
|
2780
2833
|
for (const file of files) {
|
|
2781
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2834
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2782
2835
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2783
2836
|
continue;
|
|
2784
2837
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2824,10 +2877,10 @@ function definesOrLinksGlossary(content, term) {
|
|
|
2824
2877
|
return true;
|
|
2825
2878
|
return /docs\/glossary|glossary\.md/i.test(content);
|
|
2826
2879
|
}
|
|
2827
|
-
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix) {
|
|
2880
|
+
function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix = SHIPS_PREFIX) {
|
|
2828
2881
|
const findings = [];
|
|
2829
2882
|
for (const file of files) {
|
|
2830
|
-
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix);
|
|
2883
|
+
const cls = classifyProseFile(file.path, readerFacingPrefix, readerFacingSuffix, shipsPrefix);
|
|
2831
2884
|
if (!cls || !SWEPT_CLASSES.has(cls))
|
|
2832
2885
|
continue;
|
|
2833
2886
|
const scrubbed = stripNonProse(file.path, file.content);
|
|
@@ -2846,10 +2899,10 @@ function checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, read
|
|
|
2846
2899
|
}
|
|
2847
2900
|
return findings;
|
|
2848
2901
|
}
|
|
2849
|
-
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = []) {
|
|
2902
|
+
function checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, legacySlugs = [], shipsPrefix = SHIPS_PREFIX) {
|
|
2850
2903
|
return [
|
|
2851
|
-
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs),
|
|
2852
|
-
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix)
|
|
2904
|
+
...checkUnresolvableReferences(files, readerFacingPrefix, readerFacingSuffix, legacySlugs, shipsPrefix),
|
|
2905
|
+
...checkUndefinedVocabulary(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, shipsPrefix)
|
|
2853
2906
|
];
|
|
2854
2907
|
}
|
|
2855
2908
|
function parseGlossaryTerms(glossaryContent) {
|
|
@@ -2863,6 +2916,101 @@ function parseGlossaryTerms(glossaryContent) {
|
|
|
2863
2916
|
}
|
|
2864
2917
|
return terms;
|
|
2865
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
|
+
}
|
|
2866
3014
|
// ../../packages/aeg-core/src/dispatch-gate.ts
|
|
2867
3015
|
function isHandClosedByRecognizedPrincipal(dep, principalAllowlist) {
|
|
2868
3016
|
return dep.issueState === "closed" && dep.stateReason === "completed" && isPrincipal(dep.closedByActor ?? null, principalAllowlist);
|