Drop contract prose for the deleted problem-resource surfaces

frontend-primitives.md still told new route-level copy to extend
problemResourcePresentation, deleted in ae65c5e9a2, and kept a paragraph
tying that helper to ProblemResourcesTable.tsx, deleted with the dashboard
overview in c743a231b8. It also kept a readability rule for that table and
the dashboard Pulse Brief. Neither surface exists and no live surface
implements the rule; Patrol's grouping and affected-resource counts are
governed in patrol-intelligence.md. Drop the ownership paragraph and the
rule, and list problem-resource among the deleted dashboard helpers that
must not return.

unified-resources.md still said the change and correlation summary cards
default Infrastructure resource-filter links for the Patrol page and the
problem-resource dashboard panels. Since the 2026-05-16 drilldown
retirement the cards have no link default and render only in the resource
drawer, which passes no link builder, so labels show as plain text.
api-contracts.md named the dashboard Pulse Brief as a sender of
autonomous_mode:false and described that field as a client override. Since
4edf5f8265 ChatRequest has no autonomous_mode field: the server runs every
/api/ai/chat exchange in approval-required mode, as
TestHandleChat_CannotElevateAutonomousModePerRequest pins, and the field
that scoped handoffs still send is dropped at decode. Say so, and stop
calling Patrol finding handoffs stricter than ordinary chat.

