@attalabs/vinaya 0.28.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.
Files changed (138) hide show
  1. package/README.md +1 -1
  2. package/aeg-root/contracts/planner-developer.md +4 -1
  3. package/aeg-root/contracts/planner-operator.md +86 -0
  4. package/aeg-root/contracts/principal-operator.md +88 -0
  5. package/aeg-root/roles/developer.md +2 -1
  6. package/aeg-root/roles/operator.md +133 -0
  7. package/aeg-root/roles/planner.md +4 -0
  8. package/aeg-root/skills/aeg-context-packets/SKILL.md +123 -0
  9. package/aeg-root/skills/aeg-context-packets/examples/operator-start.md +30 -0
  10. package/aeg-root/templates/brief-template.md +6 -2
  11. package/dist/checks/bin/check-body-bare-digits.js +376 -16
  12. package/dist/checks/bin/check-branch-topology.js +403 -16
  13. package/dist/checks/bin/check-brief-shape.js +380 -19
  14. package/dist/checks/bin/check-changeset-coverage.js +673 -33
  15. package/dist/checks/bin/check-closes-n.js +403 -16
  16. package/dist/checks/bin/check-coherence.js +410 -16
  17. package/dist/checks/bin/check-dead-branch-push.js +369 -16
  18. package/dist/checks/bin/check-dispatch-readiness.js +410 -16
  19. package/dist/checks/bin/check-doc-coverage-push.js +670 -30
  20. package/dist/checks/bin/check-doc-coverage.js +672 -32
  21. package/dist/checks/bin/check-doctrine-no-procedures.js +376 -16
  22. package/dist/checks/bin/check-doctrine-portability.js +670 -30
  23. package/dist/checks/bin/check-evidence-fresh.js +762 -113
  24. package/dist/checks/bin/check-exec-bits.js +668 -28
  25. package/dist/checks/bin/check-first-push-dispatch.js +410 -16
  26. package/dist/checks/bin/check-issue-assignment.js +403 -16
  27. package/dist/checks/bin/check-issue-milestone-attach.js +369 -16
  28. package/dist/checks/bin/check-issue-objectives-numbering.js +369 -16
  29. package/dist/checks/bin/check-issue-parts-coverage.js +369 -16
  30. package/dist/checks/bin/check-issue-surface-globs.js +410 -16
  31. package/dist/checks/bin/check-issue-title-grammar.js +369 -16
  32. package/dist/checks/bin/check-issue-tranche-label.js +369 -16
  33. package/dist/checks/bin/check-main-branch-refusal.js +369 -16
  34. package/dist/checks/bin/check-no-disk-state.js +369 -16
  35. package/dist/checks/bin/check-pr-premise-reassert.js +376 -16
  36. package/dist/checks/bin/check-pr-report-density.js +369 -16
  37. package/dist/checks/bin/check-quoted-command.js +671 -31
  38. package/dist/checks/bin/check-reader-resolvable-prose.js +674 -34
  39. package/dist/checks/bin/check-registry-gates.js +369 -16
  40. package/dist/checks/bin/check-retired-vocabulary.js +669 -29
  41. package/dist/checks/bin/check-review-gate.js +391 -16
  42. package/dist/checks/bin/check-single-plan-pr.js +369 -16
  43. package/dist/checks/bin/check-surface-scope.js +403 -16
  44. package/dist/checks/bin/check-test-plan.js +369 -16
  45. package/dist/checks/bin/check-token-collection-wired.js +369 -16
  46. package/dist/checks/bin/check-token-report.js +382 -19
  47. package/dist/checks/bin/check-workspace-escape.js +668 -28
  48. package/dist/index.js +15307 -10932
  49. package/dist/lib/pre-push-select-tests.js +154 -11
  50. package/package.json +1 -1
  51. package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
  52. package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
  53. package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
  54. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error/page.js +2 -1
  55. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  56. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
  57. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
  58. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  59. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  61. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  62. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  63. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
  64. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js +8 -7
  65. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  66. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  67. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
  68. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js +8 -7
  69. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
  70. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
  71. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
  72. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js +9 -8
  73. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
  74. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
  75. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
  76. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js +9 -8
  77. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
  78. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
  79. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
  80. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js +8 -7
  81. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
  82. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
  83. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +16 -4
  84. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js +10 -8
  85. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
  86. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
  87. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
  88. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js +8 -7
  89. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
  90. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
  91. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
  92. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js +8 -7
  93. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
  94. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
  95. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
  96. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js +9 -8
  97. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
  98. package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
  99. 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
  100. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__08f5pba._.js +3 -0
  101. 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
  102. 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
  103. 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
  104. 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
  105. 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
  106. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1-zcufa._.js +51 -0
  107. 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
  108. 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
  109. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1bh2awk._.js +3 -0
  110. 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
  111. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1qmxez3._.js +4 -0
  112. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1r47dr7._.js +28 -0
  113. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
  114. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_01fv4fj._.js +1 -1
  115. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0gvm3og._.js → _096f46i._.js} +3 -2
  116. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_0lwxg63._.js → _0af2one._.js} +3 -2
  117. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_1n0cnq-._.js → _0zf4d27._.js} +45 -2
  118. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{_03x_w6q._.js → _1-wo68i._.js} +3 -2
  119. 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
  120. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1wdusod._.js +3 -0
  121. 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
  122. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_next_1khj-jh._.js +3 -0
  123. package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
  124. package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
  125. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
  126. package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +17 -5
  127. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3_9xytdmiv1xi.js → 25f3-jtiv8p5n.js} +4 -4
  128. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{0bn8c8v5q429o.js → 27-6ym7lp2v8o.js} +1 -1
  129. package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{3-6a3tinbdb-7.js → 3daxns3o--9me.js} +1 -1
  130. package/studio-standalone/apps/vinaya-studio/web/tsconfig.json +12 -0
  131. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0z6dav-._.js +0 -51
  132. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__13rrmhr._.js +0 -3
  133. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__17h4sy8._.js +0 -45
  134. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +0 -3
  135. package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_next_17sz44y._.js +0 -3
  136. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_buildManifest.js +0 -0
  137. /package/studio-standalone/apps/vinaya-studio/web/.next/static/{DMofV2-9FrHE7100GfrpI → -UC6GS6zDHeiawEYgYbTN}/_clientMiddlewareManifest.js +0 -0
  138. /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);
