Skip to content

Multi-level SCOUT V1 (first slice)#109

Merged
jukka-matti merged 20 commits into
mainfrom
feat/multi-level-scout-v1
Apr 30, 2026
Merged

Multi-level SCOUT V1 (first slice)#109
jukka-matti merged 20 commits into
mainfrom
feat/multi-level-scout-v1

Conversation

@jukka-matti
Copy link
Copy Markdown
Owner

Summary

Lands the first delivery slice of the Multi-level SCOUT design (docs/superpowers/specs/2026-04-29-multi-level-scout-design.md, now status: delivered).

Engine layer (Tasks 0–7):

  • TimelineWindow discriminated union + type guards
  • applyWindow filters rows by timeline window over a parser-detected timeColumn
  • detectScope classifies investigations as b0/b1/b2 by nodeMappings cardinality
  • mergeRows for append-mode re-upload (dedupe / correction / add)
  • computeFindingWindowDrift + WindowContext on Finding
  • New throughput/ module: computeOutputRate + computeBottleneck
  • AnalysisModeStrategy.dataRouter for (scope, phase, window) routing

Hooks layer (Tasks 8–9):

  • useTimelineWindow — pure projection over ProcessHubInvestigationMetadata.timelineWindow (no new Zustand store; persistence via caller's existing persistInvestigation flow)
  • useDataRouter — sanity-check wrapper over the strategy router (no runtime hook switching)
  • useFilteredData and useProductionLineGlanceData accept optional window arg

UI layer (Tasks 10–12):

  • TimelineWindowPicker — four-kind window selector with secondary inputs
  • DashboardLayoutBase exposes the picker in dashboard chrome (data-export-hide region)
  • FindingCard renders window-context footer when windowContext is present

App layer (Tasks 13–14):

  • ProcessHubCapabilityTab consults useDataRouter and threads window into useProductionLineGlanceData
  • Investigation Dashboards (Azure + PWA) hold local timeline-window state and thread to layout + filtered data
  • Hub Capability tab renders the picker

Boundary policy (Task 15): ADR-074 boundary check script + pre-commit wiring.

Docs (Task 16): three new docs (timeline-window-investigations, multi-level-dashboard, timeline-window-architecture); vision/glossary/journey/CLAUDE.md updates; spec status flipped to delivered.

Plan-spec drifts caught and resolved during execution

Three Task specs needed substantive revision against codebase reality — all revisions are committed in the plan file:

  • Task 8 original Zustand-store design rejected; replaced with pure projection over investigation metadata.
  • Task 13 original <strategy.chartSlots.slot1 /> JSX impossible (ChartSlots carries strings, not components); V1 routes at call site instead.
  • Task 14 original useTimelineWindow({ investigationId }) signature stale after Task 8 revision; dashboards use local state for V1 (V2 makes them investigation-aware).

V2 / V1.5 follow-ups (named-future)

  • Hub Capability tab cadence default (rolling matched to hub.cadence on first mount)
  • Investigation-aware Dashboards so useTimelineWindow can persist the choice
  • Slot-component registry for full strategy-driven dashboard rendering
  • Second-slice metrics (cycle time, FPY, RTY, OEE)

Test plan

  • All package tests pass — core 2947, hooks 1016, ui 1285, azure 970, pwa 124
  • pnpm --filter @variscout/ui build clean (cross-package type-export check per feedback_ui_build_before_merge.md)
  • bash scripts/pr-ready-check.sh ✓ all checks passed
  • ADR-074 boundary check ✓ clean
  • Manual chrome walk: investigation-time picker works in PWA + Azure
  • Manual chrome walk: hub-time picker on Hub Capability tab
  • Re-upload an investigation and verify append-mode merge report

Commits (12)

Engine (8): TimelineWindow types, applyWindow, detectScope, mergeRows (bundled into f059c59), drift, throughput, dataRouter, decisions doc.
Hooks (2): useTimelineWindow + JSDoc nit, useDataRouter + window-aware sibling hooks.
UI (3): TimelineWindowPicker, DashboardLayoutBase chrome slot, FindingCard footer.
Apps (1): Dashboard + Hub Capability picker wiring.
Refactor (1): ProcessHubCapabilityTab dataRouter consultation.
Chore (1): ADR-074 boundary check + pre-commit wiring.
Docs (3): plan revisions + completeness sweep.

🤖 Generated with ruflo

jukka-matti and others added 19 commits April 29, 2026 19:14
Adds TimelineWindow (fixed | rolling | openEnded | cumulative) type,
TimelineWindowKind utility type, and four isXxxWindow type guards.
Barrel exported from ./timeline and re-exported from core root.
TDD: test written first, confirmed failing, then passing after impl.

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

Implements scope detection per §2 of the investigation-scope-and-drill-semantics
spec. Accepts ProcessHubInvestigation (the actual type carrying nodeMappings via
metadata), not a nonexistent Investigation envelope. 4 tests: absent/empty → b0,
length===1 → b2, length>1 → b1.

Co-Authored-By: ruflo <ruv@ruv.net>
The original Decision #1 referenced a fictitious Investigation envelope with processContext.nodeMappings. The actual codebase models hub-attached investigations as ProcessHubInvestigation with metadata.nodeMappings. Updating to put TimelineWindow on ProcessHubInvestigationMetadata alongside nodeMappings — the intent (window separate from scope, co-located with mappings) is preserved.

Caught during V1 Task 3 (detectScope) implementation when the implementer needed to operate against the actual type.

Co-Authored-By: ruflo <ruv@ruv.net>
Implements Task 5 of multi-level SCOUT V1. Adds WindowContext type to
Finding (optional, backward-compatible) and computeFindingWindowDrift()
which compares stats-at-creation vs current-window stats using relative
change with a default 0.20 threshold. 4 tests pass. Interleaved doc
section added to statistics-reference.md.

Co-Authored-By: ruflo <ruv@ruv.net>
Adds packages/core/src/throughput/ mirroring defect/yamazumi shape.
computeOutputRate buckets rows by time granularity and emits ratePerHour;
computeBottleneck ranks steps by rate and flags the slowest. 3/3 tests
pass. Re-exported from core barrel; statistics-reference Part 17 added.

Co-Authored-By: ruflo <ruv@ruv.net>
…window) routing

