Skip to content

feat: ProcessHubCurrentStatePanel evidence chip (Phase 2 V2 PR #5)#99

Merged
jukka-matti merged 5 commits into
mainfrom
phase-2/pr-5-evidence-chip
Apr 27, 2026
Merged

feat: ProcessHubCurrentStatePanel evidence chip (Phase 2 V2 PR #5)#99
jukka-matti merged 5 commits into
mainfrom
phase-2/pr-5-evidence-chip

Conversation

@jukka-matti
Copy link
Copy Markdown
Owner

Summary

PR #5 of Phase 2 V2 closure — adds an evidence chip to each state-item card in ProcessHubCurrentStatePanel. Chip shows the count of relevant findings (analyzed / improving / resolved) for the item's linked investigations. Click navigates to the most-recent linked investigation with App Insights telemetry. Closes the actionable-panel work for V2.

Building blocks:

  • linkFindingsToStateItems pure aggregator in @variscout/core — 2-input join with caller-provided resolver, deduplicates investigation IDs, filters to RELEVANT_FINDING_STATUSES (analyzed/improving/resolved). Pure, testable in isolation.
  • EvidenceChip subcomponent in ProcessHubCurrentStatePanel — renders only when count > 0; event.stopPropagation() prevents card click from firing.
  • ProcessHubReviewPanel wires the resolver + count derivation from ProcessHubInvestigationMetadata.findingCounts, plus handleChipClick with non-PII telemetry.

Pragmatic divergence from spec (documented up front)

The spec called for a full EvidenceSheet rendering linked findings. Dashboard does not load full Finding[] objects today — loading hub-wide would be a meaningful new data surface. This PR scopes down to:

  • Chip count derived from findingCounts metadata (already on the rollup, cheap).
  • Chip click navigates to the most-recent linked investigation (where the existing investigation surface shows the findings naturally).

The full EvidenceSheet with finding labels is deferred to a follow-up PR, recorded in the plan's "Future PRs" section. The aggregator is fully implemented per spec — the deferred work is the data load + sheet rendering, not the core function.

Spec: docs/superpowers/specs/2026-04-27-actionable-current-process-state-panel-design.md (commit 24e85496)
Plan: docs/superpowers/plans/2026-04-27-actionable-current-process-state-panel-plan.md

Test plan

  • pnpm --filter @variscout/core exec vitest run — 10 new tests in processEvidence (RELEVANT_FINDING_STATUSES + linkFindingsToStateItems edge cases)
  • pnpm --filter @variscout/ui exec vitest run — 5 new chip tests (count display, singular/plural, empty omit, click stops propagation, renders on unsupported cards). 20/20 panel tests pass.
  • pnpm --filter @variscout/azure-app exec vitest run — 933/933 pass (no regressions; existing fixtures with empty findingCounts mean chip stays hidden in those tests)
  • pnpm --filter @variscout/ui build — clean cross-package type check
  • bash scripts/pr-ready-check.sh — all checks green
  • claude --chrome walk: open Azure Dashboard with seeded hub + investigation that has analyzed findings; verify chip appears with the right count; click chip; verify navigation lands on the investigation; verify telemetry event fires with non-PII payload

Notable code-review fixes during implementation

  1. Replaced Math.random() in test factory with a sequential counter (per packages/core/CLAUDE.md hard rule: never Math.random in tests).
  2. Added clarifying comments at the synthetic-Finding placeholder cast site (TODO referencing the future Pick<Finding, 'id'> narrow type) and at the chip-click navigation target (per-investigation items use investigationIds[0]; aggregate items use the most-recent-modified default).

🤖 Generated with Claude Code

jukka-matti and others added 5 commits April 27, 2026 23:33
Pure 2-input join: state items × findings (pre-grouped by investigation
ID). Caller provides a resolver implementing the per-item-type linkage
rules. Findings filtered to RELEVANT_FINDING_STATUSES (analyzed,
improving, resolved).

Phase 2 V2 PR #5, Tasks 1-3.

Co-Authored-By: ruflo <ruv@ruv.net>
…dence tests

Per packages/core/CLAUDE.md hard rule: never Math.random in tests. The
finding-ID factory now uses a module-scoped sequential counter for
deterministic test fixtures.

Phase 2 V2 PR #5, code-review followup.

Co-Authored-By: ruflo <ruv@ruv.net>
… cards

Each state-item card now renders a small evidence chip in the lower-right
showing the count of linked findings (analyzed / improving / resolved).
Chip click fires evidence.onChipClick with the item + resolved findings;
event.stopPropagation prevents the card click from also firing.

Chip is independent of action support — Planned/Informational cards still
show evidence counts when present. Chip is omitted when findings is empty.

The evidence prop, previously stubbed in PR #4, is now wired through.
Azure consumer still passes a stub findingsFor (() => []), so the chip
won't render in the running app until the next subagent task wires
findingsFor to ProcessHubInvestigationMetadata.findingCounts.

5 new chip tests added (count display, singular/plural, empty omit,
click fires + stops propagation, renders on unsupported cards too).

Phase 2 V2 PR #5, Tasks 4-5.

Co-Authored-By: ruflo <ruv@ruv.net>
…anel

Replaces the PR #4 stub evidence contract with a real wiring:

- findingsFor: derives chip count from
  ProcessHubInvestigationMetadata.findingCounts (relevant statuses
  analyzed + improving + resolved). Returns synthetic Finding-shaped
  placeholder objects (only id surface) — chip uses .length.
- onChipClick: emits 'process_hub.evidence_chip_click' App Insights
  event with no-PII payload (hubId, responsePath, lens, evidenceCount)
  and navigates to the most-recent linked investigation via the
  existing onOpenInvestigation callback.

Pragmatic divergence from spec: Dashboard doesn't load full Finding[]
objects today. The EvidenceSheet with finding labels is deferred to a
follow-up PR — see plan PR #5 future work.

Phase 2 V2 PR #5, Task 6.

Co-Authored-By: ruflo <ruv@ruv.net>
Two reviewer-flagged comment additions:

1. The Finding[] cast in findingsFor is intentionally narrow — chip only
   reads .length. Adds a TODO referencing the follow-up EvidenceSheet PR
   that will introduce a Pick<Finding, 'id'> narrow type at the panel's
   evidence-contract boundary, removing the cast.

2. Documents the per-investigation item.investigationIds[0] navigation
   target — typically a single linked investigation, so most-recency is
   moot. Hub-aggregate items already fall back to the most-recent via
   defaultInvestigationId.

No code changes — comments only.

Phase 2 V2 PR #5, code-review followup.

Co-Authored-By: ruflo <ruv@ruv.net>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mean-beoynd-lite-pwa Ready Ready Preview, Comment Apr 27, 2026 9:14pm
variscout_website Ready Ready Preview, Comment Apr 27, 2026 9:14pm

@jukka-matti jukka-matti merged commit caba84e into main Apr 27, 2026
2 of 3 checks passed
@jukka-matti jukka-matti deleted the phase-2/pr-5-evidence-chip branch April 27, 2026 21:13
jukka-matti added a commit that referenced this pull request Apr 27, 2026
Combines three sequenced PRs into one spec per feedback_full_vision_spec
memory:
- PR #1 (H1): team notes on state items — question / gemba / data-gap /
  decision kinds, persisted in ProcessHubInvestigationMetadata.stateNotes
- PR #2 (V2 follow-up): full EvidenceSheet rendering — refactors
  ProcessHubEvidenceContract to split countFor (sync) + loadFindingsFor
  (async), eliminates the synthetic-Finding cast from PR #99
- PR #3 (H2 launch): General Evidence Source for CSV/Excel — adds
  GENERIC_TABULAR_PROFILE to DATA_PROFILE_REGISTRY, mapping confirmation
  UI in ProcessHubEvidencePanel, cadence metadata

Resolves both prior open questions inline:
- Evidence contract split (countFor + loadFindingsFor + onChipClick +
  onFindingSelect — cleaner than overloading findingsFor sync/async)
- Mapping UX explicit confirmation (matches operating-model § "analyst
  confirms mappings" language)

Updates spec index, marks the parent V2 actionable-panel spec as
Delivered (PRs #98 #99).

Co-Authored-By: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request Apr 27, 2026
Sequenced TDD breakdown for 3 PRs:
- PR #1: team notes on state items (~250-350 LOC, 8 tasks). New
  ProcessStateNote types in core, ProcessHubInvestigationMetadata
  extension, ProcessHubNotesContract on the panel, StateItemNotesDrawer
  in apps/azure, Dashboard wiring via useStorage round-trip.
- PR #2: full EvidenceSheet rendering (~300-400 LOC, 5 tasks). Refactors
  ProcessHubEvidenceContract to split countFor (sync) + loadFindingsFor
  (async); EvidenceSheet bottom sheet; Dashboard owns sheet state +
  async load via useStorage; eliminates synthetic-Finding cast from PR
  #99.
- PR #3: General Evidence Source for CSV/Excel (~600-800 LOC, 4 tasks).
  GENERIC_TABULAR_PROFILE in DATA_PROFILE_REGISTRY; profile picker UI;
  mapping confirmation form; cadence selector (5 actual EvidenceCadence
  values); telemetry on save.

Three implementation reality notes flagged at top:
1. Actual DataProfileDefinition signature differs from spec sketch
   (single 'label' field; detect takes only rows; confidence is
   'high'/'medium'/'low' enum not number).
2. EvidenceCadence enum lacks 'monthly' — use existing 5 values.
3. Spec back-link upgrades to Markdown link in PR #1 Task 7.

Co-Authored-By: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request Apr 28, 2026
* refactor(ui): split ProcessHubEvidenceContract into countFor + loadFindingsFor

Replaces the synthetic-Finding placeholder pattern from PR #99 with a
clean separation of concerns:
- countFor (sync) — chip badge count, derived from rollup metadata
- loadFindingsFor (async) — fetches real findings for the sheet, only
  called when consumer wires it after chip click
- onChipClick(item) — telemetry signal, no findings arg
- onFindingSelect(item, finding) — sheet's selection callback

Sheet management stays on the consumer side (next task wires Dashboard).
Eliminates the 'as unknown as readonly Finding[]' cast and the synthetic-
placeholder generation entirely.

Existing chip tests rewritten for the new contract; 2 new tests added
(no-load-on-render guard + onFindingSelect contract presence).

Phase 3 PR #2, Task 2.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(azure): add EvidenceSheet bottom sheet for finding click-thru

Lightweight sheet listing findings (label + status badge + click-thru).
Renders nothing when item is null; loading state when findings is null;
empty state for zero findings. Esc key, click-outside, and close button
all fire onClose.

Phase 3 PR #2, Task 3.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(azure): wire EvidenceSheet with lazy finding load on chip click

Replaces PR #99's synthetic-Finding placeholder pattern with a real
async load through the existing useStorage().loadProject() chain.

ProcessHubReviewPanel:
- countFor derives chip count from ProcessHubInvestigationMetadata.findingCounts
  (same arithmetic as the previous synthetic-placeholder length)
- loadFindingsForItem / onChipClick / onFindingSelect pass-through to Dashboard
- removes the synthetic Finding[] cast and TODO(evidence-sheet-pr) comment
- removes safeTrackEvent import (no longer needed in this component)

Dashboard:
- sheetState managed at Dashboard level (item + hubId + findings | null)
- handleChipClick: fires telemetry, opens sheet in loading state, async-loads
  via loadProject() chain, applies findings with a race guard
- handleFindingSelect: fires telemetry, closes sheet, navigates via existing
  onOpenProject + best-effort URL hash for finding deep-link
- EvidenceSheet rendered at Dashboard level (sibling of StateItemNotesDrawer)

Telemetry: process_hub.evidence_sheet_{opened,finding_clicked} with non-PII
payloads (hubId from rollup.hub.id, lens, responsePath, findingStatus enum
in finding-click event). No PII per ADR-059.

Phase 3 PR #2, Task 4.

Co-Authored-By: ruflo <ruv@ruv.net>

* fix(azure): drop dead URL-hash guard in handleFindingSelect

The guard `window.location.hash !== '#finding-${id}'` (with `#`) compared
against an assignment without `#` — the comparison was always false so
the guard never short-circuited. Assignment is idempotent in browsers
anyway; just drop the guard.

Phase 3 PR #2, code-review followup.

Co-Authored-By: ruflo <ruv@ruv.net>

* fix(azure): include evidenceCount in process_hub.evidence_sheet_opened telemetry

The Phase 3 spec's telemetry table specified payload {hubId, responsePath,
lens, evidenceCount} but the implementation omitted evidenceCount.
evidenceCount is the key engagement metric for the chip feature.

Threads count through the panel's onChipClick(item, hubId, count) so
Dashboard can include it in safeTrackEvent without re-deriving.

Phase 3 PR #2, code-review followup.

Co-Authored-By: ruflo <ruv@ruv.net>

---------

Co-authored-by: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request May 17, 2026
…e/ + Coherence §3 markers) (#194)

* docs(wedge): archive Group 1 — 8 pre-wedge specs + fix inbound links

Moves 8 specs superseded by the 2026-05-16 wedge pivot to docs/archive/specs/.
Each file receives status:archived in frontmatter + a blockquote ARCHIVED header
with the specific supersession reason + institutional-knowledge preservation note.

Files moved:
- 2026-05-09-response-path-system-v1-design.md (5-path RPS → wedge 3-path reduction)
- 2026-05-08-improvement-project-v1-design.md (superseded by RPS V1 then wedge)
- 2026-05-04-canvas-migration-design.md (migration completed; canvas is live substrate)
- 2026-05-03-variscout-vision-design.md (5-path + multi-Hub → wedge 3-path + single-Hub)
- 2026-04-29-consolidated-method-and-surface-overview-design.md (pre-wedge state-of-union)
- 2026-04-02-knowledge-tab-design.md (tier-gating retires; scope narrows to project-level)
- 2026-03-30-holistic-evaluation-vqi.md (pre-wedge holistic evaluation)
- 2026-03-24-adr049-evaluation-report.md (point-in-time PR review, pre-wedge surface model)

Inbound links fixed in 17 files (ADRs 059/068/070/078/080/081, decision-log,
roadmap, investigations, methodology, variscout-process measurement-system +
scope-line, 4 plan files, 4 active spec files, specs/index.md).
9 additional files (items 6 and 10-17 in the audit list) were already in
docs/archive/specs/ from earlier work — no action needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(wedge): archive Group 2 — 8 pre-wedge plans to docs/archive/plans/

Moves 8 implementation plans superseded by the 2026-05-16 wedge pivot to
docs/archive/plans/. Each file receives status:archived in frontmatter + an
ARCHIVED blockquote header with specific supersession reason.

Files moved:
- 2026-05-14-projects-tab-foundation.md (4-stage IP detail; amended by wedge)
- 2026-05-09-response-path-system-v1.md (5-path RPS; delivered, wedge reduced to 3)
- 2026-05-08-improvement-project-v1.md (superseded by RPS V1 system-level plan)
- 2026-05-07-canvas-pr8-8a-mode-aware-ctas.md (5-path tier-gating; wedge retired it)
- 2026-05-06-data-flow-foundation-f1-f2.md (delivered; pre-wedge scope assumptions)
- 2026-05-06-data-flow-foundation-f1-f2-audit.md (audit companion to f1-f2 plan)
- 2026-05-06-canvas-pr4c-pr6-followup.md (delivered; pre-wedge retrospective)
- 2026-04-27-actionable-current-process-state-panel-plan.md (delivered PRs #98/#99)

Inbound links fixed in 11 files (adr-077, adr-080, decision-log, roadmap,
f3-5-ingestion plan, f3-6-azure plan, projects-tab-launchpad-cascade plan,
canvas-pr8-master plan × 2 edits, projects-tab-design spec, projects-tab-launchpad).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(wedge): archive Group 3 — ADR-033 to docs/archive/adrs/ (superseded by ADR-082)

* docs(wedge): archive Group 4 — pricing-tiers + tier-gating (single-SKU supersedes)

* docs(wedge): add §3 SUPERSEDED marker to Coherence design spec (V1 single-persona)

* docs(wedge): fix 3 broken cross-refs to archived docs (PR 4 followup)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant