@loopover/engine 1.0.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 (272) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/LICENSE +661 -0
  3. package/README.md +676 -0
  4. package/dist/advisory/gate-advisory.d.ts +151 -0
  5. package/dist/advisory/gate-advisory.js +512 -0
  6. package/dist/ai-policy-map.d.ts +97 -0
  7. package/dist/ai-policy-map.js +377 -0
  8. package/dist/ams-policy-spec.d.ts +56 -0
  9. package/dist/ams-policy-spec.js +165 -0
  10. package/dist/calibration-dashboard.d.ts +23 -0
  11. package/dist/calibration-dashboard.js +65 -0
  12. package/dist/calibration-trend.d.ts +40 -0
  13. package/dist/calibration-trend.js +60 -0
  14. package/dist/contributor-fit.d.ts +24 -0
  15. package/dist/contributor-fit.js +50 -0
  16. package/dist/discovery-index-contract.d.ts +74 -0
  17. package/dist/discovery-index-contract.js +184 -0
  18. package/dist/discovery-soft-claim.d.ts +35 -0
  19. package/dist/discovery-soft-claim.js +50 -0
  20. package/dist/duplicate-winner.d.ts +57 -0
  21. package/dist/duplicate-winner.js +98 -0
  22. package/dist/feasibility.d.ts +27 -0
  23. package/dist/feasibility.js +86 -0
  24. package/dist/finding-severity-calibration.d.ts +116 -0
  25. package/dist/finding-severity-calibration.js +457 -0
  26. package/dist/fleet-run-manifest.d.ts +41 -0
  27. package/dist/fleet-run-manifest.js +151 -0
  28. package/dist/focus-manifest/guidance.d.ts +21 -0
  29. package/dist/focus-manifest/guidance.js +222 -0
  30. package/dist/focus-manifest.d.ts +826 -0
  31. package/dist/focus-manifest.js +2730 -0
  32. package/dist/gate-verdict-calibration.d.ts +111 -0
  33. package/dist/gate-verdict-calibration.js +411 -0
  34. package/dist/github/constants.d.ts +1 -0
  35. package/dist/github/constants.js +1 -0
  36. package/dist/github/sanitize-public-comment.d.ts +1 -0
  37. package/dist/github/sanitize-public-comment.js +26 -0
  38. package/dist/goal-model.d.ts +7 -0
  39. package/dist/goal-model.js +87 -0
  40. package/dist/governor/action-mode.d.ts +55 -0
  41. package/dist/governor/action-mode.js +74 -0
  42. package/dist/governor/budget-cap.d.ts +49 -0
  43. package/dist/governor/budget-cap.js +34 -0
  44. package/dist/governor/chokepoint.d.ts +58 -0
  45. package/dist/governor/chokepoint.js +269 -0
  46. package/dist/governor/kill-switch.d.ts +38 -0
  47. package/dist/governor/kill-switch.js +62 -0
  48. package/dist/governor/rate-limit.d.ts +40 -0
  49. package/dist/governor/rate-limit.js +63 -0
  50. package/dist/governor/reputation-throttle.d.ts +50 -0
  51. package/dist/governor/reputation-throttle.js +94 -0
  52. package/dist/governor/run-halt.d.ts +39 -0
  53. package/dist/governor/run-halt.js +83 -0
  54. package/dist/governor/self-plagiarism.d.ts +47 -0
  55. package/dist/governor/self-plagiarism.js +200 -0
  56. package/dist/governor/write-rate-limit.d.ts +52 -0
  57. package/dist/governor/write-rate-limit.js +132 -0
  58. package/dist/governor-ledger.d.ts +25 -0
  59. package/dist/governor-ledger.js +91 -0
  60. package/dist/index.d.ts +99 -0
  61. package/dist/index.js +120 -0
  62. package/dist/issue-plan-decomposition.d.ts +18 -0
  63. package/dist/issue-plan-decomposition.js +56 -0
  64. package/dist/issue-rag-query.d.ts +12 -0
  65. package/dist/issue-rag-query.js +35 -0
  66. package/dist/local-scorer.d.ts +34 -0
  67. package/dist/local-scorer.js +36 -0
  68. package/dist/metadata-best-min-score.d.ts +9 -0
  69. package/dist/metadata-best-min-score.js +9 -0
  70. package/dist/metadata-best-pick.d.ts +9 -0
  71. package/dist/metadata-best-pick.js +9 -0
  72. package/dist/metadata-min-score.d.ts +9 -0
  73. package/dist/metadata-min-score.js +13 -0
  74. package/dist/metadata-top-min-score.d.ts +9 -0
  75. package/dist/metadata-top-min-score.js +13 -0
  76. package/dist/metadata-top-pick.d.ts +9 -0
  77. package/dist/metadata-top-pick.js +13 -0
  78. package/dist/miner/acceptance-criteria.d.ts +43 -0
  79. package/dist/miner/acceptance-criteria.js +77 -0
  80. package/dist/miner/agent-sdk-driver.d.ts +39 -0
  81. package/dist/miner/agent-sdk-driver.js +162 -0
  82. package/dist/miner/attempt-log.d.ts +29 -0
  83. package/dist/miner/attempt-log.js +100 -0
  84. package/dist/miner/attempt-metering.d.ts +39 -0
  85. package/dist/miner/attempt-metering.js +67 -0
  86. package/dist/miner/cli-subprocess-driver.d.ts +68 -0
  87. package/dist/miner/cli-subprocess-driver.js +272 -0
  88. package/dist/miner/coding-agent-driver.d.ts +33 -0
  89. package/dist/miner/coding-agent-driver.js +36 -0
  90. package/dist/miner/coding-agent-invoke.d.ts +11 -0
  91. package/dist/miner/coding-agent-invoke.js +80 -0
  92. package/dist/miner/coding-agent-mode.d.ts +25 -0
  93. package/dist/miner/coding-agent-mode.js +43 -0
  94. package/dist/miner/driver-factory.d.ts +82 -0
  95. package/dist/miner/driver-factory.js +169 -0
  96. package/dist/miner/harness-submission-trigger.d.ts +37 -0
  97. package/dist/miner/harness-submission-trigger.js +46 -0
  98. package/dist/miner/iterate-loop.d.ts +97 -0
  99. package/dist/miner/iterate-loop.js +278 -0
  100. package/dist/miner/iterate-policy.d.ts +98 -0
  101. package/dist/miner/iterate-policy.js +98 -0
  102. package/dist/miner/lint-guard.d.ts +50 -0
  103. package/dist/miner/lint-guard.js +68 -0
  104. package/dist/miner/local-write-tools.d.ts +81 -0
  105. package/dist/miner/local-write-tools.js +113 -0
  106. package/dist/miner/loop-reentry-policy.d.ts +36 -0
  107. package/dist/miner/loop-reentry-policy.js +53 -0
  108. package/dist/miner/repo-map.d.ts +51 -0
  109. package/dist/miner/repo-map.js +268 -0
  110. package/dist/miner/self-review-adapter.d.ts +106 -0
  111. package/dist/miner/self-review-adapter.js +83 -0
  112. package/dist/miner/submission-gate.d.ts +40 -0
  113. package/dist/miner/submission-gate.js +89 -0
  114. package/dist/miner/worktree-allocator.d.ts +59 -0
  115. package/dist/miner/worktree-allocator.js +60 -0
  116. package/dist/miner/worktree-pool.d.ts +55 -0
  117. package/dist/miner/worktree-pool.js +65 -0
  118. package/dist/miner-goal-lane-fit.d.ts +18 -0
  119. package/dist/miner-goal-lane-fit.js +76 -0
  120. package/dist/miner-goal-spec.d.ts +139 -0
  121. package/dist/miner-goal-spec.js +281 -0
  122. package/dist/miner-prediction-metrics.d.ts +16 -0
  123. package/dist/miner-prediction-metrics.js +61 -0
  124. package/dist/miner-telemetry.d.ts +32 -0
  125. package/dist/miner-telemetry.js +87 -0
  126. package/dist/objective-anchor.d.ts +125 -0
  127. package/dist/objective-anchor.js +401 -0
  128. package/dist/opportunity-competition.d.ts +6 -0
  129. package/dist/opportunity-competition.js +29 -0
  130. package/dist/opportunity-freshness.d.ts +18 -0
  131. package/dist/opportunity-freshness.js +55 -0
  132. package/dist/opportunity-metadata.d.ts +53 -0
  133. package/dist/opportunity-metadata.js +204 -0
  134. package/dist/opportunity-ranker.d.ts +46 -0
  135. package/dist/opportunity-ranker.js +74 -0
  136. package/dist/pairwise-calibration.d.ts +49 -0
  137. package/dist/pairwise-calibration.js +106 -0
  138. package/dist/phase7-calibration-loop.d.ts +136 -0
  139. package/dist/phase7-calibration-loop.js +437 -0
  140. package/dist/plan-blocked.d.ts +6 -0
  141. package/dist/plan-blocked.js +24 -0
  142. package/dist/plan-completed.d.ts +5 -0
  143. package/dist/plan-completed.js +6 -0
  144. package/dist/plan-completion.d.ts +6 -0
  145. package/dist/plan-completion.js +7 -0
  146. package/dist/plan-empty.d.ts +5 -0
  147. package/dist/plan-empty.js +6 -0
  148. package/dist/plan-export.d.ts +27 -0
  149. package/dist/plan-export.js +86 -0
  150. package/dist/plan-failure.d.ts +5 -0
  151. package/dist/plan-failure.js +6 -0
  152. package/dist/plan-overall-status.d.ts +6 -0
  153. package/dist/plan-overall-status.js +25 -0
  154. package/dist/plan-pending.d.ts +5 -0
  155. package/dist/plan-pending.js +6 -0
  156. package/dist/plan-progress-complete.d.ts +7 -0
  157. package/dist/plan-progress-complete.js +10 -0
  158. package/dist/plan-ready.d.ts +6 -0
  159. package/dist/plan-ready.js +12 -0
  160. package/dist/plan-running.d.ts +5 -0
  161. package/dist/plan-running.js +6 -0
  162. package/dist/plan-skipped.d.ts +5 -0
  163. package/dist/plan-skipped.js +6 -0
  164. package/dist/plan-step-count.d.ts +5 -0
  165. package/dist/plan-step-count.js +6 -0
  166. package/dist/plan-step-stats.d.ts +5 -0
  167. package/dist/plan-step-stats.js +6 -0
  168. package/dist/plan-templates.d.ts +25 -0
  169. package/dist/plan-templates.js +107 -0
  170. package/dist/plan-terminated.d.ts +6 -0
  171. package/dist/plan-terminated.js +9 -0
  172. package/dist/portfolio/non-convergence.d.ts +37 -0
  173. package/dist/portfolio/non-convergence.js +57 -0
  174. package/dist/portfolio/queue.d.ts +30 -0
  175. package/dist/portfolio/queue.js +150 -0
  176. package/dist/predicted-gate.d.ts +103 -0
  177. package/dist/predicted-gate.js +218 -0
  178. package/dist/prompt-packet.d.ts +11 -0
  179. package/dist/prompt-packet.js +34 -0
  180. package/dist/ranked-opportunity-best-min-score.d.ts +8 -0
  181. package/dist/ranked-opportunity-best-min-score.js +9 -0
  182. package/dist/ranked-opportunity-best-pick.d.ts +8 -0
  183. package/dist/ranked-opportunity-best-pick.js +9 -0
  184. package/dist/ranked-opportunity-min-score.d.ts +8 -0
  185. package/dist/ranked-opportunity-min-score.js +13 -0
  186. package/dist/ranked-opportunity-top-min-score.d.ts +8 -0
  187. package/dist/ranked-opportunity-top-min-score.js +13 -0
  188. package/dist/review/advisory-ai-routing-config.d.ts +8 -0
  189. package/dist/review/advisory-ai-routing-config.js +40 -0
  190. package/dist/review/check-names.d.ts +1 -0
  191. package/dist/review/check-names.js +1 -0
  192. package/dist/review/cla-check.d.ts +49 -0
  193. package/dist/review/cla-check.js +71 -0
  194. package/dist/review/diff-file-priority.d.ts +1 -0
  195. package/dist/review/diff-file-priority.js +12 -0
  196. package/dist/review/enrichment-analyzer-names.d.ts +3 -0
  197. package/dist/review/enrichment-analyzer-names.js +63 -0
  198. package/dist/review/guardrail-config.d.ts +10 -0
  199. package/dist/review/guardrail-config.js +62 -0
  200. package/dist/review/linked-issue-hard-rules-config.d.ts +4 -0
  201. package/dist/review/linked-issue-hard-rules-config.js +79 -0
  202. package/dist/review/linked-issue-label-propagation.d.ts +9 -0
  203. package/dist/review/linked-issue-label-propagation.js +114 -0
  204. package/dist/review/pre-merge-checks.d.ts +28 -0
  205. package/dist/review/pre-merge-checks.js +66 -0
  206. package/dist/review/review-thread-findings.d.ts +1 -0
  207. package/dist/review/review-thread-findings.js +1 -0
  208. package/dist/review/safe-url.d.ts +5 -0
  209. package/dist/review/safe-url.js +137 -0
  210. package/dist/review/screenshot-table-gate.d.ts +87 -0
  211. package/dist/review/screenshot-table-gate.js +340 -0
  212. package/dist/review/unlinked-issue-guardrail-config.d.ts +9 -0
  213. package/dist/review/unlinked-issue-guardrail-config.js +44 -0
  214. package/dist/reviewer-consensus-calibration.d.ts +113 -0
  215. package/dist/reviewer-consensus-calibration.js +493 -0
  216. package/dist/reward-risk.d.ts +223 -0
  217. package/dist/reward-risk.js +618 -0
  218. package/dist/scoring/label-match.d.ts +4 -0
  219. package/dist/scoring/label-match.js +145 -0
  220. package/dist/scoring/model.d.ts +31 -0
  221. package/dist/scoring/model.js +157 -0
  222. package/dist/scoring/pending-pr-scenarios.d.ts +44 -0
  223. package/dist/scoring/pending-pr-scenarios.js +145 -0
  224. package/dist/scoring/preview.d.ts +246 -0
  225. package/dist/scoring/preview.js +1108 -0
  226. package/dist/scoring/types.d.ts +131 -0
  227. package/dist/scoring/types.js +7 -0
  228. package/dist/settings/auto-close-exempt.d.ts +10 -0
  229. package/dist/settings/auto-close-exempt.js +58 -0
  230. package/dist/settings/autonomy.d.ts +33 -0
  231. package/dist/settings/autonomy.js +80 -0
  232. package/dist/settings/command-authorization.d.ts +49 -0
  233. package/dist/settings/command-authorization.js +222 -0
  234. package/dist/settings/contributor-blacklist.d.ts +17 -0
  235. package/dist/settings/contributor-blacklist.js +86 -0
  236. package/dist/settings/moderation-rules.d.ts +51 -0
  237. package/dist/settings/moderation-rules.js +104 -0
  238. package/dist/settings/pr-type-label.d.ts +70 -0
  239. package/dist/settings/pr-type-label.js +149 -0
  240. package/dist/signals/change-guardrail.d.ts +49 -0
  241. package/dist/signals/change-guardrail.js +164 -0
  242. package/dist/signals/check-summary.d.ts +9 -0
  243. package/dist/signals/check-summary.js +12 -0
  244. package/dist/signals/contributor-calibration.d.ts +23 -0
  245. package/dist/signals/contributor-calibration.js +47 -0
  246. package/dist/signals/duplicate-winner.d.ts +9 -0
  247. package/dist/signals/duplicate-winner.js +9 -0
  248. package/dist/signals/path-matchers.d.ts +36 -0
  249. package/dist/signals/path-matchers.js +371 -0
  250. package/dist/signals/predicted-gate-engine.d.ts +62 -0
  251. package/dist/signals/predicted-gate-engine.js +895 -0
  252. package/dist/signals/preflight-limits.d.ts +14 -0
  253. package/dist/signals/preflight-limits.js +14 -0
  254. package/dist/signals/slop.d.ts +56 -0
  255. package/dist/signals/slop.js +324 -0
  256. package/dist/signals/test-evidence.d.ts +25 -0
  257. package/dist/signals/test-evidence.js +108 -0
  258. package/dist/subprocess-env.d.ts +23 -0
  259. package/dist/subprocess-env.js +74 -0
  260. package/dist/track-record-summary.d.ts +92 -0
  261. package/dist/track-record-summary.js +301 -0
  262. package/dist/types/manifest-deps-types.d.ts +514 -0
  263. package/dist/types/manifest-deps-types.js +4 -0
  264. package/dist/types/predicted-gate-types.d.ts +338 -0
  265. package/dist/types/predicted-gate-types.js +3 -0
  266. package/dist/types/reward-risk-types.d.ts +319 -0
  267. package/dist/types/reward-risk-types.js +11 -0
  268. package/dist/utils/json.d.ts +1 -0
  269. package/dist/utils/json.js +3 -0
  270. package/dist/version.d.ts +2 -0
  271. package/dist/version.js +3 -0
  272. package/package.json +80 -0