Adds RouterScope, RouterPhase, RouterArgs, RouterResult, RouterHook and ChartSlots
types to analysisStrategy.ts. Extends AnalysisModeStrategy with an optional
dataRouter field (backward compat). All 5 registered strategies implement it with
locked routing decisions: investigation→useFilteredData, hub→useProductionLineGlanceData
(where supported). Process Flow mode has no strategy registration in V1.

Co-Authored-By: ruflo <ruv@ruv.net>
The original Task 8 spec invented a 5th module-level Zustand store in
@variscout/hooks keyed by investigationId. Three issues with that:

1. Wrong layer — CLAUDE.md invariant locks 4 domain Zustand stores; window
   selection is viewer state, not a 5th domain store.
2. Memory leak by design — module-level Map<id, window> has no eviction in
   a long-lived PWA session.
3. Decision #1 already located the window on ProcessHubInvestigationMetadata
   alongside nodeMappings (see commit f059c59). The original plan's parallel
   cache ignored that, same class of mismatch the Decision #1 revision
   already corrected once.

Revised: useTimelineWindow becomes a thin pure projection. Caller passes
the investigation envelope and an onChange callback wired to its existing
persistInvestigation flow (canonical pattern at apps/azure/src/features/
processHub/useHubMigrationState.ts:67-114). Window persists where the
investigation persists (IndexedDB / Blob per ADR-059). No new Zustand
store, no zustand dep added to @variscout/hooks, package flow stays clean.

Adds timelineWindow?: TimelineWindow to ProcessHubInvestigationMetadata
in core (the type-level half of Decision #1's intent that was previously
documented but not yet wired into the type).

