@cat-factory/executor-harness 1.43.4 → 1.43.8

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/dist/failure.js CHANGED
@@ -1,16 +1,17 @@
1
1
  // Single source of truth for how a job FAILS: the canonical failure-cause vocabulary plus
2
2
  // the watchdog abort-message builders.
3
3
  //
4
- // WHY THIS MODULE EXISTS — the backend classifies a failed job by REGEX-matching the
5
- // harness's free-text `error` string (it has no other signal today):
6
- // - server `ContainerRepoBootstrapper.classifyBootstrapFailure`:
7
- // /inactivity|no agent activity|max duration/i 'timeout', else 'agent'
8
- // - orchestration `job.logic.isContainerEvictionError`: /evicted or crashed/i (FACADE-owned,
9
- // NOT emitted here the harness must keep NOT emitting that phrase for a non-eviction)
10
- // Because those phrases are matched downstream, their wording MUST stay stable. Centralizing
11
- // the builders here keeps the emitted text from drifting away from the regex that reads it.
12
- // Alongside the strings we now also emit a STRUCTURED {@link FailureCause} on the job view so
13
- // the backend can prefer it and treat the regex as a backward-compatible fallback.
4
+ // WHY THIS MODULE EXISTS — a failed job surfaces a STRUCTURED {@link FailureCause} on the job
5
+ // view, and that is the ONLY signal the backend classifies on (`failureKindFromHarnessCause`);
6
+ // the watchdog kills set their cause from `killReason`. Centralizing the cause vocabulary + the
7
+ // abort-message builders here keeps the two in step.
8
+ //
9
+ // The abort-message wording is now HUMAN-READABLE ONLY the backend no longer regex-matches it
10
+ // (the string-fallback classifiers `classify{Agent,Bootstrap,Repair}Failure` were deleted in
11
+ // error-message coverage I5), so it is free to change. The one phrase that stays load-bearing is
12
+ // the facade-owned eviction sentinel `(container evicted or crashed)`, which
13
+ // `job.logic.isContainerEvictionError` still matches for a DISPATCH-time throw that carries no job
14
+ // view — and which the harness must keep NOT emitting for a non-eviction failure.
14
15
  /**
15
16
  * A thrown failure that carries a structured {@link FailureCause}, so a `git` / `api`
16
17
  * operation that fails deep in a helper surfaces its real cause instead of being flattened
@@ -30,17 +31,19 @@ export function failureCauseOf(err) {
30
31
  return err instanceof HarnessFailure ? err.failureCause : undefined;
31
32
  }
32
33
  /**
33
- * The inactivity-watchdog abort message PREFIX. The `no agent activity` phrase is
34
- * regex-matched by the backend's `classifyBootstrapFailure` ( `timeout`); do not reword it.
35
- * The caller appends a `(likely hung ...)` diagnostic clause (phase + last tool) after this,
36
- * so the prefix deliberately stops before the parenthetical (see `runner.ts` drive catch).
34
+ * The inactivity-watchdog abort message PREFIX. Human-readable only now the backend reads the
35
+ * structured `inactivity-timeout` {@link FailureCause}, not this phrase (the string fallback was
36
+ * deleted in error-message coverage I5), so it is free to change. The caller appends a `(likely
37
+ * hung ...)` diagnostic clause (phase + last tool) after this, so the prefix deliberately stops
38
+ * before the parenthetical (see `runner.ts` drive catch).
37
39
  */
38
40
  export function inactivityAbortMessage(inactivityMs) {
39
41
  return `Aborted: no agent activity for ${Math.round(inactivityMs / 1000)}s`;
40
42
  }
41
43
  /**
42
- * The max-duration-watchdog abort message. The `max duration` phrase is regex-matched by the
43
- * backend's `classifyBootstrapFailure` ( `timeout`); do not reword it.
44
+ * The max-duration-watchdog abort message. Human-readable only now the backend reads the
45
+ * structured `max-duration` {@link FailureCause}, not this phrase (the string fallback was deleted
46
+ * in error-message coverage I5), so it is free to change.
44
47
  */
