@@ -34,6 +34,7 @@ import {
3434 preferCompletedSubAgentReply ,
3535 resolveSubAgentCatchOutcome ,
3636 resolveSubAgentDeadlineMs ,
37+ shouldRequireEvidence ,
3738 subAgentToolName ,
3839 SUBAGENT_DEADLINE_MARGIN_MS ,
3940 SUBAGENT_PLUGIN_SPAWN_TEARDOWN_LIMITS ,
@@ -45,6 +46,8 @@ import {
4546} from "./index.js" ;
4647
4748import { type } from "arktype" ;
49+ import { formatDirectorSystemPrompt } from "../agent/directors/identity.js" ;
50+ import { DIRECTOR_REGISTRY } from "../agent/directors/registry.js" ;
4851import type {
4952 ReactorAction ,
5053 ReactorCapabilities ,
@@ -277,6 +280,91 @@ describe("sub-agent stop helpers", () => {
277280 ) . toBe ( "complete" ) ;
278281 } ) ;
279282
283+ test ( "shouldRequireEvidence is armed for CritiqueDirector prompt" , ( ) => {
284+ expect (
285+ shouldRequireEvidence ( {
286+ systemPromptRole : formatDirectorSystemPrompt ( DIRECTOR_REGISTRY . critique ) ,
287+ } ) ,
288+ ) . toBe ( true ) ;
289+ expect (
290+ shouldRequireEvidence ( {
291+ systemPromptRole : DIRECTOR_REGISTRY . critique . systemPrompt ,
292+ } ) ,
293+ ) . toBe ( true ) ;
294+ } ) ;
295+
296+ test ( "shouldRequireEvidence is off for greybeard even with intent=review" , ( ) => {
297+ expect (
298+ shouldRequireEvidence ( {
299+ intent : "review" ,
300+ systemPromptRole : formatDirectorSystemPrompt ( DIRECTOR_REGISTRY . greybeard ) ,
301+ } ) ,
302+ ) . toBe ( false ) ;
303+ } ) ;
304+
305+ test ( "evaluateSubAgentStop does not complete a review/critique with empty readCounts even with a full envelope" , ( ) => {
306+ const thrashState = {
307+ totalToolCalls : 1 ,
308+ readCounts : new Map ( ) ,
309+ editedPaths : new Set < string > ( ) ,
310+ } ;
311+ expect (
312+ evaluateSubAgentStop ( {
313+ hasToolCalls : false ,
314+ everHadToolCalls : true ,
315+ turnsCompleted : 2 ,
316+ maxTurns : 10 ,
317+ consecutiveIdentical : 0 ,
318+ repeatLimit : 2 ,
319+ lastAssistantText : FULL_REPORT_ENVELOPE ,
320+ thrashState,
321+ requireEvidence : true ,
322+ } ) ,
323+ ) . toBe ( "incomplete-report" ) ;
324+ } ) ;
325+
326+ test ( "evaluateSubAgentStop completes a review when readCounts has file evidence" , ( ) => {
327+ const thrashState = {
328+ totalToolCalls : 1 ,
329+ readCounts : new Map ( [ [ "src/gate.ts" , 1 ] ] ) ,
330+ editedPaths : new Set < string > ( ) ,
331+ } ;
332+ expect (
333+ evaluateSubAgentStop ( {
334+ hasToolCalls : false ,
335+ everHadToolCalls : true ,
336+ turnsCompleted : 2 ,
337+ maxTurns : 10 ,
338+ consecutiveIdentical : 0 ,
339+ repeatLimit : 2 ,
340+ lastAssistantText : FULL_REPORT_ENVELOPE ,
341+ thrashState,
342+ requireEvidence : true ,
343+ } ) ,
344+ ) . toBe ( "complete" ) ;
345+ } ) ;
346+
347+ test ( "evaluateSubAgentStop completes greybeard spawn-only envelope when requireEvidence is off" , ( ) => {
348+ const thrashState = {
349+ totalToolCalls : 1 ,
350+ readCounts : new Map ( ) ,
351+ editedPaths : new Set < string > ( ) ,
352+ } ;
353+ expect (
354+ evaluateSubAgentStop ( {
355+ hasToolCalls : false ,
356+ everHadToolCalls : true ,
357+ turnsCompleted : 2 ,
358+ maxTurns : 10 ,
359+ consecutiveIdentical : 0 ,
360+ repeatLimit : 2 ,
361+ lastAssistantText : FULL_REPORT_ENVELOPE ,
362+ thrashState,
363+ requireEvidence : false ,
364+ } ) ,
365+ ) . toBe ( "complete" ) ;
366+ } ) ;
367+
280368 test ( "evaluateSubAgentStop returns never-acted when the run never used tools" , ( ) => {
281369 expect (
282370 evaluateSubAgentStop ( {
0 commit comments