From 43f4e63087264dc6f50f6ec379bbb00c3d3dc247 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 25 Mar 2026 22:18:19 +0000 Subject: [PATCH] Fail closed on zero-coverage Patrol scoped runs --- .../v6/internal/subsystems/patrol-intelligence.md | 2 ++ .../src/utils/__tests__/patrolRunPresentation.test.ts | 10 ++++++++++ frontend-modern/src/utils/patrolRunPresentation.ts | 3 +-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md index d2756f78d..1cc1ebd5b 100644 --- a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md +++ b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md @@ -424,6 +424,8 @@ owner, so the Patrol hook composes one canonical payload-to-summary derivation instead of rebuilding recent-change, correlation, and governed-resource count copy inline. That same normalization applies to supporting effort strips inside the expanded +Zero-coverage scoped runs must also fail closed as `Checked 0 of N scoped +resources` rather than drifting back to a scope-only headline. run card. Once the run presenter is already carrying canonical coverage copy, secondary chips must not reintroduce a raw `Scoped to N resources` variant that re-opens the same ambiguity. diff --git a/frontend-modern/src/utils/__tests__/patrolRunPresentation.test.ts b/frontend-modern/src/utils/__tests__/patrolRunPresentation.test.ts index 5ff7a579c..a4ae31555 100644 --- a/frontend-modern/src/utils/__tests__/patrolRunPresentation.test.ts +++ b/frontend-modern/src/utils/__tests__/patrolRunPresentation.test.ts @@ -91,6 +91,16 @@ describe('patrolRunPresentation', () => { it('uses checked-resource language for non-scoped coverage summaries', () => { expect(getPatrolRunCoverageSummary(fullCoverageRun)).toBe('Checked 58 resources'); expect(getPatrolRunResourcesHeading(fullCoverageRun)).toBe('Resources checked (58)'); + + it('fails closed on zero-coverage scoped runs', () => { + expect( + getPatrolRunCoverageSummary({ + resources_checked: 0, + scope_resource_ids: ['seed-resource'], + effective_scope_resource_ids: ['expanded-a', 'expanded-b'], + }), + ).toBe('Checked 0 of 2 scoped resources'); + }); }); it('returns canonical patrol run loading and unavailable copy', () => { diff --git a/frontend-modern/src/utils/patrolRunPresentation.ts b/frontend-modern/src/utils/patrolRunPresentation.ts index ed60a52d3..487009325 100644 --- a/frontend-modern/src/utils/patrolRunPresentation.ts +++ b/frontend-modern/src/utils/patrolRunPresentation.ts @@ -95,13 +95,12 @@ export function getPatrolRunCoverageSummary(run: Pick 0) { - if (resourcesChecked > 0 && resourcesChecked < scopedResourceCount) { + if (resourcesChecked < scopedResourceCount) { return `Checked ${resourcesChecked} of ${scopedResourceCount} scoped resources`; } if (resourcesChecked > 0) { return `Checked ${formatResourceCount(resourcesChecked, 'scoped')}`; } - return `Scoped to ${formatResourceCount(scopedResourceCount)}`; } if (resourcesChecked > 0) {