@@ -72,7 +72,11 @@ const PANEL_MIME = 'text/html;profile=mcp-app';
7272 * call, and the progress-handler map the lifecycle replay composes, delegates
7373 * to the real client.
7474 */
75- const withAppSurface = ( client : Client ) : Client => {
75+ const withAppSurface = ( client : Client ) : Client => appSurface ( client , 'serves' ) ;
76+
77+ const withRejectingAppSurface = ( client : Client ) : Client => appSurface ( client , 'rejects' ) ;
78+
79+ const appSurface = ( client : Client , read : 'rejects' | 'serves' ) : Client => {
7680 const panelListing = { mimeType : PANEL_MIME , name : 'panel' , uri : PANEL_URI } ;
7781 const wrapper = {
7882 _notificationHandlers : ( client as unknown as { readonly _notificationHandlers : unknown } )
@@ -88,6 +92,7 @@ const withAppSurface = (client: Client): Client => {
8892 readResource : async ( ...arguments_ : Parameters < Client [ 'readResource' ] > ) => {
8993 const [ params ] = arguments_ ;
9094 if ( params . uri !== PANEL_URI ) return client . readResource ( ...arguments_ ) ;
95+ if ( read === 'rejects' ) throw new Error ( 'panel resource handler exploded' ) ;
9196 return { contents : [ { mimeType : PANEL_MIME , text : '<!doctype html><span>route-harness panel</span>' , uri : PANEL_URI } ] } ;
9297 } ,
9398 } ;
@@ -635,6 +640,24 @@ describe('the generated-plugin contract matrix', () => {
635640 } ) ;
636641 } , 30_000 ) ;
637642
643+ it ( 'records a rejected auto-covered app read as a sweep failure inside the aggregated violation' , async ( ) => {
644+ const error = await withPackedShapedSession (
645+ { decorate : withRejectingAppSurface , entry : 'in-memory rejecting app read fixture' , includeApps : true } ,
646+ ( session , manifest ) => runPackedContractMatrix ( {
647+ fixtures : routeHarnessContractFixtures ( ) ,
648+ manifest,
649+ server : 'harness' ,
650+ session,
651+ } ) . catch ( ( thrown : unknown ) => thrown ) ,
652+ ) ;
653+
654+ expect ( error ) . toBeInstanceOf ( AgentTestError ) ;
655+ expect ( ( error as AgentTestError ) . code ) . toBe ( 'contract-violation' ) ;
656+ expect ( ( error as AgentTestError ) . message ) . toContain ( 'app:harness/panel / sweep' ) ;
657+ expect ( ( error as AgentTestError ) . message ) . toContain ( 'readResource threw for "ui://harness/panel"' ) ;
658+ expect ( ( error as AgentTestError ) . message ) . toContain ( 'panel resource handler exploded' ) ;
659+ } , 30_000 ) ;
660+
638661 it ( 'requires an app fixture entry only when apps: "explicit" is requested' , async ( ) => {
639662 const error = await withPackedShapedSession (
640663 { decorate : withAppSurface , entry : 'in-memory explicit app coverage fixture' , includeApps : true } ,
0 commit comments