@on-par/factory-core 0.9.28-next.23 → 0.9.28-next.25

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.
Files changed (81) hide show
  1. package/dist/config/index.d.ts +1 -0
  2. package/dist/config/index.d.ts.map +1 -1
  3. package/dist/config/index.js +8 -1
  4. package/dist/config/index.js.map +1 -1
  5. package/dist/events/queue-traits.d.ts +1 -1
  6. package/dist/events/queue-traits.d.ts.map +1 -1
  7. package/dist/events/queue-traits.js +4 -1
  8. package/dist/events/queue-traits.js.map +1 -1
  9. package/dist/fakes/octokit.d.ts +13 -1
  10. package/dist/fakes/octokit.d.ts.map +1 -1
  11. package/dist/fakes/octokit.js +13 -0
  12. package/dist/fakes/octokit.js.map +1 -1
  13. package/dist/internal.d.ts +3 -0
  14. package/dist/internal.d.ts.map +1 -1
  15. package/dist/internal.js +4 -0
  16. package/dist/internal.js.map +1 -1
  17. package/dist/kpis/phase.d.ts.map +1 -1
  18. package/dist/kpis/phase.js +1 -0
  19. package/dist/kpis/phase.js.map +1 -1
  20. package/dist/phases/ship-open-pr.d.ts.map +1 -1
  21. package/dist/phases/ship-open-pr.js +2 -2
  22. package/dist/phases/ship-open-pr.js.map +1 -1
  23. package/dist/phases/ship-options.d.ts +3 -0
  24. package/dist/phases/ship-options.d.ts.map +1 -1
  25. package/dist/phases/ship-options.js.map +1 -1
  26. package/dist/phases/stack-order.d.ts +9 -0
  27. package/dist/phases/stack-order.d.ts.map +1 -1
  28. package/dist/phases/stack-order.js +13 -0
  29. package/dist/phases/stack-order.js.map +1 -1
  30. package/dist/queue/github-queue.d.ts +4 -2
  31. package/dist/queue/github-queue.d.ts.map +1 -1
  32. package/dist/queue/github-queue.js.map +1 -1
  33. package/dist/queue/internal-exports.d.ts +1 -0
  34. package/dist/queue/internal-exports.d.ts.map +1 -1
  35. package/dist/queue/internal-exports.js +1 -0
  36. package/dist/queue/internal-exports.js.map +1 -1
  37. package/dist/queue/prerequisite-stack.d.ts +47 -0
  38. package/dist/queue/prerequisite-stack.d.ts.map +1 -0
  39. package/dist/queue/prerequisite-stack.js +41 -0
  40. package/dist/queue/prerequisite-stack.js.map +1 -0
  41. package/dist/queue/review-rework-trigger.d.ts +2 -2
  42. package/dist/queue/review-rework-trigger.d.ts.map +1 -1
  43. package/dist/queue/review-rework-trigger.js +6 -2
  44. package/dist/queue/review-rework-trigger.js.map +1 -1
  45. package/dist/run/ci-rework-loop.d.ts.map +1 -1
  46. package/dist/run/ci-rework-loop.js +4 -1
  47. package/dist/run/ci-rework-loop.js.map +1 -1
  48. package/dist/run/feedback-github.d.ts +50 -0
  49. package/dist/run/feedback-github.d.ts.map +1 -0
  50. package/dist/run/feedback-github.js +87 -0
  51. package/dist/run/feedback-github.js.map +1 -0
  52. package/dist/run/feedback-round-hooks.d.ts +19 -0
  53. package/dist/run/feedback-round-hooks.d.ts.map +1 -0
  54. package/dist/run/feedback-round-hooks.js +106 -0
  55. package/dist/run/feedback-round-hooks.js.map +1 -0
  56. package/dist/run/feedback-round.d.ts +97 -0
  57. package/dist/run/feedback-round.d.ts.map +1 -0
  58. package/dist/run/feedback-round.js +275 -0
  59. package/dist/run/feedback-round.js.map +1 -0
  60. package/dist/run/prerequisite-restack.d.ts +39 -0
  61. package/dist/run/prerequisite-restack.d.ts.map +1 -0
  62. package/dist/run/prerequisite-restack.js +79 -0
  63. package/dist/run/prerequisite-restack.js.map +1 -0
  64. package/dist/run/review-rework-cap.js +1 -1
  65. package/dist/run/review-rework-cap.js.map +1 -1
  66. package/dist/run/review-rework.d.ts +7 -2
  67. package/dist/run/review-rework.d.ts.map +1 -1
  68. package/dist/run/review-rework.js +66 -30
  69. package/dist/run/review-rework.js.map +1 -1
  70. package/dist/run/run-issue.d.ts +3 -0
  71. package/dist/run/run-issue.d.ts.map +1 -1
  72. package/dist/run/run-issue.js +13 -7
  73. package/dist/run/run-issue.js.map +1 -1
  74. package/dist/run/stack-rebase.d.ts +28 -0
  75. package/dist/run/stack-rebase.d.ts.map +1 -0
  76. package/dist/run/stack-rebase.js +79 -0
  77. package/dist/run/stack-rebase.js.map +1 -0
  78. package/dist/run/stack-restack.d.ts.map +1 -1
  79. package/dist/run/stack-restack.js +21 -49
  80. package/dist/run/stack-restack.js.map +1 -1
  81. package/package.json +5 -5
