@ai-dossier/sched 0.63.0 → 0.65.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 CHANGED
@@ -1814,8 +1814,21 @@ re-screened at all — but neither is closed by it.
1814
1814
 
1815
1815
  ## The PR watcher + tail work (#468)
1816
1816
 
1817
- Dispatched runs park their PR on `auto-merge` (detached ship mode — the default
1818
- prompt instructs it) and exit. The engine owns everything after the park:
1817
+ Dispatched runs park their PR on `auto-merge` (detached ship mode) and exit — **only where
1818
+ a merge mechanism is confirmed** (#887). sched's watch only WAITS for a merge; it never merges,
1819
+ so the default prompts render `{ship_clause}` from `GroundTruth.mergeMechanism()` (`gh api
1820
+ repos/<r>` `allow_auto_merge` + allowed methods, and a scan of the remote default branch's
1821
+ `.github/workflows` for a label watcher, both read through the GitHub API so a stale local
1822
+ `origin/*` ref can never hide a newly added watcher — #921; cached 10 min). A confirmed mechanism still parks only
1823
+ after `gh pr view --json autoMergeRequest` reads back non-null (the label is not proof); with no
1824
+ confirmed mechanism — or an unknown one — the run ships **attached** (waits for checks, merges
1825
+ with an allowed method) and blocks `no-merge-mechanism` if it cannot. A batch tail needs a
1826
+ confirmed *watcher* (native auto-merge alone never confirms a detached batch ship). An
1827
+ `awaiting-merge` milestone carrying `ship_mode=attached` is not a park. Backstop for custom
1828
+ prompts: a parked, OPEN PR with no auto-merge request and no watcher (positively read absent —
1829
+ unknown never counts) that persists past 10 minutes fails `no-merge-mechanism`; the batch PR
1830
+ watch has the same backstop (#921): the batch blocks `no-merge-mechanism`, and the onset marker
1831
+ (`BatchEntry.no_merge_mechanism_since`) resets when a request lands. The engine owns everything after the park:
1819
1832
 
1820
1833
  1. **Park detection (AC1)** — an agent exit whose latest milestone is the ship
1821
1834
  phase's `awaiting-merge` (with `pr=`) is a VERIFIED park, not an unverified
@@ -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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"}
@@ -116,6 +116,7 @@ const dispatch_health_1 = require("./dispatch-health");
116
116
  const dossier_root_1 = require("./dossier-root");
117
117
  const groundtruth_1 = require("./groundtruth");
118
118
  const journal_1 = require("./journal");
119
+ const merge_mechanism_1 = require("./merge-mechanism");
119
120
  const readiness_1 = require("./readiness");
120
121
  const recovery_1 = require("./recovery");
121
122
  const run_log_1 = require("./run-log");
@@ -1510,6 +1511,8 @@ function spawnTailAgent(deps, config, dispatch, batchId, now, result) {
1510
1511
  // before a slot is claimed — `blockBatchForOperator` posts a milestone, an
1511
1512
  // exec that must not run under the store lock).
1512
1513
  const before = deps.store.load();
1514
+ // #887: read outside the store lock (a cache miss runs `gh api`).
1515
+ const mechanism = deps.groundTruth.mergeMechanism?.();
1513
1516
  const pending = (0, state_1.findBatch)(before, batchId);
1514
1517
  if (pending) {
1515
1518
  const refusal = tailDispatchRefusal(before, pending);
@@ -1540,7 +1543,9 @@ function spawnTailAgent(deps, config, dispatch, batchId, now, result) {
1540
1543
  }
1541
1544
  const spawnSpec = (0, dispatch_1.resolveTierSpawn)(dispatch, 'strong', batch.anchor);
1542
1545
  const cmd = spawnSpec.cmd;
1543
- const prompt = (0, dispatch_1.buildBatchTailPrompt)(dispatch.batchTailPrompt, batchId, batch.anchor, landed, batch.worktree);
1546
+ const prompt = (0, dispatch_1.buildBatchTailPrompt)(dispatch.batchTailPrompt, batchId, batch.anchor, landed, batch.worktree,
1547
+ // #887: the repo's detected merge mechanism decides detached vs attached ship.
1548
+ mechanism);
1544
1549
  const logFile = (0, dispatch_1.batchTailLogPath)(deps.store.runsDir, batchId);
1545
1550
  // #629: fences `handleDeadDispatchApiError`'s classification to this
1546
1551
  // dispatch's slice — see `spawnMember`'s identical comment.
@@ -3324,6 +3329,16 @@ function advanceBatchDedupStreak(priorReason, priorSince, priorTicks, reason, no
3324
3329
  */
3325
3330
  function clearPrWatchFailed(deps, batch, now) {
3326
3331
  clearBatchDedupMarker(deps, batch, batch.pr_watch_failed_reason, state_1.CLEARED_PR_WATCH_FIELDS, now);
3332
+ clearNoMergeMechanism(deps, batch, now);
3333
+ }
3334
+ /** Drop the #921 `no-merge-mechanism` onset marker (a no-op, no write, when none is recorded). */
3335
+ function clearNoMergeMechanism(deps, batch, now) {
3336
+ if (batch.no_merge_mechanism_since == null)
3337
+ return;
3338
+ deps.store.withLock((s) => ({
3339
+ state: (0, state_1.patchBatch)(s, batch.id, { no_merge_mechanism_since: null }, now, false),
3340
+ result: undefined,
3341
+ }));
3327
3342
  }
3328
3343
  function reconcilePrWatch(deps, config, now, result) {
3329
3344
  const state = deps.store.load();
@@ -3405,6 +3420,9 @@ function reconcilePrWatch(deps, config, now, result) {
3405
3420
  }, now, false),
3406
3421
  result: undefined,
3407
3422
  }));
3423
+ // A conflicting/blocked PR is a different condition: end any no-merge-mechanism onset so a
3424
+ // re-ship starts a fresh grace window.
3425
+ clearNoMergeMechanism(deps, batch, now);
3408
3426
  // An awaiting-merge record without its integration checkout is an
3409
3427
  // incomplete/corrupt batch, not safe to rebase. Keep its durable watch
3410
3428
  // evidence for an operator rather than running recovery in repoDir.
@@ -3465,6 +3483,47 @@ function reconcilePrWatch(deps, config, now, result) {
3465
3483
  result.failed.push(unit(batch.id));
3466
3484
  }
3467
3485
  }
3486
+ else if (truth.state === 'OPEN' &&
3487
+ truth.autoMergeRequested === false &&
3488
+ (0, merge_mechanism_1.parkedWithoutMerger)(truth, deps.groundTruth.mergeMechanism?.())) {
3489
+ // #921: the issue-unit backstop (#887) for a batch PR — parked OPEN with no auto-merge
3490
+ // request and a POSITIVELY absent watcher. sched's watch only waits, so once this has
3491
+ // persisted past the grace window the batch blocks loudly instead of waiting forever.
3492
+ // `mergeMechanism()` is cached and, like `prState`, read outside the store lock.
3493
+ clearBatchDedupMarker(deps, batch, batch.pr_watch_failed_reason, state_1.CLEARED_PR_WATCH_FIELDS, now);
3494
+ const step = (0, merge_mechanism_1.advanceNoMergeMechanism)(batch.no_merge_mechanism_since, pr, now);
3495
+ if (step.arm !== null) {
3496
+ deps.store.withLock((s) => ({
3497
+ state: (0, state_1.patchBatch)(s, batch.id, { no_merge_mechanism_since: step.arm }, now, false),
3498
+ result: undefined,
3499
+ }));
3500
+ }
3501
+ else if (step.due) {
3502
+ // Re-check on a fresh load: the batch may have merged, blocked or been abandoned since
3503
+ // the poll above, and blockBatch throws on a terminal batch — never abort the tick.
3504
+ const fresh = deps.store.load();
3505
+ if ((0, state_1.findBatch)(fresh, batch.id)?.status !== 'awaiting-merge')
3506
+ continue;
3507
+ let blocked;
3508
+ try {
3509
+ blocked = (0, recovery_1.blockBatch)(fresh, batch.id, { reason: merge_mechanism_1.NO_MERGE_MECHANISM_REASON, milestonePhase: 'batch-ship' }, recoveryDeps(deps, config, batch, now));
3510
+ }
3511
+ catch {
3512
+ continue;
3513
+ }
3514
+ journalEvent(deps, 'pr-watch-failed', unit(batch.id), {
3515
+ reason: merge_mechanism_1.NO_MERGE_MECHANISM_REASON,
3516
+ pr,
3517
+ at: now.toISOString(),
3518
+ });
3519
+ deps.store.withLock((s) => ({
3520
+ state: applyBatchAndIssues(s, blocked.state, batch.id, [], batch.members),
3521
+ result: undefined,
3522
+ }));
3523
+ stopAndReleaseBlocked(deps, batch.id, now);
3524
+ result.failed.push(unit(batch.id));
3525
+ }
3526
+ }
3468
3527
  else {
3469
3528
  // #630: the condition cleared — reset the marker so a future
3470
3529
  // re-occurrence (even the SAME reason) journals its own fresh entry.