@ai-dossier/sched 0.2.1 → 0.3.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
@@ -3,11 +3,14 @@
3
3
  [![npm](https://img.shields.io/npm/v/@ai-dossier/sched.svg)](https://www.npmjs.com/package/@ai-dossier/sched)
4
4
 
5
5
  Deterministic scheduler core for dossier batch cycles — queue, worker slots, typed state
6
- machines, crash-safe persistence, and (since #464) the **dispatch engine**: spawning agent
7
- processes, verifying their completion against ground truth, and mechanizing the
8
- stall/escalation ladder. The scheduler itself **never invokes an LLM** — it spawns the
9
- agent process the operator configured and reconciles the durable record
10
- (`ai-dossier runstate` / `gh` / `git`) that the spawned run leaves behind.
6
+ machines, crash-safe persistence, the **dispatch engine** (#464: spawning agent
7
+ processes, verifying their completion against ground truth, mechanizing the
8
+ stall/escalation ladder), and since #468 the **PR watcher + tail work** (parked-PR
9
+ watching, script-based teardown, cheap-tier report dispatch retiring the fleet
10
+ pattern of re-dispatching a full-cycle run for the tail). The scheduler itself **never
11
+ invokes an LLM** — it spawns the agent process the operator configured and reconciles
12
+ the durable record (`ai-dossier runstate` / `gh` / `git`) that the spawned run leaves
13
+ behind.
11
14
 
12
15
  Design: RFC-0001 *Batch Cycles* §B/C.1/D (the RFC lives on branch `docs/batch-cycles-rfc`,
13
16
  not yet merged to `main`; the §D state machines are frozen verbatim into the types below).
@@ -17,14 +20,14 @@ this state machine makes impossible to forget.
17
20
 
18
21
  ## CLI surface
19
22
 
20
- Consumed through the monorepo CLI (`@ai-dossier/cli` ≥ 0.18.0):
23
+ Consumed through the monorepo CLI (`@ai-dossier/cli` ≥ 0.19.0):
21
24
 
22
25
  ```bash
23
26
  ai-dossier sched enqueue --issues 101,105..109 --deps 100 --tier strong # flags
24
27
  ai-dossier sched enqueue --from-manifest batch-prep.json # batch-prep output
25
- ai-dossier sched start # the dispatch engine: spawn, verify, escalate (Ctrl-C stops it)
28
+ ai-dossier sched start # the dispatch engine: spawn, verify, escalate, watch parked PRs (Ctrl-C stops it)
26
29
  ai-dossier sched start --once # a single reconcile+refill tick (cron-style)
27
- ai-dossier sched status # queue, slots (pid/phase/last-progress), batches, blocked/failed
30
+ ai-dossier sched status # queue (+pr/cleanup), parked PRs, slots, batches, blocked/failed
28
31
  ai-dossier sched pause # stop NEW assignments; live units keep running
29
32
  ai-dossier sched resume
30
33
  ai-dossier sched abandon --issue 42 --reason "operator abort"
@@ -91,13 +94,26 @@ import {
91
94
  parseManifest, // batch-prep JSON → EnqueueInput[]
92
95
  computeAssignments, // pure: fill idle slots with runnable units, bounded by max_slots
93
96
  runnableUnits, // pure: which units may run right now (dep-gated)
94
- tick, // one engine cycle: reconcile + verify + refill + spawn
97
+ tick, // one engine cycle: reconcile + verify + refill + spawn,
98
+ // and since #468: park-watch, teardown, report dispatch
95
99
  runLoop, // the sched start loop (tick, sleep, repeat)
96
- type TickResult, // what one tick did (spawned/completed/redispatched/failed/blocked)
97
- type EngineDeps, // inject everything the engine touches (store/journal/spawn/ground truth/clock)
100
+ type TickResult, // what one tick did (spawned/parked/merge-accepted/report-dispatched/
101
+ // teardown/completed/redispatched/failed/blocked)
102
+ type EngineDeps, // inject everything the engine touches (store/journal/spawn/ground
103
+ // truth/clock/repoDir/teardownExec)
98
104
  createSpawnDeps, // real detached-spawn process I/O
99
- createExecGroundTruth, // runstate/gh/git ground truth via subprocesses (injectable exec)
100
- resolveDispatch, // config resolved command/prompt/tier-models/timers
105
+ createExecGroundTruth, // runstate/gh/git ground truth via subprocesses (injectable exec);
106
+ // since #468 also gh pr view PR state + setup info from comments
107
+ resolveDispatch, // config → resolved command/prompt/report-prompt/tier-models/timers
108
+ buildReportPrompt, // report-agent prompt ({issue}/{pr}/{cleanup} substituted)
109
+ reportTierFor, // report (re)dispatch tier after N escalations
110
+ isParkedMilestone, // ship-phase awaiting-merge + pr= → the park signal
111
+ prOfMilestone, // a milestone's pr= key as a positive integer
112
+ parsePrViewJson, // gh pr view --json → PR truth (mergedAt/mergeable/blocked label)
113
+ parseSetupInfo, // gh issue view --json comments → teardown inputs
114
+ runTeardown, // #468 script teardown for a merged unit (pool return / worktree remove)
115
+ isSafeWorktree, // worktree-path containment check (CWE-22)
116
+ TEARDOWN_TIMEOUT_MS, // teardown subprocess timeout (120 s)
101
117
  Journal, // append-only events.jsonl
102
118
  transitionIssue, transitionBatch, transitionSlot, // typed §D transitions
103
119
  TRANSITIONS, // the transition tables themselves (for previews)
@@ -119,7 +135,8 @@ fake agents and stub ground truth; no LLM calls anywhere.
119
135
  ```
120
136
  ~/.dossier/sched/<project>/
121
137
  ├── state.json # hot operational truth — atomic tmp+fsync+rename writes;
122
- ├── config.json # durable intent: max_slots, stall_timeout_ms, reconcile_interval_ms, dispatch
138
+ ├── config.json # durable intent: max_slots, stall_timeout_ms, reconcile_interval_ms,
139
+ │ # pr_poll_interval_ms, dispatch (incl. report_prompt)
123
140
  ├── events.jsonl # append-only event journal (the operator's flight recorder)
124
141
  ├── runs/ # per-unit agent output logs (issue-<n>.log)
125
142
  └── .sched-lock/ # cross-process directory mutex (pid; stolen from dead holders)
@@ -133,14 +150,63 @@ fake agents and stub ground truth; no LLM calls anywhere.
133
150
  - **Corrupt state is loud**: `load()` throws `CorruptStateError` naming the file —
134
151
  never a silent queue reset. `state.json` is deletable and rebuildable from GitHub,
135
152
  which remains the system of record.
136
- - **Schema**: state/config files from #460 (schema 1.0.0) load and migrate to 1.1.0
137
- automatically (slot `branch`/`last_head` backfill to null).
153
+ - **Schema**: state/config files from #460 (schema 1.0.0) and #464 (1.1.0) load and
154
+ migrate to 1.2.0 automatically (slot `branch`/`last_head`, entry `pr`/`cleanup`,
155
+ and state-level `last_pr_poll_at` backfill to null).
138
156
  - **`max_slots`** bounds live units (`assigned | running | recovering`); dependency
139
157
  edges gate readiness — an issue with an unmerged dependency, and a batch behind an
140
158
  unmerged batch, are never runnable.
141
159
  - **Pause** stops new assignments only; abandon routes through the typed failure rails
142
160
  (`evicted → requeued{full}` for batch members — nothing green is discarded).
143
161
 
162
+ ## The PR watcher + tail work (#468)
163
+
164
+ Dispatched runs park their PR on `auto-merge` (detached ship mode — the default
165
+ prompt instructs it) and exit. The engine owns everything after the park:
166
+
167
+ 1. **Park detection (AC1)** — an agent exit whose latest milestone is the ship
168
+ phase's `awaiting-merge` (with `pr=`) is a VERIFIED park, not an unverified
169
+ exit: the entry moves to `parked`, the slot is released (a waiting unit
170
+ consumes zero slots), and the watcher takes over.
171
+ 2. **PR watching (AC1)** — parked PRs are polled every `pr_poll_interval_ms`
172
+ (default 150 s — "every 2–3 min", persisted `last_pr_poll_at` so a restart
173
+ honors the cadence; checked on each reconcile tick when due, so a
174
+ `reconcile_interval_ms` longer than the interval slows the effective cadence)
175
+ via `gh pr view --json state,mergedAt,mergeable,labels`.
176
+ A merge is accepted only when state is MERGED **and** `mergedAt` is non-null
177
+ **and** the issue is closed — never inferred from an agent exit. An
178
+ unreachable poll pauses the watcher (decision 2, option A).
179
+ 3. **Failure states (AC3)** — `CONFLICTING`, closed-unmerged, or the
180
+ `auto-merge-blocked` label fail the unit with the reason and block its
181
+ TRANSITIVE dependents. The engine never merges anything itself.
182
+ 4. **Gating on MERGE, not park (AC4)** — `parked` is not a satisfied status:
183
+ dependents stay blocked until the merge lands (`parked → shipped`).
184
+ 5. **Teardown as a script (AC2)** — on merge, the run's setup milestone
185
+ (recovered once from the issue's comments — collaborator-authored only, and
186
+ the worktree path must pass a containment check before any destructive
187
+ subprocess) chooses the script: pool-claimed worktrees run
188
+ `worktree-pool return --path <wt> --json` (the pool's own self-check is the
189
+ verification); cold worktrees run
190
+ `git worktree remove --force <wt>` with a path-gone check. Both are
191
+ verify-first idempotent; a failed step records `cleanup=failed-<step>` on
192
+ the entry and in the journal — degradation, never unit failure.
193
+ 6. **Report dispatch (AC2)** — once teardown is recorded (when a slot is
194
+ free — a waiting report consumes zero slots), a **mechanical-tier** report
195
+ agent is spawned with the report-phase prompt (`dispatch.report_prompt`;
196
+ `{issue}`/`{pr}`/`{cleanup}` substituted — the cleanup status rides into
197
+ the report). It completes like any agent; a report that stalls climbs the
198
+ same ladder (mechanical → mid → strong, cap 2), and at the cap the unit
199
+ completes (`done`, reason `report-escalation-cap`) with a `report-failed`
200
+ journal event — the work is merged, so dependents are never re-blocked.
201
+ The full-cycle tail-run pattern (re-dispatching a whole run for
202
+ teardown+report) is retired.
203
+
204
+ `sched status` shows parked PRs (zero slots, with the last poll's age), a
205
+ `pr` column and a `cleanup` column on the queue; every watcher decision lands
206
+ in `events.jsonl` (`pr-parked`, `merge-accepted`, `pr-watch-failed`,
207
+ `pr-watch-waiting`, `teardown-done`/`teardown-failed`, `report-dispatched`,
208
+ `report-failed`, `ground-truth-unreachable`).
209
+
144
210
  ## Development
145
211
 
146
212
  ```bash
@@ -152,4 +218,6 @@ npm test # vitest — state machines, persistence, crash/restart, engine
152
218
 
153
219
  No network, no GitHub in unit tests — persistence tests run on temp directories; the
154
220
  integration tests spawn fake-agent fixtures against a scratch git repo with stubbed
155
- ground truth.
221
+ ground truth. The #468 integration tests run the full detached-ship tail
222
+ (park → watch → merge → REAL worktree removal → report) end-to-end, including a
223
+ sched restart mid-watch.
@@ -22,18 +22,34 @@ export declare const DEFAULT_TIER_MODELS: Readonly<Record<ModelTier, string>>;
22
22
  export declare const DEFAULT_DISPATCH_COMMAND: readonly string[];
23
23
  /** opencode equivalent (the run machinery's second agent, #459). */
24
24
  export declare const OPENCODE_DISPATCH_COMMAND: readonly string[];
25
- /** Default prompt sent on the child's stdin. */
25
+ /**
26
+ * Default prompt sent on the child's stdin. Detached ship mode (#468): the
27
+ * agent parks the PR on `auto-merge` and STOPS — the scheduler's PR watcher
28
+ * owns the merge wait and dispatches teardown + report as tail work. The
29
+ * fleet pattern of re-dispatching a full-cycle run for the tail is retired.
30
+ * Operators wanting attached runs (agent drives to the final report itself)
31
+ * override `dispatch.prompt` in config.json.
32
+ */
26
33
  export declare const DEFAULT_PROMPT_TEMPLATE: string;
34
+ /**
35
+ * Default prompt for the report agent dispatched after a merged PR (#468
36
+ * AC2) — a cheap-tier run of the report phase only, never a full cycle.
37
+ */
38
+ export declare const DEFAULT_REPORT_PROMPT_TEMPLATE: string;
27
39
  /** Fully-resolved dispatch settings the engine runs with. */
28
40
  export interface ResolvedDispatch {
29
41
  /** Command template with `{model}`/`{issue}` placeholders. */
30
42
  command: string[];
31
43
  /** Prompt template with `{issue}` placeholder. */
32
44
  prompt: string;
45
+ /** Report-agent prompt template with `{issue}`/`{pr}`/`{cleanup}` placeholders (#468). */
46
+ reportPrompt: string;
33
47
  /** Model per tier; null means "no model flag" (the command's `--model {model}` pair drops). */
34
48
  tierModels: Record<ModelTier, string | null>;
35
49
  stallTimeoutMs: number;
36
50
  reconcileIntervalMs: number;
51
+ /** Parked-PR poll interval (#468 AC1, default 150 s — "every 2–3 min"). */
52
+ prPollIntervalMs: number;
37
53
  }
38
54
  /** Resolve engine dispatch settings from the (possibly sparse) config. */
39
55
  export declare function resolveDispatch(config: SchedConfig): ResolvedDispatch;
@@ -46,8 +62,17 @@ export declare function resolveDispatch(config: SchedConfig): ResolvedDispatch;
46
62
  export declare function buildAgentCommand(template: readonly string[], tier: ModelTier, issue: number, tierModels: Readonly<Record<ModelTier, string | null>>): string[];
47
63
  /** Build the child's stdin prompt for one dispatch. */
48
64
  export declare function buildPrompt(template: string, issue: number): string;
65
+ /** Build the report agent's stdin prompt (#468): `{issue}`/`{pr}`/`{cleanup}` substituted. */
66
+ export declare function buildReportPrompt(template: string, issue: number, pr: number, cleanup: string): string;
49
67
  /** One tier stronger on the ladder, or null at the top (RFC-0001 §C.1). */
50
68
  export declare function escalateTier(tier: ModelTier): ModelTier | null;
69
+ /**
70
+ * The tier for a report-agent (re)dispatch after `recoveries` escalations
71
+ * (#468): reports start cheap (mechanical) and climb the same ladder —
72
+ * mechanical → mid → strong — with null past the top. The engine's
73
+ * `ESCALATION_CAP` check fails the unit before that null is reached.
74
+ */
75
+ export declare function reportTierFor(recoveries: number): ModelTier | null;
51
76
  export interface SpawnDeps {
52
77
  /**
53
78
  * Spawn a detached agent process and return its pid. `logFile` receives the
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,WAAW,EAEjB,MAAM,SAAS,CAAC;AAEjB,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAInE,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAOrD,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAOtD,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,uBAAuB,QAKwB,CAAC;AAE7D,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,gBAAgB,CAcrE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GACrD,MAAM,EAAE,CAgBV;AAED,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAE9D;AAID,MAAM,WAAW,SAAS;IACxB;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9D;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACnD;;;OAGG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACtD;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAC1C;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAcxD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAyEvD"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
package/dist/dispatch.js CHANGED
@@ -50,11 +50,13 @@ var __importStar = (this && this.__importStar) || (function () {
50
50
  };
51
51
  })();
52
52
  Object.defineProperty(exports, "__esModule", { value: true });
53
- exports.STOP_POLL_MAX_MS = exports.STOP_POLL_MIN_MS = exports.DEFAULT_PROMPT_TEMPLATE = exports.OPENCODE_DISPATCH_COMMAND = exports.DEFAULT_DISPATCH_COMMAND = exports.DEFAULT_TIER_MODELS = void 0;
53
+ exports.STOP_POLL_MAX_MS = exports.STOP_POLL_MIN_MS = exports.DEFAULT_REPORT_PROMPT_TEMPLATE = exports.DEFAULT_PROMPT_TEMPLATE = exports.OPENCODE_DISPATCH_COMMAND = exports.DEFAULT_DISPATCH_COMMAND = exports.DEFAULT_TIER_MODELS = void 0;
54
54
  exports.resolveDispatch = resolveDispatch;
55
55
  exports.buildAgentCommand = buildAgentCommand;
56
56
  exports.buildPrompt = buildPrompt;
57
+ exports.buildReportPrompt = buildReportPrompt;
57
58
  exports.escalateTier = escalateTier;
59
+ exports.reportTierFor = reportTierFor;
58
60
  exports.unitLogName = unitLogName;
59
61
  exports.procStartTime = procStartTime;
60
62
  exports.createSpawnDeps = createSpawnDeps;
@@ -87,12 +89,30 @@ exports.OPENCODE_DISPATCH_COMMAND = [
87
89
  '--model',
88
90
  '{model}',
89
91
  ];
90
- /** Default prompt sent on the child's stdin. */
92
+ /**
93
+ * Default prompt sent on the child's stdin. Detached ship mode (#468): the
94
+ * agent parks the PR on `auto-merge` and STOPS — the scheduler's PR watcher
95
+ * owns the merge wait and dispatches teardown + report as tail work. The
96
+ * fleet pattern of re-dispatching a full-cycle run for the tail is retired.
97
+ * Operators wanting attached runs (agent drives to the final report itself)
98
+ * override `dispatch.prompt` in config.json.
99
+ */
91
100
  exports.DEFAULT_PROMPT_TEMPLATE = 'Run the full-cycle-issue workflow for GitHub issue #{issue} in this repository.\n\n' +
92
101
  'Begin by fetching the workflow: ai-dossier run imboard-ai/git/full-cycle-issue --pull\n\n' +
93
- 'Then execute it end-to-end for issue #{issue}, following every phase ' +
94
- '(gate, setup, plan, implement, review, ship, report) without asking questions, ' +
95
- 'until the final report milestone is posted on the issue.';
102
+ 'Then execute it for issue #{issue} in detached ship mode (ship_mode=detached), following every ' +
103
+ 'phase (gate, setup, plan, implement, review) without asking questions, until Phase 5 parks the ' +
104
+ 'PR: apply the auto-merge label, post the awaiting-merge milestone, and STOP. Do not wait for ' +
105
+ 'the merge, do not run teardown or report — the scheduler watches the PR and dispatches those.';
106
+ /**
107
+ * Default prompt for the report agent dispatched after a merged PR (#468
108
+ * AC2) — a cheap-tier run of the report phase only, never a full cycle.
109
+ */
110
+ exports.DEFAULT_REPORT_PROMPT_TEMPLATE = 'Run the report phase for GitHub issue #{issue} in this repository.\n\n' +
111
+ 'Begin by fetching the workflow: ai-dossier run imboard-ai/git/report-issue --pull\n\n' +
112
+ 'The work is DONE: pull request #{pr} is merged (merge commit via `gh pr view {pr}`), the issue ' +
113
+ 'is closed, and the worktree is already torn down (cleanup status: {cleanup}). Do not ' +
114
+ 're-implement, re-review, or re-ship anything — produce the final report for issue #{issue} and ' +
115
+ 'post its runstate milestone.';
96
116
  /** Resolve engine dispatch settings from the (possibly sparse) config. */
97
117
  function resolveDispatch(config) {
98
118
  const dispatch = config.dispatch ?? {};
@@ -104,9 +124,11 @@ function resolveDispatch(config) {
104
124
  return {
105
125
  command: dispatch.command ?? [...exports.DEFAULT_DISPATCH_COMMAND],
106
126
  prompt: dispatch.prompt ?? exports.DEFAULT_PROMPT_TEMPLATE,
127
+ reportPrompt: dispatch.report_prompt ?? exports.DEFAULT_REPORT_PROMPT_TEMPLATE,
107
128
  tierModels,
108
129
  stallTimeoutMs: config.stall_timeout_ms ?? types_1.DEFAULT_STALL_TIMEOUT_MS,
109
130
  reconcileIntervalMs: config.reconcile_interval_ms ?? types_1.DEFAULT_RECONCILE_INTERVAL_MS,
131
+ prPollIntervalMs: config.pr_poll_interval_ms ?? types_1.DEFAULT_PR_POLL_INTERVAL_MS,
110
132
  };
111
133
  }
112
134
  /**
@@ -137,10 +159,26 @@ function buildAgentCommand(template, tier, issue, tierModels) {
137
159
  function buildPrompt(template, issue) {
138
160
  return template.replaceAll('{issue}', String(issue));
139
161
  }
162
+ /** Build the report agent's stdin prompt (#468): `{issue}`/`{pr}`/`{cleanup}` substituted. */
163
+ function buildReportPrompt(template, issue, pr, cleanup) {
164
+ return template
165
+ .replaceAll('{issue}', String(issue))
166
+ .replaceAll('{pr}', String(pr))
167
+ .replaceAll('{cleanup}', cleanup);
168
+ }
140
169
  /** One tier stronger on the ladder, or null at the top (RFC-0001 §C.1). */
141
170
  function escalateTier(tier) {
142
171
  return types_1.TIER_LADDER[tier];
143
172
  }
173
+ /**
174
+ * The tier for a report-agent (re)dispatch after `recoveries` escalations
175
+ * (#468): reports start cheap (mechanical) and climb the same ladder —
176
+ * mechanical → mid → strong — with null past the top. The engine's
177
+ * `ESCALATION_CAP` check fails the unit before that null is reached.
178
+ */
179
+ function reportTierFor(recoveries) {
180
+ return types_1.TIER_ORDER[recoveries] ?? null;
181
+ }
144
182
  /** `issue:464` → `issue-464` (filesystem-safe unit ids for log file names). */
145
183
  function unitLogName(unit) {
146
184
  return (0, project_1.sanitizeSlug)(unit);
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
package/dist/engine.d.ts CHANGED
@@ -1,12 +1,16 @@
1
1
  /**
2
2
  * The scheduler engine (#464): dispatch, completion verification, and the
3
3
  * stall/escalation ladder (RFC-0001 §C.1) — the deterministic organs that
4
- * replace fleet-cycle's LLM supervision.
4
+ * replace fleet-cycle's LLM supervision. Since #468 it also owns the
5
+ * detached-ship tail: the PR watcher, script-based teardown, and the
6
+ * cheap-tier report dispatch.
5
7
  *
6
8
  * One `tick()` is a full reconcile+refill cycle:
7
9
  *
8
- * 1. **Poll** ground truth for every live unit OUTSIDE the state lock (gh/git
9
- * subprocesses are slow; the lock must never wait on a network call).
10
+ * 1. **Poll** ground truth for every live unit and every parked PR OUTSIDE
11
+ * the state lock (gh/git subprocesses are slow; the lock must never wait
12
+ * on a network call). Parked PRs poll on their own cadence
13
+ * (`pr_poll_interval_ms`, persisted `last_pr_poll_at`) — every 2–3 min.
10
14
  * 2. **Apply** under `SchedStore.withLock`:
11
15
  * - `assigned` slots (crash between assign and spawn) are spawned/re-attached
12
16
  * - `running` slots: dead pid → exit rail; ground truth says complete →
@@ -14,13 +18,25 @@
14
18
  * pushed commit → progress; no progress for `stall_timeout_ms` →
15
19
  * redispatch one tier stronger (cap 2, then failed)
16
20
  * - `exited`/`verifying` slots: the agent exited — completion is verified
17
- * against ground truth, never assumed (AC2); unverified exits ride the
18
- * same recovery ladder as stalls
19
- * - `recovering` slots: respawned with the escalated tier (resume rails
20
- * the agent re-enters via gate and resumes from the milestone trail)
21
+ * against ground truth, never assumed (AC2); an exit whose milestone is
22
+ * the ship phase's `awaiting-merge` (with `pr=`) is a VERIFIED park:
23
+ * entry parked, slot released (a parked unit holds no slot AC5)
24
+ * - `parked` entries: the watcher applies the PR truth — merge accepted
25
+ * only when state MERGED AND mergedAt non-null AND the issue is closed
26
+ * (AC1) → shipped (gating on MERGE, never the park — AC4);
27
+ * CONFLICTING / closed-unmerged / auto-merge-blocked → failed + transitive
28
+ * dependents blocked (AC3)
21
29
  * - failures block their TRANSITIVE dependents (AC4)
22
- * 3. **Refill**: `computeAssignments` fills every freed slot in the SAME tick —
23
- * a runnable unit never waits while a slot is idle (AC5).
30
+ * - report agents are dispatched for merged units whose teardown is
31
+ * already recorded (before queue refill cheap reports don't queue
32
+ * behind long runs)
33
+ * - **Refill** in the SAME lock pass: `computeAssignments` fills every
34
+ * freed slot — a runnable unit never waits while a slot is idle (AC5)
35
+ * 3. **Teardown** (outside the lock — pool/git subprocesses are slow): for
36
+ * every freshly-merged unit, recover the setup milestone's worktree info
37
+ * and run pool return / worktree remove, VERIFIED before claimed
38
+ * (`cleanup=failed-<step>` on mismatch, AC2). Results land in a second
39
+ * short lock pass together with the report dispatch.
24
40
  *
25
41
  * Everything that touches the world (processes, GitHub, git) is injected;
26
42
  * the state machine is pure. Only `issue:<n>` units are dispatched — batch
@@ -30,6 +46,7 @@ import { type SpawnDeps } from './dispatch';
30
46
  import { type GroundTruth } from './groundtruth';
31
47
  import { type Journal } from './journal';
32
48
  import type { SchedStore } from './persist';
49
+ import type { ExecFn } from './project';
33
50
  import { type SchedConfig } from './types';
34
51
  export interface EngineDeps {
35
52
  store: SchedStore;
@@ -37,6 +54,10 @@ export interface EngineDeps {
37
54
  groundTruth: GroundTruth;
38
55
  spawnDeps: SpawnDeps;
39
56
  now: () => Date;
57
+ /** Repo working directory — cwd for teardown subprocesses (#468). */
58
+ repoDir: string;
59
+ /** Exec for teardown scripts (#468); injectable so tests never touch git/npx. */
60
+ teardownExec: ExecFn;
40
61
  }
41
62
  /** What one tick did — surfaced by `sched start`. */
42
63
  export interface TickResult {
@@ -46,17 +67,36 @@ export interface TickResult {
46
67
  externalAdvances: string[];
47
68
  /** Units verified complete after an observed exit. */
48
69
  completed: string[];
70
+ /** Units whose agent exited having parked its PR (#468) — now watcher-owned. */
71
+ parked: string[];
72
+ /** Parked units whose merge was accepted this tick (#468). */
73
+ mergeAccepted: string[];
74
+ /** Report agents dispatched for merged units this tick (#468). */
75
+ reportDispatched: string[];
76
+ /** Merged units whose report could not dispatch — waiting for a free slot (#468). */
77
+ reportWaiting: number;
78
+ /** Units whose teardown was verified this tick (#468). */
79
+ teardownDone: string[];
80
+ /** Units whose teardown failed a step this tick (#468) — degradation, not unit failure. */
81
+ teardownFailed: string[];
49
82
  /** Units redispatched one tier stronger (stall or unverified exit). */
50
83
  redispatched: string[];
51
- /** Units failed (escalation cap / strongest tier / spawn error). */
84
+ /**
85
+ * Units that hit a failure rail. Full-cycle units end `failed`; MERGED
86
+ * units also land here on merged-aware REPORT failures
87
+ * (`report-escalation-cap` / report spawn-error), where the unit actually
88
+ * completes (`done`, reason recorded) — the report failed, not the work.
89
+ */
52
90
  failed: string[];
53
91
  /** Issues blocked transitively by a failure. */
54
92
  blocked: number[];
55
93
  }
56
94
  /**
57
- * One full reconcile+refill cycle. Ground truth is polled WITHOUT the lock;
58
- * every state mutation happens under `store.withLock`; refills are computed in
59
- * the same pass, so a freed slot is reused within this tick (AC5).
95
+ * One full reconcile+refill cycle. Ground truth is polled WITHOUT the lock
96
+ * (live units AND parked PRs); every state mutation happens under
97
+ * `store.withLock`; refills are computed in the same pass, so a freed slot
98
+ * is reused within this tick (AC5). Teardown subprocesses run between two
99
+ * short lock passes — a slow `npx`/`git` call never holds the lock.
60
100
  */
61
101
  export declare function tick(deps: EngineDeps, config: SchedConfig): TickResult;
62
102
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,EAML,KAAK,SAAS,EAIf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,WAAW,EAAiD,MAAM,eAAe,CAAC;AAChG,OAAO,EAAe,KAAK,OAAO,EAAa,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG5C,OAAO,EAGL,KAAK,WAAW,EAKjB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,UAAU;IACzB,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;CACjB;AAED,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kFAAkF;IAClF,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sDAAsD;IACtD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,uEAAuE;IACvE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,oEAAoE;IACpE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAqkBD;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,UAAU,CAWtE;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,OAAO,EACzB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GACpC,OAAO,CAAC,IAAI,CAAC,CAcf"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,EAQL,KAAK,SAAS,EAIf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAe,KAAK,OAAO,EAAa,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAIxC,OAAO,EAKL,KAAK,WAAW,EAKjB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,UAAU;IACzB,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,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kFAAkF;IAClF,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sDAAsD;IACtD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gFAAgF;IAChF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,kEAAkE;IAClE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,qFAAqF;IACrF,aAAa,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,2FAA2F;IAC3F,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,uEAAuE;IACvE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA06BD;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,UAAU,CAyCtE;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,OAAO,EACzB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GACpC,OAAO,CAAC,IAAI,CAAC,CAcf"}