@@ -1942,6 +1942,7 @@ describe("list_agents", () => {
19421942 } ) ;
19431943
19441944 test ( "projects a bound grant_request_id without relying on ask prose" , async ( ) => {
1945+ getProcessWorkerGrantStore ( ) . clear ( ) ;
19451946 const sessions = createSubAgentSessionStore ( ) ;
19461947 const fleetRecords = createFleetMailbox ( sessions ) ;
19471948 const id = "grant-projection" ;
@@ -1996,6 +1997,123 @@ describe("list_agents", () => {
19961997 expect ( waitedAgent . grant_request_id ) . toBe ( envelope . requestId ) ;
19971998 } ) ;
19981999
2000+ test ( "does not rebind a resolved denial to a later generic ask" , async ( ) => {
2001+ getProcessWorkerGrantStore ( ) . clear ( ) ;
2002+ const sessions = createSubAgentSessionStore ( ) ;
2003+ const fleetRecords = createFleetMailbox ( sessions ) ;
2004+ const id = "grant-projection-no-rebind" ;
2005+ sessions . start ( {
2006+ id,
2007+ description : "need approval" ,
2008+ agentId : "a" ,
2009+ brief : "b" ,
2010+ } ) ;
2011+ sessions . markRunning ( id ) ;
2012+ fleetRecords . register ( id ) ;
2013+ const grantStore = getProcessWorkerGrantStore ( ) ;
2014+ const envelopeA = grantStore . register (
2015+ createDeniedCallEnvelope ( {
2016+ callId : "denied-call-A" ,
2017+ tool : "run_shell" ,
2018+ action : "Run" ,
2019+ subject : "git status" ,
2020+ args : { command : "git status" } ,
2021+ cwd : process . cwd ( ) ,
2022+ workerSessionId : id ,
2023+ } ) ,
2024+ ) ;
2025+ expect (
2026+ sessions . registerAsk ( id , {
2027+ question : "Please decide how to proceed." ,
2028+ questionId : "ask-1" ,
2029+ grantRequestId : envelopeA . requestId ,
2030+ assessment : assessedAsk ,
2031+ resolve : ( ) => undefined ,
2032+ reject : ( ) => undefined ,
2033+ } ) ,
2034+ ) . toBe ( true ) ;
2035+ expect (
2036+ sessions . resolveEscalationAsk ( id , {
2037+ kind : "minimum_grant_available" ,
2038+ answer : "continue" ,
2039+ questionId : "ask-1" ,
2040+ } ) ,
2041+ ) . toBe ( true ) ;
2042+ expect ( grantStore . peek ( envelopeA . requestId ) ?. status ) . toBe ( "pending" ) ;
2043+
2044+ expect (
2045+ sessions . registerAsk ( id , {
2046+ question : "What should I do next?" ,
2047+ questionId : "ask-2" ,
2048+ assessment : assessedAsk ,
2049+ resolve : ( ) => undefined ,
2050+ reject : ( ) => undefined ,
2051+ } ) ,
2052+ ) . toBe ( true ) ;
2053+ expect ( sessions . peekAsk ( id ) ?. deniedCall ) . toBeUndefined ( ) ;
2054+
2055+ const list = createListAgentsTool ( { sessions, fleetRecords } ) ;
2056+ const listed = parseFleetJson (
2057+ ( await callFleetToolRaw ( list , { } ) ) . content ,
2058+ ) as { agents : { grant_request_id ?: string } [ ] } ;
2059+ expect ( defined ( listed . agents [ 0 ] ) . grant_request_id ) . toBeUndefined ( ) ;
2060+
2061+ const wait = createWaitAgentsTool ( { sessions, fleetRecords } ) ;
2062+ const waited = await callFleetTool ( wait , {
2063+ targets : [ id ] ,
2064+ timeout_ms : 1 ,
2065+ } ) ;
2066+ expect (
2067+ defined ( ( waited . results as { grant_request_id ?: string } [ ] ) [ 0 ] )
2068+ . grant_request_id ,
2069+ ) . toBeUndefined ( ) ;
2070+
2071+ expect ( sessions . resolveAsk ( id , "continue" ) ) . toBe ( true ) ;
2072+ const envelopeB = grantStore . register (
2073+ createDeniedCallEnvelope ( {
2074+ callId : "denied-call-B" ,
2075+ tool : "run_shell" ,
2076+ action : "Run" ,
2077+ subject : "git diff" ,
2078+ args : { command : "git diff" } ,
2079+ cwd : process . cwd ( ) ,
2080+ workerSessionId : id ,
2081+ } ) ,
2082+ ) ;
2083+ expect (
2084+ sessions . registerAsk ( id , {
2085+ question : "May I retry git diff?" ,
2086+ questionId : "ask-3" ,
2087+ grantRequestId : envelopeB . requestId ,
2088+ assessment : assessedAsk ,
2089+ resolve : ( ) => undefined ,
2090+ reject : ( ) => undefined ,
2091+ } ) ,
2092+ ) . toBe ( true ) ;
2093+ expect ( sessions . peekAsk ( id ) ?. deniedCall ?. requestId ) . toBe (
2094+ envelopeB . requestId ,
2095+ ) ;
2096+ expect ( grantStore . peek ( envelopeA . requestId ) ?. questionId ) . toBe ( "ask-1" ) ;
2097+
2098+ const listB = createListAgentsTool ( { sessions, fleetRecords } ) ;
2099+ const listedB = parseFleetJson (
2100+ ( await callFleetToolRaw ( listB , { } ) ) . content ,
2101+ ) as { agents : { grant_request_id ?: string } [ ] } ;
2102+ expect ( defined ( listedB . agents [ 0 ] ) . grant_request_id ) . toBe (
2103+ envelopeB . requestId ,
2104+ ) ;
2105+
2106+ const waitB = createWaitAgentsTool ( { sessions, fleetRecords } ) ;
2107+ const waitedB = await callFleetTool ( waitB , {
2108+ targets : [ id ] ,
2109+ timeout_ms : 1 ,
2110+ } ) ;
2111+ expect (
2112+ defined ( ( waitedB . results as { grant_request_id ?: string } [ ] ) [ 0 ] )
2113+ . grant_request_id ,
2114+ ) . toBe ( envelopeB . requestId ) ;
2115+ } ) ;
2116+
19992117 test ( "errors after wait_agents surfaces awaiting_director with a question" , async ( ) => {
20002118 const { gate, deps, list, id } = await spawnParkedAsk ( ) ;
20012119 const wait = waitTool ( deps ) ;
0 commit comments