Skip to content

Commit af56100

Browse files
mchwangclaude
andcommitted
Refresh only an opened PR: drop beginRefresh's unused adopt path
Adoption of an abandoned opening's PR happens in adoptOpening, under the state-version guard, when publish first sees the PR. beginRefresh now requires an opened row, leaving one adoption path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 8a4e5ea commit af56100

2 files changed

Lines changed: 11 additions & 6 deletions

File tree

‎runner/store.ts‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -991,16 +991,13 @@ export class Store {
991991
* draft change may land even if their confirmation is lost; the record keeps that visible until the update is
992992
* confirmed or abandoned. Returns the state version the update owns.
993993
*/
994-
beginRefresh(identity: PlanIdentity, input: { checkId: string; openingId: string; headSha: string; draft: boolean; adopt?: { number: number; url: string } }): number {
994+
beginRefresh(identity: PlanIdentity, input: { checkId: string; openingId: string; headSha: string; draft: boolean }): number {
995995
const key = identityKey(identity);
996996
return this.#transaction(() => {
997997
this.#assertCheckedHead(identity, input);
998+
// Only an opened PR is refreshed; an abandoned opening's PR is adopted first, by adoptOpening, when publish sees it.
998999
const row = this.#get('SELECT state FROM task_pull_requests WHERE plan_key=? AND opening_id=?', key, input.openingId);
999-
// An abandoned opening whose PR became visible later is adopted here, under the same guard as the update.
1000-
if (row?.state === 'abandoned' && input.adopt) {
1001-
if (!Number.isSafeInteger(input.adopt.number) || input.adopt.number < 1 || typeof input.adopt.url !== 'string') throw new Error('Invalid pull request.');
1002-
this.#run("UPDATE task_pull_requests SET state='opened', number=?, url=? WHERE opening_id=?", input.adopt.number, input.adopt.url, input.openingId);
1003-
} else if (row?.state !== 'opened') throw new GuardRefusal('Unknown pull request.');
1000+
if (row?.state !== 'opened') throw new GuardRefusal('Unknown pull request.');
10041001
this.#touch(key);
10051002
const version = this.#task(key).state_version as number;
10061003
this.#run('UPDATE task_pull_requests SET refresh_head=?, refresh_draft=?, refresh_version=?, updated_at=? WHERE opening_id=?',

‎test/publish.test.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ describe('PR records', () => {
263263
expect(await publisher.publish(identity)).toMatchObject({ kind: 'opened', number: 9, status: 'cancelled' });
264264
expect(store.taskPullRequests(identity)).toMatchObject([{ state: 'opened', number: 9 }]);
265265
});
266+
it('refreshes only an opened PR: an abandoned opening must be adopted first', async () => {
267+
const store = runningTask();
268+
const clear = () => store.recordAlreadyFixed(identity, store.getTask(identity).stateVersion, { snapshotId: store.getSnapshot(identity).id, draft: false, result: { outcome: 'clear', baseHead: oid(9) } });
269+
const opening = store.beginPullRequest(identity, { checkId: clear().id, repository: 'owner/repo', base: 'main', headBranch: 'b', headSha: oid(2), draft: false });
270+
store.abandonPullRequestOpening(identity, opening.openingId);
271+
expect(() => store.beginRefresh(identity, { checkId: clear().id, openingId: opening.openingId, headSha: oid(2), draft: false })).toThrow(/Unknown pull request/);
272+
expect(store.taskPullRequests(identity)).toMatchObject([{ state: 'abandoned', number: null, refresh: null }]);
273+
});
266274
it('binds an opening to the checked head, with no task change since the check', async () => {
267275
const store = runningTask();
268276
const check = store.recordAlreadyFixed(identity, store.getTask(identity).stateVersion, { snapshotId: store.getSnapshot(identity).id, draft: false, result: { outcome: 'clear', baseHead: oid(9) } });

0 commit comments

Comments
 (0)