@ai-dossier/sched 0.68.2 → 0.68.3
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 +51 -3
- package/dist/batch-dispatch.d.ts.map +1 -1
- package/dist/batch-dispatch.js +65 -6
- package/dist/batch-dispatch.js.map +1 -1
- package/dist/engine.d.ts +4 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1 -9
- package/dist/engine.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -380,7 +380,54 @@ This applies to `issue:<n>` unit dispatch (`dispatchAssignments`). `batch:<id>`
|
|
|
380
380
|
through a separate pass with its own claim/reconcile logic — see
|
|
381
381
|
[Batch dispatch (#523)](#batch-dispatch-523) below.
|
|
382
382
|
|
|
383
|
-
### Supervised deployment (#679)
|
|
383
|
+
### Supervised deployment (#679, #945)
|
|
384
|
+
|
|
385
|
+
**The way to run the engine is `ai-dossier sched service install`** (run it from the project's
|
|
386
|
+
checkout). The engine is safe to kill at any instant, but it cannot restart itself — the service is
|
|
387
|
+
what makes it come back by itself, so no session ever has to start, stop or babysit it.
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
ai-dossier sched service install [--alert-issue <n>] # systemd user unit; cron watchdog if no systemd
|
|
391
|
+
ai-dossier sched service status # supervised? engine live? heartbeat?
|
|
392
|
+
ai-dossier sched service uninstall
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
- **systemd** (default when a user manager is running): writes
|
|
396
|
+
`~/.config/systemd/user/dossier-sched-<project>.service` — `Restart=always` (a clean exit, such as
|
|
397
|
+
a graceful stop, comes back too) with **crash-loop bounds**: exponential `RestartSec` backoff
|
|
398
|
+
(10 s up to 300 s, systemd >= 254; older versions keep 10 s) and `StartLimitBurst=10` per
|
|
399
|
+
`StartLimitIntervalSec=600` — past that the unit is left `failed` for an operator
|
|
400
|
+
(`systemctl --user reset-failed <unit>`); `KillMode=process`, `WorkingDirectory` = the project's
|
|
401
|
+
**main checkout** (never a linked worktree; validated against `--project`, override with
|
|
402
|
+
`--repo-dir`), and the node/nvm `PATH` at install time (absolute entries only). Install refuses
|
|
403
|
+
node / entry-point / repo paths that are missing, relative, or under a temp or `worktrees/`
|
|
404
|
+
directory, and warns that an nvm node path must be re-pinned (re-run `install`) after a node
|
|
405
|
+
upgrade. It runs `sched start --auto-upgrade` (opt out with `--no-auto-upgrade`); after a
|
|
406
|
+
completed tick, a stale engine installs the latest CLI and re-execs the same command before
|
|
407
|
+
another state write. Detached agents keep running and the new engine reattaches by pid. The
|
|
408
|
+
new version migrates state on load; older engines reject newer schemas. If the Node runtime
|
|
409
|
+
cannot replace the process directly, exit code 75 asks systemd/the watchdog to restart the
|
|
410
|
+
updated entry point.
|
|
411
|
+
Output goes to the journal (`journalctl --user -u <unit>`) and the durable trail is the
|
|
412
|
+
project's `events.jsonl`. Run `loginctl enable-linger $USER` once so it starts at boot without a
|
|
413
|
+
login. Re-running `install` is idempotent; a changed unit is restarted (agents keep running).
|
|
414
|
+
- **cron fallback** (no systemd): a tagged crontab block with `@reboot` and a per-minute
|
|
415
|
+
`sched ensure-running` watchdog (`%` is escaped for cron). The watchdog starts a detached engine
|
|
416
|
+
(output to `<sched-dir>/engine.log`) when no live engine holds the lease, after raising the
|
|
417
|
+
once-per-episode stale-lease alert; a healthy minute does nothing (no `gh` call). Restarts back
|
|
418
|
+
off exponentially while the engine keeps dying: at a 60 s cadence the first restarts are
|
|
419
|
+
immediate, then gaps of 2, 4, 8 … minutes up to 30, and a live engine resets it. The existing
|
|
420
|
+
crontab is read strictly — only "no crontab for <user>" counts as empty; any other `crontab -l`
|
|
421
|
+
failure aborts the install and changes nothing. The engine takes the lease atomically, so two
|
|
422
|
+
watchdogs — or a watchdog plus the systemd unit — never run two engines. To stop the engine on
|
|
423
|
+
purpose under the watchdog: `sched ensure-running --disable` (`--enable` to resume).
|
|
424
|
+
- **Crash alerts are deduplicated:** repeats of the same alert kind within an hour are ONE tracking
|
|
425
|
+
comment on `--alert-issue`, edited with a repeat count, not a comment per restart.
|
|
426
|
+
- `install` / `uninstall` exit non-zero and print `✗` when anything failed (systemctl, crontab).
|
|
427
|
+
`--no-activate` renders the unit / cron block without calling `systemctl` or `crontab` and says
|
|
428
|
+
plainly that nothing is installed; `--print` prints it.
|
|
429
|
+
|
|
430
|
+
The manual shapes below remain valid, and explain the rules the service encodes.
|
|
384
431
|
|
|
385
432
|
Two supported shapes, one rule: **dispatched agents must outlive the tick or engine that
|
|
386
433
|
spawned them.** Agents are spawned detached and unref'd precisely so they survive a sched
|
|
@@ -470,6 +517,7 @@ Only SIGINT had a handler, so a SIGTERM/SIGHUP (another session's restart, a clo
|
|
|
470
517
|
terminal) killed the engine with no line and no lease release. That is now logged; if the
|
|
471
518
|
2026-09-29 cause was SIGKILL/OOM, the missing `engine-exit` plus the stale lease is now the
|
|
472
519
|
documented signature (`journalctl -k` for the OOM window).
|
|
520
|
+
|
|
473
521
|
### Restart never discards work (#945, #940)
|
|
474
522
|
|
|
475
523
|
Before the engine respawns an agent onto a worktree that already exists — a batch **tail**, a
|
|
@@ -520,8 +568,8 @@ last pushed head while local work exists, the engine does **not** respawn. Rows
|
|
|
520
568
|
fields (the engine's own post-landing gate rows) and clean rows are never evidence; an older dirty
|
|
521
569
|
row is superseded by a newer clean or failed one. It blocks the batch `tail-dirty-worktree`, with the evidence and the
|
|
522
570
|
rescue ref in the journal and `sched status`. Commit or discard the work in the worktree, then
|
|
523
|
-
`sched resume --batch <id>`. A tail that left only unpushed commits is respawned, told to resume
|
|
524
|
-
from the rescue ref. `sched resume --batch` deliberately does NOT re-run this guard: by resuming, the operator has looked at the worktree.
|
|
571
|
+
`sched resume --batch <id>`. A tail that left only unpushed commits is respawned, told to resume
|
|
572
|
+
from the rescue ref. `sched resume --batch` deliberately does NOT re-run this guard: by resuming, the operator has looked at the worktree.
|
|
525
573
|
|
|
526
574
|
### Zombie-run fencing (#504)
|
|
527
575
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-dispatch.d.ts","sourceRoot":"","sources":["../src/batch-dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAWH,OAAO,EAIL,KAAK,YAAY,EAGjB,KAAK,gBAAgB,EAGtB,MAAM,gBAAgB,CAAC;AAUxB,OAAO,EAeL,KAAK,gBAAgB,EAGrB,KAAK,SAAS,EAEf,MAAM,YAAY,CAAC;AAGpB,OAAO,EAGL,KAAK,WAAW,EAcjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,OAAO,EAAa,MAAM,WAAW,CAAC;AAMpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAW5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EACL,KAAK,iBAAiB,EActB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EA2BL,kBAAkB,EAKnB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,QAAQ,EAMd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAGV,UAAU,EAEV,oBAAoB,EAKpB,kBAAkB,EAClB,cAAc,EAId,WAAW,EACX,UAAU,EAEX,MAAM,SAAS,CAAC;AAajB,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,8DAA8D;AAC9D,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,SAAS,CAAC;IACrB,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,iBAAiB,KAAK,WAAW,CAAC;IACrE;;;;;;;;;;;;;;;;;;;OAmBG;IACH,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,oBAAoB,CAAC;IACjF,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,8FAA8F;AAC9F,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,uFAAuF;IACvF,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,8FAA8F;IAC9F,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;;OAIG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AA+sBD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3F;
|
|
1
|
+
{"version":3,"file":"batch-dispatch.d.ts","sourceRoot":"","sources":["../src/batch-dispatch.ts"],"names":[],"mappings":"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"}
|
package/dist/batch-dispatch.js
CHANGED
|
@@ -1424,15 +1424,28 @@ function claimAndSetup(deps, config, dispatch, batchId, now, result) {
|
|
|
1424
1424
|
abortSetup(`member-worktree-prep-failed:${memberPrep.reason}`, `member worktree prep failed: ${memberPrep.reason} (member 1 #${firstIssue}, branch ${memberBranchFor(batchId, 1, firstIssue)})`);
|
|
1425
1425
|
return;
|
|
1426
1426
|
}
|
|
1427
|
+
// Persist the completed setup and the batch's executing/member-1 assignment
|
|
1428
|
+
// BEFORE spawning. If SIGKILL lands between this write and the provider
|
|
1429
|
+
// process creation, the next engine sees `executing` + an assigned slot and
|
|
1430
|
+
// `reconcileMemberSlot` resumes from the deterministic member worktree. The
|
|
1431
|
+
// previous single lock pass spawned first and only saved afterward, leaving
|
|
1432
|
+
// a kill window with batch=status ready + an assigned slot that no tick arm
|
|
1433
|
+
// could claim again.
|
|
1427
1434
|
deps.store.withLock((s) => ({
|
|
1428
|
-
state: landSetup(deps, s, batchId, setup, now, { member_dispatch: 'serial' }, 1, (next) =>
|
|
1429
|
-
const slot = slotFor(next, batchId);
|
|
1430
|
-
return slot
|
|
1431
|
-
? spawnMember(deps, dispatch, next, slot, batchId, now, result, memberPrep)
|
|
1432
|
-
: next;
|
|
1433
|
-
}),
|
|
1435
|
+
state: landSetup(deps, s, batchId, setup, now, { member_dispatch: 'serial' }, 1, (next) => next),
|
|
1434
1436
|
result: undefined,
|
|
1435
1437
|
}));
|
|
1438
|
+
deps.store.withLock((s) => {
|
|
1439
|
+
const freshBatch = (0, state_1.findBatch)(s, batchId);
|
|
1440
|
+
const slot = slotFor(s, batchId);
|
|
1441
|
+
if (!freshBatch || freshBatch.status !== 'executing' || !slot) {
|
|
1442
|
+
return { state: s, result: undefined };
|
|
1443
|
+
}
|
|
1444
|
+
return {
|
|
1445
|
+
state: spawnMember(deps, dispatch, s, slot, batchId, now, result, memberPrep),
|
|
1446
|
+
result: undefined,
|
|
1447
|
+
};
|
|
1448
|
+
});
|
|
1436
1449
|
}
|
|
1437
1450
|
/**
|
|
1438
1451
|
* Land a completed `runBatchSetup` on the batch entry (inside the caller's
|
|
@@ -2965,6 +2978,45 @@ function reconcileMemberSlot(deps, config, dispatch, batchId, slot, now, result)
|
|
|
2965
2978
|
release, () => runLog?.append());
|
|
2966
2979
|
}
|
|
2967
2980
|
}
|
|
2981
|
+
/**
|
|
2982
|
+
* Recover the durable setup→member handoff when an engine dies after
|
|
2983
|
+
* `landSetup` saved `batch.status=executing` but before the member process was
|
|
2984
|
+
* spawned and its pid was saved. The slot is still `assigned`; release that
|
|
2985
|
+
* claim and reuse `spawnMemberContinuation`, whose deterministic member
|
|
2986
|
+
* worktree path adopts the already-prepared tree. This is the batch equivalent
|
|
2987
|
+
* of `engine.ts`'s assigned-before-spawn recovery rail.
|
|
2988
|
+
*/
|
|
2989
|
+
function recoverAssignedMemberSlot(deps, config, dispatch, batchId, slot, now, result) {
|
|
2990
|
+
const current = deps.store.load();
|
|
2991
|
+
const batch = (0, state_1.findBatch)(current, batchId);
|
|
2992
|
+
if (!batch ||
|
|
2993
|
+
batch.status !== 'executing' ||
|
|
2994
|
+
isParallelBatch(batch) ||
|
|
2995
|
+
slot.status !== 'assigned' ||
|
|
2996
|
+
slot.pid !== null) {
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
2999
|
+
const released = deps.store.withLock((state) => {
|
|
3000
|
+
const fresh = (0, state_1.findBatch)(state, batchId);
|
|
3001
|
+
const freshSlot = slotFor(state, batchId);
|
|
3002
|
+
if (!fresh ||
|
|
3003
|
+
fresh.status !== 'executing' ||
|
|
3004
|
+
isParallelBatch(fresh) ||
|
|
3005
|
+
!freshSlot ||
|
|
3006
|
+
freshSlot.status !== 'assigned' ||
|
|
3007
|
+
freshSlot.pid !== null) {
|
|
3008
|
+
return { state, result: false };
|
|
3009
|
+
}
|
|
3010
|
+
return { state: releaseSlot(state, batchId, now), result: true };
|
|
3011
|
+
});
|
|
3012
|
+
if (!released)
|
|
3013
|
+
return;
|
|
3014
|
+
journalEvent(deps, 'assigned-recovered', unit(batchId), {
|
|
3015
|
+
slot: slot.id,
|
|
3016
|
+
detail: 'engine restarted after a serial batch assignment was persisted but before member spawn was recorded',
|
|
3017
|
+
});
|
|
3018
|
+
spawnMemberContinuation(deps, config, dispatch, batchId, now, result);
|
|
3019
|
+
}
|
|
2968
3020
|
/**
|
|
2969
3021
|
* Park a member that left the batch before landing, record the exit, and
|
|
2970
3022
|
* dissolve if this tips the batch past its `dissolve_policy` threshold (#563;
|
|
@@ -5355,6 +5407,13 @@ function runBatchTick(deps, config, dispatch) {
|
|
|
5355
5407
|
reconcileParallelBatch(deps, config, batchDispatch, batch.id, now, result, paused);
|
|
5356
5408
|
continue;
|
|
5357
5409
|
}
|
|
5410
|
+
if (batch.status === 'executing' &&
|
|
5411
|
+
!isParallelBatch(batch) &&
|
|
5412
|
+
slot?.status === 'assigned' &&
|
|
5413
|
+
slot.pid === null) {
|
|
5414
|
+
recoverAssignedMemberSlot(deps, config, batchDispatch, batch.id, slot, now, result);
|
|
5415
|
+
continue;
|
|
5416
|
+
}
|
|
5358
5417
|
if (slot && (slot.status === 'running' || slot.status === 'assigned')) {
|
|
5359
5418
|
if (batch.status === 'executing') {
|
|
5360
5419
|
reconcileMemberSlot(deps, config, batchDispatch, batch.id, slot, now, result);
|