@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
|
@@ -24,6 +24,15 @@ var GATE_AUDIENCE = {
|
|
|
24
24
|
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."
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
+
var NON_GATE_BINS = [
|
|
28
|
+
"archive-task",
|
|
29
|
+
"assign-task-issue",
|
|
30
|
+
"dead-branch-audit",
|
|
31
|
+
"eval-agent-compliance",
|
|
32
|
+
"open-issue",
|
|
33
|
+
"open-pr",
|
|
34
|
+
"report-tokens"
|
|
35
|
+
];
|
|
27
36
|
function isShipped(a) {
|
|
28
37
|
return "shippedAs" in a;
|
|
29
38
|
}
|
|
@@ -384,7 +393,7 @@ var LABELS = [
|
|
|
384
393
|
id: "vinaya/needs:brief-correction",
|
|
385
394
|
category: "needs",
|
|
386
395
|
form: "literal",
|
|
387
|
-
carries: "Waiting on the
|
|
396
|
+
carries: "Waiting on the Planner — the brief contradicts the surface it describes."
|
|
388
397
|
},
|
|
389
398
|
{
|
|
390
399
|
key: "waiver-docs",
|
|
@@ -2391,7 +2400,7 @@ function objectivesOf(body) {
|
|
|
2391
2400
|
continue;
|
|
2392
2401
|
}
|
|
2393
2402
|
if (hasBacktickedPath(text) && wordCount(stripObjectiveBackticks(text)) < MIN_WORDS_OUTSIDE_BACKTICKS) {
|
|
2394
|
-
errors.push(`O${n} is little more than a file path — an objective states an observable outcome, never a bare path (the
|
|
2403
|
+
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).`);
|
|
2395
2404
|
continue;
|
|
2396
2405
|
}
|
|
2397
2406
|
objectives.push({ id: `O${n}`, text });
|
|
@@ -2603,18 +2612,14 @@ function checkTestPlanExclusivity(prBody) {
|
|
|
2603
2612
|
function checkPrincipalPlaceholder(prBody) {
|
|
2604
2613
|
const region = testPlanRegion(prBody);
|
|
2605
2614
|
const lineRe = /^-\s*\[[ xX]\]\s*\*{2}\[principal\]\*{2}(.*)$/gim;
|
|
2615
|
+
const errors = [];
|
|
2606
2616
|
for (const m of region.matchAll(lineRe)) {
|
|
2607
2617
|
const content = m[1] ?? "";
|
|
2608
2618
|
if (/^\s*None\b/i.test(content)) {
|
|
2609
|
-
|
|
2610
|
-
status: "fail",
|
|
2611
|
-
errors: [
|
|
2612
|
-
'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.'
|
|
2613
|
-
]
|
|
2614
|
-
};
|
|
2619
|
+
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.`);
|
|
2615
2620
|
}
|
|
2616
2621
|
}
|
|
2617
|
-
return { status: "pass", errors: [] };
|
|
2622
|
+
return errors.length > 0 ? { status: "fail", errors } : { status: "pass", errors: [] };
|
|
2618
2623
|
}
|
|
2619
2624
|
function checkSurfaceMap(prBody) {
|
|
2620
2625
|
return headingCheck(prBody, "(?:technical\\s+)?surface map", "Technical surface map");
|
|
@@ -2930,6 +2935,18 @@ function checkBriefSections(prBody, readTier, options = {}) {
|
|
|
2930
2935
|
];
|
|
2931
2936
|
return { errors: results.flatMap((r) => r.errors) };
|
|
2932
2937
|
}
|
|
2938
|
+
var AEG_BRIEF_V1_MARKER = "<!-- aeg:brief:v1 -->";
|
|
2939
|
+
function contentAfterTwoLines(body) {
|
|
2940
|
+
const first = body.indexOf(`
|
|
2941
|
+
`);
|
|
2942
|
+
if (first === -1)
|
|
2943
|
+
return "";
|
|
2944
|
+
const second = body.indexOf(`
|
|
2945
|
+
`, first + 1);
|
|
2946
|
+
if (second === -1)
|
|
2947
|
+
return "";
|
|
2948
|
+
return body.slice(second + 1);
|
|
2949
|
+
}
|
|
2933
2950
|
// ../../packages/aeg-core/src/doctrine-portability.ts
|
|
2934
2951
|
var DEFAULT_SHIPS_PREFIX = "aeg-root/";
|
|
2935
2952
|
var STATIC_PORTABLE_PREFIXES = [
|
|
@@ -3172,6 +3189,66 @@ function checkIssueObjectives(body, issueNumber) {
|
|
|
3172
3189
|
return { status: "pass", errors: [] };
|
|
3173
3190
|
return { status: "fail", errors: result.errors.map((e) => `issue-validation objectives: ${e}`) };
|
|
3174
3191
|
}
|
|
3192
|
+
function topLevelSectionText(body, headingName) {
|
|
3193
|
+
const headingRe = new RegExp(`^##[ \\t]*${headingName}[ \\t]*$`, "im");
|
|
3194
|
+
const heading = headingRe.exec(body);
|
|
3195
|
+
if (!heading)
|
|
3196
|
+
return null;
|
|
3197
|
+
const afterHeading = body.slice(heading.index + heading[0].length);
|
|
3198
|
+
const next = /^##[ \t]/m.exec(afterHeading);
|
|
3199
|
+
return next ? afterHeading.slice(0, next.index) : afterHeading;
|
|
3200
|
+
}
|
|
3201
|
+
function looksLikeFilePath(entry2) {
|
|
3202
|
+
const stripped = entry2.replace(/\/\*\*?$/, "");
|
|
3203
|
+
const lastSegment = stripped.split("/").pop() ?? stripped;
|
|
3204
|
+
const extMatch = /\.[A-Za-z0-9]{1,6}$/.exec(lastSegment);
|
|
3205
|
+
return extMatch !== null && extMatch.index > 0;
|
|
3206
|
+
}
|
|
3207
|
+
function splitGlobList(raw) {
|
|
3208
|
+
return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
3209
|
+
}
|
|
3210
|
+
function parseIssueSurface(body) {
|
|
3211
|
+
const section = topLevelSectionText(body, "Surface");
|
|
3212
|
+
if (section === null)
|
|
3213
|
+
return { ok: false, errors: ["no `## Surface` heading found in the body."] };
|
|
3214
|
+
const inLine = /^in:\s*(.+)$/im.exec(section);
|
|
3215
|
+
const outLine = /^out:\s*(.+)$/im.exec(section);
|
|
3216
|
+
const errors = [];
|
|
3217
|
+
if (!inLine)
|
|
3218
|
+
errors.push("`## Surface` has no `in:` line.");
|
|
3219
|
+
if (!outLine)
|
|
3220
|
+
errors.push("`## Surface` has no `out:` line.");
|
|
3221
|
+
if (errors.length > 0)
|
|
3222
|
+
return { ok: false, errors };
|
|
3223
|
+
const inGlobs = splitGlobList(inLine[1]);
|
|
3224
|
+
const outGlobs = splitGlobList(outLine[1]);
|
|
3225
|
+
for (const g of [...inGlobs, ...outGlobs]) {
|
|
3226
|
+
if (looksLikeFilePath(g)) {
|
|
3227
|
+
errors.push(`\`${g}\` in \`## Surface\` looks like a file path — Surface entries are directory-level globs, never file paths.`);
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
if (inGlobs.length === 0)
|
|
3231
|
+
errors.push("`## Surface`'s `in:` line resolved to zero globs.");
|
|
3232
|
+
if (errors.length > 0)
|
|
3233
|
+
return { ok: false, errors };
|
|
3234
|
+
return { ok: true, value: { in: inGlobs, out: outGlobs } };
|
|
3235
|
+
}
|
|
3236
|
+
function globCoversPath(glob, path) {
|
|
3237
|
+
const g = glob.replace(/\/\*\*?$/, "").replace(/\/+$/, "");
|
|
3238
|
+
const p = path.replace(/\/+$/, "");
|
|
3239
|
+
return g === p || g.startsWith(`${p}/`) || p.startsWith(`${g}/`);
|
|
3240
|
+
}
|
|
3241
|
+
function checkSurfaceScope(changedFiles, outGlobs) {
|
|
3242
|
+
if (outGlobs.length === 0)
|
|
3243
|
+
return { ok: true };
|
|
3244
|
+
const violations = [];
|
|
3245
|
+
for (const file of changedFiles) {
|
|
3246
|
+
const glob = outGlobs.find((g) => globCoversPath(g, file));
|
|
3247
|
+
if (glob)
|
|
3248
|
+
violations.push({ file, glob });
|
|
3249
|
+
}
|
|
3250
|
+
return violations.length > 0 ? { ok: false, violations } : { ok: true };
|
|
3251
|
+
}
|
|
3175
3252
|
function isTaskIssueLabelSet(labels) {
|
|
3176
3253
|
return hasLabel("tranche", labels);
|
|
3177
3254
|
}
|
|
@@ -3236,6 +3313,8 @@ function checkProjectsRegistered(body, _labels, registeredNames) {
|
|
|
3236
3313
|
}
|
|
3237
3314
|
return errors.length > 0 ? { status: "fail", errors } : { status: "pass", errors: [] };
|
|
3238
3315
|
}
|
|
3316
|
+
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;
|
|
3317
|
+
var DOC_PATH_RE_GLOBAL = new RegExp(DOC_PATH_RE.source, "gi");
|
|
3239
3318
|
|
|
3240
3319
|
// ../../packages/aeg-core/src/coherence-checks.ts
|
|
3241
3320
|
var COHERENCE_ENFORCED_FROM = "2026-07-01";
|
|
@@ -3765,16 +3844,33 @@ function checkG1(rows, existsFn) {
|
|
|
3765
3844
|
return { check: "G1", status: findings.length > 0 ? "fail" : "pass", findings };
|
|
3766
3845
|
}
|
|
3767
3846
|
var SCAFFOLD_PLACEHOLDER = "[undocumented — fill in why]";
|
|
3847
|
+
var NON_GATE_BIN_NAMES = NON_GATE_BINS;
|
|
3848
|
+
var TWIN_CANDIDATE_EXCEPTIONS = {
|
|
3849
|
+
"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)',
|
|
3850
|
+
"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)`,
|
|
3851
|
+
"apps/cli/src/checks/bin/check-closes-n.ts": 'Ring 1 "Closes linkage" (implementation: verify-coherence.ts)'
|
|
3852
|
+
};
|
|
3853
|
+
var NON_GATE_HOOK_SCRIPTS = [".claude/hooks/track-transcript.sh"];
|
|
3768
3854
|
function checkG2(rows, candidateFiles) {
|
|
3769
3855
|
const implementations = new Set(rows.map((r) => r.implementation).filter((p) => p !== ""));
|
|
3856
|
+
const claimedNames = new Set(rows.flatMap((r) => claimedCheckNames(r.implementation)));
|
|
3770
3857
|
const findings = [];
|
|
3771
3858
|
for (const path of candidateFiles) {
|
|
3772
|
-
if (
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3859
|
+
if (implementations.has(path))
|
|
3860
|
+
continue;
|
|
3861
|
+
if (path.startsWith(AEG_CORE_BIN_PATH_PREFIX) && NON_GATE_BIN_NAMES.includes(basenameNoExt(path)))
|
|
3862
|
+
continue;
|
|
3863
|
+
if (NON_GATE_HOOK_SCRIPTS.includes(path))
|
|
3864
|
+
continue;
|
|
3865
|
+
if (path in TWIN_CANDIDATE_EXCEPTIONS)
|
|
3866
|
+
continue;
|
|
3867
|
+
const candidateNames = claimedCheckNames(path);
|
|
3868
|
+
if (candidateNames.length > 0 && candidateNames.some((n) => claimedNames.has(n)))
|
|
3869
|
+
continue;
|
|
3870
|
+
findings.push({
|
|
3871
|
+
path,
|
|
3872
|
+
reason: `"${path}" is not named as the implementation of any row in enforcement.md's ring tables`
|
|
3873
|
+
});
|
|
3778
3874
|
}
|
|
3779
3875
|
for (const row of rows) {
|
|
3780
3876
|
const carriesPlaceholder = [row.summary, row.description, row.spec].some((cell) => cell === SCAFFOLD_PLACEHOLDER);
|
|
@@ -3786,7 +3882,7 @@ function checkG2(rows, candidateFiles) {
|
|
|
3786
3882
|
});
|
|
3787
3883
|
}
|
|
3788
3884
|
}
|
|
3789
|
-
return { check: "G2", status: findings.length > 0 ? "
|
|
3885
|
+
return { check: "G2", status: findings.length > 0 ? "fail" : "pass", findings };
|
|
3790
3886
|
}
|
|
3791
3887
|
function checkG3(ring0Rows, crossingFiles) {
|
|
3792
3888
|
const ring0Implementations = new Set(ring0Rows.map((r) => r.implementation));
|
|
@@ -4662,7 +4758,6 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
|
|
|
4662
4758
|
import { z } from "zod";
|
|
4663
4759
|
var ROLE_VALUES = [
|
|
4664
4760
|
"planner",
|
|
4665
|
-
"brief-author",
|
|
4666
4761
|
"developer",
|
|
4667
4762
|
"code-reviewer",
|
|
4668
4763
|
"security",
|
|
@@ -4736,18 +4831,20 @@ var dispatchShared = {
|
|
|
4736
4831
|
round: z.number().int().optional(),
|
|
4737
4832
|
effect_id: z.string()
|
|
4738
4833
|
};
|
|
4834
|
+
var dispatchUsageField = z.object({ input: z.number().nonnegative(), output: z.number().nonnegative() }).strict().nullable();
|
|
4739
4835
|
var DispatchEventSchema = z.discriminatedUnion("event", [
|
|
4740
4836
|
z.object({ ...dispatchShared, event: z.literal("dispatched"), prompt_hash: z.string() }).strict(),
|
|
4741
4837
|
z.object({
|
|
4742
4838
|
...dispatchShared,
|
|
4743
4839
|
event: z.literal("outcome_received"),
|
|
4744
4840
|
outcome: DispatchOutcomeSchema,
|
|
4745
|
-
usage:
|
|
4841
|
+
usage: dispatchUsageField
|
|
4746
4842
|
}).strict(),
|
|
4747
4843
|
z.object({
|
|
4748
4844
|
...dispatchShared,
|
|
4749
4845
|
event: z.literal("dispatch_failed"),
|
|
4750
|
-
reason: z.enum(["timeout", "crash", "refused", "unattributed_write"])
|
|
4846
|
+
reason: z.enum(["timeout", "crash", "refused", "unattributed_write"]),
|
|
4847
|
+
usage: dispatchUsageField
|
|
4751
4848
|
}).strict()
|
|
4752
4849
|
]);
|
|
4753
4850
|
var loopShared = {
|