@attalabs/vinaya 0.25.0 → 0.26.0
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 +4 -4
- package/aeg-root/contracts/architect-planner.md +5 -5
- package/aeg-root/contracts/developer-reviewer.md +7 -7
- package/aeg-root/contracts/planner-developer.md +142 -0
- package/aeg-root/contracts/reviewer-archivist.md +2 -2
- package/aeg-root/contracts/tranche-archivist-planner.md +12 -11
- package/aeg-root/enforcement.md +15 -5
- package/aeg-root/process.md +53 -75
- package/aeg-root/roles/archivist.md +3 -3
- package/aeg-root/roles/developer.md +10 -10
- package/aeg-root/roles/planner.md +88 -23
- package/aeg-root/roles/principal.md +11 -11
- package/aeg-root/roles/reviewer.md +10 -10
- package/aeg-root/roles/security.md +7 -7
- package/aeg-root/roles/tranche-archivist.md +2 -2
- package/aeg-root/skills/aeg/SKILL.md +5 -5
- package/aeg-root/skills/aeg-roles/SKILL.md +7 -7
- package/aeg-root/state-machine.md +35 -34
- package/aeg-root/task-model.md +3 -3
- package/aeg-root/templates/brief-template.md +2 -2
- package/aeg-root/templates/issue-rationale-template.md +3 -3
- package/aeg-root/tranche-model.md +21 -21
- package/dist/checks/bin/check-body-bare-digits.js +116 -19
- package/dist/checks/bin/check-branch-topology.js +116 -19
- package/dist/checks/bin/check-brief-shape.js +121 -1101
- package/dist/checks/bin/check-changeset-coverage.js +877 -26
- package/dist/checks/bin/check-closes-n.js +116 -19
- package/dist/checks/bin/check-coherence.js +116 -19
- package/dist/checks/bin/check-dead-branch-push.js +116 -19
- package/dist/checks/bin/check-dispatch-readiness.js +119 -22
- package/dist/checks/bin/check-doc-coverage-push.js +877 -26
- package/dist/checks/bin/check-doc-coverage.js +879 -28
- package/dist/checks/bin/check-doctrine-no-procedures.js +116 -19
- package/dist/checks/bin/check-doctrine-portability.js +877 -26
- package/dist/checks/bin/check-evidence-fresh.js +116 -19
- package/dist/checks/bin/check-exec-bits.js +877 -26
- package/dist/checks/bin/check-first-push-dispatch.js +116 -19
- package/dist/checks/bin/check-issue-assignment.js +116 -19
- package/dist/checks/bin/check-main-branch-refusal.js +117 -20
- package/dist/checks/bin/check-no-disk-state.js +116 -19
- package/dist/checks/bin/check-pr-premise-reassert.js +5401 -0
- package/dist/checks/bin/check-pr-report-density.js +116 -19
- package/dist/checks/bin/check-quoted-command.js +875 -24
- package/dist/checks/bin/check-reader-resolvable-prose.js +875 -24
- package/dist/checks/bin/check-registry-gates.js +147 -21
- package/dist/checks/bin/check-retired-vocabulary.js +875 -24
- package/dist/checks/bin/check-review-gate.js +116 -19
- package/dist/checks/bin/check-single-plan-pr.js +116 -19
- package/dist/checks/bin/check-surface-scope.js +5722 -0
- package/dist/checks/bin/check-test-plan.js +116 -19
- package/dist/checks/bin/check-token-collection-wired.js +116 -19
- package/dist/checks/bin/check-token-report.js +128 -26
- package/dist/checks/bin/check-workspace-escape.js +875 -24
- package/dist/index.js +1002 -214
- package/package.json +1 -1
- package/aeg-root/contracts/brief-developer.md +0 -141
- package/aeg-root/contracts/planner-brief.md +0 -143
- package/aeg-root/roles/brief-author.md +0 -116
- package/aeg-root/skills/brief-authoring/SKILL.md +0 -509
|
@@ -29,6 +29,15 @@ var GATE_AUDIENCE = {
|
|
|
29
29
|
internal: "A composite that shells this repo's own `typecheck`/`lint`/`test`/`build` scripts by name. Those names are this monorepo's toolchain (bun + turbo + biome), not an adopter's; the shipped equivalent of its intent is `vinaya check --all`, which is portable by construction."
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
|
+
var NON_GATE_BINS = [
|
|
33
|
+
"archive-task",
|
|
34
|
+
"assign-task-issue",
|
|
35
|
+
"dead-branch-audit",
|
|
36
|
+
"eval-agent-compliance",
|
|
37
|
+
"open-issue",
|
|
38
|
+
"open-pr",
|
|
39
|
+
"report-tokens"
|
|
40
|
+
];
|
|
32
41
|
function isShipped(a) {
|
|
33
42
|
return "shippedAs" in a;
|
|
34
43
|
}
|
|
@@ -389,7 +398,7 @@ var LABELS = [
|
|
|
389
398
|
id: "vinaya/needs:brief-correction",
|
|
390
399
|
category: "needs",
|
|
391
400
|
form: "literal",
|
|
392
|
-
carries: "Waiting on the
|
|
401
|
+
carries: "Waiting on the Planner — the brief contradicts the surface it describes."
|
|
393
402
|
},
|
|
394
403
|
{
|
|
395
404
|
key: "waiver-docs",
|
|
@@ -2396,7 +2405,7 @@ function objectivesOf(body) {
|
|
|
2396
2405
|
continue;
|
|
2397
2406
|
}
|
|
2398
2407
|
if (hasBacktickedPath(text) && wordCount(stripObjectiveBackticks(text)) < MIN_WORDS_OUTSIDE_BACKTICKS) {
|
|
2399
|
-
errors.push(`O${n} is little more than a file path — an objective states an observable outcome, never a bare path (the
|
|
2408
|
+
errors.push(`O${n} is little more than a file path — an objective states an observable outcome, never a bare path (the Planner maps it to files).`);
|
|
2400
2409
|
continue;
|
|
2401
2410
|
}
|
|
2402
2411
|
objectives.push({ id: `O${n}`, text });
|
|
@@ -2608,18 +2617,14 @@ function checkTestPlanExclusivity(prBody) {
|
|
|
2608
2617
|
function checkPrincipalPlaceholder(prBody) {
|
|
2609
2618
|
const region = testPlanRegion(prBody);
|
|
2610
2619
|
const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
|
|
2620
|
+
const errors = [];
|
|
2611
2621
|
for (const m of region.matchAll(lineRe)) {
|
|
2612
2622
|
const content = m[1] ?? "";
|
|
2613
2623
|
if (/^\s*None\b/i.test(content)) {
|
|
2614
|
-
|
|
2615
|
-
status: "fail",
|
|
2616
|
-
errors: [
|
|
2617
|
-
'brief-validation Test Plan shape: a `**[principal]**` checkbox item is a "None" placeholder — if there is no principal-runnable surface, omit the item entirely; an untickable placeholder box blocks the merge gate forever.'
|
|
2618
|
-
]
|
|
2619
|
-
};
|
|
2624
|
+
errors.push(`brief-validation Test Plan shape: a \`**[principal]**\` checkbox item is a "None" placeholder ("${content.trim()}") — if there is no principal-runnable surface, omit the item entirely; an untickable placeholder box blocks the merge gate forever.`);
|
|
2620
2625
|
}
|
|
2621
2626
|
}
|
|
2622
|
-
return { status: "pass", errors: [] };
|
|
2627
|
+
return errors.length > 0 ? { status: "fail", errors } : { status: "pass", errors: [] };
|
|
2623
2628
|
}
|
|
2624
2629
|
function checkSurfaceMap(prBody) {
|
|
2625
2630
|
return headingCheck(prBody, "(?:technical\\s+)?surface map", "Technical surface map");
|
|
@@ -2935,6 +2940,18 @@ function checkBriefSections(prBody, readTier, options = {}) {
|
|
|
2935
2940
|
];
|
|
2936
2941
|
return { errors: results.flatMap((r) => r.errors) };
|
|
2937
2942
|
}
|
|
2943
|
+
var AEG_BRIEF_V1_MARKER = "<!-- aeg:brief:v1 -->";
|
|
2944
|
+
function contentAfterTwoLines(body) {
|
|
2945
|
+
const first = body.indexOf(`
|
|
2946
|
+
`);
|
|
2947
|
+
if (first === -1)
|
|
2948
|
+
return "";
|
|
2949
|
+
const second = body.indexOf(`
|
|
2950
|
+
`, first + 1);
|
|
2951
|
+
if (second === -1)
|
|
2952
|
+
return "";
|
|
2953
|
+
return body.slice(second + 1);
|
|
2954
|
+
}
|
|
2938
2955
|
// ../../packages/aeg-core/src/doctrine-portability.ts
|
|
2939
2956
|
var DEFAULT_SHIPS_PREFIX = "aeg-root/";
|
|
2940
2957
|
var STATIC_PORTABLE_PREFIXES = [
|
|
@@ -3177,6 +3194,66 @@ function checkIssueObjectives(body, issueNumber) {
|
|
|
3177
3194
|
return { status: "pass", errors: [] };
|
|
3178
3195
|
return { status: "fail", errors: result.errors.map((e) => `issue-validation objectives: ${e}`) };
|
|
3179
3196
|
}
|
|
3197
|
+
function topLevelSectionText(body, headingName) {
|
|
3198
|
+
const headingRe = new RegExp(`^##[ \\t]*${headingName}[ \\t]*$`, "im");
|
|
3199
|
+
const heading = headingRe.exec(body);
|
|
3200
|
+
if (!heading)
|
|
3201
|
+
return null;
|
|
3202
|
+
const afterHeading = body.slice(heading.index + heading[0].length);
|
|
3203
|
+
const next = /^##[ \t]/m.exec(afterHeading);
|
|
3204
|
+
return next ? afterHeading.slice(0, next.index) : afterHeading;
|
|
3205
|
+
}
|
|
3206
|
+
function looksLikeFilePath(entry2) {
|
|
3207
|
+
const stripped = entry2.replace(/\/\*\*?$/, "");
|
|
3208
|
+
const lastSegment = stripped.split("/").pop() ?? stripped;
|
|
3209
|
+
const extMatch = /\.[A-Za-z0-9]{1,6}$/.exec(lastSegment);
|
|
3210
|
+
return extMatch !== null && extMatch.index > 0;
|
|
3211
|
+
}
|
|
3212
|
+
function splitGlobList(raw) {
|
|
3213
|
+
return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
3214
|
+
}
|
|
3215
|
+
function parseIssueSurface(body) {
|
|
3216
|
+
const section = topLevelSectionText(body, "Surface");
|
|
3217
|
+
if (section === null)
|
|
3218
|
+
return { ok: false, errors: ["no `## Surface` heading found in the body."] };
|
|
3219
|
+
const inLine = /^in:\s*(.+)$/im.exec(section);
|
|
3220
|
+
const outLine = /^out:\s*(.+)$/im.exec(section);
|
|
3221
|
+
const errors = [];
|
|
3222
|
+
if (!inLine)
|
|
3223
|
+
errors.push("`## Surface` has no `in:` line.");
|
|
3224
|
+
if (!outLine)
|
|
3225
|
+
errors.push("`## Surface` has no `out:` line.");
|
|
3226
|
+
if (errors.length > 0)
|
|
3227
|
+
return { ok: false, errors };
|
|
3228
|
+
const inGlobs = splitGlobList(inLine[1]);
|
|
3229
|
+
const outGlobs = splitGlobList(outLine[1]);
|
|
3230
|
+
for (const g of [...inGlobs, ...outGlobs]) {
|
|
3231
|
+
if (looksLikeFilePath(g)) {
|
|
3232
|
+
errors.push(`\`${g}\` in \`## Surface\` looks like a file path — Surface entries are directory-level globs, never file paths.`);
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
if (inGlobs.length === 0)
|
|
3236
|
+
errors.push("`## Surface`'s `in:` line resolved to zero globs.");
|
|
3237
|
+
if (errors.length > 0)
|
|
3238
|
+
return { ok: false, errors };
|
|
3239
|
+
return { ok: true, value: { in: inGlobs, out: outGlobs } };
|
|
3240
|
+
}
|
|
3241
|
+
function globCoversPath(glob, path) {
|
|
3242
|
+
const g = glob.replace(/\/\*\*?$/, "").replace(/\/+$/, "");
|
|
3243
|
+
const p = path.replace(/\/+$/, "");
|
|
3244
|
+
return g === p || g.startsWith(`${p}/`) || p.startsWith(`${g}/`);
|
|
3245
|
+
}
|
|
3246
|
+
function checkSurfaceScope(changedFiles, outGlobs) {
|
|
3247
|
+
if (outGlobs.length === 0)
|
|
3248
|
+
return { ok: true };
|
|
3249
|
+
const violations = [];
|
|
3250
|
+
for (const file of changedFiles) {
|
|
3251
|
+
const glob = outGlobs.find((g) => globCoversPath(g, file));
|
|
3252
|
+
if (glob)
|
|
3253
|
+
violations.push({ file, glob });
|
|
3254
|
+
}
|
|
3255
|
+
return violations.length > 0 ? { ok: false, violations } : { ok: true };
|
|
3256
|
+
}
|
|
3180
3257
|
function isTaskIssueLabelSet(labels) {
|
|
3181
3258
|
return hasLabel("tranche", labels);
|
|
3182
3259
|
}
|
|
@@ -3241,6 +3318,8 @@ function checkProjectsRegistered(body, _labels, registeredNames) {
|
|
|
3241
3318
|
}
|
|
3242
3319
|
return errors.length > 0 ? { status: "fail", errors } : { status: "pass", errors: [] };
|
|
3243
3320
|
}
|
|
3321
|
+
var DOC_PATH_RE = /(?:(?:aeg-root|apps|packages|specs|docs|tools|\.claude|\.github)\/[\w./@-]*\.(?:md|mdx)|\.claude\/(?:skills|rules)\/[\w./-]+|\b(?:docs-index|decisions|projects|state-machine|enforcement|process|README|CLAUDE)\.md\b|\b[\w-]+-(?:spec|decisions|backlog)\.md\b)/i;
|
|
3322
|
+
var DOC_PATH_RE_GLOBAL = new RegExp(DOC_PATH_RE.source, "gi");
|
|
3244
3323
|
|
|
3245
3324
|
// ../../packages/aeg-core/src/coherence-checks.ts
|
|
3246
3325
|
var COHERENCE_ENFORCED_FROM = "2026-07-01";
|
|
@@ -3770,16 +3849,33 @@ function checkG1(rows, existsFn) {
|
|
|
3770
3849
|
return { check: "G1", status: findings.length > 0 ? "fail" : "pass", findings };
|
|
3771
3850
|
}
|
|
3772
3851
|
var SCAFFOLD_PLACEHOLDER = "[undocumented — fill in why]";
|
|
3852
|
+
var NON_GATE_BIN_NAMES = NON_GATE_BINS;
|
|
3853
|
+
var TWIN_CANDIDATE_EXCEPTIONS = {
|
|
3854
|
+
"apps/cli/src/checks/bin/check-dead-branch-push.ts": 'Ring 0 "Pushing to a branch whose pull request already resolved" (implementation: check-push-target.ts)',
|
|
3855
|
+
"apps/cli/src/checks/bin/check-issue-assignment.ts": `Ring 0 "A task branch's first push (Issue self-assignment)" (implementation: assign-task-issue.ts)`,
|
|
3856
|
+
"apps/cli/src/checks/bin/check-closes-n.ts": 'Ring 1 "Closes linkage" (implementation: verify-coherence.ts)'
|
|
3857
|
+
};
|
|
3858
|
+
var NON_GATE_HOOK_SCRIPTS = [".claude/hooks/track-transcript.sh"];
|
|
3773
3859
|
function checkG2(rows, candidateFiles) {
|
|
3774
3860
|
const implementations = new Set(rows.map((r) => r.implementation).filter((p) => p !== ""));
|
|
3861
|
+
const claimedNames = new Set(rows.flatMap((r) => claimedCheckNames(r.implementation)));
|
|
3775
3862
|
const findings = [];
|
|
3776
3863
|
for (const path of candidateFiles) {
|
|
3777
|
-
if (
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3864
|
+
if (implementations.has(path))
|
|
3865
|
+
continue;
|
|
3866
|
+
if (path.startsWith(AEG_CORE_BIN_PATH_PREFIX) && NON_GATE_BIN_NAMES.includes(basenameNoExt(path)))
|
|
3867
|
+
continue;
|
|
3868
|
+
if (NON_GATE_HOOK_SCRIPTS.includes(path))
|
|
3869
|
+
continue;
|
|
3870
|
+
if (path in TWIN_CANDIDATE_EXCEPTIONS)
|
|
3871
|
+
continue;
|
|
3872
|
+
const candidateNames = claimedCheckNames(path);
|
|
3873
|
+
if (candidateNames.length > 0 && candidateNames.some((n) => claimedNames.has(n)))
|
|
3874
|
+
continue;
|
|
3875
|
+
findings.push({
|
|
3876
|
+
path,
|
|
3877
|
+
reason: `"${path}" is not named as the implementation of any row in enforcement.md's ring tables`
|
|
3878
|
+
});
|
|
3783
3879
|
}
|
|
3784
3880
|
for (const row of rows) {
|
|
3785
3881
|
const carriesPlaceholder = [row.summary, row.description, row.spec].some((cell) => cell === SCAFFOLD_PLACEHOLDER);
|
|
@@ -3791,7 +3887,7 @@ function checkG2(rows, candidateFiles) {
|
|
|
3791
3887
|
});
|
|
3792
3888
|
}
|
|
3793
3889
|
}
|
|
3794
|
-
return { check: "G2", status: findings.length > 0 ? "
|
|
3890
|
+
return { check: "G2", status: findings.length > 0 ? "fail" : "pass", findings };
|
|
3795
3891
|
}
|
|
3796
3892
|
function checkG3(ring0Rows, crossingFiles) {
|
|
3797
3893
|
const ring0Implementations = new Set(ring0Rows.map((r) => r.implementation));
|
|
@@ -4667,7 +4763,6 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
|
|
|
4667
4763
|
import { z } from "zod";
|
|
4668
4764
|
var ROLE_VALUES = [
|
|
4669
4765
|
"planner",
|
|
4670
|
-
"brief-author",
|
|
4671
4766
|
"developer",
|
|
4672
4767
|
"code-reviewer",
|
|
4673
4768
|
"security",
|
|
@@ -4741,18 +4836,20 @@ var dispatchShared = {
|
|
|
4741
4836
|
round: z.number().int().optional(),
|
|
4742
4837
|
effect_id: z.string()
|
|
4743
4838
|
};
|
|
4839
|
+
var dispatchUsageField = z.object({ input: z.number().nonnegative(), output: z.number().nonnegative() }).strict().nullable();
|
|
4744
4840
|
var DispatchEventSchema = z.discriminatedUnion("event", [
|
|
4745
4841
|
z.object({ ...dispatchShared, event: z.literal("dispatched"), prompt_hash: z.string() }).strict(),
|
|
4746
4842
|
z.object({
|
|
4747
4843
|
...dispatchShared,
|
|
4748
4844
|
event: z.literal("outcome_received"),
|
|
4749
4845
|
outcome: DispatchOutcomeSchema,
|
|
4750
|
-
usage:
|
|
4846
|
+
usage: dispatchUsageField
|
|
4751
4847
|
}).strict(),
|
|
4752
4848
|
z.object({
|
|
4753
4849
|
...dispatchShared,
|
|
4754
4850
|
event: z.literal("dispatch_failed"),
|
|
4755
|
-
reason: z.enum(["timeout", "crash", "refused", "unattributed_write"])
|
|
4851
|
+
reason: z.enum(["timeout", "crash", "refused", "unattributed_write"]),
|
|
4852
|
+
usage: dispatchUsageField
|
|
4756
4853
|
}).strict()
|
|
4757
4854
|
]);
|
|
4758
4855
|
var loopShared = {
|
|
@@ -4977,6 +5074,18 @@ var REGISTRY = [
|
|
|
4977
5074
|
},
|
|
4978
5075
|
0
|
|
4979
5076
|
],
|
|
5077
|
+
[
|
|
5078
|
+
{
|
|
5079
|
+
name: "pr-premise-reassert",
|
|
5080
|
+
run: bin("check-pr-premise-reassert"),
|
|
5081
|
+
scope: "diff",
|
|
5082
|
+
timeoutMs: 15000,
|
|
5083
|
+
env: {
|
|
5084
|
+
PR_BODY: { optional: true }
|
|
5085
|
+
}
|
|
5086
|
+
},
|
|
5087
|
+
0
|
|
5088
|
+
],
|
|
4980
5089
|
[
|
|
4981
5090
|
{
|
|
4982
5091
|
name: "dispatch-readiness",
|
|
@@ -5025,6 +5134,22 @@ var REGISTRY = [
|
|
|
5025
5134
|
},
|
|
5026
5135
|
0
|
|
5027
5136
|
],
|
|
5137
|
+
[
|
|
5138
|
+
{
|
|
5139
|
+
name: "surface-scope",
|
|
5140
|
+
run: bin("check-surface-scope"),
|
|
5141
|
+
scope: "diff",
|
|
5142
|
+
timeoutMs: 15000,
|
|
5143
|
+
env: {
|
|
5144
|
+
AEG_REPO: { optional: true },
|
|
5145
|
+
BASE_SHA: { optional: true },
|
|
5146
|
+
BRANCH: { optional: true },
|
|
5147
|
+
GITHUB_TOKEN: { optional: true },
|
|
5148
|
+
GH_TOKEN: { optional: true }
|
|
5149
|
+
}
|
|
5150
|
+
},
|
|
5151
|
+
0
|
|
5152
|
+
],
|
|
5028
5153
|
[
|
|
5029
5154
|
{
|
|
5030
5155
|
name: "test-plan",
|
|
@@ -5066,6 +5191,7 @@ var REGISTRY = [
|
|
|
5066
5191
|
requiresOpenPr: true,
|
|
5067
5192
|
env: {
|
|
5068
5193
|
PR_BODY: { optional: true },
|
|
5194
|
+
BRANCH: { optional: true },
|
|
5069
5195
|
CLAUDE_PROJECT_DIR: { optional: true },
|
|
5070
5196
|
CLAUDE_CODE_SESSION_ID: { optional: true }
|
|
5071
5197
|
}
|
|
@@ -5488,13 +5614,13 @@ async function main() {
|
|
|
5488
5614
|
const g3 = checkG3(ring0Rows, crossingFiles);
|
|
5489
5615
|
const g5 = checkG5(roles, contracts);
|
|
5490
5616
|
const g6 = checkG6(rows, new Set(coreCheckRegistry().map((s) => s.name)));
|
|
5491
|
-
emitResult(g2, false);
|
|
5492
5617
|
emitResult(g1, true);
|
|
5618
|
+
emitResult(g2, true);
|
|
5493
5619
|
emitResult(g3, true);
|
|
5494
5620
|
emitResult(g4Result, true);
|
|
5495
5621
|
emitResult(g5, true);
|
|
5496
5622
|
emitResult(g6, true);
|
|
5497
|
-
const blockingFailed = [g1, g3, g4Result, g5, g6].some((r) => r.status === "fail");
|
|
5623
|
+
const blockingFailed = [g1, g2, g3, g4Result, g5, g6].some((r) => r.status === "fail");
|
|
5498
5624
|
process.exit(blockingFailed ? 1 : 0);
|
|
5499
5625
|
}
|
|
5500
5626
|
main();
|