@@ -0,0 +1,52 @@
1
+ import type { GovernorLedgerEvent } from "../governor-ledger.js";
2
+ import { type LocalRateBucket, type LocalRateLimitConfig, type LocalRateLimitDecision } from "./rate-limit.js";
3
+ /** Conservative jitter base when a write is over-limit (not hard-coded at call sites). */
4
+ export declare const DEFAULT_WRITE_RATE_LIMIT_BACKOFF_BASE_MS = 1000;
5
+ export type WriteRateLimitPolicies = {
6
+ /** Per actionClass global ceiling across all repos. */
7
+ global: Readonly<Record<string, LocalRateLimitConfig>>;
8
+ /** Per actionClass per-repo ceiling. */
9
+ perRepo: Readonly<Record<string, LocalRateLimitConfig>>;
10
+ /** Jitter backoff base when a write is rate-limited. */
11
+ backoffBaseMs: number;
12
+ };
13
+ export declare const DEFAULT_WRITE_RATE_LIMIT_POLICIES: Readonly<WriteRateLimitPolicies>;
14
+ export type WriteRateLimitBucketStore = {
15
+ global: Record<string, LocalRateBucket>;
16
+ perRepo: Record<string, LocalRateBucket>;
17
+ };
18
+ /** Burst-attempt counter keyed by `${actionClass}:${repo}` for jittered backoff growth. */
19
+ export type WriteRateLimitBackoffStore = Record<string, number>;
20
+ export type WriteRateLimitBlockedBy = "global" | "per_repo";
21
+ export type WriteRateLimitVerdict = {
22
+ allowed: boolean;
23
+ blockedBy: WriteRateLimitBlockedBy | null;
24
+ global: LocalRateLimitDecision;
25
+ perRepo: LocalRateLimitDecision;
26
+ /** When blocked: milliseconds until the caller should retry (window wait ∪ jittered backoff). */
27
+ retryAfterMs: number;
28
+ backoffAttempt: number;
29
+ reason: string;
30
+ };
31
+ export declare function writeRateLimitRepoKey(actionClass: string, repoFullName: string): string;
32
+ /**
33
+ * Consult global and per-repo rolling-window buckets before a governor write. Both must permit the event;
34
+ * a repo under its own limit can still be blocked by the global ceiling.
35
+ */
36
+ export declare function evaluateWriteRateLimit(input: {
37
+ actionClass: string;
38
+ repoFullName: string;
39
+ buckets: WriteRateLimitBucketStore;
40
+ backoffAttempts: WriteRateLimitBackoffStore;
41
+ policies?: WriteRateLimitPolicies;
42
+ nowMs: number;
43
+ randomFn?: () => number;
44
+ }): WriteRateLimitVerdict;
45
+ /** Record a permitted write against both bucket scopes. */
46
+ export declare function recordWriteRateLimitAllowed(buckets: WriteRateLimitBucketStore, actionClass: string, repoFullName: string, nowMs: number, policies?: WriteRateLimitPolicies): WriteRateLimitBucketStore;
47
+ /** Bump the jitter backoff attempt after a throttled write (does not mutate rate buckets). */
48
+ export declare function recordWriteRateLimitDenied(backoffAttempts: WriteRateLimitBackoffStore, actionClass: string, repoFullName: string): WriteRateLimitBackoffStore;
49
+ /** Clear backoff attempts after a successful write. */
50
+ export declare function clearWriteRateLimitBackoff(backoffAttempts: WriteRateLimitBackoffStore, actionClass: string, repoFullName: string): WriteRateLimitBackoffStore;
51
+ /** Governor-ledger row for a write-rate-limit decision (#2344 deliverable). */
52
+ export declare function buildWriteRateLimitGovernorLedgerEvent(repoFullName: string, actionClass: string, verdict: WriteRateLimitVerdict): GovernorLedgerEvent;
@@ -0,0 +1,132 @@
1
+ // Governor write-rate-limit enforcement (#2344): composes the pure `evaluateLocalRateLimit` calculator with
2
+ // global + per-repo buckets and jittered retry scheduling for the local Governor chokepoint. Maintains bucket
3
+ // math only — callers own persistence/scheduling; this module returns updated in-memory state snapshots.
4
+ import { evaluateLocalRateLimit, jitteredBackoffMs, } from "./rate-limit.js";
5
+ /** Conservative jitter base when a write is over-limit (not hard-coded at call sites). */
6
+ export const DEFAULT_WRITE_RATE_LIMIT_BACKOFF_BASE_MS = 1_000;
7
+ const PERMISSIVE_CONFIG = Object.freeze({
8
+ limit: 1_000_000,
9
+ windowMs: 60_000,
10
+ });
11
+ export const DEFAULT_WRITE_RATE_LIMIT_POLICIES = Object.freeze({
12
+ global: Object.freeze({
13
+ open_pr: Object.freeze({ limit: 30, windowMs: 60_000 }),
14
+ comment: Object.freeze({ limit: 60, windowMs: 60_000 }),
15
+ }),
16
+ perRepo: Object.freeze({
17
+ open_pr: Object.freeze({ limit: 3, windowMs: 60_000 }),
18
+ comment: Object.freeze({ limit: 10, windowMs: 60_000 }),
19
+ }),
20
+ backoffBaseMs: DEFAULT_WRITE_RATE_LIMIT_BACKOFF_BASE_MS,
21
+ });
22
+ export function writeRateLimitRepoKey(actionClass, repoFullName) {
23
+ return `${actionClass.trim()}:${repoFullName.trim().toLowerCase()}`;
24
+ }
25
+ function policyFor(policies, actionClass, scope) {
26
+ const table = scope === "global" ? policies.global : policies.perRepo;
27
+ return table[actionClass] ?? PERMISSIVE_CONFIG;
28
+ }
29
+ function emptyBucket(nowMs) {
30
+ return { count: 0, windowStartMs: nowMs };
31
+ }
32
+ function incrementBucket(bucket, config, nowMs) {
33
+ const windowMs = Number.isFinite(config.windowMs) ? Math.max(0, Math.floor(config.windowMs)) : 0;
34
+ const windowStartMs = Number.isFinite(bucket.windowStartMs) ? bucket.windowStartMs : nowMs;
35
+ const windowElapsed = nowMs - windowStartMs >= windowMs;
36
+ const effectiveCount = windowElapsed ? 0 : Math.max(0, Math.floor(bucket.count));
37
+ return {
38
+ count: effectiveCount + 1,
39
+ windowStartMs: windowElapsed ? nowMs : windowStartMs,
40
+ };
41
+ }
42
+ /**
43
+ * Consult global and per-repo rolling-window buckets before a governor write. Both must permit the event;
44
+ * a repo under its own limit can still be blocked by the global ceiling.
45
+ */
46
+ export function evaluateWriteRateLimit(input) {
47
+ const policies = input.policies ?? DEFAULT_WRITE_RATE_LIMIT_POLICIES;
48
+ const randomFn = input.randomFn ?? (() => 0.5);
49
+ const nowMs = Number.isFinite(input.nowMs) ? input.nowMs : 0;
50
+ const repoKey = writeRateLimitRepoKey(input.actionClass, input.repoFullName);
51
+ const backoffAttempt = input.backoffAttempts[repoKey] ?? 0;
52
+ const globalBucket = input.buckets.global[input.actionClass] ?? emptyBucket(nowMs);
53
+ const perRepoBucket = input.buckets.perRepo[repoKey] ?? emptyBucket(nowMs);
54
+ const globalConfig = policyFor(policies, input.actionClass, "global");
55
+ const perRepoConfig = policyFor(policies, input.actionClass, "perRepo");
56
+ const global = evaluateLocalRateLimit(globalBucket, globalConfig, nowMs);
57
+ const perRepo = evaluateLocalRateLimit(perRepoBucket, perRepoConfig, nowMs);
58
+ if (global.allowed && perRepo.allowed) {
59
+ return {
60
+ allowed: true,
61
+ blockedBy: null,
62
+ global,
63
+ perRepo,
64
+ retryAfterMs: 0,
65
+ backoffAttempt,
66
+ reason: "under_limit",
67
+ };
68
+ }
69
+ const blockedBy = global.allowed ? "per_repo" : "global";
70
+ const windowWait = Math.max(global.retryAfterMs, perRepo.retryAfterMs);
71
+ const jitterWait = jitteredBackoffMs(policies.backoffBaseMs, backoffAttempt, randomFn);
72
+ return {
73
+ allowed: false,
74
+ blockedBy,
75
+ global,
76
+ perRepo,
77
+ retryAfterMs: Math.max(windowWait, jitterWait),
78
+ backoffAttempt,
79
+ reason: blockedBy === "global" ? "global_rate_limit" : "per_repo_rate_limit",
80
+ };
81
+ }
82
+ /** Record a permitted write against both bucket scopes. */
83
+ export function recordWriteRateLimitAllowed(buckets, actionClass, repoFullName, nowMs, policies = DEFAULT_WRITE_RATE_LIMIT_POLICIES) {
84
+ const repoKey = writeRateLimitRepoKey(actionClass, repoFullName);
85
+ const globalConfig = policyFor(policies, actionClass, "global");
86
+ const perRepoConfig = policyFor(policies, actionClass, "perRepo");
87
+ const globalBucket = buckets.global[actionClass] ?? emptyBucket(nowMs);
88
+ const perRepoBucket = buckets.perRepo[repoKey] ?? emptyBucket(nowMs);
89
+ return {
90
+ global: {
91
+ ...buckets.global,
92
+ [actionClass]: incrementBucket(globalBucket, globalConfig, nowMs),
93
+ },
94
+ perRepo: {
95
+ ...buckets.perRepo,
96
+ [repoKey]: incrementBucket(perRepoBucket, perRepoConfig, nowMs),
97
+ },
98
+ };
99
+ }
100
+ /** Bump the jitter backoff attempt after a throttled write (does not mutate rate buckets). */
101
+ export function recordWriteRateLimitDenied(backoffAttempts, actionClass, repoFullName) {
102
+ const key = writeRateLimitRepoKey(actionClass, repoFullName);
103
+ return { ...backoffAttempts, [key]: (backoffAttempts[key] ?? 0) + 1 };
104
+ }
105
+ /** Clear backoff attempts after a successful write. */
106
+ export function clearWriteRateLimitBackoff(backoffAttempts, actionClass, repoFullName) {
107
+ const key = writeRateLimitRepoKey(actionClass, repoFullName);
108
+ if (!(key in backoffAttempts))
109
+ return backoffAttempts;
110
+ const next = { ...backoffAttempts };
111
+ delete next[key];
112
+ return next;
113
+ }
114
+ /** Governor-ledger row for a write-rate-limit decision (#2344 deliverable). */
115
+ export function buildWriteRateLimitGovernorLedgerEvent(repoFullName, actionClass, verdict) {
116
+ return {
117
+ eventType: verdict.allowed ? "allowed" : "throttled",
118
+ repoFullName,
119
+ actionClass,
120
+ decision: verdict.allowed ? "allow" : "throttle",
121
+ reason: verdict.reason,
122
+ payload: verdict.allowed
123
+ ? {}
124
+ : {
125
+ blockedBy: verdict.blockedBy,
126
+ retryAfterMs: verdict.retryAfterMs,
127
+ backoffAttempt: verdict.backoffAttempt,
128
+ globalResetAtMs: verdict.global.resetAtMs,
129
+ perRepoResetAtMs: verdict.perRepo.resetAtMs,
130
+ },
131
+ };
132
+ }
@@ -0,0 +1,25 @@
1
+ /** Immutable governor decision vocabulary — unknown values fail closed before insert. */
2
+ export declare const GOVERNOR_LEDGER_EVENT_TYPES: readonly ["allowed", "denied", "throttled", "kill_switch"];
3
+ export type GovernorLedgerEventType = (typeof GOVERNOR_LEDGER_EVENT_TYPES)[number];
4
+ export type GovernorLedgerEvent = {
5
+ eventType: GovernorLedgerEventType;
6
+ repoFullName?: string | null | undefined;
7
+ actionClass: string;
8
+ decision: string;
9
+ reason: string;
10
+ payload?: Record<string, unknown> | undefined;
11
+ };
12
+ export type NormalizedGovernorLedgerEvent = {
13
+ eventType: GovernorLedgerEventType;
14
+ repoFullName: string | null;
15
+ actionClass: string;
16
+ decision: string;
17
+ reason: string;
18
+ payloadJson: string;
19
+ };
20
+ /**
21
+ * Validate and normalize a governor ledger row before append-only insert. Mirrors the structured-event shape of
22
+ * `logAudit` in `src/selfhost/audit.ts`, but for local SQLite storage. This module does NOT wire into live
23
+ * governor enforcement — it only defines the storage contract other issues will write into. (#2328)
24
+ */
25
+ export declare function normalizeGovernorLedgerEvent(input: unknown): NormalizedGovernorLedgerEvent;
@@ -0,0 +1,91 @@
1
+ /** Immutable governor decision vocabulary — unknown values fail closed before insert. */
2
+ export const GOVERNOR_LEDGER_EVENT_TYPES = Object.freeze([
3
+ "allowed",
4
+ "denied",
5
+ "throttled",
6
+ "kill_switch",
7
+ ]);
8
+ const governorEventTypeSet = new Set(GOVERNOR_LEDGER_EVENT_TYPES);
9
+ /* v8 ignore start -- Normalization helpers are covered through normalizeGovernorLedgerEvent export tests. */
10
+ function normalizeRequiredString(value, code) {
11
+ if (typeof value !== "string")
12
+ throw new Error(code);
13
+ const trimmed = value.trim();
14
+ if (!trimmed)
15
+ throw new Error(code);
16
+ return trimmed;
17
+ }
18
+ function normalizeOptionalRepoFullName(repoFullName) {
19
+ if (repoFullName === undefined || repoFullName === null)
20
+ return null;
21
+ if (typeof repoFullName !== "string")
22
+ throw new Error("invalid_repo_full_name");
23
+ const [owner, repo, extra] = repoFullName.trim().split("/");
24
+ if (!owner || !repo || extra !== undefined)
25
+ throw new Error("invalid_repo_full_name");
26
+ return `${owner}/${repo}`;
27
+ }
28
+ // Structural equality between a JSON.parse() result and the plain object it was stringified from. One side is
29
+ // always JSON-safe (parsed from JSON text); this only needs to compare plain objects/arrays/primitives, not the
30
+ // full generality of node:util's isDeepStrictEqual (no Dates/RegExp/Maps/getters/symbols to worry about) — this
31
+ // package's tsconfig deliberately sets `types: []` (no Node ambient types leak into its public .d.ts surface),
32
+ // so importing "node:util" here isn't viable; a small local check avoids that entirely.
33
+ function jsonRoundTripEqual(a, b) {
34
+ if (a === b)
35
+ return true;
36
+ if (typeof a !== typeof b || a === null || b === null)
37
+ return false;
38
+ if (typeof a !== "object")
39
+ return false;
40
+ const aIsArray = Array.isArray(a);
41
+ if (aIsArray !== Array.isArray(b))
42
+ return false;
43
+ if (aIsArray) {
44
+ const bArr = b;
45
+ const aArr = a;
46
+ return aArr.length === bArr.length && aArr.every((value, index) => jsonRoundTripEqual(value, bArr[index]));
47
+ }
48
+ const aKeys = Object.keys(a);
49
+ const bRecord = b;
50
+ return aKeys.length === Object.keys(bRecord).length && aKeys.every((key) => Object.hasOwn(bRecord, key) && jsonRoundTripEqual(a[key], bRecord[key]));
51
+ }
52
+ function serializePayload(payload) {
53
+ if (payload === undefined)
54
+ return "{}";
55
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
56
+ throw new Error("invalid_payload");
57
+ }
58
+ let json;
59
+ try {
60
+ json = JSON.stringify(payload);
61
+ }
62
+ catch {
63
+ throw new Error("invalid_payload");
64
+ }
65
+ if (!jsonRoundTripEqual(JSON.parse(json), payload)) {
66
+ throw new Error("invalid_payload");
67
+ }
68
+ return json;
69
+ }
70
+ /* v8 ignore stop */
71
+ /**
72
+ * Validate and normalize a governor ledger row before append-only insert. Mirrors the structured-event shape of
73
+ * `logAudit` in `src/selfhost/audit.ts`, but for local SQLite storage. This module does NOT wire into live
74
+ * governor enforcement — it only defines the storage contract other issues will write into. (#2328)
75
+ */
76
+ export function normalizeGovernorLedgerEvent(input) {
77
+ if (!input || typeof input !== "object")
78
+ throw new Error("invalid_event");
79
+ const event = input;
80
+ const eventType = normalizeRequiredString(event.eventType, "invalid_event_type");
81
+ if (!governorEventTypeSet.has(eventType))
82
+ throw new Error("invalid_event_type");
83
+ return {
84
+ eventType: eventType,
85
+ repoFullName: normalizeOptionalRepoFullName(event.repoFullName),
86
+ actionClass: normalizeRequiredString(event.actionClass, "invalid_action_class"),
87
+ decision: normalizeRequiredString(event.decision, "invalid_decision"),
88
+ reason: normalizeRequiredString(event.reason, "invalid_reason"),
89
+ payloadJson: serializePayload(event.payload),
90
+ };
91
+ }
@@ -0,0 +1,99 @@
1
+ export { ENGINE_VERSION } from "./version.js";
2
+ export { pickTopRankedOpportunities, rankOpportunityScore, rankOpportunities, type OpportunityRankInput, } from "./opportunity-ranker.js";
3
+ export { rankOpportunitiesAtOrAboveScore } from "./ranked-opportunity-min-score.js";
4
+ export { pickTopRankedOpportunitiesAtOrAboveScore } from "./ranked-opportunity-top-min-score.js";
5
+ export { bestRankedOpportunity } from "./ranked-opportunity-best-pick.js";
6
+ export { bestRankedOpportunityAtOrAboveScore } from "./ranked-opportunity-best-min-score.js";
7
+ export { extractObjectiveAnchorHistory, extractObjectiveAnchorFeatures, scoreObjectiveAnchor, scoreObjectiveAnchorHistory, renderObjectiveAnchorAuditMarkdown, type ObjectiveAnchorAudit, type ObjectiveAnchorChangeKind, type ObjectiveAnchorDimensionScores, type ObjectiveAnchorFeatures, type ObjectiveAnchorHistoryExtraction, type ObjectiveAnchorHistoryItem, type ObjectiveAnchorHistoryItemAudit, type ObjectiveAnchorHistoryScore, type ObjectiveAnchorInput, type ObjectiveAnchorScore, type ObjectiveAnchorWeights, } from "./objective-anchor.js";
8
+ export { computePairwiseCalibrationScore, resolvePairwiseCalibrationSample, type PairwiseCalibrationAttempt, type PairwiseCalibrationResolvedSample, type PairwiseCalibrationScore, type PairwiseCalibrationVerdict, type PairwiseCalibrationWeights, } from "./pairwise-calibration.js";
9
+ export { computeGateVerdictCompositeCalibrationScore, ingestGateVerdictCalibrationSignals, renderGateVerdictCalibrationAuditMarkdown, resolveGateVerdictCalibrationConfig, type GateVerdictCalibrationConfig, type GateVerdictCalibrationDimension, type GateVerdictCalibrationDimensionInput, type GateVerdictCalibrationDimensionSignal, type GateVerdictCalibrationIngestion, type GateVerdictCalibrationManifest, type GateVerdictCalibrationOutcome, type GateVerdictCalibrationSignal, type GateVerdictCalibrationSignalInput, type GateVerdictCalibrationWeights, type GateVerdictCompositeCalibrationScore, } from "./gate-verdict-calibration.js";
10
+ export { computePhase7CalibrationLoop, computePrOutcomeCalibrationAccuracy, DOCUMENTED_CALIBRATION_BASELINE, evaluateAutonomyIncreaseEligibility, isHistoricalReplayRunFresh, renderPhase7CalibrationAuditMarkdown, resolvePhase7CalibrationConfig, shouldScheduleHistoricalReplayRun, type CalibrationSignalSource, type CalibrationSourceMetric, type HistoricalReplayCalibrationInput, type Phase7CalibrationConfig, type Phase7CalibrationLoopResult, type Phase7CalibrationManifest, type PrOutcomeCalibrationInput, type ReplayHarnessStatus, } from "./phase7-calibration-loop.js";
11
+ export { buildCalibrationDashboardView, resolveCalibrationDashboardStatus, type CalibrationDashboardRow, type CalibrationDashboardStatus, type CalibrationDashboardView, } from "./calibration-dashboard.js";
12
+ export { buildCalibrationTrendView, calibrationSnapshotFromResult, type CalibrationTrendDirection, type CalibrationTrendPoint, type CalibrationTrendSnapshot, type CalibrationTrendView, } from "./calibration-trend.js";
13
+ export { computeFindingSeverityCompositeCalibrationScore, ingestFindingSeverityCalibrationSignals, renderFindingSeverityCalibrationAuditMarkdown, resolveFindingSeverityCalibrationConfig, type FindingSeverityCalibrationConfig, type FindingSeverityCalibrationIngestion, type FindingSeverityCalibrationManifest, type FindingSeverityCalibrationSignal, type FindingSeverityCalibrationSignalInput, type FindingSeverityCalibrationWeights, type FindingSeverityCompositeCalibrationScore, type FindingSeverityTier, type FindingSeverityTierInput, type FindingSeverityTierSignal, } from "./finding-severity-calibration.js";
14
+ export { computeReviewerConsensusCompositeCalibrationScore, ingestReviewerConsensusCalibrationSignals, renderReviewerConsensusCalibrationAuditMarkdown, resolveReviewerConsensusCalibrationConfig, type ReviewerConsensusCalibrationConfig, type ReviewerConsensusCalibrationIngestion, type ReviewerConsensusCalibrationManifest, type ReviewerConsensusCalibrationSignal, type ReviewerConsensusCalibrationSignalInput, type ReviewerConsensusCalibrationWeights, type ReviewerConsensusCompositeCalibrationScore, type ReviewerConsensusDimension, type ReviewerConsensusDimensionInput, type ReviewerConsensusDimensionSignal, type ReviewerConsensusVote, } from "./reviewer-consensus-calibration.js";
15
+ export { computeTrackRecordSummary, renderTrackRecordSummaryMarkdown, resolveTrackRecordSummaryConfig, shouldIncludeTrackRecordSummary, type TrackRecordIncidentKind, type TrackRecordIncidentRecord, type TrackRecordIncidentStatus, type TrackRecordMergeRate, type TrackRecordPullRequestOutcome, type TrackRecordPullRequestState, type TrackRecordSummary, type TrackRecordSummaryAudit, type TrackRecordSummaryConfig, type TrackRecordSummaryManifest, type TrackRecordSummaryOutcomeCounts, type TrackRecordTenure, } from "./track-record-summary.js";
16
+ export * from "./governor/rate-limit.js";
17
+ export * from "./governor/budget-cap.js";
18
+ export * from "./governor/self-plagiarism.js";
19
+ export * from "./governor/reputation-throttle.js";
20
+ export * from "./governor/write-rate-limit.js";
21
+ export * from "./governor/run-halt.js";
22
+ export * from "./governor/kill-switch.js";
23
+ export * from "./governor/action-mode.js";
24
+ export * from "./governor/chokepoint.js";
25
+ export { GOVERNOR_LEDGER_EVENT_TYPES, normalizeGovernorLedgerEvent, type GovernorLedgerEvent, type GovernorLedgerEventType, type NormalizedGovernorLedgerEvent, } from "./governor-ledger.js";
26
+ export { MINER_TELEMETRY_EVENT_TYPES, MINER_TELEMETRY_OUTCOME_BUCKETS, normalizeMinerTelemetryEvent, type MinerTelemetryEvent, type MinerTelemetryEventType, type MinerTelemetryOutcomeBucket, type NormalizedMinerTelemetryEvent, } from "./miner-telemetry.js";
27
+ export { MINER_PREDICTIONS_TOTAL, MINER_PREDICTION_CORRECT_TOTAL, MINER_PREDICTION_INCORRECT_TOTAL, renderMinerPredictionMetrics, type MinerPredictionMetricRow, } from "./miner-prediction-metrics.js";
28
+ export { ATTEMPT_LOG_EVENT_TYPES, createAttemptLogBuffer, formatAttemptLogJsonl, normalizeAttemptLogEvent, type AttemptLogEvent, type AttemptLogEventType, type NormalizedAttemptLogEvent, } from "./miner/attempt-log.js";
29
+ export { ACCEPTANCE_CRITERIA_FILENAME, ACCEPTANCE_CRITERIA_VERSION, buildAcceptanceCriteria, serializeAcceptanceCriteria, shouldWriteAcceptanceCriteria, type AcceptanceCriteria, type AcceptanceCriteriaInput, } from "./miner/acceptance-criteria.js";
30
+ export type { AdvisoryFinding, BountyRecord, IssueQualityReport, IssueRecord, PullRequestRecord, RepositoryRecord, } from "./types/predicted-gate-types.js";
31
+ export { buildSelfReviewChangedPaths, buildSelfReviewPredictedGateInput, buildSelfReviewSlopInput, runSelfReview, SELF_REVIEW_PASSING_CONCLUSION, type AttemptDiffState, type SelfReviewAdapterDeps, type SelfReviewChangedFile, type SelfReviewContext, type SelfReviewSlopAssessment, type SelfReviewSlopBand, type SelfReviewSlopInput, type SelfReviewVerdict, } from "./miner/self-review-adapter.js";
32
+ export { decideNextAction, decideNextActionWithReason, deriveSelfReviewOutcome, type AbandonReason, type HandoffPacket, type IterateLoopAction, type IterateLoopDecision, type IterationState, type SelfReviewOutcome, } from "./miner/iterate-policy.js";
33
+ export { runIterateLoop, type IterateLoopDeps, type IterateLoopInput, type IterateLoopIterationRecord, type IterateLoopOutcome, type IterateLoopResult, } from "./miner/iterate-loop.js";
34
+ export { isSlopBandWithinThreshold, shouldSubmit, SUBMISSION_GATE_PASSING_CONCLUSION, type SubmissionGateCandidate, type SubmissionGateDecision, type SubmissionGateMode, } from "./miner/submission-gate.js";
35
+ export { DEFAULT_MAX_CONSECUTIVE_DISENGAGEMENTS, DEFAULT_MAX_REENTRIES_PER_HOUR, DEFAULT_MAX_REENTRIES_PER_SESSION, shouldReenter, type LoopReentryCandidate, type LoopReentryDecision, type LoopReentryOutcome, } from "./miner/loop-reentry-policy.js";
36
+ export { DEFAULT_MAX_CONSECUTIVE_GATE_BLOCKS, evaluateHarnessSubmissionTrigger, type HarnessSubmissionTriggerCandidate, type HarnessSubmissionTriggerDecision, } from "./miner/harness-submission-trigger.js";
37
+ export { codingAgentModeExecutes, isGlobalMinerCodingAgentPause, resolveCodingAgentExecutionMode, resolveCodingAgentModeFromConfig, type CodingAgentExecutionMode, } from "./miner/coding-agent-mode.js";
38
+ export { createFakeCodingAgentDriver, createNoopCodingAgentDriver, type CodingAgentDriver, type CodingAgentDriverResult, type CodingAgentDriverTask, } from "./miner/coding-agent-driver.js";
39
+ export { createCliSubprocessCodingAgentDriver, defaultClaudeCliArgs, defaultCodexCliArgs, type CliSubprocessDriverOptions, type CliSubprocessSpawnFn, } from "./miner/cli-subprocess-driver.js";
40
+ export { addWorktree, planWorktree, removeWorktree, shouldRetainWorktree, WORKTREE_BRANCH_PREFIX, WORKTREE_SUBDIR, type WorktreeAddResult, type WorktreeExecFn, type WorktreeExecResult, type WorktreePlan, type WorktreeRemoveResult, } from "./miner/worktree-allocator.js";
41
+ export * from "./miner/worktree-pool.js";
42
+ export { invokeCodingAgentDriver, type AttemptLogSink, } from "./miner/coding-agent-invoke.js";
43
+ export { classifyLintGuardPackage, guardChangedFiles, guardCodingAgentDriverResult, type LintGuardCheckResult, type LintGuardedDriverResult, type LintGuardOptions, type LintGuardPackage, type LintGuardResult, type LintGuardSpawnFn, } from "./miner/lint-guard.js";
44
+ export { CODING_AGENT_DRIVER_CONFIG_ENV, CODING_AGENT_DRIVER_NAMES, createCodingAgentDriver, createFakeCodingAgentDriverForFactory, isConfiguredCodingAgentDriver, resolveConfiguredCodingAgentDriverNames, resolveFirstConfiguredCodingAgentDriverName, runCodingAgentAttempt, type CodingAgentDriverName, type CreateCodingAgentDriverOptions, type RunCodingAgentAttemptOptions, } from "./miner/driver-factory.js";
45
+ export * from "./miner/attempt-metering.js";
46
+ export { buildRepoMap, extractRepoMapSymbols, renderRepoMap, resolveRepoMapLanguage, type BuildRepoMapOptions, type ExtractRepoMapSymbolsOptions, type LoadRepoMapLanguageFn, type RepoMapFileEntry, type RepoMapSkipReason, type RepoMapSourceFile, type RepoMapSymbol, type RepoMapSymbolKind, } from "./miner/repo-map.js";
47
+ export { createAgentSdkCodingAgentDriver, type AgentSdkHooks, type AgentSdkQueryFn, type AgentSdkQueryOptions, type CreateAgentSdkDriverOptions, } from "./miner/agent-sdk-driver.js";
48
+ export { LOCAL_WRITE_BOUNDARY, buildApplyLabelsSpec, buildClosePrSpec, buildCreateBranchSpec, buildDeleteBranchSpec, buildFileIssueSpec, buildFollowUpIssueSpec, buildOpenPrSpec, buildPostEligibilityCommentSpec, buildTestGenSpec, type LocalWriteActionSpec, type LocalWriteJsonValue, } from "./miner/local-write-tools.js";
49
+ export { GENERIC_COMMIT_PATTERN, SLOP_RUBRIC_MARKDOWN, SLOP_WEIGHTS, buildDuplicateClusterFinding, buildEmptyDescriptionFinding, buildLowQualityCommitMessageFinding, buildMissingTestEvidenceFinding, buildNoLinkedIssueRationaleFinding, buildNonSubstantivePaddingFinding, buildSlopAssessment, buildTrivialWhitespaceChurnFinding, hasClearNoIssueRationale, type SlopAssessment, type SlopAssessmentInput, type SlopBand, type SlopChangedFile, } from "./signals/slop.js";
50
+ export { buildCollisionReport, type CollisionCluster, type CollisionReport } from "./signals/predicted-gate-engine.js";
51
+ export type { CollisionItem } from "./types/predicted-gate-types.js";
52
+ export * from "./plan-export.js";
53
+ export { countPlanStepsByStatus } from "./plan-step-stats.js";
54
+ export { countPlanSteps } from "./plan-step-count.js";
55
+ export { isPlanEmpty } from "./plan-empty.js";
56
+ export { isPlanFullyCompleted } from "./plan-completion.js";
57
+ export { hasPlanFailedSteps } from "./plan-failure.js";
58
+ export { hasPlanPendingSteps } from "./plan-pending.js";
59
+ export { hasPlanRunningSteps } from "./plan-running.js";
60
+ export { hasPlanSkippedSteps } from "./plan-skipped.js";
61
+ export { hasPlanCompletedSteps } from "./plan-completed.js";
62
+ export { isPlanBlocked } from "./plan-blocked.js";
63
+ export { isPlanProgressComplete } from "./plan-progress-complete.js";
64
+ export { resolvePlanOverallStatus, type PlanOverallStatus, } from "./plan-overall-status.js";
65
+ export { hasPlanReadySteps } from "./plan-ready.js";
66
+ export { isPlanTerminated } from "./plan-terminated.js";
67
+ export * from "./plan-templates.js";
68
+ export * from "./issue-plan-decomposition.js";
69
+ export { PROMPT_PACKET_REDACTED_PATH, PROMPT_PACKET_REDACTED_TERM, PROMPT_PACKET_TEXT_FIELDS, buildPromptPacket, sanitizePromptPacketField, type PromptPacket, type PromptPacketInput, type PromptPacketTextField, } from "./prompt-packet.js";
70
+ export * from "./portfolio/queue.js";
71
+ export * from "./portfolio/non-convergence.js";
72
+ export { applyAiPolicyFatigueToRankInput, createAiPolicyFatigueCacheEntry, describeAiPolicyFatigueCache, renderAiPolicyFatigueMarkdown, resolveAiPolicyFatigueVerdict, resolveAiPolicyVerdict, scanAiPolicyText, type AiFatigueDocLanguageChange, type AiFatiguePullRequestMetadata, type AiPolicyFatigueRankAdjustment, type AiPolicyFatigueRankInput, type AiPolicyFatigueCacheEntry, type AiPolicyFatigueCacheState, type AiPolicyFatigueEvidence, type AiPolicyFatigueEvidenceKind, type AiPolicyFatigueInput, type AiPolicyFatigueLevel, type AiPolicyFatigueVerdict, type AiPolicyPriorityAdjustment, type AiPolicySource, type AiPolicyVerdict, } from "./ai-policy-map.js";
73
+ export { DEFAULT_MINER_GOAL_SPEC, parseMinerGoalSpec, parseMinerGoalSpecContent, discoverMinerGoalSpecPath, MINER_GOAL_SPEC_FILENAMES, type FeasibilityGatePolicy, type MinerExecutionPolicy, type MinerGoalSpec, type MinerIssueDiscoveryPolicy, type MinerKillSwitchPolicy, type ParsedMinerGoalSpec, } from "./miner-goal-spec.js";
74
+ export { DEFAULT_AMS_POLICY_SPEC, parseAmsPolicySpec, parseAmsPolicySpecContent, AMS_POLICY_SPEC_FILENAMES, type AmsCapLimits, type AmsPolicySpec, type AmsSlopThreshold, type AmsSubmissionMode, type ParsedAmsPolicySpec, } from "./ams-policy-spec.js";
75
+ export { DEFAULT_FLEET_RUN_MANIFEST, parseFleetRunManifest, parseFleetRunManifestContent, type FleetRunManifest, type FleetRunManifestRepo, type ParsedFleetRunManifest, } from "./fleet-run-manifest.js";
76
+ export { DISCOVERY_INDEX_CONTRACT_VERSION, DISCOVERY_INDEX_FORBIDDEN_FIELDS, discoveryIndexBoundaryViolations, normalizeDiscoveryIndexCandidate, normalizeDiscoveryIndexRequest, normalizeDiscoveryIndexResponse, type DiscoveryIndexAiPolicySource, type DiscoveryIndexCandidate, type DiscoveryIndexQuery, type DiscoveryIndexRequest, type DiscoveryIndexResponse, type ParsedDiscoveryIndexRequest, type ParsedDiscoveryIndexResponse, } from "./discovery-index-contract.js";
77
+ export { buildSoftClaimRequest, softClaimActionForStatus, type SoftClaimAction, type SoftClaimRecord, type SoftClaimRequest, type SoftClaimRequestContext, type SoftClaimStatus, } from "./discovery-soft-claim.js";
78
+ export { computeMetadataLaneFit, computeMinerGoalLaneFit, isMinerRepoTargetable, } from "./miner-goal-lane-fit.js";
79
+ export { computeOpportunityFreshness, type FreshnessIssue, } from "./opportunity-freshness.js";
80
+ export { computeOpportunityCompetition } from "./opportunity-competition.js";
81
+ export { computeLaneFit, type GoalModelInput } from "./goal-model.js";
82
+ export { classifyContributorFit, type ContributorFit, type ContributorFitCheck, type ContributorFitProfile, } from "./contributor-fit.js";
83
+ export { buildFeasibilityVerdict, feasibilityInputFromPreStartCheck, type FeasibilityClaimStatus, type FeasibilityDuplicateClusterRisk, type FeasibilityGateInput, type FeasibilityGateResult, type FeasibilityIssueStatus, type FeasibilityVerdict, } from "./feasibility.js";
84
+ export { buildMetadataRankInput, computeMetadataDupRisk, computeMetadataFeasibility, computeMetadataPotential, rankMetadataOpportunities, type MetadataCandidateIssue, type MetadataRankContext, } from "./opportunity-metadata.js";
85
+ export { pickTopMetadataOpportunities } from "./metadata-top-pick.js";
86
+ export { rankMetadataOpportunitiesAtOrAboveScore } from "./metadata-min-score.js";
87
+ export { pickTopMetadataOpportunitiesAtOrAboveScore } from "./metadata-top-min-score.js";
88
+ export { bestMetadataOpportunity } from "./metadata-best-pick.js";
89
+ export { bestMetadataOpportunityAtOrAboveScore } from "./metadata-best-min-score.js";
90
+ export * as scoringModel from "./scoring/model.js";
91
+ export * as scoringPreview from "./scoring/preview.js";
92
+ export * as scoringPendingPrScenarios from "./scoring/pending-pr-scenarios.js";
93
+ export { isDuplicateClusterWinner, isDuplicateClusterWinnerByClaim, resolveDuplicateClusterWinnerNumber, type DuplicateClaimMember, } from "./duplicate-winner.js";
94
+ export { MIN_QUERY_CHARS, buildIssueRagQuery, type IssueRagQueryInput, } from "./issue-rag-query.js";
95
+ export { computeLocalScorerTokens, type LocalScorerChangedFile, type LocalScorerValidation, type LocalScorerResult, } from "./local-scorer.js";
96
+ export { buildPredictedGateVerdict, predictedGateNote, publicSafeFinding, applyContributorCalibration, MIN_CALIBRATION_SAMPLES, MAX_READINESS_ADJUSTMENT, type GateCheckConclusion, type GatePolicyPack, type PredictedGateInput, type PredictedGateVerdict, type ContributorCalibrationSignal, } from "./predicted-gate.js";
97
+ export { compileFocusManifestPolicy, contentLaneConfigToJson, experimentalConfigToJson, featuresConfigToJson, formatManifestValidationNotice, gateConfigToJson, isFocusManifestPublicSafe, matchesManifestPath, normalizeReadinessGateMode, parseFocusManifest, parseFocusManifestContent, repoDocGenerationConfigToJson, reviewConfigToJson, reviewRecapConfigToJson, maintainerRecapConfigToJson, settingsOverrideToJson, MAX_FOCUS_MANIFEST_BYTES, CONVERGED_FEATURE_KEYS, EXPERIMENTAL_PLUGIN_KEYS, COMMENT_VERBOSITY_LEVELS, EMPTY_AUTO_REVIEW_CONFIG, EMPTY_MAX_FINDINGS_CONFIG, EMPTY_SELF_HOST_AI_MODEL_CONFIG, EMPTY_VISUAL_CONFIG, LINKED_ISSUE_SATISFACTION_MODES, REVIEW_FIELD_KEYS, REVIEW_FINDING_SEVERITY_LADDER, REVIEW_PROFILES, type AutoReviewConfig, type CommentVerbosity, type ConvergedFeatureKey, type ExperimentalPluginKey, type FocusManifest, type FocusManifestContentLaneConfig, type FocusManifestExperimentalConfig, type FocusManifestFeaturesConfig, type FocusManifestGateConfig, type FocusManifestIssueDiscoveryPolicy, type FocusManifestLanePreference, type FocusManifestLinkedIssuePolicy, type FocusManifestPolicy, type FocusManifestPolicyContributionLane, type FocusManifestPolicyLabelPolicy, type FocusManifestPolicyValidation, type FocusManifestRepoDocGenerationConfig, type FocusManifestRepoDocGenerationScope, type FocusManifestReviewConfig, type FocusManifestReviewRecapConfig, type FocusManifestMaintainerRecapConfig, type FocusManifestSettings, type FocusManifestSource, type LinkedIssueSatisfactionMode, type MaxFindingsConfig, type PreMergeCheck, type ReviewFieldKey, type ReviewFindingSeverity, type ReviewPathInstruction, type ReviewProfile, type SelfHostAiModelConfig, type VisualConfig, type VisualPreviewConfig, type VisualRoutesConfig, type VisualTheme, } from "./focus-manifest.js";
98
+ export { buildRepoRewardRisk, buildContributorRewardRiskStrategy, buildMaintainerNoiseReport, buildPullRequestReviewability, rewardRiskFreshnessInternals, type RewardRiskEngineDeps, type PullRequestReviewabilityInput, type PullRequestReviewIntelligenceView, type RewardRiskAction, type RewardRiskActionKind, type RewardRiskActionSeverity, type RepoRewardRisk, type EligibilityGapEntry, type ContributorRewardRiskStrategy, type MaintainerNoiseReport, type PullRequestReviewability, } from "./reward-risk.js";
99
+ export { SUBPROCESS_CLI_ENV_ALLOWLIST, buildAllowlistedEnv, SECRET_PATTERNS, redactSecrets, } from "./subprocess-env.js";
package/dist/index.js ADDED
@@ -0,0 +1,120 @@
1
+ // Barrel export for @loopover/engine.
2
+ //
3
+ // This package houses the deterministic, side-effect-free logic shared by the Gittensory review-stack
4
+ // backend and the gittensory-miner (scoring preview/model, predicted-gate types, reward-risk, slop signals,
5
+ // focus-manifest parse/compile core, duplicate-winner adjudication, and their engine-parity fixtures).
6
+ // More modules land in follow-up issues.
7
+ export { ENGINE_VERSION } from "./version.js";
8
+ export { pickTopRankedOpportunities, rankOpportunityScore, rankOpportunities, } from "./opportunity-ranker.js";
9
+ export { rankOpportunitiesAtOrAboveScore } from "./ranked-opportunity-min-score.js";
10
+ export { pickTopRankedOpportunitiesAtOrAboveScore } from "./ranked-opportunity-top-min-score.js";
11
+ export { bestRankedOpportunity } from "./ranked-opportunity-best-pick.js";
12
+ export { bestRankedOpportunityAtOrAboveScore } from "./ranked-opportunity-best-min-score.js";
13
+ export { extractObjectiveAnchorHistory, extractObjectiveAnchorFeatures, scoreObjectiveAnchor, scoreObjectiveAnchorHistory, renderObjectiveAnchorAuditMarkdown, } from "./objective-anchor.js";
14
+ export { computePairwiseCalibrationScore, resolvePairwiseCalibrationSample, } from "./pairwise-calibration.js";
15
+ export { computeGateVerdictCompositeCalibrationScore, ingestGateVerdictCalibrationSignals, renderGateVerdictCalibrationAuditMarkdown, resolveGateVerdictCalibrationConfig, } from "./gate-verdict-calibration.js";
16
+ export { computePhase7CalibrationLoop, computePrOutcomeCalibrationAccuracy, DOCUMENTED_CALIBRATION_BASELINE, evaluateAutonomyIncreaseEligibility, isHistoricalReplayRunFresh, renderPhase7CalibrationAuditMarkdown, resolvePhase7CalibrationConfig, shouldScheduleHistoricalReplayRun, } from "./phase7-calibration-loop.js";
17
+ export { buildCalibrationDashboardView, resolveCalibrationDashboardStatus, } from "./calibration-dashboard.js";
18
+ export { buildCalibrationTrendView, calibrationSnapshotFromResult, } from "./calibration-trend.js";
19
+ export { computeFindingSeverityCompositeCalibrationScore, ingestFindingSeverityCalibrationSignals, renderFindingSeverityCalibrationAuditMarkdown, resolveFindingSeverityCalibrationConfig, } from "./finding-severity-calibration.js";
20
+ export { computeReviewerConsensusCompositeCalibrationScore, ingestReviewerConsensusCalibrationSignals, renderReviewerConsensusCalibrationAuditMarkdown, resolveReviewerConsensusCalibrationConfig, } from "./reviewer-consensus-calibration.js";
21
+ export { computeTrackRecordSummary, renderTrackRecordSummaryMarkdown, resolveTrackRecordSummaryConfig, shouldIncludeTrackRecordSummary, } from "./track-record-summary.js";
22
+ export * from "./governor/rate-limit.js";
23
+ export * from "./governor/budget-cap.js";
24
+ export * from "./governor/self-plagiarism.js";
25
+ export * from "./governor/reputation-throttle.js";
26
+ export * from "./governor/write-rate-limit.js";
27
+ export * from "./governor/run-halt.js";
28
+ export * from "./governor/kill-switch.js";
29
+ export * from "./governor/action-mode.js";
30
+ export * from "./governor/chokepoint.js";
31
+ export { GOVERNOR_LEDGER_EVENT_TYPES, normalizeGovernorLedgerEvent, } from "./governor-ledger.js";
32
+ export { MINER_TELEMETRY_EVENT_TYPES, MINER_TELEMETRY_OUTCOME_BUCKETS, normalizeMinerTelemetryEvent, } from "./miner-telemetry.js";
33
+ export { MINER_PREDICTIONS_TOTAL, MINER_PREDICTION_CORRECT_TOTAL, MINER_PREDICTION_INCORRECT_TOTAL, renderMinerPredictionMetrics, } from "./miner-prediction-metrics.js";
34
+ export { ATTEMPT_LOG_EVENT_TYPES, createAttemptLogBuffer, formatAttemptLogJsonl, normalizeAttemptLogEvent, } from "./miner/attempt-log.js";
35
+ export { ACCEPTANCE_CRITERIA_FILENAME, ACCEPTANCE_CRITERIA_VERSION, buildAcceptanceCriteria, serializeAcceptanceCriteria, shouldWriteAcceptanceCriteria, } from "./miner/acceptance-criteria.js";
36
+ export { buildSelfReviewChangedPaths, buildSelfReviewPredictedGateInput, buildSelfReviewSlopInput, runSelfReview, SELF_REVIEW_PASSING_CONCLUSION, } from "./miner/self-review-adapter.js";
37
+ export { decideNextAction, decideNextActionWithReason, deriveSelfReviewOutcome, } from "./miner/iterate-policy.js";
38
+ export { runIterateLoop, } from "./miner/iterate-loop.js";
39
+ export { isSlopBandWithinThreshold, shouldSubmit, SUBMISSION_GATE_PASSING_CONCLUSION, } from "./miner/submission-gate.js";
40
+ export { DEFAULT_MAX_CONSECUTIVE_DISENGAGEMENTS, DEFAULT_MAX_REENTRIES_PER_HOUR, DEFAULT_MAX_REENTRIES_PER_SESSION, shouldReenter, } from "./miner/loop-reentry-policy.js";
41
+ export { DEFAULT_MAX_CONSECUTIVE_GATE_BLOCKS, evaluateHarnessSubmissionTrigger, } from "./miner/harness-submission-trigger.js";
42
+ export { codingAgentModeExecutes, isGlobalMinerCodingAgentPause, resolveCodingAgentExecutionMode, resolveCodingAgentModeFromConfig, } from "./miner/coding-agent-mode.js";
43
+ export { createFakeCodingAgentDriver, createNoopCodingAgentDriver, } from "./miner/coding-agent-driver.js";
44
+ export { createCliSubprocessCodingAgentDriver, defaultClaudeCliArgs, defaultCodexCliArgs, } from "./miner/cli-subprocess-driver.js";
45
+ export { addWorktree, planWorktree, removeWorktree, shouldRetainWorktree, WORKTREE_BRANCH_PREFIX, WORKTREE_SUBDIR, } from "./miner/worktree-allocator.js";
46
+ export * from "./miner/worktree-pool.js";
47
+ export { invokeCodingAgentDriver, } from "./miner/coding-agent-invoke.js";
48
+ export { classifyLintGuardPackage, guardChangedFiles, guardCodingAgentDriverResult, } from "./miner/lint-guard.js";
49
+ export { CODING_AGENT_DRIVER_CONFIG_ENV, CODING_AGENT_DRIVER_NAMES, createCodingAgentDriver, createFakeCodingAgentDriverForFactory, isConfiguredCodingAgentDriver, resolveConfiguredCodingAgentDriverNames, resolveFirstConfiguredCodingAgentDriverName, runCodingAgentAttempt, } from "./miner/driver-factory.js";
50
+ export * from "./miner/attempt-metering.js";
51
+ export { buildRepoMap, extractRepoMapSymbols, renderRepoMap, resolveRepoMapLanguage, } from "./miner/repo-map.js";
52
+ export { createAgentSdkCodingAgentDriver, } from "./miner/agent-sdk-driver.js";
53
+ export { LOCAL_WRITE_BOUNDARY, buildApplyLabelsSpec, buildClosePrSpec, buildCreateBranchSpec, buildDeleteBranchSpec, buildFileIssueSpec, buildFollowUpIssueSpec, buildOpenPrSpec, buildPostEligibilityCommentSpec, buildTestGenSpec, } from "./miner/local-write-tools.js";
54
+ export { GENERIC_COMMIT_PATTERN, SLOP_RUBRIC_MARKDOWN, SLOP_WEIGHTS, buildDuplicateClusterFinding, buildEmptyDescriptionFinding, buildLowQualityCommitMessageFinding, buildMissingTestEvidenceFinding, buildNoLinkedIssueRationaleFinding, buildNonSubstantivePaddingFinding, buildSlopAssessment, buildTrivialWhitespaceChurnFinding, hasClearNoIssueRationale, } from "./signals/slop.js";
55
+ // Scoped (not `export *`) because predicted-gate-engine.ts also defines its own hasClearNoIssueRationale --
56
+ // a near-duplicate of slop.js's own export (see that function's doc comment) -- which would collide with the
57
+ // one already re-exported above. Only buildCollisionReport + its result types are needed publicly so far
58
+ // (#5145, the miner's real SelfReviewContext fetcher needs to compute inDuplicateCluster the same way the
59
+ // live gate does), not this file's full internal surface.
60
+ export { buildCollisionReport } from "./signals/predicted-gate-engine.js";
61
+ export * from "./plan-export.js";
62
+ export { countPlanStepsByStatus } from "./plan-step-stats.js";
63
+ export { countPlanSteps } from "./plan-step-count.js";
64
+ export { isPlanEmpty } from "./plan-empty.js";
65
+ export { isPlanFullyCompleted } from "./plan-completion.js";
66
+ export { hasPlanFailedSteps } from "./plan-failure.js";
67
+ export { hasPlanPendingSteps } from "./plan-pending.js";
68
+ export { hasPlanRunningSteps } from "./plan-running.js";
69
+ export { hasPlanSkippedSteps } from "./plan-skipped.js";
70
+ export { hasPlanCompletedSteps } from "./plan-completed.js";
71
+ export { isPlanBlocked } from "./plan-blocked.js";
72
+ export { isPlanProgressComplete } from "./plan-progress-complete.js";
73
+ export { resolvePlanOverallStatus, } from "./plan-overall-status.js";
74
+ export { hasPlanReadySteps } from "./plan-ready.js";
75
+ export { isPlanTerminated } from "./plan-terminated.js";
76
+ export * from "./plan-templates.js";
77
+ export * from "./issue-plan-decomposition.js";
78
+ export { PROMPT_PACKET_REDACTED_PATH, PROMPT_PACKET_REDACTED_TERM, PROMPT_PACKET_TEXT_FIELDS, buildPromptPacket, sanitizePromptPacketField, } from "./prompt-packet.js";
79
+ export * from "./portfolio/queue.js";
80
+ export * from "./portfolio/non-convergence.js";
81
+ export { applyAiPolicyFatigueToRankInput, createAiPolicyFatigueCacheEntry, describeAiPolicyFatigueCache, renderAiPolicyFatigueMarkdown, resolveAiPolicyFatigueVerdict, resolveAiPolicyVerdict, scanAiPolicyText, } from "./ai-policy-map.js";
82
+ export { DEFAULT_MINER_GOAL_SPEC, parseMinerGoalSpec, parseMinerGoalSpecContent, discoverMinerGoalSpecPath, MINER_GOAL_SPEC_FILENAMES, } from "./miner-goal-spec.js";
83
+ export { DEFAULT_AMS_POLICY_SPEC, parseAmsPolicySpec, parseAmsPolicySpecContent, AMS_POLICY_SPEC_FILENAMES, } from "./ams-policy-spec.js";
84
+ export { DEFAULT_FLEET_RUN_MANIFEST, parseFleetRunManifest, parseFleetRunManifestContent, } from "./fleet-run-manifest.js";
85
+ export { DISCOVERY_INDEX_CONTRACT_VERSION, DISCOVERY_INDEX_FORBIDDEN_FIELDS, discoveryIndexBoundaryViolations, normalizeDiscoveryIndexCandidate, normalizeDiscoveryIndexRequest, normalizeDiscoveryIndexResponse, } from "./discovery-index-contract.js";
86
+ export { buildSoftClaimRequest, softClaimActionForStatus, } from "./discovery-soft-claim.js";
87
+ export { computeMetadataLaneFit, computeMinerGoalLaneFit, isMinerRepoTargetable, } from "./miner-goal-lane-fit.js";
88
+ export { computeOpportunityFreshness, } from "./opportunity-freshness.js";
89
+ export { computeOpportunityCompetition } from "./opportunity-competition.js";
90
+ export { computeLaneFit } from "./goal-model.js";
91
+ export { classifyContributorFit, } from "./contributor-fit.js";
92
+ export { buildFeasibilityVerdict, feasibilityInputFromPreStartCheck, } from "./feasibility.js";
93
+ export { buildMetadataRankInput, computeMetadataDupRisk, computeMetadataFeasibility, computeMetadataPotential, rankMetadataOpportunities, } from "./opportunity-metadata.js";
94
+ export { pickTopMetadataOpportunities } from "./metadata-top-pick.js";
95
+ export { rankMetadataOpportunitiesAtOrAboveScore } from "./metadata-min-score.js";
96
+ export { pickTopMetadataOpportunitiesAtOrAboveScore } from "./metadata-top-min-score.js";
97
+ export { bestMetadataOpportunity } from "./metadata-best-pick.js";
98
+ export { bestMetadataOpportunityAtOrAboveScore } from "./metadata-best-min-score.js";
99
+ // Score-preview machinery (#2282): namespaced (rather than flattened) so the three ported files keep their
100
+ // own identity and cannot collide with each other or the ~50 other top-level exports above.
101
+ export * as scoringModel from "./scoring/model.js";
102
+ export * as scoringPreview from "./scoring/preview.js";
103
+ export * as scoringPendingPrScenarios from "./scoring/pending-pr-scenarios.js";
104
+ export { isDuplicateClusterWinner, isDuplicateClusterWinnerByClaim, resolveDuplicateClusterWinnerNumber, } from "./duplicate-winner.js";
105
+ // Issue-centric RAG query composition (#2320, extracted in #4254): the pure query builder + the shared
106
+ // minimum-query floor; the Vectorize/D1 retrieval backend intentionally stays in the backend.
107
+ export { MIN_QUERY_CHARS, buildIssueRagQuery, } from "./issue-rag-query.js";
108
+ // #782 deterministic local scorer (extracted in #4253): pure token-scoring from changed-file metadata,
109
+ // shared by the published CLIs and the hosted Worker. The Node-coupled local-branch.ts stays in the backend.
110
+ export { computeLocalScorerTokens, } from "./local-scorer.js";
111
+ export { buildPredictedGateVerdict, predictedGateNote, publicSafeFinding, applyContributorCalibration, MIN_CALIBRATION_SAMPLES, MAX_READINESS_ADJUSTMENT, } from "./predicted-gate.js";
112
+ // Focus-manifest parse/compile core (#2280): shared by the maintainer review stack and the miner's
113
+ // `.gittensory-miner.yml` goal-spec parser (see miner-goal-spec.ts for the parallel surface).
114
+ export { compileFocusManifestPolicy, contentLaneConfigToJson, experimentalConfigToJson, featuresConfigToJson, formatManifestValidationNotice, gateConfigToJson, isFocusManifestPublicSafe, matchesManifestPath, normalizeReadinessGateMode, parseFocusManifest, parseFocusManifestContent, repoDocGenerationConfigToJson, reviewConfigToJson, reviewRecapConfigToJson, maintainerRecapConfigToJson, settingsOverrideToJson, MAX_FOCUS_MANIFEST_BYTES, CONVERGED_FEATURE_KEYS, EXPERIMENTAL_PLUGIN_KEYS, COMMENT_VERBOSITY_LEVELS, EMPTY_AUTO_REVIEW_CONFIG, EMPTY_MAX_FINDINGS_CONFIG, EMPTY_SELF_HOST_AI_MODEL_CONFIG, EMPTY_VISUAL_CONFIG, LINKED_ISSUE_SATISFACTION_MODES, REVIEW_FIELD_KEYS, REVIEW_FINDING_SEVERITY_LADDER, REVIEW_PROFILES, } from "./focus-manifest.js";
115
+ // Reward/risk reasoning signals (#2281). The four builders depend on the still-in-`src` maintainer signal
116
+ // stack, so they take an injected `RewardRiskEngineDeps` (the `src/signals/reward-risk.ts` shim binds it).
117
+ export { buildRepoRewardRisk, buildContributorRewardRiskStrategy, buildMaintainerNoiseReport, buildPullRequestReviewability, rewardRiskFreshnessInternals, } from "./reward-risk.js";
118
+ // Shared subprocess env-allowlist + secret-redaction helpers (#4284) — one source of truth for every driver that
119
+ // spawns a locally-authenticated CLI subprocess (src/selfhost/ai.ts and the coming gittensory-miner drivers).
120
+ export { SUBPROCESS_CLI_ENV_ALLOWLIST, buildAllowlistedEnv, SECRET_PATTERNS, redactSecrets, } from "./subprocess-env.js";
@@ -0,0 +1,18 @@
1
+ import type { RawPlanStep } from "./plan-templates.js";
2
+ /** Issue-level metadata this heuristic decomposes into an execution plan. Every field is optional so a bare issue
3
+ * (title-only, or nothing at all) still yields a valid baseline DAG. A PromptPacket caller (#2321) can map its
4
+ * `taskBrief` onto `title` and `retrievalContext`/`constraints` onto `body`. */
5
+ export type IssuePlanInput = {
6
+ title?: string | undefined;
7
+ body?: string | undefined;
8
+ labels?: readonly string[] | undefined;
9
+ };
10
+ /**
11
+ * Decompose a target issue into a deterministic execution-plan DAG of {@link RawPlanStep}s. Same input always
12
+ * yields identical output (no clock, no randomness) — matching every other pure composer in this package. The spine
13
+ * is always `locate → implement → test → verify`; a bug signal inserts a `reproduce` step before `implement` (and
14
+ * asks `test` for a regression test), and a docs signal inserts a `docs` step that `verify` then also waits on.
15
+ * Every `dependsOn` references an EARLIER step, so the result is acyclic with a ready topological order and passes
16
+ * rawPlanStepSchema + plan-store.js's `validatePlanDag` unchanged (unique ids, in-plan deps, no cycles).
17
+ */
18
+ export declare function decomposeIssueToPlan(issue?: IssuePlanInput): RawPlanStep[];
@@ -0,0 +1,56 @@
1
+ // Issue-to-plan decomposition heuristic (pure) (#4292).
2
+ //
3
+ // The stateless plan-DAG surface (rawPlanStepSchema / gittensory_build_plan, src/mcp/server.ts; plan-store.js
4
+ // persistence) consumes a caller-supplied RawPlanStep[], but nothing in the repo turns a TARGET ISSUE into those
5
+ // steps — every caller has to hand it one already-built. plan-templates.ts's PLAN_TEMPLATE_BUILDERS describe the
6
+ // miner's OWN fixed lifecycle, not the issue's actual implementation work; planPlanTemplate even carries a
7
+ // `plan-dag-build` placeholder step with no logic behind it. This module is that missing piece: a deterministic,
8
+ // side-effect-free function that folds issue-level metadata (title / body / labels only — never source content)
9
+ // into a RawPlanStep[] execution DAG in the SAME raw-step shape plan-templates.ts emits, so build_plan and
10
+ // plan-store.js's validatePlanDag validate it identically.
11
+ // Title ceiling of rawPlanStepSchema.title (max 300) and a subject cap kept well under it, mirroring
12
+ // plan-templates.ts, so a long issue title can never produce an out-of-range step title.
13
+ const MAX_TITLE_CHARS = 300;
14
+ const MAX_SUBJECT_CHARS = 200;
15
+ // Collapse any run of whitespace to a single space and trim/bound, so a subject yields a clean deterministic
16
+ // one-line title (mirrors plan-templates.ts's normalizeSubject).
17
+ function normalizeSubject(subject) {
18
+ return (subject ?? "").replace(/\s+/g, " ").trim().slice(0, MAX_SUBJECT_CHARS);
19
+ }
20
+ // Compose a step title from a fixed prefix and the optional subject, hard-capped to the schema's title ceiling.
21
+ function titleFor(prefix, subject) {
22
+ const full = subject ? `${prefix}: ${subject}` : prefix;
23
+ return full.slice(0, MAX_TITLE_CHARS);
24
+ }
25
+ // Low-cardinality issue-kind signals derived deterministically from the combined title+body+labels text. Labels
26
+ // are folded into the SAME lowercased haystack as the free text, so an issue tagged `bug` and one whose title
27
+ // merely says "fix the crash" take the same path without a separate label-only branch.
28
+ const BUG_SIGNAL = /\b(bug|bugs|fix|fixes|regression|broken|crash|crashes|incorrect)\b/;
29
+ const DOCS_SIGNAL = /\b(doc|docs|documentation|readme|guide)\b/;
30
+ /**
31
+ * Decompose a target issue into a deterministic execution-plan DAG of {@link RawPlanStep}s. Same input always
32
+ * yields identical output (no clock, no randomness) — matching every other pure composer in this package. The spine
33
+ * is always `locate → implement → test → verify`; a bug signal inserts a `reproduce` step before `implement` (and
34
+ * asks `test` for a regression test), and a docs signal inserts a `docs` step that `verify` then also waits on.
35
+ * Every `dependsOn` references an EARLIER step, so the result is acyclic with a ready topological order and passes
36
+ * rawPlanStepSchema + plan-store.js's `validatePlanDag` unchanged (unique ids, in-plan deps, no cycles).
37
+ */
38
+ export function decomposeIssueToPlan(issue = {}) {
39
+ const subject = normalizeSubject(issue.title);
40
+ const haystack = `${issue.title ?? ""} ${issue.body ?? ""} ${(issue.labels ?? []).join(" ")}`.toLowerCase();
41
+ const isBugFix = BUG_SIGNAL.test(haystack);
42
+ const wantsDocs = DOCS_SIGNAL.test(haystack);
43
+ const steps = [
44
+ { id: "locate", title: titleFor("Locate the code to change", subject), actionClass: "analyze", dependsOn: [], maxAttempts: 2 },
45
+ ];
46
+ if (isBugFix) {
47
+ steps.push({ id: "reproduce", title: titleFor("Reproduce the reported behavior", subject), actionClass: "analyze", dependsOn: ["locate"], maxAttempts: 1 });
48
+ }
49
+ steps.push({ id: "implement", title: titleFor("Implement the change", subject), actionClass: "codegen", dependsOn: [isBugFix ? "reproduce" : "locate"], maxAttempts: 1 });
50
+ steps.push({ id: "test", title: titleFor(isBugFix ? "Add a regression test and run the suite" : "Add tests and run the suite", subject), actionClass: "test", dependsOn: ["implement"], maxAttempts: 2 });
51
+ if (wantsDocs) {
52
+ steps.push({ id: "docs", title: titleFor("Update documentation", subject), actionClass: "compose", dependsOn: ["implement"], maxAttempts: 1 });
53
+ }
54
+ steps.push({ id: "verify", title: titleFor("Verify the full gate is green", subject), actionClass: "analyze", dependsOn: wantsDocs ? ["test", "docs"] : ["test"], maxAttempts: 2 });
55
+ return steps;
56
+ }