45
48
  export function maxDurationAbortMessage(maxDurationMs) {
46
49
  return `Aborted: exceeded max duration of ${Math.round(maxDurationMs / 1000)}s`;
package/dist/runner.js CHANGED
@@ -219,10 +219,11 @@ export class JobRegistry {
219
219
  }
220
220
  /**
221
221
  * Build the redacted one-line `error`, the structured {@link FailureCause}, and the extended
222
- * `detail` for a failed job. Watchdog kills keep their regex-stable phrase (so the backend's
223
- * `classifyBootstrapFailure` fallback still works) and gain a breadcrumb of where they hung;
224
- * a thrown error keeps its own message and its structured cause when tagged (a git op → `git`,
225
- * an upstream API call → `api`), else `agent`. All strings are credential-scrubbed.
222
+ * `detail` for a failed job. Watchdog kills set their structured cause (`inactivity-timeout` /
223
+ * `max-duration`) the backend classifies on that, so their message is a human-readable
224
+ * breadcrumb of where they hung, no longer a regex-stable phrase; a thrown error keeps its own
225
+ * message and its structured cause when tagged (a git op → `git`, an upstream API call → `api`),
226
+ * else `agent`. All strings are credential-scrubbed.
226
227
  */
227
228
  describeFailure(killReason, error, phase, lastTool, phaseTimingsMs) {
228
229
  // `lastTool` is the last tool that COMPLETED (a span is emitted on tool end), so when the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/executor-harness",
3
- "version": "1.43.4",
3
+ "version": "1.43.8",
4
4
  "description": "Container payload: a thin TypeScript wrapper that runs the Pi coding agent against a cloned repo and opens a PR. Runs in the Cloudflare Container (and, in local native mode, as a host process); carries no secrets.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,10 +24,10 @@
24
24
  "@hono/node-server": "^2.0.8",
25
25
  "@types/node": "^26.1.1",
26
26
  "hono": "^4.12.29",
27
- "typescript": "^6.0.3",
27
+ "typescript": "7.0.2",
28
28
  "vitest": "^4.1.10",
29
- "@cat-factory/server": "0.113.5",
30
- "@cat-factory/spend": "0.12.26"
29
+ "@cat-factory/server": "0.122.0",
30
+ "@cat-factory/spend": "0.12.34"
31
31
  },
32
32
  "scripts": {
33
33
  "build": "tsc -p tsconfig.json",
package/src/failure.ts CHANGED
@@ -1,16 +1,17 @@
1
1
  // Single source of truth for how a job FAILS: the canonical failure-cause vocabulary plus
2
2
  // the watchdog abort-message builders.
3
3
  //
4
- // WHY THIS MODULE EXISTS — the backend classifies a failed job by REGEX-matching the
5
- // harness's free-text `error` string (it has no other signal today):
6
- // - server `ContainerRepoBootstrapper.classifyBootstrapFailure`:
7
- // /inactivity|no agent activity|max duration/i 'timeout', else 'agent'
8
- // - orchestration `job.logic.isContainerEvictionError`: /evicted or crashed/i (FACADE-owned,
9
- // NOT emitted here the harness must keep NOT emitting that phrase for a non-eviction)
10
- // Because those phrases are matched downstream, their wording MUST stay stable. Centralizing
11
- // the builders here keeps the emitted text from drifting away from the regex that reads it.
12
- // Alongside the strings we now also emit a STRUCTURED {@link FailureCause} on the job view so
13
- // the backend can prefer it and treat the regex as a backward-compatible fallback.
4
+ // WHY THIS MODULE EXISTS — a failed job surfaces a STRUCTURED {@link FailureCause} on the job
5
+ // view, and that is the ONLY signal the backend classifies on (`failureKindFromHarnessCause`);
6
+ // the watchdog kills set their cause from `killReason`. Centralizing the cause vocabulary + the
7
+ // abort-message builders here keeps the two in step.
8
+ //
9
+ // The abort-message wording is now HUMAN-READABLE ONLY the backend no longer regex-matches it
10
+ // (the string-fallback classifiers `classify{Agent,Bootstrap,Repair}Failure` were deleted in
11
+ // error-message coverage I5), so it is free to change. The one phrase that stays load-bearing is
12
+ // the facade-owned eviction sentinel `(container evicted or crashed)`, which
13
+ // `job.logic.isContainerEvictionError` still matches for a DISPATCH-time throw that carries no job
14
+ // view — and which the harness must keep NOT emitting for a non-eviction failure.
14
15
 
15
16
  /**
16
17
  * The structured reason a harness job failed, surfaced on the job view's `failureCause`.
@@ -58,18 +59,20 @@ export function failureCauseOf(err: unknown): FailureCause | undefined {
58
59
  }
59
60
 
60
61
  /**
61
- * The inactivity-watchdog abort message PREFIX. The `no agent activity` phrase is
62
- * regex-matched by the backend's `classifyBootstrapFailure` ( `timeout`); do not reword it.
63
- * The caller appends a `(likely hung ...)` diagnostic clause (phase + last tool) after this,
64
- * so the prefix deliberately stops before the parenthetical (see `runner.ts` drive catch).
62
+ * The inactivity-watchdog abort message PREFIX. Human-readable only now the backend reads the
63
+ * structured `inactivity-timeout` {@link FailureCause}, not this phrase (the string fallback was
64
+ * deleted in error-message coverage I5), so it is free to change. The caller appends a `(likely
65
+ * hung ...)` diagnostic clause (phase + last tool) after this, so the prefix deliberately stops
66
+ * before the parenthetical (see `runner.ts` drive catch).
65
67
  */
66
68
  export function inactivityAbortMessage(inactivityMs: number): string {
67
69
  return `Aborted: no agent activity for ${Math.round(inactivityMs / 1000)}s`
68
70
  }
69
71
 
70
72
  /**
71
- * The max-duration-watchdog abort message. The `max duration` phrase is regex-matched by the
72
- * backend's `classifyBootstrapFailure` ( `timeout`); do not reword it.
73
+ * The max-duration-watchdog abort message. Human-readable only now the backend reads the
74
+ * structured `max-duration` {@link FailureCause}, not this phrase (the string fallback was deleted
75
+ * in error-message coverage I5), so it is free to change.
73
76
  */
74
77
  export function maxDurationAbortMessage(maxDurationMs: number): string {
75
78
  return `Aborted: exceeded max duration of ${Math.round(maxDurationMs / 1000)}s`
package/src/runner.ts CHANGED
@@ -368,10 +368,11 @@ export class JobRegistry<TJob = unknown, TResult extends JobResultBase = JobResu
368
368
 
369
369
  /**
370
370
  * Build the redacted one-line `error`, the structured {@link FailureCause}, and the extended
371
- * `detail` for a failed job. Watchdog kills keep their regex-stable phrase (so the backend's
372
- * `classifyBootstrapFailure` fallback still works) and gain a breadcrumb of where they hung;
373
- * a thrown error keeps its own message and its structured cause when tagged (a git op → `git`,
374
- * an upstream API call → `api`), else `agent`. All strings are credential-scrubbed.
371
+ * `detail` for a failed job. Watchdog kills set their structured cause (`inactivity-timeout` /
372
+ * `max-duration`) the backend classifies on that, so their message is a human-readable
373
+ * breadcrumb of where they hung, no longer a regex-stable phrase; a thrown error keeps its own
374
+ * message and its structured cause when tagged (a git op → `git`, an upstream API call → `api`),
375
+ * else `agent`. All strings are credential-scrubbed.
375
376
  */
376
377
  private describeFailure(
377
378
  killReason: 'inactivity' | 'max-duration' | undefined,