@ai-dossier/cli 0.55.0 → 0.57.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 +147 -5
- package/dist/batch-compose.d.ts +172 -0
- package/dist/batch-compose.d.ts.map +1 -0
- package/dist/batch-compose.js +475 -0
- package/dist/batch-compose.js.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/batch.d.ts +58 -0
- package/dist/commands/batch.d.ts.map +1 -0
- package/dist/commands/batch.js +395 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/sched.d.ts.map +1 -1
- package/dist/commands/sched.js +60 -3
- package/dist/commands/sched.js.map +1 -1
- package/dist/gh.d.ts +3 -1
- package/dist/gh.d.ts.map +1 -1
- package/dist/gh.js +4 -1
- package/dist/gh.js.map +1 -1
- package/dist/runstate.d.ts +14 -3
- package/dist/runstate.d.ts.map +1 -1
- package/dist/runstate.js +20 -6
- package/dist/runstate.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -453,7 +453,7 @@ prints `No runstate milestones on issue #440.` (or `null` under `--json`) and ex
|
|
|
453
453
|
| `--status <s>` | `done`, `partial`, `blocked`, `awaiting-merge` (required). `superseded` is rejected here — a fence is written by [`runstate fence`](#run-fencing-504) |
|
|
454
454
|
| `--run <id>` | Run id (`r-<issue>-<hex>`) — mint one with `runstate mint`; full-cycle runs mint it at the gate phase (required) |
|
|
455
455
|
| `--kv <key=value...>` | Phase-specific key, repeatable (and variadic: `--kv a=1 b=2` works too) |
|
|
456
|
-
| `--next <phase>` | Override the computed `next=` line — a phase name or `
|
|
456
|
+
| `--next <phase>` | Override the computed `next=` line — a phase name, `done`, or `operator` (batch phases only) |
|
|
457
457
|
| `--gen <n>` | Run generation this agent owns (default 0). A post below the trail's fenced generation is refused — see [Run fencing](#run-fencing-504) |
|
|
458
458
|
| `--repo <owner/name>` | Target repository (defaults to the current one) |
|
|
459
459
|
| `--dry-run` | Print the comment body instead of posting it |
|
|
@@ -532,7 +532,8 @@ vocabulary underneath it is stable. `batch-ship` mirrors `ship`'s two-milestone
|
|
|
532
532
|
`awaiting-merge`, then `done` after the merge, and `stats` reports the gap between them
|
|
533
533
|
under its own `batch-merge-wait` label (not pooled with full-cycle `merge-wait`).
|
|
534
534
|
`next=` walks the batch line: batch-setup → batch-validate → batch-review → batch-ship →
|
|
535
|
-
batch-report → done.
|
|
535
|
+
batch-report → done. A `blocked` batch milestone is followed by `next=operator`, not `done`
|
|
536
|
+
(#768): the batch's anchor is still open and its next step is operator inspection.
|
|
536
537
|
|
|
537
538
|
> **Compatibility.** Reading and posting these phases requires CLI ≥ 0.14.0. An older
|
|
538
539
|
> CLI rejects them outright on `post` (`Unknown phase 'classify' — expected one of: …`),
|
|
@@ -634,7 +635,8 @@ valid on **every** phase — a takeover can happen anywhere — and requires `ge
|
|
|
634
635
|
`post` refuses it.
|
|
635
636
|
|
|
636
637
|
`next=` is computed for you: the linear order `gate → setup → plan → implement → review →
|
|
637
|
-
ship → report → done`, except that `blocked` ends the run (`next=done`
|
|
638
|
+
ship → report → done`, except that `blocked` ends the run (`next=done` — on a `batch-*`
|
|
639
|
+
phase it is `next=operator` instead, #768) and the three
|
|
638
640
|
non-terminal statuses stay in their own phase — `superseded` points back at its own phase,
|
|
639
641
|
so a takeover that dies leaves a resumable trail rather than a terminal one;
|
|
640
642
|
`ship`/`awaiting-merge` is followed by a
|
|
@@ -677,7 +679,7 @@ Every `--kv` pair is checked before anything is posted:
|
|
|
677
679
|
| `deps` | `none`, or comma-separated issue numbers, e.g. `474,480` |
|
|
678
680
|
| `batch` | a batch id slug starting with a letter or digit, then letters, digits, `.`, `_`, `-` (e.g. `b-2026-08-29-01`) |
|
|
679
681
|
|
|
680
|
-
- `--next` must be a phase name or `
|
|
682
|
+
- `--next` must be a phase name, `done`, or `operator` (batch phases only). It is written to the comment verbatim, so an
|
|
681
683
|
unchecked typo would point the next resume at a phase that does not exist.
|
|
682
684
|
- Comments are append-only: never edit or delete a prior milestone.
|
|
683
685
|
|
|
@@ -1114,6 +1116,132 @@ measured pre-screen hit rate:
|
|
|
1114
1116
|
|
|
1115
1117
|
---
|
|
1116
1118
|
|
|
1119
|
+
## Batch Composition (`batch compose`)
|
|
1120
|
+
|
|
1121
|
+
Previews which issues may share a batch PR **before any model spend** (#773, #770 P3
|
|
1122
|
+
"selection = admission"). It runs the classify pre-screen (`prescreen:v2`) plus the
|
|
1123
|
+
deterministic readiness screen over the operator's picks and/or the open backlog, and proposes
|
|
1124
|
+
one composition that honours the scheduler's batch invariants. No model call, no writes (no
|
|
1125
|
+
labels, comments, or queue changes) — only `gh` reads and a read-only look at the local sched
|
|
1126
|
+
queue/config. Exits 0 once arguments validate; `status` is the payload, not a pass/fail gate.
|
|
1127
|
+
|
|
1128
|
+
```bash
|
|
1129
|
+
ai-dossier batch compose --issues 4114,4178,4327 [--repo owner/name] [--json]
|
|
1130
|
+
ai-dossier batch compose --backlog [--label backend]... [--search "no:assignee"] [--limit 100]
|
|
1131
|
+
```
|
|
1132
|
+
|
|
1133
|
+
| Flag | Default | Meaning |
|
|
1134
|
+
|---|---|---|
|
|
1135
|
+
| `--issues <selection>` | — | Operator picks (fleet grammar: `1,2,5..8`, ≤ 200) |
|
|
1136
|
+
| `--backlog` | off | Draw candidates from the open backlog (`gh issue list`, one call) |
|
|
1137
|
+
| `--no-backfill` | backfill on | With `--issues`: never query the backlog, even when picks fall below `--min-members` |
|
|
1138
|
+
| `--label <name>` (repeatable), `--search <q>`, `--limit <n>` | —, —, 100 (max 500) | Backlog filters, passed to `gh issue list` |
|
|
1139
|
+
| `--base <branch>` | `main` | The base branch every member shares |
|
|
1140
|
+
| `--min-members <n>` / `--max-members <n>` | 3 / 6 | Minimum viable batch / member ceiling (≤ 6) |
|
|
1141
|
+
| `--max-full-review <n>` | sched config `max_full_review_members`, else 2 | Per-batch `review=full` cap (#771) |
|
|
1142
|
+
| `--rules v2\|legacy` | `v2` | `legacy` replays pre-#770 admission (any risk keyword ⇒ `mode=full` ⇒ excluded) for comparison |
|
|
1143
|
+
| `--repo`, `--project` | cwd repo, `owner-name` | Target repo; sched project whose queue/config is read |
|
|
1144
|
+
|
|
1145
|
+
At least one of `--issues` / `--backlog` is required. With `--issues` alone, the backlog is
|
|
1146
|
+
read **only** when the picks by themselves compose fewer than `--min-members` members — counted
|
|
1147
|
+
after the caps, so five admissible `review=full` picks (cap 2) still trigger backfill.
|
|
1148
|
+
|
|
1149
|
+
**Admission.** An issue is excluded — with every reason recorded, not just the first — on:
|
|
1150
|
+
|
|
1151
|
+
| `code` | Rule |
|
|
1152
|
+
|---|---|
|
|
1153
|
+
| `unreadable` | `gh issue view` failed (the report is `degraded`; the run continues) |
|
|
1154
|
+
| `closed` | Not `OPEN` |
|
|
1155
|
+
| `assigned` | Has an assignee |
|
|
1156
|
+
| `in-progress` | Carries the `in-progress` label |
|
|
1157
|
+
| `hard-block-label` | `decision-pending`, `needs-clarification`, `epic`, `decomposed` |
|
|
1158
|
+
| `batch-anchor` | Carries `batch-epic` |
|
|
1159
|
+
| `not-a-unit` | Tracker / decision / research / parked: labels `tracker` `decision` `question` `discussion` `research` `parked` `on-hold` `wontfix` `duplicate`; titles like `[PARKED] …`, `research: …`, `epic(x): …`; a `## Decision needed` section |
|
|
1160
|
+
| `in-flight` | Latest runstate milestone is any phase other than `classify` |
|
|
1161
|
+
| `sched-active` | A non-terminal, not-yet-merged sched queue entry exists |
|
|
1162
|
+
| `open-dependency` | `Depends on #N` with N open and not among the picks; N a pick that is itself excluded; or N whose state could not be read (fails closed) |
|
|
1163
|
+
| `data-mutation` | Change surface names a production data action (`data migration`, `data backfill`, `backfill script`, `one-off script`, `bulk delete`, …) — never shares a PR |
|
|
1164
|
+
| `prescreen-full` | `prescreen:v2` excluding floor: plan:v1 path floor or > 8 predicted files |
|
|
1165
|
+
| `legacy-full` | `--rules legacy` only: any text-floor keyword anywhere in title/body/labels |
|
|
1166
|
+
|
|
1167
|
+
`--rules legacy` replays only the pre-#770 keyword rule on top of today's readiness screen (the
|
|
1168
|
+
other codes above still apply) — it is a comparison of the admission rule, not a full replay of
|
|
1169
|
+
the old pipeline, which also ran a model classifier no deterministic check reproduces.
|
|
1170
|
+
|
|
1171
|
+
A risk keyword in the change surface (`billing`, `security`, `deploy`, …) does **not**
|
|
1172
|
+
exclude: the issue is admissible as a `review=full` member (#770 Option A). The data-mutation
|
|
1173
|
+
and text-floor scans read the same change-surface text (`floorScanText`: reference sections,
|
|
1174
|
+
provenance clauses and quoted spans removed).
|
|
1175
|
+
|
|
1176
|
+
**Composition** (deterministic): every admissible pick joins, bounded by `--max-members` and
|
|
1177
|
+
the `review=full` cap; the overflow is listed under `held` (`review-full-cap` / `max-members`).
|
|
1178
|
+
Then, while the set is below its target — `--min-members` with picks, `--max-members` with
|
|
1179
|
+
`--backlog` alone — admissible backlog issues are added greedily, ranked: shares a workspace
|
|
1180
|
+
package with the current members → `light` before `full` → more shared packages → lower issue
|
|
1181
|
+
number. Packages come from a plan:v1 artifact's predicted files when present, else from paths
|
|
1182
|
+
named in the issue body (`…/packages/<x>/…` → `packages/<x>`, else the first path segment).
|
|
1183
|
+
`status` is `ok` (≥ min), `under-min` (2 … min−1), or `no-batch` (< 2 — run the survivor as a
|
|
1184
|
+
full-cycle issue, #770 P4).
|
|
1185
|
+
|
|
1186
|
+
**JSON contract (`schema: batch-compose:v1`).** Consumers (batch-issues-preparation, #774)
|
|
1187
|
+
branch on `status`, take `manifest_entries`, and report `excluded`:
|
|
1188
|
+
|
|
1189
|
+
```json
|
|
1190
|
+
{
|
|
1191
|
+
"schema": "batch-compose:v1",
|
|
1192
|
+
"repo": "imboard-ai/imboard-monorepo",
|
|
1193
|
+
"project": "imboard-ai-imboard-monorepo",
|
|
1194
|
+
"base_branch": "main",
|
|
1195
|
+
"rules": "v2",
|
|
1196
|
+
"params": {
|
|
1197
|
+
"min_members": 3, "max_members": 6, "max_full_review": 2, "picks": [4178, 4333, 4343],
|
|
1198
|
+
"backlog": { "queried": true, "labels": [], "search": null, "limit": 100 }
|
|
1199
|
+
},
|
|
1200
|
+
"status": "ok",
|
|
1201
|
+
"members": [
|
|
1202
|
+
{ "issue": 4333, "title": "…", "review": "light", "source": "pick", "packages": [], "review_reasons": [] },
|
|
1203
|
+
{ "issue": 4343, "title": "…", "review": "full", "source": "pick", "packages": ["packages/backend"],
|
|
1204
|
+
"review_reasons": ["Title/body/labels match 'rule1-risk-floor-area' (keyword: 'billing')."] },
|
|
1205
|
+
{ "issue": 4241, "title": "…", "review": "full", "source": "backfill", "packages": ["packages/backend"], "review_reasons": ["…"] }
|
|
1206
|
+
],
|
|
1207
|
+
"held": [],
|
|
1208
|
+
"backfill": [
|
|
1209
|
+
{ "rank": 1, "issue": 4241, "title": "…", "review": "full", "packages": ["packages/backend"], "shared_packages": ["packages/backend"], "selected": true }
|
|
1210
|
+
],
|
|
1211
|
+
"shared_packages": ["packages/backend"],
|
|
1212
|
+
"recommendation": "Form one batch of 3 on 'main' (2 review=full).",
|
|
1213
|
+
"manifest_entries": [
|
|
1214
|
+
{ "issue": 4333, "mode": "slot", "review": "light", "base_branch": "main" },
|
|
1215
|
+
{ "issue": 4343, "mode": "slot", "review": "full", "base_branch": "main" },
|
|
1216
|
+
{ "issue": 4241, "mode": "slot", "review": "full", "base_branch": "main" }
|
|
1217
|
+
],
|
|
1218
|
+
"excluded": [
|
|
1219
|
+
{ "issue": 4178, "title": "…", "source": "pick",
|
|
1220
|
+
"reasons": [{ "code": "in-progress", "message": "Carries the 'in-progress' label." }] }
|
|
1221
|
+
],
|
|
1222
|
+
"counts": { "assessed": 102, "admissible": 62, "excluded": 40 },
|
|
1223
|
+
"model_calls": 0,
|
|
1224
|
+
"degraded": false,
|
|
1225
|
+
"warnings": []
|
|
1226
|
+
}
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
- `members` is in selection order (picks, then backfill); `source` is `pick`, `backfill`, or
|
|
1230
|
+
`backlog` (backlog-only mode). `review_reasons` are the prescreen findings behind a `full`.
|
|
1231
|
+
- `manifest_entries` are **draft** `sched enqueue --from-manifest` entries (`parseManifest`
|
|
1232
|
+
shape): batch-issues-preparation adds `batch`, `anchor`, `run_id`, `tier`, `deps`, and
|
|
1233
|
+
`dispatch` — compose mints nothing and claims nothing. The report itself is not a manifest;
|
|
1234
|
+
extract the entries first, e.g.
|
|
1235
|
+
`jq '{entries: [.manifest_entries[] | . + {batch: $b, anchor: $a}]}' --arg b b-20260924-02 --argjson a 4410`.
|
|
1236
|
+
- `backfill` is present only with `--issues`: every admissible backlog candidate, ranked
|
|
1237
|
+
against the admitted picks, `selected: true` on the ones the composition took.
|
|
1238
|
+
- `held` lists admissible issues left out (`review-full-cap`, `max-members`).
|
|
1239
|
+
- `degraded`/`warnings` name any lookup that did not complete (an unreadable pick, the backlog
|
|
1240
|
+
list, a dependency's state, the sched queue/config); the result reflects what did complete.
|
|
1241
|
+
- `model_calls` is always `0`.
|
|
1242
|
+
|
|
1243
|
+
---
|
|
1244
|
+
|
|
1117
1245
|
## Plan Artifacts (`plan`) — plan:v1
|
|
1118
1246
|
|
|
1119
1247
|
Issues used to be planned up to three times (triage, batch prep, plan-issue). The
|
|
@@ -1168,7 +1296,7 @@ respectively; `get --json` includes the comment's `author`.
|
|
|
1168
1296
|
ai-dossier sched enqueue --issues 101,105..109 [--mode full|slot] [--batch b1] [--more-members-expected] [--deps 100,104] [--tier mechanical|mid|strong] [--priority <n>] [--repo owner/name]
|
|
1169
1297
|
ai-dossier sched enqueue --from-manifest batch-prep.json [--repo owner/name]
|
|
1170
1298
|
ai-dossier sched start [--interval <seconds>] [--once] [--auto-upgrade] [--json]
|
|
1171
|
-
ai-dossier sched status [--json] # ⚠ health warnings: long pause, stale lease, stuck / stale-closed slots (#776)
|
|
1299
|
+
ai-dossier sched status [--json] [--anchors] # ⚠ health warnings: long pause, stale lease, stuck / stale-closed slots (#776)
|
|
1172
1300
|
ai-dossier sched pause | resume
|
|
1173
1301
|
ai-dossier sched stop (--issue 42 | --batch b1) [--reason "..."]
|
|
1174
1302
|
ai-dossier sched abandon --issue 42 [--reason "..."] | --batch b1 [--reason "..."]
|
|
@@ -1268,6 +1396,20 @@ atomically. `abandon` instead records failure and releases a slot without termin
|
|
|
1268
1396
|
`shipped` — journaled `stale-failure-reconciled` — unblocking whatever
|
|
1269
1397
|
dependents were blocked by the original failure, up to a 7-day watch
|
|
1270
1398
|
window past which an abandoned failure is left as-is.
|
|
1399
|
+
A batch's anchor issue is closed off the happy path too (#768), but only on
|
|
1400
|
+
positive evidence: every member issue CLOSED as completed BY SHIPPED CODE (a
|
|
1401
|
+
PR merged into the batch's base, or a commit reachable from it — never a bare
|
|
1402
|
+
hand close), and no member evicted, handed back (`decision-pending`, any
|
|
1403
|
+
case), requeued, or failed. The engine then comments on the anchor with each
|
|
1404
|
+
member's shipping PR or commit (marker `batch-close:v1`, honoured only on its
|
|
1405
|
+
own comments, so a rerun never double-posts) and closes it — journaled
|
|
1406
|
+
`anchor-closed` (`anchor-close-failed` on a failed write, deduped like
|
|
1407
|
+
`pr-watch-failed`). It acts only on batches touched within 7 days, and only
|
|
1408
|
+
when the current directory is verified to be the project's repository (every
|
|
1409
|
+
`gh` call names it with `-R`). Any other shape leaves the anchor open;
|
|
1410
|
+
`status --anchors` lists every still-open anchor under
|
|
1411
|
+
`== Open batch anchors ==` as `closable`, `needs-operator`, or `unknown`
|
|
1412
|
+
(report-only and opt-in — without `--anchors`, `status` makes no GitHub call).
|
|
1271
1413
|
`--once` runs a single tick (cron-style); Ctrl-C stops
|
|
1272
1414
|
the engine while spawned agents keep running. Pids are identity-guarded via
|
|
1273
1415
|
`/proc` start-times (a reused pid is never signalled; best-effort on macOS/Windows),
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ai-dossier batch compose` core (#773, #770 P3 "selection = admission").
|
|
3
|
+
*
|
|
4
|
+
* The batch pipeline used to admit members by keyword AFTER humans/models had already selected
|
|
5
|
+
* them — a hand-picked five-issue set collapsed to one member only after ~425k decision-grade
|
|
6
|
+
* classifier tokens (#770). This module previews admission BEFORE any model spend: it runs the
|
|
7
|
+
* deterministic `classify prescreen` (prescreen:v2, #772) plus the readiness screen
|
|
8
|
+
* batch-issues-preparation Step 1/5 applies, and proposes a composition that honours the
|
|
9
|
+
* scheduler's batch invariants — at most `max_full_review_members` (default 2, #771) `review=full`
|
|
10
|
+
* members, one base branch, `min_members` (default 3) to `max_members` (default 6) — preferring
|
|
11
|
+
* members that share a workspace package so the repo's expensive gate stage runs once for all.
|
|
12
|
+
*
|
|
13
|
+
* Pure and dependency-free (no `gh`, network, fs, or model) — same discipline as `prescreen.ts`.
|
|
14
|
+
* All I/O (fetching issues, dependency states, the sched queue) lives in `commands/batch.ts`.
|
|
15
|
+
*/
|
|
16
|
+
import { type PrescreenReason } from './prescreen';
|
|
17
|
+
/** Version of the `batch compose --json` contract. Bump on any breaking shape change. */
|
|
18
|
+
export declare const COMPOSE_SCHEMA = "batch-compose:v1";
|
|
19
|
+
/** Default floor below which a composition is reported `under-min` and backfill is proposed (#770 P4). */
|
|
20
|
+
export declare const DEFAULT_MIN_MEMBERS = 3;
|
|
21
|
+
/** Default (and hard) member ceiling — batch-issues-preparation Step 5 constraint 3 (≤ 6 members). */
|
|
22
|
+
export declare const DEFAULT_MAX_MEMBERS = 6;
|
|
23
|
+
/** Fewer admissible members than this and no batch should form — hand the survivor to full-cycle (#770 P4). */
|
|
24
|
+
export declare const MIN_FORMABLE_MEMBERS = 2;
|
|
25
|
+
/** Admission rules: `v2` = prescreen:v2 + #771 review level (today); `legacy` = pre-#770 (any keyword ⇒ full ⇒ excluded). */
|
|
26
|
+
export type ComposeRules = 'v2' | 'legacy';
|
|
27
|
+
/** Why an issue cannot join a batch. Stable codes — consumers branch on `code`, humans read `message`. */
|
|
28
|
+
export type ExclusionCode = 'unreadable' | 'closed' | 'assigned' | 'in-progress' | 'hard-block-label' | 'batch-anchor' | 'in-flight' | 'sched-active' | 'open-dependency' | 'data-mutation' | 'not-a-unit' | 'prescreen-full' | 'legacy-full';
|
|
29
|
+
export interface ExclusionReason {
|
|
30
|
+
code: ExclusionCode;
|
|
31
|
+
message: string;
|
|
32
|
+
}
|
|
33
|
+
/** Everything the core needs about one issue — the command layer fills it from `gh`. */
|
|
34
|
+
export interface ComposeIssueInput {
|
|
35
|
+
issue: number;
|
|
36
|
+
/** `pick` = named by the operator via `--issues`; `backlog` = drawn from the backlog query. */
|
|
37
|
+
source: 'pick' | 'backlog';
|
|
38
|
+
/** Set when the issue could not be read at all; everything else is then ignored. */
|
|
39
|
+
error?: string;
|
|
40
|
+
title: string;
|
|
41
|
+
body: string;
|
|
42
|
+
labels: readonly string[];
|
|
43
|
+
/** GitHub `state` (`OPEN` / `CLOSED`). */
|
|
44
|
+
state: string;
|
|
45
|
+
assignees: readonly string[];
|
|
46
|
+
/** plan:v1 predicted files when the issue carries an artifact. */
|
|
47
|
+
predictedFiles?: readonly string[];
|
|
48
|
+
/** Phase of the LATEST runstate milestone on the issue, or null when it has none. */
|
|
49
|
+
latestPhase?: string | null;
|
|
50
|
+
/** Status of the issue's non-terminal sched queue entry, or null when it has none. */
|
|
51
|
+
schedStatus?: string | null;
|
|
52
|
+
/** `Depends on #N` refs resolved OPEN and outside the operator's picks. */
|
|
53
|
+
openDependencies?: readonly number[];
|
|
54
|
+
/** `Depends on #N` refs whose state could not be read — an admission gate fails closed on them. */
|
|
55
|
+
unknownDependencies?: readonly number[];
|
|
56
|
+
}
|
|
57
|
+
export interface AssessedIssue {
|
|
58
|
+
issue: number;
|
|
59
|
+
source: 'pick' | 'backlog';
|
|
60
|
+
title: string;
|
|
61
|
+
admissible: boolean;
|
|
62
|
+
/** Review depth the member needs (prescreen:v2 / #771 vocabulary). */
|
|
63
|
+
review: 'light' | 'full';
|
|
64
|
+
/** Workspace packages the issue is predicted to touch (plan:v1 files first, else paths named in the body). */
|
|
65
|
+
packages: string[];
|
|
66
|
+
/** Every prescreen finding — the reason a member is `review=full`. */
|
|
67
|
+
prescreen: PrescreenReason[];
|
|
68
|
+
/** Empty when admissible. */
|
|
69
|
+
excluded: ExclusionReason[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Phrases that mark an issue as production data mutation / ops — the one class #770 P1 keeps
|
|
73
|
+
* out of shared PRs ("prod data mutation/ops"): a batch reverts per commit, a data change does
|
|
74
|
+
* not revert with it. Deliberately ACTION phrases, not bare words or places: "backfill" alone is batch
|
|
75
|
+
* vocabulary (this very feature proposes "backfill candidates"), "migration" alone is already a
|
|
76
|
+
* `review=full` text-floor hit, "delete" alone is ordinary code prose, and "production data" /
|
|
77
|
+
* "prod db" name a place an issue merely talks about (an IAM or pentest issue) — measured on the
|
|
78
|
+
* imboard backlog, those place phrases excluded five issues that mutate nothing. Matched against the
|
|
79
|
+
* same change-surface text the prescreen text floor scans (`floorScanText` — reference sections,
|
|
80
|
+
* provenance clauses and quoted spans removed), whole-word, case-insensitive.
|
|
81
|
+
*/
|
|
82
|
+
export declare const DATA_MUTATION_PHRASES: readonly string[];
|
|
83
|
+
/** First data-mutation phrase the change-surface text matches, or null. */
|
|
84
|
+
export declare function matchDataMutation(text: string): string | null;
|
|
85
|
+
/**
|
|
86
|
+
* Labels marking an issue as something other than one implementable change — a tracker, a
|
|
87
|
+
* decision, parked or research work (#770 P1: "decisions/epics/trackers" never share a PR;
|
|
88
|
+
* batch-issues-preparation Step 5 "Is it a tracker or a decision?"). The hard-block labels
|
|
89
|
+
* (`epic`, `decomposed`, …) are reported separately as `hard-block-label`.
|
|
90
|
+
*/
|
|
91
|
+
export declare const NOT_A_UNIT_LABELS: readonly string[];
|
|
92
|
+
/** Why the issue is not one implementable unit, or null. */
|
|
93
|
+
export declare function notAUnitReason(title: string, body: string, labels: readonly string[]): string | null;
|
|
94
|
+
/** The workspace package a repo-relative path belongs to: `…/packages/<x>/…` → `packages/<x>`, else its first segment. */
|
|
95
|
+
export declare function workspaceOf(path: string): string | null;
|
|
96
|
+
/**
|
|
97
|
+
* Workspace packages an issue is predicted to touch. A plan:v1 artifact's predicted files win
|
|
98
|
+
* (they are the plan's own claim); otherwise path tokens named in the change-surface body
|
|
99
|
+
* (reference sections and provenance removed, but quoted spans KEPT — backticked paths are the
|
|
100
|
+
* main signal here). Sorted, de-duplicated, capped at {@link MAX_PACKAGES}.
|
|
101
|
+
*/
|
|
102
|
+
export declare function inferPackages(body: string, predictedFiles?: readonly string[]): string[];
|
|
103
|
+
/**
|
|
104
|
+
* Deterministic admission for one issue: readiness (batch-issues-preparation Step 1/5) +
|
|
105
|
+
* prescreen:v2 (#772) + data-mutation. Records EVERY exclusion reason, not just the first, so an
|
|
106
|
+
* operator sees the whole picture of why a pick cannot join.
|
|
107
|
+
*/
|
|
108
|
+
export declare function assessIssue(input: ComposeIssueInput, rules?: ComposeRules): AssessedIssue;
|
|
109
|
+
export interface ComposeOptions {
|
|
110
|
+
rules: ComposeRules;
|
|
111
|
+
baseBranch: string;
|
|
112
|
+
minMembers: number;
|
|
113
|
+
maxMembers: number;
|
|
114
|
+
/** Per-batch `review=full` cap (#771 — `max_full_review_members`, default 2). */
|
|
115
|
+
maxFullReview: number;
|
|
116
|
+
/** Whether operator picks were given (`--issues`). Picks mode fills to `minMembers`; backlog-only mode fills to `maxMembers`. */
|
|
117
|
+
picksMode: boolean;
|
|
118
|
+
}
|
|
119
|
+
export interface ComposedMember {
|
|
120
|
+
issue: number;
|
|
121
|
+
title: string;
|
|
122
|
+
review: 'light' | 'full';
|
|
123
|
+
source: 'pick' | 'backfill' | 'backlog';
|
|
124
|
+
packages: string[];
|
|
125
|
+
/** Why `review=full` (prescreen findings); empty for `light`. */
|
|
126
|
+
review_reasons: string[];
|
|
127
|
+
}
|
|
128
|
+
/** An admissible issue left out of the composition, and why. */
|
|
129
|
+
export interface HeldIssue {
|
|
130
|
+
issue: number;
|
|
131
|
+
title: string;
|
|
132
|
+
review: 'light' | 'full';
|
|
133
|
+
source: 'pick' | 'backlog';
|
|
134
|
+
packages: string[];
|
|
135
|
+
reason: 'review-full-cap' | 'max-members';
|
|
136
|
+
}
|
|
137
|
+
export interface BackfillCandidate {
|
|
138
|
+
rank: number;
|
|
139
|
+
issue: number;
|
|
140
|
+
title: string;
|
|
141
|
+
review: 'light' | 'full';
|
|
142
|
+
packages: string[];
|
|
143
|
+
/** Packages it shares with the operator's admitted picks — the ranking's first key. */
|
|
144
|
+
shared_packages: string[];
|
|
145
|
+
/** Whether the proposed composition takes it. */
|
|
146
|
+
selected: boolean;
|
|
147
|
+
}
|
|
148
|
+
export type ComposeStatus = 'ok' | 'under-min' | 'no-batch';
|
|
149
|
+
export interface CompositionResult {
|
|
150
|
+
status: ComposeStatus;
|
|
151
|
+
members: ComposedMember[];
|
|
152
|
+
held: HeldIssue[];
|
|
153
|
+
backfill: BackfillCandidate[];
|
|
154
|
+
/** Packages touched by ≥ 2 members — the expensive gate stage these members amortize. */
|
|
155
|
+
shared_packages: string[];
|
|
156
|
+
/** One line saying what to do with this result. */
|
|
157
|
+
recommendation: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Propose a composition from assessed issues. Picks first (they are the operator's intent) —
|
|
161
|
+
* all admissible picks join, bounded by `maxMembers` and the `review=full` cap; then, while the
|
|
162
|
+
* set is below its target (`minMembers` with picks, `maxMembers` from the backlog alone), backfill
|
|
163
|
+
* from admissible backlog issues. Member order: picks, then backfill, each in selection order.
|
|
164
|
+
*/
|
|
165
|
+
export declare function composeBatch(assessed: AssessedIssue[], opts: ComposeOptions): CompositionResult;
|
|
166
|
+
/**
|
|
167
|
+
* A pick that depends on ANOTHER pick is admissible only while that pick is: when the depended-on
|
|
168
|
+
* pick is excluded (and still open), the dependent would ship without it. Applied to a fixpoint,
|
|
169
|
+
* so a chain A → B → C collapses when C is excluded. Mutates and returns `assessed`.
|
|
170
|
+
*/
|
|
171
|
+
export declare function applyPickDependencies(assessed: AssessedIssue[], pickDeps: ReadonlyMap<number, readonly number[]>, isOpen: (issue: number) => boolean): AssessedIssue[];
|
|
172
|
+
//# sourceMappingURL=batch-compose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-compose.d.ts","sourceRoot":"","sources":["../src/batch-compose.ts"],"names":[],"mappings":"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"}
|