@ai-dossier/sched 0.53.0 → 0.54.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 +44 -6
- package/dist/attach-pr.d.ts +52 -0
- package/dist/attach-pr.d.ts.map +1 -0
- package/dist/attach-pr.js +168 -0
- package/dist/attach-pr.js.map +1 -0
- package/dist/batch-dispatch.d.ts +8 -0
- package/dist/batch-dispatch.d.ts.map +1 -1
- package/dist/batch-dispatch.js +41 -16
- package/dist/batch-dispatch.js.map +1 -1
- package/dist/groundtruth.d.ts +63 -12
- package/dist/groundtruth.d.ts.map +1 -1
- package/dist/groundtruth.js +104 -35
- package/dist/groundtruth.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +17 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ ai-dossier sched stop --batch b1 # terminate every batch agent (incl. parallel
|
|
|
37
37
|
ai-dossier sched abandon --issue 42 --reason "operator abort"
|
|
38
38
|
ai-dossier sched abandon --batch b1 # dissolve; every unshipped member — parked and validated ones included — requeues as full-cycle
|
|
39
39
|
ai-dossier sched requeue --issue 42 # a PARKED batch member (evicted / handed-back) → full-cycle from its member branch, on the batch profile (#810)
|
|
40
|
+
ai-dossier sched attach-pr --batch b1 4270 # record a blocked batch's own MERGED PR by hand (resolves pr-detect-ambiguous, #824)
|
|
40
41
|
ai-dossier sched stats --issues 4..9 # per-issue tokens/cost from ~/.dossier/runs.jsonl (#524)
|
|
41
42
|
ai-dossier sched stats --batch b1 --project owner-repo # batch member/tail/report/fix costs from raw dispatch logs (#564)
|
|
42
43
|
```
|
|
@@ -1133,8 +1134,9 @@ import {
|
|
|
1133
1134
|
createSpawnDeps, // real detached-spawn process I/O
|
|
1134
1135
|
createExecGroundTruth, // runstate/gh/git ground truth via subprocesses (injectable exec);
|
|
1135
1136
|
// since #468 also gh pr view PR state + setup info from comments;
|
|
1136
|
-
// since #789 also mergedPrForBranch
|
|
1137
|
-
// verified `repo`
|
|
1137
|
+
// since #789 also mergedPrForBranch, and since #824
|
|
1138
|
+
// batchPrCandidate, when constructed with a verified `repo`
|
|
1139
|
+
// (resolveProjectRepo) — which also pins prState with -R
|
|
1138
1140
|
resolveDispatch, // config → resolved command/prompt/report-prompt/tier-models/timers/
|
|
1139
1141
|
// per-tier spawn specs (tiers — #527)
|
|
1140
1142
|
buildTierCommand, // resolved dispatch + tier + issue → argv, using that tier's OWN
|
|
@@ -1168,6 +1170,16 @@ import {
|
|
|
1168
1170
|
type MergedPrLookup, // { kind: 'found', pr, mergedAt } | { kind: 'none' } |
|
|
1169
1171
|
// { kind: 'ambiguous', matches } — GroundTruth.mergedPrForBranch's
|
|
1170
1172
|
// own return type (#789)
|
|
1173
|
+
checkBatchPrCandidate, // the #789 candidate checks (fork/head/base/merged/created-after)
|
|
1174
|
+
// → { ok: true, pr, mergedAt } | { ok: false, check } — shared by
|
|
1175
|
+
// parseMergedPrListJson and attachBatchPr (#824)
|
|
1176
|
+
type BatchPrCheck, // which check failed: fork|head|base|unmerged|created-before-batch|number
|
|
1177
|
+
parsePrCandidateJson, // gh pr view --json → the PR object (GroundTruth.batchPrCandidate, #824)
|
|
1178
|
+
attachBatchPr, // sched attach-pr: verify an operator-named PR, record batch.pr,
|
|
1179
|
+
// clear the pr-detect-ambiguous streak, journal pr-attached (#824)
|
|
1180
|
+
type AttachPrDeps, // { store, journal, groundTruth (repo-verified), repo? }
|
|
1181
|
+
type AttachPrResult, // { outcome: 'attached', pr, mergedAt, clearedAmbiguousTicks } |
|
|
1182
|
+
// { outcome: 'already-attached', pr }
|
|
1171
1183
|
parseSetupInfo, // gh issue view --json comments → teardown inputs
|
|
1172
1184
|
runTeardown, // #468 script teardown for a merged unit (pool return / worktree remove)
|
|
1173
1185
|
isSafeWorktree, // worktree-path containment check (CWE-22)
|
|
@@ -1547,7 +1559,8 @@ predicate in `anchor-close.ts`) over `blocked`/`done` batches touched within the
|
|
|
1547
1559
|
batch that same tick is the ambiguity journaled (`pr-detect-ambiguous`, deduped like
|
|
1548
1560
|
`pr-watch-failed`: once per `blocked` stretch, re-announced every
|
|
1549
1561
|
`JOURNAL_DEDUP_REANNOUNCE_TICKS`; a batch that leaves `blocked` any way — this
|
|
1550
|
-
reconcile's own success, `sched resume --batch`, `sched abandon` —
|
|
1562
|
+
reconcile's own success, `sched resume --batch`, `sched abandon` — or `sched
|
|
1563
|
+
attach-pr` recording the batch's PR clears the marker,
|
|
1551
1564
|
so a later re-block never inherits a stale streak). A batch that still reconciles via
|
|
1552
1565
|
`commits-in-base`/`members-closed` does so without a PR and finishes inline, same as
|
|
1553
1566
|
before #789. On a match, `batch.pr` is recorded as part of the SAME `blocked →
|
|
@@ -1557,9 +1570,34 @@ predicate in `anchor-close.ts`) over `blocked`/`done` batches touched within the
|
|
|
1557
1570
|
per-issue-only despite the section's origin) dispatches the report agent exactly as if the
|
|
1558
1571
|
fleet had opened the PR itself, and `sched status`'s existing `pr` column shows it.
|
|
1559
1572
|
Recording `batch.pr` never closes the anchor by itself — that stays #768's own
|
|
1560
|
-
evidence-gated `reconcileAnchorClosure`, unchanged. An ambiguous match
|
|
1561
|
-
|
|
1562
|
-
|
|
1573
|
+
evidence-gated `reconcileAnchorClosure`, unchanged. An ambiguous match still lets the
|
|
1574
|
+
batch reconcile via its other evidence; otherwise the operator resolves it with
|
|
1575
|
+
`sched attach-pr` (below), or falls to `sched abandon --batch`.
|
|
1576
|
+
- **`sched attach-pr --batch <id> <pr>` (#824).** The operator's explicit, auditable
|
|
1577
|
+
answer to `pr-detect-ambiguous` — and the scripted form of the `batch-integrate`
|
|
1578
|
+
dossier's manual-recovery step that hand-records a batch PR (Step 6b of that registry
|
|
1579
|
+
dossier; `<pr>` also accepts `#4270`). Positive evidence only: the project repository is verified first
|
|
1580
|
+
(`resolveProjectRepo`; unverifiable → refused before any PR is read), the PR is read
|
|
1581
|
+
with `gh pr view <pr> -R <owner/name>` (`GroundTruth.batchPrCandidate`, repo-gated like
|
|
1582
|
+
`mergedPrForBranch`), and it must pass the SAME candidate checks #789's automatic path
|
|
1583
|
+
applies (`checkBatchPrCandidate`: not a fork, head = `batch.branch`, base =
|
|
1584
|
+
`batch.base_branch`, a real merge timestamp, created at or after the batch) plus an
|
|
1585
|
+
explicit `state == MERGED` and a positively-read `isCrossRepository == false`. Any
|
|
1586
|
+
mismatch, a failed or unusable gh read, a batch that is not `blocked` (or has no
|
|
1587
|
+
branch), or a batch whose `batch.pr` is already a DIFFERENT PR refuses with a message
|
|
1588
|
+
naming why — nothing written, nothing journaled; the same PR already recorded is a
|
|
1589
|
+
no-op. There is no `--force`: every check reads a field `gh pr view` always returns.
|
|
1590
|
+
On success `batch.pr` is recorded and the `pr_detect_ambiguous_*` streak cleared in
|
|
1591
|
+
one locked write (`updated_at` is touched, which re-arms the 7-day reconcile window),
|
|
1592
|
+
journaled as its own `pr-attached` event — never `stale-failure-reconciled` /
|
|
1593
|
+
`pr_detected`, so `events.jsonl` always tells operator from automatic apart. Nothing
|
|
1594
|
+
else happens in the command: the next tick's stale-blocked reconcile settles the batch
|
|
1595
|
+
on its ordinary `pr-merged` evidence (report + teardown follow; that read, `prState`,
|
|
1596
|
+
is `-R`-pinned too whenever the engine's repo is verified), and the anchor closes only
|
|
1597
|
+
through `reconcileAnchorClosure`, which never reads `batch.pr`. A batch with a surviving
|
|
1598
|
+
member that was never dispatched is refused too — the reconcile would never settle it
|
|
1599
|
+
on PR evidence. `--json` emits `{batch, repo, outcome: "attached", pr, mergedAt,
|
|
1600
|
+
clearedAmbiguousTicks}` or `{batch, repo, outcome: "already-attached", pr}`.
|
|
1563
1601
|
|
|
1564
1602
|
Everything else is surfaced, never closed: `sched status --anchors` (opt-in; `status`
|
|
1565
1603
|
makes no GitHub call without it) lists each still-open anchor of a batch no longer in
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sched attach-pr --batch <id> <pr>` (#824): the operator's explicit, auditable
|
|
3
|
+
* way to record `batch.pr` when #789's automatic detection refused to guess
|
|
4
|
+
* (`pr-detect-ambiguous` — two or more merged PRs share the batch branch), and
|
|
5
|
+
* the scripted form of the `batch-integrate` dossier's manual-recovery step
|
|
6
|
+
* that hand-records a batch PR (the registry dossier's Step 6b).
|
|
7
|
+
*
|
|
8
|
+
* Trust boundary: the operator's word is not evidence. The named PR must pass
|
|
9
|
+
* the SAME candidate checks #789's automatic path applies
|
|
10
|
+
* (`checkBatchPrCandidate`) plus an explicit `state === 'MERGED'` and a
|
|
11
|
+
* positively-read same-repo flag, read through a ground truth pinned with `-R`
|
|
12
|
+
* to the verified project repository — absent that pin, nothing is read and
|
|
13
|
+
* nothing is recorded. There is no `--force`: every check reads a field
|
|
14
|
+
* `gh pr view` always returns, so an unreadable one refuses rather than
|
|
15
|
+
* inviting an override.
|
|
16
|
+
*
|
|
17
|
+
* Recording is ALL this does: `batch.pr` is set (and any
|
|
18
|
+
* `pr_detect_ambiguous_*` streak cleared) under the store lock, with no status
|
|
19
|
+
* transition and no GitHub write. The next engine tick's
|
|
20
|
+
* `reconcileStaleBlockedBatches` then settles the batch on its ordinary
|
|
21
|
+
* `pr-merged` evidence, and the anchor closes (or not) only through #768's own
|
|
22
|
+
* evidence-gated `reconcileAnchorClosure` — which never reads `batch.pr`.
|
|
23
|
+
*/
|
|
24
|
+
import type { GroundTruth } from './groundtruth';
|
|
25
|
+
import type { Journal } from './journal';
|
|
26
|
+
import type { SchedStore } from './persist';
|
|
27
|
+
export interface AttachPrDeps {
|
|
28
|
+
store: SchedStore;
|
|
29
|
+
journal: Journal;
|
|
30
|
+
/** Must come from `createExecGroundTruth` with a verified `repo` — else `batchPrCandidate` is absent and the attach refuses. */
|
|
31
|
+
groundTruth: GroundTruth;
|
|
32
|
+
/** The verified `owner/name` the ground truth is pinned to — named in refusals and the journal line. */
|
|
33
|
+
repo?: string;
|
|
34
|
+
}
|
|
35
|
+
export type AttachPrResult = {
|
|
36
|
+
outcome: 'attached';
|
|
37
|
+
pr: number;
|
|
38
|
+
mergedAt: string;
|
|
39
|
+
/** Ticks of the `pr-detect-ambiguous` streak this attach cleared (0 when none was open). */
|
|
40
|
+
clearedAmbiguousTicks: number;
|
|
41
|
+
} | {
|
|
42
|
+
outcome: 'already-attached';
|
|
43
|
+
pr: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Record an operator-named PR as `batch.pr` after verifying it (see the module
|
|
47
|
+
* comment). Throws `SchedNotFoundError` — nothing written, nothing journaled —
|
|
48
|
+
* on every refusal; returns `already-attached` (also nothing written) when the
|
|
49
|
+
* same PR is already recorded.
|
|
50
|
+
*/
|
|
51
|
+
export declare function attachBatchPr(deps: AttachPrDeps, batchId: string, pr: number, now?: Date): AttachPrResult;
|
|
52
|
+
//# sourceMappingURL=attach-pr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach-pr.d.ts","sourceRoot":"","sources":["../src/attach-pr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,eAAe,CAAC;AAE/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAI5C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,gIAAgI;IAChI,WAAW,EAAE,WAAW,CAAC;IACzB,wGAAwG;IACxG,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,cAAc,GACtB;IACE,OAAO,EAAE,UAAU,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GACD;IAAE,OAAO,EAAE,kBAAkB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AA6HhD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,EACV,GAAG,GAAE,IAAiB,GACrB,cAAc,CAqEhB"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `sched attach-pr --batch <id> <pr>` (#824): the operator's explicit, auditable
|
|
4
|
+
* way to record `batch.pr` when #789's automatic detection refused to guess
|
|
5
|
+
* (`pr-detect-ambiguous` — two or more merged PRs share the batch branch), and
|
|
6
|
+
* the scripted form of the `batch-integrate` dossier's manual-recovery step
|
|
7
|
+
* that hand-records a batch PR (the registry dossier's Step 6b).
|
|
8
|
+
*
|
|
9
|
+
* Trust boundary: the operator's word is not evidence. The named PR must pass
|
|
10
|
+
* the SAME candidate checks #789's automatic path applies
|
|
11
|
+
* (`checkBatchPrCandidate`) plus an explicit `state === 'MERGED'` and a
|
|
12
|
+
* positively-read same-repo flag, read through a ground truth pinned with `-R`
|
|
13
|
+
* to the verified project repository — absent that pin, nothing is read and
|
|
14
|
+
* nothing is recorded. There is no `--force`: every check reads a field
|
|
15
|
+
* `gh pr view` always returns, so an unreadable one refuses rather than
|
|
16
|
+
* inviting an override.
|
|
17
|
+
*
|
|
18
|
+
* Recording is ALL this does: `batch.pr` is set (and any
|
|
19
|
+
* `pr_detect_ambiguous_*` streak cleared) under the store lock, with no status
|
|
20
|
+
* transition and no GitHub write. The next engine tick's
|
|
21
|
+
* `reconcileStaleBlockedBatches` then settles the batch on its ordinary
|
|
22
|
+
* `pr-merged` evidence, and the anchor closes (or not) only through #768's own
|
|
23
|
+
* evidence-gated `reconcileAnchorClosure` — which never reads `batch.pr`.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.attachBatchPr = attachBatchPr;
|
|
27
|
+
const batch_dispatch_1 = require("./batch-dispatch");
|
|
28
|
+
const groundtruth_1 = require("./groundtruth");
|
|
29
|
+
const journal_1 = require("./journal");
|
|
30
|
+
const state_1 = require("./state");
|
|
31
|
+
const types_1 = require("./types");
|
|
32
|
+
/**
|
|
33
|
+
* Why each shared candidate check refuses, in operator words. `number` and
|
|
34
|
+
* `fork` are pre-empted by `verifyCandidate`'s own stricter checks and exist
|
|
35
|
+
* for the record's exhaustiveness (`fork` is also used directly there).
|
|
36
|
+
*/
|
|
37
|
+
const CHECK_REFUSALS = {
|
|
38
|
+
fork: () => 'it is from a fork (isCrossRepository=true), not the project repository',
|
|
39
|
+
head: (pr, batch) => `its head is ${JSON.stringify(pr.headRefName)}, not the batch branch ${JSON.stringify(batch.branch)}`,
|
|
40
|
+
base: (pr, batch) => `its base is ${JSON.stringify(pr.baseRefName)}, not the batch base ${JSON.stringify(batch.base_branch)}`,
|
|
41
|
+
unmerged: () => 'it has no merge timestamp — not merged',
|
|
42
|
+
'created-before-batch': (pr, batch) => `it was created ${JSON.stringify(pr.createdAt)}, before the batch itself (${batch.created_at}) — a PR from an earlier use of the branch`,
|
|
43
|
+
number: () => 'gh returned no usable PR number',
|
|
44
|
+
};
|
|
45
|
+
/** The one refusal shape every PR-level refusal uses. */
|
|
46
|
+
function refusal(batchId, pr, why) {
|
|
47
|
+
return new types_1.SchedNotFoundError(`Refusing to attach PR #${pr} to batch ${batchId}: ${why}`);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The ledger-only preconditions, re-run under the lock on fresh state.
|
|
51
|
+
* Throws `SchedNotFoundError` naming why on every refusal.
|
|
52
|
+
*/
|
|
53
|
+
function precheck(state, batchId, pr) {
|
|
54
|
+
const batch = (0, state_1.findBatch)(state, batchId);
|
|
55
|
+
if (!batch)
|
|
56
|
+
throw new types_1.SchedNotFoundError(`Batch not found: ${batchId}`);
|
|
57
|
+
if (batch.pr === pr)
|
|
58
|
+
return { noop: true };
|
|
59
|
+
if (batch.pr !== null) {
|
|
60
|
+
throw new types_1.SchedNotFoundError(`Batch ${batchId} already has PR #${batch.pr} recorded — refusing to replace it with #${pr}`);
|
|
61
|
+
}
|
|
62
|
+
if (batch.status !== 'blocked') {
|
|
63
|
+
throw new types_1.SchedNotFoundError(`Batch ${batchId} is ${batch.status} — attach-pr only applies to a blocked batch (the state whose merge evidence reconcileStaleBlockedBatches settles from a recorded PR)`);
|
|
64
|
+
}
|
|
65
|
+
const { branch } = batch;
|
|
66
|
+
if (branch === null) {
|
|
67
|
+
throw new types_1.SchedNotFoundError(`Batch ${batchId} has no branch recorded — nothing to check PR #${pr}'s head against`);
|
|
68
|
+
}
|
|
69
|
+
// The reconcile never settles a batch with a surviving member that was never
|
|
70
|
+
// dispatched (it would call an issue `done` that shipped nothing), so a PR
|
|
71
|
+
// recorded here would sit unused forever — refuse instead of reporting a
|
|
72
|
+
// reconcile that will not happen.
|
|
73
|
+
const undispatched = (0, batch_dispatch_1.undispatchedSurvivingMembers)(state, batch);
|
|
74
|
+
if (undispatched.length > 0) {
|
|
75
|
+
throw new types_1.SchedNotFoundError(`Batch ${batchId} has member(s) ${undispatched.map((m) => `#${m}`).join(', ')} that were never dispatched — the stale-blocked reconcile will not settle it on PR evidence (it would mark unshipped work done); \`sched abandon --batch ${batchId}\` requeues them instead`);
|
|
76
|
+
}
|
|
77
|
+
return { noop: false, batch: { ...batch, branch } };
|
|
78
|
+
}
|
|
79
|
+
/** Refuse unless `candidate` is provably the batch's own merged PR `pr`; returns its merge time. */
|
|
80
|
+
function verifyCandidate(candidate, batch, pr) {
|
|
81
|
+
if (candidate.number !== pr) {
|
|
82
|
+
throw refusal(batch.id, pr, `gh answered for PR ${JSON.stringify(candidate.number)}, not #${pr}`);
|
|
83
|
+
}
|
|
84
|
+
if (candidate.state !== 'MERGED') {
|
|
85
|
+
throw refusal(batch.id, pr, `it is ${JSON.stringify(candidate.state)}, not MERGED`);
|
|
86
|
+
}
|
|
87
|
+
// Positive evidence only: `checkBatchPrCandidate` treats a MISSING flag as
|
|
88
|
+
// "not a fork" (its #789 list convention); an operator-named PR must be
|
|
89
|
+
// read as same-repo explicitly.
|
|
90
|
+
if (candidate.isCrossRepository !== false) {
|
|
91
|
+
throw refusal(batch.id, pr, candidate.isCrossRepository === true
|
|
92
|
+
? CHECK_REFUSALS.fork(candidate, batch)
|
|
93
|
+
: 'gh did not report whether it is from the project repository or a fork (isCrossRepository unreadable)');
|
|
94
|
+
}
|
|
95
|
+
const verdict = (0, groundtruth_1.checkBatchPrCandidate)(candidate, batch.branch, batch.base_branch, Date.parse(batch.created_at));
|
|
96
|
+
if (!verdict.ok)
|
|
97
|
+
throw refusal(batch.id, pr, CHECK_REFUSALS[verdict.check](candidate, batch));
|
|
98
|
+
return verdict.mergedAt;
|
|
99
|
+
}
|
|
100
|
+
/** The `pr-attached` journal line's `detail`. */
|
|
101
|
+
function attachedDetail(prRef, mergedAt, batch, clearedAmbiguousTicks) {
|
|
102
|
+
return (`operator attached ${prRef} (MERGED ${mergedAt}, head=${batch.branch}, base=${batch.base_branch}, same repository) — recorded batch.pr` +
|
|
103
|
+
(clearedAmbiguousTicks > 0
|
|
104
|
+
? `; cleared the pr-detect-ambiguous streak (${clearedAmbiguousTicks} tick(s))`
|
|
105
|
+
: '') +
|
|
106
|
+
'; the next engine tick reconciles the batch on pr-merged evidence — the anchor is left to #768');
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Record an operator-named PR as `batch.pr` after verifying it (see the module
|
|
110
|
+
* comment). Throws `SchedNotFoundError` — nothing written, nothing journaled —
|
|
111
|
+
* on every refusal; returns `already-attached` (also nothing written) when the
|
|
112
|
+
* same PR is already recorded.
|
|
113
|
+
*/
|
|
114
|
+
function attachBatchPr(deps, batchId, pr, now = new Date()) {
|
|
115
|
+
if (!Number.isInteger(pr) || pr <= 0) {
|
|
116
|
+
throw new types_1.SchedNotFoundError(`PR must be a positive integer, got ${pr}`);
|
|
117
|
+
}
|
|
118
|
+
const first = precheck(deps.store.load(), batchId, pr);
|
|
119
|
+
if (first.noop)
|
|
120
|
+
return { outcome: 'already-attached', pr };
|
|
121
|
+
const repo = deps.repo ?? 'the project repository';
|
|
122
|
+
const read = deps.groundTruth.batchPrCandidate;
|
|
123
|
+
if (read === undefined) {
|
|
124
|
+
throw refusal(batchId, pr, "the project's GitHub repository is not verified, so the PR cannot be read with a pinned -R — run from the project's own checkout (or check --project)");
|
|
125
|
+
}
|
|
126
|
+
const candidate = read(pr);
|
|
127
|
+
if (candidate === undefined) {
|
|
128
|
+
throw refusal(batchId, pr, `could not read it from ${repo} (\`gh pr view ${pr} -R ${repo}\` failed or returned an unusable payload — see the stderr line above) — nothing recorded`);
|
|
129
|
+
}
|
|
130
|
+
verifyCandidate(candidate, first.batch, pr);
|
|
131
|
+
// The GitHub read ran outside the lock: re-run the ledger checks AND the
|
|
132
|
+
// candidate checks against the fresh batch, so a batch that left `blocked`,
|
|
133
|
+
// had a PR recorded, or changed its branch/base meanwhile is refused rather
|
|
134
|
+
// than written over.
|
|
135
|
+
const applied = deps.store.withLock((s) => {
|
|
136
|
+
const fresh = precheck(s, batchId, pr);
|
|
137
|
+
if (fresh.noop)
|
|
138
|
+
return { state: s, result: null };
|
|
139
|
+
const mergedAt = verifyCandidate(candidate, fresh.batch, pr);
|
|
140
|
+
// `updated_at` IS touched (unlike the dedup writes): an operator attach is
|
|
141
|
+
// real activity, and it re-arms the stale-blocked reconcile window
|
|
142
|
+
// (measured from `updated_at`), so the PR is acted on even when the batch
|
|
143
|
+
// had been blocked longer than that window.
|
|
144
|
+
return {
|
|
145
|
+
state: (0, state_1.patchBatch)(s, batchId, { pr, ...state_1.CLEARED_PR_DETECT_AMBIGUOUS_FIELDS }, now),
|
|
146
|
+
result: {
|
|
147
|
+
batch: fresh.batch,
|
|
148
|
+
mergedAt,
|
|
149
|
+
clearedAmbiguousTicks: fresh.batch.pr_detect_ambiguous_ticks,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
if (applied === null)
|
|
154
|
+
return { outcome: 'already-attached', pr };
|
|
155
|
+
deps.journal.append((0, journal_1.unitEvent)('pr-attached', `batch:${batchId}`, {
|
|
156
|
+
pr,
|
|
157
|
+
mergedAt: applied.mergedAt,
|
|
158
|
+
branch: applied.batch.branch,
|
|
159
|
+
detail: attachedDetail(deps.repo !== undefined ? `${deps.repo}#${pr}` : `PR #${pr}`, applied.mergedAt, applied.batch, applied.clearedAmbiguousTicks),
|
|
160
|
+
}), now);
|
|
161
|
+
return {
|
|
162
|
+
outcome: 'attached',
|
|
163
|
+
pr,
|
|
164
|
+
mergedAt: applied.mergedAt,
|
|
165
|
+
clearedAmbiguousTicks: applied.clearedAmbiguousTicks,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=attach-pr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach-pr.js","sourceRoot":"","sources":["../src/attach-pr.ts"],"names":[],"mappings":"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"}
|
package/dist/batch-dispatch.d.ts
CHANGED
|
@@ -250,6 +250,14 @@ export declare function resumeBlockedGate(deps: BatchDispatchDeps, config: Sched
|
|
|
250
250
|
* ~375k tokens, stopped only by hand).
|
|
251
251
|
*/
|
|
252
252
|
export declare const MAX_BATCH_AGENT_RESPAWNS = 2;
|
|
253
|
+
/**
|
|
254
|
+
* The surviving members `everySurvivingMemberDispatched` finds NOT yet
|
|
255
|
+
* dispatched — the members that keep a blocked batch out of
|
|
256
|
+
* `reconcileStaleBlockedBatches` (#686). Exported for `sched attach-pr`
|
|
257
|
+
* (#824), which refuses to record a PR the reconcile would then never act on,
|
|
258
|
+
* and names these members in the refusal.
|
|
259
|
+
*/
|
|
260
|
+
export declare function undispatchedSurvivingMembers(state: SchedState, batch: BatchEntry): number[];
|
|
253
261
|
/**
|
|
254
262
|
* #686: reconcile a `blocked` batch whose work demonstrably shipped anyway.
|
|
255
263
|
* `reconcilePrWatch` above only watches `awaiting-merge` batches, and
|
|
@@ -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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"}
|
package/dist/batch-dispatch.js
CHANGED
|
@@ -100,6 +100,7 @@ exports.MAX_BATCH_AGENT_RESPAWNS = exports.tailMembersRefusal = void 0;
|
|
|
100
100
|
exports.memberBranchFor = memberBranchFor;
|
|
101
101
|
exports.evictMemberAndContinue = evictMemberAndContinue;
|
|
102
102
|
exports.resumeBlockedGate = resumeBlockedGate;
|
|
103
|
+
exports.undispatchedSurvivingMembers = undispatchedSurvivingMembers;
|
|
103
104
|
exports.reconcileStaleBlockedBatches = reconcileStaleBlockedBatches;
|
|
104
105
|
exports.memberDispatchModeFor = memberDispatchModeFor;
|
|
105
106
|
exports.runBatchTick = runBatchTick;
|
|
@@ -3141,7 +3142,18 @@ const MEMBER_RECONCILE_CHAIN = {
|
|
|
3141
3142
|
* and the branch is exactly what the merge evidence below covers.
|
|
3142
3143
|
*/
|
|
3143
3144
|
function everySurvivingMemberDispatched(state, batch) {
|
|
3145
|
+
return undispatchedSurvivingMembers(state, batch).length === 0;
|
|
3146
|
+
}
|
|
3147
|
+
/**
|
|
3148
|
+
* The surviving members `everySurvivingMemberDispatched` finds NOT yet
|
|
3149
|
+
* dispatched — the members that keep a blocked batch out of
|
|
3150
|
+
* `reconcileStaleBlockedBatches` (#686). Exported for `sched attach-pr`
|
|
3151
|
+
* (#824), which refuses to record a PR the reconcile would then never act on,
|
|
3152
|
+
* and names these members in the refusal.
|
|
3153
|
+
*/
|
|
3154
|
+
function undispatchedSurvivingMembers(state, batch) {
|
|
3144
3155
|
const evicted = new Set(batch.evictions.map((e) => e.issue));
|
|
3156
|
+
const undispatched = [];
|
|
3145
3157
|
for (const issue of batch.members) {
|
|
3146
3158
|
const entry = (0, state_1.findEntry)(state, issue);
|
|
3147
3159
|
if (!entry)
|
|
@@ -3159,9 +3171,9 @@ function everySurvivingMemberDispatched(state, batch) {
|
|
|
3159
3171
|
// completion — everything the entry can reach afterwards means the
|
|
3160
3172
|
// member was dispatched and its work is on the branch.
|
|
3161
3173
|
if (!DISPATCHED_MEMBER_STATUSES.has(entry.status))
|
|
3162
|
-
|
|
3174
|
+
undispatched.push(issue);
|
|
3163
3175
|
}
|
|
3164
|
-
return
|
|
3176
|
+
return undispatched;
|
|
3165
3177
|
}
|
|
3166
3178
|
/** Slot-line statuses that prove a member was actually dispatched (see above). */
|
|
3167
3179
|
const DISPATCHED_MEMBER_STATUSES = new Set([
|
|
@@ -3228,6 +3240,26 @@ function clearPrDetectAmbiguous(deps, batch, now) {
|
|
|
3228
3240
|
*/
|
|
3229
3241
|
function recordPrDetectAmbiguous(deps, batch, matches, now) {
|
|
3230
3242
|
const { since, ticks, announce } = advanceBatchDedupStreak(batch.pr_detect_ambiguous_reason, batch.pr_detect_ambiguous_since, batch.pr_detect_ambiguous_ticks, state_1.PR_DETECT_AMBIGUOUS_REASON, now);
|
|
3243
|
+
// #824 review: the lookup above ran outside the lock — an operator's
|
|
3244
|
+
// `sched attach-pr` (or a resume/abandon) may have landed meanwhile. Write
|
|
3245
|
+
// the streak (and journal it) only while the batch is STILL blocked with no
|
|
3246
|
+
// PR; never rewrite the marker an attach just cleared, nor tell the
|
|
3247
|
+
// operator to run `sched attach-pr` after they already did.
|
|
3248
|
+
const written = deps.store.withLock((s) => {
|
|
3249
|
+
const b = (0, state_1.findBatch)(s, batch.id);
|
|
3250
|
+
if (!b || b.status !== 'blocked' || b.pr !== null)
|
|
3251
|
+
return { state: s, result: false };
|
|
3252
|
+
return {
|
|
3253
|
+
state: (0, state_1.patchBatch)(s, batch.id, {
|
|
3254
|
+
pr_detect_ambiguous_reason: state_1.PR_DETECT_AMBIGUOUS_REASON,
|
|
3255
|
+
pr_detect_ambiguous_since: since,
|
|
3256
|
+
pr_detect_ambiguous_ticks: ticks,
|
|
3257
|
+
}, now, false),
|
|
3258
|
+
result: true,
|
|
3259
|
+
};
|
|
3260
|
+
});
|
|
3261
|
+
if (!written)
|
|
3262
|
+
return;
|
|
3231
3263
|
if (announce) {
|
|
3232
3264
|
journalEvent(deps, 'pr-detect-ambiguous', unit(batch.id), {
|
|
3233
3265
|
reason: state_1.PR_DETECT_AMBIGUOUS_REASON,
|
|
@@ -3236,21 +3268,14 @@ function recordPrDetectAmbiguous(deps, batch, matches, now) {
|
|
|
3236
3268
|
at: now.toISOString(),
|
|
3237
3269
|
since,
|
|
3238
3270
|
ticks_persisted: ticks,
|
|
3239
|
-
// #789 review:
|
|
3240
|
-
//
|
|
3241
|
-
//
|
|
3242
|
-
//
|
|
3243
|
-
|
|
3271
|
+
// #789 review: "close the extras" (a MERGED PR cannot be closed, so it
|
|
3272
|
+
// never leaves `gh pr list --state merged`) was never an actionable
|
|
3273
|
+
// remedy — state what actually resolves it instead: the operator names
|
|
3274
|
+
// the batch's own PR with `sched attach-pr` (#824), which holds it to
|
|
3275
|
+
// these same candidate checks.
|
|
3276
|
+
detail: `${matches.length} MERGED PRs match head=${batch.branch ?? '?'} (#${matches.join(', #')}) — refusing to guess which is ours; nothing recorded. The batch still reconciles via commits-in-base/members-closed evidence if either holds; otherwise inspect the candidates and record the batch's own with \`sched attach-pr --batch ${batch.id} <pr>\`, or \`sched abandon --batch ${batch.id}\``,
|
|
3244
3277
|
});
|
|
3245
3278
|
}
|
|
3246
|
-
deps.store.withLock((s) => ({
|
|
3247
|
-
state: (0, state_1.patchBatch)(s, batch.id, {
|
|
3248
|
-
pr_detect_ambiguous_reason: state_1.PR_DETECT_AMBIGUOUS_REASON,
|
|
3249
|
-
pr_detect_ambiguous_since: since,
|
|
3250
|
-
pr_detect_ambiguous_ticks: ticks,
|
|
3251
|
-
}, now, false),
|
|
3252
|
-
result: undefined,
|
|
3253
|
-
}));
|
|
3254
3279
|
}
|
|
3255
3280
|
/**
|
|
3256
3281
|
* #686: reconcile a `blocked` batch whose work demonstrably shipped anyway.
|
|
@@ -3382,7 +3407,7 @@ function reconcileStaleBlockedBatches(deps, now, result, anchorCtx) {
|
|
|
3382
3407
|
// #789 review: what the lock ACTUALLY applied, not what the outer
|
|
3383
3408
|
// snapshot predicted — re-derived from `b` (read under the lock) below,
|
|
3384
3409
|
// since `batch.pr` could in principle have changed between the snapshot
|
|
3385
|
-
// above and the lock acquiring (e.g.
|
|
3410
|
+
// above and the lock acquiring (e.g. `sched attach-pr`, #824).
|
|
3386
3411
|
let effectivePr = null;
|
|
3387
3412
|
let prWasRecorded = false;
|
|
3388
3413
|
deps.store.withLock((s) => {
|