@tokenfactory/acc-runner 0.40.26 → 0.40.27

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.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * GIT-AUTH-ALERT: a masked, read-only git-credential health probe.
3
+ *
4
+ * Runs `git ls-remote --heads origin` in the runner's base clone — a dry-run
5
+ * that touches the remote (so an expired/revoked token 403s exactly as a real
6
+ * fetch would) but transfers no objects, so it is cheap enough to run every 60s
7
+ * both to DETECT the initial failure and to poll for RECOVERY. The result is a
8
+ * three-way `{ ok, failureClass, detail }` where `detail` is ALWAYS masked so no
9
+ * credential material (a token embedded in the remote URL, a `x-access-token:…`
10
+ * pair, a raw PAT) can reach a log line, an activity event, or `doctor` output.
11
+ */
12
+ import { execa } from "execa";
13
+ import { buildEnv } from "../bin-resolve.js";
14
+ import { classifyGitFetchError } from "./classify.js";
15
+ /**
16
+ * Redact credential material from arbitrary git output. Covers:
17
+ * - userinfo in URLs: scheme://user:token@host → scheme://***@host
18
+ * - GitHub token shapes anywhere: ghp_/gho_/ghu_/ghs_/ghr_…, github_pat_…
19
+ * Idempotent and never throws; a masked-but-imperfect string is preferred to
20
+ * leaking, so callers can mask defensively at every boundary.
21
+ */
22
+ export function maskGitCredentials(input) {
23
+ if (!input)
24
+ return input;
25
+ let out = input;
26
+ // scheme://userinfo@host — strip everything between the scheme and the '@'.
27
+ out = out.replace(/([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1***@");
28
+ // Bare GitHub token shapes that might appear outside a URL (e.g. in an error).
29
+ out = out.replace(/\bgh[posru]_[A-Za-z0-9]{16,}\b/g, "***");
30
+ out = out.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "***");
31
+ return out;
32
+ }
33
+ /** First non-empty line of a message, masked and length-bounded. */
34
+ function summarize(raw) {
35
+ const firstLine = raw.split(/\r?\n/).find((l) => l.trim().length > 0) ?? raw;
36
+ return maskGitCredentials(firstLine.trim()).slice(0, 300);
37
+ }
38
+ async function defaultRun(repoPath, args) {
39
+ // GIT_TERMINAL_PROMPT=0 → a missing credential fails FAST with "terminal
40
+ // prompts disabled" instead of blocking on an interactive username/password.
41
+ const { stdout } = await execa("git", args, {
42
+ cwd: repoPath,
43
+ env: { ...buildEnv(), GIT_TERMINAL_PROMPT: "0" },
44
+ });
45
+ return { stdout };
46
+ }
47
+ /**
48
+ * Build a `GitAuthProbe` bound to a repo path. `GIT_TERMINAL_PROMPT=0` is forced
49
+ * on so a missing credential fails FAST with "terminal prompts disabled" instead
50
+ * of hanging waiting for an interactive username/password.
51
+ */
52
+ export function makeGitAuthProbe(opts) {
53
+ const run = opts.run ?? defaultRun;
54
+ return async () => {
55
+ try {
56
+ await run(opts.repoPath, ["ls-remote", "--heads", "origin"]);
57
+ return { ok: true, failureClass: null, detail: "ls-remote origin ok" };
58
+ }
59
+ catch (err) {
60
+ const failureClass = classifyGitFetchError(err);
61
+ const message = err?.stderr ??
62
+ err?.message ??
63
+ String(err);
64
+ return {
65
+ ok: false,
66
+ failureClass,
67
+ detail: summarize(typeof message === "string" ? message : String(message)),
68
+ };
69
+ }
70
+ };
71
+ }
72
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../../src/git-auth/probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAA6B,MAAM,eAAe,CAAC;AAcjF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,4EAA4E;IAC5E,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,qCAAqC,EAAE,QAAQ,CAAC,CAAC;IACnE,+EAA+E;IAC/E,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;IAC5D,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAC9D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,oEAAoE;AACpE,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC;IAC7E,OAAO,kBAAkB,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5D,CAAC;AASD,KAAK,UAAU,UAAU,CACvB,QAAgB,EAChB,IAAc;IAEd,yEAAyE;IACzE,6EAA6E;IAC7E,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE;QAC1C,GAAG,EAAE,QAAQ;QACb,GAAG,EAAE,EAAE,GAAG,QAAQ,EAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE;KACjD,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAyB;IACxD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC;IACnC,OAAO,KAAK,IAAI,EAAE;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC7D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;QACzE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,YAAY,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;YAChD,MAAM,OAAO,GACV,GAA+C,EAAE,MAAM;gBACvD,GAAa,EAAE,OAAO;gBACvB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,YAAY;gBACZ,MAAM,EAAE,SAAS,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;aAC3E,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
package/dist/watch.d.ts CHANGED
@@ -7,6 +7,7 @@ import { runTask, type RunTaskController } from "./task-runner.js";
7
7
  import { type ReviewAssignment, type ReviewerOutcome } from "./runtime/reviewer.js";
8
8
  import { type SingletonLock } from "./runtime/singleton.js";
9
9
  import { type SelfUpgradeResult, type SelfUpdate426Result } from "./runtime/self-upgrade.js";
10
+ import { GitAuthController, type GitAuthProbe } from "./git-auth/index.js";
10
11
  import { ResumeController, type ResumeControllerDeps } from "./capacity/resume-controller.js";
11
12
  import { AccountProbeScheduler } from "./engines/account-probe.js";
12
13
  import { type FleetChatServingHandle } from "./watch-chat/wire.js";
@@ -194,6 +195,23 @@ export interface WatchOptions {
194
195
  * guard.
195
196
  */
196
197
  enforceSingleton?: boolean;
198
+ /**
199
+ * GIT-AUTH-ALERT: cadence (ms) of the git-credential health probe. Defaults to
200
+ * 60s. Tests set a large value so only the `gitAuthProbeOnce()` hook drives it.
201
+ */
202
+ gitAuthProbeIntervalMs?: number;
203
+ /**
204
+ * GIT-AUTH-ALERT: consecutive auth-class probe failures before the runner
205
+ * trips the degraded `git_auth_failed` state. Defaults to 2 (the spec bar).
206
+ */
207
+ gitAuthFailureThreshold?: number;
208
+ /**
209
+ * GIT-AUTH-ALERT: injectable probe seam. Production builds an `ls-remote`
210
+ * probe bound to the base clone (cfg.worktreeRepoPath ?? cfg.repoPath); tests
211
+ * inject a fake to drive the state machine without shelling out to git. When
212
+ * neither this nor a base repo path is available the probe loop is disabled.
213
+ */
214
+ gitAuthProbe?: GitAuthProbe;
197
215
  }
198
216
  /**
199
217
  * v0.12.0 (T-52-7): resolve ACC_RUNNER_IDLE_TTL_MIN into ms. Returns null
@@ -228,6 +246,13 @@ export interface WatchHandle {
228
246
  * from the backstop timer.
229
247
  */
230
248
  claimBackstopOnce(): Promise<void>;
249
+ /**
250
+ * GIT-AUTH-ALERT test hook: forces one git-credential health probe and
251
+ * resolves when it finishes (including any degraded/recovered emit). Resolves
252
+ * to `false` when the probe loop is disabled (no base repo path). Production
253
+ * drives this from the probe timer.
254
+ */
255
+ gitAuthProbeOnce(): Promise<boolean>;
231
256
  /** v0.10 T-49-2: number of tasks currently executing. Useful for tests. */
232
257
  runningCount(): number;
233
258
  }
@@ -278,6 +303,19 @@ interface WatchState {
278
303
  claimBackstopTimer: NodeJS.Timeout;
279
304
  claimBackstopIntervalMs: number;
280
305
  backstopScanning: boolean;
306
+ /**
307
+ * GIT-AUTH-ALERT: the git-credential health state machine + its timer.
308
+ * `gitAuthController` is null when the probe loop is disabled (no base repo
309
+ * path resolvable, or in tests that don't opt in). `gitAuthFailed` mirrors the
310
+ * controller's degraded flag so pump() can read it synchronously (like the
311
+ * capacity flags) to pause task-lane claiming. `gitAuthChecking` is the
312
+ * single-flight guard so a slow probe can't overlap itself.
313
+ */
314
+ gitAuthController: GitAuthController | null;
315
+ gitAuthTimer: NodeJS.Timeout | null;
316
+ gitAuthProbeIntervalMs: number;
317
+ gitAuthChecking: boolean;
318
+ gitAuthFailed: boolean;
281
319
  /**
282
320
  * v0.68 (T-68-1): realtime channel-health recovery. The `.subscribe`
283
321
  * status callback previously handled ONLY `SUBSCRIBED`; a `CHANNEL_ERROR`
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"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"}
package/dist/watch.js CHANGED
@@ -43,6 +43,7 @@ import { acquireSingletonLock, singletonRunnerId, SingletonLockHeldError, } from
43
43
  import { getClaudeVersion, recordTaskClaudeVersion, } from "./runtime/version-drift.js";
44
44
  import { autoUpgradeDisabled, maybeSelfUpgrade, maybeSelfUpdateOn426, } from "./runtime/self-upgrade.js";
45
45
  import { postRunnerStateMessage } from "./messaging.js";
46
+ import { GitAuthController, makeGitAuthProbe, RUNNER_GIT_AUTH_FAILED_VERB, RUNNER_GIT_AUTH_RECOVERED_VERB, } from "./git-auth/index.js";
46
47
  // AS-3 (RESUME-WIRE): drive the live capacity pause/resume through the
47
48
  // ResumeController (pause-until reset OR account-change OR ping) instead of a
48
49
  // fixed pause-until-reset setTimeout, and off the AS-2 account-probe cadence.
@@ -119,6 +120,13 @@ const DEFAULT_CLAIM_WATCHDOG_CHECK_MS = 30_000;
119
120
  // regressions of the same shape. Default 60s — prompt recovery without a third
120
121
  // frequent DB poll racing the watchdog. Knob: `claim_backstop_interval_ms`.
121
122
  const DEFAULT_CLAIM_BACKSTOP_INTERVAL_MS = 60_000;
123
+ // GIT-AUTH-ALERT: how often the runner probes its base clone's git credential
124
+ // (a masked `ls-remote origin` dry-run). The same 60s cadence detects the first
125
+ // failure AND polls for recovery — while degraded, task-lane claiming is paused
126
+ // and this probe is the only thing that can clear it. Tests set a large value so
127
+ // only the `gitAuthProbeOnce()` hook drives it deterministically. Knob:
128
+ // `git_auth_probe_interval_ms`.
129
+ const DEFAULT_GIT_AUTH_PROBE_INTERVAL_MS = 60_000;
122
130
  // v0.56 (T-56-1): capacity-aware pause. When claude reports a session/usage
123
131
  // limit (api_error_status 429) the runner pauses claiming tasks AND reviews
124
132
  // until the stated reset time. When no reset time is parseable, fall back to
@@ -915,6 +923,7 @@ export async function watchCommand(options = {}) {
915
923
  reviewScanOnce: async () => { },
916
924
  claimWatchdogOnce: async () => { },
917
925
  claimBackstopOnce: async () => { },
926
+ gitAuthProbeOnce: async () => false,
918
927
  runningCount: () => 0,
919
928
  };
920
929
  }
@@ -1096,6 +1105,13 @@ export async function watchCommand(options = {}) {
1096
1105
  claimBackstopTimer: undefined,
1097
1106
  claimBackstopIntervalMs: options.claimBackstopIntervalMs ?? DEFAULT_CLAIM_BACKSTOP_INTERVAL_MS,
1098
1107
  backstopScanning: false,
1108
+ // GIT-AUTH-ALERT: controller wired below once `state` exists (its emit
1109
+ // callbacks close over `state`); timer armed in the timer-setup block.
1110
+ gitAuthController: null,
1111
+ gitAuthTimer: null,
1112
+ gitAuthProbeIntervalMs: options.gitAuthProbeIntervalMs ?? DEFAULT_GIT_AUTH_PROBE_INTERVAL_MS,
1113
+ gitAuthChecking: false,
1114
+ gitAuthFailed: false,
1099
1115
  // v0.68 (T-68-1): realtime channel-health recovery state.
1100
1116
  resubscribing: false,
1101
1117
  resubscribeAttempts: 0,
@@ -1167,6 +1183,10 @@ export async function watchCommand(options = {}) {
1167
1183
  // starting account is seeded before any claim can 429. Both timers unref so
1168
1184
  // the probe/poll cadence never holds the process open on its own.
1169
1185
  await wireCapacityResume(state, taskRunnerFactory, options);
1186
+ // GIT-AUTH-ALERT: build the git-credential health controller (no-op when no
1187
+ // base clone is resolvable). The probe timer is armed in the timer-setup
1188
+ // block below alongside the claim/review scans.
1189
+ wireGitAuthController(state, options);
1170
1190
  subscribeChannel(state, taskRunnerFactory);
1171
1191
  // v0.34-B / v0.62 (T-62-1): one-shot startup claim scan. The 5-minute
1172
1192
  // pollSince watermark (v0.30-B) can miss a task dispatched (runner_id set)
@@ -1243,6 +1263,17 @@ export async function watchCommand(options = {}) {
1243
1263
  state.claimBackstopTimer = setInterval(() => {
1244
1264
  void claimBackstopScan(state, taskRunnerFactory);
1245
1265
  }, state.claimBackstopIntervalMs);
1266
+ // GIT-AUTH-ALERT: periodic git-credential health probe. Armed only when the
1267
+ // controller is wired (a base clone is resolvable). The same cadence detects
1268
+ // the first auth failure AND polls for recovery while degraded. Single-flight
1269
+ // inside gitAuthProbeScan(); unref'd so the probe never holds the process
1270
+ // open on its own.
1271
+ if (state.gitAuthController) {
1272
+ state.gitAuthTimer = setInterval(() => {
1273
+ void gitAuthProbeScan(state);
1274
+ }, state.gitAuthProbeIntervalMs);
1275
+ state.gitAuthTimer.unref?.();
1276
+ }
1246
1277
  // v0.13-MULTI-RUNNER: refresh the runner's capability tags so an
1247
1278
  // operator change to ACC_RUNNER_CAPABILITIES (or to ~/.config/acc-
1248
1279
  // runner/config.json) takes effect on the next restart without
@@ -1337,6 +1368,8 @@ export async function watchCommand(options = {}) {
1337
1368
  clearInterval(state.reviewScanTimer); // v0.65 (T-65-2)
1338
1369
  clearInterval(state.claimWatchdogTimer); // v0.73 (T-73-2)
1339
1370
  clearInterval(state.claimBackstopTimer); // FIX-D
1371
+ if (state.gitAuthTimer)
1372
+ clearInterval(state.gitAuthTimer); // GIT-AUTH-ALERT
1340
1373
  if (state.resubscribeTimer)
1341
1374
  clearTimeout(state.resubscribeTimer); // v0.68 (T-68-1)
1342
1375
  if (state.idleTimer)
@@ -1447,6 +1480,7 @@ export async function watchCommand(options = {}) {
1447
1480
  reviewScanOnce: () => reviewScan(state, "periodic"), // v0.65 (T-65-2)
1448
1481
  claimWatchdogOnce: () => claimWatchdogScan(state, taskRunnerFactory), // v0.73 (T-73-2)
1449
1482
  claimBackstopOnce: () => claimBackstopScan(state, taskRunnerFactory), // FIX-D
1483
+ gitAuthProbeOnce: () => gitAuthProbeScan(state), // GIT-AUTH-ALERT
1450
1484
  runningCount: () => state.running.size,
1451
1485
  };
1452
1486
  }
@@ -1788,6 +1822,99 @@ async function pumpReviews(state) {
1788
1822
  * duplicate audit events. Sets the in-memory flag synchronously (pump()
1789
1823
  * reads it without an async hop) and best-effort persists + announces.
1790
1824
  */
1825
+ /**
1826
+ * GIT-AUTH-ALERT: build the git-credential health controller and stash it on
1827
+ * `state`. The probe defaults to a masked `ls-remote origin` against the base
1828
+ * clone (worktreeRepoPath ?? repoPath); tests inject `options.gitAuthProbe`.
1829
+ * When neither is available the controller stays null and the probe loop is
1830
+ * never armed — the feature is a no-op for chat-only / repo-less runners.
1831
+ *
1832
+ * The degraded/recovered callbacks flip `state.gitAuthFailed` (read
1833
+ * synchronously in pump() to pause task-lane claiming) and emit the
1834
+ * runner-scoped `runner.git_auth_failed` / `runner.git_auth_recovered` audit
1835
+ * events the alerts tick scans to page the operator. Both emits name the machine
1836
+ * and carry only masked, credential-safe detail.
1837
+ */
1838
+ function wireGitAuthController(state, options) {
1839
+ const repoPath = state.cfg.worktreeRepoPath ?? state.cfg.repoPath;
1840
+ const probe = options.gitAuthProbe ?? (repoPath ? makeGitAuthProbe({ repoPath }) : null);
1841
+ if (!probe)
1842
+ return;
1843
+ const machine = machineIdentity();
1844
+ const runnerId = state.session.runner_id;
1845
+ state.gitAuthController = new GitAuthController({
1846
+ probe,
1847
+ threshold: options.gitAuthFailureThreshold,
1848
+ onDegraded: async ({ consecutiveFailures, detail }) => {
1849
+ state.gitAuthFailed = true;
1850
+ process.stderr.write(chalk.red.bold(`[acc-runner] GIT AUTH FAILED on ${machine} (runner ${runnerId}): ${detail} ` +
1851
+ `— ${consecutiveFailures} consecutive auth-class fetch failures. Pausing ` +
1852
+ `task-lane claiming until a fetch succeeds (probe every ` +
1853
+ `${Math.round(state.gitAuthProbeIntervalMs / 1000)}s). ` +
1854
+ `Fix: run \`gh auth login\` or renew the PAT.\n`));
1855
+ try {
1856
+ await state.supabase.rpc("log_activity", {
1857
+ p_verb: RUNNER_GIT_AUTH_FAILED_VERB,
1858
+ p_target_id: runnerId,
1859
+ p_payload: {
1860
+ runner_id: runnerId,
1861
+ machine,
1862
+ consecutive_failures: consecutiveFailures,
1863
+ detail,
1864
+ remediation: "Run `gh auth login` on the runner host, or renew the PAT it uses.",
1865
+ version: PACKAGE_VERSION,
1866
+ },
1867
+ p_target_type: "runner",
1868
+ });
1869
+ }
1870
+ catch {
1871
+ /* best-effort audit — a failed emit must not wedge the probe loop. */
1872
+ }
1873
+ },
1874
+ onRecovered: async ({ failuresBeforeRecovery, detail }) => {
1875
+ state.gitAuthFailed = false;
1876
+ process.stderr.write(chalk.green(`[acc-runner] git auth RECOVERED on ${machine} (runner ${runnerId}): ${detail}. ` +
1877
+ `Resuming task-lane claiming.\n`));
1878
+ try {
1879
+ await state.supabase.rpc("log_activity", {
1880
+ p_verb: RUNNER_GIT_AUTH_RECOVERED_VERB,
1881
+ p_target_id: runnerId,
1882
+ p_payload: {
1883
+ runner_id: runnerId,
1884
+ machine,
1885
+ failures_before_recovery: failuresBeforeRecovery,
1886
+ version: PACKAGE_VERSION,
1887
+ },
1888
+ p_target_type: "runner",
1889
+ });
1890
+ }
1891
+ catch {
1892
+ /* best-effort audit. */
1893
+ }
1894
+ // Re-drive the pump so queued work is claimed immediately on recovery
1895
+ // instead of waiting for the next poll/scan tick.
1896
+ void pump(state, state.taskRunnerFactory);
1897
+ },
1898
+ });
1899
+ }
1900
+ /**
1901
+ * GIT-AUTH-ALERT: run exactly one git-credential probe. Single-flight via
1902
+ * `gitAuthChecking` so a slow probe can't overlap itself. Returns false (a
1903
+ * no-op) when the controller is disabled. Production drives this from the
1904
+ * probe timer; tests drive it via the `gitAuthProbeOnce()` handle hook.
1905
+ */
1906
+ async function gitAuthProbeScan(state) {
1907
+ if (state.stopped || !state.gitAuthController || state.gitAuthChecking)
1908
+ return false;
1909
+ state.gitAuthChecking = true;
1910
+ try {
1911
+ await state.gitAuthController.check();
1912
+ return true;
1913
+ }
1914
+ finally {
1915
+ state.gitAuthChecking = false;
1916
+ }
1917
+ }
1791
1918
  function enterQuarantine(state, taskId, cause, detail,
1792
1919
  // v0.53 T-53-4: how many consecutive instant-empty exits produced an
1793
1920
  // env_broken cause (1 = definitive, 2 = heuristic confirmed by the
@@ -2107,7 +2234,11 @@ async function pump(state, factory) {
2107
2234
  capacityProbe: state.capacityProbe,
2108
2235
  // RVU-2 (FU-RVU2R): pause NEW task claims under review capacity pressure so
2109
2236
  // reviews get the scarce subscription capacity first (cap-priority).
2110
- claimPaused: state.capacityClaimPaused,
2237
+ // GIT-AUTH-ALERT: also pause NEW task claims while the base git credential
2238
+ // is degraded — every claim would fail at phase=git and requeue, so backing
2239
+ // off (task-lane only; reviews keep draining) avoids the churn the live
2240
+ // 2026-07-22 incident spammed. Cleared by the recovery probe.
2241
+ claimPaused: state.capacityClaimPaused || state.gitAuthFailed,
2111
2242
  });
2112
2243
  // Fill available concurrency slots from the queue.
2113
2244
  while (!state.stopped &&