@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.
- package/README.md +7 -0
- package/aeg-root/contracts/archivist-tranche-archivist.md +2 -2
- package/aeg-root/contracts/tranche-archivist-planner.md +8 -8
- package/aeg-root/enforcement.md +6 -4
- package/aeg-root/process.md +5 -5
- package/aeg-root/roles/archivist.md +9 -10
- package/aeg-root/roles/brief-author.md +1 -1
- package/aeg-root/roles/developer.md +1 -1
- package/aeg-root/roles/planner.md +1 -1
- package/aeg-root/roles/principal.md +1 -1
- package/aeg-root/roles/tranche-archivist.md +3 -16
- package/aeg-root/skills/aeg/SKILL.md +30 -1
- package/aeg-root/skills/aeg-roles/SKILL.md +1 -1
- package/aeg-root/skills/brief-authoring/SKILL.md +2 -2
- package/aeg-root/state-machine.md +8 -6
- package/aeg-root/task-model.md +1 -1
- package/aeg-root/templates/pr-report-template.md +4 -0
- package/dist/checks/bin/check-body-bare-digits.js +192 -27
- package/dist/checks/bin/check-branch-topology.js +518 -11
- package/dist/checks/bin/check-brief-shape.js +104 -11
- package/dist/checks/bin/check-closes-n.js +518 -11
- package/dist/checks/bin/check-coherence.js +526 -12
- package/dist/checks/bin/check-dead-branch-push.js +104 -11
- package/dist/checks/bin/check-dispatch-readiness.js +621 -14
- package/dist/checks/bin/check-doc-coverage-push.js +170 -20
- package/dist/checks/bin/check-doc-coverage.js +170 -20
- package/dist/checks/bin/check-doctrine-portability.js +112 -12
- package/dist/checks/bin/check-evidence-fresh.js +213 -20
- package/dist/checks/bin/check-first-push-dispatch.js +526 -12
- package/dist/checks/bin/check-issue-assignment.js +518 -11
- package/dist/checks/bin/check-main-branch-refusal.js +3724 -0
- package/dist/checks/bin/check-no-disk-state.js +104 -11
- package/dist/checks/bin/check-reader-resolvable-prose.js +186 -17
- package/dist/checks/bin/check-registry-gates.js +185 -16
- package/dist/checks/bin/check-retired-vocabulary.js +185 -16
- package/dist/checks/bin/check-review-gate.js +112 -12
- package/dist/checks/bin/check-single-plan-pr.js +104 -11
- package/dist/checks/bin/check-test-plan.js +104 -11
- package/dist/checks/bin/check-workspace-escape.js +104 -11
- package/dist/index.js +664 -56
- package/package.json +1 -1
- package/studio-standalone/_node_modules/@attalabs/aeg-core/bin/verify-coherence.ts +1089 -0
- 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/required-server-files.json +5 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js +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/{[externals]__0pvgf28._.js → [externals]__1agj1ww._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__02a-3g8._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/1q96_modules_@clerk_nextjs_dist_esm_app-router_client_keyless-creator-reader_0lom2js.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0053k9k._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
- 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
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/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/{3noqvds-2bvrd.js → 0ea8-8nopz29h.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/0la0hhmjprdxm.css +1 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/1lk7h-0buf4ab.js +1 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3gehliafvmjo9.js → 2twnwe77d4n-m.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/server.js +1 -1
- package/aeg-root/coordination.md +0 -292
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/2iysedx-n06xc.js +0 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/42wxpzjhw7oy4.css +0 -1
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5Lv83SnT--7YJDjSbxona → b2VfZK2AItZwlghK_pUN0}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5Lv83SnT--7YJDjSbxona → b2VfZK2AItZwlghK_pUN0}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{5Lv83SnT--7YJDjSbxona → b2VfZK2AItZwlghK_pUN0}/_ssgManifest.js +0 -0
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
5
5
|
// ../../packages/aeg-core/src/gate-audience.ts
|
|
6
6
|
var GATE_AUDIENCE = {
|
|
7
|
-
"check-branch-topology": { shippedAs: "branch-topology" },
|
|
8
|
-
"check-first-push-dispatch": { shippedAs: "first-push-dispatch" },
|
|
9
|
-
"check-no-disk-state": { shippedAs: "no-disk-state" },
|
|
10
|
-
"verify-brief": { shippedAs: "brief-shape" },
|
|
11
|
-
"verify-coherence": { shippedAs: "coherence" },
|
|
12
|
-
"verify-dispatch": { shippedAs: "dispatch-readiness" },
|
|
13
|
-
"verify-docs": { shippedAs: ["doc-coverage", "doc-coverage-push"] },
|
|
14
|
-
"verify-registry": { shippedAs: "registry-gates" },
|
|
15
|
-
"verify-review-gate": { shippedAs: "review-gate" },
|
|
16
|
-
"verify-single-plan-pr": { shippedAs: "single-plan-pr" },
|
|
17
|
-
"verify-test-plan": { shippedAs: "test-plan" },
|
|
7
|
+
"check-branch-topology": { shippedAs: "branch-topology", ring: 0 },
|
|
8
|
+
"check-first-push-dispatch": { shippedAs: "first-push-dispatch", ring: 0 },
|
|
9
|
+
"check-no-disk-state": { shippedAs: "no-disk-state", ring: 0 },
|
|
10
|
+
"verify-brief": { shippedAs: "brief-shape", ring: 0 },
|
|
11
|
+
"verify-coherence": { shippedAs: "coherence", ring: 0 },
|
|
12
|
+
"verify-dispatch": { shippedAs: "dispatch-readiness", ring: 0 },
|
|
13
|
+
"verify-docs": { shippedAs: ["doc-coverage", "doc-coverage-push"], ring: 0 },
|
|
14
|
+
"verify-registry": { shippedAs: "registry-gates", ring: 0 },
|
|
15
|
+
"verify-review-gate": { shippedAs: "review-gate", ring: 1 },
|
|
16
|
+
"verify-single-plan-pr": { shippedAs: "single-plan-pr", ring: 0 },
|
|
17
|
+
"verify-test-plan": { shippedAs: "test-plan", ring: 1 },
|
|
18
18
|
"check-direct-main-push": {
|
|
19
19
|
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."
|
|
20
20
|
},
|
|
@@ -326,6 +326,13 @@ var LABELS = [
|
|
|
326
326
|
form: "literal",
|
|
327
327
|
carries: "Execution is halted pending an external unblock; wins over every other derived status."
|
|
328
328
|
},
|
|
329
|
+
{
|
|
330
|
+
key: "backlog",
|
|
331
|
+
id: "vinaya/backlog",
|
|
332
|
+
category: "state",
|
|
333
|
+
form: "literal",
|
|
334
|
+
carries: "The Issue is deliberately unplanned — belongs to no tranche and is excluded from dispatch, until a Planner promotes it."
|
|
335
|
+
},
|
|
329
336
|
{
|
|
330
337
|
key: "tier-0",
|
|
331
338
|
id: "vinaya/tier:0",
|
|
@@ -1984,7 +1991,59 @@ function overrideActive(opts) {
|
|
|
1984
1991
|
return false;
|
|
1985
1992
|
}
|
|
1986
1993
|
// ../../packages/aeg-core/src/premise-check.ts
|
|
1994
|
+
import { createHash } from "node:crypto";
|
|
1987
1995
|
var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
|
|
1996
|
+
function isPremiseHeader(line) {
|
|
1997
|
+
const stripped = line.replace(/[*#]/g, "").trim();
|
|
1998
|
+
return /^premise\s*:?$/i.test(stripped);
|
|
1999
|
+
}
|
|
2000
|
+
var PREMISE_LINE = /^[-*]\s*(\S+)\s+(contains|absent|sha256)\s*:\s*(.+)$/i;
|
|
2001
|
+
function parsePremiseBlock(prBody) {
|
|
2002
|
+
const searchIn = anchoredRegion(prBody, "PREMISE") ?? prBody;
|
|
2003
|
+
const lines = searchIn.split(/\r?\n/);
|
|
2004
|
+
const assertions = [];
|
|
2005
|
+
let inBlock = false;
|
|
2006
|
+
for (const raw of lines) {
|
|
2007
|
+
const line = raw.trim();
|
|
2008
|
+
if (!inBlock) {
|
|
2009
|
+
if (isPremiseHeader(line))
|
|
2010
|
+
inBlock = true;
|
|
2011
|
+
continue;
|
|
2012
|
+
}
|
|
2013
|
+
if (line === "")
|
|
2014
|
+
break;
|
|
2015
|
+
const m = line.match(PREMISE_LINE);
|
|
2016
|
+
if (!m)
|
|
2017
|
+
break;
|
|
2018
|
+
const [, path, kindRaw, value] = m;
|
|
2019
|
+
const kind = kindRaw.toLowerCase();
|
|
2020
|
+
if (!ASSERTION_KINDS.has(kind))
|
|
2021
|
+
continue;
|
|
2022
|
+
assertions.push({ kind, path, value: value.trim() });
|
|
2023
|
+
}
|
|
2024
|
+
return assertions;
|
|
2025
|
+
}
|
|
2026
|
+
function checkPremises(assertions, fileReader) {
|
|
2027
|
+
const failures = [];
|
|
2028
|
+
for (const a of assertions) {
|
|
2029
|
+
const content = fileReader(a.path);
|
|
2030
|
+
if (content === null) {
|
|
2031
|
+
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.`);
|
|
2032
|
+
continue;
|
|
2033
|
+
}
|
|
2034
|
+
if (a.kind === "contains" && !content.includes(a.value)) {
|
|
2035
|
+
failures.push(`premise-check: ${a.path} no longer contains "${a.value}" — the premise this brief pinned has moved; re-dig before proceeding.`);
|
|
2036
|
+
} else if (a.kind === "absent" && content.includes(a.value)) {
|
|
2037
|
+
failures.push(`premise-check: ${a.path} now contains "${a.value}", but the brief pinned it absent — the premise has moved; re-dig before proceeding.`);
|
|
2038
|
+
} else if (a.kind === "sha256") {
|
|
2039
|
+
const actual = createHash("sha256").update(content).digest("hex");
|
|
2040
|
+
if (actual !== a.value.toLowerCase()) {
|
|
2041
|
+
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.`);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
return { pass: failures.length === 0, failures };
|
|
2046
|
+
}
|
|
1988
2047
|
|
|
1989
2048
|
// ../../packages/aeg-core/src/test-plan-section.ts
|
|
1990
2049
|
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
@@ -2788,6 +2847,7 @@ function checkG1(rows, existsFn) {
|
|
|
2788
2847
|
}
|
|
2789
2848
|
return { check: "G1", status: findings.length > 0 ? "fail" : "pass", findings };
|
|
2790
2849
|
}
|
|
2850
|
+
var SCAFFOLD_PLACEHOLDER = "[undocumented — fill in why]";
|
|
2791
2851
|
function checkG2(rows, candidateFiles) {
|
|
2792
2852
|
const implementations = new Set(rows.map((r) => r.implementation).filter((p) => p !== ""));
|
|
2793
2853
|
const findings = [];
|
|
@@ -2799,6 +2859,16 @@ function checkG2(rows, candidateFiles) {
|
|
|
2799
2859
|
});
|
|
2800
2860
|
}
|
|
2801
2861
|
}
|
|
2862
|
+
for (const row of rows) {
|
|
2863
|
+
const carriesPlaceholder = [row.summary, row.description, row.spec].some((cell) => cell === SCAFFOLD_PLACEHOLDER);
|
|
2864
|
+
if (carriesPlaceholder) {
|
|
2865
|
+
findings.push({
|
|
2866
|
+
row: row.action,
|
|
2867
|
+
path: row.implementation,
|
|
2868
|
+
reason: `${row.ring} row "${row.action}" still carries the scaffold placeholder marker — the why is owed`
|
|
2869
|
+
});
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2802
2872
|
return { check: "G2", status: findings.length > 0 ? "info" : "pass", findings };
|
|
2803
2873
|
}
|
|
2804
2874
|
function checkG3(ring0Rows, crossingFiles) {
|
|
@@ -3318,6 +3388,29 @@ function isNewDiskStateFile(path, status) {
|
|
|
3318
3388
|
return false;
|
|
3319
3389
|
return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
|
|
3320
3390
|
}
|
|
3391
|
+
// ../../packages/aeg-core/src/main-branch-refusal.ts
|
|
3392
|
+
function checkMainBranchRefusal(facts) {
|
|
3393
|
+
const { currentSymbolicBranch, defaultBranch } = facts;
|
|
3394
|
+
if (currentSymbolicBranch === null)
|
|
3395
|
+
return null;
|
|
3396
|
+
if (defaultBranch === null) {
|
|
3397
|
+
return {
|
|
3398
|
+
reason: "default-branch-undetermined",
|
|
3399
|
+
severity: "warning",
|
|
3400
|
+
currentBranch: currentSymbolicBranch,
|
|
3401
|
+
defaultBranch: null
|
|
3402
|
+
};
|
|
3403
|
+
}
|
|
3404
|
+
if (currentSymbolicBranch === defaultBranch) {
|
|
3405
|
+
return {
|
|
3406
|
+
reason: "on-default-branch",
|
|
3407
|
+
severity: "error",
|
|
3408
|
+
currentBranch: currentSymbolicBranch,
|
|
3409
|
+
defaultBranch
|
|
3410
|
+
};
|
|
3411
|
+
}
|
|
3412
|
+
return null;
|
|
3413
|
+
}
|
|
3321
3414
|
// ../../packages/aeg-core/src/branch-topology-gate.ts
|
|
3322
3415
|
function taskBranchTopologyFields(branch) {
|
|
3323
3416
|
if (!/^task\/.*\/.*$/.test(branch))
|
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
// src/checks/bin/check-reader-resolvable-prose.ts
|
|
4
4
|
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync } from "node:fs";
|
|
5
|
-
import { join as
|
|
5
|
+
import { join as join5, resolve } from "node:path";
|
|
6
6
|
// ../../packages/aeg-core/src/gate-audience.ts
|
|
7
7
|
var GATE_AUDIENCE = {
|
|
8
|
-
"check-branch-topology": { shippedAs: "branch-topology" },
|
|
9
|
-
"check-first-push-dispatch": { shippedAs: "first-push-dispatch" },
|
|
10
|
-
"check-no-disk-state": { shippedAs: "no-disk-state" },
|
|
11
|
-
"verify-brief": { shippedAs: "brief-shape" },
|
|
12
|
-
"verify-coherence": { shippedAs: "coherence" },
|
|
13
|
-
"verify-dispatch": { shippedAs: "dispatch-readiness" },
|
|
14
|
-
"verify-docs": { shippedAs: ["doc-coverage", "doc-coverage-push"] },
|
|
15
|
-
"verify-registry": { shippedAs: "registry-gates" },
|
|
16
|
-
"verify-review-gate": { shippedAs: "review-gate" },
|
|
17
|
-
"verify-single-plan-pr": { shippedAs: "single-plan-pr" },
|
|
18
|
-
"verify-test-plan": { shippedAs: "test-plan" },
|
|
8
|
+
"check-branch-topology": { shippedAs: "branch-topology", ring: 0 },
|
|
9
|
+
"check-first-push-dispatch": { shippedAs: "first-push-dispatch", ring: 0 },
|
|
10
|
+
"check-no-disk-state": { shippedAs: "no-disk-state", ring: 0 },
|
|
11
|
+
"verify-brief": { shippedAs: "brief-shape", ring: 0 },
|
|
12
|
+
"verify-coherence": { shippedAs: "coherence", ring: 0 },
|
|
13
|
+
"verify-dispatch": { shippedAs: "dispatch-readiness", ring: 0 },
|
|
14
|
+
"verify-docs": { shippedAs: ["doc-coverage", "doc-coverage-push"], ring: 0 },
|
|
15
|
+
"verify-registry": { shippedAs: "registry-gates", ring: 0 },
|
|
16
|
+
"verify-review-gate": { shippedAs: "review-gate", ring: 1 },
|
|
17
|
+
"verify-single-plan-pr": { shippedAs: "single-plan-pr", ring: 0 },
|
|
18
|
+
"verify-test-plan": { shippedAs: "test-plan", ring: 1 },
|
|
19
19
|
"check-direct-main-push": {
|
|
20
20
|
internal: "Reaches adopters through `vinaya audit --only=direct-push`, not the check registry: it is a ring-2 sweep over merge history keyed on `GITHUB_SHA`, run by the generated archivist job on push to the default branch. It has no diff to key on, so there is nothing for `vinaya check` to run it against."
|
|
21
21
|
},
|
|
@@ -327,6 +327,13 @@ var LABELS = [
|
|
|
327
327
|
form: "literal",
|
|
328
328
|
carries: "Execution is halted pending an external unblock; wins over every other derived status."
|
|
329
329
|
},
|
|
330
|
+
{
|
|
331
|
+
key: "backlog",
|
|
332
|
+
id: "vinaya/backlog",
|
|
333
|
+
category: "state",
|
|
334
|
+
form: "literal",
|
|
335
|
+
carries: "The Issue is deliberately unplanned — belongs to no tranche and is excluded from dispatch, until a Planner promotes it."
|
|
336
|
+
},
|
|
330
337
|
{
|
|
331
338
|
key: "tier-0",
|
|
332
339
|
id: "vinaya/tier:0",
|
|
@@ -1985,7 +1992,59 @@ function overrideActive(opts) {
|
|
|
1985
1992
|
return false;
|
|
1986
1993
|
}
|
|
1987
1994
|
// ../../packages/aeg-core/src/premise-check.ts
|
|
1995
|
+
import { createHash } from "node:crypto";
|
|
1988
1996
|
var ASSERTION_KINDS = new Set(["contains", "absent", "sha256"]);
|
|
1997
|
+
function isPremiseHeader(line) {
|
|
1998
|
+
const stripped = line.replace(/[*#]/g, "").trim();
|
|
1999
|
+
return /^premise\s*:?$/i.test(stripped);
|
|
2000
|
+
}
|
|
2001
|
+
var PREMISE_LINE = /^[-*]\s*(\S+)\s+(contains|absent|sha256)\s*:\s*(.+)$/i;
|
|
2002
|
+
function parsePremiseBlock(prBody) {
|
|
2003
|
+
const searchIn = anchoredRegion(prBody, "PREMISE") ?? prBody;
|
|
2004
|
+
const lines = searchIn.split(/\r?\n/);
|
|
2005
|
+
const assertions = [];
|
|
2006
|
+
let inBlock = false;
|
|
2007
|
+
for (const raw of lines) {
|
|
2008
|
+
const line = raw.trim();
|
|
2009
|
+
if (!inBlock) {
|
|
2010
|
+
if (isPremiseHeader(line))
|
|
2011
|
+
inBlock = true;
|
|
2012
|
+
continue;
|
|
2013
|
+
}
|
|
2014
|
+
if (line === "")
|
|
2015
|
+
break;
|
|
2016
|
+
const m = line.match(PREMISE_LINE);
|
|
2017
|
+
if (!m)
|
|
2018
|
+
break;
|
|
2019
|
+
const [, path, kindRaw, value] = m;
|
|
2020
|
+
const kind = kindRaw.toLowerCase();
|
|
2021
|
+
if (!ASSERTION_KINDS.has(kind))
|
|
2022
|
+
continue;
|
|
2023
|
+
assertions.push({ kind, path, value: value.trim() });
|
|
2024
|
+
}
|
|
2025
|
+
return assertions;
|
|
2026
|
+
}
|
|
2027
|
+
function checkPremises(assertions, fileReader) {
|
|
2028
|
+
const failures = [];
|
|
2029
|
+
for (const a of assertions) {
|
|
2030
|
+
const content = fileReader(a.path);
|
|
2031
|
+
if (content === null) {
|
|
2032
|
+
failures.push(`premise-check: ${a.path} does not exist on disk (premise asserted \`${a.kind}: ${a.value}\`) — the surface moved since this brief was authored; re-dig before proceeding.`);
|
|
2033
|
+
continue;
|
|
2034
|
+
}
|
|
2035
|
+
if (a.kind === "contains" && !content.includes(a.value)) {
|
|
2036
|
+
failures.push(`premise-check: ${a.path} no longer contains "${a.value}" — the premise this brief pinned has moved; re-dig before proceeding.`);
|
|
2037
|
+
} else if (a.kind === "absent" && content.includes(a.value)) {
|
|
2038
|
+
failures.push(`premise-check: ${a.path} now contains "${a.value}", but the brief pinned it absent — the premise has moved; re-dig before proceeding.`);
|
|
2039
|
+
} else if (a.kind === "sha256") {
|
|
2040
|
+
const actual = createHash("sha256").update(content).digest("hex");
|
|
2041
|
+
if (actual !== a.value.toLowerCase()) {
|
|
2042
|
+
failures.push(`premise-check: ${a.path} sha256 mismatch (brief pinned ${a.value}, file is now ${actual}) — the file changed since this brief was authored; re-dig before proceeding.`);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
return { pass: failures.length === 0, failures };
|
|
2047
|
+
}
|
|
1989
2048
|
|
|
1990
2049
|
// ../../packages/aeg-core/src/test-plan-section.ts
|
|
1991
2050
|
var HEADING_FORM_RE = /^#{1,4}[ \t]*(?:\d+[a-z]?\.[ \t]*)?\*{0,2}Test Plan\*{0,2}[ \t]*$/im;
|
|
@@ -2789,6 +2848,7 @@ function checkG1(rows, existsFn) {
|
|
|
2789
2848
|
}
|
|
2790
2849
|
return { check: "G1", status: findings.length > 0 ? "fail" : "pass", findings };
|
|
2791
2850
|
}
|
|
2851
|
+
var SCAFFOLD_PLACEHOLDER = "[undocumented — fill in why]";
|
|
2792
2852
|
function checkG2(rows, candidateFiles) {
|
|
2793
2853
|
const implementations = new Set(rows.map((r) => r.implementation).filter((p) => p !== ""));
|
|
2794
2854
|
const findings = [];
|
|
@@ -2800,6 +2860,16 @@ function checkG2(rows, candidateFiles) {
|
|
|
2800
2860
|
});
|
|
2801
2861
|
}
|
|
2802
2862
|
}
|
|
2863
|
+
for (const row of rows) {
|
|
2864
|
+
const carriesPlaceholder = [row.summary, row.description, row.spec].some((cell) => cell === SCAFFOLD_PLACEHOLDER);
|
|
2865
|
+
if (carriesPlaceholder) {
|
|
2866
|
+
findings.push({
|
|
2867
|
+
row: row.action,
|
|
2868
|
+
path: row.implementation,
|
|
2869
|
+
reason: `${row.ring} row "${row.action}" still carries the scaffold placeholder marker — the why is owed`
|
|
2870
|
+
});
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2803
2873
|
return { check: "G2", status: findings.length > 0 ? "info" : "pass", findings };
|
|
2804
2874
|
}
|
|
2805
2875
|
function checkG3(ring0Rows, crossingFiles) {
|
|
@@ -3319,6 +3389,29 @@ function isNewDiskStateFile(path, status) {
|
|
|
3319
3389
|
return false;
|
|
3320
3390
|
return ANY_DEPTH_TRANCHES_MD.test(path) || TOKENS_FILE.test(path);
|
|
3321
3391
|
}
|
|
3392
|
+
// ../../packages/aeg-core/src/main-branch-refusal.ts
|
|
3393
|
+
function checkMainBranchRefusal(facts) {
|
|
3394
|
+
const { currentSymbolicBranch, defaultBranch } = facts;
|
|
3395
|
+
if (currentSymbolicBranch === null)
|
|
3396
|
+
return null;
|
|
3397
|
+
if (defaultBranch === null) {
|
|
3398
|
+
return {
|
|
3399
|
+
reason: "default-branch-undetermined",
|
|
3400
|
+
severity: "warning",
|
|
3401
|
+
currentBranch: currentSymbolicBranch,
|
|
3402
|
+
defaultBranch: null
|
|
3403
|
+
};
|
|
3404
|
+
}
|
|
3405
|
+
if (currentSymbolicBranch === defaultBranch) {
|
|
3406
|
+
return {
|
|
3407
|
+
reason: "on-default-branch",
|
|
3408
|
+
severity: "error",
|
|
3409
|
+
currentBranch: currentSymbolicBranch,
|
|
3410
|
+
defaultBranch
|
|
3411
|
+
};
|
|
3412
|
+
}
|
|
3413
|
+
return null;
|
|
3414
|
+
}
|
|
3322
3415
|
// ../../packages/aeg-core/src/branch-topology-gate.ts
|
|
3323
3416
|
function taskBranchTopologyFields(branch) {
|
|
3324
3417
|
if (!/^task\/.*\/.*$/.test(branch))
|
|
@@ -3700,8 +3793,15 @@ function isSafeRepoRelPath(p) {
|
|
|
3700
3793
|
var SafeRepoRelPath = z.string().refine(isSafeRepoRelPath, {
|
|
3701
3794
|
message: "must be a repo-root-relative path with no `..` segment or absolute root"
|
|
3702
3795
|
});
|
|
3796
|
+
var CANONICAL_HOOK_BLOCK_PREFIXES = [".git/", ".husky/", ".vinaya/hooks/", ".claude/hooks/"];
|
|
3797
|
+
function isCanonicalHookBlockPath(p) {
|
|
3798
|
+
return CANONICAL_HOOK_BLOCK_PREFIXES.some((prefix) => p.startsWith(prefix) && p.length > prefix.length);
|
|
3799
|
+
}
|
|
3800
|
+
var ManagedHookBlockPath = SafeRepoRelPath.refine(isCanonicalHookBlockPath, {
|
|
3801
|
+
message: `must start with one of ${CANONICAL_HOOK_BLOCK_PREFIXES.join(", ")} (byte-exact, case-sensitive)`
|
|
3802
|
+
});
|
|
3703
3803
|
var ManagedBlockRecordSchema = z.object({
|
|
3704
|
-
path:
|
|
3804
|
+
path: ManagedHookBlockPath,
|
|
3705
3805
|
marker: z.string(),
|
|
3706
3806
|
comment: z.enum(["hash", "html"])
|
|
3707
3807
|
});
|
|
@@ -3882,6 +3982,71 @@ function emitCheckError(error) {
|
|
|
3882
3982
|
`);
|
|
3883
3983
|
}
|
|
3884
3984
|
|
|
3985
|
+
// src/lib/diff-evidence.ts
|
|
3986
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3987
|
+
import { join as join4 } from "node:path";
|
|
3988
|
+
function fileDiffAgainst(ref, path) {
|
|
3989
|
+
let out;
|
|
3990
|
+
try {
|
|
3991
|
+
out = execFileSync3("git", ["diff", `${ref}...HEAD`, "--", path], {
|
|
3992
|
+
encoding: "utf8",
|
|
3993
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3994
|
+
}).trim();
|
|
3995
|
+
} catch {
|
|
3996
|
+
return null;
|
|
3997
|
+
}
|
|
3998
|
+
return out === "" ? null : out;
|
|
3999
|
+
}
|
|
4000
|
+
function revParse(ref) {
|
|
4001
|
+
try {
|
|
4002
|
+
return execFileSync3("git", ["rev-parse", "--verify", ref], {
|
|
4003
|
+
encoding: "utf8",
|
|
4004
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4005
|
+
}).trim();
|
|
4006
|
+
} catch {
|
|
4007
|
+
return null;
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
function repoRoot() {
|
|
4011
|
+
try {
|
|
4012
|
+
return execFileSync3("git", ["rev-parse", "--show-toplevel"], {
|
|
4013
|
+
encoding: "utf8",
|
|
4014
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4015
|
+
}).trim();
|
|
4016
|
+
} catch {
|
|
4017
|
+
return null;
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
function changedFiles(base) {
|
|
4021
|
+
let out;
|
|
4022
|
+
try {
|
|
4023
|
+
out = execFileSync3("git", ["diff", "--name-only", `${base}...HEAD`], {
|
|
4024
|
+
encoding: "utf8",
|
|
4025
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4026
|
+
}).trim();
|
|
4027
|
+
} catch {
|
|
4028
|
+
return null;
|
|
4029
|
+
}
|
|
4030
|
+
return out === "" ? [] : out.split(`
|
|
4031
|
+
`).map((s) => s.trim()).filter(Boolean);
|
|
4032
|
+
}
|
|
4033
|
+
function resolveChangedFiles(base = process.env.BASE_SHA || "origin/main") {
|
|
4034
|
+
const root = repoRoot();
|
|
4035
|
+
if (root === null)
|
|
4036
|
+
return null;
|
|
4037
|
+
const head = revParse("HEAD");
|
|
4038
|
+
for (const ref of [base, "main"]) {
|
|
4039
|
+
const resolved = revParse(ref);
|
|
4040
|
+
if (resolved === null || resolved === head)
|
|
4041
|
+
continue;
|
|
4042
|
+
const relPaths = changedFiles(ref);
|
|
4043
|
+
if (relPaths === null)
|
|
4044
|
+
continue;
|
|
4045
|
+
return relPaths.map((p) => join4(root, p));
|
|
4046
|
+
}
|
|
4047
|
+
return null;
|
|
4048
|
+
}
|
|
4049
|
+
|
|
3885
4050
|
// src/checks/bin/check-reader-resolvable-prose.ts
|
|
3886
4051
|
var CHECK_NAME = "reader-resolvable-prose";
|
|
3887
4052
|
var proseGates = loadConfig()?.proseGates;
|
|
@@ -3898,7 +4063,7 @@ function collect(dir, out = []) {
|
|
|
3898
4063
|
return out;
|
|
3899
4064
|
}
|
|
3900
4065
|
for (const name of entries) {
|
|
3901
|
-
const full =
|
|
4066
|
+
const full = join5(dir, name);
|
|
3902
4067
|
let isDir;
|
|
3903
4068
|
try {
|
|
3904
4069
|
isDir = statSync(full).isDirectory();
|
|
@@ -3934,14 +4099,18 @@ function main() {
|
|
|
3934
4099
|
const shipsPaths = collect(DOCTRINE_ROOT).filter((p) => p.endsWith(".md"));
|
|
3935
4100
|
const readerFacingPaths = READER_FACING_ACTIVE && READER_FACING_SUFFIX !== null ? collect(READER_FACING_PREFIX).filter((p) => p.endsWith(READER_FACING_SUFFIX)) : [];
|
|
3936
4101
|
const files = readAll([...shipsPaths, ...readerFacingPaths]);
|
|
3937
|
-
const glossaryPath =
|
|
4102
|
+
const glossaryPath = join5(DOCTRINE_ROOT, "glossary.md");
|
|
3938
4103
|
const glossaryTerms = existsSync4(glossaryPath) ? parseGlossaryTerms(readFileSync3(glossaryPath, "utf8")) : [];
|
|
3939
4104
|
const { slugs, dormant: legacySlugsDormant } = legacySlugs();
|
|
3940
4105
|
const readerFacingPrefix = READER_FACING_ACTIVE && READER_FACING_PREFIX !== null ? `${READER_FACING_PREFIX}/` : "/no-reader-facing-surface";
|
|
3941
4106
|
const readerFacingSuffix = READER_FACING_ACTIVE && READER_FACING_SUFFIX !== null ? READER_FACING_SUFFIX : "/page.tsx";
|
|
3942
4107
|
const findings = checkReaderResolvableProse(files, glossaryTerms, readerFacingPrefix, readerFacingSuffix, slugs, shipsPrefix);
|
|
3943
|
-
|
|
3944
|
-
|
|
4108
|
+
const changedFilesList = resolveChangedFiles();
|
|
4109
|
+
const changed = changedFilesList === null ? null : new Set(changedFilesList);
|
|
4110
|
+
const pathBase = repoRoot() ?? process.cwd();
|
|
4111
|
+
const reportable = changed === null ? findings : findings.filter((f) => changed.has(resolve(pathBase, f.file)));
|
|
4112
|
+
console.log(`${CHECK_NAME}: doctrine root "${DOCTRINE_ROOT}"; reader-facing class ${READER_FACING_ACTIVE ? "ran" : "dormant — proseGates.readerFacingPrefix/readerFacingSuffix not both set"}; ` + `legacy-slug class ${legacySlugsDormant ? `dormant — ${LEGACY_SLUG_DIR} is absent` : `ran (${slugs.length} slug(s))`}; ` + `${findings.length} finding(s) swept, ${reportable.length} in this diff`);
|
|
4113
|
+
for (const finding of reportable) {
|
|
3945
4114
|
emitCheckError({
|
|
3946
4115
|
schema: CHECK_SCHEMA_VERSION,
|
|
3947
4116
|
check: CHECK_NAME,
|