@tokenfactory/acc-runner 0.14.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/failure-classifier.d.ts +71 -13
- package/dist/failure-classifier.d.ts.map +1 -1
- package/dist/failure-classifier.js +203 -15
- package/dist/failure-classifier.js.map +1 -1
- package/dist/runtime/resolution-integrity.d.ts +86 -0
- package/dist/runtime/resolution-integrity.d.ts.map +1 -0
- package/dist/runtime/resolution-integrity.js +248 -0
- package/dist/runtime/resolution-integrity.js.map +1 -0
- package/dist/runtime/reviewer.d.ts +8 -1
- package/dist/runtime/reviewer.d.ts.map +1 -1
- package/dist/runtime/reviewer.js +18 -0
- package/dist/runtime/reviewer.js.map +1 -1
- package/dist/task-runner.d.ts +99 -1
- package/dist/task-runner.d.ts.map +1 -1
- package/dist/task-runner.js +345 -21
- package/dist/task-runner.js.map +1 -1
- package/dist/watch.d.ts +25 -0
- package/dist/watch.d.ts.map +1 -1
- package/dist/watch.js +295 -32
- package/dist/watch.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -238,6 +238,35 @@ remain uncovered by its budget/backoff. The client is the sanctioned path
|
|
|
238
238
|
for any future **direct** REST call (`fetch` against `api.github.com`) the
|
|
239
239
|
runner adds.
|
|
240
240
|
|
|
241
|
+
## Conflict-resolution integrity guardrail (v0.57, T-57-2)
|
|
242
|
+
|
|
243
|
+
When a Claude/worktree task whose job is to **resolve a merge conflict**
|
|
244
|
+
finishes, the runner does not trust the agent's self-reported gate results.
|
|
245
|
+
Before the resolution is pushed, `src/runtime/resolution-integrity.ts`
|
|
246
|
+
re-verifies it from the runner's own vantage point. The invariant —
|
|
247
|
+
**a conflict resolution is shippable only if all three hold**:
|
|
248
|
+
|
|
249
|
+
1. **Zero conflict markers** remain in any tracked file
|
|
250
|
+
(`<<<<<<<` / `=======` / `>>>>>>>`).
|
|
251
|
+
2. **`pnpm typecheck` passes** (or the task's `typecheck_cmd`).
|
|
252
|
+
3. **No version regression**: if a `package.json` `"version"` changed in the
|
|
253
|
+
resolution it must move **forward** (semver-greater than the base ref,
|
|
254
|
+
never backward) **and** `CHANGELOG.md` must carry a matching entry for the
|
|
255
|
+
new version.
|
|
256
|
+
|
|
257
|
+
On ANY failure the resolution is **rejected**: the runner does not push and
|
|
258
|
+
does not mark the task resolved. The task transitions to `failed` (so it is
|
|
259
|
+
reworked, not merged broken), an `append_task_event` of kind
|
|
260
|
+
`resolution_integrity_failed` records the offending assertion(s), and a
|
|
261
|
+
`conflict.integrity_rejected` activity event surfaces it to the operator. A
|
|
262
|
+
guardrail that itself errors **fails closed** (rejects). The check is a no-op
|
|
263
|
+
for every non-conflict task — it is gated by `isConflictResolutionTask`.
|
|
264
|
+
|
|
265
|
+
This exists because v0.55–v0.56 agent resolutions repeatedly shipped broken
|
|
266
|
+
merges that were still marked "resolved": stale-variable splices
|
|
267
|
+
(task-runner.ts), duplicate declarations (health.ts), and a silently dropped
|
|
268
|
+
version bump (#496 reverted `package.json` 0.14.0 → 0.13.0).
|
|
269
|
+
|
|
241
270
|
## Security notes
|
|
242
271
|
|
|
243
272
|
- The CLI never reads or writes your git, gh, or Anthropic credentials.
|
|
@@ -1,20 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* v0.48: classify a non-zero claude CLI exit into one of
|
|
2
|
+
* v0.48: classify a non-zero claude CLI exit into one of five categories
|
|
3
3
|
* so the watch loop can distinguish machine-level failures (which should
|
|
4
4
|
* quarantine the runner) from genuine task errors (which count toward the
|
|
5
|
-
* task's retry budget)
|
|
5
|
+
* task's retry budget) and from a spent capacity window (which should
|
|
6
|
+
* PAUSE, not quarantine).
|
|
6
7
|
*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
8
|
+
* The six classes:
|
|
9
|
+
* capacity_exhausted — Claude/Anthropic session or usage limit reached
|
|
10
|
+
* (api_error_status 429 + a "resets <time>" message).
|
|
11
|
+
* A NEW v0.56 (T-56-1) retryable-infra class: capacity is
|
|
12
|
+
* a resource, not a failure. NEVER task_error and NEVER
|
|
13
|
+
* quarantine — the runner pauses claiming until the stated
|
|
14
|
+
* reset time (or a default backoff) then resumes with a
|
|
15
|
+
* single probe. Root cause of the 2026-06-05 brownout.
|
|
16
|
+
* claude_unavailable — A NEW v0.63 (T-63-1) retryable-infra class: claude
|
|
17
|
+
* exited fast with NO output AND no env/auth/usage signal —
|
|
18
|
+
* the silent instant-empty fingerprint. Pre-v0.63 the pd36
|
|
19
|
+
* heuristic called this env_broken and (after 2 in a row)
|
|
20
|
+
* quarantined the runner; but a brief/silent claude window
|
|
21
|
+
* (a usage blip that exits without a 429, or a momentary API
|
|
22
|
+
* hiccup) presents identically. Silence alone cannot tell
|
|
23
|
+
* "broken host" from "claude momentarily down", so this class
|
|
24
|
+
* is RETRYABLE (pause + backoff + retry, like
|
|
25
|
+
* capacity_exhausted) and NEVER quarantines on its own. The
|
|
26
|
+
* task-runner's `claude --version` health probe is the
|
|
27
|
+
* authoritative tiebreaker: if the probe fails, the host is
|
|
28
|
+
* genuinely broken and the exit is upgraded to env_broken.
|
|
29
|
+
* Root cause of the live T-63-1 self-quarantine incident.
|
|
30
|
+
* usage_limit — A hard Claude/Anthropic plan limit that will NOT reset
|
|
31
|
+
* on its own soon (out of credits, monthly spend cap,
|
|
32
|
+
* quota exhausted). Quarantine is still the right response
|
|
33
|
+
* — an operator has to top up or wait out the billing cycle.
|
|
9
34
|
* auth_expired — API key invalid or session expired on the user's machine.
|
|
10
35
|
* env_broken — Host-side environment failure (dyld, missing binary, OOM).
|
|
11
36
|
* Root cause of the pd36 claim-and-fail storm (INCIDENT_2026-06-02).
|
|
12
37
|
* task_error — Everything else; genuine task-level failure.
|
|
13
38
|
*
|
|
14
|
-
* Only task_error counts toward a task's retry budget.
|
|
15
|
-
* trigger runner quarantine in watch.ts
|
|
39
|
+
* Only task_error counts toward a task's retry budget. usage_limit /
|
|
40
|
+
* auth_expired / env_broken trigger runner quarantine in watch.ts;
|
|
41
|
+
* capacity_exhausted and claude_unavailable trigger the pause/resume path
|
|
42
|
+
* instead (capacity until a reset time, claude_unavailable with an
|
|
43
|
+
* exponential backoff).
|
|
16
44
|
*/
|
|
17
|
-
export type ClaudeExitClass = "usage_limit" | "auth_expired" | "env_broken" | "task_error";
|
|
45
|
+
export type ClaudeExitClass = "capacity_exhausted" | "claude_unavailable" | "usage_limit" | "auth_expired" | "env_broken" | "task_error";
|
|
18
46
|
export interface ClassifiedExit {
|
|
19
47
|
exitCode: number | null;
|
|
20
48
|
class: ClaudeExitClass;
|
|
@@ -24,15 +52,45 @@ export interface ClassifiedExit {
|
|
|
24
52
|
* fast-exit/empty-output heuristic (the pd36 fingerprint), not from a
|
|
25
53
|
* definitive signal (exit 127, a matched dyld/OOM/usage/auth pattern).
|
|
26
54
|
*
|
|
27
|
-
*
|
|
28
|
-
* env_broken
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
55
|
+
* v0.63 T-63-1: the heuristic now yields `claude_unavailable` (retryable),
|
|
56
|
+
* NOT `env_broken` (quarantine). A lone instant-empty exit was always too
|
|
57
|
+
* weak to bench a healthy machine (v0.52 incident (d) — ONE 249ms empty
|
|
58
|
+
* exit quarantined a working box); the live T-63-1 incident proved that
|
|
59
|
+
* even TWO in a row can be a transient/silent claude window rather than a
|
|
60
|
+
* broken host. The task-runner still retries the spawn once, but a
|
|
61
|
+
* confirmed instant-empty streak now routes to pause + backoff + retry and
|
|
62
|
+
* only escalates to env_broken (quarantine) when a `claude --version`
|
|
63
|
+
* health probe ALSO fails. Absent/false on every non-heuristic
|
|
64
|
+
* classification.
|
|
33
65
|
*/
|
|
34
66
|
heuristic?: boolean;
|
|
35
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* v0.56 (T-56-1): pull `api_error_status` out of claude's
|
|
70
|
+
* `--output-format=json` envelope. On a session/usage limit the CLI exits
|
|
71
|
+
* 1 with a JSON object carrying `{ "is_error": true, "api_error_status":
|
|
72
|
+
* 429, "result": "You've hit your session limit - resets 3:20pm
|
|
73
|
+
* (Asia/Calcutta)" }`. Returns the numeric status when present, else null.
|
|
74
|
+
* Kept self-contained (a local parse, no cost-pricing import) so the
|
|
75
|
+
* classifier stays a pure (strings) → class function for unit tests.
|
|
76
|
+
*/
|
|
77
|
+
export declare function parseApiErrorStatus(stdout: string): number | null;
|
|
78
|
+
/**
|
|
79
|
+
* v0.56 (T-56-1): parse the reset time Claude states when it pauses a
|
|
80
|
+
* session ("...resets 3:20pm (Asia/Calcutta)") into an absolute epoch
|
|
81
|
+
* (ms). The runner schedules its capacity resume off this so it wakes
|
|
82
|
+
* exactly when the window reopens rather than guessing a fixed backoff.
|
|
83
|
+
*
|
|
84
|
+
* - 12h ("3:20pm") and 24h ("15:20") clock forms are both accepted.
|
|
85
|
+
* - A parenthetical IANA zone ("(Asia/Calcutta)") is honoured; without
|
|
86
|
+
* one the time is read in the runner's local zone.
|
|
87
|
+
* - The soonest FUTURE occurrence wins: a stated time already past today
|
|
88
|
+
* rolls to tomorrow.
|
|
89
|
+
*
|
|
90
|
+
* Returns null when no reset time is present or the zone is unparseable —
|
|
91
|
+
* the caller then falls back to a default backoff.
|
|
92
|
+
*/
|
|
93
|
+
export declare function extractResetTime(text: string, now?: number): number | null;
|
|
36
94
|
/**
|
|
37
95
|
* Classify a non-zero claude exit.
|
|
38
96
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failure-classifier.d.ts","sourceRoot":"","sources":["../src/failure-classifier.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"failure-classifier.d.ts","sourceRoot":"","sources":["../src/failure-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,MAAM,MAAM,eAAe,GACvB,oBAAoB,GACpB,oBAAoB,GACpB,aAAa,GACb,cAAc,GACd,YAAY,GACZ,YAAY,CAAC;AAEjB,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA0ED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYjE;AA2DD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,GAAG,IAAI,CAiCtF;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,GAClB,cAAc,CAqFhB"}
|
|
@@ -1,19 +1,62 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* v0.48: classify a non-zero claude CLI exit into one of
|
|
2
|
+
* v0.48: classify a non-zero claude CLI exit into one of five categories
|
|
3
3
|
* so the watch loop can distinguish machine-level failures (which should
|
|
4
4
|
* quarantine the runner) from genuine task errors (which count toward the
|
|
5
|
-
* task's retry budget)
|
|
5
|
+
* task's retry budget) and from a spent capacity window (which should
|
|
6
|
+
* PAUSE, not quarantine).
|
|
6
7
|
*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
8
|
+
* The six classes:
|
|
9
|
+
* capacity_exhausted — Claude/Anthropic session or usage limit reached
|
|
10
|
+
* (api_error_status 429 + a "resets <time>" message).
|
|
11
|
+
* A NEW v0.56 (T-56-1) retryable-infra class: capacity is
|
|
12
|
+
* a resource, not a failure. NEVER task_error and NEVER
|
|
13
|
+
* quarantine — the runner pauses claiming until the stated
|
|
14
|
+
* reset time (or a default backoff) then resumes with a
|
|
15
|
+
* single probe. Root cause of the 2026-06-05 brownout.
|
|
16
|
+
* claude_unavailable — A NEW v0.63 (T-63-1) retryable-infra class: claude
|
|
17
|
+
* exited fast with NO output AND no env/auth/usage signal —
|
|
18
|
+
* the silent instant-empty fingerprint. Pre-v0.63 the pd36
|
|
19
|
+
* heuristic called this env_broken and (after 2 in a row)
|
|
20
|
+
* quarantined the runner; but a brief/silent claude window
|
|
21
|
+
* (a usage blip that exits without a 429, or a momentary API
|
|
22
|
+
* hiccup) presents identically. Silence alone cannot tell
|
|
23
|
+
* "broken host" from "claude momentarily down", so this class
|
|
24
|
+
* is RETRYABLE (pause + backoff + retry, like
|
|
25
|
+
* capacity_exhausted) and NEVER quarantines on its own. The
|
|
26
|
+
* task-runner's `claude --version` health probe is the
|
|
27
|
+
* authoritative tiebreaker: if the probe fails, the host is
|
|
28
|
+
* genuinely broken and the exit is upgraded to env_broken.
|
|
29
|
+
* Root cause of the live T-63-1 self-quarantine incident.
|
|
30
|
+
* usage_limit — A hard Claude/Anthropic plan limit that will NOT reset
|
|
31
|
+
* on its own soon (out of credits, monthly spend cap,
|
|
32
|
+
* quota exhausted). Quarantine is still the right response
|
|
33
|
+
* — an operator has to top up or wait out the billing cycle.
|
|
9
34
|
* auth_expired — API key invalid or session expired on the user's machine.
|
|
10
35
|
* env_broken — Host-side environment failure (dyld, missing binary, OOM).
|
|
11
36
|
* Root cause of the pd36 claim-and-fail storm (INCIDENT_2026-06-02).
|
|
12
37
|
* task_error — Everything else; genuine task-level failure.
|
|
13
38
|
*
|
|
14
|
-
* Only task_error counts toward a task's retry budget.
|
|
15
|
-
* trigger runner quarantine in watch.ts
|
|
39
|
+
* Only task_error counts toward a task's retry budget. usage_limit /
|
|
40
|
+
* auth_expired / env_broken trigger runner quarantine in watch.ts;
|
|
41
|
+
* capacity_exhausted and claude_unavailable trigger the pause/resume path
|
|
42
|
+
* instead (capacity until a reset time, claude_unavailable with an
|
|
43
|
+
* exponential backoff).
|
|
16
44
|
*/
|
|
45
|
+
// v0.56 (T-56-1): signatures of a SPENT-BUT-RECOVERABLE capacity window —
|
|
46
|
+
// the session/usage limit Claude resets on a clock (vs. usage_limit below,
|
|
47
|
+
// which is a hard billing wall). These must stay disjoint from the
|
|
48
|
+
// usage_limit patterns so the live 2026-06-05 signature
|
|
49
|
+
// ("You've hit your session limit - resets 3:20pm (Asia/Calcutta)")
|
|
50
|
+
// routes to pause, while "out of credits" / "monthly spend limit" still
|
|
51
|
+
// route to quarantine. The authoritative signal is api_error_status 429 in
|
|
52
|
+
// the result JSON; these message patterns are the fallback when the runner
|
|
53
|
+
// only has plain text (older claude, or the JSON envelope was not emitted).
|
|
54
|
+
const CAPACITY_PATTERNS = [
|
|
55
|
+
/hit your (?:session|usage|account) limit/i,
|
|
56
|
+
/session limit/i,
|
|
57
|
+
/(?:session|usage|account|limit).*resets?\b/i,
|
|
58
|
+
/resets?\s+(?:at\s+)?\d{1,2}(?::\d{2})?\s*(?:am|pm)/i,
|
|
59
|
+
];
|
|
17
60
|
const USAGE_LIMIT_PATTERNS = [
|
|
18
61
|
/usage limit/i,
|
|
19
62
|
/you have reached the maximum number of tokens/i,
|
|
@@ -65,6 +108,129 @@ const FAST_EXIT_MAX_OUTPUT_BYTES = 100;
|
|
|
65
108
|
function matchesAny(text, patterns) {
|
|
66
109
|
return patterns.some((p) => p.test(text));
|
|
67
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* v0.56 (T-56-1): pull `api_error_status` out of claude's
|
|
113
|
+
* `--output-format=json` envelope. On a session/usage limit the CLI exits
|
|
114
|
+
* 1 with a JSON object carrying `{ "is_error": true, "api_error_status":
|
|
115
|
+
* 429, "result": "You've hit your session limit - resets 3:20pm
|
|
116
|
+
* (Asia/Calcutta)" }`. Returns the numeric status when present, else null.
|
|
117
|
+
* Kept self-contained (a local parse, no cost-pricing import) so the
|
|
118
|
+
* classifier stays a pure (strings) → class function for unit tests.
|
|
119
|
+
*/
|
|
120
|
+
export function parseApiErrorStatus(stdout) {
|
|
121
|
+
const trimmed = stdout.trim();
|
|
122
|
+
if (!trimmed.startsWith("{"))
|
|
123
|
+
return null;
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(trimmed);
|
|
126
|
+
const status = parsed?.api_error_status;
|
|
127
|
+
if (typeof status === "number")
|
|
128
|
+
return status;
|
|
129
|
+
if (typeof status === "string" && /^\d+$/.test(status))
|
|
130
|
+
return Number(status);
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const RESET_TIME_RE = /resets?\s+(?:at\s+|by\s+)?(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\s*(?:\(([^)]+)\))?/i;
|
|
138
|
+
function tzDateParts(instant, tz) {
|
|
139
|
+
const dtf = new Intl.DateTimeFormat("en-US", {
|
|
140
|
+
timeZone: tz,
|
|
141
|
+
year: "numeric",
|
|
142
|
+
month: "2-digit",
|
|
143
|
+
day: "2-digit",
|
|
144
|
+
hour: "2-digit",
|
|
145
|
+
minute: "2-digit",
|
|
146
|
+
second: "2-digit",
|
|
147
|
+
hour12: false,
|
|
148
|
+
});
|
|
149
|
+
const map = {};
|
|
150
|
+
for (const p of dtf.formatToParts(instant)) {
|
|
151
|
+
if (p.type !== "literal")
|
|
152
|
+
map[p.type] = p.value;
|
|
153
|
+
}
|
|
154
|
+
// Intl can emit "24" for midnight in hour12:false mode; normalise to 0.
|
|
155
|
+
const hour = Number(map.hour) === 24 ? 0 : Number(map.hour);
|
|
156
|
+
return {
|
|
157
|
+
year: Number(map.year),
|
|
158
|
+
month: Number(map.month),
|
|
159
|
+
day: Number(map.day),
|
|
160
|
+
hour,
|
|
161
|
+
minute: Number(map.minute),
|
|
162
|
+
second: Number(map.second),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/** Offset (ms) of `tz` relative to UTC at the given instant (east = positive). */
|
|
166
|
+
function zoneOffsetMs(instant, tz) {
|
|
167
|
+
const p = tzDateParts(instant, tz);
|
|
168
|
+
const asUtc = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second);
|
|
169
|
+
return asUtc - instant;
|
|
170
|
+
}
|
|
171
|
+
/** Resolve a wall-clock Y-M-D H:M in `tz` to a UTC epoch (one DST refinement). */
|
|
172
|
+
function wallClockToUtc(year, month, day, hour, minute, tz) {
|
|
173
|
+
const guess = Date.UTC(year, month - 1, day, hour, minute, 0);
|
|
174
|
+
let instant = guess - zoneOffsetMs(guess, tz);
|
|
175
|
+
const off2 = zoneOffsetMs(instant, tz);
|
|
176
|
+
const refined = guess - off2;
|
|
177
|
+
if (refined !== instant)
|
|
178
|
+
instant = refined;
|
|
179
|
+
return instant;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* v0.56 (T-56-1): parse the reset time Claude states when it pauses a
|
|
183
|
+
* session ("...resets 3:20pm (Asia/Calcutta)") into an absolute epoch
|
|
184
|
+
* (ms). The runner schedules its capacity resume off this so it wakes
|
|
185
|
+
* exactly when the window reopens rather than guessing a fixed backoff.
|
|
186
|
+
*
|
|
187
|
+
* - 12h ("3:20pm") and 24h ("15:20") clock forms are both accepted.
|
|
188
|
+
* - A parenthetical IANA zone ("(Asia/Calcutta)") is honoured; without
|
|
189
|
+
* one the time is read in the runner's local zone.
|
|
190
|
+
* - The soonest FUTURE occurrence wins: a stated time already past today
|
|
191
|
+
* rolls to tomorrow.
|
|
192
|
+
*
|
|
193
|
+
* Returns null when no reset time is present or the zone is unparseable —
|
|
194
|
+
* the caller then falls back to a default backoff.
|
|
195
|
+
*/
|
|
196
|
+
export function extractResetTime(text, now = Date.now()) {
|
|
197
|
+
if (!text)
|
|
198
|
+
return null;
|
|
199
|
+
const m = RESET_TIME_RE.exec(text);
|
|
200
|
+
if (!m)
|
|
201
|
+
return null;
|
|
202
|
+
let hour = Number(m[1]);
|
|
203
|
+
const minute = m[2] ? Number(m[2]) : 0;
|
|
204
|
+
const ampm = m[3]?.toLowerCase();
|
|
205
|
+
const tz = m[4]?.trim();
|
|
206
|
+
if (Number.isNaN(hour) || hour > 23 || minute > 59)
|
|
207
|
+
return null;
|
|
208
|
+
if (ampm === "pm" && hour < 12)
|
|
209
|
+
hour += 12;
|
|
210
|
+
if (ampm === "am" && hour === 12)
|
|
211
|
+
hour = 0;
|
|
212
|
+
try {
|
|
213
|
+
if (tz) {
|
|
214
|
+
const today = tzDateParts(now, tz);
|
|
215
|
+
let instant = wallClockToUtc(today.year, today.month, today.day, hour, minute, tz);
|
|
216
|
+
if (instant <= now) {
|
|
217
|
+
const tomorrow = tzDateParts(now + 24 * 3_600_000, tz);
|
|
218
|
+
instant = wallClockToUtc(tomorrow.year, tomorrow.month, tomorrow.day, hour, minute, tz);
|
|
219
|
+
}
|
|
220
|
+
return instant;
|
|
221
|
+
}
|
|
222
|
+
const local = new Date(now);
|
|
223
|
+
local.setHours(hour, minute, 0, 0);
|
|
224
|
+
let instant = local.getTime();
|
|
225
|
+
if (instant <= now)
|
|
226
|
+
instant += 24 * 3_600_000;
|
|
227
|
+
return instant;
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// Unknown/garbled IANA zone — let the caller apply its default backoff.
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
68
234
|
/**
|
|
69
235
|
* Classify a non-zero claude exit.
|
|
70
236
|
*
|
|
@@ -84,6 +250,18 @@ export function classifyClaudeExit(exitCode, stderr, stdout, durationMs) {
|
|
|
84
250
|
};
|
|
85
251
|
}
|
|
86
252
|
const combined = `${stderr}\n${stdout}`;
|
|
253
|
+
// v0.56 (T-56-1): capacity check FIRST so the recoverable session/usage
|
|
254
|
+
// window routes to pause, not quarantine. Authoritative signal is the
|
|
255
|
+
// result JSON's api_error_status 429; the message patterns are the
|
|
256
|
+
// plain-text fallback. Disjoint from USAGE_LIMIT_PATTERNS below, which
|
|
257
|
+
// stay quarantine-worthy (hard billing walls).
|
|
258
|
+
if (parseApiErrorStatus(stdout) === 429 || matchesAny(combined, CAPACITY_PATTERNS)) {
|
|
259
|
+
return {
|
|
260
|
+
exitCode,
|
|
261
|
+
class: "capacity_exhausted",
|
|
262
|
+
detail: "Claude session/usage capacity reached (429) — runner will pause until reset",
|
|
263
|
+
};
|
|
264
|
+
}
|
|
87
265
|
if (matchesAny(combined, USAGE_LIMIT_PATTERNS)) {
|
|
88
266
|
return {
|
|
89
267
|
exitCode,
|
|
@@ -105,21 +283,31 @@ export function classifyClaudeExit(exitCode, stderr, stdout, durationMs) {
|
|
|
105
283
|
detail: "host environment error detected in process output",
|
|
106
284
|
};
|
|
107
285
|
}
|
|
108
|
-
// pd36
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
286
|
+
// pd36 fingerprint: exit almost immediately with near-empty output, and
|
|
287
|
+
// none of the definitive signals above matched (no exit 127, no dyld/OOM,
|
|
288
|
+
// no usage/auth/capacity pattern). A real task failure always produces at
|
|
289
|
+
// least some stdout (the model's preamble + any partial work). Pure silence
|
|
290
|
+
// + fast exit is genuinely ambiguous: it can be a broken host (missing lib,
|
|
291
|
+
// bad PATH) OR a transient/silent claude window (a usage blip that exits
|
|
292
|
+
// without a 429, a momentary API hiccup).
|
|
293
|
+
//
|
|
294
|
+
// v0.63 T-63-1: classify this BARE silent instant-empty exit as the
|
|
295
|
+
// retryable `claude_unavailable`, NOT `env_broken`. Quarantining on silence
|
|
296
|
+
// alone benched a healthy runner in the live T-63-1 incident (claude -p
|
|
297
|
+
// worked seconds later in the same shell). The task-runner pauses + backs
|
|
298
|
+
// off + retries on this class, and only upgrades it to env_broken (the
|
|
299
|
+
// quarantine cause) when a `claude --version` health probe ALSO fails —
|
|
300
|
+
// that probe being the authoritative "is the binary/host actually broken?"
|
|
301
|
+
// tiebreaker. `heuristic: true` is preserved so the runner still applies
|
|
302
|
+
// the retry-once tune before pausing.
|
|
112
303
|
if (durationMs !== undefined &&
|
|
113
304
|
durationMs < FAST_EXIT_MS &&
|
|
114
305
|
stderr.trim().length === 0 &&
|
|
115
306
|
stdout.trim().length < FAST_EXIT_MAX_OUTPUT_BYTES) {
|
|
116
307
|
return {
|
|
117
308
|
exitCode,
|
|
118
|
-
class: "
|
|
119
|
-
detail: `claude exited ${exitCode ?? "signal"} in ${durationMs}ms with empty output (
|
|
120
|
-
// v0.53 T-53-4: flag the heuristic origin so the task-runner applies
|
|
121
|
-
// the "retry once, quarantine only on 2 consecutive" tune rather than
|
|
122
|
-
// benching the machine on a single instant-empty blip.
|
|
309
|
+
class: "claude_unavailable",
|
|
310
|
+
detail: `claude exited ${exitCode ?? "signal"} in ${durationMs}ms with empty output (silent instant-empty — claude momentarily unavailable, retrying)`,
|
|
123
311
|
heuristic: true,
|
|
124
312
|
};
|
|
125
313
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failure-classifier.js","sourceRoot":"","sources":["../src/failure-classifier.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"failure-classifier.js","sourceRoot":"","sources":["../src/failure-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export type IntegrityAssertion = "conflict_markers" | "typecheck" | "version_regression" | "changelog_missing";
|
|
2
|
+
export interface IntegrityFailure {
|
|
3
|
+
assertion: IntegrityAssertion;
|
|
4
|
+
/** Human-readable, log-safe (no secrets) explanation of the failure. */
|
|
5
|
+
detail: string;
|
|
6
|
+
/** Offending tracked files, when the assertion is file-scoped. */
|
|
7
|
+
files?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface ResolutionIntegrityResult {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
/** Assertions that actually ran (version checks skip when nothing changed). */
|
|
12
|
+
checked: IntegrityAssertion[];
|
|
13
|
+
failures: IntegrityFailure[];
|
|
14
|
+
}
|
|
15
|
+
/** A package.json / CHANGELOG.md pair to version-check, relative to workdir. */
|
|
16
|
+
export interface VersionTarget {
|
|
17
|
+
packageJsonPath: string;
|
|
18
|
+
changelogPath: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AssertResolutionOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Base ref the resolution should not regress against (e.g. the integration
|
|
23
|
+
* branch). When omitted, or when the base file can't be read, the version
|
|
24
|
+
* assertion is skipped — never false-failed.
|
|
25
|
+
*/
|
|
26
|
+
baseRef?: string;
|
|
27
|
+
/** Typecheck command (defaults to `pnpm typecheck`). */
|
|
28
|
+
typecheckCmd?: string;
|
|
29
|
+
/**
|
|
30
|
+
* package.json / CHANGELOG.md pairs to version-check. Defaults to the repo
|
|
31
|
+
* root pair. The runner passes the acc-runner package pair (the #496 site).
|
|
32
|
+
*/
|
|
33
|
+
versionTargets?: VersionTarget[];
|
|
34
|
+
}
|
|
35
|
+
export interface ResolutionIntegrityDeps {
|
|
36
|
+
/** Tracked files still carrying a conflict marker. Default: `git grep`. */
|
|
37
|
+
findConflictMarkers?: (workdir: string) => Promise<string[]>;
|
|
38
|
+
/** Run the typecheck command. Default: spawn `pnpm typecheck` in workdir. */
|
|
39
|
+
runTypecheck?: (workdir: string, cmd: string) => Promise<{
|
|
40
|
+
ok: boolean;
|
|
41
|
+
output: string;
|
|
42
|
+
}>;
|
|
43
|
+
/** Resolved (post-resolution, on-disk) version for a target, or null. */
|
|
44
|
+
readResolvedVersion?: (workdir: string, target: VersionTarget) => Promise<string | null>;
|
|
45
|
+
/** Base-ref version for a target, or null when unreadable (→ skip check). */
|
|
46
|
+
readBaseVersion?: (workdir: string, baseRef: string, target: VersionTarget) => Promise<string | null>;
|
|
47
|
+
/** CHANGELOG.md text for a target, or null when absent. */
|
|
48
|
+
readChangelog?: (workdir: string, target: VersionTarget) => Promise<string | null>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Conflict-marker line shape: 7 of the same marker char at the start of a
|
|
52
|
+
* line. `<<<<<<<` and `>>>>>>>` are unambiguous; the `=======` divider is
|
|
53
|
+
* matched only as a whole line so a 7-equals markdown rule plus trailing text
|
|
54
|
+
* does not trip it.
|
|
55
|
+
*/
|
|
56
|
+
export declare const CONFLICT_MARKER_RE: RegExp;
|
|
57
|
+
export declare function textHasConflictMarker(text: string): boolean;
|
|
58
|
+
/** Semver compare (a-b sign); tolerant of pre-release/build suffixes. */
|
|
59
|
+
export declare function cmpSemver(a: string, b: string): number;
|
|
60
|
+
/**
|
|
61
|
+
* True when `changelog` carries an entry for `version`. The version must
|
|
62
|
+
* appear bounded by non-version characters so 0.14.0 does not match inside
|
|
63
|
+
* 0.14.00 or 10.14.0.
|
|
64
|
+
*/
|
|
65
|
+
export declare function changelogMentionsVersion(changelog: string, version: string): boolean;
|
|
66
|
+
export declare const DEFAULT_VERSION_TARGET: VersionTarget;
|
|
67
|
+
/**
|
|
68
|
+
* Assert that a conflict resolution in `workdir` is shippable. Returns a
|
|
69
|
+
* structured result; `ok === false` means the caller MUST reject the
|
|
70
|
+
* resolution (do not push, do not mark resolved).
|
|
71
|
+
*/
|
|
72
|
+
export declare function assertResolutionIntegrity(workdir: string, opts?: AssertResolutionOptions, deps?: ResolutionIntegrityDeps): Promise<ResolutionIntegrityResult>;
|
|
73
|
+
/**
|
|
74
|
+
* True when a task that reaches the worktree/push path is a conflict
|
|
75
|
+
* resolution and must clear the integrity guardrail. `conflict_resolution`
|
|
76
|
+
* task types are handled mechanically upstream and never reach the push path,
|
|
77
|
+
* so the live signal here is the title an operator/manager files when the
|
|
78
|
+
* mechanical resolver bails and a Claude session takes over the merge.
|
|
79
|
+
*/
|
|
80
|
+
export declare function isConflictResolutionTask(task: {
|
|
81
|
+
type?: string | null;
|
|
82
|
+
title?: string | null;
|
|
83
|
+
}): boolean;
|
|
84
|
+
/** One-line, log-safe summary of which assertions failed. */
|
|
85
|
+
export declare function summariseFailures(failures: IntegrityFailure[]): string;
|
|
86
|
+
//# sourceMappingURL=resolution-integrity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolution-integrity.d.ts","sourceRoot":"","sources":["../../src/runtime/resolution-integrity.ts"],"names":[],"mappings":"AAsCA,MAAM,MAAM,kBAAkB,GAC1B,kBAAkB,GAClB,WAAW,GACX,oBAAoB,GACpB,mBAAmB,CAAC;AAExB,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,kBAAkB,CAAC;IAC9B,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,OAAO,CAAC;IACZ,+EAA+E;IAC/E,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7D,6EAA6E;IAC7E,YAAY,CAAC,EAAE,CACb,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,KACR,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9C,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,CACpB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,aAAa,KAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,aAAa,KAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B,2DAA2D;IAC3D,aAAa,CAAC,EAAE,CACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,aAAa,KAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC7B;AAMD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAsC,CAAC;AAEtE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAGT;AAED,eAAO,MAAM,sBAAsB,EAAE,aAGpC,CAAC;AAqGF;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,uBAA4B,EAClC,IAAI,GAAE,uBAA4B,GACjC,OAAO,CAAC,yBAAyB,CAAC,CAgFpC;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,GAAG,OAAO,CAIV;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAEtE"}
|