Note for Tasks 11/14: app-level wiring now hangs onChange off
persistInvestigation alongside the nodeMappings flow.

Co-Authored-By: ruflo <ruv@ruv.net>
Per code-review nit on 4adae8b: the returned `window` memoizes on
`metadata.timelineWindow` identity, so a parent passing a fresh object
literal each render would thrash the memo. Future Task 9 callers
(useDataRouter) read `window` from this hook, so calling out the
contract on the arg itself prevents the footgun. JSDoc-only; no
behavior change.

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

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

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

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

Co-Authored-By: ruflo <ruv@ruv.net>
Plan Task 14 V1 interpretation. Original plan used the old
useTimelineWindow({ investigationId, defaultKind }) signature that
Task 8's revision (commit cf5daaa) already replaced with a pure
projection over an investigation envelope. The investigation Dashboards
(Azure + PWA) don't receive a ProcessHubInvestigation envelope today —
they read from useProjectStore — so the persistence-aware hook can't
be used there in V1. Local useState is the correct V1 fit, with a
documented V2 follow-up to make the dashboards investigation-aware.

Hub Capability tab already had local window state from Task 13; this
commit extends the destructure to expose the setter and renders
TimelineWindowPicker above the dashboard composition. Cadence-default
override (rolling matched to hub.cadence on first mount) is deferred
to V1.5 per the plan revision.

Plan-file Task 14 body replaced with a V1-interpretation note.

Co-Authored-By: ruflo <ruv@ruv.net>
Closes Task 16 (Steps 16.1–16.6, 16.8) of the Multi-level SCOUT V1 plan.

Created (3):
- docs/03-features/analysis/timeline-window-investigations.md
- docs/03-features/analysis/multi-level-dashboard.md
- docs/05-technical/architecture/timeline-window-architecture.md

Modified (16):
- Vision: methodology.md temporal-scope paragraph; eda-mental-model.md SCOUT-loops note
- Glossary: docs glossary + packages/core/src/glossary/terms.ts (timeline window, output rate, bottleneck, finding drift, hub-time, investigation-time)
- Journeys: USER-JOURNEYS.md + USER-JOURNEYS-CAPABILITY.md timeline-picker mentions
- Agent map: docs/llms.txt new entry points
- Per-package CLAUDE.md: core (timeline/throughput/findings), hooks (useTimelineWindow + useDataRouter), ui (TimelineWindowPicker), apps/azure + apps/pwa (multi-level integration)
- Lifecycle: spec status draft → delivered, last-reviewed 2026-04-30; decision-log V1 row + SCOUT journey row updated; ADR-074 strikes the 'to be added' note (boundary script ships in 6c68218)
- Plan-file checkboxes for Steps 16.1–16.6 + 16.8 ticked; 16.7/16.9 left for orchestrator

Step 16.7 (memory updates) handled separately by orchestrator. Step 16.9 (push + open PR) deferred to user-authorized step.

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

vercel Bot commented Apr 30, 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 30, 2026 7:25am
variscout_website Ready Ready Preview, Comment Apr 30, 2026 7:25am

Pre-merge code review on PR #109 caught a hard-rule violation in the
defect strategy registration. packages/core/CLAUDE.md forbids .toFixed
on exported stat values; consumers should call formatStatistic from
@variscout/core/i18n. The line itself predates this PR (commit 69eca5a)
but the PR added dataRouter to the same strategy block, so folding the
fix in pre-merge per feedback_bundle_followups_pre_merge.md.

Replaces v.toFixed(1) with Math.round(v * 10) / 10 — same numeric output,
no toFixed. Mirrors the yamazumi strategy's Math.round(v * 100) pattern.

Co-Authored-By: ruflo <ruv@ruv.net>
@jukka-matti jukka-matti merged commit 55c8f1f into main Apr 30, 2026
1 of 3 checks passed
@jukka-matti jukka-matti deleted the feat/multi-level-scout-v1 branch April 30, 2026 07:19
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