Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/data/vortexopedia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,37 @@ export const vortexopediaTerms: VortexopediaTerm[] = [
source: "Discussion",
updated: "2025-12-04",
},
{
ref: 43.1,
id: "invision_band",
name: "Invision band",
category: "governance",
short:
"A readable health label for an Invision score, grouping the raw percentage into a low, medium, or high condition.",
long: [
"Invision engines calculate raw scores for system dimensions such as decentralization and stability.",
"The band translates that percentage into a quick status label so a user can scan the system without interpreting every component immediately.",
"The band does not replace the score. The score is the numerical result; the band is the human-readable bucket for that result.",
],
tags: ["invision", "system_health", "score", "status", "band"],
related: [
"gradual_decentralization",
"constant_deterrence",
"legitimacy_referendum",
],
examples: [
"A stability score of 28% can sit in a low band, while a score near 80% can sit in a high band.",
],
stages: ["global"],
links: [
{
label: "Invision",
url: "/app/invision",
},
],
source: "App UX: Invision system health",
updated: "2026-06-19",
},
{
ref: 44,
id: "voter_apathy",
Expand Down
43 changes: 33 additions & 10 deletions src/pages/invision/Invision.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@ function toneForScore(tone: InvisionStabilityComponentDto["tone"]) {
return "ok";
}

function toneForConfidence(engine: EngineDto): StatusTone {
if (engine.confidenceBand === "High" || engine.confidence >= 75) return "ok";
if (engine.confidenceBand === "Medium" || engine.confidence >= 50) {
return "warn";
}
function toneForHealthScore(score: number): StatusTone {
if (score >= 67) return "ok";
if (score >= 34) return "warn";
return "danger";
}

function toneForMetricValue(value: string): StatusTone {
const percentValue = Number(value.replace("%", "").trim());
if (!Number.isFinite(percentValue)) return "neutral";
return toneForHealthScore(percentValue);
}

function toneForRiskStatus(status: string) {
const normalized = status.trim().toLowerCase();
if (normalized === "critical") return "danger";
Expand All @@ -56,12 +60,27 @@ function EngineSection({
}) {
return (
<GlassySection className="h-full" title={title}>
<GlassyCompactGrid className="lg:grid-cols-3">
<GlassyCompactMetric label="Band" value={engine.band} />
<GlassyCompactGrid className="lg:grid-cols-4">
<GlassyCompactMetric
label="Score"
value={
<GlassyStatusChip tone={toneForHealthScore(engine.score)}>
{engine.score}%
</GlassyStatusChip>
}
/>
<GlassyCompactMetric
label="Confidence"
label={<HintLabel termId="invision_band">Band</HintLabel>}
value={
<GlassyStatusChip tone={toneForConfidence(engine)}>
<GlassyStatusChip tone={toneForHealthScore(engine.score)}>
{engine.band}
</GlassyStatusChip>
}
/>
<GlassyCompactMetric
label="Evidence coverage"
value={
<GlassyStatusChip tone="neutral">
{engine.confidence}% · {engine.confidenceBand}
</GlassyStatusChip>
}
Expand Down Expand Up @@ -197,7 +216,11 @@ const Invision: React.FC = () => {
<GlassyMetricTile
key={metric.label}
label={metric.label}
value={metric.value}
value={
<GlassyStatusChip tone={toneForMetricValue(metric.value)}>
{metric.value}
</GlassyStatusChip>
}
/>
))}
</GlassyCompactGrid>
Expand Down
3 changes: 3 additions & 0 deletions src/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@ export type GetFormationResponse = {
export type InvisionGovernanceMetricDto = { label: string; value: string };
export type InvisionGovernanceStateDto = {
label: string;
tone?: "critical" | "watch" | "stable" | "strong" | "unknown";
summary?: string;
drivers?: string[];
metrics: InvisionGovernanceMetricDto[];
};
export type InvisionStabilityComponentDto = {
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/phase89-visual-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ test("Phase 89 static visual contract covers public entry routes", () => {
assert.match(guide, /The two UX primitives: hints and stages/);

assert.match(vortexopedia, /Search terms/);
assert.match(vortexopedia, /Showing 56 \/ 56 entries/);
assert.match(vortexopedia, /Showing 57 \/ 57 entries/);
assert.match(vortexopedia, /Invision band/);
assert.match(vortexopedia, /Vortex/);
});

Expand Down
Loading