@ai-dossier/sched 0.57.3 → 0.57.5

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.
@@ -207,7 +207,7 @@ export declare function memberBranchFor(batchId: string, memberIndex: number, is
207
207
  */
208
208
  export declare function evictMemberAndContinue(deps: BatchDispatchDeps, config: SchedConfig, dispatch: ResolvedDispatch, batchId: string, batch: BatchEntry, memberIssue: number, failure: MemberFailure, now: Date, result: BatchTickResult,
209
209
  /** #844: the member's slot release (or any pre-write) — committed in the eviction's own write. */
210
- preWrite?: (s: SchedState) => SchedState): void;
210
+ preWrite?: (s: SchedState) => SchedState, afterEvict?: () => void): void;
211
211
  /**
212
212
  * `sched resume --batch <id>` (#583 AC4): an operator-triggered, synchronous
213
213
  * one-shot recheck of a batch blocked on `gate-inconclusive:<capabilityId>`
@@ -1 +1 @@
1
- {"version":3,"file":"batch-dispatch.d.ts","sourceRoot":"","sources":["../src/batch-dispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"batch-dispatch.d.ts","sourceRoot":"","sources":["../src/batch-dispatch.ts"],"names":[],"mappings":"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"}
@@ -1838,10 +1838,11 @@ serialTeardown) {
1838
1838
  */
