plan/04-findings.md
04 · Findings listing (S2) + finding detail (S1) (Wave 2)
TL;DR: "Not enforced" becomes Observed; Observed is hidden by default with a one-click way in and an honest zero state (D3); add severity; consolidate the filters into one bar; the snoozed line goes. Resolve records a decision — reason + text, no inline exception, a follow-on link (S, D10). History marks manual vs re-evaluation; findings show their Policy Config version at detection.
Owns: app/pages/pages/phase4/mock/{findings,finding-detail}.vue, app/components/governance/part/{FindingsTable,FindingHistory,FindingDetails}.vue, app/components/governance/mock/ResolveCapture.vue.
Today
findings.vuefilters: status Open/Resolved?status=(l.13–18), framework chips?fw=(l.20–25), policy/team chips (l.26–27), column search?q=, group/individual?view=, enforcement FilterTriggerBar All · Enforced · "Not enforced (N)"?ne=(l.34–40), clear; variant?v.observe=tagged|hidden|preview(l.220–233); snoozed amber lines (l.45–50, l.304). No severity filter (sorter only, l.69).FindingsTable.vuemode tags incl. "snoozed" (l.24, l.135–139), group mode line (l.88), "policy v{n}" (l.89), resolve card (l.72–82), lifecycle (l.91–100).ResolveCapture.vue: reasons (fixtureRESOLVE_REASONS), text required for Other; optional inline Off exception with until (l.19–33); done message (l.106–114).finding-detail.vue: Resolve + "Too noisy? Quiet the policy →" (l.23–24);?v.resolve=reasons|exception(l.94–98).FindingHistory.vue: actor = person vsqdash, no explicit kind.
Steps
- One filter bar (L: "too many filters, consolidate"). Assemble from the layer's
DataListingBar(c95: FilterTriggerBar + column picker) if it fits: Status (Open · Resolved) · Outcome (Enforced · Observed · All, default Enforced;?outcome=) · Severity (multi;?sev=) · Framework (?fw=). Policy and team stay as removable chips from deep links only. Group/Individual moves to the bar's right edge. Keep?q=in the column header. Drop?ne=and the?v.observe=variants (map old?ne=show|onlytooutcome=all|observedfor old links). - Observed hidden by default (D3). Bar shows "Observed (N)" count even when excluded. Zero state when the filtered result is empty: "No enforced findings match. 12 Observed findings are hidden — show them" (use the layer's
FilterNoMatches/StateEmptypattern). Framework zero state "Nothing open against ISO 27001" reads as good news (R: audit-ready view). - Rename. Every "Not enforced" → "Observed"; "Enforced" only when actually blocked (labels come from 00's rows file). Remove "snoozed" tags and the snoozed lines; group mode line shows "Observe · until Nov 15" instead.
- Resolve (S, I). ResolveCapture: reasons False positive · By design · Security testing · Other + explanation; remove the inline exception block and
?v.resolve=exception. After resolving: "Resolved as By design. The policy didn't change." + link "Change this policy or add an exception →" to S3?policy=<id>&add=user:<subject>#exceptions(D10). Replace "Too noisy? Quiet the policy →" with the same link pattern pointing at#mode. - History. A small kind marker per event: Manual (person) vs Re-evaluation (system, with the Policy Config version that caused it, linking to Changes) vs System (Until passed). Same in the S2 card lifecycle.
- Config version. "Policy Config v12 at detection" in FindingDetails and the S2 card (replaces "policy v{n}").
Done when
/pages/phase4/mock/findings default (enforced only), ?outcome=all, ?sev=critical, framework zero state, a finding resolved with each reason, history with all three kinds. Screenshots shots/04-*.png.
Look for (review)
Is the bar fewer things than today? Can you tell in one glance that Observed findings exist but are hidden?