@@ -7,7 +7,7 @@ import { Questions, type QuestionAgent } from '../runner/questions.ts';
77import { GhMergeGateway , type MergeGateway } from '../github/merge.ts' ;
88import { MergeCoordinator , MergeNotApplied , MergeOutcomeUnknown } from '../runner/merge.ts' ;
99import { RunnerCoordinator , type RunnerDeps } from '../runner/coordinator.ts' ;
10- import { BadRequest , GuardRefusal , ShuttingDownError , isUuidV4 , sameContext } from '../runner/lifecycle.ts' ;
10+ import { BadRequest , GuardRefusal , ShuttingDownError , assertUuidV4 , isUuidV4 , sameContext } from '../runner/lifecycle.ts' ;
1111import { GhIssueGateway , type IssueGateway } from '../github/issues.ts' ;
1212import { demoIssueGateway } from '../scripts/demo-issues.ts' ;
1313import { IssueBoard } from './issues.ts' ;
@@ -47,19 +47,20 @@ export async function startServer(config: ReviewConfig, port = 4318, questionAge
4747 } ;
4848 const runnerAction = ( input : Record < string , unknown > ) => {
4949 const { action, attemptId, expectedStateVersion, actionId } = input ;
50- if ( ! [ 'cancel-attempt' , 'retry' , 'cancel-task' ] . includes ( action as string ) ) throw new GuardRefusal ( 'Unsupported runner action.' ) ;
51- if ( ! Number . isSafeInteger ( expectedStateVersion ) ) throw new GuardRefusal ( 'expectedStateVersion is required.' ) ;
50+ // Malformed requests are refused before userAction, so nothing is recorded under their action ID (HTTP 400).
51+ if ( ! [ 'cancel-attempt' , 'retry' , 'cancel-task' ] . includes ( action as string ) ) throw new BadRequest ( 'Unsupported runner action.' ) ;
52+ if ( ! Number . isSafeInteger ( expectedStateVersion ) ) throw new BadRequest ( 'expectedStateVersion must be an integer.' ) ;
53+ if ( action !== 'cancel-task' ) assertUuidV4 ( attemptId , 'Attempt ID' ) ;
5254 return service . store . userAction ( identity , { actionId : actionId as string , kind : action as string , request : { attemptId, expectedStateVersion } } , ( ) => {
5355 if ( service . store . getTask ( identity ) . stateVersion !== expectedStateVersion ) throw new GuardRefusal ( 'Stale task state. Reload before writing.' ) ;
5456 if ( action === 'cancel-task' ) return { outcome : runner ? runner . cancelTask ( identity , expectedStateVersion as number , actionId as string ) : service . store . cancelTask ( identity , expectedStateVersion as number , actionId as string ) } ;
5557 if ( ! runner ) throw new GuardRefusal ( 'The runner is not available yet.' ) ;
56- if ( typeof attemptId !== 'string' ) throw new GuardRefusal ( 'attemptId is required.' ) ;
5758 if ( action === 'cancel-attempt' ) {
58- if ( ! runner . stop ( identity , attemptId , 'cancelled' ) ) throw new GuardRefusal ( 'That attempt is not running.' ) ;
59+ if ( ! runner . stop ( identity , attemptId as string , 'cancelled' ) ) throw new GuardRefusal ( 'That attempt is not running.' ) ;
5960 return { outcome : 'stopping' } ;
6061 }
61- const last = service . store . getAttempt ( identity , attemptId ) ;
62- const retry = runner . retry ( identity , attemptId , { expectedStateVersion : expectedStateVersion as number , kind : last . kind , item : last . item ,
62+ const last = service . store . getAttempt ( identity , attemptId as string ) ;
63+ const retry = runner . retry ( identity , attemptId as string , { expectedStateVersion : expectedStateVersion as number , kind : last . kind , item : last . item ,
6364 expectedContext : service . store . currentContext ( identity ) , deadline : Date . now ( ) + 10 * 60_000 } ) ;
6465 return { outcome : 'started' , attemptId : retry . id } ;
6566 } ) . response ;
0 commit comments