The new lookup test pins the deleted helper as unowned, next to the other
retired dashboard paths, so the dropped ownership claim cannot come back
through the registry unnoticed.
This commit is contained in:
rcourtman
2026-10-07 18:08:44 +01:00
parent dace9295c6
commit 60527fa8ab
4 changed files with 29 additions and 30 deletions
@@ -7141,12 +7141,14 @@ introducing VMware-only mention payloads or provider-local inventory reads
under `/api/vmware/*`. Runtime-specific container/app mentions remain shared
unified-resource mentions as well; VMware network inventory does not create a
provider-local mention family.
That same `/api/ai/chat` payload boundary owns per-request execution-mode
overrides. Dashboard Pulse Brief and other scoped handoffs may include
`autonomous_mode:false` on the chat request to force approval-required command
execution for that exchange, but the transport must treat the field as a
request override only and must not mutate the user's persistent AI control
setting.
That same `/api/ai/chat` payload boundary owns request-local execution mode,
and the server sets it. `ChatRequest` in `internal/api/ai_handler.go` has no
`autonomous_mode` field, so the `autonomous_mode:false` that scoped handoffs
such as an explain-this-issue request still send is dropped at decode, and the
handler passes approval-required mode into the chat service for every
exchange; an Autonomous control level runs as Controlled for that request.
That clamp is request-local and must not mutate the user's persistent AI
control setting.
That same chat transport boundary owns new-session anchoring. When the request
omits `session_id`, the handler may generate and stream a session ID
immediately so the browser can anchor the visible turn, but that generated ID is
@@ -7199,7 +7201,7 @@ not serialize the model-only `handoff_context`, runtime failure detail, action
preflight/result bodies, remediation descriptions, raw commands, or approval
command payloads, and it must not preserve Patrol-authored next-step
recommendation fields from legacy handoffs.
Patrol finding handoffs are stricter than ordinary chat requests: when a request
Patrol finding handoffs keep that clamp on their own path: when a request
carries a non-empty `finding_id` or resolves to model-only Patrol briefing,
resource, or action context, `internal/api/ai_handler.go` must clamp the
request-local autonomous mode to false even if the caller supplied
@@ -5123,10 +5123,10 @@ KPI, problem-resource, or card shells. Workload-table and guest-row fallback
copy that lives under `frontend-modern/src/components/Workloads/` must keep
using `frontend-modern/src/utils/workloadEmptyStatePresentation.ts` and
`frontend-modern/src/utils/workloadGuestPresentation.ts`. New route-level empty
states, tone mapping, or compact issue copy must extend the shared
`emptyStatePresentation`, `semanticTonePresentation`, and
`problemResourcePresentation` helpers instead of reviving deleted
dashboard-only KPI, metric, storage, recovery, or trend presentation helpers.
states or tone mapping must extend the shared `emptyStatePresentation` and
`semanticTonePresentation` helpers instead of reviving deleted dashboard-only
KPI, metric, storage, recovery, problem-resource, or trend presentation
helpers.
That shell must also stay passive with respect to data ownership: future
overview trend cards may render summary-range controls and operator-facing
empty or error copy only after they have a governed owner, and they must not
@@ -6405,20 +6405,6 @@ rollups, points, or facets payloads arrive, it must keep that selected
platform present in the option set so the shared `LabeledFilterSelect` shows
the owned value immediately instead of flashing back to `All Platforms` until
recovery data warms.
`frontend-modern/src/utils/problemResourcePresentation.ts` now also belongs to
that same dashboard overview boundary so the problem-resource severity contract
stays shared with `ProblemResourcesTable.tsx` instead of floating as an
unowned helper.
Problem-resource table readability belongs to that same owner. Repeated rows
may collapse only when they share the same governed display label, resource
type, and problem signal; the header count and Pulse Brief counts must continue
to represent the underlying affected resources, and grouped links must route to
the broad owning surface rather than inventing a synthetic resource target.
Problem Resources and Pulse Brief wording must not amplify generic
status-shaped names such as `storage (offline)` into first-viewport prose or
grouped-row sublabels; when the resource name is only a type plus status, the
surface should summarize the type-level issue in operator language instead of
repeating raw backend-shaped labels.
The retired dashboard action queue must not be reintroduced as a compact
Patrol or infrastructure issue panel. Patrol-owned runtime findings remain
governed by `frontend-modern/src/utils/aiFindingPresentation.ts` and their
@@ -5497,12 +5497,14 @@ wording stays aligned with the drawer's recent-change cards and timeline.
Timeline cards in that drawer surface change metadata when it is present, so
the history view preserves the richer provenance already carried by the
unified-resource model instead of flattening those fields away.
The same Infrastructure resource-only links now also default through the
shared `frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx`
The shared `frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx`
and `frontend-modern/src/components/Infrastructure/ResourceCorrelationSummary.tsx`
cards from the Patrol page, resource drawer, and problem-resource dashboard
panels, so canonical resource-filter path construction stays owned by the
shared summary cards rather than being duplicated per surface.
cards keep resource links behind an optional `buildResourceHref` input with no
default, following the 2026-05-16 cross-resource drilldown retirement above.
The resource drawer passes none, so its change and correlation labels render
as plain text; a surface that needs resource links must pass a platform-route
builder into the shared card rather than rebuilding resource-filter paths per
surface.
Platform tables supply the resource-label resolver to the resource drawer
through `PlatformResourceDetailTableRow`. `createPlatformResourceLabelResolver(...)`
in `frontend-modern/src/features/platformPage/PlatformResourceDetailTableRow.tsx`
@@ -672,6 +672,15 @@ class SubsystemLookupTest(unittest.TestCase):
self.assertEqual(file_entry["classification"], "runtime")
self.assertEqual(file_entry["matches"], [])
def test_lookup_paths_reports_retired_problem_resource_helper_as_unowned(self) -> None:
path = "frontend-modern/src/utils/problemResourcePresentation.ts"
result = lookup_paths([path])
self.assertEqual(result["unowned_runtime_files"], [path])
self.assertEqual(result["impacted_subsystems"], [])
file_entry = result["files"][0]
self.assertEqual(file_entry["classification"], "runtime")
self.assertEqual(file_entry["matches"], [])
def test_lookup_paths_assigns_recovery_points_hook_to_storage_recovery(self) -> None:
result = lookup_paths(["frontend-modern/src/hooks/useRecoveryPoints.ts"])
self.assertEqual(result["unowned_runtime_files"], [])