@@ -0,0 +1,275 @@
1
+ // packages/core/src/run/feedback-round.ts — a feedback round on a factory PR: collect unhandled trusted feedback, triage it, rework or re-plan, then answer each item and resolve what was fixed (#3910)
2
+ import { z } from 'zod';
3
+ import { parseReworkCommand } from '../queue/comment-rework-trigger.js';
4
+ import { extractJsonObject } from '../readiness/decompose.js';
5
+ import { UNTRUSTED_REVIEW_FEEDBACK_NOTICE, wrapUntrustedReviewFeedback } from '../utils/untrusted-input.js';
6
+ import { ReviewReworkError } from './review-rework.js';
7
+ const DispositionSchema = z.object({
8
+ id: z.number(),
9
+ kind: z.enum(['review', 'inline', 'comment']),
10
+ verdict: z.enum(['actionable', 'question', 'out-of-scope']),
11
+ changesSpec: z.boolean().default(false),
12
+ summary: z.string().default(''),
13
+ answer: z.string().optional(),
14
+ reason: z.string().optional(),
15
+ followUpIssue: z.number().optional(),
16
+ });
17
+ const MARKER_RE = /<!-- factory:feedback-handled (review|inline|comment):(\d+) -->/g;
18
+ const FEEDBACK_MAX_CHARS = 20_000;
19
+ const REVISED_SPEC_OPEN = '<!-- factory:revised-spec -->';
20
+ const REVISED_SPEC_CLOSE = '<!-- /factory:revised-spec -->';
21
+ const errorMessage = (err) => (err instanceof Error ? err.message : String(err));
22
+ const itemKey = (item) => `${item.kind}:${item.id}`;
23
+ export function feedbackHandledMarker(item) {
24
+ return `<!-- factory:feedback-handled ${itemKey(item)} -->`;
25
+ }
26
+ function handledKeys(bodies) {
27
+ const handled = new Set();
28
+ for (const body of bodies) {
29
+ for (const m of body.matchAll(MARKER_RE))
30
+ handled.add(`${m[1]}:${m[2]}`);
31
+ }
32
+ return handled;
33
+ }
34
+ /** Trusted, unhandled feedback on the PR, oldest id first. Factory-authored, empty and marker-handled items are dropped. */
35
+ export async function collectFeedbackItems(opts) {
36
+ const { github, prNumber, isTrusted } = opts;
37
+ const viewer = (await github.viewerLogin()).toLowerCase();
38
+ const [reviews, inline, comments, threads] = await Promise.all([
39
+ github.listReviews(prNumber),
40
+ github.listReviewComments(prNumber),
41
+ github.listIssueComments(prNumber),
42
+ github.listReviewThreads(prNumber),
43
+ ]);
44
+ const isViewer = (login) => login.toLowerCase() === viewer;
45
+ const handled = handledKeys([
46
+ ...comments.filter((c) => isViewer(c.login)).map((c) => c.body),
47
+ ...inline.filter((c) => isViewer(c.login)).map((c) => c.body),
48
+ ]);
49
+ const threadOf = (commentId) => threads.find((t) => t.commentIds.includes(commentId))?.threadId;
50
+ const candidates = [
51
+ ...reviews.map((r) => ({ kind: 'review', id: r.id, author: r.login, body: r.body, url: r.htmlUrl })),
52
+ ...inline.map((c) => ({
53
+ kind: 'inline',
54
+ id: c.id,
55
+ author: c.login,
56
+ body: c.body,
57
+ url: c.htmlUrl,
58
+ path: c.path,
59
+ ...(c.line === undefined ? {} : { line: c.line }),
60
+ ...(threadOf(c.id) === undefined ? {} : { threadId: threadOf(c.id) }),
61
+ ...(c.inReplyTo === undefined ? {} : { inReplyTo: c.inReplyTo }),
62
+ })),
63
+ ...comments.map((c) => {
64
+ const command = parseReworkCommand(c.body);
65
+ return { kind: 'comment', id: c.id, author: c.login, body: command ?? c.body, url: c.htmlUrl };
66
+ }),
67
+ ];
68
+ const trust = new Map();
69
+ const items = [];
70
+ for (const item of candidates) {
71
+ if (isViewer(item.author) || item.body.trim() === '' || handled.has(itemKey(item)))
72
+ continue;
73
+ let trusted = trust.get(item.author);
74
+ if (trusted === undefined) {
75
+ trusted = await isTrusted(item.author);
76
+ trust.set(item.author, trusted);
77
+ }
78
+ if (trusted)
79
+ items.push(item);
80
+ }
81
+ return items.sort((a, b) => a.id - b.id);
82
+ }
83
+ const failClosed = (item) => ({
84
+ id: item.id,
85
+ kind: item.kind,
86
+ verdict: 'actionable',
87
+ changesSpec: false,
88
+ summary: '',
89
+ });
90
+ function renderItem(item) {
91
+ const where = item.path === undefined ? '' : `${item.path}${item.line === undefined ? '' : `:${item.line}`} `;
92
+ return `- ${item.kind} ${item.id} ${where}(@${item.author}):\n ${item.body}`;
93
+ }
94
+ /** One model call over every item; any parse failure, or a missing or unknown id, falls back to actionable. */
95
+ export async function triageFeedback(opts) {
96
+ const { items, spec, run } = opts;
97
+ if (items.length === 0)
98
+ return [];
99
+ const prompt = [
100
+ 'You triage review feedback on a pull request the factory opened. Judge each item against the frozen spec below.',
101
+ 'For every item answer with a verdict:',
102
+ '- "actionable": it asks for a code or doc change in scope of this PR.',
103
+ '- "question": it asks something to answer; put the reply in "answer".',
104
+ '- "out-of-scope": it asks for work outside this PR; put the reason in "reason".',
105
+ 'Set "changesSpec" to true only when an actionable item changes the PR\'s goal, scope or acceptance criteria.',
106
+ 'Put a one-line description of the change (actionable) in "summary".',
107
+ 'Reply with one JSON object: {"items":[{"id":<number>,"kind":"review"|"inline"|"comment","verdict":...,"changesSpec":<boolean>,"summary":"...","answer":"...","reason":"..."}]} and nothing else.',
108
+ '',
109
+ '## Frozen spec',
110
+ spec,
111
+ '',
112
+ '## Feedback items',
113
+ UNTRUSTED_REVIEW_FEEDBACK_NOTICE,
114
+ ...items.map((item) => wrapUntrustedReviewFeedback(renderItem(item))),
115
+ ].join('\n');
116
+ const byKey = new Map();
117
+ try {
118
+ const { output } = await run(prompt);
119
+ const json = extractJsonObject(output);
120
+ const parsed = json === undefined ? undefined : JSON.parse(json);
121
+ const raw = typeof parsed === 'object' && parsed !== null && 'items' in parsed ? parsed.items : undefined;
122
+ for (const entry of Array.isArray(raw) ? raw : []) {
123
+ const d = DispositionSchema.safeParse(entry);
124
+ if (d.success)
125
+ byKey.set(itemKey(d.data), d.data);
126
+ }
127
+ }
128
+ catch {
129
+ // unparsable or failed triage reads as no dispositions, so every item fails closed
130
+ }
131
+ return items.map((item) => byKey.get(itemKey(item)) ?? failClosed(item));
132
+ }
133
+ const dispositionFor = (dispositions, item) => dispositions.find((d) => d.kind === item.kind && d.id === item.id);
134
+ /** The actionable items as a one-result CheckSummary for the rework worker; undefined when nothing is actionable. */
135
+ export function feedbackReworkSummary(items, dispositions) {
136
+ const actionable = items.filter((i) => dispositionFor(dispositions, i)?.verdict === 'actionable');
137
+ if (actionable.length === 0)
138
+ return undefined;
139
+ let inner = ['Feedback to address on the open PR:', ...actionable.map(renderItem)].join('\n');
140
+ if (inner.length > FEEDBACK_MAX_CHARS)
141
+ inner = `${inner.slice(0, FEEDBACK_MAX_CHARS)}\n… (feedback truncated)`;
142
+ return {
143
+ failures: 1,
144
+ passes: 0,
145
+ skips: 0,
146
+ total: 1,
147
+ results: [
148
+ {
149
+ checker: 'review_feedback',
150
+ result: 'FAIL',
151
+ details: `${UNTRUSTED_REVIEW_FEEDBACK_NOTICE}\n${wrapUntrustedReviewFeedback(inner)}`,
152
+ },
153
+ ],
154
+ };
155
+ }
156
+ /** Reads, triages and plans one round; throws ReviewReworkError unless the PR is open. */
157
+ export async function prepareFeedbackRound(opts) {
158
+ const { github, target, spec, isTrusted, run, log } = opts;
159
+ const pull = await github.getPull(target.prNumber);
160
+ if (pull.state !== 'open') {
161
+ throw new ReviewReworkError(`PR #${target.prNumber} must be open for a feedback round; found ${pull.state}`);
162
+ }
163
+ const items = await collectFeedbackItems({ github, prNumber: target.prNumber, isTrusted });
164
+ const dispositions = await triageFeedback({ items, spec, run });
165
+ const count = (verdict) => dispositions.filter((d) => d.verdict === verdict).length;
166
+ log('feedback_round_triaged', `PR #${target.prNumber}: ${items.length} feedback item(s) — ${count('actionable')} actionable, ${count('question')} question, ${count('out-of-scope')} out-of-scope`);
167
+ const excluded = new Set([pull.author.toLowerCase(), (await github.viewerLogin()).toLowerCase()]);
168
+ const reviewers = [...new Set(items.map((i) => i.author))].filter((a) => !excluded.has(a.toLowerCase()));
169
+ return {
170
+ prNumber: target.prNumber,
171
+ items,
172
+ dispositions,
173
+ replan: dispositions.some((d) => d.verdict === 'actionable' && d.changesSpec),
174
+ reviewers,
175
+ summary: feedbackReworkSummary(items, dispositions),
176
+ };
177
+ }
178
+ /** The reply posted where the item was left, ending in the handled marker. */
179
+ export function renderFeedbackReply(item, disposition, ctx) {
180
+ let text;
181
+ if (disposition.verdict === 'actionable') {
182
+ const fixed = ctx.headSha === undefined
183
+ ? 'Fixed in the latest push'
184
+ : `Fixed in [\`${ctx.headSha.slice(0, 7)}\`](https://github.com/${ctx.repo}/commit/${ctx.headSha})`;
185
+ text = disposition.summary === '' ? fixed : `${fixed}: ${disposition.summary}`;
186
+ }
187
+ else if (disposition.verdict === 'question') {
188
+ text =
189
+ disposition.answer ?? 'Thanks for the question; see the PR description for the reasoning behind this change.';
190
+ }
191
+ else {
192
+ text = `Not changed: ${disposition.reason ?? 'this is outside the scope of this PR.'}`;
193
+ if (disposition.followUpIssue !== undefined)
194
+ text += `\n\nFollow-up: #${disposition.followUpIssue}`;
195
+ }
196
+ const quote = item.kind === 'inline' ? [] : [`> [@${item.author}](${item.url})`, ''];
197
+ return [...quote, text, '', feedbackHandledMarker(item)].join('\n');
198
+ }
199
+ function withRevisedSpec(body, summary) {
200
+ const block = `${REVISED_SPEC_OPEN}\n## Revised spec\n\n${summary}\n${REVISED_SPEC_CLOSE}`;
201
+ const start = body.indexOf(REVISED_SPEC_OPEN);
202
+ const end = body.indexOf(REVISED_SPEC_CLOSE);
203
+ if (start >= 0 && end > start)
204
+ return `${body.slice(0, start)}${block}${body.slice(end + REVISED_SPEC_CLOSE.length)}`;
205
+ return body === '' ? block : `${body}\n\n${block}`;
206
+ }
207
+ /** Replies to every item, records a revised spec, resolves fixed threads and re-requests review; GitHub errors warn and continue. */
208
+ export async function publishFeedbackRound(opts) {
209
+ const { github, plan, repo, headSha, revisedSpecSummary, log } = opts;
210
+ const warn = (what, err) => log('rework', `feedback round: ${what} failed — ${errorMessage(err)}`);
211
+ const replied = new Set();
212
+ for (const item of plan.items) {
213
+ const disposition = dispositionFor(plan.dispositions, item) ?? failClosed(item);
214
+ const body = renderFeedbackReply(item, disposition, { repo, headSha });
215
+ try {
216
+ if (item.kind === 'inline')
217
+ await github.replyToReviewComment(plan.prNumber, item.inReplyTo ?? item.id, body);
218
+ else
219
+ await github.postIssueComment(plan.prNumber, body);
220
+ replied.add(itemKey(item));
221
+ }
222
+ catch (err) {
223
+ warn(`reply to ${itemKey(item)}`, err);
224
+ }
225
+ }
226
+ if (revisedSpecSummary !== undefined) {
227
+ try {
228
+ const pull = await github.getPull(plan.prNumber);
229
+ await github.updatePullBody(plan.prNumber, withRevisedSpec(pull.body, revisedSpecSummary));
230
+ }
231
+ catch (err) {
232
+ warn('revised-spec update of the PR body', err);
233
+ }
234
+ }
235
+ const toResolve = new Set();
236
+ for (const item of plan.items) {
237
+ const verdict = dispositionFor(plan.dispositions, item)?.verdict ?? 'actionable';
238
+ if (item.kind === 'inline' && verdict === 'actionable' && item.threadId && replied.has(itemKey(item))) {
239
+ toResolve.add(item.threadId);
240
+ }
241
+ }
242
+ let resolved = 0;
243
+ if (toResolve.size > 0) {
244
+ try {
245
+ const open = new Set((await github.listReviewThreads(plan.prNumber)).filter((t) => !t.isResolved).map((t) => t.threadId));
246
+ for (const threadId of toResolve) {
247
+ if (!open.has(threadId))
248
+ continue;
249
+ try {
250
+ await github.resolveThread(threadId);
251
+ resolved++;
252
+ }
253
+ catch (err) {
254
+ warn(`resolving thread ${threadId}`, err);
255
+ }
256
+ }
257
+ }
258
+ catch (err) {
259
+ warn('listing review threads', err);
260
+ }
261
+ }
262
+ let reviewersRequested = [];
263
+ if (plan.reviewers.length > 0) {
264
+ try {
265
+ await github.requestReviewers(plan.prNumber, plan.reviewers);
266
+ reviewersRequested = [...plan.reviewers];
267
+ }
268
+ catch (err) {
269
+ warn('re-requesting review', err);
270
+ }
271
+ }
272
+ log('feedback_round_replied', `PR #${plan.prNumber}: replied to ${replied.size}/${plan.items.length} item(s), resolved ${resolved} thread(s), re-requested review from ${reviewersRequested.length} reviewer(s)`);
273
+ return { replied: replied.size, resolved, reviewersRequested };
274
+ }
275
+ //# sourceMappingURL=feedback-round.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback-round.js","sourceRoot":"","sources":["../../src/run/feedback-round.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { Octokit } from '@octokit/rest';
2
+ import type { PrerequisiteStackTarget } from '../queue/prerequisite-stack.js';
3
+ export interface PrerequisiteRestackOptions {
4
+ /** Main checkout; a short-lived detached worktree is added from it. */
5
+ repoRoot: string;
6
+ octokit: Octokit;
7
+ /** owner/name */
8
+ repo: string;
9
+ /** The stacked PR. */
10
+ prNumber: number;
11
+ branch: string;
12
+ /** The stacked branch head the factory last saw; the push lease and the ownership check. */
13
+ recordedHead: string;
14
+ /** The prerequisite PR and head the stacked branch was built on (from the PR body marker). */
15
+ stackedOn: PrerequisiteStackTarget;
16
+ onto: {
17
+ kind: 'main';
18
+ mergedHead: string;
19
+ } | {
20
+ kind: 'prerequisite';
21
+ newHead: string;
22
+ };
23
+ /** Default 'origin'. */
24
+ remote?: string;
25
+ /** Default 'main'. */
26
+ baseBranch?: string;
27
+ }
28
+ export type PrerequisiteRestackOutcome = {
29
+ status: 'restacked';
30
+ headSha: string;
31
+ retargeted: boolean;
32
+ } | {
33
+ status: 'park';
34
+ reason: string;
35
+ files: string[];
36
+ };
37
+ /** Rebases the stacked branch `--onto` main (prerequisite merged) or the prerequisite's new head, then updates the PR. */
38
+ export declare function restackOnPrerequisite(opts: PrerequisiteRestackOptions): Promise<PrerequisiteRestackOutcome>;
39
+ //# sourceMappingURL=prerequisite-restack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerequisite-restack.d.ts","sourceRoot":"","sources":["../../src/run/prerequisite-restack.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAI9E,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,YAAY,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,SAAS,EAAE,uBAAuB,CAAC;IACnC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACvF,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,0BAA0B,GACpC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAQtH,0HAA0H;AAC1H,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CA+EjH"}
@@ -0,0 +1,79 @@
1
+ // packages/core/src/run/prerequisite-restack.ts — cross-issue stacks (#3916): rebase a stacked PR onto main after its
2
+ // prerequisite squash-merged, or onto the prerequisite's new head after it moved. Reuses ADR-0161's rebase/push.
3
+ import { prerequisiteStackOrder, renderPrerequisiteStackLine, replaceStackOrderLine } from '../phases/stack-order.js';
4
+ import { execGit } from '../utils/git-exec.js';
5
+ import { gitErrorDetail, rebaseAndPushStack } from './stack-rebase.js';
6
+ const PREREQUISITE_MARKER_PREFIX = '<!-- factory:prerequisite-stack ';
7
+ async function git(cwd, ...args) {
8
+ return (await execGit(args, { cwd })).stdout.trim();
9
+ }
10
+ /** Rebases the stacked branch `--onto` main (prerequisite merged) or the prerequisite's new head, then updates the PR. */
11
+ export async function restackOnPrerequisite(opts) {
12
+ const { repoRoot, octokit, prNumber, branch, recordedHead, stackedOn, onto } = opts;
13
+ const remote = opts.remote ?? 'origin';
14
+ const base = opts.baseBranch ?? 'main';
15
+ const [owner, repoName] = opts.repo.split('/');
16
+ const park = (reason, files = []) => ({
17
+ status: 'park',
18
+ reason,
19
+ files,
20
+ });
21
+ const label = `PR #${prNumber} (${branch})`;
22
+ let startBase;
23
+ try {
24
+ await git(repoRoot, 'fetch', remote, `+refs/heads/${base}:refs/remotes/${remote}/${base}`);
25
+ await git(repoRoot, 'fetch', remote, `+refs/heads/${branch}:refs/remotes/${remote}/${branch}`);
26
+ if (onto.kind === 'prerequisite') {
27
+ await git(repoRoot, 'fetch', remote, `+refs/heads/${stackedOn.branch}:refs/remotes/${remote}/${stackedOn.branch}`);
28
+ await git(repoRoot, 'cat-file', '-e', `${onto.newHead}^{commit}`);
29
+ startBase = onto.newHead;
30
+ }
31
+ else {
32
+ startBase = `${remote}/${base}`;
33
+ }
34
+ const head = await git(repoRoot, 'rev-parse', `refs/remotes/${remote}/${branch}`);
35
+ if (head !== recordedHead) {
36
+ return park(`${label} moved since the factory recorded ${recordedHead}; a human may have pushed — not restacking onto prerequisite PR #${stackedOn.prNumber}`);
37
+ }
38
+ }
39
+ catch (err) {
40
+ return park(`restack of ${label} onto prerequisite PR #${stackedOn.prNumber} could not fetch: ${gitErrorDetail(err)}`);
41
+ }
42
+ const rebased = await rebaseAndPushStack({
43
+ repoRoot,
44
+ remote,
45
+ startBase,
46
+ layers: [{ branch, recordedHead, upstream: stackedOn.headSha }],
47
+ });
48
+ if (!rebased.ok) {
49
+ return park(`restack of ${label} ${rebased.reason}`, rebased.files);
50
+ }
51
+ const headSha = rebased.newHeads[0];
52
+ try {
53
+ const { data } = await octokit.rest.pulls.get({ owner, repo: repoName, pull_number: prNumber });
54
+ const merged = onto.kind === 'main';
55
+ const retargeted = merged && data.base.ref !== base;
56
+ const without = (data.body ?? '')
57
+ .split('\n')
58
+ .filter((l) => !l.startsWith(PREREQUISITE_MARKER_PREFIX))
59
+ .join('\n');
60
+ const issue = Number(/^factory\/(\d+)-/.exec(branch)?.[1]);
61
+ const body = merged
62
+ ? replaceStackOrderLine(without, renderPrerequisiteStackLine({ prerequisite: stackedOn, issue, base }))
63
+ : replaceStackOrderLine(without, prerequisiteStackOrder({ ...stackedOn, headSha: onto.newHead }, issue, stackedOn.branch));
64
+ if (retargeted || body !== (data.body ?? '')) {
65
+ await octokit.rest.pulls.update({
66
+ owner,
67
+ repo: repoName,
68
+ pull_number: prNumber,
69
+ body,
70
+ ...(retargeted ? { base } : {}),
71
+ });
72
+ }
73
+ return { status: 'restacked', headSha, retargeted };
74
+ }
75
+ catch (err) {
76
+ return park(`${label} restacked and pushed but updating the PR failed: ${gitErrorDetail(err)}`);
77
+ }
78
+ }
79
+ //# sourceMappingURL=prerequisite-restack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerequisite-restack.js","sourceRoot":"","sources":["../../src/run/prerequisite-restack.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ export function countReviewReworkRuns(store, issue) {
12
12
  }
