@@ -7,7 +7,7 @@ import { afterEach, describe, expect, test } from "bun:test";
77import { mkdtempSync , rmSync , writeFileSync } from "node:fs" ;
88import { tmpdir } from "node:os" ;
99import { join } from "node:path" ;
10- import { applyEffortCap , effortCapAppliesTo , effortCapFor , isSubagentRequest , resolveCappedEffort , supportedLadderFor } from "../src/server/effort-policy" ;
10+ import { applyEffortCap , effortCapAppliesTo , effortCapFor , isThreadSpawnRequest , resolveCappedEffort , supportedLadderFor } from "../src/server/effort-policy" ;
1111import { collabSurface } from "../src/server/responses" ;
1212import { handleManagementAPI } from "../src/server/management-api" ;
1313import { routeModel } from "../src/router" ;
@@ -51,22 +51,33 @@ const MAIN_HEADERS = new Headers({
5151 "x-codex-turn-metadata" : JSON . stringify ( { turn_id : "t1" } ) ,
5252} ) ;
5353
54- describe ( "isSubagentRequest " , ( ) => {
55- test ( "x-openai-subagent marker classifies as sub-agent " , ( ) => {
56- expect ( isSubagentRequest ( SUBAGENT_HEADERS ) ) . toBe ( true ) ;
54+ describe ( "isThreadSpawnRequest " , ( ) => {
55+ test ( "x-openai-subagent: collab_spawn classifies as spawned child " , ( ) => {
56+ expect ( isThreadSpawnRequest ( SUBAGENT_HEADERS ) ) . toBe ( true ) ;
5757 } ) ;
5858
59- test ( "subagent_kind inside x-codex-turn-metadata classifies as sub-agent " , ( ) => {
60- expect ( isSubagentRequest ( TURN_META_HEADERS ) ) . toBe ( true ) ;
59+ test ( "subagent_kind: thread_spawn inside x-codex-turn-metadata classifies as spawned child " , ( ) => {
60+ expect ( isThreadSpawnRequest ( TURN_META_HEADERS ) ) . toBe ( true ) ;
6161 } ) ;
6262
6363 test ( "main-agent turn metadata and bare headers stay main" , ( ) => {
64- expect ( isSubagentRequest ( MAIN_HEADERS ) ) . toBe ( false ) ;
65- expect ( isSubagentRequest ( new Headers ( ) ) ) . toBe ( false ) ;
64+ expect ( isThreadSpawnRequest ( MAIN_HEADERS ) ) . toBe ( false ) ;
65+ expect ( isThreadSpawnRequest ( new Headers ( ) ) ) . toBe ( false ) ;
6666 } ) ;
6767
68- test ( "malformed turn metadata never classifies as sub-agent" , ( ) => {
69- expect ( isSubagentRequest ( new Headers ( { "x-codex-turn-metadata" : "{not json" } ) ) ) . toBe ( false ) ;
68+ test ( "non-spawn subagent categories never classify as spawned children" , ( ) => {
69+ // Upstream emits x-openai-subagent for review/compact/memory-consolidation/"other"
70+ // maintenance turns too (responses_metadata.rs) — only collab_spawn is a child.
71+ for ( const kind of [ "review" , "compact" , "memory_consolidation" , "other" , "anything" ] ) {
72+ expect ( isThreadSpawnRequest ( new Headers ( { "x-openai-subagent" : kind } ) ) ) . toBe ( false ) ;
73+ const meta = new Headers ( { "x-codex-turn-metadata" : JSON . stringify ( { subagent_kind : kind } ) } ) ;
74+ expect ( isThreadSpawnRequest ( meta ) ) . toBe ( false ) ;
75+ }
76+ } ) ;
77+
78+ test ( "malformed turn metadata never classifies as spawned child" , ( ) => {
79+ expect ( isThreadSpawnRequest ( new Headers ( { "x-codex-turn-metadata" : "{not json" } ) ) ) . toBe ( false ) ;
80+ expect ( isThreadSpawnRequest ( new Headers ( { "x-codex-turn-metadata" : JSON . stringify ( { subagent_kind : 42 } ) } ) ) ) . toBe ( false ) ;
7081 } ) ;
7182} ) ;
7283
@@ -320,9 +331,10 @@ describe("effortCapAppliesTo (caps are a v2-feature gate)", () => {
320331 expect ( effortCapAppliesTo ( null , new Headers ( ) , makeConfig ( { effortCap : "high" , subagentEffortCap : "medium" } ) ) ) . toBe ( false ) ;
321332 } ) ;
322333
323- test ( "child turn carries no collab tools — the spawned-child header still admits the cap" , ( ) => {
324- // Regression guard: children never carry spawn_agent, so a surface-only gate would
325- // skip exactly the turns subagentEffortCap exists for.
334+ test ( "depth-limited child turn carries no collab tools — the spawned-child header still admits the cap" , ( ) => {
335+ // Regression guard: depth-limited leaf children carry no collab tools (surface
336+ // null), so a surface-only gate would skip exactly the turns subagentEffortCap
337+ // exists for.
326338 const parsed = parsedWithTools ( [ { name : "shell" } ] , "max" ) ;
327339 expect ( collabSurface ( parsed ) ) . toBeNull ( ) ;
328340 const config = makeConfig ( { subagentEffortCap : "medium" } ) ;
@@ -331,6 +343,29 @@ describe("effortCapAppliesTo (caps are a v2-feature gate)", () => {
331343 expect ( applyEffortCap ( parsed , childHeaders , config ) ) . toEqual ( { from : "max" , to : "medium" , subagent : true } ) ;
332344 } ) ;
333345
346+ test ( "header-marked child with a v1 tool surface is still admitted (surface-agnostic child gate)" , ( ) => {
347+ // Children below the spawn-depth limit retain collab tools (spec_plan.rs leaf
348+ // guard) — two siblings must not get different cap treatment based on depth.
349+ const childHeaders = new Headers ( { "x-openai-subagent" : "collab_spawn" } ) ;
350+ const config = makeConfig ( { subagentEffortCap : "medium" } ) ;
351+ expect ( effortCapAppliesTo ( "v1" , childHeaders , config ) ) . toBe ( true ) ;
352+ expect ( effortCapAppliesTo ( "v2" , childHeaders , config ) ) . toBe ( true ) ;
353+ } ) ;
354+
355+ test ( "non-spawn subagent markers do not admit the cap" , ( ) => {
356+ const config = makeConfig ( { effortCap : "high" , subagentEffortCap : "medium" } ) ;
357+ expect ( effortCapAppliesTo ( null , new Headers ( { "x-openai-subagent" : "review" } ) , config ) ) . toBe ( false ) ;
358+ expect ( effortCapAppliesTo ( null , new Headers ( { "x-openai-subagent" : "compact" } ) , config ) ) . toBe ( false ) ;
359+ expect ( effortCapAppliesTo ( null , new Headers ( { "x-openai-subagent" : "memory_consolidation" } ) , config ) ) . toBe ( false ) ;
360+ const otherMeta = new Headers ( { "x-codex-turn-metadata" : JSON . stringify ( { subagent_kind : "other" } ) } ) ;
361+ expect ( effortCapAppliesTo ( null , otherMeta , config ) ) . toBe ( false ) ;
362+ } ) ;
363+
364+ test ( "malformed turn metadata never admits the cap" , ( ) => {
365+ const config = makeConfig ( { effortCap : "high" , subagentEffortCap : "medium" } ) ;
366+ expect ( effortCapAppliesTo ( null , new Headers ( { "x-codex-turn-metadata" : "{not json" } ) , config ) ) . toBe ( false ) ;
367+ } ) ;
368+
334369 test ( "turn-metadata subagent_kind alone admits the cap for a child turn" , ( ) => {
335370 const headers = new Headers ( { "x-codex-turn-metadata" : JSON . stringify ( { subagent_kind : "thread_spawn" } ) } ) ;
336371 expect ( effortCapAppliesTo ( null , headers , makeConfig ( { subagentEffortCap : "medium" } ) ) ) . toBe ( true ) ;
@@ -341,6 +376,24 @@ describe("effortCapAppliesTo (caps are a v2-feature gate)", () => {
341376 expect ( effortCapAppliesTo ( "v2" , new Headers ( ) , config ) ) . toBe ( false ) ;
342377 expect ( effortCapAppliesTo ( null , new Headers ( { "x-openai-subagent" : "collab_spawn" } ) , config ) ) . toBe ( false ) ;
343378 } ) ;
379+
380+ test ( "explicit default and forced-v2 modes keep the gate open for v2 surfaces and marked children" , ( ) => {
381+ for ( const mode of [ "default" , "v2" ] as const ) {
382+ const config = makeConfig ( { effortCap : "high" , multiAgentMode : mode } ) ;
383+ expect ( effortCapAppliesTo ( "v2" , new Headers ( ) , config ) ) . toBe ( true ) ;
384+ expect ( effortCapAppliesTo ( null , new Headers ( { "x-openai-subagent" : "collab_spawn" } ) , config ) ) . toBe ( true ) ;
385+ // A plain main turn stays out even under forced v2 — no collab tools, no markers.
386+ expect ( effortCapAppliesTo ( null , new Headers ( ) , config ) ) . toBe ( false ) ;
387+ }
388+ } ) ;
389+
390+ test ( "compaction turns bypass the cap regardless of surface or markers" , ( ) => {
391+ // Native /v1/responses/compact never enters handleResponses; routed compaction
392+ // must not diverge from it, so the gate refuses when the compaction flag is set.
393+ const config = makeConfig ( { effortCap : "high" , subagentEffortCap : "medium" } ) ;
394+ expect ( effortCapAppliesTo ( "v2" , new Headers ( ) , config , true ) ) . toBe ( false ) ;
395+ expect ( effortCapAppliesTo ( null , new Headers ( { "x-openai-subagent" : "collab_spawn" } ) , config , true ) ) . toBe ( false ) ;
396+ } ) ;
344397} ) ;
345398
346399describe ( "cap composition with downstream clamps" , ( ) => {
0 commit comments