@tokenfactory/acc-runner 0.44.0 → 0.44.2

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 (197) hide show
  1. package/README.md +43 -1
  2. package/dist/bin-resolve.d.ts +39 -3
  3. package/dist/bin-resolve.d.ts.map +1 -1
  4. package/dist/bin-resolve.js +176 -12
  5. package/dist/bin-resolve.js.map +1 -1
  6. package/dist/build-fingerprint.d.ts +66 -0
  7. package/dist/build-fingerprint.d.ts.map +1 -0
  8. package/dist/build-fingerprint.js +70 -0
  9. package/dist/build-fingerprint.js.map +1 -0
  10. package/dist/build-info.generated.d.ts +3 -0
  11. package/dist/build-info.generated.d.ts.map +1 -0
  12. package/dist/build-info.generated.js +3 -0
  13. package/dist/build-info.generated.js.map +1 -0
  14. package/dist/capacity/resume-controller.d.ts +5 -3
  15. package/dist/capacity/resume-controller.d.ts.map +1 -1
  16. package/dist/capacity/resume-controller.js +9 -0
  17. package/dist/capacity/resume-controller.js.map +1 -1
  18. package/dist/chat-delegation-guard.d.ts +23 -0
  19. package/dist/chat-delegation-guard.d.ts.map +1 -0
  20. package/dist/chat-delegation-guard.js +62 -0
  21. package/dist/chat-delegation-guard.js.map +1 -0
  22. package/dist/chat-lane.d.ts +17 -6
  23. package/dist/chat-lane.d.ts.map +1 -1
  24. package/dist/chat-lane.js +29 -8
  25. package/dist/chat-lane.js.map +1 -1
  26. package/dist/companion-identity.d.ts +37 -0
  27. package/dist/companion-identity.d.ts.map +1 -1
  28. package/dist/companion-identity.js +98 -29
  29. package/dist/companion-identity.js.map +1 -1
  30. package/dist/companion-run.d.ts +1 -50
  31. package/dist/companion-run.d.ts.map +1 -1
  32. package/dist/companion-run.js +48 -105
  33. package/dist/companion-run.js.map +1 -1
  34. package/dist/config.d.ts +1 -0
  35. package/dist/config.d.ts.map +1 -1
  36. package/dist/config.js +14 -3
  37. package/dist/config.js.map +1 -1
  38. package/dist/conformance.d.ts +49 -0
  39. package/dist/conformance.d.ts.map +1 -0
  40. package/dist/conformance.js +121 -0
  41. package/dist/conformance.js.map +1 -0
  42. package/dist/cost-pricing.d.ts +91 -0
  43. package/dist/cost-pricing.d.ts.map +1 -1
  44. package/dist/cost-pricing.js +115 -1
  45. package/dist/cost-pricing.js.map +1 -1
  46. package/dist/credential-identity.d.ts +70 -0
  47. package/dist/credential-identity.d.ts.map +1 -0
  48. package/dist/credential-identity.js +128 -0
  49. package/dist/credential-identity.js.map +1 -0
  50. package/dist/doctor.d.ts +37 -1
  51. package/dist/doctor.d.ts.map +1 -1
  52. package/dist/doctor.js +300 -41
  53. package/dist/doctor.js.map +1 -1
  54. package/dist/engines/chat-stream.d.ts +71 -1
  55. package/dist/engines/chat-stream.d.ts.map +1 -1
  56. package/dist/engines/chat-stream.js +126 -8
  57. package/dist/engines/chat-stream.js.map +1 -1
  58. package/dist/engines/claude-code-chat.d.ts +11 -1
  59. package/dist/engines/claude-code-chat.d.ts.map +1 -1
  60. package/dist/engines/claude-code-chat.js +69 -5
  61. package/dist/engines/claude-code-chat.js.map +1 -1
  62. package/dist/engines/claude-code.d.ts.map +1 -1
  63. package/dist/engines/claude-code.js +30 -6
  64. package/dist/engines/claude-code.js.map +1 -1
  65. package/dist/engines/codex.d.ts.map +1 -1
  66. package/dist/engines/codex.js +18 -5
  67. package/dist/engines/codex.js.map +1 -1
  68. package/dist/engines/registry.d.ts +26 -0
  69. package/dist/engines/registry.d.ts.map +1 -1
  70. package/dist/engines/registry.js +37 -0
  71. package/dist/engines/registry.js.map +1 -1
  72. package/dist/engines/types.d.ts +5 -0
  73. package/dist/engines/types.d.ts.map +1 -1
  74. package/dist/failure-classifier.d.ts +1 -1
  75. package/dist/failure-classifier.d.ts.map +1 -1
  76. package/dist/failure-classifier.js +65 -12
  77. package/dist/failure-classifier.js.map +1 -1
  78. package/dist/gh.d.ts +15 -0
  79. package/dist/gh.d.ts.map +1 -1
  80. package/dist/gh.js +18 -0
  81. package/dist/gh.js.map +1 -1
  82. package/dist/git.d.ts +6 -0
  83. package/dist/git.d.ts.map +1 -1
  84. package/dist/git.js +27 -1
  85. package/dist/git.js.map +1 -1
  86. package/dist/instance.d.ts +30 -0
  87. package/dist/instance.d.ts.map +1 -0
  88. package/dist/instance.js +51 -0
  89. package/dist/instance.js.map +1 -0
  90. package/dist/keychain.d.ts +20 -7
  91. package/dist/keychain.d.ts.map +1 -1
  92. package/dist/keychain.js +40 -4
  93. package/dist/keychain.js.map +1 -1
  94. package/dist/loc-advisory.d.ts +70 -0
  95. package/dist/loc-advisory.d.ts.map +1 -0
  96. package/dist/loc-advisory.js +196 -0
  97. package/dist/loc-advisory.js.map +1 -0
  98. package/dist/locks/claim-lock-policy.d.ts +67 -0
  99. package/dist/locks/claim-lock-policy.d.ts.map +1 -0
  100. package/dist/locks/claim-lock-policy.js +132 -0
  101. package/dist/locks/claim-lock-policy.js.map +1 -0
  102. package/dist/login.d.ts +63 -2
  103. package/dist/login.d.ts.map +1 -1
  104. package/dist/login.js +93 -8
  105. package/dist/login.js.map +1 -1
  106. package/dist/mcp-spawn.d.ts +54 -0
  107. package/dist/mcp-spawn.d.ts.map +1 -1
  108. package/dist/mcp-spawn.js +88 -4
  109. package/dist/mcp-spawn.js.map +1 -1
  110. package/dist/memory-context.d.ts +106 -0
  111. package/dist/memory-context.d.ts.map +1 -0
  112. package/dist/memory-context.js +220 -0
  113. package/dist/memory-context.js.map +1 -0
  114. package/dist/memory-curation.d.ts +172 -0
  115. package/dist/memory-curation.d.ts.map +1 -0
  116. package/dist/memory-curation.js +277 -0
  117. package/dist/memory-curation.js.map +1 -0
  118. package/dist/migration-seq-guard.d.ts +28 -1
  119. package/dist/migration-seq-guard.d.ts.map +1 -1
  120. package/dist/migration-seq-guard.js +111 -6
  121. package/dist/migration-seq-guard.js.map +1 -1
  122. package/dist/output-diagnostics.d.ts +15 -0
  123. package/dist/output-diagnostics.d.ts.map +1 -0
  124. package/dist/output-diagnostics.js +95 -0
  125. package/dist/output-diagnostics.js.map +1 -0
  126. package/dist/pr-open-guard.d.ts +67 -0
  127. package/dist/pr-open-guard.d.ts.map +1 -0
  128. package/dist/pr-open-guard.js +79 -0
  129. package/dist/pr-open-guard.js.map +1 -0
  130. package/dist/prepr-gate.d.ts +229 -1
  131. package/dist/prepr-gate.d.ts.map +1 -1
  132. package/dist/prepr-gate.js +406 -3
  133. package/dist/prepr-gate.js.map +1 -1
  134. package/dist/program.d.ts.map +1 -1
  135. package/dist/program.js +43 -5
  136. package/dist/program.js.map +1 -1
  137. package/dist/provider-auth.d.ts +27 -0
  138. package/dist/provider-auth.d.ts.map +1 -1
  139. package/dist/provider-auth.js +33 -0
  140. package/dist/provider-auth.js.map +1 -1
  141. package/dist/runtime/cache-dir.d.ts.map +1 -1
  142. package/dist/runtime/cache-dir.js +8 -3
  143. package/dist/runtime/cache-dir.js.map +1 -1
  144. package/dist/runtime/decision-provenance.d.ts +63 -0
  145. package/dist/runtime/decision-provenance.d.ts.map +1 -0
  146. package/dist/runtime/decision-provenance.js +107 -0
  147. package/dist/runtime/decision-provenance.js.map +1 -0
  148. package/dist/runtime/prompt-substitute.d.ts +100 -0
  149. package/dist/runtime/prompt-substitute.d.ts.map +1 -0
  150. package/dist/runtime/prompt-substitute.js +124 -0
  151. package/dist/runtime/prompt-substitute.js.map +1 -0
  152. package/dist/runtime/quarantine.d.ts +11 -0
  153. package/dist/runtime/quarantine.d.ts.map +1 -1
  154. package/dist/runtime/quarantine.js +16 -1
  155. package/dist/runtime/quarantine.js.map +1 -1
  156. package/dist/runtime/review-cost-cap.d.ts +167 -0
  157. package/dist/runtime/review-cost-cap.d.ts.map +1 -0
  158. package/dist/runtime/review-cost-cap.js +182 -0
  159. package/dist/runtime/review-cost-cap.js.map +1 -0
  160. package/dist/runtime/reviewer-abstain.d.ts +101 -0
  161. package/dist/runtime/reviewer-abstain.d.ts.map +1 -0
  162. package/dist/runtime/reviewer-abstain.js +138 -0
  163. package/dist/runtime/reviewer-abstain.js.map +1 -0
  164. package/dist/runtime/reviewer.d.ts +165 -2
  165. package/dist/runtime/reviewer.d.ts.map +1 -1
  166. package/dist/runtime/reviewer.js +752 -111
  167. package/dist/runtime/reviewer.js.map +1 -1
  168. package/dist/runtime/running-build.d.ts +24 -0
  169. package/dist/runtime/running-build.d.ts.map +1 -0
  170. package/dist/runtime/running-build.js +62 -0
  171. package/dist/runtime/running-build.js.map +1 -0
  172. package/dist/runtime/singleton.d.ts.map +1 -1
  173. package/dist/runtime/singleton.js +9 -1
  174. package/dist/runtime/singleton.js.map +1 -1
  175. package/dist/runtime/worktree.d.ts +45 -0
  176. package/dist/runtime/worktree.d.ts.map +1 -1
  177. package/dist/runtime/worktree.js +174 -5
  178. package/dist/runtime/worktree.js.map +1 -1
  179. package/dist/serving-auth/index.d.ts +79 -0
  180. package/dist/serving-auth/index.d.ts.map +1 -0
  181. package/dist/serving-auth/index.js +169 -0
  182. package/dist/serving-auth/index.js.map +1 -0
  183. package/dist/task-runner.d.ts +134 -5
  184. package/dist/task-runner.d.ts.map +1 -1
  185. package/dist/task-runner.js +1255 -129
  186. package/dist/task-runner.js.map +1 -1
  187. package/dist/types.d.ts +8 -0
  188. package/dist/types.d.ts.map +1 -1
  189. package/dist/watch-chat/wire.d.ts +80 -0
  190. package/dist/watch-chat/wire.d.ts.map +1 -1
  191. package/dist/watch-chat/wire.js +203 -43
  192. package/dist/watch-chat/wire.js.map +1 -1
  193. package/dist/watch.d.ts +70 -16
  194. package/dist/watch.d.ts.map +1 -1
  195. package/dist/watch.js +548 -108
  196. package/dist/watch.js.map +1 -1
  197. package/package.json +4 -3
