@@ -100,6 +100,60 @@ test("findViolation: invalid role and empty content named", () => {
100100 assert . match ( findViolation ( b2 ) , / c o n t e n t : m e s s a g e s \[ 3 \] / ) ;
101101} ) ;
102102
103+ // --- Invariant 5: assistant-terminal (BACKLOG.md, "suppression can strip
104+ // a request's FINAL message", 2026-07-30) ---
105+
106+ test ( "findViolation: healthy body, incoming also ends non-assistant -> null (no incomingBody = cannot verify, also null)" , ( ) => {
107+ const b = goodBody ( ) ; // ends on a tool_result (role user)
108+ assert . equal ( findViolation ( b , b ) , null ) ;
109+ assert . equal ( findViolation ( b ) , null , "no incomingBody -> this check cannot fire" ) ;
110+ } ) ;
111+
112+ test ( "findViolation: incoming ended non-assistant but forwarded ends assistant -> assistant-terminal named" , ( ) => {
113+ const incoming = goodBody ( ) ; // last message role "user"
114+ const forwarded = goodBody ( ) ;
115+ forwarded . messages . pop ( ) ; // simulate a mutation stripping the trailing tool_result
116+ assert . equal ( forwarded . messages [ forwarded . messages . length - 1 ] . role , "assistant" ) ;
117+ assert . match ( findViolation ( forwarded , incoming ) , / a s s i s t a n t - t e r m i n a l / ) ;
118+ } ) ;
119+
120+ test ( "findViolation: incoming ITSELF ended assistant (prefill-shaped) -> not this guard's business, no violation" , ( ) => {
121+ const incoming = goodBody ( ) ;
122+ incoming . messages . push ( { role : "assistant" , content : [ { type : "text" , text : "partial" } ] } ) ;
123+ const forwarded = structuredClone ( incoming ) ; // forwarded also ends assistant, matching CC's own intent
124+ assert . equal ( findViolation ( forwarded , incoming ) , null ) ;
125+ } ) ;
126+
127+ test ( "findViolation: incoming and forwarded both end non-assistant -> null (healthy case)" , ( ) => {
128+ const incoming = goodBody ( ) ;
129+ const forwarded = structuredClone ( incoming ) ;
130+ assert . equal ( findViolation ( forwarded , incoming ) , null ) ;
131+ } ) ;
132+
133+ test ( "gate 2 (assistant-terminal): a mutator that strips the trailing message is caught, forwards the original, telemetry names it" , async ( ) => {
134+ await withGuardEnv ( async ( dir ) => {
135+ const body = goodBody ( ) ;
136+ const originalHash = sha ( body ) ;
137+ const ctx = { body, headers : { "x-session-id" : "tail-strip-test" } , meta : { route : "messages" } } ;
138+ const stripTailMutator = {
139+ name : "test-strip-tail-mutator" ,
140+ order : 300 ,
141+ async onRequest ( c ) {
142+ c . body . messages . pop ( ) ;
143+ } ,
144+ } ;
145+ await runOnRequest ( ctx , [ stash , stripTailMutator , guard ] ) ;
146+
147+ assert . equal ( ctx . meta . outputGuardStats . fired , true ) ;
148+ assert . equal ( ctx . meta . outputGuardStats . restored , true ) ;
149+ assert . match ( ctx . meta . outputGuardStats . violation , / a s s i s t a n t - t e r m i n a l / ) ;
150+ assert . equal ( sha ( ctx . body ) , originalHash , "forwarded body is byte-identical to the pre-pipeline original" ) ;
151+
152+ const events = await readFile ( join ( dir , "cache-fix-snapshots" , "s-tail-strip-test-guard-events.jsonl" ) , "utf-8" ) ;
153+ assert . match ( events , / a s s i s t a n t - t e r m i n a l / , "telemetry record names the violated invariant" ) ;
154+ } ) ;
155+ } ) ;
156+
103157// --- Gate 1: zero fires on all healthy class corpora ---
104158
105159// The corpus COUNT is deliberately not pinned. It was (`=== 8`), and adding a
0 commit comments