@@ -1953,6 +1999,7 @@ var OBJECTIVES_VERSION_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Objectives version:\
1953
1999
  var RULING_ORDINAL_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Ruling ordinal:\s*(\d+)(?!\d)/im;
1954
2000
  var BRIEF_HASH_PATTERN = /^[ \t]*(?:\*{1,3}|_{1,3})?Brief hash:\s*([0-9a-f]{64})(?![A-Za-z0-9])/im;
1955
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;
1956
2003
  function firstFiveLines(comment) {
1957
2004
  return comment.split(`
1958
2005
  `).slice(0, 5).join(`
@@ -1988,6 +2035,15 @@ function extractPolicyDigest(comment) {
1988
2035
  const m = firstElevenLines(comment).match(POLICY_DIGEST_PATTERN);
1989
2036
  return m ? m[1].toLowerCase() : null;
1990
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
+ }
1991
2047
  var FINDING_SEVERITY_LINE = /^\d+\.\s+\[([A-Z][A-Z]*)\]\s+(.+?)\s+—/gm;
1992
2048
  function extractFindingSeverities(comment) {
1993
2049
  return [...comment.matchAll(FINDING_SEVERITY_LINE)].map((m) => ({
@@ -2005,6 +2061,7 @@ function extractVerdict(comments, valuePattern, missingLabel) {
2005
2061
  rulingOrdinal: null,
2006
2062
  briefHash: null,
2007
2063
  policyDigest: null,
2064
+ baseSha: null,
2008
2065
  findingSeverities: [],
2009
2066
  danglingNote: `no ${missingLabel} verdict comment found on this PR`
2010
2067
  };
@@ -2019,6 +2076,7 @@ function extractVerdict(comments, valuePattern, missingLabel) {
2019
2076
  rulingOrdinal: null,
2020
2077
  briefHash: null,
2021
2078
  policyDigest: null,
2079
+ baseSha: null,
2022
2080
  findingSeverities: [],
2023
2081
  danglingNote: `the most recent ${missingLabel} verdict comment carries a VERDICT-shaped line outside the first-five-line read window`
2024
2082
  };
@@ -2030,6 +2088,7 @@ function extractVerdict(comments, valuePattern, missingLabel) {
2030
2088
  rulingOrdinal: extractRulingOrdinal(latest),
2031
2089
  briefHash: extractBriefHash(latest),
2032
2090
  policyDigest: extractPolicyDigest(latest),
2091
+ baseSha: extractBaseSha(latest),
2033
2092
  findingSeverities: extractFindingSeverities(latest),
2034
2093
  danglingNote: null
2035
2094
  };
@@ -3943,7 +4002,11 @@ function briefHash(brief) {
3943
4002
  `).digest("hex");
3944
4003
  }