@@ -0,0 +1,70 @@
1
+ /** Heading of the generated section. Matched case-insensitively on splice. */
2
+ export declare const LOC_ADVISORY_HEADING = "## LOC advisory";
3
+ /** `kind` of the structured task_event emitted alongside the section. */
4
+ export declare const LOC_ADVISORY_EVENT_KIND = "loc_advisory";
5
+ /** House guideline (CLAUDE.md "≤300 LOC per commit"), read as IMPL lines. */
6
+ export declare const HOUSE_IMPL_LOC_GUIDELINE = 300;
7
+ /** Added/removed lines of a diff, split into implementation vs test files. */
8
+ export interface LocSplit {
9
+ /** Added lines: non-test / test / both, then removed lines (never budgeted). */
10
+ impl: number;
11
+ tests: number;
12
+ total: number;
13
+ removed: number;
14
+ }
15
+ /** LOC ceilings declared by a task's acceptance criteria; null = undeclared. */
16
+ export type LocCeilings = {
17
+ impl: number | null;
18
+ total: number | null;
19
+ };
20
+ /** A computed overage. Only ever constructed when a ceiling is exceeded. */
21
+ export interface LocAdvisory extends LocSplit {
22
+ /** Effective impl ceiling — declared, else HOUSE_IMPL_LOC_GUIDELINE. */
23
+ ceiling: number;
24
+ /** Declared total ceiling (null = undeclared), and where `ceiling` came from. */
25
+ totalCeiling: number | null;
26
+ ceilingSource: "declared" | "house";
27
+ /** Which ceilings are exceeded, in report order. Never empty. */
28
+ exceeded: Array<"impl" | "total">;
29
+ }
30
+ /**
31
+ * True when a repo-relative path is a TEST file: anything under a `tests/` /
32
+ * `__tests__/` dir at any depth, or a `*.test.*` / `*.spec.*` basename.
33
+ * Backslashes are normalised so a Windows-shaped path classifies identically.
34
+ */
35
+ export declare function isTestPath(path: string | null | undefined): boolean;
36
+ /**
37
+ * Split a unified diff into impl vs test line counts. Binary files contribute
38
+ * nothing — the same convention the Files-changed table uses.
39
+ */
40
+ export declare function splitDiffLoc(diff: string | null | undefined): LocSplit;
41
+ /**
42
+ * Parse the LOC ceilings a task declared in its acceptance criteria — the
43
+ * `<= N LOC` family named in the spec ("Implementation (non-test) additions
44
+ * <= 250; total diff <= 450 LOC", "LOC budget: implementation <= 250", or a
45
+ * bare "<= 300 LOC"). A criterion must mention LOC / lines / additions before
46
+ * any of its `<= N` clauses count — otherwise "retries <= 3" reads as a budget.
47
+ * Each clause (delimited by `;`, `,`, `.`) binds to a bucket by the qualifier
48
+ * words before its operator; an UNQUALIFIED ceiling fills `impl` first (the
49
+ * house guideline is itself impl-shaped), then `total`. First one per bucket wins.
50
+ */
51
+ export declare function parseLocCeilings(acceptance: readonly string[] | null | undefined): LocCeilings;
52
+ /**
53
+ * Measure a pushed diff against the task's ceilings. Returns `null` — the common
54
+ * case — when nothing is exceeded, so the caller emits nothing at all.
55
+ */
56
+ export declare function evaluateLocAdvisory(diff: string | null | undefined, acceptance: readonly string[] | null | undefined): LocAdvisory | null;
57
+ /** The `loc_advisory` task_event payload (snake_case, like its peers). */
58
+ export declare function locAdvisoryEventPayload(a: LocAdvisory): Record<string, unknown>;
59
+ /**
60
+ * Render the `## LOC advisory` section — deliberately short: state the split,
61
+ * name the ceiling that is over, say plainly that it is not a blocker.
62
+ */
63
+ export declare function renderLocAdvisorySection(a: LocAdvisory): string;
64
+ /**
65
+ * Prepend the advisory to a PR body. Any pre-existing `## LOC advisory` section
66
+ * (up to the next `## ` heading) is REMOVED first, so a re-run can never stack
67
+ * two advisories.
68
+ */
69
+ export declare function prependLocAdvisory(body: string | null | undefined, advisory: LocAdvisory): string;
70
+ //# sourceMappingURL=loc-advisory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loc-advisory.d.ts","sourceRoot":"","sources":["../src/loc-advisory.ts"],"names":[],"mappings":"AAuBA,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AACtD,yEAAyE;AACzE,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AACtD,6EAA6E;AAC7E,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,8EAA8E;AAC9E,MAAM,WAAW,QAAQ;IACvB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAExE,4EAA4E;AAC5E,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,UAAU,GAAG,OAAO,CAAC;IACpC,iEAAiE;IACjE,QAAQ,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;CACnC;AAWD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAMnE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,QAAQ,CAUtE;AAWD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,GAC/C,WAAW,CAuBb;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,GAC/C,WAAW,GAAG,IAAI,CAepB;AAED,0EAA0E;AAC1E,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAW/E;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAkB/D;AAKD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,QAAQ,EAAE,WAAW,GACpB,MAAM,CAYR"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * LOC-ADVISORY-2B — pre-PR LOC advisory, with an impl-vs-test line split.
3
+ *
4
+ * A PR that blows its LOC ceiling is discovered MID-review today: the reviewer
5
+ * reads the diff, notices the overage, and either rejects or grants a
6
+ * `loc_exception` after the fact (api/_lib/automerge-gates.ts). Both outcomes
7
+ * burn a review cycle on something the runner already knew at push time. So
8
+ * before opening the PR the runner measures the pushed diff, splits it into
9
+ * IMPLEMENTATION and TEST lines and — only when a ceiling is exceeded — emits a
10
+ * structured `loc_advisory` task_event and prepends a short `## LOC advisory`
11
+ * section to the PR body, so the overage is granted CONSCIOUSLY. The split
12
+ * matters because tests are the cheapest lines in a diff: 180 impl + 200 test
13
+ * lines is not the review risk that 380 impl lines is, and a single additions
14
+ * number cannot tell them apart.
15
+ *
16
+ * The advisory NEVER blocks. Everything here is pure and dependency-free; the
17
+ * caller wraps it so a parse error, a missing diff, or a failed event RPC all
18
+ * fall through to opening the PR anyway. impl/tests/total count ADDED lines,
19
+ * matching the server-side LOC gate (which budgets `additions`) and the house
20
+ * "≤300 LOC per commit" guideline; removed lines are context, never budgeted.
21
+ */
22
+ import { parseDiffFileStats } from "./pr-body.js";
23
+ /** Heading of the generated section. Matched case-insensitively on splice. */
24
+ export const LOC_ADVISORY_HEADING = "## LOC advisory";
25
+ /** `kind` of the structured task_event emitted alongside the section. */
26
+ export const LOC_ADVISORY_EVENT_KIND = "loc_advisory";
27
+ /** House guideline (CLAUDE.md "≤300 LOC per commit"), read as IMPL lines. */
28
+ export const HOUSE_IMPL_LOC_GUIDELINE = 300;
29
+ /**
30
+ * Dirs whose contents are tests. `tests` is the spec'd one, `__tests__` is
31
+ * unambiguous; a bare `test/` is deliberately absent — it collides with real
32
+ * source dirs too often to assume.
33
+ */
34
+ const TEST_DIR_SEGMENTS = new Set(["tests", "__tests__"]);
35
+ /** `foo.test.ts` / `foo.spec.tsx` — the test marker must precede the extension. */
36
+ const TEST_FILE_RE = /\.(test|spec)\.[^./]+$/i;
37
+ /**
38
+ * True when a repo-relative path is a TEST file: anything under a `tests/` /
39
+ * `__tests__/` dir at any depth, or a `*.test.*` / `*.spec.*` basename.
40
+ * Backslashes are normalised so a Windows-shaped path classifies identically.
41
+ */
42
+ export function isTestPath(path) {
43
+ const p = (path ?? "").replace(/\\/g, "/").trim();
44
+ const segments = p.split("/").filter((s) => s.length > 0 && s !== ".");
45
+ if (segments.length === 0)
46
+ return false;
47
+ if (TEST_FILE_RE.test(segments[segments.length - 1]))
48
+ return true;
49
+ return segments.slice(0, -1).some((s) => TEST_DIR_SEGMENTS.has(s.toLowerCase()));
50
+ }
51
+ /**
52
+ * Split a unified diff into impl vs test line counts. Binary files contribute
53
+ * nothing — the same convention the Files-changed table uses.
54
+ */
55
+ export function splitDiffLoc(diff) {
56
+ const split = { impl: 0, tests: 0, total: 0, removed: 0 };
57
+ for (const stat of parseDiffFileStats(diff)) {
58
+ if (stat.binary)
59
+ continue;
60
+ if (isTestPath(stat.path))
61
+ split.tests += stat.added;
62
+ else
63
+ split.impl += stat.added;
64
+ split.removed += stat.removed;
65
+ }
66
+ split.total = split.impl + split.tests;
67
+ return split;
68
+ }
69
+ /** A criterion only carries a ceiling if it talks about LOC/lines/additions. */
70
+ const LOC_CONTEXT_RE = /\b(loc|lines?|additions?)\b/i;
71
+ /** `<= 250`, `≤250`, `< 450` — the ceiling operators we accept. */
72
+ const CEILING_RE = /(<=|≤|<)\s*(\d{1,6})\b/g;
73
+ /** Words binding a ceiling to the implementation bucket. */
74
+ const IMPL_QUALIFIER_RE = /\b(impl|implementation|non-?test|source|code)\b/i;
75
+ /** Words binding a ceiling to the total bucket. */
76
+ const TOTAL_QUALIFIER_RE = /\b(total|overall|combined|whole|entire|diff)\b/i;
77
+ /**
78
+ * Parse the LOC ceilings a task declared in its acceptance criteria — the
79
+ * `<= N LOC` family named in the spec ("Implementation (non-test) additions
80
+ * <= 250; total diff <= 450 LOC", "LOC budget: implementation <= 250", or a
81
+ * bare "<= 300 LOC"). A criterion must mention LOC / lines / additions before
82
+ * any of its `<= N` clauses count — otherwise "retries <= 3" reads as a budget.
83
+ * Each clause (delimited by `;`, `,`, `.`) binds to a bucket by the qualifier
84
+ * words before its operator; an UNQUALIFIED ceiling fills `impl` first (the
85
+ * house guideline is itself impl-shaped), then `total`. First one per bucket wins.
86
+ */
87
+ export function parseLocCeilings(acceptance) {
88
+ const out = { impl: null, total: null };
89
+ for (const raw of acceptance ?? []) {
90
+ if (typeof raw !== "string" || !LOC_CONTEXT_RE.test(raw))
91
+ continue;
92
+ const text = raw.replace(/\r\n/g, "\n");
93
+ CEILING_RE.lastIndex = 0;
94
+ let m;
95
+ while ((m = CEILING_RE.exec(text)) !== null) {
96
+ const n = Number.parseInt(m[2], 10);
97
+ if (!Number.isFinite(n) || n <= 0)
98
+ continue;
99
+ // The clause is the run of text since the last delimiter — the phrase
100
+ // that qualifies THIS operator ("total diff <=" vs "implementation <=").
101
+ const head = text.slice(0, m.index);
102
+ const clause = head.slice(head.search(/[^;,.\n]*$/));
103
+ if (IMPL_QUALIFIER_RE.test(clause)) {
104
+ if (out.impl === null)
105
+ out.impl = n;
106
+ }
107
+ else if (TOTAL_QUALIFIER_RE.test(clause)) {
108
+ if (out.total === null)
109
+ out.total = n;
110
+ }
111
+ else if (out.impl === null)
112
+ out.impl = n;
113
+ else if (out.total === null)
114
+ out.total = n;
115
+ }
116
+ }
117
+ return out;
118
+ }
119
+ /**
120
+ * Measure a pushed diff against the task's ceilings. Returns `null` — the common
121
+ * case — when nothing is exceeded, so the caller emits nothing at all.
122
+ */
123
+ export function evaluateLocAdvisory(diff, acceptance) {
124
+ const split = splitDiffLoc(diff);
125
+ const declared = parseLocCeilings(acceptance);
126
+ const ceiling = declared.impl ?? HOUSE_IMPL_LOC_GUIDELINE;
127
+ const exceeded = [];
128
+ if (split.impl > ceiling)
129
+ exceeded.push("impl");
130
+ if (declared.total !== null && split.total > declared.total)
131
+ exceeded.push("total");
132
+ if (exceeded.length === 0)
133
+ return null;
134
+ return {
135
+ ...split,
136
+ ceiling,
137
+ totalCeiling: declared.total,
138
+ ceilingSource: declared.impl !== null ? "declared" : "house",
139
+ exceeded,
140
+ };
141
+ }
142
+ /** The `loc_advisory` task_event payload (snake_case, like its peers). */
143
+ export function locAdvisoryEventPayload(a) {
144
+ return {
145
+ impl: a.impl,
146
+ tests: a.tests,
147
+ total: a.total,
148
+ ceiling: a.ceiling,
149
+ total_ceiling: a.totalCeiling,
150
+ ceiling_source: a.ceilingSource,
151
+ exceeded: a.exceeded,
152
+ removed: a.removed,
153
+ };
154
+ }
155
+ /**
156
+ * Render the `## LOC advisory` section — deliberately short: state the split,
157
+ * name the ceiling that is over, say plainly that it is not a blocker.
158
+ */
159
+ export function renderLocAdvisorySection(a) {
160
+ const note = (n, cap, label) => cap === null ? "" : n > cap
161
+ ? ` — **exceeds** the ${label} of ${cap} (over by ${n - cap})`
162
+ : ` (${label} ${cap})`;
163
+ const implLabel = a.ceilingSource === "declared" ? "declared ceiling" : "house guideline";
164
+ return [
165
+ LOC_ADVISORY_HEADING,
166
+ "",
167
+ `- Implementation (non-test) additions: **${a.impl}**${note(a.impl, a.ceiling, implLabel)}`,
168
+ `- Test additions: ${a.tests}`,
169
+ `- Total additions: **${a.total}**${note(a.total, a.totalCeiling, "declared total ceiling")}` +
170
+ ` (removed: ${a.removed})`,
171
+ "",
172
+ "_(Advisory only — it does not block this PR. Grant a `loc_exception` in the " +
173
+ "review verdict if the diff is cohesive, or ask for a split.)_",
174
+ ].join("\n");
175
+ }
176
+ /** Match an existing `## LOC advisory` heading at line start. */
177
+ const HEADING_RE = /^##[ \t]+loc advisory[ \t]*$/im;
178
+ /**
179
+ * Prepend the advisory to a PR body. Any pre-existing `## LOC advisory` section
180
+ * (up to the next `## ` heading) is REMOVED first, so a re-run can never stack
181
+ * two advisories.
182
+ */
183
+ export function prependLocAdvisory(body, advisory) {
184
+ let text = (body ?? "").replace(/\r\n/g, "\n");
185
+ const match = HEADING_RE.exec(text);
186
+ if (match) {
187
+ const after = match.index + match[0].length;
188
+ const next = /^##[ \t]+\S/m.exec(text.slice(after));
189
+ const end = next != null ? after + next.index : text.length;
190
+ text = `${text.slice(0, match.index)}\n${text.slice(end)}`;
191
+ }
192
+ const tail = text.trim();
193
+ const section = renderLocAdvisorySection(advisory);
194
+ return tail.length > 0 ? `${section}\n\n${tail}\n` : `${section}\n`;
195
+ }
196
+ //# sourceMappingURL=loc-advisory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loc-advisory.js","sourceRoot":"","sources":["../src/loc-advisory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,8EAA8E;AAC9E,MAAM,CAAC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC;AACtD,yEAAyE;AACzE,MAAM,CAAC,MAAM,uBAAuB,GAAG,cAAc,CAAC;AACtD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAyB5C;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;AAC1D,mFAAmF;AACnF,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAE/C;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAA+B;IACxD,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACvE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AACnF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAA+B;IAC1D,MAAM,KAAK,GAAa,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACpE,KAAK,MAAM,IAAI,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,MAAM;YAAE,SAAS;QAC1B,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC;;YAChD,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC;QAC9B,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC;IAChC,CAAC;IACD,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;IACvC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gFAAgF;AAChF,MAAM,cAAc,GAAG,8BAA8B,CAAC;AACtD,mEAAmE;AACnE,MAAM,UAAU,GAAG,yBAAyB,CAAC;AAC7C,4DAA4D;AAC5D,MAAM,iBAAiB,GAAG,kDAAkD,CAAC;AAC7E,mDAAmD;AACnD,MAAM,kBAAkB,GAAG,iDAAiD,CAAC;AAE7E;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAgD;IAEhD,MAAM,GAAG,GAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACrD,KAAK,MAAM,GAAG,IAAI,UAAU,IAAI,EAAE,EAAE,CAAC;QACnC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QACnE,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACxC,UAAU,CAAC,SAAS,GAAG,CAAC,CAAC;QACzB,IAAI,CAAyB,CAAC;QAC9B,OAAO,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5C,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC5C,sEAAsE;YACtE,yEAAyE;YACzE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;YACrD,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnC,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI;oBAAE,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;YACtC,CAAC;iBAAM,IAAI,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3C,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI;oBAAE,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;YACxC,CAAC;iBAAM,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI;gBAAE,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;iBACtC,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI;gBAAE,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAA+B,EAC/B,UAAgD;IAEhD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,IAAI,wBAAwB,CAAC;IAC1D,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,IAAI,KAAK,CAAC,IAAI,GAAG,OAAO;QAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK;QAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO;QACL,GAAG,KAAK;QACR,OAAO;QACP,YAAY,EAAE,QAAQ,CAAC,KAAK;QAC5B,aAAa,EAAE,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO;QAC5D,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,uBAAuB,CAAC,CAAc;IACpD,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,aAAa,EAAE,CAAC,CAAC,YAAY;QAC7B,cAAc,EAAE,CAAC,CAAC,aAAa;QAC/B,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,CAAc;IACrD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,GAAkB,EAAE,KAAa,EAAE,EAAE,CAC5D,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;QACzB,CAAC,CAAC,sBAAsB,KAAK,OAAO,GAAG,aAAa,CAAC,GAAG,GAAG,GAAG;QAC9D,CAAC,CAAC,KAAK,KAAK,IAAI,GAAG,GAAG,CAAC;IAC3B,MAAM,SAAS,GACb,CAAC,CAAC,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAC1E,OAAO;QACL,oBAAoB;QACpB,EAAE;QACF,4CAA4C,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE;QAC3F,qBAAqB,CAAC,CAAC,KAAK,EAAE;QAC9B,wBAAwB,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,YAAY,EAAE,wBAAwB,CAAC,EAAE;YAC3F,cAAc,CAAC,CAAC,OAAO,GAAG;QAC5B,EAAE;QACF,8EAA8E;YAC5E,+DAA+D;KAClE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,GAAG,gCAAgC,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAA+B,EAC/B,QAAqB;IAErB,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5C,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QAC5D,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAC7D,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC;AACtE,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Claim-time lock POLICY — runner-side copy.
3
+ *
4
+ * The runner is a standalone published package and MUST NOT import from
5
+ * api/_lib (see capacity-plugin.ts / cost-pricing.ts for the same rule), so this
6
+ * DUPLICATES the pure policy in api/_lib/claim-lock-policy.ts. Keep the two in
7
+ * sync — that api module is the canonical spec, and migration
8
+ * 0353_acc_claim_lock_file_granular.sql mirrors `declaredLockPaths` in SQL
9
+ * (acc._declared_lock_paths) so the DB overlap key is file-granular too.
10
+ *
11
+ * The rule (the bug this fixes): claim-time locking is FILE-granular. A broad
12
+ * directory glob (`api/_lib/**`, `tests/*`) is AUTHORIZATION scope, not lock
13
+ * scope — it acquires no directory-wide lock, so two tasks that share a parent
14
+ * directory but touch disjoint files never serialize. A concrete lock only
15
+ * exists once concrete files are known through the task's declared `allowed[]`
16
+ * or its touched-file reporting.
17
+ */
18
+ /** At most three fast claim attempts against a live lock holder before yielding. */
19
+ export declare const CLAIM_LOCK_MAX_FAST_ATTEMPTS = 3;
20
+ /** Spacing between the fast attempts. */
21
+ export declare const CLAIM_LOCK_FAST_RETRY_MS = 60000;
22
+ /** Bounded back-off once the fast attempts are spent (AC3). */
23
+ export declare const CLAIM_LOCK_YIELD_MS: number;
24
+ /** Per-task claim-loss state, persisted across runTask invocations. */
25
+ export interface ClaimLockLossState {
26
+ attempts: number;
27
+ eventRecorded: boolean;
28
+ firstConflictAtMs: number;
29
+ }
30
+ export interface ClaimLockLossDecision {
31
+ attempts: number;
32
+ eventRecorded: boolean;
33
+ firstConflictAtMs: number;
34
+ nextAttemptAtMs: number;
35
+ /** Non-null once the fast attempts are spent: do not re-attempt before this. */
36
+ yieldUntilMs: number | null;
37
+ /** The single conflict event to record, or null when it was already recorded. */
38
+ event: {
39
+ phase: "claim_locks";
40
+ conflicts: string[];
41
+ message: string;
42
+ } | null;
43
+ }
44
+ /**
45
+ * The concrete file paths a task actually locks at claim time. Broad directory
46
+ * globs are dropped (authorization scope, not lock scope); concrete files from
47
+ * `allowed[]` and any reported `touched` files are kept, de-duplicated, sorted.
48
+ */
49
+ export declare function declaredLockPaths(allowed: readonly string[] | null | undefined, touched?: readonly string[]): string[];
50
+ /**
51
+ * Advance the claim-loss retry state after a file-lock conflict. Returns the
52
+ * back-off decision: fast retries up to CLAIM_LOCK_MAX_FAST_ATTEMPTS, then a
53
+ * bounded yield (AC3), plus the ONE conflict event to record — null after the
54
+ * first, so the caller emits a single event per contention episode (AC4).
55
+ */
56
+ export declare function planClaimLockLoss(previous: ClaimLockLossState | null | undefined, conflicts: readonly string[], nowMs: number): ClaimLockLossDecision;
57
+ /**
58
+ * Clear the claim-loss state after a SUCCESSFUL claim so the next contention
59
+ * episode starts over — attempts back to 1 and a fresh conflict event emitted.
60
+ * `planClaimLockLoss` only ever advances state (attempts saturate at the cap,
61
+ * `eventRecorded` stays true), so without an explicit reset a task that once
62
+ * lost a claim could never resume fast attempts or re-open an event for the
63
+ * life of the state. Callers pass the result (null) back as `previous` on the
64
+ * next episode; passing null directly is equivalent.
65
+ */
66
+ export declare function resetClaimLockLoss(): ClaimLockLossState | null;
67
+ //# sourceMappingURL=claim-lock-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claim-lock-policy.d.ts","sourceRoot":"","sources":["../../src/locks/claim-lock-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,oFAAoF;AACpF,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,yCAAyC;AACzC,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAC/C,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,QAAa,CAAC;AAE9C,uEAAuE;AACvE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iFAAiF;IACjF,KAAK,EACD;QACE,KAAK,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;KACjB,GACD,IAAI,CAAC;CACV;AAyDD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,EAC7C,OAAO,GAAE,SAAS,MAAM,EAAO,GAC9B,MAAM,EAAE,CAOV;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,EAC/C,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,KAAK,EAAE,MAAM,GACZ,qBAAqB,CAsBvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,kBAAkB,GAAG,IAAI,CAE9D"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Claim-time lock POLICY — runner-side copy.
3
+ *
4
+ * The runner is a standalone published package and MUST NOT import from
5
+ * api/_lib (see capacity-plugin.ts / cost-pricing.ts for the same rule), so this
6
+ * DUPLICATES the pure policy in api/_lib/claim-lock-policy.ts. Keep the two in
7
+ * sync — that api module is the canonical spec, and migration
8
+ * 0353_acc_claim_lock_file_granular.sql mirrors `declaredLockPaths` in SQL
9
+ * (acc._declared_lock_paths) so the DB overlap key is file-granular too.
10
+ *
11
+ * The rule (the bug this fixes): claim-time locking is FILE-granular. A broad
12
+ * directory glob (`api/_lib/**`, `tests/*`) is AUTHORIZATION scope, not lock
13
+ * scope — it acquires no directory-wide lock, so two tasks that share a parent
14
+ * directory but touch disjoint files never serialize. A concrete lock only
15
+ * exists once concrete files are known through the task's declared `allowed[]`
16
+ * or its touched-file reporting.
17
+ */
18
+ /** At most three fast claim attempts against a live lock holder before yielding. */
19
+ export const CLAIM_LOCK_MAX_FAST_ATTEMPTS = 3;
20
+ /** Spacing between the fast attempts. */
21
+ export const CLAIM_LOCK_FAST_RETRY_MS = 60_000;
22
+ /** Bounded back-off once the fast attempts are spent (AC3). */
23
+ export const CLAIM_LOCK_YIELD_MS = 5 * 60_000;
24
+ // ── shared file-lock scope helpers ──────────────────────────────────────────
25
+ // The block from EXTENSIONLESS_LOCK_FILENAMES through declaredLockPaths is kept
26
+ // BYTE-IDENTICAL with api/_lib/claim-lock-policy.ts (the canonical spec) and
27
+ // acc._declared_lock_paths in the migration. tests/unit/claim-lock-policy.test.ts
28
+ // runs BOTH copies over one shared input table and asserts identical output, so
29
+ // the three normalizers can never silently diverge into two different lock keys.
30
+ /**
31
+ * Canonical extensionless filenames that ARE concrete file locks despite having
32
+ * no dotted extension. Without this set they are indistinguishable from a bare
33
+ * directory and would be silently dropped from lock scope, so two tasks editing
34
+ * the same one would both claim. Kept small and closed — only conventional,
35
+ * unambiguous filenames.
36
+ */
37
+ const EXTENSIONLESS_LOCK_FILENAMES = new Set([
38
+ "Dockerfile",
39
+ "Makefile",
40
+ "Rakefile",
41
+ "Gemfile",
42
+ "Procfile",
43
+ "Brewfile",
44
+ "Vagrantfile",
45
+ "Jenkinsfile",
46
+ "Caddyfile",
47
+ "LICENSE",
48
+ "NOTICE",
49
+ "CODEOWNERS",
50
+ ]);
51
+ /** The wildcard-free leading token of a raw allowed[] entry, path-normalized. */
52
+ function normalizePath(raw) {
53
+ const first = (raw ?? "").trim().split(/\s+/)[0] ?? "";
54
+ return first
55
+ .replace(/^\.\//, "")
56
+ .replace(/^\/+/, "")
57
+ .replace(/\/{2,}/g, "/")
58
+ .replace(/\/+$/, "");
59
+ }
60
+ /**
61
+ * True for a concrete file path — one that names a single file, not a directory
62
+ * or wildcard scope. A basename counts as a file when it carries a dotted
63
+ * extension, is a dotfile (`.env`, `.gitignore`), or is a canonical
64
+ * extensionless filename (Dockerfile, Makefile, …). A bare directory
65
+ * (`api/_lib`) has none of those and is authorization scope, not a lock. The
66
+ * `.` and `..` path segments are never files.
67
+ */
68
+ function isConcreteFilePath(path) {
69
+ if (!path || path.includes("*") || path.endsWith("/"))
70
+ return false;
71
+ const base = path.split("/").pop() ?? "";
72
+ if (base === "" || base === "." || base === "..")
73
+ return false;
74
+ if (EXTENSIONLESS_LOCK_FILENAMES.has(base))
75
+ return true;
76
+ return base.includes(".");
77
+ }
78
+ /**
79
+ * The concrete file paths a task actually locks at claim time. Broad directory
80
+ * globs are dropped (authorization scope, not lock scope); concrete files from
81
+ * `allowed[]` and any reported `touched` files are kept, de-duplicated, sorted.
82
+ */
83
+ export function declaredLockPaths(allowed, touched = []) {
84
+ const paths = new Set();
85
+ for (const raw of [...(allowed ?? []), ...touched]) {
86
+ const path = normalizePath(raw);
87
+ if (isConcreteFilePath(path))
88
+ paths.add(path);
89
+ }
90
+ return [...paths].sort();
91
+ }
92
+ /**
93
+ * Advance the claim-loss retry state after a file-lock conflict. Returns the
94
+ * back-off decision: fast retries up to CLAIM_LOCK_MAX_FAST_ATTEMPTS, then a
95
+ * bounded yield (AC3), plus the ONE conflict event to record — null after the
96
+ * first, so the caller emits a single event per contention episode (AC4).
97
+ */
98
+ export function planClaimLockLoss(previous, conflicts, nowMs) {
99
+ const attempts = Math.min((previous?.attempts ?? 0) + 1, CLAIM_LOCK_MAX_FAST_ATTEMPTS);
100
+ const alreadyRecorded = previous?.eventRecorded === true;
101
+ const firstConflictAtMs = previous?.firstConflictAtMs ?? nowMs;
102
+ const boundedYield = attempts >= CLAIM_LOCK_MAX_FAST_ATTEMPTS;
103
+ const uniqueConflicts = [...new Set(conflicts.filter(Boolean))].sort();
104
+ const nextAttemptAtMs = nowMs + (boundedYield ? CLAIM_LOCK_YIELD_MS : CLAIM_LOCK_FAST_RETRY_MS);
105
+ return {
106
+ attempts,
107
+ eventRecorded: true,
108
+ firstConflictAtMs,
109
+ nextAttemptAtMs,
110
+ yieldUntilMs: boundedYield ? nextAttemptAtMs : null,
111
+ event: alreadyRecorded
112
+ ? null
113
+ : {
114
+ phase: "claim_locks",
115
+ conflicts: uniqueConflicts,
116
+ message: `file-lock conflict with: ${uniqueConflicts.join(", ") || "(unknown)"}`,
117
+ },
118
+ };
119
+ }
120
+ /**
121
+ * Clear the claim-loss state after a SUCCESSFUL claim so the next contention
122
+ * episode starts over — attempts back to 1 and a fresh conflict event emitted.
123
+ * `planClaimLockLoss` only ever advances state (attempts saturate at the cap,
124
+ * `eventRecorded` stays true), so without an explicit reset a task that once
125
+ * lost a claim could never resume fast attempts or re-open an event for the
126
+ * life of the state. Callers pass the result (null) back as `previous` on the
127
+ * next episode; passing null directly is equivalent.
128
+ */
129
+ export function resetClaimLockLoss() {
130
+ return null;
131
+ }
132
+ //# sourceMappingURL=claim-lock-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claim-lock-policy.js","sourceRoot":"","sources":["../../src/locks/claim-lock-policy.ts"],"names":[],"mappings":"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"}
package/dist/login.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { type ConcurrencySource, type RunnerConcurrency } from "./config.js";
1
+ import { type ConcurrencySource, type RunnerConcurrency, type RunnerConfig } from "./config.js";
2
2
  import type { RunnerCaps } from "./types.js";
3
+ import { type RunnerBuildCaps } from "./build-fingerprint.js";
4
+ import { type CredentialIdentity } from "./credential-identity.js";
3
5
  export declare const RUNNER_CAPS: RunnerCaps;
4
6
  /**
5
7
  * Repo-scoped routing — build the register_runner `p_caps` payload with
@@ -33,13 +35,60 @@ export declare const RUNNER_CAPS: RunnerCaps;
33
35
  * advertised number can never drift from the number the runner actually runs.
34
36
  * Both keys are additive to the frozen caps shape — a pure superset.
35
37
  */
36
- export declare function runnerCapsWithRepos(repos: readonly string[] | undefined, engines?: readonly string[] | undefined, conc?: RunnerConcurrency, source?: ConcurrencySource): RunnerCaps & {
38
+ export declare function runnerCapsWithRepos(repos: readonly string[] | undefined, engines?: readonly string[] | undefined, conc?: RunnerConcurrency, source?: ConcurrencySource, processCapabilities?: readonly string[], identity?: CredentialIdentity, build?: RunnerBuildCaps): RunnerCaps & {
37
39
  repos: string[];
38
40
  engines: string[];
41
+ process_capabilities: string[];
39
42
  concurrency: number;
40
43
  reserved_review_slots: number;
41
44
  concurrency_source: ConcurrencySource;
45
+ account_email: string | null;
46
+ account_org: string | null;
47
+ credential_source: CredentialIdentity["credential_source"];
48
+ build?: RunnerBuildCaps;
42
49
  };
50
+ /**
51
+ * CAPS-ENGINES-STALE-KEYCHAIN-1 (AC10): the SINGLE `register_runner` `p_caps`
52
+ * builder shared by the `login` CLI and the watch-boot register, so the two
53
+ * cannot drift for the same environment. Merged with the upstream caps shape:
54
+ * it also folds liveProcessCapabilities(cfg), the resolved credential identity
55
+ * (capacity-attribution), and the build fingerprint — the caller resolves the
56
+ * async `identity`/`build` once and passes them so both paths publish an
57
+ * identical rich caps payload.
58
+ */
59
+ export declare function registerRunnerCaps(cfg: Pick<RunnerConfig, "repos" | "capabilities">, engines: readonly string[], conc: RunnerConcurrency, identity: CredentialIdentity, build: RunnerBuildCaps | undefined): ReturnType<typeof runnerCapsWithRepos>;
60
+ /**
61
+ * REGISTER-CAPS-PRESERVE-1 — the `p_capabilities` array every `register_runner`
62
+ * call must send. Neither call site passed the argument at all, so PostgREST
63
+ * omitted it, the RPC took its `text[] default '{}'` and the 0114/0153 body
64
+ * wrote that empty array straight over acc.runners.capabilities: a runner
65
+ * dispatchable for seven tags came back matching only tasks with an EMPTY
66
+ * required_capabilities — nothing the board queues. Migration 0349 makes the
67
+ * server refuse to shrink; this stops the client asking, which is what keeps
68
+ * 0349's activity-event alarm quiet in steady state. Same set that
69
+ * `set_runner_capabilities` publishes (ACC_RUNNER_CAPABILITIES > config.json >
70
+ * profile > []), so register and refresh can never disagree. Empty stays empty
71
+ * on the wire: 0349 reads it as "preserve", and on a FRESH row it is the 0114
72
+ * backward-compat default.
73
+ */
74
+ export declare function advertisedCapabilities(cfg: Pick<RunnerConfig, "capabilities">): string[];
75
+ /**
76
+ * M5 (CODEX-DISPATCH-WIRE-1): the runner's LIVE process capabilities, published
77
+ * as `caps.process_capabilities` for the capability-divergence report (#2131).
78
+ * Advertised capabilities are static config (`ACC_RUNNER_CAPABILITIES`); the
79
+ * live set drops any advertised tag that names a batch engine THIS runner's
80
+ * registry does not currently register — e.g. a config advertising `codex`
81
+ * while `ACC_ENGINE_CODEX_ENABLED` is off. Publishing the config value verbatim
82
+ * (the pre-M5 behaviour) made `advertised == process` always, so `stale_config`
83
+ * could never fire; deriving it from `engineIds()` is what lets the fleet report
84
+ * surface a disabled/unregistered Codex runner whose advertised caps are stale.
85
+ * Non-engine tags (e.g. `code`, `migration`, `review`) pass through untouched.
86
+ */
87
+ export declare function liveProcessCapabilities(cfg: Pick<RunnerConfig, "capabilities">, registeredEngineIds?: readonly string[]): string[];
88
+ /** The `machine` string the server dedups identity on. NAMED-INSTANCES-1
89
+ * appends `#<name>` so each instance resolves its own stable runner id;
90
+ * unnamed = the v0.44.0 string byte-for-byte. Every caller shares this fn so
91
+ * the suffix can never reach some payloads and not others. */
43
92
  export declare function machineIdentity(): string;
44
93
  export declare function detectInstalledModels(): Promise<string[]>;
45
94
  /**
@@ -91,6 +140,18 @@ export interface LoginOptions extends BrowserOpenContext {
91
140
  timeoutSeconds?: number;
92
141
  /** Injectable `open` (tests). Defaults to the real `open` package. */
93
142
  openBrowser?: (url: string) => Promise<unknown>;
143
+ /**
144
+ * AC10/AC11: engine-detection seam (mirrors WatchOptions.detectEngines).
145
+ * Defaults to the real detectCapableEngines; a test injects the same probe
146
+ * into login and watch to compare the two real caps paths without a mock.
147
+ */
148
+ detectEngines?: () => Promise<string[]>;
149
+ /**
150
+ * Injectable default-engine executable preflight. Production resolves `claude`
151
+ * before registering so a machine that cannot run the default engine fails the
152
+ * login loudly instead of registering a runner that can only fail at dispatch.
153
+ */
154
+ claudePreflight?: () => void;
94
155
  }
95
156
  export declare function loginCommand(options?: LoginOptions): Promise<void>;
96
157
  //# sourceMappingURL=login.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAaA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAIrB,OAAO,KAAK,EAGV,UAAU,EACX,MAAM,YAAY,CAAC;AAOpB,eAAO,MAAM,WAAW,EAAE,UAczB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EACpC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EACvC,IAAI,GAAE,iBAA8C,EAKpD,MAAM,GAAE,iBAAgE,GACvE,UAAU,GAAG;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,iBAAiB,CAAC;CACvC,CASA;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAGD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAe/D;AAoBD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AASD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,kBAAuB,GAAG,MAAM,GAAG,IAAI,CAWhF;AAED,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,kBAAuB,GAAG,OAAO,CAEvE;AAED,MAAM,WAAW,uBAAwB,SAAQ,kBAAkB;IACjE,sEAAsE;IACtE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACjD;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD,gEAAgE;IAChE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACjD;AAED,wBAAsB,YAAY,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0H5E"}
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"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"}