13
13
  export function reviewReworkCapMessage(input) {
14
14
  const { issue, pr, cap, count, reviewIds } = input;
15
- const what = input.source === 'comment' ? 'comment' : 'review';
15
+ const what = input.source === 'comment' ? 'comment' : input.source === 'feedback' ? 'feedback round' : 'review';
16
16
  return `#${issue} has had ${count} review-rework runs (cap ${cap}, queue.max_review_rework_runs); PR #${pr} ${what} ${reviewIds.join(', ')} started no new run. Resolve the review by hand, then run \`factory unpark ${issue}\`.`;
17
17
  }
18
18
  export async function parkAtReviewReworkCap(deps) {
@@ -1 +1 @@
1
- {"version":3,"file":"review-rework-cap.js","sourceRoot":"","sources":["../../src/run/review-rework-cap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"review-rework-cap.js","sourceRoot":"","sources":["../../src/run/review-rework-cap.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { Octokit } from '@octokit/rest';
2
2
  import { reworkWorker, type checkPhase } from '../phases/check.js';
3
3
  import type { CheckSummary } from '../types/index.js';
4
+ import type { FeedbackRoundPlan, FeedbackRoundTarget } from './feedback-round.js';
4
5
  import type { RunPorts, RunRequest } from './run-issue.js';
5
6
  export interface ReviewReworkTarget {
6
7
  prNumber: number;
@@ -21,6 +22,10 @@ export interface ReworkRequestFields {
21
22
  reviewRework?: ReviewReworkTarget;
22
23
  /** #3625: a /factory iterate comment — skip PLAN/BUILD and re-run CHECK/rework on the PR branch. */
23
24
  iterate?: IterateTarget;
25
+ /** #3910: a feedback round — read every unhandled trusted PR feedback item, triage, then rework or re-plan. */
26
+ feedbackRound?: FeedbackRoundTarget;
27
+ /** Logins trusted to give feedback (intake.trustedApprovers); absent falls back to repo permission (ADR-0128). */
28
+ trustedApprovers?: readonly string[];
24
29
  }
25
30
  export interface ReviewFeedback {
26
31
  prNumber: number;
@@ -58,7 +63,7 @@ export declare function renderReviewFeedback(feedback: ReviewFeedback): string;
58
63
  /** The review as a one-result CheckSummary, the same shape ciReworkSummary gives the rework worker. */
59
64
  export declare function reviewReworkSummary(feedback: ReviewFeedback): CheckSummary;
60
65
  /** A synthetic CHECK resume: skips PLAN and BUILD for a review-rework run. */
61
- export declare function reviewReworkResume(request: Pick<RunRequest, 'reviewRework' | 'iterate' | 'preferredRoute' | 'modelPins'>): NonNullable<RunRequest['resumeFrom']> | undefined;
66
+ export declare function reviewReworkResume(request: Pick<RunRequest, 'reviewRework' | 'iterate' | 'feedbackRound' | 'preferredRoute' | 'modelPins'>, feedbackPlan?: Pick<FeedbackRoundPlan, 'replan'>): NonNullable<RunRequest['resumeFrom']> | undefined;
62
67
  export declare function runReviewReworkBuild(opts: {
63
68
  target: ReviewReworkTarget;
64
69
  repo: string;
@@ -70,5 +75,5 @@ export declare function runReviewReworkBuild(opts: {
70
75
  feedback: ReviewFeedback;
71
76
  }>;
72
77
  /** runIssue's hook before the first CHECK: reworks the requested review unless a CHECK resume was asked for. */
73
- export declare function runRequestedReviewRework(request: Pick<RunRequest, 'reviewRework' | 'iterate' | 'resumeFrom' | 'repo' | 'branch'>, ports: Pick<RunPorts, 'octokit' | 'reworkWorker'>, checkOpts: Parameters<typeof checkPhase>[0]): Promise<void>;
78
+ export declare function runRequestedReviewRework(request: Pick<RunRequest, 'reviewRework' | 'iterate' | 'feedbackRound' | 'resumeFrom' | 'repo' | 'branch'>, ports: Pick<RunPorts, 'octokit' | 'reworkWorker'>, checkOpts: Parameters<typeof checkPhase>[0], feedbackPlan?: Pick<FeedbackRoundPlan, 'prNumber' | 'summary'>): Promise<void>;
74
79
  //# sourceMappingURL=review-rework.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"review-rework.d.ts","sourceRoot":"","sources":["../../src/run/review-rework.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"review-rework.d.ts","sourceRoot":"","sources":["../../src/run/review-rework.ts"],"names":[],"mappings":"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"}
@@ -86,8 +86,10 @@ export function reviewReworkSummary(feedback) {
86
86
  };
87
87
  }
88
88
  /** A synthetic CHECK resume: skips PLAN and BUILD for a review-rework run. */
89
- export function reviewReworkResume(request) {
90
- if (!request.reviewRework && !request.iterate)
89
+ export function reviewReworkResume(request, feedbackPlan) {
90
+ if (feedbackPlan?.replan)
91
+ return undefined;
92
+ if (!request.reviewRework && !request.iterate && !request.feedbackRound)
91
93
  return undefined;
92
94
  return {
93
95
  phase: 'check',
@@ -96,6 +98,43 @@ export function reviewReworkResume(request) {
96
98
  buildMinutes: 0,
97
99
  };
98
100
  }
101
+ /** Fails closed unless the PR is open with `branch` as head, so a rework can never ship to a different PR. */
102
+ async function assertOpenPrHead(octokit, opts) {
103
+ const { data: pull } = await octokit.rest.pulls.get({
104
+ owner: opts.owner,
105
+ repo: opts.repo,
106
+ pull_number: opts.prNumber,
107
+ });
108
+ if (pull.state !== 'open' || pull.head.ref !== opts.branch) {
109
+ throw new ReviewReworkError(`PR #${opts.prNumber} must be open with head ${opts.branch}; found ${pull.state} with head ${pull.head.ref}`);
110
+ }
111
+ }
112
+ /** One rework worker call on the PR branch for `summary`; throws when the worker never ran. */
113
+ async function runReworkWorker(checkOpts, summary, where, rework) {
114
+ const worked = await rework({
115
+ issue: checkOpts.issue,
116
+ worktree: checkOpts.worktree,
117
+ specPath: checkOpts.specPath,
118
+ summary,
119
+ constitution: checkOpts.constitution,
120
+ router: checkOpts.router,
121
+ log: checkOpts.log,
122
+ buildTimeoutSeconds: checkOpts.buildTimeoutSeconds,
123
+ sandbox: checkOpts.sandbox,
124
+ appPort: checkOpts.appPort,
125
+ appBaseUrl: checkOpts.appBaseUrl,
126
+ onPgid: checkOpts.onPgid,
127
+ budgetGuard: checkOpts.budgetGuard,
128
+ reworkRoute: checkOpts.reworkRoute,
129
+ reworkModel: checkOpts.reworkModel,
130
+ runId: checkOpts.runId,
131
+ onWorkerResult: checkOpts.onWorkerResult,
132
+ extraInstructions: REVIEW_REWORK_INSTRUCTIONS,
133
+ });
134
+ if (!worked.modelCompleted) {
135
+ throw new ReviewReworkError(`review rework worker never ran for ${where}${worked.failureReason ? `: ${worked.failureReason}` : ''}`);
136
+ }
137
+ }
99
138
  export async function runReviewReworkBuild(opts) {
100
139
  const { target, repo, branch, octokit, checkOpts, rework = reworkWorker } = opts;
101
140
  const [owner = '', name = ''] = repo.split('/');
@@ -103,10 +142,7 @@ export async function runReviewReworkBuild(opts) {
103
142
  const where = `PR #${target.prNumber} / ${kind} ${target.reviewId}`;
104
143
  let feedback;
105
144
  try {
106
- const { data: pull } = await octokit.rest.pulls.get({ owner, repo: name, pull_number: target.prNumber });
107
- if (pull.state !== 'open' || pull.head.ref !== branch) {
108
- throw new ReviewReworkError(`PR #${target.prNumber} must be open with head ${branch}; found ${pull.state} with head ${pull.head.ref}`);
109
- }
145
+ await assertOpenPrHead(octokit, { owner, repo: name, prNumber: target.prNumber, branch });
110
146
  feedback =
111
147
  target.source === 'comment'
112
148
  ? await fetchCommentFeedback(octokit, {
@@ -128,29 +164,7 @@ export async function runReviewReworkBuild(opts) {
128
164
  throw new ReviewReworkError(`could not read ${where}: ${errorMessage(err)}`, { cause: err });
129
165
  }
130
166
  checkOpts.log('rework', `review rework: PR #${target.prNumber} ${kind} ${target.reviewId} by @${target.reviewer} — ${feedback.comments.length} inline comment(s) on ${branch}`);
131
- const worked = await rework({
132
- issue: checkOpts.issue,
133
- worktree: checkOpts.worktree,
134
- specPath: checkOpts.specPath,
135
- summary: reviewReworkSummary(feedback),
136
- constitution: checkOpts.constitution,
137
- router: checkOpts.router,
138
- log: checkOpts.log,
139
- buildTimeoutSeconds: checkOpts.buildTimeoutSeconds,
140
- sandbox: checkOpts.sandbox,
141
- appPort: checkOpts.appPort,
142
- appBaseUrl: checkOpts.appBaseUrl,
143
- onPgid: checkOpts.onPgid,
144
- budgetGuard: checkOpts.budgetGuard,
145
- reworkRoute: checkOpts.reworkRoute,
146
- reworkModel: checkOpts.reworkModel,
147
- runId: checkOpts.runId,
148
- onWorkerResult: checkOpts.onWorkerResult,
149
- extraInstructions: REVIEW_REWORK_INSTRUCTIONS,
150
- });
151
- if (!worked.modelCompleted) {
152
- throw new ReviewReworkError(`review rework worker never ran for ${where}${worked.failureReason ? `: ${worked.failureReason}` : ''}`);
153
- }
167
+ await runReworkWorker(checkOpts, reviewReworkSummary(feedback), where, rework);
154
168
  return { feedback };
155
169
  }
156
170
  /** Iterate fails closed unless the PR is still open with the run branch as head, so SHIP can never open a new PR. */
@@ -170,9 +184,31 @@ async function guardIterateTarget(target, request, octokit, checkOpts) {
170
184
  checkOpts.log('rework', `iterate: PR #${target.prNumber} by @${target.actor} (comment ${target.commentId}) — re-running CHECK on ${request.branch}`);
171
185
  }
172
186
  /** runIssue's hook before the first CHECK: reworks the requested review unless a CHECK resume was asked for. */
173
- export async function runRequestedReviewRework(request, ports, checkOpts) {
187
+ export async function runRequestedReviewRework(request, ports, checkOpts, feedbackPlan) {
174
188
  if (request.resumeFrom)
175
189
  return;
190
+ if (feedbackPlan) {
191
+ if (feedbackPlan.summary === undefined)
192
+ return;
193
+ const where = `PR #${feedbackPlan.prNumber} / feedback round`;
194
+ const [owner = '', name = ''] = request.repo.split('/');
195
+ try {
196
+ await assertOpenPrHead(ports.octokit, {
197
+ owner,
198
+ repo: name,
199
+ prNumber: feedbackPlan.prNumber,
200
+ branch: request.branch,
201
+ });
202
+ }
203
+ catch (err) {
204
+ if (err instanceof ReviewReworkError)
205
+ throw err;
206
+ throw new ReviewReworkError(`could not read ${where}: ${errorMessage(err)}`, { cause: err });
207
+ }
208
+ checkOpts.log('rework', `feedback round: reworking PR #${feedbackPlan.prNumber} on ${request.branch}`);
209
+ await runReworkWorker(checkOpts, feedbackPlan.summary, where, ports.reworkWorker ?? reworkWorker);
210
+ return;
211
+ }
176
212
  if (!request.reviewRework) {
177
213
  if (request.iterate)
178
214
  await guardIterateTarget(request.iterate, request, ports.octokit, checkOpts);