Spec
Intent
Drift is the silent killer in autonomous systems — small unobserved divergences from spec that compound until an incident surfaces. This gauge gives it a face.
Acceptance Criteria
[ ] Needle position maps to drift % (0–100)
[ ] Threshold tick marks the tolerance line
[ ] Colour bands: green / pink / red
[ ] Numeric readout + status word
Constraints
Pure SVG, theme-aware fills
Below threshold = nominal; above = needs intervention
Respects prefers-reduced-motion
// drift-detector.astro copy
---
import type { CompendiumMeta } from '../../../data/types';
export const meta: CompendiumMeta = {
id: 39,
slug: 'drift-detector',
name: 'Drift Detector',
category: 'governance-risk',
subcategory: 'thresholds',
pillar: 'go',
description: 'Gauge measuring how far implementation has drifted from approved intent.',
spec: `## Intent
Drift is the silent killer in autonomous systems — small unobserved divergences from spec that compound until an incident surfaces. This gauge gives it a face.
## Acceptance Criteria
- [ ] Needle position maps to drift % (0–100)
- [ ] Threshold tick marks the tolerance line
- [ ] Colour bands: green / pink / red
- [ ] Numeric readout + status word
## Constraints
- Pure SVG, theme-aware fills
- Below threshold = nominal; above = needs intervention
- Respects prefers-reduced-motion`,
tags: ['svg', 'gauge', 'animated', 'reduced-motion', 'dark-mode-tested'],
status: 'stable',
health: { ics: 86, a11y: 'aa', themed: true, animated: true },
};
const drift = 41;
const threshold = 30;
const status = drift > threshold ? 'INTERVENE' : 'NOMINAL';
const statusTone = drift > threshold ? 'bg-danger' : 'bg-success';
const angle = -90 + (drift / 100) * 180;
const tickAngle = -90 + (threshold / 100) * 180;
---
<div data-this-component class="w-full bg-paper text-black border-4 border-black p-4 flex flex-col items-center overflow-hidden">
<p class="font-mono text-[10px] uppercase tracking-widest opacity-60 self-start">Intent ↔ implementation drift</p>
<svg viewBox="0 0 200 120" class="w-full max-w-[260px] block mt-1" role="img" aria-label={`Drift ${drift} percent, threshold ${threshold} percent`}>
<path d="M 10 100 A 90 90 0 0 1 64 31" stroke="var(--color-success)" stroke-width="14" fill="none" />
<path d="M 64 31 A 90 90 0 0 1 136 31" stroke="var(--color-attention)" stroke-width="14" fill="none" />
<path d="M 136 31 A 90 90 0 0 1 190 100" stroke="var(--color-danger)" stroke-width="14" fill="none" />
<g transform={`rotate(${tickAngle} 100 100)`}>
<line x1="100" y1="14" x2="100" y2="32" stroke="var(--color-ink)" stroke-width="3" />
</g>
<g class="dd-needle" transform={`rotate(${angle} 100 100)`}>
<polygon points="100,100 96,108 100,22 104,108" fill="var(--color-ink)" />
<circle cx="100" cy="100" r="6" fill="var(--color-ink)" />
<circle cx="100" cy="100" r="2" fill="var(--color-paper)" />
</g>
<text x="100" y="118" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="9" letter-spacing="2" fill="var(--color-ink)" opacity="0.6">DRIFT %</text>
</svg>
<div class="mt-1 flex items-baseline gap-3">
<span class="font-black text-2xl leading-none tabular-nums">{drift}%</span>
<span class:list={['px-2 py-0.5 border-2 border-black text-white font-black text-[10px] uppercase tracking-widest', statusTone]}>{status}</span>
</div>
<p class="mt-1 font-mono text-[10px] uppercase tracking-widest opacity-60">Tolerance · {threshold}%</p>
</div>
<style>
[data-this-component] .dd-needle {
transform-origin: 100px 100px;
transition: transform 700ms cubic-bezier(0.2, 0, 0.13, 1.4);
}
@media (prefers-reduced-motion: reduce) {
[data-this-component] .dd-needle {
transition: none;
}
}
</style>