Add signal contracts for reachability, exploitability, trust, and unknown symbols
- Introduced `ReachabilityState`, `RuntimeHit`, `ExploitabilitySignal`, `ReachabilitySignal`, `SignalEnvelope`, `SignalType`, `TrustSignal`, and `UnknownSymbolSignal` records to define various signal types and their properties. - Implemented JSON serialization attributes for proper data interchange. - Created project files for the new signal contracts library and corresponding test projects. - Added deterministic test fixtures for micro-interaction testing. - Included cryptographic keys for secure operations with cosign.
This commit is contained in:
60
docs/modules/ui/micro-interactions-map.md
Normal file
60
docs/modules/ui/micro-interactions-map.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# UI Micro-Interactions Component Map (MI6)
|
||||
|
||||
This document maps StellaOps UI components to their interaction types and motion token usage. Components must use tokens from the catalog (`tokens/motion.scss`, `motion-tokens.ts`) rather than bespoke values.
|
||||
|
||||
## Token Catalog Reference
|
||||
|
||||
| Token | CSS Variable | Duration | Use Case |
|
||||
| --- | --- | --- | --- |
|
||||
| durationXs | --motion-duration-xs | 80ms | Focus rings, instant feedback |
|
||||
| durationSm | --motion-duration-sm | 140ms | Hover states, button presses |
|
||||
| durationMd | --motion-duration-md | 200ms | Modal open/close, panel slide |
|
||||
| durationLg | --motion-duration-lg | 260ms | Page transitions, accordions |
|
||||
| durationXl | --motion-duration-xl | 320ms | Complex sequences, onboarding |
|
||||
| easeStandard | --motion-ease-standard | cubic-bezier(0.2,0,0,1) | Default for all transitions |
|
||||
| easeEntrance | --motion-ease-entrance | cubic-bezier(0.18,0.89,0.32,1) | Elements appearing |
|
||||
| easeExit | --motion-ease-exit | cubic-bezier(0.36,0,-0.56,-0.56) | Elements leaving |
|
||||
| easeBounce | --motion-ease-bounce | cubic-bezier(0.34,1.56,0.64,1) | Playful feedback only |
|
||||
|
||||
## Component Mapping
|
||||
|
||||
| Component | Interaction Type | Tokens Used | Reduced-Motion Behavior |
|
||||
| --- | --- | --- | --- |
|
||||
| Button (primary) | Hover lift, press scale | durationSm, easeStandard, scaleSm | No transform, instant state change |
|
||||
| Button (secondary) | Hover border, press | durationXs, easeStandard | Instant state change |
|
||||
| Modal/Dialog | Fade + slide up | durationMd, easeEntrance/Exit, translateMd | Instant show/hide |
|
||||
| Dropdown/Menu | Fade + scale | durationSm, easeStandard, scaleSm | Instant show/hide |
|
||||
| Toast/Snackbar | Slide in, auto-dismiss | durationMd, easeEntrance, translateLg | Instant show/hide |
|
||||
| Accordion | Height expand | durationMd, easeStandard | Instant toggle |
|
||||
| Tabs | Indicator slide | durationSm, easeStandard | Instant indicator |
|
||||
| Progress bar | Width fill | durationMd, easeStandard | No animation, instant fill |
|
||||
| Spinner/Loader | Rotate animation | N/A (CSS keyframe) | Static icon or hidden |
|
||||
| Skeleton | Shimmer pulse | durationXl, easeStandard | Static skeleton, no shimmer |
|
||||
| Badge (status) | Scale pop on change | durationXs, easeBounce, scaleSm | No scale, instant |
|
||||
| Focus ring | Fade in | durationXs, easeStandard | Always visible, no fade |
|
||||
| Tooltip | Fade + offset | durationSm, easeEntrance, translateSm | Instant show/hide |
|
||||
| Banner (info) | Slide down | durationMd, easeEntrance, translateMd | Instant show/hide |
|
||||
| Error state | Shake animation | durationSm, easeStandard | No shake, border only |
|
||||
|
||||
## Perf Budget Compliance (MI5)
|
||||
|
||||
| Metric | Budget | Measurement |
|
||||
| --- | --- | --- |
|
||||
| Interaction response | <= 100ms | Time to visual feedback |
|
||||
| Animation frame (avg) | <= 16ms | Chrome DevTools Performance |
|
||||
| Animation frame (p95) | <= 50ms | Chrome DevTools Performance |
|
||||
| Layout shift | <= 0.05 CLS | Lighthouse CI |
|
||||
| LCP placeholder | Show within 400ms | Lighthouse CI |
|
||||
|
||||
## Validation Rules
|
||||
|
||||
1. **Lint rule**: ESLint/Stylelint blocks non-catalog easing values in `.scss` and `.ts` files
|
||||
2. **Storybook check**: All component stories must demonstrate reduced-motion variant
|
||||
3. **Playwright check**: Snapshot tests run with `--disable-animations` and reduced-motion emulation
|
||||
4. **CI gate**: Perf budget failures block merge
|
||||
|
||||
## Evidence
|
||||
|
||||
- Token catalog: `src/Web/StellaOps.Web/src/styles/tokens/_motion.scss`
|
||||
- TypeScript tokens: `src/Web/StellaOps.Web/src/app/styles/motion-tokens.ts`
|
||||
- Storybook stories: `src/Web/StellaOps.Web/src/stories/motion-tokens.stories.ts`
|
||||
149
docs/modules/ui/micro-theme.md
Normal file
149
docs/modules/ui/micro-theme.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# UI Micro-Interaction Theme & Contrast Guidance (MI10)
|
||||
|
||||
This document defines theme tokens and contrast requirements for micro-interactions across light, dark, and high-contrast modes.
|
||||
|
||||
## Color Contrast Requirements
|
||||
|
||||
| Element Type | Minimum Contrast Ratio | WCAG Level |
|
||||
| --- | --- | --- |
|
||||
| Normal text (< 18px) | 4.5:1 | AA |
|
||||
| Large text (>= 18px bold or >= 24px) | 3:1 | AA |
|
||||
| UI components (borders, icons) | 3:1 | AA |
|
||||
| Focus indicators | 3:1 | AA |
|
||||
| Status colors on background | 3:1 | AA |
|
||||
|
||||
## Theme Token Reference
|
||||
|
||||
### Light Theme (Default)
|
||||
|
||||
```scss
|
||||
:root {
|
||||
/* Backgrounds */
|
||||
--theme-bg-primary: #ffffff;
|
||||
--theme-bg-secondary: #f8fafc;
|
||||
--theme-bg-elevated: #ffffff;
|
||||
--theme-bg-overlay: rgba(15, 23, 42, 0.5);
|
||||
|
||||
/* Text */
|
||||
--theme-text-primary: #0f172a; /* 15.42:1 on white */
|
||||
--theme-text-secondary: #475569; /* 7.05:1 on white */
|
||||
--theme-text-muted: #94a3b8; /* 3.21:1 on white - decorative only */
|
||||
--theme-text-inverse: #ffffff;
|
||||
|
||||
/* Borders */
|
||||
--theme-border-default: #e2e8f0;
|
||||
--theme-border-focus: #3b82f6; /* 4.5:1 on white */
|
||||
--theme-border-error: #ef4444;
|
||||
|
||||
/* Status Colors */
|
||||
--theme-status-success: #16a34a; /* 4.52:1 on white */
|
||||
--theme-status-warning: #d97706; /* 4.51:1 on white */
|
||||
--theme-status-error: #dc2626; /* 5.92:1 on white */
|
||||
--theme-status-info: #2563eb; /* 5.28:1 on white */
|
||||
|
||||
/* Focus Ring */
|
||||
--theme-focus-ring-color: #3b82f6;
|
||||
--theme-focus-ring-width: 2px;
|
||||
--theme-focus-ring-offset: 2px;
|
||||
}
|
||||
```
|
||||
|
||||
### Dark Theme
|
||||
|
||||
```scss
|
||||
[data-theme='dark'] {
|
||||
/* Backgrounds */
|
||||
--theme-bg-primary: #0f172a;
|
||||
--theme-bg-secondary: #1e293b;
|
||||
--theme-bg-elevated: #334155;
|
||||
--theme-bg-overlay: rgba(0, 0, 0, 0.7);
|
||||
|
||||
/* Text */
|
||||
--theme-text-primary: #f8fafc; /* 15.42:1 on dark bg */
|
||||
--theme-text-secondary: #cbd5e1; /* 8.12:1 on dark bg */
|
||||
--theme-text-muted: #64748b;
|
||||
--theme-text-inverse: #0f172a;
|
||||
|
||||
/* Borders */
|
||||
--theme-border-default: #334155;
|
||||
--theme-border-focus: #60a5fa;
|
||||
--theme-border-error: #f87171;
|
||||
|
||||
/* Status Colors */
|
||||
--theme-status-success: #4ade80;
|
||||
--theme-status-warning: #fbbf24;
|
||||
--theme-status-error: #f87171;
|
||||
--theme-status-info: #60a5fa;
|
||||
|
||||
/* Focus Ring */
|
||||
--theme-focus-ring-color: #60a5fa;
|
||||
}
|
||||
```
|
||||
|
||||
### High Contrast Theme
|
||||
|
||||
```scss
|
||||
[data-theme='high-contrast'] {
|
||||
/* Backgrounds */
|
||||
--theme-bg-primary: #000000;
|
||||
--theme-bg-secondary: #000000;
|
||||
--theme-bg-elevated: #1a1a1a;
|
||||
--theme-bg-overlay: rgba(0, 0, 0, 0.9);
|
||||
|
||||
/* Text */
|
||||
--theme-text-primary: #ffffff; /* 21:1 on black */
|
||||
--theme-text-secondary: #ffffff;
|
||||
--theme-text-muted: #e5e5e5;
|
||||
--theme-text-inverse: #000000;
|
||||
|
||||
/* Borders - thicker and higher contrast */
|
||||
--theme-border-default: #ffffff;
|
||||
--theme-border-focus: #ffff00; /* Yellow for maximum visibility */
|
||||
--theme-border-error: #ff0000;
|
||||
|
||||
/* Status Colors - bold, saturated */
|
||||
--theme-status-success: #00ff00;
|
||||
--theme-status-warning: #ffff00;
|
||||
--theme-status-error: #ff0000;
|
||||
--theme-status-info: #00ffff;
|
||||
|
||||
/* Focus Ring - extra visible */
|
||||
--theme-focus-ring-color: #ffff00;
|
||||
--theme-focus-ring-width: 3px;
|
||||
--theme-focus-ring-offset: 3px;
|
||||
}
|
||||
```
|
||||
|
||||
## Focus Indicator Requirements
|
||||
|
||||
1. Focus ring must be visible in all themes (never `outline: none` without replacement)
|
||||
2. Minimum 2px width, 3:1 contrast with adjacent colors
|
||||
3. In high-contrast mode: 3px width, yellow (#ffff00) color
|
||||
4. Focus must be visible when using keyboard navigation only
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
- [ ] All text passes 4.5:1 contrast ratio (use axe DevTools)
|
||||
- [ ] All UI elements pass 3:1 contrast ratio
|
||||
- [ ] Focus indicators visible in all themes
|
||||
- [ ] No reliance on color alone for state indication
|
||||
- [ ] Theme toggle persists user preference
|
||||
- [ ] Reduced motion settings respected across themes
|
||||
|
||||
## Testing
|
||||
|
||||
Run axe accessibility tests in Storybook:
|
||||
```bash
|
||||
npm run test:a11y
|
||||
```
|
||||
|
||||
Run contrast checks in Playwright:
|
||||
```bash
|
||||
npx playwright test --project=a11y
|
||||
```
|
||||
|
||||
## Evidence
|
||||
|
||||
- Storybook: Theme toggle available in toolbar
|
||||
- Playwright: `tests/e2e/theme-contrast.spec.ts`
|
||||
- axe reports: `tests/a11y/reports/`
|
||||
72
docs/modules/ui/telemetry/ui-micro.schema.json
Normal file
72
docs/modules/ui/telemetry/ui-micro.schema.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://stella-ops.org/ui/schemas/ui-micro.schema.json",
|
||||
"title": "UI Micro-Interaction Telemetry Event",
|
||||
"description": "Schema for ui.micro.* telemetry events (MI7)",
|
||||
"type": "object",
|
||||
"required": ["schema_version", "event_type", "timestamp", "tenant_id", "surface", "component", "action"],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"type": "string",
|
||||
"pattern": "^v[0-9]+\\.[0-9]+$",
|
||||
"description": "Schema version (e.g., v1.0)"
|
||||
},
|
||||
"event_type": {
|
||||
"type": "string",
|
||||
"enum": ["ui.micro.interaction", "ui.micro.error", "ui.micro.latency", "ui.micro.state_change"],
|
||||
"description": "Event type category"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 UTC timestamp"
|
||||
},
|
||||
"tenant_id": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Tenant identifier (required for scoping)"
|
||||
},
|
||||
"surface": {
|
||||
"type": "string",
|
||||
"enum": ["dashboard", "vulnerabilities", "graph", "exceptions", "releases", "settings", "onboarding"],
|
||||
"description": "UI surface/page where interaction occurred"
|
||||
},
|
||||
"component": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Component name (e.g., button, modal, dropdown)"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Action taken (e.g., click, hover, focus, submit, dismiss)"
|
||||
},
|
||||
"latency_ms": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Time from action to visual feedback in milliseconds"
|
||||
},
|
||||
"outcome": {
|
||||
"type": "string",
|
||||
"enum": ["success", "error", "cancelled", "timeout", "offline"],
|
||||
"description": "Result of the interaction"
|
||||
},
|
||||
"reduced_motion": {
|
||||
"type": "boolean",
|
||||
"description": "True if user has prefers-reduced-motion enabled"
|
||||
},
|
||||
"offline_mode": {
|
||||
"type": "boolean",
|
||||
"description": "True if app is in offline mode"
|
||||
},
|
||||
"error_code": {
|
||||
"type": ["string", "null"],
|
||||
"description": "Error code if outcome is error (e.g., UI_ERR_001)"
|
||||
},
|
||||
"correlation_id": {
|
||||
"type": "string",
|
||||
"description": "Trace correlation ID for request tracing"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
Reference in New Issue
Block a user