You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
37 lines
5.1 KiB
37 lines
5.1 KiB
|
4 months ago
|
# Audit: metrics
|
||
|
|
audit-version: 1
|
||
|
|
audited-at: 2026-06-26
|
||
|
|
scope:
|
||
|
|
method: adversarially-verified workflow; HIGH lead-verified. B7 ground-truth: Toolbar A35 + Form A36 incidents STAYED FIXED (untrack present); toast/clipboard/drag-drop use uix.timers (no A6 leak); button is clean (its archetype finding was inert — Spinner not runtime-registered); data-size/data-shape are eidos visual attrs (not contract violations).
|
||
|
|
provider: G:/dev/svelte/vicen/src/uix/soma/components/metrics/metrics.svelte.ts (runtime-only, no traditional provider)
|
||
|
|
cleanup-audit (A6/A35/A36): No timers, setInterval, ResizeObserver, IntersectionObserver, MutationObserver, addEventListener, or pointer listeners declared in eidos or soma directories. A35 loop check: metrics-delta's $effect writes to context.setIntent (line 46-48), which updates root's currentIntent state, but no component r
|
||
|
|
|
||
|
|
## Summary
|
||
|
|
Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 1 · LOW 0.
|
||
|
|
|
||
|
|
## Findings
|
||
|
|
### MEDIUM: F (Tests): a component with a non-trivial soma runtime path (live-region dispatch + value- — metrics-no-runtime-test <!-- id: metrics-no-runtime-test -->
|
||
|
|
- dimension: F
|
||
|
|
- rule: F (Tests): a component with a non-trivial soma runtime path (live-region dispatch + value-change effect + intent-publish effect) should have a provider/runtime test mapping the RISK paths. None exists.
|
||
|
|
- location: src/uix/soma/components/metrics/ (no *.test.ts) — verified via find/grep: zero files reference metricsMorfo/createMetricsRuntime/notifyUpdate in any *.test.ts/*.spec.ts
|
||
|
|
- evidence: `createMetricsRuntime` (metrics.svelte.ts:17) is exercised through three reactive code paths with no coverage: (1) the live-signal dispatch — metrics.svelte:57-63 `notifyUpdate` → `runtime.trigger('signal-notify-update', { fallbackTarget: el, message: text })`, which routes through `uix.announce` via the morfo's `a11ySemantic.requiresLiveRegion` (metrics.ts:64); (2) the value-change detector — metrics-value.svelte:21-32 (`prev`/`firstRun` memo, the `live`-off no-op path, and the first-run-suppressed path); (3) the intent-publish effect — metrics-delta.svelte:46-48. These are exactly the live-region/effect paths the audit flags as high-risk, yet there is no test asserting the trigger fires only on a real change, stays inert when `live` is off, suppresses the first run, and announces `message`.
|
||
|
|
- impact: Regressions in the live-update signal (e.g. re-introducing a first-run announce, or firing when value is unchanged, or breaking the `live`-off no-op gate) would ship silently. The change-detection memo logic (metrics-value.svelte:18-32) is subtle and untested.
|
||
|
|
- repro: find/grep over src for metric*test / metricsMorfo|createMetricsRuntime|notifyUpdate in *.test.ts returns nothing.
|
||
|
|
- proposed-fix: Add src/uix/soma/components/metrics/metrics.svelte.test.ts (or a runtime test) using a real ActiveUix via createActiveUix/attachActiveUix (never a fake announce per project rule): assert `notifyUpdate` triggers `signal-notify-update` only on a value change when `live` is on, is a no-op when `live` is off, suppresses the first run, and forwards `message` to the live region.
|
||
|
|
- verify: [verifier-added] added by adversarial verify pass
|
||
|
|
- fix-status: open
|
||
|
|
|
||
|
|
## No-findings dimensions
|
||
|
|
A: Contract (morfo scope satisfies, parts declared and present, 2-of-3 rule, part data-* naming correct, aria declarations present), B: Behavior (A35: no per-item effect reading opts.ref.current + writing provider state; A36: no async-microtask-mediated freeze; A33: no $state(Map/Set) non-reactive; A31: no O(N²) derived with global provider reads; A6: no timers/observers/listeners declared; A30: no child->parent id registration in $effect; A15: no gesture; LIVE REGIONS: signal-notify-update correctly dispatched via runtime.trigger with message + announce; A34: announce provider reachable), C: DOM-selector (no interpolated consumer values; global document/window not used), D: Frontier (no soma imports from eidos; no eidos imports from soma except in root to call createMetricsRuntime; data-size/color/variant are visual attrs; Progress/Gauge use framework Meter composition), E: TSC tokens (all spacing via --space-* tokens; all icon-size via --icon-size-*; all color via CSS custom properties; no hardcoded focus-ring or :active), E-bis Theming (Delta composes Badge which uses canonical color roles; featured icon colors use 9 canonical roles; no hardcoded hex; recipe tokens via --metrics-* private scale), F: Tests (no test file present - gap noted but not violation per baseline), G: Redundancy (standard context pattern for live-signal bridge; no gesture re-implementation)
|
||
|
|
|
||
|
|
## Theming facts (E-bis)
|
||
|
|
- magic z-index: none
|
||
|
|
- magic literals: none
|
||
|
|
- undeclared parts: none
|
||
|
|
- roles clean: true · variants clean: true
|
||
|
|
|
||
|
|
## Tests (F)
|
||
|
|
- exists: false · env: N/A
|
||
|
|
- covers:
|
||
|
|
- untested: signal-notify-update dispatch when live=true and value changes; intent derivation (trend vs goodTrend); size cascading to sub-parts (Badge, Meter, icon size); aria-label generation on Delta; part composition (Badge, Meter, Sparkline) integration; reduced-motion behavior (if applicable); announce() called with correct priority (polite/assertive)
|