1839
1839
  function evictMemberAndContinue(deps, config, dispatch, batchId, batch, memberIssue, failure, now, result,
1840
1840
  /** #844: the member's slot release (or any pre-write) — committed in the eviction's own write. */
1841
- preWrite) {
1841
+ preWrite, afterEvict) {
1842
1842
  const { batchEnded, duplicate } = evictMemberDirectly(deps, config, batchId, memberIssue, failure, now, preWrite);
1843
1843
  if (duplicate)
1844
1844
  return;
1845
+ afterEvict?.();
1845
1846
  if (batchEnded) {
1846
1847
  result.failed.push(unit(batchId));
1847
1848
  return;
@@ -2271,7 +2272,7 @@ function resumeBlockedGate(deps, config, dispatch, batchId, now) {
2271
2272
  * full-cycle run is an independent unit), so unlike `engine.ts`'s per-unit log, a member's log file is
2272
2273
  * always one-shot and reading from offset 0 is always correct.
2273
2274
  */
2274
- function recordMemberRunLog(deps, dispatch, state, batchId,
2275
+ function prepareMemberRunLog(deps, dispatch, state, batchId,
2275
2276
  /** 1-based member index — names the per-member log file (serial: `executing_member`; parallel: `MemberRun.index`). */
2276
2277
  memberIndex, memberIssue, slot, now) {
2277
2278
  if (slot.status !== 'running' || slot.spawned_at === null) {
@@ -2309,10 +2310,17 @@ memberIndex, memberIssue, slot, now) {
2309
2310
  cwd: deps.repoDir,
2310
2311
  tier,
2311
2312
  });
2312
- (0, run_log_1.finalizeRunLogEntry)(runEntry, logContent, deps.homeDir, (event, extra) => journalEvent(deps, event, unit(batchId), extra), { issue: memberIssue, log: logFile });
2313
- // #591: the last tool this member dispatch called — attributes an
2314
- // `agent-exited-unverified` failure to a concrete cause without opening the transcript.
2315
- return (0, core_1.parseLastToolUse)(logContent);
2313
+ return {
2314
+ lastTool: (0, core_1.parseLastToolUse)(logContent),
2315
+ append: () => (0, run_log_1.finalizeRunLogEntry)(runEntry, logContent, deps.homeDir, (event, extra) => journalEvent(deps, event, unit(batchId), extra), { issue: memberIssue, log: logFile }),
2316
+ };
2317
+ }
2318
+ function recordMemberRunLog(deps, dispatch, state, batchId, memberIndex, memberIssue, slot, now) {
2319
+ const runLog = prepareMemberRunLog(deps, dispatch, state, batchId, memberIndex, memberIssue, slot, now);
2320
+ if (runLog === null)
2321
+ return null;
2322
+ runLog.append();
2323
+ return runLog.lastTool;
2316
2324
  }
2317
2325
  /**
2318
2326
  * #622: the milestone a member dispatch's fate is read from.
@@ -2477,9 +2485,9 @@ function currentDispatchStamp(stamp, spawnedAt, now) {
2477
2485
  * `kill-escalated` once (`kill_escalated_at`). Pre-#844 this path re-sent
2478
2486
  * SIGTERM forever, so an agent ignoring it held its member indefinitely.
2479
2487
  */
2480
- function stopAgentBeforeDeciding(deps, batchId, memberIssue, slot, now) {
2488
+ function stopAgentBeforeDeciding(deps, config, batchId, memberIssue, slot, now, result) {
2481
2489
  if (!agentAlive(deps, slot))
2482
- return false;
2490
+ return 'gone';
2483
2491
  const pid = slot.pid;
2484
2492
  const pidStart = slot.pid_start ?? undefined;
2485
2493
  const sentAt = currentDispatchStamp(slot.kill_sent_at, slot.spawned_at, now);
@@ -2488,7 +2496,26 @@ function stopAgentBeforeDeciding(deps, batchId, memberIssue, slot, now) {
2488
2496
  // `kill` refuses a pid whose recorded identity no longer matches (reused by
2489
2497
  // another process): the agent we spawned is gone, so stop waiting on it.
2490
2498
  if (!deps.spawnDeps.kill(pid, pidStart, escalate ? 'SIGKILL' : 'SIGTERM'))
2491
- return false;
2499
+ return 'gone';
2500
+ const escalatedAt = currentDispatchStamp(slot.kill_escalated_at, slot.spawned_at, now);
2501
+ const ineffective = escalatedAt !== null && now.getTime() - Date.parse(escalatedAt) >= dispatch_1.KILL_ESCALATION_MS;
2502
+ if (ineffective) {
2503
+ const firstIneffective = currentDispatchStamp(slot.kill_ineffective_at, slot.spawned_at, now) === null;
2504
+ if (firstIneffective) {
2505
+ deps.store.withLock((s) => ({
2506
+ state: (0, state_1.patchSlot)(s, slot.id, { kill_ineffective_at: now.toISOString() }, now),
2507
+ result: undefined,
2508
+ }));
2509
+ journalEvent(deps, 'kill-ineffective', unit(batchId), {
2510
+ issue: memberIssue,
2511
+ pid,
2512
+ slot: slot.id,
2513
+ detail: `agent remained alive ${dispatch_1.KILL_ESCALATION_MS / 1000}s after SIGKILL — blocking for operator`,
2514
+ });
2515
+ blockBatchForOperator(deps, config, batchId, { reason: 'agent-unkillable' }, now, result);
2516
+ }
2517
+ return 'unkillable';
2518
+ }
2492
2519
  const firstEscalation = escalate && currentDispatchStamp(slot.kill_escalated_at, slot.spawned_at, now) === null;
2493
2520
  if (sentAt === null || firstEscalation) {
2494
2521
  deps.store.withLock((s) => {
@@ -2522,7 +2549,7 @@ function stopAgentBeforeDeciding(deps, batchId, memberIssue, slot, now) {
2522
2549
  detail: `agent still alive ${Math.round(aliveForMs / 1000)}s after SIGTERM (bound ${dispatch_1.KILL_ESCALATION_MS / 1000}s) — sent SIGKILL (to its process group where available)`,
2523
2550
  });
2524
2551
  }
2525
- return true;
2552
+ return 'waiting';
2526
2553
  }
2527
2554
  /**
2528
2555
  * #822 (#810 proposal 3): the member's dispatch ran the wrong procedure (a
@@ -2538,12 +2565,12 @@ function stopAgentBeforeDeciding(deps, batchId, memberIssue, slot, now) {
2538
2565
  * `evictMemberAndContinue`/`evictParallelMember`, which commits it in the
2539
2566
  * eviction's own write (#844).
2540
2567
  */
2541
- function repromptWrongProcedure(deps, batchId, memberIssue, milestoneAt, slot, release, now) {
2568
+ function repromptWrongProcedure(deps, config, batchId, memberIssue, milestoneAt, slot, release, now, result) {
2542
2569
  // Never respawn into (or release) a worktree the old agent is still in: a
2543
2570
  // dying full-cycle run could still push, post, or open a PR. Signal it and
2544
2571
  // decide on a later tick, once it is gone — and so the re-prompt's
2545
2572
  // `reprompted_at` fence postdates everything it could still post.
2546
- if (stopAgentBeforeDeciding(deps, batchId, memberIssue, slot, now))
2573
+ if (stopAgentBeforeDeciding(deps, config, batchId, memberIssue, slot, now, result) !== 'gone')
2547
2574
  return 'waiting';
2548
2575
  const outcome = deps.store.withLock((s) => {
2549
2576
  const b = (0, state_1.findBatch)(s, batchId);
@@ -2597,15 +2624,15 @@ function wrongProcedureFailure(lastTool, shippedPr = null) {
2597
2624
  * a re-prompt. On an eviction the slot is still held: the caller passes
2598
2625
  * `release` to the eviction, which commits both in one write (#844).
2599
2626
  */
2600
- function decideWrongProcedure(deps, batchId, memberIssue, milestone, slot, release, lastTool, now) {
2627
+ function decideWrongProcedure(deps, config, batchId, memberIssue, milestone, slot, release, lastTool, now, result) {
2601
2628
  const shipped = (0, groundtruth_1.wrongProcedureShippedPr)(milestone);
2602
2629
  if (shipped !== null) {
2603
- if (stopAgentBeforeDeciding(deps, batchId, memberIssue, slot, now))
2630
+ if (stopAgentBeforeDeciding(deps, config, batchId, memberIssue, slot, now, result) !== 'gone')
2604
2631
  return 'waiting';
2605
2632
  // #844: the caller's eviction releases the slot in its own write.
2606
2633
  return wrongProcedureFailure(lastTool(), shipped);
2607
2634
  }
2608
- const verdict = repromptWrongProcedure(deps, batchId, memberIssue, milestone.at, slot, release, now);
2635
+ const verdict = repromptWrongProcedure(deps, config, batchId, memberIssue, milestone.at, slot, release, now, result);
2609
2636
  if (verdict === 'waiting')
2610
2637
  return verdict;
2611
2638
  // The finished dispatch's run-log entry, exactly once (never while waiting).
@@ -2688,7 +2715,7 @@ function reconcileMemberSlot(deps, config, dispatch, batchId, slot, now, result)
2688
2715
  // before the dead/blocked rail, which would otherwise evict it as an
2689
2716
  // unverified exit at the first sight.
2690
2717
  if (wrongProcedureCounts(batch, memberIssue, read) && read.milestone !== null) {
2691
- const decision = decideWrongProcedure(deps, batchId, memberIssue, read.milestone, slot, release, () => recordMemberRunLog(deps, dispatch, state0, batchId, batch.executing_member, memberIssue, slot, now), now);
2718
+ const decision = decideWrongProcedure(deps, config, batchId, memberIssue, read.milestone, slot, release, () => recordMemberRunLog(deps, dispatch, state0, batchId, batch.executing_member, memberIssue, slot, now), now, result);
2692
2719
  if (typeof decision === 'object') {
2693
2720
  evictMemberAndContinue(deps, config, dispatch, batchId, batch, memberIssue, decision, now, result, release);
2694
2721
  }
@@ -2705,7 +2732,7 @@ function reconcileMemberSlot(deps, config, dispatch, batchId, slot, now, result)
2705
2732
  return;
2706
2733
  }
2707
2734
  if (read.blockedNow || read.dead) {
2708
- const lastTool = recordMemberRunLog(deps, dispatch, state0, batchId, batch.executing_member, memberIssue, slot, now);
2735
+ const runLog = prepareMemberRunLog(deps, dispatch, state0, batchId, batch.executing_member, memberIssue, slot, now);
2709
2736
  // A member that never went green (RFC F.1) evicts DIRECTLY — no aggregate
2710
2737
  // suite has run yet, so there is nothing for `attributing`/`evicting` (the
2711
2738
  // AGGREGATE-suite-red pipeline, RFC F.2) to attribute or revert: the
@@ -2714,9 +2741,9 @@ function reconcileMemberSlot(deps, config, dispatch, batchId, slot, now, result)
2714
2741
  // attributing → evicting` is not even a legal edge from mid-`executing`
2715
2742
  // (BATCH_TRANSITIONS has no `executing → evicting`) — this stays entirely
2716
2743
  // within `executing`/`dissolving`, both of which ARE legal from here.
2717
- evictMemberAndContinue(deps, config, dispatch, batchId, batch, memberIssue, memberFailureFor(read, lastTool), now, result,
2744
+ evictMemberAndContinue(deps, config, dispatch, batchId, batch, memberIssue, memberFailureFor(read, runLog?.lastTool ?? null), now, result,
2718
2745
  // #844: released in the eviction's own write, never before it.
2719
- release);
2746
+ release, () => runLog?.append());
2720
2747
  }
2721
2748
  }
2722
2749
  /**
@@ -4368,7 +4395,7 @@ function spawnParallelMembers(deps, config, dispatch, batchId, now, result) {
4368
4395
  */
4369
4396
  function evictParallelMember(deps, config, batchId, run, failure, now, result,
4370
4397
  /** #844: the member's own slot release — committed in the eviction's write. */
4371
- release) {
4398
+ release, afterEvict) {
4372
4399
  const { batchEnded, duplicate } = evictMemberDirectly(deps, config, batchId, run.issue, failure, now,
4373
4400
  // #844: the run's `evicted` status lands in the eviction's write too — a
4374
4401
  // separate write left an evicted member's run `running` (slotless, its
@@ -4376,6 +4403,7 @@ release) {
4376
4403
  (s) => patchRun(release ? release(s) : s, batchId, run.issue, { status: 'evicted', gate_inconclusive: null }, now));
4377
4404
  if (duplicate)
4378
4405
  return;
4406
+ afterEvict?.();
4379
4407
  result.failed.push(batchEnded ? unit(batchId) : (0, state_1.batchMemberUnit)(batchId, run.issue));
4380
4408
  if (batchEnded)
4381
4409
  return;
@@ -4404,7 +4432,7 @@ function reconcileParallelMemberSlot(deps, config, dispatch, batchId, run, slot,
4404
4432
  // The member's tree may be rebased or removed immediately after its slot
4405
4433
  // is released. Keep this slot draining until the agent is really gone so
4406
4434
  // the #844 SIGKILL bound remains available to a SIGTERM-ignoring agent.
4407
- if (stopAgentBeforeDeciding(deps, batchId, run.issue, slot, now))
4435
+ if (stopAgentBeforeDeciding(deps, config, batchId, run.issue, slot, now, result) !== 'gone')
4408
4436
  return;
4409
4437
  journalEvent(deps, 'external-advance', unit(batchId), {
4410
4438
  issue: run.issue,
@@ -4432,7 +4460,7 @@ function reconcileParallelMemberSlot(deps, config, dispatch, batchId, run, slot,
4432
4460
  if (parallelBatch &&
4433
4461
  wrongProcedureCounts(parallelBatch, run.issue, read) &&
4434
4462
  read.milestone !== null) {
4435
- const decision = decideWrongProcedure(deps, batchId, run.issue, read.milestone, slot, release, () => recordMemberRunLog(deps, dispatch, state0, batchId, run.index, run.issue, slot, now), now);
4463
+ const decision = decideWrongProcedure(deps, config, batchId, run.issue, read.milestone, slot, release, () => recordMemberRunLog(deps, dispatch, state0, batchId, run.index, run.issue, slot, now), now, result);
4436
4464
  if (typeof decision === 'object') {
4437
4465
  evictParallelMember(deps, config, batchId, run, decision, now, result, release);
4438
4466
  }
@@ -4446,8 +4474,8 @@ function reconcileParallelMemberSlot(deps, config, dispatch, batchId, run, slot,
4446
4474
  return;
4447
4475
  }
4448
4476
  if (read.blockedNow || read.dead) {
4449
- const lastTool = recordMemberRunLog(deps, dispatch, state0, batchId, run.index, run.issue, slot, now);
4450
- evictParallelMember(deps, config, batchId, run, memberFailureFor(read, lastTool), now, result, release);
4477
+ const runLog = prepareMemberRunLog(deps, dispatch, state0, batchId, run.index, run.issue, slot, now);
4478
+ evictParallelMember(deps, config, batchId, run, memberFailureFor(read, runLog?.lastTool ?? null), now, result, release, () => runLog?.append());
4451
4479
  }
4452
4480
  }
4453
4481
  /**