3945
4004
  function policyDigest(policy) {
3946
- return createHash4("sha256").update(JSON.stringify({ codeReviewThreshold: policy.codeReviewThreshold, securityThreshold: policy.securityThreshold })).digest("hex");
4005
+ return createHash4("sha256").update(JSON.stringify({
4006
+ codeReviewThreshold: policy.codeReviewThreshold,
4007
+ securityThreshold: policy.securityThreshold,
4008
+ maxRounds: policy.maxRounds
4009
+ })).digest("hex");
3947
4010
  }
3948
4011
  function isBoundToHead(echoed, headSha) {
3949
4012
  if (!echoed.headSha)
@@ -3959,8 +4022,12 @@ function isBoundByPatchIdentity(echoed, headSha, patchIdOf) {
3959
4022
  return false;
3960
4023
  return judged === current;
3961
4024
  }
3962
- function isBoundToPatch(echoed, headSha, patchIdOf) {
3963
- return isBoundToHead(echoed, headSha) || isBoundByPatchIdentity(echoed, headSha, patchIdOf);
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());
3964
4031
  }
3965
4032
  function isBoundToObjectives(echoed, currentVersion) {
3966
4033
  if (currentVersion === null)
@@ -3981,14 +4048,18 @@ function isBoundToPolicy(echoed, currentDigest) {
3981
4048
  return echoed.policyDigest === currentDigest;
3982
4049
  }
3983
4050
  function compareManifest(echoed, current, patchIdOf) {
3984
- const head = isBoundToPatch(echoed, current.headSha, 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);
3985
4055
  const briefHashBound = isBoundToBriefHash(echoed, current.briefHash);
3986
4056
  const objectivesVersion2 = isBoundToObjectives(echoed, current.objectivesVersion);
3987
4057
  const rulingOrdinal = isBoundToRulings(echoed, current.rulingOrdinal);
3988
4058
  const policyDigestBound = isBoundToPolicy(echoed, current.policyDigest);
3989
4059
  return {
3990
- bound: head && briefHashBound && objectivesVersion2 && rulingOrdinal && policyDigestBound,
4060
+ bound: head && base && briefHashBound && objectivesVersion2 && rulingOrdinal && policyDigestBound,
3991
4061
  head,
4062
+ base,
3992
4063
  briefHash: briefHashBound,
3993
4064
  objectivesVersion: objectivesVersion2,
3994
4065
  rulingOrdinal,
@@ -4040,6 +4111,7 @@ function checkReviewGate(input) {
4040
4111
  const securityClean = securityTextClean && securityPolicyClean;
4041
4112
  const currentManifest = {
4042
4113
  headSha: input.headSha,
4114
+ baseSha: input.baseSha ?? null,
4043
4115
  briefHash: input.briefHash ?? null,
4044
4116
  objectivesVersion: input.objectivesVersion,
4045
4117
  rulingOrdinal: input.rulingOrdinal,
@@ -4047,6 +4119,7 @@ function checkReviewGate(input) {
4047
4119
  };
4048
4120
  const codeReviewEchoed = {
4049
4121
  headSha: codeReview.headSha,
4122
+ baseSha: codeReview.baseSha,
4050
4123
  briefHash: codeReview.briefHash,
4051
4124
  objectivesVersion: codeReview.objectivesVersion,
4052
4125
  rulingOrdinal: codeReview.rulingOrdinal,
@@ -4054,6 +4127,7 @@ function checkReviewGate(input) {
4054
4127
  };
4055
4128
  const securityEchoed = {
4056
4129
  headSha: security.headSha,
4130
+ baseSha: security.baseSha,
4057
4131
  briefHash: security.briefHash,
4058
4132
  objectivesVersion: security.objectivesVersion,
4059
4133
  rulingOrdinal: security.rulingOrdinal,
@@ -4081,6 +4155,8 @@ function checkReviewGate(input) {
4081
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`);
4082
4156
  } else if (!codeReviewBound) {
4083
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)`);
4084
4160
  } else if (!codeReviewObjectivesBound) {
4085
4161
  problems.push(`the newest code-review verdict was cast against objectives version ${codeReview.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
4086
4162
  } else if (!codeReviewRulingsBound) {
@@ -4096,6 +4172,8 @@ function checkReviewGate(input) {
4096
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`);
4097
4173
  } else if (!securityBound) {
4098
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)`);
4099
4177
  } else if (!securityObjectivesBound) {
4100
4178
  problems.push(`the newest security-review verdict was cast against objectives version ${security.objectivesVersion ?? "none"}, the Issue's list is now ${input.objectivesVersion}`);
4101
4179
  } else if (!securityRulingsBound) {
@@ -4953,8 +5031,8 @@ var TaskToolErrorSchema = z.object({
4953
5031
  detail: z.string().optional()
4954
5032
  });
4955
5033
  var TaskToolRefSchema = z.union([
4956
- z.object({ tranche: z.string().min(1), id: z.string().min(1) }),
4957
- z.object({ issue: z.number().int().positive() })
5034
+ z.object({ tranche: z.string().min(1), id: z.string().min(1) }).strict(),
5035
+ z.object({ issue: z.number().int().positive() }).strict()
4958
5036
  ]);
4959
5037
  var MAX_PAGE_LIMIT = 100;
4960
5038
  var PageRequestSchema = z.object({
@@ -4968,7 +5046,7 @@ var ObservedSchema = z.object({
4968
5046
  });
4969
5047
  var TaskStatusInputSchema = z.object({
4970
5048
  task: TaskToolRefSchema.optional()
4971
- }).merge(PageRequestSchema);
5049
+ }).merge(PageRequestSchema).strict();
4972
5050
  var TaskStatusItemSchema = z.object({
4973
5051
  task: TaskToolRefSchema,
4974
5052
  issue: z.number().int().positive(),
@@ -4992,9 +5070,20 @@ var EscalationEvidenceSchema = z.object({
4992
5070
  reviewer: z.string().nullable(),
4993
5071
  security: z.string().nullable()
4994
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
+ });
4995
5084
  var TaskEscalationReadInputSchema = z.object({
4996
5085
  task: TaskToolRefSchema
4997
- }).merge(PageRequestSchema);
5086
+ }).merge(PageRequestSchema).strict();
4998
5087
  var TaskEscalationPacketSchema = z.object({
4999
5088
  reason: z.string(),
5000
5089
  detail: z.string().nullable(),
@@ -5002,7 +5091,9 @@ var TaskEscalationPacketSchema = z.object({
5002
5091
  evidence: EscalationEvidenceSchema.nullable(),
5003
5092
  attemptedRecovery: z.string(),
5004
5093
  requestedAuthority: RequestedAuthoritySchema,
5005
- permittedNextActions: z.array(z.string())
5094
+ permittedNextActions: z.array(z.string()),
5095
+ runIdentity: EscalationRunIdentitySchema.nullable(),
5096
+ inputVersions: EscalationInputVersionsSchema.nullable()
5006
5097
  }).merge(ObservedSchema);
5007
5098
  var TaskEscalationReadResultSchema = z.object({
5008
5099
  items: z.array(TaskEscalationPacketSchema),
@@ -5011,15 +5102,48 @@ var TaskEscalationReadResultSchema = z.object({
5011
5102
  var TaskStartInputSchema = z.object({
5012
5103
  tranche: z.string().min(1),
5013
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")
5014
5112
  });
5015
5113
  var TaskResumeInputSchema = z.object({
5016
5114
  task: TaskToolRefSchema
5017
- });
5115
+ }).strict();
5018
5116
  var TaskCancelInputSchema = z.object({
5019
5117
  task: TaskToolRefSchema,
5020
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())
5021
5137
  });
5022
- var NoResultSchema = z.never();
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];
5023
5147
  // ../../packages/aeg-core/src/first-push-dispatch-gate.ts
5024
5148
  function parseTaskBranch(branch) {
5025
5149
  const m = /^task\/([^/]+)\/([^/]+)$/.exec(branch);
@@ -5242,6 +5366,9 @@ function findWorkspaceEscapes(files, knownPaths, workspaceDirs = DEFAULT_WORKSPA
5242
5366
  }
5243
5367
  return findings;
5244
5368
  }
5369
+ // ../../packages/aeg-core/src/log/envelope.ts
5370
+ import { createHash as createHash5 } from "node:crypto";
5371
+
5245
5372
  // ../../packages/aeg-core/src/log/schema.ts
5246
5373
  import { z as z2 } from "zod";
5247
5374
  var ROLE_VALUES = [
@@ -5343,7 +5470,8 @@ var DispatchOutcomeSchema = z2.discriminatedUnion("type", [
5343
5470
  }).strict(),
5344
5471
  z2.object({ type: z2.literal("brief"), comment_id: z2.number().int(), hash: z2.string() }).strict(),
5345
5472
  z2.object({ type: z2.literal("plan"), issues: z2.array(z2.number().int()) }).strict(),
5346
- z2.object({ type: z2.literal("archive"), provenance_comment_id: 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()
5347
5475
  ]);
5348
5476
  var dispatchShared = {
5349
5477
  meta: HeaderMetaSchema,
@@ -5403,7 +5531,8 @@ var DevReviewLoopEventSchema = z2.discriminatedUnion("event", [
5403
5531
  round: z2.number().int(),
5404
5532
  head: z2.string(),
5405
5533
  all_approve: z2.boolean(),
5406
- blockers: z2.number().int().nonnegative()
5534
+ blockers: z2.number().int().nonnegative(),
5535
+ findings: z2.array(ReviewFindingSchema).optional()
5407
5536
  }).strict(),
5408
5537
  z2.object({
5409
5538
  ...loopShared,
@@ -5582,7 +5711,9 @@ var roleAttemptShared = {
5582
5711
  kind: z2.literal("role_attempt"),
5583
5712
  ...envelopeTail,
5584
5713
  actor: z2.string().nullable(),
5585
- attempt: z2.number().int().nullable()
5714
+ attempt: z2.number().int().nullable(),
5715
+ effect_id: z2.string(),
5716
+ model: z2.string().nullable()
5586
5717
  };
5587
5718
  var RoleAttemptEventSchema = z2.discriminatedUnion("event", [
5588
5719
  z2.object({
@@ -5641,6 +5772,144 @@ var LogEventSchema = z2.union([
5641
5772
  HandoffEventSchema,
5642
5773
  EffectEventSchema
5643
5774
  ]);
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;
5644
5913
  // ../../packages/aeg-core/src/dev-review-loop/journal-reconstruction.ts
5645
5914
  var STOPPED_CONDITIONS = new Set(["confidence", "reappearance", "no_progress", "max_rounds"]);
5646
5915
  // ../../packages/aeg-core/src/control-store/records.ts
@@ -5655,7 +5924,9 @@ var RunRecordSchema = z3.object({
5655
5924
  runId: z3.string().min(1),
5656
5925
  pid: z3.number().int().positive(),
5657
5926
  host: z3.string().min(1),
5658
- startedAt: isoTimestamp
5927
+ startedAt: isoTimestamp,
5928
+ childStartedAt: z3.string().min(1).nullable().optional(),
5929
+ childCommand: z3.string().min(1).nullable().optional()
5659
5930
  }).strict();
5660
5931
  var InputRecordSchema = z3.object({
5661
5932
  version: z3.literal(1),
@@ -5688,6 +5959,88 @@ var TransitionRecordSchema = z3.object({
5688
5959
  detail: z3.string().optional(),
5689
5960
  at: isoTimestamp
5690
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();
5691
6044
  // src/checks/contract.ts
5692
6045
  var CHECK_SCHEMA_VERSION = 1;
5693
6046
  function emitCheckError(error) {
@@ -5885,6 +6238,16 @@ var COMMANDS = [
5885
6238
  ],
5886
6239
  status: "shipped"
5887
6240
  },
6241
+ {
6242
+ name: "task-tools serve",
6243
+ description: "Run the task-operator MCP tool server over stdio — the command both runtime adapters register",
6244
+ details: [
6245
+ "Exposes the task-operator tool catalog (`packages/aeg-core/src/task-tools.ts`) to an agent runtime as one MCP server speaking newline-delimited JSON-RPC 2.0 (`initialize`/`tools/list`/`tools/call`). Claude registers it through the generated `.mcp.json`; Codex through its documented `~/.codex/config.toml` `[mcp_servers]` table — both point at this same command.",
6246
+ "stdout carries JSON-RPC and nothing else: any stray write from the CLI (a forge-read warning) is redirected to stderr, so the protocol stream is never corrupted.",
6247
+ "`task_status`/`task_escalation_read` read; `task_start` starts a run in attended mode only, requiring an authenticated caller from the invocation context (`VINAYA_MCP_CALLER`) and refusing without one — MCP is a transport, not authorization. `task_resume`/`task_cancel` require the same authenticated caller, plus a current Principal ruling read fresh from the run's own PR — never a caller-supplied approval; `task_resume` triggers the existing `dev-review-loop --resume` continuation exactly once per escalation, and `task_cancel` reports a truthful `confirmed`/`pending`/`uncertain` outcome, idempotently, across repeated calls. No unattended start until the worker-isolation boundary and a capability flag land."
6248
+ ],
6249
+ status: "shipped"
6250
+ },
5888
6251
  {
5889
6252
  name: "pr create",
5890
6253
  description: "Open a pull request after full brief-schema validation",
@@ -6029,6 +6392,30 @@ var COMMANDS = [
6029
6392
  ],
6030
6393
  status: "shipped"
6031
6394
  },
6395
+ {
6396
+ name: "log export-artifact",
6397
+ description: "Copy this run's own local outbox into a file, for the generated task-path workflow's own upload step",
6398
+ flags: [],
6399
+ details: [
6400
+ "Concatenates every `*.ndjson` file under `~/.vinaya/outbox/` into `<dest>`, verbatim — no filtering, no second redaction pass (lines are already redacted at `log()`'s own write boundary). Writes nothing when the outbox is empty, and exits 0 either way: no gate events this run is a legitimate outcome, never a failure.",
6401
+ "Runs inside the generated `vinaya-checks.yml` job, which holds no forge-write credential — this command never calls the forge. Both this step and the `actions/upload-artifact` step after it run `if: always()`, so a cancelled or failed job still exports whatever partial outbox it has."
6402
+ ],
6403
+ status: "shipped"
6404
+ },
6405
+ {
6406
+ name: "log collect-artifact",
6407
+ description: "Validate a downloaded task-log artifact and publish the valid records through the existing flush path",
6408
+ flags: [
6409
+ { flag: "--pr", description: "The pull request this artifact belongs to" },
6410
+ { flag: "--repo", description: "Expected `owner/repo` — a provenance cross-check against each record" }
6411
+ ],
6412
+ details: [
6413
+ "Runs inside the generated `vinaya-task-log-collector.yml` workflow — a `workflow_run`-triggered job on the default branch, holding the write credential the task-path job that produced the artifact never gets. `<path>` is already downloaded by that workflow, scoped to a specific, API-verified run id — a provenance guarantee this command never re-derives from the artifact bytes.",
6414
+ "Never executes, imports, or evaluates the artifact's content: every line is read as text and validated (schema, an 8 MiB whole-artifact size cap, redaction, and a repo cross-check) before anything is trusted. A rejected line becomes a named gap — printed, never a silent drop — and the artifact is never partially trusted past that check into executing anything.",
6415
+ "The valid, re-redacted survivors are appended into the same local outbox `vinaya log flush` would read for that PR's Issue, then published through the existing `flushOutbox` unmodified — reusing its chunking, its `<!-- aeg:log:… -->` marker, and its idempotent-retry read, rather than a second publisher. A retried collector run (a fresh runner, the same forge state) therefore dedupes for free: the marker already on the forge is acknowledged, never re-posted."
6416
+ ],
6417
+ status: "shipped"
6418
+ },
6032
6419
  {
6033
6420
  name: "milestone create",
6034
6421
  description: "Create a GitHub Milestone from a validated body",
@@ -6697,6 +7084,13 @@ var VinayaConfigSchema = z5.object({
6697
7084
  message: "must be at most 3600000 (1 hour)"
6698
7085
  });
6699
7086
  }
7087
+ }).optional(),
7088
+ logPublish: z5.object({
7089
+ issue: z5.number().int().positive().optional(),
7090
+ pr: z5.number().int().positive().optional(),
7091
+ maxChunksPerFlush: z5.number().int().positive().optional()
7092
+ }).refine((v) => !(v.issue !== undefined && v.pr !== undefined), {
7093
+ message: "logPublish: set at most one of issue/pr, not both"
6700
7094
  }).optional()
6701
7095
  });
6702
7096
  var GLOBAL_VINAYA_HOME = join(homedir(), ".vinaya");