@@ -88,10 +88,10 @@ describe("assign_to_agent", () => {
8888 const _tempIdMap = loadTemporaryIdMap();
8989 for (const _item of _items) { await _handler(_item, {}, _tempIdMap); }
9090 }
91- await writeAssignToAgentSummary();
92- const _errorCount = getAssignToAgentErrorCount();
93- core.setOutput("assigned", getAssignToAgentAssigned());
94- core.setOutput("assignment_errors", getAssignToAgentErrors());
91+ await writeAssignToAgentSummary(_handler );
92+ const _errorCount = getAssignToAgentErrorCount(_handler );
93+ core.setOutput("assigned", getAssignToAgentAssigned(_handler ));
94+ core.setOutput("assignment_errors", getAssignToAgentErrors(_handler ));
9595 core.setOutput("assignment_error_count", String(_errorCount));
9696 if (_errorCount > 0) { core.setFailed("Failed to assign " + _errorCount + " agent(s)"); }
9797 ` ;
@@ -1359,6 +1359,88 @@ describe("assign_to_agent", () => {
13591359 expect ( mockSleep ) . toHaveBeenCalledWith ( 10000 ) ;
13601360 } ) ;
13611361
1362+ it ( "does not consume a max slot for invalid items" , async ( ) => {
1363+ mockGithub . rest . issues . checkUserCanBeAssigned . mockResolvedValue ( { } ) ;
1364+ mockGithub . rest . users . getByUsername . mockResolvedValue ( { data : { id : 99999 } } ) ;
1365+ mockGithub . rest . issues . get . mockImplementation ( async ( { issue_number } ) => ( {
1366+ data : { id : Number ( issue_number ) + 1000 , number : issue_number , assignees : [ ] , html_url : "" , title : "" , body : "" } ,
1367+ } ) ) ;
1368+ mockGithub . request . mockResolvedValue ( { data : { id : "task-123" } } ) ;
1369+
1370+ const result = await eval ( `(async () => {
1371+ ${ assignToAgentScript } ;
1372+ const _handler = await main({ max: "1", name: "copilot" });
1373+ const _invalid = await _handler({ type: "assign_to_agent", issue_number: 1, pull_number: 2, agent: "copilot" }, {}, new Map());
1374+ const _valid = await _handler({ type: "assign_to_agent", issue_number: 3, agent: "copilot" }, {}, new Map());
1375+ return {
1376+ invalid: _invalid,
1377+ valid: _valid,
1378+ assigned: getAssignToAgentAssigned(_handler),
1379+ };
1380+ })()` ) ;
1381+
1382+ expect ( result . invalid . success ) . toBe ( false ) ;
1383+ expect ( result . valid . success ) . toBe ( true ) ;
1384+ expect ( result . assigned . split ( "\n" ) . filter ( Boolean ) ) . toHaveLength ( 1 ) ;
1385+ } ) ;
1386+
1387+ it ( "atomically reserves the max slot before the inter-assignment delay" , async ( ) => {
1388+ mockGithub . rest . issues . checkUserCanBeAssigned . mockResolvedValue ( { } ) ;
1389+ mockGithub . rest . users . getByUsername . mockResolvedValue ( { data : { id : 99999 } } ) ;
1390+ mockGithub . rest . issues . get . mockImplementation ( async ( { issue_number } ) => ( {
1391+ data : { id : Number ( issue_number ) + 1000 , number : issue_number , assignees : [ ] , html_url : "" , title : "" , body : "" } ,
1392+ } ) ) ;
1393+ mockGithub . request . mockResolvedValue ( { data : { id : "task-123" } } ) ;
1394+
1395+ let releaseSleep ;
1396+ mockSleep . mockImplementationOnce (
1397+ ( ) =>
1398+ new Promise ( resolve => {
1399+ releaseSleep = resolve ;
1400+ } )
1401+ ) ;
1402+
1403+ const result = await eval ( `(async () => {
1404+ ${ assignToAgentScript } ;
1405+ const _handler = await main({ max: "2", name: "copilot" });
1406+ await _handler({ type: "assign_to_agent", issue_number: 1, agent: "copilot" }, {}, new Map());
1407+ return {
1408+ second: _handler({ type: "assign_to_agent", issue_number: 2, agent: "copilot" }, {}, new Map()),
1409+ third: _handler({ type: "assign_to_agent", issue_number: 3, agent: "copilot" }, {}, new Map()),
1410+ };
1411+ })()` ) ;
1412+
1413+ await vi . waitFor ( ( ) => expect ( mockSleep ) . toHaveBeenCalledTimes ( 1 ) ) ;
1414+ releaseSleep ( ) ;
1415+
1416+ const [ second , third ] = await Promise . all ( [ result . second , result . third ] ) ;
1417+ expect ( second . success ) . toBe ( true ) ;
1418+ expect ( third . skipped ) . toBe ( true ) ;
1419+ } ) ;
1420+
1421+ it ( "keeps assign_to_agent results isolated per main() invocation" , async ( ) => {
1422+ mockGithub . rest . issues . checkUserCanBeAssigned . mockResolvedValue ( { } ) ;
1423+ mockGithub . rest . users . getByUsername . mockResolvedValue ( { data : { id : 99999 } } ) ;
1424+ mockGithub . rest . issues . get . mockImplementation ( async ( { issue_number } ) => ( {
1425+ data : { id : Number ( issue_number ) + 2000 , number : issue_number , assignees : [ ] , html_url : "" , title : "" , body : "" } ,
1426+ } ) ) ;
1427+ mockGithub . request . mockResolvedValue ( { data : { id : "task-123" } } ) ;
1428+
1429+ const result = await eval ( `(async () => {
1430+ ${ assignToAgentScript } ;
1431+ const _handlerA = await main({ max: "5", name: "copilot" });
1432+ const _handlerB = await main({ max: "5", name: "copilot" });
1433+ await _handlerA({ type: "assign_to_agent", issue_number: 11, agent: "copilot" }, {}, new Map());
1434+ return {
1435+ assignedA: getAssignToAgentAssigned(_handlerA),
1436+ assignedB: getAssignToAgentAssigned(_handlerB),
1437+ };
1438+ })()` ) ;
1439+
1440+ expect ( result . assignedA ) . toContain ( "issue:11:copilot" ) ;
1441+ expect ( result . assignedB ) . toBe ( "" ) ;
1442+ } ) ;
1443+
13621444 describe ( "Cross-repository allowlist validation" , ( ) => {
13631445 it ( "should reject target repository not in allowlist" , async ( ) => {
13641446 process . env . GH_AW_ALLOWED_REPOS = "allowed-owner/allowed-repo" ;
0 commit comments