@attalabs/vinaya 0.27.0 → 0.29.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 +5 -4
- package/aeg-root/contracts/planner-developer.md +4 -1
- package/aeg-root/contracts/planner-operator.md +86 -0
- package/aeg-root/contracts/principal-operator.md +88 -0
- package/aeg-root/enforcement.md +4 -4
- package/aeg-root/roles/developer.md +25 -18
- package/aeg-root/roles/operator.md +133 -0
- package/aeg-root/roles/planner.md +6 -0
- package/aeg-root/roles/principal.md +4 -0
- package/aeg-root/roles/reviewer.md +3 -3
- package/aeg-root/roles/security.md +3 -3
- package/aeg-root/skills/aeg-context-packets/SKILL.md +123 -0
- package/aeg-root/skills/aeg-context-packets/examples/operator-start.md +30 -0
- package/aeg-root/templates/brief-template.md +6 -2
- package/dist/checks/bin/check-body-bare-digits.js +1275 -240
- package/dist/checks/bin/check-branch-topology.js +1207 -180
- package/dist/checks/bin/check-brief-shape.js +1279 -243
- package/dist/checks/bin/check-changeset-coverage.js +2176 -264
- package/dist/checks/bin/check-closes-n.js +1211 -184
- package/dist/checks/bin/check-coherence.js +1378 -265
- package/dist/checks/bin/check-dead-branch-push.js +1158 -176
- package/dist/checks/bin/check-dispatch-readiness.js +1440 -276
- package/dist/checks/bin/check-doc-coverage-push.js +2171 -259
- package/dist/checks/bin/check-doc-coverage.js +2173 -261
- package/dist/checks/bin/check-doctrine-no-procedures.js +1275 -240
- package/dist/checks/bin/check-doctrine-portability.js +2171 -259
- package/dist/checks/bin/check-evidence-fresh.js +2613 -347
- package/dist/checks/bin/check-exec-bits.js +2169 -257
- package/dist/checks/bin/check-first-push-dispatch.js +1326 -246
- package/dist/checks/bin/check-issue-assignment.js +1209 -182
- package/dist/checks/bin/check-issue-milestone-attach.js +6087 -0
- package/dist/checks/bin/check-issue-objectives-numbering.js +6089 -0
- package/dist/checks/bin/check-issue-parts-coverage.js +6089 -0
- package/dist/checks/bin/check-issue-surface-globs.js +7304 -0
- package/dist/checks/bin/check-issue-title-grammar.js +6089 -0
- package/dist/checks/bin/check-issue-tranche-label.js +6089 -0
- package/dist/checks/bin/check-main-branch-refusal.js +1158 -176
- package/dist/checks/bin/check-no-disk-state.js +1158 -176
- package/dist/checks/bin/check-pr-premise-reassert.js +1275 -240
- package/dist/checks/bin/check-pr-report-density.js +1158 -176
- package/dist/checks/bin/check-quoted-command.js +2150 -257
- package/dist/checks/bin/check-reader-resolvable-prose.js +2153 -260
- package/dist/checks/bin/check-registry-gates.js +1245 -176
- package/dist/checks/bin/check-retired-vocabulary.js +2148 -255
- package/dist/checks/bin/check-review-gate.js +1375 -245
- package/dist/checks/bin/check-single-plan-pr.js +1158 -176
- package/dist/checks/bin/check-surface-scope.js +1217 -182
- package/dist/checks/bin/check-test-plan.js +1187 -189
- package/dist/checks/bin/check-token-collection-wired.js +1158 -176
- package/dist/checks/bin/check-token-report.js +1171 -179
- package/dist/checks/bin/check-workspace-escape.js +2167 -255
- package/dist/index.js +17322 -8709
- package/dist/lib/pre-push-changed-files.js +57 -0
- package/dist/lib/pre-push-select-tests.js +1616 -0
- package/package.json +4 -2
- 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/page.js +2 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error/page.js.nft.json +1 -1
- 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 +8 -7
- 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/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js +8 -7
- 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 +9 -8
- 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 +9 -8
- 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 +8 -7
- 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 +16 -4
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js +10 -8
- 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 +8 -7
- 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 +8 -7
- 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 +9 -8
- 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/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]__08f5pba._.js +3 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__1o_0tjy._.js → [root-of-the-server]__0h9yhwx._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0053k9k._.js → [root-of-the-server]__0ls23oh._.js} +3 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0puovz5._.js → [root-of-the-server]__0nye8tb._.js} +3 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__18kqy4q._.js → [root-of-the-server]__0tfykr-._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0o771t1._.js → [root-of-the-server]__0th3gyp._.js} +3 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1-zcufa._.js +51 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0p8q38b._.js → [root-of-the-server]__11svemm._.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__02c71kv._.js → [root-of-the-server]__140m1i_._.js} +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1bh2awk._.js +3 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__0112h-k._.js → [root-of-the-server]__1gjqmhq._.js} +3 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1qmxez3._.js +4 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1r47dr7._.js +28 -0
- 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/_01fv4fj._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0gvm3og._.js → _096f46i._.js} +3 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0lwxg63._.js → _0af2one._.js} +3 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_1n0cnq-._.js → _0zf4d27._.js} +45 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_03x_w6q._.js → _1-wo68i._.js} +3 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_projects_[name]_tranches_[slug]_05ufo8i._.js +1 -12
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1wdusod._.js +3 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{node_modules_1vo08dj._.js → node_modules_@clerk_nextjs_dist_esm_app-router_server-actions_1x7vfhn.js} +3 -4
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_next_1khj-jh._.js +3 -0
- 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 +17 -5
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3_9xytdmiv1xi.js → 25f3-jtiv8p5n.js} +4 -4
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0bn8c8v5q429o.js → 27-6ym7lp2v8o.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3-6a3tinbdb-7.js → 3daxns3o--9me.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/tsconfig.json +12 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0z6dav-._.js +0 -51
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__13rrmhr._.js +0 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__17h4sy8._.js +0 -45
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +0 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_next_17sz44y._.js +0 -3
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_ssgManifest.js +0 -0
|
@@ -1641,6 +1641,52 @@ var systemEnv3 = {
|
|
|
1641
1641
|
...process.env,
|
|
1642
1642
|
PATH: [process.env.PATH, "/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin"].filter(Boolean).join(":")
|
|
1643
1643
|
};
|
|
1644
|
+
var defaultExec = () => execFileAsync3("git", ["remote", "get-url", "origin"], { env: systemEnv3, timeout: 5000 });
|
|
1645
|
+
var cached;
|
|
1646
|
+
var inflight;
|
|
1647
|
+
async function resolveRepo(exec = defaultExec) {
|
|
1648
|
+
if (cached !== undefined)
|
|
1649
|
+
return cached;
|
|
1650
|
+
const fromEnv = process.env.AEG_REPO;
|
|
1651
|
+
if (fromEnv) {
|
|
1652
|
+
const parsed = parseOwnerRepo(fromEnv);
|
|
1653
|
+
if (parsed) {
|
|
1654
|
+
cached = parsed;
|
|
1655
|
+
return cached;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
if (inflight)
|
|
1659
|
+
return inflight;
|
|
1660
|
+
inflight = (async () => {
|
|
1661
|
+
try {
|
|
1662
|
+
const { stdout } = await exec();
|
|
1663
|
+
cached = parseGitRemoteUrl(stdout.trim());
|
|
1664
|
+
return cached;
|
|
1665
|
+
} catch (err) {
|
|
1666
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1667
|
+
console.warn(`[aeg-forge-state] resolveRepo: git remote lookup failed (will retry): ${message}`);
|
|
1668
|
+
return null;
|
|
1669
|
+
} finally {
|
|
1670
|
+
inflight = undefined;
|
|
1671
|
+
}
|
|
1672
|
+
})();
|
|
1673
|
+
return inflight;
|
|
1674
|
+
}
|
|
1675
|
+
function parseGitRemoteUrl(url) {
|
|
1676
|
+
const ssh = url.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
|
|
1677
|
+
if (ssh?.[1] && ssh[2])
|
|
1678
|
+
return { owner: ssh[1], repo: ssh[2] };
|
|
1679
|
+
const https = url.match(/^https?:\/\/(?:[^@]+@)?github\.com\/([^/]+)\/(.+?)(?:\.git)?\/?$/);
|
|
1680
|
+
if (https?.[1] && https[2])
|
|
1681
|
+
return { owner: https[1], repo: https[2] };
|
|
1682
|
+
return null;
|
|
1683
|
+
}
|
|
1684
|
+
function parseOwnerRepo(value) {
|
|
1685
|
+
const match = value.match(/^([^/]+)\/(.+)$/);
|
|
1686
|
+
if (!match?.[1] || !match[2])
|
|
1687
|
+
return null;
|
|
1688
|
+
return { owner: match[1], repo: match[2] };
|
|
1689
|
+
}
|
|
1644
1690
|
// ../../packages/aeg-core/src/anchored-region.ts
|
|
1645
1691
|
function anchoredRegionBounds(body, field) {
|
|
1646
1692
|
const masked = maskCode(body);
|
|
@@ -1951,6 +1997,9 @@ function parseInlineFieldList(section) {
|
|
|
1951
1997
|
var HEAD_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged head:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
|
|
1952
1998
|
var OBJECTIVES_VERSION_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Objectives version:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
|
|
1953
1999
|
var RULING_ORDINAL_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Ruling ordinal:\s*(\d+)(?!\d)/im;
|
|
2000
|
+
var BRIEF_HASH_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Brief hash:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
|
|
2001
|
+
var POLICY_DIGEST_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Policy digest:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
|
|
2002
|
+
var BASE_SHA_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Judged base:\s*([0-9a-f]{7,40})(?![A-Za-z0-9])/im;
|
|
1954
2003
|
function firstFiveLines(comment) {
|
|
1955
2004
|
return comment.split(`
|
|
1956
2005
|
`).slice(0, 5).join(`
|
|
@@ -1973,6 +2022,35 @@ function extractRulingOrdinal(comment) {
|
|
|
1973
2022
|
const m = firstSevenLines(comment).match(RULING_ORDINAL_PATTERN);
|
|
1974
2023
|
return m ? Number.parseInt(m[1], 10) : null;
|
|
1975
2024
|
}
|
|
2025
|
+
function firstElevenLines(comment) {
|
|
2026
|
+
return comment.split(`
|
|
2027
|
+
`).slice(0, 11).join(`
|
|
2028
|
+
`);
|
|
2029
|
+
}
|
|
2030
|
+
function extractBriefHash(comment) {
|
|
2031
|
+
const m = firstElevenLines(comment).match(BRIEF_HASH_PATTERN);
|
|
2032
|
+
return m ? m[1].toLowerCase() : null;
|
|
2033
|
+
}
|
|
2034
|
+
function extractPolicyDigest(comment) {
|
|
2035
|
+
const m = firstElevenLines(comment).match(POLICY_DIGEST_PATTERN);
|
|
2036
|
+
return m ? m[1].toLowerCase() : null;
|
|
2037
|
+
}
|
|
2038
|
+
function firstThirteenLines(comment) {
|
|
2039
|
+
return comment.split(`
|
|
2040
|
+
`).slice(0, 13).join(`
|
|
2041
|
+
`);
|
|
2042
|
+
}
|
|
2043
|
+
function extractBaseSha(comment) {
|
|
2044
|
+
const m = firstThirteenLines(comment).match(BASE_SHA_PATTERN);
|
|
2045
|
+
return m ? m[1].toLowerCase() : null;
|
|
2046
|
+
}
|
|
2047
|
+
var FINDING_SEVERITY_LINE = /^\d+\.\s+\[([A-Z][A-Z]*)\]\s+(.+?)\s+—/gm;
|
|
2048
|
+
function extractFindingSeverities(comment) {
|
|
2049
|
+
return [...comment.matchAll(FINDING_SEVERITY_LINE)].map((m) => ({
|
|
2050
|
+
severity: m[1],
|
|
2051
|
+
location: m[2]
|
|
2052
|
+
}));
|
|
2053
|
+
}
|
|
1976
2054
|
function extractVerdict(comments, valuePattern, missingLabel) {
|
|
1977
2055
|
const candidates = comments.filter((c) => valuePattern.test(c));
|
|
1978
2056
|
if (candidates.length === 0) {
|
|
@@ -1981,6 +2059,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
1981
2059
|
headSha: null,
|
|
1982
2060
|
objectivesVersion: null,
|
|
1983
2061
|
rulingOrdinal: null,
|
|
2062
|
+
briefHash: null,
|
|
2063
|
+
policyDigest: null,
|
|
2064
|
+
baseSha: null,
|
|
2065
|
+
findingSeverities: [],
|
|
1984
2066
|
danglingNote: `no ${missingLabel} verdict comment found on this PR`
|
|
1985
2067
|
};
|
|
1986
2068
|
}
|
|
@@ -1992,6 +2074,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
1992
2074
|
headSha: null,
|
|
1993
2075
|
objectivesVersion: null,
|
|
1994
2076
|
rulingOrdinal: null,
|
|
2077
|
+
briefHash: null,
|
|
2078
|
+
policyDigest: null,
|
|
2079
|
+
baseSha: null,
|
|
2080
|
+
findingSeverities: [],
|
|
1995
2081
|
danglingNote: `the most recent ${missingLabel} verdict comment carries a VERDICT-shaped line outside the first-five-line read window`
|
|
1996
2082
|
};
|
|
1997
2083
|
}
|
|
@@ -2000,6 +2086,10 @@ function extractVerdict(comments, valuePattern, missingLabel) {
|
|
|
2000
2086
|
headSha: extractHeadSha(latest),
|
|
2001
2087
|
objectivesVersion: extractObjectivesVersion(latest),
|
|
2002
2088
|
rulingOrdinal: extractRulingOrdinal(latest),
|
|
2089
|
+
briefHash: extractBriefHash(latest),
|
|
2090
|
+
policyDigest: extractPolicyDigest(latest),
|
|
2091
|
+
baseSha: extractBaseSha(latest),
|
|
2092
|
+
findingSeverities: extractFindingSeverities(latest),
|
|
2003
2093
|
danglingNote: null
|
|
2004
2094
|
};
|
|
2005
2095
|
}
|
|
@@ -2335,6 +2425,53 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive,
|
|
|
2335
2425
|
}
|
|
2336
2426
|
return out;
|
|
2337
2427
|
}
|
|
2428
|
+
// ../../packages/aeg-core/src/review-policy.ts
|
|
2429
|
+
var CODE_REVIEW_SEVERITY_ORDER = ["BLOCKER", "MAJOR", "MINOR"];
|
|
2430
|
+
var SECURITY_SEVERITY_ORDER = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
|
|
2431
|
+
var DEFAULT_MAX_ROUNDS = 3;
|
|
2432
|
+
var DEFAULT_REVIEW_POLICY = {
|
|
2433
|
+
codeReviewThreshold: "BLOCKER",
|
|
2434
|
+
securityThreshold: "HIGH",
|
|
2435
|
+
maxRounds: DEFAULT_MAX_ROUNDS
|
|
2436
|
+
};
|
|
2437
|
+
var FILE_SHAPED_LOCATION = /\.[a-zA-Z0-9]{1,10}(:\d+)?\s*$/;
|
|
2438
|
+
var PROSE_LOCATION_PATTERNS = [/\bpr\s*body\b/i, /\bcomment\b/i];
|
|
2439
|
+
var ROLE_FILE_LOCATION = /(^|\/)aeg-root\/roles\//i;
|
|
2440
|
+
function isProseLocation(location) {
|
|
2441
|
+
if (ROLE_FILE_LOCATION.test(location))
|
|
2442
|
+
return true;
|
|
2443
|
+
if (FILE_SHAPED_LOCATION.test(location))
|
|
2444
|
+
return false;
|
|
2445
|
+
return PROSE_LOCATION_PATTERNS.some((pattern) => pattern.test(location));
|
|
2446
|
+
}
|
|
2447
|
+
var PROSE_CAP_SEVERITY = "MINOR";
|
|
2448
|
+
function blockingSeverities(scale, threshold) {
|
|
2449
|
+
const idx = scale.indexOf(threshold);
|
|
2450
|
+
if (idx === -1) {
|
|
2451
|
+
throw new Error(`blockingSeverities: threshold "${threshold}" is not one of ${scale.join(" > ")}`);
|
|
2452
|
+
}
|
|
2453
|
+
return scale.slice(0, idx + 1);
|
|
2454
|
+
}
|
|
2455
|
+
function evaluateReviewFindings(findings, scale, threshold) {
|
|
2456
|
+
const blocking = new Set(blockingSeverities(scale, threshold));
|
|
2457
|
+
const blockingFindings = findings.filter((f) => {
|
|
2458
|
+
if (!scale.includes(f.severity)) {
|
|
2459
|
+
throw new Error(`evaluateReviewFindings: severity "${f.severity}" is not one of ${scale.join(" > ")}`);
|
|
2460
|
+
}
|
|
2461
|
+
const effectiveSeverity = f.location !== undefined && isProseLocation(f.location) ? PROSE_CAP_SEVERITY : f.severity;
|
|
2462
|
+
return blocking.has(effectiveSeverity);
|
|
2463
|
+
});
|
|
2464
|
+
return { outcome: blockingFindings.length > 0 ? "blocked" : "clean", blockingFindings };
|
|
2465
|
+
}
|
|
2466
|
+
function evaluateCodeReview(findings, policy) {
|
|
2467
|
+
return evaluateReviewFindings(findings, CODE_REVIEW_SEVERITY_ORDER, policy.codeReviewThreshold);
|
|
2468
|
+
}
|
|
2469
|
+
function evaluateSecurityReview(findings, policy) {
|
|
2470
|
+
return evaluateReviewFindings(findings, SECURITY_SEVERITY_ORDER, policy.securityThreshold);
|
|
2471
|
+
}
|
|
2472
|
+
function isKnownSeverity(scale, value) {
|
|
2473
|
+
return scale.includes(value);
|
|
2474
|
+
}
|
|
2338
2475
|
// ../../packages/aeg-core/src/pr-tier.ts
|
|
2339
2476
|
var TIER_FIELD = /(\*\*)?\s*Tier\s*(\*\*)?\s*:\s*(\*\*)?\s*([013])\b/i;
|
|
2340
2477
|
function readTierFromPrBody(prBody) {
|
|
@@ -2705,7 +2842,7 @@ function checkForField(prBody) {
|
|
|
2705
2842
|
]
|
|
2706
2843
|
};
|
|
2707
2844
|
}
|
|
2708
|
-
function
|
|
2845
|
+
function checkClosesNPresence(prBody) {
|
|
2709
2846
|
const closesPattern = /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s{0,8}:?\s{0,8}#\d+/i;
|
|
2710
2847
|
if (closesPattern.test(stripCode(prBody))) {
|
|
2711
2848
|
return { status: "pass", errors: [] };
|
|
@@ -2737,10 +2874,22 @@ var COMMIT_TYPES = [
|
|
|
2737
2874
|
"Test"
|
|
2738
2875
|
];
|
|
2739
2876
|
var COMMIT_TYPE_STYLE = new RegExp(`^(${COMMIT_TYPES.join("|")})(\\([a-z0-9-]+\\))?: \\S`);
|
|
2877
|
+
function checkForgeTitle(title) {
|
|
2878
|
+
const taskStyle = /^\[[a-z0-9._-]+\] \S+ — \S/;
|
|
2879
|
+
if (COMMIT_TYPE_STYLE.test(title) || taskStyle.test(title))
|
|
2880
|
+
return { status: "pass", errors: [] };
|
|
2881
|
+
return {
|
|
2882
|
+
status: "fail",
|
|
2883
|
+
errors: [
|
|
2884
|
+
`brief-validation title: "${title}" matches neither title grammar — expected \`Type: description\` / \`Type(scope): description\` (commitlint types + Plan) or \`[tranche] id — description\` (task form).`
|
|
2885
|
+
]
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2740
2888
|
var BRIEF_SHAPE_MARKERS = [checkSurfaceMap, checkDocUpdateList, checkStopConditions, checkAutonomyClause];
|
|
2741
2889
|
var TASK_BRANCH_PATTERN = /^task\/[^/]+\/[^/]+$/;
|
|
2890
|
+
var TASK_ISSUE_BRANCH_PATTERN = /^task\/issue-\d+$/;
|
|
2742
2891
|
function isTaskBranch(branch) {
|
|
2743
|
-
return TASK_BRANCH_PATTERN.test(branch);
|
|
2892
|
+
return TASK_BRANCH_PATTERN.test(branch) || TASK_ISSUE_BRANCH_PATTERN.test(branch);
|
|
2744
2893
|
}
|
|
2745
2894
|
function isBriefShaped(prBody) {
|
|
2746
2895
|
const stripped = stripCode(prBody);
|
|
@@ -2862,8 +3011,9 @@ function packagesNamedIn(text) {
|
|
|
2862
3011
|
}
|
|
2863
3012
|
function hasTestPathForConsumer(text, consumerDir) {
|
|
2864
3013
|
const escaped = consumerDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2865
|
-
const
|
|
2866
|
-
|
|
3014
|
+
const filePathRe = new RegExp(`${escaped}\\/[\\w./-]*\\.test\\.[A-Za-z0-9]+`);
|
|
3015
|
+
const testDirRe = new RegExp(`${escaped}\\/(?:[\\w-]+\\/)*(?:tests|specs)(?:\\/|\\b)`);
|
|
3016
|
+
return filePathRe.test(text) || testDirRe.test(text);
|
|
2867
3017
|
}
|
|
2868
3018
|
function checkConsumerTests(prBody, consumersOf) {
|
|
2869
3019
|
const section4 = extractNumberedSection(prBody, 4);
|
|
@@ -2967,7 +3117,7 @@ function checkBriefSections(prBody, readTier, options = {}) {
|
|
|
2967
3117
|
checkConsumerTests(prBody, consumersOf),
|
|
2968
3118
|
checkDefeatCases(prBody),
|
|
2969
3119
|
...issueObjectives !== undefined ? [checkObjectivesCopy(prBody, issueObjectives), checkObjectivesCoverage(prBody)] : [],
|
|
2970
|
-
...requireClosesN ? [
|
|
3120
|
+
...requireClosesN ? [checkClosesNPresence(prBody)] : []
|
|
2971
3121
|
];
|
|
2972
3122
|
return { errors: results.flatMap((r) => r.errors) };
|
|
2973
3123
|
}
|
|
@@ -3257,6 +3407,28 @@ function topLevelSectionText(body, headingName) {
|
|
|
3257
3407
|
const next = /^##[ \t]/m.exec(afterHeading);
|
|
3258
3408
|
return next ? afterHeading.slice(0, next.index) : afterHeading;
|
|
3259
3409
|
}
|
|
3410
|
+
function partHasBacktickedPath(text) {
|
|
3411
|
+
let i = 0;
|
|
3412
|
+
while (i < text.length) {
|
|
3413
|
+
const start = text.indexOf("`", i);
|
|
3414
|
+
if (start === -1)
|
|
3415
|
+
return false;
|
|
3416
|
+
const end = text.indexOf("`", start + 1);
|
|
3417
|
+
if (end === -1)
|
|
3418
|
+
return false;
|
|
3419
|
+
if (text.slice(start + 1, end).includes("/"))
|
|
3420
|
+
return true;
|
|
3421
|
+
i = end + 1;
|
|
3422
|
+
}
|
|
3423
|
+
return false;
|
|
3424
|
+
}
|
|
3425
|
+
var PART_MIN_WORDS_OUTSIDE_BACKTICKS = 3;
|
|
3426
|
+
function stripPartBackticks(text) {
|
|
3427
|
+
return text.replace(/`[^`\n]*`/g, " ");
|
|
3428
|
+
}
|
|
3429
|
+
function partWordCount(text) {
|
|
3430
|
+
return text.split(/\s+/).filter((w) => /[a-z]/i.test(w)).length;
|
|
3431
|
+
}
|
|
3260
3432
|
function looksLikeFilePath(entry2) {
|
|
3261
3433
|
const stripped = entry2.replace(/\/\*\*?$/, "");
|
|
3262
3434
|
const lastSegment = stripped.split("/").pop() ?? stripped;
|
|
@@ -3297,6 +3469,18 @@ function globCoversPath(glob, path) {
|
|
|
3297
3469
|
const p = path.replace(/\/+$/, "");
|
|
3298
3470
|
return g === p || g.startsWith(`${p}/`) || p.startsWith(`${g}/`);
|
|
3299
3471
|
}
|
|
3472
|
+
function checkSurfaceGlobsResolve(body, resolvesToFile) {
|
|
3473
|
+
const surface = parseIssueSurface(body);
|
|
3474
|
+
if (!surface.ok)
|
|
3475
|
+
return { status: "pass", errors: [] };
|
|
3476
|
+
const errors = [];
|
|
3477
|
+
for (const glob of surface.value.in) {
|
|
3478
|
+
if (!resolvesToFile(glob)) {
|
|
3479
|
+
errors.push(`issue-validation Surface: \`${glob}\` in \`## Surface\`'s \`in:\` list matches no tracked file — a Surface that cannot resolve cannot render a brief's file list.`);
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
return { status: errors.length > 0 ? "fail" : "pass", errors };
|
|
3483
|
+
}
|
|
3300
3484
|
function checkSurfaceScope(changedFiles, outGlobs) {
|
|
3301
3485
|
if (outGlobs.length === 0)
|
|
3302
3486
|
return { ok: true };
|
|
@@ -3308,9 +3492,77 @@ function checkSurfaceScope(changedFiles, outGlobs) {
|
|
|
3308
3492
|
}
|
|
3309
3493
|
return violations.length > 0 ? { ok: false, violations } : { ok: true };
|
|
3310
3494
|
}
|
|
3495
|
+
var ISSUE_PART_LINE_RE = /^Part\s+(\d+)\s*\(([^)]*)\)\s*[-—–]\s*(.*)$/i;
|
|
3496
|
+
function parseIssueParts(body) {
|
|
3497
|
+
const section = topLevelSectionText(body, "Parts");
|
|
3498
|
+
if (section === null)
|
|
3499
|
+
return { ok: false, errors: ["no `## Parts` heading found in the body."] };
|
|
3500
|
+
const lines = section.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
|
|
3501
|
+
const parts = [];
|
|
3502
|
+
const errors = [];
|
|
3503
|
+
for (const line of lines) {
|
|
3504
|
+
const m = ISSUE_PART_LINE_RE.exec(line);
|
|
3505
|
+
if (!m) {
|
|
3506
|
+
errors.push(`"${line}" is not a well-formed Parts line — expected \`Part <n> (<refs>) — <outcome>\`.`);
|
|
3507
|
+
continue;
|
|
3508
|
+
}
|
|
3509
|
+
const n = Number.parseInt(m[1], 10);
|
|
3510
|
+
const refs = m[2];
|
|
3511
|
+
const text = m[3].trim();
|
|
3512
|
+
if (text.length === 0) {
|
|
3513
|
+
errors.push(`Part ${n} has no outcome text after the dash — every Part states one observable outcome.`);
|
|
3514
|
+
continue;
|
|
3515
|
+
}
|
|
3516
|
+
if (partHasBacktickedPath(text) && partWordCount(stripPartBackticks(text)) < PART_MIN_WORDS_OUTSIDE_BACKTICKS) {
|
|
3517
|
+
errors.push(`Part ${n} is little more than a file path — a Part names an outcome and symbols, never a bare path.`);
|
|
3518
|
+
continue;
|
|
3519
|
+
}
|
|
3520
|
+
const objectiveIds = [...refs.matchAll(/O(\d+)/g)].map((r) => Number.parseInt(r[1], 10));
|
|
3521
|
+
parts.push({ n, objectiveIds, text });
|
|
3522
|
+
}
|
|
3523
|
+
if (parts.length === 0) {
|
|
3524
|
+
errors.push("the `## Parts` section has no well-formed `Part <n> (<refs>) — <outcome>` lines.");
|
|
3525
|
+
}
|
|
3526
|
+
if (errors.length > 0)
|
|
3527
|
+
return { ok: false, errors };
|
|
3528
|
+
return { ok: true, value: parts };
|
|
3529
|
+
}
|
|
3530
|
+
function checkPartsCiteDefinedObjectives(body) {
|
|
3531
|
+
const parts = parseIssueParts(body);
|
|
3532
|
+
const objectives = objectivesOf(body);
|
|
3533
|
+
if (!parts.ok || !objectives.ok)
|
|
3534
|
+
return { status: "pass", errors: [] };
|
|
3535
|
+
const definedIds = new Set(objectives.objectives.map((o) => Number.parseInt(o.id.slice(1), 10)));
|
|
3536
|
+
const errors = [];
|
|
3537
|
+
for (const part of parts.value) {
|
|
3538
|
+
for (const objectiveId of part.objectiveIds) {
|
|
3539
|
+
if (!definedIds.has(objectiveId)) {
|
|
3540
|
+
errors.push(`issue-validation Parts: Part ${part.n} cites O${objectiveId}, which the Issue's own \`## Objectives\` section does not define.`);
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
return { status: errors.length > 0 ? "fail" : "pass", errors };
|
|
3545
|
+
}
|
|
3311
3546
|
function isTaskIssueLabelSet(labels) {
|
|
3312
3547
|
return hasLabel("tranche", labels);
|
|
3313
3548
|
}
|
|
3549
|
+
function checkTrancheLabelPresence(_body, _labels) {
|
|
3550
|
+
return { status: "pass", errors: [] };
|
|
3551
|
+
}
|
|
3552
|
+
function checkMilestoneAttach(labels, currentMilestoneTitle, resolvedMilestoneTitle) {
|
|
3553
|
+
if (!isTaskIssueLabelSet(labels))
|
|
3554
|
+
return { status: "pass", errors: [] };
|
|
3555
|
+
if (resolvedMilestoneTitle === null)
|
|
3556
|
+
return { status: "pass", errors: [] };
|
|
3557
|
+
if (currentMilestoneTitle === resolvedMilestoneTitle)
|
|
3558
|
+
return { status: "pass", errors: [] };
|
|
3559
|
+
return {
|
|
3560
|
+
status: "fail",
|
|
3561
|
+
errors: [
|
|
3562
|
+
`issue-validation milestone attach: this task Issue's tranche label resolves to Milestone "${resolvedMilestoneTitle}", but its live Milestone is ${currentMilestoneTitle === null ? "unset" : `"${currentMilestoneTitle}"`} — attach it to "${resolvedMilestoneTitle}".`
|
|
3563
|
+
]
|
|
3564
|
+
};
|
|
3565
|
+
}
|
|
3314
3566
|
var TYPE_LABEL_IDS = LABELS.filter((l) => l.category === "type").map((l) => l.id);
|
|
3315
3567
|
function isControlCodePoint(codePoint) {
|
|
3316
3568
|
return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
|
|
@@ -3375,6 +3627,19 @@ function checkProjectsRegistered(body, _labels, registeredNames) {
|
|
|
3375
3627
|
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;
|
|
3376
3628
|
var DOC_PATH_RE_GLOBAL = new RegExp(DOC_PATH_RE.source, "gi");
|
|
3377
3629
|
|
|
3630
|
+
// ../../packages/aeg-core/src/task-branch-identity.ts
|
|
3631
|
+
var ISSUE_BRANCH_PATTERN = /^task\/issue-(\d+)$/;
|
|
3632
|
+
var TRANCHE_BRANCH_PATTERN = /^task\/([^/]+)\/([^/]+)$/;
|
|
3633
|
+
function parseTaskBranchIdentity(branch) {
|
|
3634
|
+
const issueMatch = ISSUE_BRANCH_PATTERN.exec(branch);
|
|
3635
|
+
if (issueMatch)
|
|
3636
|
+
return { kind: "issue", issueNumber: Number(issueMatch[1]) };
|
|
3637
|
+
const trancheMatch = TRANCHE_BRANCH_PATTERN.exec(branch);
|
|
3638
|
+
if (trancheMatch)
|
|
3639
|
+
return { kind: "tranche", tranche: trancheMatch[1], taskId: trancheMatch[2] };
|
|
3640
|
+
return null;
|
|
3641
|
+
}
|
|
3642
|
+
|
|
3378
3643
|
// ../../packages/aeg-core/src/coherence-checks.ts
|
|
3379
3644
|
var COHERENCE_ENFORCED_FROM = "2026-07-01";
|
|
3380
3645
|
function isGrandfathered(isoDate) {
|
|
@@ -3395,6 +3660,7 @@ function checkA1(entries, principalAllowlist = PRINCIPAL_ALLOWLIST) {
|
|
|
3395
3660
|
if (handClosed)
|
|
3396
3661
|
continue;
|
|
3397
3662
|
failures.push({
|
|
3663
|
+
code: "closed-without-merge",
|
|
3398
3664
|
issue: e.task.issue,
|
|
3399
3665
|
tranche: e.trancheSlug,
|
|
3400
3666
|
task: e.task.id,
|
|
@@ -3419,6 +3685,7 @@ function checkA3(entries) {
|
|
|
3419
3685
|
continue;
|
|
3420
3686
|
if (e.facts.prState === "merged" && e.facts.issueState !== "closed") {
|
|
3421
3687
|
failures.push({
|
|
3688
|
+
code: "auto-close-misfire",
|
|
3422
3689
|
issue: e.task.issue,
|
|
3423
3690
|
tranche: e.trancheSlug,
|
|
3424
3691
|
task: e.task.id,
|
|
@@ -3443,6 +3710,7 @@ function checkT1(entries) {
|
|
|
3443
3710
|
continue;
|
|
3444
3711
|
if (e.facts === undefined) {
|
|
3445
3712
|
failures.push({
|
|
3713
|
+
code: "phantom-issue-ref",
|
|
3446
3714
|
issue: e.task.issue,
|
|
3447
3715
|
tranche: e.trancheSlug,
|
|
3448
3716
|
task: e.task.id,
|
|
@@ -3461,6 +3729,7 @@ function checkT2(openIssuesBySlug, topologyIssuesBySlug, ciTrancheSlug) {
|
|
|
3461
3729
|
for (const num of openNums) {
|
|
3462
3730
|
if (!topologySet.has(num)) {
|
|
3463
3731
|
failures.push({
|
|
3732
|
+
code: "orphan-task",
|
|
3464
3733
|
issue: num,
|
|
3465
3734
|
tranche: slug,
|
|
3466
3735
|
reason: `Issue #${num} is open and labeled ${trancheLabel(slug)} but does not appear in the topology file`
|
|
@@ -3495,6 +3764,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
|
|
|
3495
3764
|
continue;
|
|
3496
3765
|
if (forgeUnavailableSlugs?.has(e.trancheSlug)) {
|
|
3497
3766
|
failures.push({
|
|
3767
|
+
code: "tbd-in-active-tranche",
|
|
3498
3768
|
issue: null,
|
|
3499
3769
|
tranche: e.trancheSlug,
|
|
3500
3770
|
task: e.task.id,
|
|
@@ -3504,6 +3774,7 @@ function checkT3(entries, ciTrancheSlug, enrichedEntries, forgeUnavailableSlugs)
|
|
|
3504
3774
|
continue;
|
|
3505
3775
|
}
|
|
3506
3776
|
failures.push({
|
|
3777
|
+
code: "tbd-in-active-tranche",
|
|
3507
3778
|
issue: null,
|
|
3508
3779
|
tranche: e.trancheSlug,
|
|
3509
3780
|
task: e.task.id,
|
|
@@ -3536,6 +3807,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
|
|
|
3536
3807
|
const sameIssue = depEntry.task.issue !== null && e.task.issue !== null && depEntry.task.issue === e.task.issue;
|
|
3537
3808
|
if (sameTask || sameIssue) {
|
|
3538
3809
|
failures.push({
|
|
3810
|
+
code: "d1-self-dependency",
|
|
3539
3811
|
issue: e.task.issue,
|
|
3540
3812
|
tranche: e.trancheSlug,
|
|
3541
3813
|
task: e.task.id,
|
|
@@ -3547,6 +3819,7 @@ function checkD1(entries, issueToEntry, taskToEntry) {
|
|
|
3547
3819
|
const depClosed = depFacts?.issueState === "closed";
|
|
3548
3820
|
if (!depClosed) {
|
|
3549
3821
|
failures.push({
|
|
3822
|
+
code: "dispatched-on-unmet-deps",
|
|
3550
3823
|
issue: e.task.issue,
|
|
3551
3824
|
tranche: e.trancheSlug,
|
|
3552
3825
|
task: e.task.id,
|
|
@@ -3572,11 +3845,13 @@ function checkR1(issuesBySlug, grandfatheredIssues, registeredNames = []) {
|
|
|
3572
3845
|
const errors = [
|
|
3573
3846
|
...checkIssueRationale(issue.body).errors,
|
|
3574
3847
|
...checkProjectsRegistered(issue.body, issue.labels, registeredNames).errors,
|
|
3575
|
-
...checkIssueObjectives(issue.body, issue.number).errors
|
|
3848
|
+
...checkIssueObjectives(issue.body, issue.number).errors,
|
|
3849
|
+
...checkPartsCiteDefinedObjectives(issue.body).errors
|
|
3576
3850
|
];
|
|
3577
3851
|
if (errors.length === 0)
|
|
3578
3852
|
continue;
|
|
3579
3853
|
failures.push({
|
|
3854
|
+
code: "missing-rationale-field",
|
|
3580
3855
|
issue: issue.number,
|
|
3581
3856
|
tranche: slug,
|
|
3582
3857
|
reason: `Issue #${issue.number} fails the rationale gate: ${errors.join(" | ")}`,
|
|
@@ -3605,6 +3880,7 @@ function checkL1(files, entriesBySlug) {
|
|
|
3605
3880
|
const allClosed = withFacts.every((e) => e.facts?.issueState === "closed");
|
|
3606
3881
|
if (allClosed) {
|
|
3607
3882
|
failures.push({
|
|
3883
|
+
code: "archive-recommended",
|
|
3608
3884
|
tranche: f.slug,
|
|
3609
3885
|
reason: "Active tranche has no open task-Issues — consider archiving to completed/"
|
|
3610
3886
|
});
|
|
@@ -3636,27 +3912,38 @@ function extractClosesReferences(prBody) {
|
|
|
3636
3912
|
}
|
|
3637
3913
|
return referenced;
|
|
3638
3914
|
}
|
|
3639
|
-
function
|
|
3915
|
+
function checkClosesNTopology(branch, prBody, trancheFiles, taskIssueRefs) {
|
|
3640
3916
|
const referenced = extractClosesReferences(prBody);
|
|
3641
3917
|
if (taskIssueRefs) {
|
|
3642
3918
|
for (const n of referenced) {
|
|
3643
|
-
const
|
|
3644
|
-
if (!
|
|
3919
|
+
const ref2 = taskIssueRefs.get(n);
|
|
3920
|
+
if (!ref2)
|
|
3645
3921
|
continue;
|
|
3646
|
-
const expectedBranch = `task/${
|
|
3922
|
+
const expectedBranch = `task/${ref2.trancheSlug}/${ref2.taskId}`;
|
|
3647
3923
|
if (branch !== expectedBranch) {
|
|
3648
3924
|
return {
|
|
3649
3925
|
ok: false,
|
|
3650
|
-
message: `closes-n-reverse: branch "${branch}" closes #${n} (task ${
|
|
3926
|
+
message: `closes-n-reverse: branch "${branch}" closes #${n} (task ${ref2.taskId} of tranche "${ref2.trancheSlug}") but is not named "${expectedBranch}" — rename the branch and re-push, or if this work is intentionally outside AEG's dispatch flow, remove the Closes reference.`
|
|
3651
3927
|
};
|
|
3652
3928
|
}
|
|
3653
3929
|
}
|
|
3654
3930
|
}
|
|
3655
|
-
const
|
|
3656
|
-
if (!
|
|
3931
|
+
const ref = parseTaskBranchIdentity(branch);
|
|
3932
|
+
if (!ref)
|
|
3657
3933
|
return { ok: true };
|
|
3658
|
-
|
|
3659
|
-
|
|
3934
|
+
if (ref.kind === "issue") {
|
|
3935
|
+
const expectedIssue2 = ref.issueNumber;
|
|
3936
|
+
if (!referenced.has(expectedIssue2)) {
|
|
3937
|
+
return {
|
|
3938
|
+
ok: false,
|
|
3939
|
+
expectedIssue: expectedIssue2,
|
|
3940
|
+
message: `closes-n: PR body does not contain \`Closes #${expectedIssue2}\` (required for branch "${branch}"). Add it to the PR body Summary section.`
|
|
3941
|
+
};
|
|
3942
|
+
}
|
|
3943
|
+
return { ok: true, expectedIssue: expectedIssue2 };
|
|
3944
|
+
}
|
|
3945
|
+
const trancheSlug = ref.tranche;
|
|
3946
|
+
const taskId = ref.taskId;
|
|
3660
3947
|
const trancheFile = trancheFiles.find((f) => f.slug === trancheSlug);
|
|
3661
3948
|
if (!trancheFile) {
|
|
3662
3949
|
return {
|
|
@@ -3708,34 +3995,79 @@ function extractIssue(body) {
|
|
|
3708
3995
|
const issue = headerNums.length > 0 ? headerNums[0] : bodyNums[0];
|
|
3709
3996
|
return { issue, extraIssues: bodyNums.filter((n) => n !== issue), outsideHeader: headerNums.length === 0 };
|
|
3710
3997
|
}
|
|
3711
|
-
// ../../packages/aeg-core/src/review-
|
|
3712
|
-
|
|
3713
|
-
|
|
3998
|
+
// ../../packages/aeg-core/src/review-input-manifest.ts
|
|
3999
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
4000
|
+
function briefHash(brief) {
|
|
4001
|
+
return createHash4("sha256").update(`${brief}
|
|
4002
|
+
`).digest("hex");
|
|
4003
|
+
}
|
|
4004
|
+
function policyDigest(policy) {
|
|
4005
|
+
return createHash4("sha256").update(JSON.stringify({
|
|
4006
|
+
codeReviewThreshold: policy.codeReviewThreshold,
|
|
4007
|
+
securityThreshold: policy.securityThreshold,
|
|
4008
|
+
maxRounds: policy.maxRounds
|
|
4009
|
+
})).digest("hex");
|
|
4010
|
+
}
|
|
4011
|
+
function isBoundToHead(echoed, headSha) {
|
|
4012
|
+
if (!echoed.headSha)
|
|
3714
4013
|
return false;
|
|
3715
|
-
return headSha.toLowerCase().startsWith(
|
|
4014
|
+
return headSha.toLowerCase().startsWith(echoed.headSha.toLowerCase());
|
|
3716
4015
|
}
|
|
3717
|
-
function isBoundByPatchIdentity(
|
|
3718
|
-
if (patchIdOf === undefined || !
|
|
4016
|
+
function isBoundByPatchIdentity(echoed, headSha, patchIdOf) {
|
|
4017
|
+
if (patchIdOf === undefined || !echoed.headSha)
|
|
3719
4018
|
return false;
|
|
3720
|
-
const judged = patchIdOf(
|
|
4019
|
+
const judged = patchIdOf(echoed.headSha);
|
|
3721
4020
|
const current = patchIdOf(headSha);
|
|
3722
4021
|
if (judged === null || current === null)
|
|
3723
4022
|
return false;
|
|
3724
4023
|
return judged === current;
|
|
3725
4024
|
}
|
|
3726
|
-
function
|
|
3727
|
-
|
|
4025
|
+
function isBoundToBase(echoed, currentBase) {
|
|
4026
|
+
if (currentBase === null)
|
|
4027
|
+
return true;
|
|
4028
|
+
if (!echoed.baseSha)
|
|
4029
|
+
return false;
|
|
4030
|
+
return currentBase.toLowerCase().startsWith(echoed.baseSha.toLowerCase());
|
|
3728
4031
|
}
|
|
3729
|
-
function isBoundToObjectives(
|
|
4032
|
+
function isBoundToObjectives(echoed, currentVersion) {
|
|
3730
4033
|
if (currentVersion === null)
|
|
3731
4034
|
return true;
|
|
3732
|
-
return
|
|
4035
|
+
return echoed.objectivesVersion === currentVersion;
|
|
3733
4036
|
}
|
|
3734
|
-
function isBoundToRulings(
|
|
3735
|
-
if (
|
|
4037
|
+
function isBoundToRulings(echoed, currentOrdinal) {
|
|
4038
|
+
if (echoed.rulingOrdinal === null)
|
|
3736
4039
|
return currentOrdinal === 0;
|
|
3737
|
-
return
|
|
4040
|
+
return echoed.rulingOrdinal === currentOrdinal;
|
|
3738
4041
|
}
|
|
4042
|
+
function isBoundToBriefHash(echoed, currentHash) {
|
|
4043
|
+
if (currentHash === null)
|
|
4044
|
+
return true;
|
|
4045
|
+
return echoed.briefHash === currentHash;
|
|
4046
|
+
}
|
|
4047
|
+
function isBoundToPolicy(echoed, currentDigest) {
|
|
4048
|
+
return echoed.policyDigest === currentDigest;
|
|
4049
|
+
}
|
|
4050
|
+
function compareManifest(echoed, current, patchIdOf) {
|
|
4051
|
+
const exactHead = isBoundToHead(echoed, current.headSha);
|
|
4052
|
+
const patchHead = exactHead ? false : isBoundByPatchIdentity(echoed, current.headSha, patchIdOf);
|
|
4053
|
+
const head = exactHead || patchHead;
|
|
4054
|
+
const base = patchHead ? true : isBoundToBase(echoed, current.baseSha);
|
|
4055
|
+
const briefHashBound = isBoundToBriefHash(echoed, current.briefHash);
|
|
4056
|
+
const objectivesVersion2 = isBoundToObjectives(echoed, current.objectivesVersion);
|
|
4057
|
+
const rulingOrdinal = isBoundToRulings(echoed, current.rulingOrdinal);
|
|
4058
|
+
const policyDigestBound = isBoundToPolicy(echoed, current.policyDigest);
|
|
4059
|
+
return {
|
|
4060
|
+
bound: head && base && briefHashBound && objectivesVersion2 && rulingOrdinal && policyDigestBound,
|
|
4061
|
+
head,
|
|
4062
|
+
base,
|
|
4063
|
+
briefHash: briefHashBound,
|
|
4064
|
+
objectivesVersion: objectivesVersion2,
|
|
4065
|
+
rulingOrdinal,
|
|
4066
|
+
policyDigest: policyDigestBound
|
|
4067
|
+
};
|
|
4068
|
+
}
|
|
4069
|
+
|
|
4070
|
+
// ../../packages/aeg-core/src/review-gate.ts
|
|
3739
4071
|
function checkReviewGate(input) {
|
|
3740
4072
|
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
3741
4073
|
const waived = isWaiverLabelActorVerified({
|
|
@@ -3758,15 +4090,58 @@ function checkReviewGate(input) {
|
|
|
3758
4090
|
const verifiedBodies = verified.map((c) => c.body);
|
|
3759
4091
|
const codeReview = extractCodeReviewVerdict(verifiedBodies);
|
|
3760
4092
|
const security = extractSecurityReviewVerdict(verifiedBodies);
|
|
3761
|
-
const
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
4093
|
+
const policy = input.policy ?? DEFAULT_REVIEW_POLICY;
|
|
4094
|
+
let codeReviewPolicyEvaluation;
|
|
4095
|
+
let securityPolicyEvaluation;
|
|
4096
|
+
try {
|
|
4097
|
+
codeReviewPolicyEvaluation = evaluateCodeReview(codeReview.findingSeverities, policy);
|
|
4098
|
+
securityPolicyEvaluation = evaluateSecurityReview(security.findingSeverities, policy);
|
|
4099
|
+
} catch (err) {
|
|
4100
|
+
return {
|
|
4101
|
+
verdict: "fail",
|
|
4102
|
+
reason: `a verdict comment carries a finding severity this repository's policy does not recognize: ${err instanceof Error ? err.message : String(err)}`,
|
|
4103
|
+
waived: false
|
|
4104
|
+
};
|
|
4105
|
+
}
|
|
4106
|
+
const codeReviewTextClean = codeReview.value === "APPROVE";
|
|
4107
|
+
const securityTextClean = security.value === "PASS";
|
|
4108
|
+
const codeReviewPolicyClean = codeReviewPolicyEvaluation.outcome === "clean";
|
|
4109
|
+
const securityPolicyClean = securityPolicyEvaluation.outcome === "clean";
|
|
4110
|
+
const codeReviewClean = codeReviewTextClean && codeReviewPolicyClean;
|
|
4111
|
+
const securityClean = securityTextClean && securityPolicyClean;
|
|
4112
|
+
const currentManifest = {
|
|
4113
|
+
headSha: input.headSha,
|
|
4114
|
+
baseSha: input.baseSha ?? null,
|
|
4115
|
+
briefHash: input.briefHash ?? null,
|
|
4116
|
+
objectivesVersion: input.objectivesVersion,
|
|
4117
|
+
rulingOrdinal: input.rulingOrdinal,
|
|
4118
|
+
policyDigest: policyDigest(policy)
|
|
4119
|
+
};
|
|
4120
|
+
const codeReviewEchoed = {
|
|
4121
|
+
headSha: codeReview.headSha,
|
|
4122
|
+
baseSha: codeReview.baseSha,
|
|
4123
|
+
briefHash: codeReview.briefHash,
|
|
4124
|
+
objectivesVersion: codeReview.objectivesVersion,
|
|
4125
|
+
rulingOrdinal: codeReview.rulingOrdinal,
|
|
4126
|
+
policyDigest: codeReview.policyDigest
|
|
4127
|
+
};
|
|
4128
|
+
const securityEchoed = {
|
|
4129
|
+
headSha: security.headSha,
|
|
4130
|
+
baseSha: security.baseSha,
|
|
4131
|
+
briefHash: security.briefHash,
|
|
4132
|
+
objectivesVersion: security.objectivesVersion,
|
|
4133
|
+
rulingOrdinal: security.rulingOrdinal,
|
|
4134
|
+
policyDigest: security.policyDigest
|
|
4135
|
+
};
|
|
4136
|
+
const codeReviewBinding = compareManifest(codeReviewEchoed, currentManifest, input.patchIdOf);
|
|
4137
|
+
const securityBinding = compareManifest(securityEchoed, currentManifest, input.patchIdOf);
|
|
4138
|
+
const codeReviewBound = codeReviewBinding.head;
|
|
4139
|
+
const securityBound = securityBinding.head;
|
|
4140
|
+
const codeReviewObjectivesBound = codeReviewBinding.objectivesVersion;
|
|
4141
|
+
const securityObjectivesBound = securityBinding.objectivesVersion;
|
|
4142
|
+
const codeReviewRulingsBound = codeReviewBinding.rulingOrdinal;
|
|
4143
|
+
const securityRulingsBound = securityBinding.rulingOrdinal;
|
|
4144
|
+
if (codeReviewClean && codeReviewBinding.bound && securityClean && securityBinding.bound && mechanicalChecksClean) {
|
|
3770
4145
|
return {
|
|
3771
4146
|
verdict: "pass",
|
|
3772
4147
|
reason: `code-reviewer verdict is a clean APPROVE and security-review verdict is a clean PASS, both covering head ${input.headSha}, and every reported mechanical check is green.`,
|
|
@@ -3774,23 +4149,39 @@ function checkReviewGate(input) {
|
|
|
3774
4149
|
};
|
|
3775
4150
|
}
|
|
3776
4151
|
const problems = [];
|
|
3777
|
-
if (!
|
|
4152
|
+
if (!codeReviewTextClean) {
|
|
3778
4153
|
problems.push(`code-reviewer verdict is not a clean APPROVE (found: ${codeReview.value})`);
|
|
4154
|
+
} else if (!codeReviewPolicyClean) {
|
|
4155
|
+
problems.push(`code-reviewer verdict says APPROVE but carries a finding (${codeReviewPolicyEvaluation.blockingFindings.map((f) => f.severity).join(", ")}) at or above this repository's code-review policy threshold (${policy.codeReviewThreshold}) — a reviewer's own APPROVE never overrides policy`);
|
|
3779
4156
|
} else if (!codeReviewBound) {
|
|
3780
4157
|
problems.push(`the newest code-review verdict covers ${codeReview.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
4158
|
+
} else if (!codeReviewBinding.base) {
|
|
4159
|
+
problems.push(`the newest code-review verdict was cast against base ${codeReview.baseSha ?? "no recorded base"}, the PR's base is now ${currentManifest.baseSha ?? "unresolved"} (a base-only change under an unchanged candidate — same patch text on a new base is not automatically equivalent)`);
|
|
3781
4160
|
} else if (!codeReviewObjectivesBound) {
|
|
3782
4161
|
problems.push(`the newest code-review verdict was cast against objectives version ${codeReview.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
|
|
3783
4162
|
} else if (!codeReviewRulingsBound) {
|
|
3784
4163
|
problems.push(`the newest code-review verdict was cast against ruling ordinal ${codeReview.rulingOrdinal ?? "none"}, a newer ruling (ruling ${input.rulingOrdinal}) is now posted on this PR`);
|
|
4164
|
+
} else if (!codeReviewBinding.briefHash) {
|
|
4165
|
+
problems.push(`the newest code-review verdict was cast against brief hash ${codeReview.briefHash ?? "none"}, the frozen brief's current hash is ${currentManifest.briefHash ?? "none"}`);
|
|
4166
|
+
} else if (!codeReviewBinding.policyDigest) {
|
|
4167
|
+
problems.push(`the newest code-review verdict was cast against review policy digest ${codeReview.policyDigest ?? "none"}, this repository's current policy digest is ${currentManifest.policyDigest}`);
|
|
3785
4168
|
}
|
|
3786
|
-
if (!
|
|
4169
|
+
if (!securityTextClean) {
|
|
3787
4170
|
problems.push(`security-review verdict is not a clean PASS (found: ${security.value})`);
|
|
4171
|
+
} else if (!securityPolicyClean) {
|
|
4172
|
+
problems.push(`security-review verdict says PASS but carries a finding (${securityPolicyEvaluation.blockingFindings.map((f) => f.severity).join(", ")}) at or above this repository's security policy threshold (${policy.securityThreshold}) — a reviewer's own PASS never overrides policy`);
|
|
3788
4173
|
} else if (!securityBound) {
|
|
3789
4174
|
problems.push(`the newest security-review verdict covers ${security.headSha ?? "no recorded commit"}, head is ${input.headSha}`);
|
|
4175
|
+
} else if (!securityBinding.base) {
|
|
4176
|
+
problems.push(`the newest security-review verdict was cast against base ${security.baseSha ?? "no recorded base"}, the PR's base is now ${currentManifest.baseSha ?? "unresolved"} (a base-only change under an unchanged candidate — same patch text on a new base is not automatically equivalent)`);
|
|
3790
4177
|
} else if (!securityObjectivesBound) {
|
|
3791
4178
|
problems.push(`the newest security-review verdict was cast against objectives version ${security.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
|
|
3792
4179
|
} else if (!securityRulingsBound) {
|
|
3793
4180
|
problems.push(`the newest security-review verdict was cast against ruling ordinal ${security.rulingOrdinal ?? "none"}, a newer ruling (ruling ${input.rulingOrdinal}) is now posted on this PR`);
|
|
4181
|
+
} else if (!securityBinding.briefHash) {
|
|
4182
|
+
problems.push(`the newest security-review verdict was cast against brief hash ${security.briefHash ?? "none"}, the frozen brief's current hash is ${currentManifest.briefHash ?? "none"}`);
|
|
4183
|
+
} else if (!securityBinding.policyDigest) {
|
|
4184
|
+
problems.push(`the newest security-review verdict was cast against review policy digest ${security.policyDigest ?? "none"}, this repository's current policy digest is ${currentManifest.policyDigest}`);
|
|
3794
4185
|
}
|
|
3795
4186
|
if (!mechanicalChecksClean) {
|
|
3796
4187
|
problems.push(reportedMechanicalChecks.length === 0 ? "no mechanical checks have reported for this head yet" : `mechanical check(s) not green: ${reportedMechanicalChecks.filter((c) => c.bucket !== "pass").map((c) => `${c.name} (${c.bucket})`).join(", ")}`);
|
|
@@ -4482,42 +4873,45 @@ function checkDispatchReadiness(input) {
|
|
|
4482
4873
|
const { trancheSlug, task } = input;
|
|
4483
4874
|
const taskLabel = `task ${task.id} (tranche ${trancheSlug})`;
|
|
4484
4875
|
const principalAllowlist = input.principalAllowlist ?? PRINCIPAL_ALLOWLIST;
|
|
4485
|
-
const
|
|
4876
|
+
const blockerDetails = [];
|
|
4877
|
+
const push = (blockerClass, message) => {
|
|
4878
|
+
blockerDetails.push({ class: blockerClass, message });
|
|
4879
|
+
};
|
|
4486
4880
|
if (task.issue === null) {
|
|
4487
|
-
|
|
4881
|
+
push("issue-existence", `dispatch-gate issue-existence: ${taskLabel} has no Issue (#TBD or blank) in the topology — not dispatchable until the Planner cuts the Issue.`);
|
|
4488
4882
|
} else if (input.issue === null) {
|
|
4489
|
-
|
|
4883
|
+
push("issue-existence", `dispatch-gate issue-existence: ${taskLabel} names Issue #${task.issue}, but it does not resolve to a real GitHub Issue (phantom reference).`);
|
|
4490
4884
|
}
|
|
4491
4885
|
if (input.issue !== null && !input.issueRationalePass) {
|
|
4492
|
-
|
|
4886
|
+
push("rationale", `dispatch-gate rationale: Issue #${input.issue.number} for ${taskLabel} fails the rationale gate (checkIssueRationale) — the Planner must complete the eight-field rationale before this task is dispatchable.`);
|
|
4493
4887
|
}
|
|
4494
4888
|
for (const dep of input.dependsOn) {
|
|
4495
4889
|
if (isSelfDependency(dep, task, input.issue)) {
|
|
4496
4890
|
const issueStr = input.issue !== null ? `#${input.issue.number}` : "?";
|
|
4497
|
-
|
|
4891
|
+
push("internal-self-dependency", `dispatch-gate INTERNAL: parsed a self-dependency for task ${task.id} (${issueStr}) — this is a parser bug in parseRationaleDeps, not a real dependency. Please report it upstream. Re-run once the rationale is corrected or the fix ships.`);
|
|
4498
4892
|
continue;
|
|
4499
4893
|
}
|
|
4500
4894
|
if (dep.resolved === false) {
|
|
4501
|
-
|
|
4895
|
+
push("depends-on-unresolvable", `dispatch-gate depends-on: ${taskLabel} depends on "${dep.id}", which is UNRESOLVABLE — the resolver could not find a matching tranche/task/Issue for this edge (not a claim about merge status). Not dispatchable until the edge is corrected.`);
|
|
4502
4896
|
continue;
|
|
4503
4897
|
}
|
|
4504
4898
|
if (!dep.merged && !isHandClosedByRecognizedPrincipal(dep, principalAllowlist)) {
|
|
4505
4899
|
const issueStr = dep.issue !== null ? ` (#${dep.issue})` : "";
|
|
4506
|
-
|
|
4900
|
+
push("depends-on-not-merged", `dispatch-gate depends-on: ${taskLabel} depends on ${dep.id}${issueStr}, whose PR is not merged yet — not dispatchable, it serializes behind it.`);
|
|
4507
4901
|
}
|
|
4508
4902
|
}
|
|
4509
4903
|
for (const c of input.conflictsWith) {
|
|
4510
4904
|
if (c.openOrInFlight) {
|
|
4511
4905
|
const issueStr = c.issue !== null ? ` (#${c.issue})` : "";
|
|
4512
|
-
|
|
4906
|
+
push("conflicts-with", `dispatch-gate conflicts-with: ${taskLabel} conflicts with ${c.id}${issueStr}, whose PR is open or in-flight — not dispatchable until it merges.`);
|
|
4513
4907
|
}
|
|
4514
4908
|
}
|
|
4515
4909
|
for (const proj of input.priorTrancheArchival) {
|
|
4516
4910
|
if (proj.priorTrancheSlug !== null && !proj.archived) {
|
|
4517
|
-
|
|
4911
|
+
push("prior-tranche-archival", `dispatch-gate prior-tranche-archival: project \`${proj.project}\`'s previous tranche \`${proj.priorTrancheSlug}\` is not archived — the Tranche Archivist must run before new work on this product.`);
|
|
4518
4912
|
}
|
|
4519
4913
|
}
|
|
4520
|
-
return { ready:
|
|
4914
|
+
return { ready: blockerDetails.length === 0, blockers: blockerDetails.map((b) => b.message), blockerDetails };
|
|
4521
4915
|
}
|
|
4522
4916
|
// ../../packages/aeg-core/src/single-plan-pr.ts
|
|
4523
4917
|
function trancheSlugFromTopologyPath(path) {
|
|
@@ -4619,6 +5013,137 @@ function checkBranchTopology(input) {
|
|
|
4619
5013
|
reason: `Branch \`${branch}\` matches topology row \`${taskId}\` in ${topoPath}.`
|
|
4620
5014
|
};
|
|
4621
5015
|
}
|
|
5016
|
+
// ../../packages/aeg-core/src/task-tools.ts
|
|
5017
|
+
import { z } from "zod";
|
|
5018
|
+
var TASK_TOOL_ERROR_KINDS = [
|
|
5019
|
+
"validation",
|
|
5020
|
+
"authority",
|
|
5021
|
+
"precondition",
|
|
5022
|
+
"capability",
|
|
5023
|
+
"infrastructure",
|
|
5024
|
+
"cancellation",
|
|
5025
|
+
"timeout",
|
|
5026
|
+
"uncertain_effect"
|
|
5027
|
+
];
|
|
5028
|
+
var TaskToolErrorSchema = z.object({
|
|
5029
|
+
kind: z.enum(TASK_TOOL_ERROR_KINDS),
|
|
5030
|
+
message: z.string().min(1),
|
|
5031
|
+
detail: z.string().optional()
|
|
5032
|
+
});
|
|
5033
|
+
var TaskToolRefSchema = z.union([
|
|
5034
|
+
z.object({ tranche: z.string().min(1), id: z.string().min(1) }).strict(),
|
|
5035
|
+
z.object({ issue: z.number().int().positive() }).strict()
|
|
5036
|
+
]);
|
|
5037
|
+
var MAX_PAGE_LIMIT = 100;
|
|
5038
|
+
var PageRequestSchema = z.object({
|
|
5039
|
+
cursor: z.string().optional(),
|
|
5040
|
+
limit: z.number().int().positive().max(MAX_PAGE_LIMIT).optional()
|
|
5041
|
+
});
|
|
5042
|
+
var FreshnessSchema = z.enum(["fresh", "stale", "unknown"]);
|
|
5043
|
+
var ObservedSchema = z.object({
|
|
5044
|
+
observedAt: z.string(),
|
|
5045
|
+
freshness: FreshnessSchema
|
|
5046
|
+
});
|
|
5047
|
+
var TaskStatusInputSchema = z.object({
|
|
5048
|
+
task: TaskToolRefSchema.optional()
|
|
5049
|
+
}).merge(PageRequestSchema).strict();
|
|
5050
|
+
var TaskStatusItemSchema = z.object({
|
|
5051
|
+
task: TaskToolRefSchema,
|
|
5052
|
+
issue: z.number().int().positive(),
|
|
5053
|
+
pr: z.number().int().positive().nullable(),
|
|
5054
|
+
state: z.string()
|
|
5055
|
+
}).merge(ObservedSchema);
|
|
5056
|
+
var TaskStatusResultSchema = z.object({
|
|
5057
|
+
items: z.array(TaskStatusItemSchema),
|
|
5058
|
+
nextCursor: z.string().nullable()
|
|
5059
|
+
});
|
|
5060
|
+
var RequestedAuthoritySchema = z.enum(["planner", "principal", "operator", "self"]);
|
|
5061
|
+
var EscalationInputsSchema = z.object({
|
|
5062
|
+
task: z.number().int().positive(),
|
|
5063
|
+
round: z.number().int().nonnegative(),
|
|
5064
|
+
head: z.string(),
|
|
5065
|
+
branch: z.string(),
|
|
5066
|
+
prNumber: z.number().int().positive()
|
|
5067
|
+
});
|
|
5068
|
+
var EscalationEvidenceSchema = z.object({
|
|
5069
|
+
round: z.number().int().nonnegative(),
|
|
5070
|
+
reviewer: z.string().nullable(),
|
|
5071
|
+
security: z.string().nullable()
|
|
5072
|
+
});
|
|
5073
|
+
var EscalationRunIdentitySchema = z.object({
|
|
5074
|
+
runId: z.string(),
|
|
5075
|
+
pid: z.number().int().positive(),
|
|
5076
|
+
host: z.string()
|
|
5077
|
+
});
|
|
5078
|
+
var EscalationInputVersionsSchema = z.object({
|
|
5079
|
+
briefHash: z.string().nullable(),
|
|
5080
|
+
objectivesVersion: z.string().nullable(),
|
|
5081
|
+
rulingOrdinal: z.number().int().nonnegative(),
|
|
5082
|
+
policyDigest: z.string()
|
|
5083
|
+
});
|
|
5084
|
+
var TaskEscalationReadInputSchema = z.object({
|
|
5085
|
+
task: TaskToolRefSchema
|
|
5086
|
+
}).merge(PageRequestSchema).strict();
|
|
5087
|
+
var TaskEscalationPacketSchema = z.object({
|
|
5088
|
+
reason: z.string(),
|
|
5089
|
+
detail: z.string().nullable(),
|
|
5090
|
+
inputs: EscalationInputsSchema.nullable(),
|
|
5091
|
+
evidence: EscalationEvidenceSchema.nullable(),
|
|
5092
|
+
attemptedRecovery: z.string(),
|
|
5093
|
+
requestedAuthority: RequestedAuthoritySchema,
|
|
5094
|
+
permittedNextActions: z.array(z.string()),
|
|
5095
|
+
runIdentity: EscalationRunIdentitySchema.nullable(),
|
|
5096
|
+
inputVersions: EscalationInputVersionsSchema.nullable()
|
|
5097
|
+
}).merge(ObservedSchema);
|
|
5098
|
+
var TaskEscalationReadResultSchema = z.object({
|
|
5099
|
+
items: z.array(TaskEscalationPacketSchema),
|
|
5100
|
+
nextCursor: z.string().nullable()
|
|
5101
|
+
}).merge(ObservedSchema);
|
|
5102
|
+
var TaskStartInputSchema = z.object({
|
|
5103
|
+
tranche: z.string().min(1),
|
|
5104
|
+
id: z.string().min(1)
|
|
5105
|
+
}).strict();
|
|
5106
|
+
var TaskStartResultSchema = z.object({
|
|
5107
|
+
requestId: z.string().min(1),
|
|
5108
|
+
run: z.object({ tranche: z.string().min(1), id: z.string().min(1) }),
|
|
5109
|
+
started: z.boolean(),
|
|
5110
|
+
startedAt: z.string(),
|
|
5111
|
+
mode: z.literal("attended")
|
|
5112
|
+
});
|
|
5113
|
+
var TaskResumeInputSchema = z.object({
|
|
5114
|
+
task: TaskToolRefSchema
|
|
5115
|
+
}).strict();
|
|
5116
|
+
var TaskCancelInputSchema = z.object({
|
|
5117
|
+
task: TaskToolRefSchema,
|
|
5118
|
+
reason: z.string().min(1)
|
|
5119
|
+
}).strict();
|
|
5120
|
+
var TaskResumeResultSchema = z.object({
|
|
5121
|
+
task: z.number().int().positive(),
|
|
5122
|
+
pr: z.number().int().positive(),
|
|
5123
|
+
escalationId: z.string().min(1),
|
|
5124
|
+
outcome: z.enum(["started", "already_resumed"]),
|
|
5125
|
+
authenticatedBy: z.string().min(1),
|
|
5126
|
+
authenticatedFrom: z.string().min(1)
|
|
5127
|
+
});
|
|
5128
|
+
var TaskCancelOutcomeSchema = z.enum(["confirmed", "pending", "uncertain"]);
|
|
5129
|
+
var TaskCancelResultSchema = z.object({
|
|
5130
|
+
task: z.number().int().positive(),
|
|
5131
|
+
pr: z.number().int().positive(),
|
|
5132
|
+
escalationId: z.string().min(1),
|
|
5133
|
+
outcome: TaskCancelOutcomeSchema,
|
|
5134
|
+
authenticatedBy: z.string().min(1),
|
|
5135
|
+
authenticatedFrom: z.string().min(1),
|
|
5136
|
+
fencedEffectKeys: z.array(z.string())
|
|
5137
|
+
});
|
|
5138
|
+
var TASK_TOOL_NAMES = [
|
|
5139
|
+
"task_start",
|
|
5140
|
+
"task_status",
|
|
5141
|
+
"task_escalation_read",
|
|
5142
|
+
"task_resume",
|
|
5143
|
+
"task_cancel"
|
|
5144
|
+
];
|
|
5145
|
+
var OPERATOR_STATUS_FOLLOW = "task_status_follow";
|
|
5146
|
+
var OPERATOR_TOOL_GRANT = [...TASK_TOOL_NAMES, OPERATOR_STATUS_FOLLOW];
|
|
4622
5147
|
// ../../packages/aeg-core/src/first-push-dispatch-gate.ts
|
|
4623
5148
|
function parseTaskBranch(branch) {
|
|
4624
5149
|
const m = /^task\/([^/]+)\/([^/]+)$/.exec(branch);
|
|
@@ -4702,7 +5227,6 @@ function decideIssueAssignment(input) {
|
|
|
4702
5227
|
};
|
|
4703
5228
|
}
|
|
4704
5229
|
// ../../packages/aeg-core/src/test-plan-gate.ts
|
|
4705
|
-
var TASK_BRANCH_PATTERN2 = /^task\/[^/]+\/[^/]+$/;
|
|
4706
5230
|
function evaluateTestPlanGate(body, branch) {
|
|
4707
5231
|
if (!body) {
|
|
4708
5232
|
return {
|
|
@@ -4715,7 +5239,7 @@ function evaluateTestPlanGate(body, branch) {
|
|
|
4715
5239
|
}
|
|
4716
5240
|
const located = locateTestPlanSection(body);
|
|
4717
5241
|
if (!located.found) {
|
|
4718
|
-
if (
|
|
5242
|
+
if (parseTaskBranchIdentity(branch) !== null) {
|
|
4719
5243
|
return {
|
|
4720
5244
|
verdict: "fail",
|
|
4721
5245
|
messages: [
|
|
@@ -4842,8 +5366,11 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
|
|
|
4842
5366
|
}
|
|
4843
5367
|
return findings;
|
|
4844
5368
|
}
|
|
5369
|
+
// ../../packages/aeg-core/src/log/envelope.ts
|
|
5370
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
5371
|
+
|
|
4845
5372
|
// ../../packages/aeg-core/src/log/schema.ts
|
|
4846
|
-
import { z } from "zod";
|
|
5373
|
+
import { z as z2 } from "zod";
|
|
4847
5374
|
var ROLE_VALUES = [
|
|
4848
5375
|
"planner",
|
|
4849
5376
|
"developer",
|
|
@@ -4853,136 +5380,174 @@ var ROLE_VALUES = [
|
|
|
4853
5380
|
"archivist",
|
|
4854
5381
|
"architect"
|
|
4855
5382
|
];
|
|
4856
|
-
var RoleSchema =
|
|
5383
|
+
var RoleSchema = z2.enum(ROLE_VALUES);
|
|
4857
5384
|
var HOST_VALUES = ["hook", "ci", "cli", "loop"];
|
|
4858
|
-
var HostSchema =
|
|
5385
|
+
var HostSchema = z2.enum(HOST_VALUES);
|
|
4859
5386
|
var RUN_ID_PATTERN = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
4860
|
-
var
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
doctrine: z.string(),
|
|
5387
|
+
var headerMetaCore = {
|
|
5388
|
+
ts: z2.string(),
|
|
5389
|
+
run_id: z2.string().regex(RUN_ID_PATTERN),
|
|
5390
|
+
seq: z2.number().int().nonnegative(),
|
|
5391
|
+
repo: z2.string().nullable(),
|
|
5392
|
+
vinaya: z2.string(),
|
|
5393
|
+
doctrine: z2.string(),
|
|
4868
5394
|
host: HostSchema,
|
|
4869
|
-
machine:
|
|
5395
|
+
machine: z2.string()
|
|
5396
|
+
};
|
|
5397
|
+
var HeaderMetaV1Schema = z2.object({
|
|
5398
|
+
schema: z2.literal(1),
|
|
5399
|
+
...headerMetaCore
|
|
5400
|
+
}).strict();
|
|
5401
|
+
var LineageSchema = z2.object({
|
|
5402
|
+
run: z2.string().nullable(),
|
|
5403
|
+
attempt: z2.number().int().nullable(),
|
|
5404
|
+
parent: z2.string().nullable()
|
|
4870
5405
|
}).strict();
|
|
4871
|
-
var
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
round: z.number().int().optional(),
|
|
4877
|
-
objectives_version: z.string().optional()
|
|
5406
|
+
var InputVersionsSchema = z2.object({
|
|
5407
|
+
objectives_version: z2.string().nullable(),
|
|
5408
|
+
brief_hash: z2.string().nullable(),
|
|
5409
|
+
ruling_ordinal: z2.number().int().nullable(),
|
|
5410
|
+
policy_digest: z2.string().nullable()
|
|
4878
5411
|
}).strict();
|
|
4879
|
-
var
|
|
5412
|
+
var ProvenanceSchema = z2.enum(["parent_attributed", "env_correlated", "self_reported", "unavailable"]);
|
|
5413
|
+
var HeaderMetaV2Schema = z2.object({
|
|
5414
|
+
schema: z2.literal(2),
|
|
5415
|
+
...headerMetaCore,
|
|
5416
|
+
event_id: z2.string().min(1),
|
|
5417
|
+
process_id: z2.string().min(1),
|
|
5418
|
+
actor_id: z2.string().nullable(),
|
|
5419
|
+
lineage: LineageSchema,
|
|
5420
|
+
input_versions: InputVersionsSchema,
|
|
5421
|
+
provenance: ProvenanceSchema
|
|
5422
|
+
}).strict();
|
|
5423
|
+
var HeaderMetaSchema = z2.discriminatedUnion("schema", [HeaderMetaV1Schema, HeaderMetaV2Schema]);
|
|
5424
|
+
var SubjectSchema = z2.object({
|
|
5425
|
+
issue: z2.number().int().nullable(),
|
|
5426
|
+
pr: z2.number().int().optional(),
|
|
5427
|
+
sha: z2.string().optional(),
|
|
5428
|
+
role: z2.union([RoleSchema, z2.literal("unattributed")]),
|
|
5429
|
+
round: z2.number().int().optional(),
|
|
5430
|
+
objectives_version: z2.string().optional()
|
|
5431
|
+
}).strict();
|
|
5432
|
+
var HeaderSchema = z2.object({
|
|
4880
5433
|
meta: HeaderMetaSchema,
|
|
4881
5434
|
subject: SubjectSchema
|
|
4882
5435
|
}).strict();
|
|
4883
5436
|
var envelopeTail = {
|
|
4884
|
-
duration_ms:
|
|
4885
|
-
payload:
|
|
5437
|
+
duration_ms: z2.number().nonnegative().optional(),
|
|
5438
|
+
payload: z2.object({}).strict()
|
|
4886
5439
|
};
|
|
4887
|
-
var
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
5440
|
+
var ReviewFindingSchema = z2.object({
|
|
5441
|
+
id: z2.string(),
|
|
5442
|
+
severity: z2.string(),
|
|
5443
|
+
state: z2.string().optional(),
|
|
5444
|
+
severity_scale: z2.string().optional(),
|
|
5445
|
+
policy_treatment: z2.enum(["blocking", "non_blocking", "unavailable"]).optional(),
|
|
5446
|
+
confidence: z2.number().min(0).max(1).optional(),
|
|
5447
|
+
confidence_scale: z2.string().optional(),
|
|
5448
|
+
confidence_source: z2.string().optional()
|
|
5449
|
+
}).strict();
|
|
5450
|
+
var DispatchOutcomeSchema = z2.discriminatedUnion("type", [
|
|
5451
|
+
z2.object({ type: z2.literal("pr_opened"), pr: z2.number().int(), head: z2.string() }).strict(),
|
|
5452
|
+
z2.object({
|
|
5453
|
+
type: z2.literal("round_pushed"),
|
|
5454
|
+
pr: z2.number().int(),
|
|
5455
|
+
head: z2.string(),
|
|
5456
|
+
comment_id: z2.number().int()
|
|
4894
5457
|
}).strict(),
|
|
4895
|
-
|
|
4896
|
-
type:
|
|
4897
|
-
verdict:
|
|
4898
|
-
head:
|
|
4899
|
-
comment_id:
|
|
4900
|
-
objectives:
|
|
4901
|
-
findings:
|
|
5458
|
+
z2.object({
|
|
5459
|
+
type: z2.literal("verdict"),
|
|
5460
|
+
verdict: z2.enum(["APPROVE", "REQUEST CHANGES", "PASS", "FAIL"]),
|
|
5461
|
+
head: z2.string(),
|
|
5462
|
+
comment_id: z2.number().int(),
|
|
5463
|
+
objectives: z2.array(z2.object({ id: z2.string(), met: z2.boolean() }).strict()),
|
|
5464
|
+
findings: z2.array(ReviewFindingSchema)
|
|
4902
5465
|
}).strict(),
|
|
4903
|
-
|
|
4904
|
-
type:
|
|
4905
|
-
class:
|
|
4906
|
-
comment_id:
|
|
5466
|
+
z2.object({
|
|
5467
|
+
type: z2.literal("escalation"),
|
|
5468
|
+
class: z2.enum(["authority", "strategy", "product"]),
|
|
5469
|
+
comment_id: z2.number().int()
|
|
4907
5470
|
}).strict(),
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
5471
|
+
z2.object({ type: z2.literal("brief"), comment_id: z2.number().int(), hash: z2.string() }).strict(),
|
|
5472
|
+
z2.object({ type: z2.literal("plan"), issues: z2.array(z2.number().int()) }).strict(),
|
|
5473
|
+
z2.object({ type: z2.literal("archive"), provenance_comment_id: z2.number().int() }).strict(),
|
|
5474
|
+
z2.object({ type: z2.literal("completed") }).strict()
|
|
4911
5475
|
]);
|
|
4912
5476
|
var dispatchShared = {
|
|
4913
5477
|
meta: HeaderMetaSchema,
|
|
4914
5478
|
subject: SubjectSchema,
|
|
4915
|
-
kind:
|
|
5479
|
+
kind: z2.literal("dispatch"),
|
|
4916
5480
|
...envelopeTail,
|
|
4917
5481
|
target_role: RoleSchema,
|
|
4918
|
-
model:
|
|
4919
|
-
round:
|
|
4920
|
-
effect_id:
|
|
5482
|
+
model: z2.string(),
|
|
5483
|
+
round: z2.number().int().optional(),
|
|
5484
|
+
effect_id: z2.string()
|
|
4921
5485
|
};
|
|
4922
|
-
var dispatchUsageField =
|
|
4923
|
-
var DispatchEventSchema =
|
|
4924
|
-
|
|
4925
|
-
|
|
5486
|
+
var dispatchUsageField = z2.object({ input: z2.number().nonnegative(), output: z2.number().nonnegative() }).strict().nullable();
|
|
5487
|
+
var DispatchEventSchema = z2.discriminatedUnion("event", [
|
|
5488
|
+
z2.object({ ...dispatchShared, event: z2.literal("dispatched"), prompt_hash: z2.string() }).strict(),
|
|
5489
|
+
z2.object({
|
|
4926
5490
|
...dispatchShared,
|
|
4927
|
-
event:
|
|
5491
|
+
event: z2.literal("outcome_received"),
|
|
4928
5492
|
outcome: DispatchOutcomeSchema,
|
|
4929
5493
|
usage: dispatchUsageField
|
|
4930
5494
|
}).strict(),
|
|
4931
|
-
|
|
5495
|
+
z2.object({
|
|
4932
5496
|
...dispatchShared,
|
|
4933
|
-
event:
|
|
4934
|
-
reason:
|
|
5497
|
+
event: z2.literal("dispatch_failed"),
|
|
5498
|
+
reason: z2.enum(["timeout", "crash", "refused", "unattributed_write"]),
|
|
4935
5499
|
usage: dispatchUsageField
|
|
4936
5500
|
}).strict()
|
|
4937
5501
|
]);
|
|
4938
5502
|
var loopShared = {
|
|
4939
5503
|
meta: HeaderMetaSchema,
|
|
4940
5504
|
subject: SubjectSchema,
|
|
4941
|
-
kind:
|
|
5505
|
+
kind: z2.literal("dev_review_loop"),
|
|
4942
5506
|
...envelopeTail,
|
|
4943
|
-
loop_id:
|
|
5507
|
+
loop_id: z2.string()
|
|
4944
5508
|
};
|
|
4945
|
-
var DevReviewLoopEventSchema =
|
|
4946
|
-
|
|
5509
|
+
var DevReviewLoopEventSchema = z2.discriminatedUnion("event", [
|
|
5510
|
+
z2.object({
|
|
4947
5511
|
...loopShared,
|
|
4948
|
-
event:
|
|
4949
|
-
task:
|
|
4950
|
-
policy:
|
|
4951
|
-
max_rounds:
|
|
4952
|
-
reviewers:
|
|
4953
|
-
models:
|
|
5512
|
+
event: z2.literal("loop_started"),
|
|
5513
|
+
task: z2.number().int(),
|
|
5514
|
+
policy: z2.object({
|
|
5515
|
+
max_rounds: z2.number().int().nonnegative(),
|
|
5516
|
+
reviewers: z2.array(RoleSchema),
|
|
5517
|
+
models: z2.record(RoleSchema, z2.string())
|
|
4954
5518
|
}).strict()
|
|
4955
5519
|
}).strict(),
|
|
4956
|
-
|
|
4957
|
-
|
|
5520
|
+
z2.object({ ...loopShared, event: z2.literal("round_started"), round: z2.number().int(), base_head: z2.string() }).strict(),
|
|
5521
|
+
z2.object({
|
|
4958
5522
|
...loopShared,
|
|
4959
|
-
event:
|
|
4960
|
-
round:
|
|
4961
|
-
head:
|
|
4962
|
-
green:
|
|
5523
|
+
event: z2.literal("gate_result_read"),
|
|
5524
|
+
round: z2.number().int(),
|
|
5525
|
+
head: z2.string(),
|
|
5526
|
+
green: z2.boolean()
|
|
4963
5527
|
}).strict(),
|
|
4964
|
-
|
|
5528
|
+
z2.object({
|
|
4965
5529
|
...loopShared,
|
|
4966
|
-
event:
|
|
4967
|
-
round:
|
|
4968
|
-
head:
|
|
4969
|
-
all_approve:
|
|
4970
|
-
blockers:
|
|
5530
|
+
event: z2.literal("verdicts_read"),
|
|
5531
|
+
round: z2.number().int(),
|
|
5532
|
+
head: z2.string(),
|
|
5533
|
+
all_approve: z2.boolean(),
|
|
5534
|
+
blockers: z2.number().int().nonnegative(),
|
|
5535
|
+
findings: z2.array(ReviewFindingSchema).optional()
|
|
4971
5536
|
}).strict(),
|
|
4972
|
-
|
|
5537
|
+
z2.object({
|
|
4973
5538
|
...loopShared,
|
|
4974
|
-
event:
|
|
4975
|
-
round:
|
|
4976
|
-
open:
|
|
4977
|
-
resolved:
|
|
4978
|
-
new:
|
|
4979
|
-
recurring:
|
|
5539
|
+
event: z2.literal("findings_compared"),
|
|
5540
|
+
round: z2.number().int(),
|
|
5541
|
+
open: z2.array(z2.string()),
|
|
5542
|
+
resolved: z2.array(z2.string()),
|
|
5543
|
+
new: z2.array(z2.string()),
|
|
5544
|
+
recurring: z2.array(z2.string())
|
|
4980
5545
|
}).strict(),
|
|
4981
|
-
|
|
5546
|
+
z2.object({
|
|
4982
5547
|
...loopShared,
|
|
4983
|
-
event:
|
|
4984
|
-
round:
|
|
4985
|
-
condition:
|
|
5548
|
+
event: z2.literal("stop_condition_met"),
|
|
5549
|
+
round: z2.number().int(),
|
|
5550
|
+
condition: z2.enum([
|
|
4986
5551
|
"green",
|
|
4987
5552
|
"max_rounds",
|
|
4988
5553
|
"no_progress",
|
|
@@ -4992,42 +5557,49 @@ var DevReviewLoopEventSchema = z.discriminatedUnion("event", [
|
|
|
4992
5557
|
"reappearance"
|
|
4993
5558
|
])
|
|
4994
5559
|
}).strict(),
|
|
4995
|
-
|
|
5560
|
+
z2.object({
|
|
4996
5561
|
...loopShared,
|
|
4997
|
-
event:
|
|
4998
|
-
round:
|
|
4999
|
-
reason:
|
|
5562
|
+
event: z2.literal("paused"),
|
|
5563
|
+
round: z2.number().int(),
|
|
5564
|
+
reason: z2.enum(["escalation", "principal_item", "refreeze_needed"])
|
|
5000
5565
|
}).strict(),
|
|
5001
|
-
|
|
5566
|
+
z2.object({
|
|
5002
5567
|
...loopShared,
|
|
5003
|
-
event:
|
|
5004
|
-
round:
|
|
5005
|
-
by:
|
|
5568
|
+
event: z2.literal("resumed"),
|
|
5569
|
+
round: z2.number().int(),
|
|
5570
|
+
by: z2.literal("principal")
|
|
5006
5571
|
}).strict(),
|
|
5007
|
-
|
|
5572
|
+
z2.object({
|
|
5008
5573
|
...loopShared,
|
|
5009
|
-
event:
|
|
5010
|
-
round:
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
files_changed: z.number().int().nonnegative(),
|
|
5014
|
-
insertions: z.number().int().nonnegative(),
|
|
5015
|
-
deletions: z.number().int().nonnegative(),
|
|
5016
|
-
wall_ms: z.number().nonnegative(),
|
|
5017
|
-
outcome: z.enum(["green", "changes_requested", "escalated"])
|
|
5574
|
+
event: z2.literal("unpushed_work_resume"),
|
|
5575
|
+
round: z2.number().int(),
|
|
5576
|
+
branch: z2.string(),
|
|
5577
|
+
detail: z2.string()
|
|
5018
5578
|
}).strict(),
|
|
5019
|
-
|
|
5579
|
+
z2.object({
|
|
5020
5580
|
...loopShared,
|
|
5021
|
-
event:
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5581
|
+
event: z2.literal("round_ended"),
|
|
5582
|
+
round: z2.number().int(),
|
|
5583
|
+
base_head: z2.string(),
|
|
5584
|
+
head: z2.string(),
|
|
5585
|
+
files_changed: z2.number().int().nonnegative(),
|
|
5586
|
+
insertions: z2.number().int().nonnegative(),
|
|
5587
|
+
deletions: z2.number().int().nonnegative(),
|
|
5588
|
+
wall_ms: z2.number().nonnegative(),
|
|
5589
|
+
outcome: z2.enum(["green", "changes_requested", "escalated"])
|
|
5590
|
+
}).strict(),
|
|
5591
|
+
z2.object({
|
|
5592
|
+
...loopShared,
|
|
5593
|
+
event: z2.literal("journal_finalized"),
|
|
5594
|
+
rounds: z2.number().int().nonnegative(),
|
|
5595
|
+
total_wall_ms: z2.number().nonnegative(),
|
|
5596
|
+
time_to_green_ms: z2.number().nonnegative().nullable(),
|
|
5597
|
+
files_changed_total: z2.number().int().nonnegative(),
|
|
5598
|
+
final_head: z2.string(),
|
|
5599
|
+
result: z2.enum(["merged_ready", "stopped"])
|
|
5028
5600
|
}).strict()
|
|
5029
5601
|
]);
|
|
5030
|
-
var ForgeOpSchema =
|
|
5602
|
+
var ForgeOpSchema = z2.enum([
|
|
5031
5603
|
"pr.create",
|
|
5032
5604
|
"pr.comment",
|
|
5033
5605
|
"pr.body.replace",
|
|
@@ -5041,24 +5613,434 @@ var ForgeOpSchema = z.enum([
|
|
|
5041
5613
|
"label.add",
|
|
5042
5614
|
"label.remove"
|
|
5043
5615
|
]);
|
|
5044
|
-
var ForgeWriteTargetSchema =
|
|
5045
|
-
issue:
|
|
5046
|
-
pr:
|
|
5616
|
+
var ForgeWriteTargetSchema = z2.object({
|
|
5617
|
+
issue: z2.number().int().optional(),
|
|
5618
|
+
pr: z2.number().int().optional()
|
|
5047
5619
|
}).strict();
|
|
5048
5620
|
var forgeWriteShared = {
|
|
5049
5621
|
meta: HeaderMetaSchema,
|
|
5050
5622
|
subject: SubjectSchema,
|
|
5051
|
-
kind:
|
|
5623
|
+
kind: z2.literal("forge_write"),
|
|
5052
5624
|
...envelopeTail,
|
|
5053
5625
|
op: ForgeOpSchema,
|
|
5054
5626
|
target: ForgeWriteTargetSchema
|
|
5055
5627
|
};
|
|
5056
|
-
var ForgeWriteEventSchema =
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5628
|
+
var ForgeWriteEventSchema = z2.discriminatedUnion("event", [
|
|
5629
|
+
z2.object({ ...forgeWriteShared, event: z2.literal("validated") }).strict(),
|
|
5630
|
+
z2.object({ ...forgeWriteShared, event: z2.literal("refused"), reason: z2.string() }).strict(),
|
|
5631
|
+
z2.object({ ...forgeWriteShared, event: z2.literal("written"), comment_ids: z2.array(z2.string()) }).strict()
|
|
5632
|
+
]);
|
|
5633
|
+
var GateOutcomeSchema = z2.enum([
|
|
5634
|
+
"pass",
|
|
5635
|
+
"fail",
|
|
5636
|
+
"wait",
|
|
5637
|
+
"skip",
|
|
5638
|
+
"invalid_input",
|
|
5639
|
+
"unavailable_dependency",
|
|
5640
|
+
"timeout",
|
|
5641
|
+
"cancelled"
|
|
5642
|
+
]);
|
|
5643
|
+
var gateShared = {
|
|
5644
|
+
meta: HeaderMetaSchema,
|
|
5645
|
+
subject: SubjectSchema,
|
|
5646
|
+
kind: z2.literal("gate"),
|
|
5647
|
+
...envelopeTail,
|
|
5648
|
+
check: z2.string(),
|
|
5649
|
+
check_version: z2.string().nullable(),
|
|
5650
|
+
policy_version: z2.string().nullable(),
|
|
5651
|
+
input_fingerprint: z2.string().nullable()
|
|
5652
|
+
};
|
|
5653
|
+
var GateEventSchema = z2.discriminatedUnion("event", [
|
|
5654
|
+
z2.object({
|
|
5655
|
+
...gateShared,
|
|
5656
|
+
event: z2.literal("checked"),
|
|
5657
|
+
outcome: GateOutcomeSchema,
|
|
5658
|
+
reason: z2.string().optional()
|
|
5659
|
+
}).strict()
|
|
5660
|
+
]);
|
|
5661
|
+
var OperationResultSchema = z2.enum(["ok", "error", "refused", "timeout", "cancelled", "unavailable"]);
|
|
5662
|
+
var operationShared = {
|
|
5663
|
+
meta: HeaderMetaSchema,
|
|
5664
|
+
subject: SubjectSchema,
|
|
5665
|
+
kind: z2.literal("operation"),
|
|
5666
|
+
...envelopeTail,
|
|
5667
|
+
operation: z2.string(),
|
|
5668
|
+
target: z2.string().nullable()
|
|
5669
|
+
};
|
|
5670
|
+
var OperationEventSchema = z2.discriminatedUnion("event", [
|
|
5671
|
+
z2.object({
|
|
5672
|
+
...operationShared,
|
|
5673
|
+
event: z2.literal("completed"),
|
|
5674
|
+
result: OperationResultSchema,
|
|
5675
|
+
error_class: z2.string().nullable()
|
|
5676
|
+
}).strict()
|
|
5677
|
+
]);
|
|
5678
|
+
var UsageUnitsSchema = z2.object({
|
|
5679
|
+
input: z2.number().nonnegative().nullable(),
|
|
5680
|
+
output: z2.number().nonnegative().nullable(),
|
|
5681
|
+
cache: z2.number().nonnegative().nullable()
|
|
5682
|
+
}).strict();
|
|
5683
|
+
var usageShared = {
|
|
5684
|
+
meta: HeaderMetaSchema,
|
|
5685
|
+
subject: SubjectSchema,
|
|
5686
|
+
kind: z2.literal("usage"),
|
|
5687
|
+
...envelopeTail,
|
|
5688
|
+
model: z2.string().nullable(),
|
|
5689
|
+
source: z2.string(),
|
|
5690
|
+
semantics: z2.enum(["cumulative", "delta"])
|
|
5691
|
+
};
|
|
5692
|
+
var UsageEventSchema = z2.discriminatedUnion("event", [
|
|
5693
|
+
z2.object({
|
|
5694
|
+
...usageShared,
|
|
5695
|
+
event: z2.literal("observed"),
|
|
5696
|
+
units: UsageUnitsSchema,
|
|
5697
|
+
unknown_reason: z2.string().nullable()
|
|
5698
|
+
}).strict()
|
|
5699
|
+
]);
|
|
5700
|
+
var RoleAttemptOutcomeSchema = z2.enum([
|
|
5701
|
+
"completed",
|
|
5702
|
+
"incomplete",
|
|
5703
|
+
"infrastructure_failed",
|
|
5704
|
+
"cancelled",
|
|
5705
|
+
"timed_out",
|
|
5706
|
+
"capability_refused"
|
|
5707
|
+
]);
|
|
5708
|
+
var roleAttemptShared = {
|
|
5709
|
+
meta: HeaderMetaSchema,
|
|
5710
|
+
subject: SubjectSchema,
|
|
5711
|
+
kind: z2.literal("role_attempt"),
|
|
5712
|
+
...envelopeTail,
|
|
5713
|
+
actor: z2.string().nullable(),
|
|
5714
|
+
attempt: z2.number().int().nullable(),
|
|
5715
|
+
effect_id: z2.string(),
|
|
5716
|
+
model: z2.string().nullable()
|
|
5717
|
+
};
|
|
5718
|
+
var RoleAttemptEventSchema = z2.discriminatedUnion("event", [
|
|
5719
|
+
z2.object({
|
|
5720
|
+
...roleAttemptShared,
|
|
5721
|
+
event: z2.literal("attempted"),
|
|
5722
|
+
outcome: RoleAttemptOutcomeSchema,
|
|
5723
|
+
usage: dispatchUsageField
|
|
5724
|
+
}).strict()
|
|
5725
|
+
]);
|
|
5726
|
+
var handoffShared = {
|
|
5727
|
+
meta: HeaderMetaSchema,
|
|
5728
|
+
subject: SubjectSchema,
|
|
5729
|
+
kind: z2.literal("handoff"),
|
|
5730
|
+
...envelopeTail,
|
|
5731
|
+
class: z2.enum(["authority", "strategy", "product"]),
|
|
5732
|
+
reason: z2.string()
|
|
5733
|
+
};
|
|
5734
|
+
var HandoffEventSchema = z2.discriminatedUnion("event", [
|
|
5735
|
+
z2.object({
|
|
5736
|
+
...handoffShared,
|
|
5737
|
+
event: z2.literal("raised"),
|
|
5738
|
+
requested_decision: z2.string().nullable()
|
|
5739
|
+
}).strict(),
|
|
5740
|
+
z2.object({
|
|
5741
|
+
...handoffShared,
|
|
5742
|
+
event: z2.literal("resolved"),
|
|
5743
|
+
resolution: z2.string().nullable(),
|
|
5744
|
+
resolved_by: z2.string().nullable()
|
|
5745
|
+
}).strict()
|
|
5746
|
+
]);
|
|
5747
|
+
var EffectTargetSchema = z2.object({
|
|
5748
|
+
kind: z2.string(),
|
|
5749
|
+
ref: z2.string()
|
|
5750
|
+
}).strict();
|
|
5751
|
+
var effectShared = {
|
|
5752
|
+
meta: HeaderMetaSchema,
|
|
5753
|
+
subject: SubjectSchema,
|
|
5754
|
+
kind: z2.literal("effect"),
|
|
5755
|
+
...envelopeTail,
|
|
5756
|
+
effect_id: z2.string(),
|
|
5757
|
+
target: EffectTargetSchema
|
|
5758
|
+
};
|
|
5759
|
+
var EffectEventSchema = z2.discriminatedUnion("event", [
|
|
5760
|
+
z2.object({ ...effectShared, event: z2.literal("attempted") }).strict(),
|
|
5761
|
+
z2.object({ ...effectShared, event: z2.literal("observed"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict(),
|
|
5762
|
+
z2.object({ ...effectShared, event: z2.literal("verified"), outcome: z2.enum(["success", "failure", "uncertain"]) }).strict()
|
|
5763
|
+
]);
|
|
5764
|
+
var LogEventSchema = z2.union([
|
|
5765
|
+
DispatchEventSchema,
|
|
5766
|
+
DevReviewLoopEventSchema,
|
|
5767
|
+
ForgeWriteEventSchema,
|
|
5768
|
+
GateEventSchema,
|
|
5769
|
+
OperationEventSchema,
|
|
5770
|
+
UsageEventSchema,
|
|
5771
|
+
RoleAttemptEventSchema,
|
|
5772
|
+
HandoffEventSchema,
|
|
5773
|
+
EffectEventSchema
|
|
5060
5774
|
]);
|
|
5061
|
-
|
|
5775
|
+
|
|
5776
|
+
// ../../packages/aeg-core/src/log/envelope.ts
|
|
5777
|
+
function isRole(value) {
|
|
5778
|
+
return value !== undefined && ROLE_VALUES.includes(value);
|
|
5779
|
+
}
|
|
5780
|
+
function actorIdFromEnv(role) {
|
|
5781
|
+
return role === undefined || role === "" ? null : role;
|
|
5782
|
+
}
|
|
5783
|
+
function lineageFieldFromEnv(value) {
|
|
5784
|
+
return value === undefined || value === "" ? null : value;
|
|
5785
|
+
}
|
|
5786
|
+
function attemptFromEnv(value) {
|
|
5787
|
+
if (value === undefined || value === "")
|
|
5788
|
+
return null;
|
|
5789
|
+
const n = Number(value);
|
|
5790
|
+
return Number.isInteger(n) ? n : null;
|
|
5791
|
+
}
|
|
5792
|
+
function provenanceFor(input) {
|
|
5793
|
+
if (input.provenance)
|
|
5794
|
+
return input.provenance;
|
|
5795
|
+
if (input.env.role || input.env.task)
|
|
5796
|
+
return "env_correlated";
|
|
5797
|
+
return "unavailable";
|
|
5798
|
+
}
|
|
5799
|
+
function issueFromTask(task) {
|
|
5800
|
+
if (task === undefined || task === "")
|
|
5801
|
+
return null;
|
|
5802
|
+
const n = Number(task);
|
|
5803
|
+
return Number.isInteger(n) ? n : null;
|
|
5804
|
+
}
|
|
5805
|
+
function roundFromEnv(round) {
|
|
5806
|
+
if (round === undefined || round === "")
|
|
5807
|
+
return;
|
|
5808
|
+
const n = Number(round);
|
|
5809
|
+
return Number.isInteger(n) ? n : undefined;
|
|
5810
|
+
}
|
|
5811
|
+
function buildHeader(input) {
|
|
5812
|
+
const role = isRole(input.env.role) ? input.env.role : "unattributed";
|
|
5813
|
+
const round = roundFromEnv(input.env.round);
|
|
5814
|
+
const subject = {
|
|
5815
|
+
issue: issueFromTask(input.env.task),
|
|
5816
|
+
role,
|
|
5817
|
+
...round !== undefined ? { round } : {},
|
|
5818
|
+
...input.subject ?? {}
|
|
5819
|
+
};
|
|
5820
|
+
return {
|
|
5821
|
+
meta: {
|
|
5822
|
+
schema: 2,
|
|
5823
|
+
ts: input.now.toISOString(),
|
|
5824
|
+
run_id: input.runId,
|
|
5825
|
+
seq: input.seq,
|
|
5826
|
+
repo: input.repo,
|
|
5827
|
+
vinaya: input.vinaya,
|
|
5828
|
+
doctrine: input.doctrine,
|
|
5829
|
+
host: input.host,
|
|
5830
|
+
machine: createHash5("sha256").update(input.hostname).digest("hex"),
|
|
5831
|
+
event_id: input.eventId,
|
|
5832
|
+
process_id: input.processId,
|
|
5833
|
+
actor_id: actorIdFromEnv(input.env.role),
|
|
5834
|
+
lineage: {
|
|
5835
|
+
run: lineageFieldFromEnv(input.env.run),
|
|
5836
|
+
attempt: attemptFromEnv(input.env.attempt),
|
|
5837
|
+
parent: lineageFieldFromEnv(input.env.parent)
|
|
5838
|
+
},
|
|
5839
|
+
input_versions: {
|
|
5840
|
+
objectives_version: input.inputVersions?.objectivesVersion ?? null,
|
|
5841
|
+
brief_hash: input.inputVersions?.briefHash ?? null,
|
|
5842
|
+
ruling_ordinal: input.inputVersions?.rulingOrdinal ?? null,
|
|
5843
|
+
policy_digest: input.inputVersions?.policyDigest ?? null
|
|
5844
|
+
},
|
|
5845
|
+
provenance: provenanceFor(input)
|
|
5846
|
+
},
|
|
5847
|
+
subject
|
|
5848
|
+
};
|
|
5849
|
+
}
|
|
5850
|
+
// ../../packages/aeg-core/src/log/redact.ts
|
|
5851
|
+
var GITHUB_TOKEN_PATTERN = /\b(?:gho_|ghp_|ghs_|ghu_|ghr_|github_pat_)[A-Za-z0-9_]+\b/g;
|
|
5852
|
+
var CLASSIC_GITHUB_PAT_PATTERN = /\b((?:token|GITHUB_TOKEN|PAT|api[_-]?key|api[_-]?token)\s*[:=]\s*)[a-f0-9]{40}\b/gi;
|
|
5853
|
+
var BEARER_TOKEN_PATTERN = /\bBearer\s+\S+/g;
|
|
5854
|
+
var AWS_ACCESS_KEY_PATTERN = /\bAKIA[0-9A-Z]{16}\b/g;
|
|
5855
|
+
var SLACK_TOKEN_PATTERN = /\bxox[baprs]-[0-9A-Za-z-]+\b/g;
|
|
5856
|
+
var STRIPE_KEY_PATTERN = /\b(?:sk|pk|rk)_(?:live|test)_[0-9A-Za-z]{10,}\b/g;
|
|
5857
|
+
var ANTHROPIC_KEY_PATTERN = /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g;
|
|
5858
|
+
var OPENAI_KEY_PATTERN = /\bsk-(?!ant-)[A-Za-z0-9]{20,}\b/g;
|
|
5859
|
+
var NPM_TOKEN_PATTERN = /\bnpm_[A-Za-z0-9]{36}\b/g;
|
|
5860
|
+
var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g;
|
|
5861
|
+
var PEM_BLOCK_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g;
|
|
5862
|
+
var BASIC_AUTH_URL_PATTERN = /(https?:\/\/)[^/\s:@]+:[^/\s@]+@/g;
|
|
5863
|
+
var GENERIC_SECRET_ASSIGNMENT_PATTERN = /\b((?:secret|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)\s*[:=]\s*)[A-Za-z0-9+/_=-]{16,}\b/gi;
|
|
5864
|
+
function redactString(value, home) {
|
|
5865
|
+
let out = value.replace(GITHUB_TOKEN_PATTERN, "<redacted>").replace(CLASSIC_GITHUB_PAT_PATTERN, "$1<redacted>").replace(BEARER_TOKEN_PATTERN, "<redacted>").replace(AWS_ACCESS_KEY_PATTERN, "<redacted>").replace(SLACK_TOKEN_PATTERN, "<redacted>").replace(STRIPE_KEY_PATTERN, "<redacted>").replace(ANTHROPIC_KEY_PATTERN, "<redacted>").replace(OPENAI_KEY_PATTERN, "<redacted>").replace(NPM_TOKEN_PATTERN, "<redacted>").replace(JWT_PATTERN, "<redacted>").replace(PEM_BLOCK_PATTERN, "<redacted>").replace(BASIC_AUTH_URL_PATTERN, "$1<redacted>@").replace(GENERIC_SECRET_ASSIGNMENT_PATTERN, "$1<redacted>");
|
|
5866
|
+
if (home.length > 0 && out.startsWith(home)) {
|
|
5867
|
+
const rest = out.slice(home.length);
|
|
5868
|
+
if (rest === "" || rest.startsWith("/"))
|
|
5869
|
+
out = `~${rest}`;
|
|
5870
|
+
}
|
|
5871
|
+
return out;
|
|
5872
|
+
}
|
|
5873
|
+
function redact(value, home) {
|
|
5874
|
+
if (typeof value === "string")
|
|
5875
|
+
return redactString(value, home);
|
|
5876
|
+
if (Array.isArray(value))
|
|
5877
|
+
return value.map((v) => redact(v, home));
|
|
5878
|
+
if (value !== null && typeof value === "object") {
|
|
5879
|
+
const out = {};
|
|
5880
|
+
for (const [k, v] of Object.entries(value)) {
|
|
5881
|
+
out[k] = redact(v, home);
|
|
5882
|
+
}
|
|
5883
|
+
return out;
|
|
5884
|
+
}
|
|
5885
|
+
return value;
|
|
5886
|
+
}
|
|
5887
|
+
// ../../packages/aeg-core/src/log/store.ts
|
|
5888
|
+
function metaOf(obj) {
|
|
5889
|
+
if (obj === null || typeof obj !== "object")
|
|
5890
|
+
return null;
|
|
5891
|
+
const meta = obj.meta;
|
|
5892
|
+
if (meta === null || typeof meta !== "object")
|
|
5893
|
+
return null;
|
|
5894
|
+
return meta;
|
|
5895
|
+
}
|
|
5896
|
+
function recordIdentity(obj) {
|
|
5897
|
+
const meta = metaOf(obj);
|
|
5898
|
+
if (meta === null)
|
|
5899
|
+
return null;
|
|
5900
|
+
const eventId = meta.event_id;
|
|
5901
|
+
if (typeof eventId === "string" && eventId.length > 0)
|
|
5902
|
+
return eventId;
|
|
5903
|
+
const runId = meta.run_id;
|
|
5904
|
+
const seq = meta.seq;
|
|
5905
|
+
if (typeof runId === "string" && runId.length > 0 && typeof seq === "number" && Number.isInteger(seq)) {
|
|
5906
|
+
return `${runId}:${seq}`;
|
|
5907
|
+
}
|
|
5908
|
+
return null;
|
|
5909
|
+
}
|
|
5910
|
+
|
|
5911
|
+
// ../../packages/aeg-core/src/log/artifact.ts
|
|
5912
|
+
var TASK_LOG_ARTIFACT_MAX_BYTES = 8 * 1024 * 1024;
|
|
5913
|
+
// ../../packages/aeg-core/src/dev-review-loop/journal-reconstruction.ts
|
|
5914
|
+
var STOPPED_CONDITIONS = new Set(["confidence", "reappearance", "no_progress", "max_rounds"]);
|
|
5915
|
+
// ../../packages/aeg-core/src/control-store/records.ts
|
|
5916
|
+
import { z as z3 } from "zod";
|
|
5917
|
+
var isoTimestamp = z3.string().min(1);
|
|
5918
|
+
var taskId = z3.number().int().positive();
|
|
5919
|
+
var epochNumber = z3.number().int().nonnegative();
|
|
5920
|
+
var RunRecordSchema = z3.object({
|
|
5921
|
+
version: z3.literal(1),
|
|
5922
|
+
kind: z3.literal("run"),
|
|
5923
|
+
task: taskId,
|
|
5924
|
+
runId: z3.string().min(1),
|
|
5925
|
+
pid: z3.number().int().positive(),
|
|
5926
|
+
host: z3.string().min(1),
|
|
5927
|
+
startedAt: isoTimestamp,
|
|
5928
|
+
childStartedAt: z3.string().min(1).nullable().optional(),
|
|
5929
|
+
childCommand: z3.string().min(1).nullable().optional()
|
|
5930
|
+
}).strict();
|
|
5931
|
+
var InputRecordSchema = z3.object({
|
|
5932
|
+
version: z3.literal(1),
|
|
5933
|
+
kind: z3.literal("input"),
|
|
5934
|
+
task: taskId,
|
|
5935
|
+
runId: z3.string().min(1),
|
|
5936
|
+
source: z3.union([z3.literal("fresh"), z3.literal("resume")]),
|
|
5937
|
+
pr: z3.number().int().positive().nullable(),
|
|
5938
|
+
round: z3.number().int().nonnegative(),
|
|
5939
|
+
recordedAt: isoTimestamp
|
|
5940
|
+
}).strict();
|
|
5941
|
+
var OwnershipRecordSchema = z3.object({
|
|
5942
|
+
version: z3.literal(1),
|
|
5943
|
+
kind: z3.literal("ownership"),
|
|
5944
|
+
task: taskId,
|
|
5945
|
+
epoch: epochNumber,
|
|
5946
|
+
ownerId: z3.string().min(1),
|
|
5947
|
+
pid: z3.number().int().positive(),
|
|
5948
|
+
host: z3.string().min(1),
|
|
5949
|
+
acquiredAt: isoTimestamp
|
|
5950
|
+
}).strict();
|
|
5951
|
+
var TransitionRecordSchema = z3.object({
|
|
5952
|
+
version: z3.literal(1),
|
|
5953
|
+
kind: z3.literal("transition"),
|
|
5954
|
+
task: taskId,
|
|
5955
|
+
epoch: epochNumber,
|
|
5956
|
+
seq: z3.number().int().nonnegative(),
|
|
5957
|
+
from: z3.string().min(1),
|
|
5958
|
+
to: z3.string().min(1),
|
|
5959
|
+
detail: z3.string().optional(),
|
|
5960
|
+
at: isoTimestamp
|
|
5961
|
+
}).strict();
|
|
5962
|
+
var ManifestRecordSchema = z3.object({
|
|
5963
|
+
version: z3.literal(1),
|
|
5964
|
+
kind: z3.literal("manifest"),
|
|
5965
|
+
task: taskId,
|
|
5966
|
+
round: epochNumber,
|
|
5967
|
+
repository: z3.string().min(1),
|
|
5968
|
+
pr: z3.number().int().positive(),
|
|
5969
|
+
branch: z3.string().min(1),
|
|
5970
|
+
baseSha: z3.string().min(1).nullable(),
|
|
5971
|
+
headSha: z3.string().min(1),
|
|
5972
|
+
briefHash: z3.string().min(1).nullable(),
|
|
5973
|
+
objectivesVersion: z3.string().min(1).nullable(),
|
|
5974
|
+
rulingOrdinal: epochNumber,
|
|
5975
|
+
policyDigest: z3.string().min(1),
|
|
5976
|
+
recordedAt: isoTimestamp
|
|
5977
|
+
}).strict();
|
|
5978
|
+
var roundHeadIdentity = z3.object({ round: z3.number().int().positive(), head: z3.string().min(1) }).strict();
|
|
5979
|
+
var LoopBudgetsSchema = z3.object({
|
|
5980
|
+
mechanicalRetries: z3.number().int().nonnegative(),
|
|
5981
|
+
reviewRounds: z3.number().int().nonnegative(),
|
|
5982
|
+
infrastructureRetries: z3.number().int().nonnegative()
|
|
5983
|
+
}).strict();
|
|
5984
|
+
var LoopStateRecordSchema = z3.object({
|
|
5985
|
+
version: z3.literal(1),
|
|
5986
|
+
kind: z3.literal("loop_state"),
|
|
5987
|
+
task: taskId,
|
|
5988
|
+
round: z3.number().int().positive(),
|
|
5989
|
+
phase: z3.string().min(1),
|
|
5990
|
+
pauseReason: z3.string().min(1).nullable(),
|
|
5991
|
+
budgets: LoopBudgetsSchema,
|
|
5992
|
+
heldResult: roundHeadIdentity.nullable(),
|
|
5993
|
+
deliveredFindings: roundHeadIdentity.nullable(),
|
|
5994
|
+
recordedAt: isoTimestamp
|
|
5995
|
+
}).strict();
|
|
5996
|
+
var EffectRecordSchema = z3.object({
|
|
5997
|
+
version: z3.literal(1),
|
|
5998
|
+
kind: z3.literal("effect"),
|
|
5999
|
+
task: taskId,
|
|
6000
|
+
key: z3.string().min(1),
|
|
6001
|
+
operation: z3.string().min(1),
|
|
6002
|
+
target: z3.string().min(1),
|
|
6003
|
+
inputVersion: z3.number().int().nonnegative(),
|
|
6004
|
+
payloadDigest: z3.string().min(1),
|
|
6005
|
+
status: z3.union([z3.literal("started"), z3.literal("verified"), z3.literal("uncertain")]),
|
|
6006
|
+
url: z3.string().optional(),
|
|
6007
|
+
recordedAt: isoTimestamp
|
|
6008
|
+
}).strict();
|
|
6009
|
+
var EscalationRecordSchema = z3.object({
|
|
6010
|
+
version: z3.literal(1),
|
|
6011
|
+
kind: z3.literal("escalation"),
|
|
6012
|
+
task: taskId,
|
|
6013
|
+
escalationId: z3.string().min(1),
|
|
6014
|
+
round: epochNumber,
|
|
6015
|
+
head: z3.string().min(1),
|
|
6016
|
+
branch: z3.string().min(1),
|
|
6017
|
+
pr: z3.number().int().positive().nullable(),
|
|
6018
|
+
runId: z3.string().min(1),
|
|
6019
|
+
pid: z3.number().int().positive(),
|
|
6020
|
+
host: z3.string().min(1),
|
|
6021
|
+
agent: z3.string().min(1).optional(),
|
|
6022
|
+
reason: z3.string().min(1),
|
|
6023
|
+
detail: z3.string().optional(),
|
|
6024
|
+
evidence: z3.string().optional(),
|
|
6025
|
+
attemptedRecovery: z3.string().min(1),
|
|
6026
|
+
requestedDecision: z3.string().min(1),
|
|
6027
|
+
recipient: z3.string().min(1),
|
|
6028
|
+
briefHash: z3.string().min(1).nullable(),
|
|
6029
|
+
objectivesVersion: z3.string().min(1).nullable(),
|
|
6030
|
+
rulingOrdinal: epochNumber,
|
|
6031
|
+
policyDigest: z3.string().min(1),
|
|
6032
|
+
recordedAt: isoTimestamp
|
|
6033
|
+
}).strict();
|
|
6034
|
+
var ResolutionRecordSchema = z3.object({
|
|
6035
|
+
version: z3.literal(1),
|
|
6036
|
+
kind: z3.literal("resolution"),
|
|
6037
|
+
task: taskId,
|
|
6038
|
+
escalationId: z3.string().min(1),
|
|
6039
|
+
decision: z3.union([z3.literal("resume"), z3.literal("cancel")]),
|
|
6040
|
+
authenticatedBy: z3.string().min(1),
|
|
6041
|
+
authenticatedFrom: z3.string().min(1),
|
|
6042
|
+
consumedAt: isoTimestamp
|
|
6043
|
+
}).strict();
|
|
5062
6044
|
// src/checks/contract.ts
|
|
5063
6045
|
var CHECK_SCHEMA_VERSION = 1;
|
|
5064
6046
|
function emitCheckError(error) {
|
|
@@ -5068,24 +6050,40 @@ function emitCheckError(error) {
|
|
|
5068
6050
|
|
|
5069
6051
|
// src/checks/bin/check-test-plan.ts
|
|
5070
6052
|
var CHECK_NAME = "test-plan";
|
|
6053
|
+
function buildTestPlanCheckErrors(result) {
|
|
6054
|
+
if (result.verdict !== "fail")
|
|
6055
|
+
return [];
|
|
6056
|
+
const principalPending = result.messages.some((m) => m.startsWith("FAIL — the following [principal] Test Plan items are unticked:"));
|
|
6057
|
+
const errors = [];
|
|
6058
|
+
for (const message of result.messages) {
|
|
6059
|
+
if (!message)
|
|
6060
|
+
continue;
|
|
6061
|
+
errors.push({
|
|
6062
|
+
schema: CHECK_SCHEMA_VERSION,
|
|
6063
|
+
check: CHECK_NAME,
|
|
6064
|
+
severity: "error",
|
|
6065
|
+
message,
|
|
6066
|
+
agent_recovery_prompt: principalPending ? "Nothing for the Developer to fix here — wait for the Principal to verify in a real signed-in browser and tick each `[principal]` Test Plan box, then re-run `vinaya check test-plan`." : "Add a `## Test Plan` section to the PR body (or the `Test Plan: unit-tests-only` sentinel for a pure-logic brief with no runtime surface), then re-run `vinaya check test-plan`.",
|
|
6067
|
+
...principalPending ? { pending: true } : {}
|
|
6068
|
+
});
|
|
6069
|
+
}
|
|
6070
|
+
return errors;
|
|
6071
|
+
}
|
|
5071
6072
|
function main() {
|
|
5072
6073
|
const body = process.env.PR_BODY ?? "";
|
|
5073
6074
|
const branch = process.env.BRANCH ?? "";
|
|
5074
6075
|
const result = evaluateTestPlanGate(body, branch);
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
emitCheckError({
|
|
5080
|
-
schema: CHECK_SCHEMA_VERSION,
|
|
5081
|
-
check: CHECK_NAME,
|
|
5082
|
-
severity: "error",
|
|
5083
|
-
message,
|
|
5084
|
-
agent_recovery_prompt: "Run each `[agent]` Test Plan command from the PR head and let `vinaya pr report` write its output into the AEG:EVIDENCE block; leave `[principal]` boxes for the Principal to tick after verifying in a real signed-in browser. Re-run `vinaya check test-plan` afterwards."
|
|
5085
|
-
});
|
|
5086
|
-
}
|
|
6076
|
+
const errors = buildTestPlanCheckErrors(result);
|
|
6077
|
+
if (errors.length > 0) {
|
|
6078
|
+
for (const error of errors)
|
|
6079
|
+
emitCheckError(error);
|
|
5087
6080
|
process.exit(1);
|
|
5088
6081
|
}
|
|
5089
6082
|
process.exit(0);
|
|
5090
6083
|
}
|
|
5091
|
-
main
|
|
6084
|
+
if (__require.main == __require.module) {
|
|
6085
|
+
main();
|
|
6086
|
+
}
|
|
6087
|
+
export {
|
|
6088
|
+
buildTestPlanCheckErrors
|
|
6089
|
+
};
|