helixevo 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +9 -2
- package/dashboard/app/api/proof/route.ts +71 -0
- package/dashboard/app/api/run/route.ts +1 -0
- package/dashboard/app/coevolution/client.tsx +6 -1
- package/dashboard/app/coevolution/page.tsx +3 -1
- package/dashboard/app/commands/page.tsx +32 -5
- package/dashboard/app/guide/page.tsx +34 -21
- package/dashboard/app/ontology/client.tsx +8 -1
- package/dashboard/app/ontology/page.tsx +3 -1
- package/dashboard/app/page.tsx +6 -0
- package/dashboard/app/proof/client.tsx +295 -0
- package/dashboard/app/proof/page.tsx +9 -0
- package/dashboard/app/topology/client.tsx +9 -0
- package/dashboard/app/topology/page.tsx +3 -1
- package/dashboard/components/sidebar-nav.tsx +1 -0
- package/dashboard/lib/loop-map.ts +23 -3
- package/dashboard/lib/proof.ts +577 -0
- package/dashboard/lib/release-spotlight.ts +10 -10
- package/dist/cli.js +500 -0
- package/package.json +2 -2
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { ConsolePanel } from '@/components/console-panel'
|
|
5
|
+
import { MetricCard } from '@/components/metric-card'
|
|
6
|
+
import { NextStepEmptyState } from '@/components/next-step-empty-state'
|
|
7
|
+
import { OperatorLoopTrail } from '@/components/operator-loop-trail'
|
|
8
|
+
import { PageHero } from '@/components/page-hero'
|
|
9
|
+
import { SectionFrame } from '@/components/section-frame'
|
|
10
|
+
import { SurfaceJumpLinks } from '@/components/surface-jump-links'
|
|
11
|
+
import type { ProofDashboardSummary, ProofOutcomeState, ProofReviewDecisionStatus, ProofTargetType } from '@/lib/proof'
|
|
12
|
+
|
|
13
|
+
type RunState = 'idle' | 'running' | 'success' | 'error'
|
|
14
|
+
|
|
15
|
+
function toneForOutcome(outcome: ProofOutcomeState): 'green' | 'yellow' | 'purple' | 'neutral' {
|
|
16
|
+
if (outcome === 'effective') return 'green'
|
|
17
|
+
if (outcome === 'regressed') return 'yellow'
|
|
18
|
+
if (outcome === 'mixed') return 'purple'
|
|
19
|
+
return 'neutral'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function toneForTarget(targetType: ProofTargetType): 'blue' | 'green' | 'purple' | 'yellow' | 'neutral' {
|
|
23
|
+
if (targetType === 'pressure-intervention') return 'blue'
|
|
24
|
+
if (targetType === 'transfer-event') return 'green'
|
|
25
|
+
if (targetType === 'topology-execution') return 'yellow'
|
|
26
|
+
if (targetType === 'ontology-extension') return 'purple'
|
|
27
|
+
return 'neutral'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function labelForTarget(targetType: ProofTargetType) {
|
|
31
|
+
if (targetType === 'pressure-intervention') return 'Intervention'
|
|
32
|
+
if (targetType === 'transfer-event') return 'Transfer'
|
|
33
|
+
if (targetType === 'topology-execution') return 'Topology'
|
|
34
|
+
if (targetType === 'ontology-extension') return 'Ontology'
|
|
35
|
+
return 'Evolution'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function labelForOutcome(outcome: ProofOutcomeState) {
|
|
39
|
+
return outcome.replace(/-/g, ' ')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function formatDate(value: string | undefined) {
|
|
43
|
+
if (!value) return '—'
|
|
44
|
+
return new Date(value).toLocaleString()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function consoleTone(state: RunState): 'neutral' | 'green' | 'red' | 'yellow' {
|
|
48
|
+
if (state === 'success') return 'green'
|
|
49
|
+
if (state === 'error') return 'red'
|
|
50
|
+
if (state === 'running') return 'yellow'
|
|
51
|
+
return 'neutral'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default function ProofClient({ initialDashboard }: { initialDashboard: ProofDashboardSummary }) {
|
|
55
|
+
const [dashboard, setDashboard] = useState(initialDashboard)
|
|
56
|
+
const [runState, setRunState] = useState<RunState>('idle')
|
|
57
|
+
const [output, setOutput] = useState('')
|
|
58
|
+
const [pendingKey, setPendingKey] = useState<string | null>(null)
|
|
59
|
+
|
|
60
|
+
const runReview = async (recordId: string, decision: ProofReviewDecisionStatus, label: string) => {
|
|
61
|
+
setPendingKey(recordId)
|
|
62
|
+
setRunState('running')
|
|
63
|
+
setOutput('')
|
|
64
|
+
try {
|
|
65
|
+
const res = await fetch('/api/proof', {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: { 'Content-Type': 'application/json' },
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
action: 'review',
|
|
70
|
+
recordId,
|
|
71
|
+
decision,
|
|
72
|
+
rationale: `${decision} proof record from dashboard proof control.`,
|
|
73
|
+
}),
|
|
74
|
+
})
|
|
75
|
+
const data = await res.json()
|
|
76
|
+
if (!res.ok || !data.success) {
|
|
77
|
+
setRunState('error')
|
|
78
|
+
setOutput(data.error ?? `${label} failed`)
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
setDashboard(data.dashboard)
|
|
82
|
+
setRunState('success')
|
|
83
|
+
setOutput(data.output || `${label} completed`)
|
|
84
|
+
} catch (err: unknown) {
|
|
85
|
+
setRunState('error')
|
|
86
|
+
setOutput(err instanceof Error ? err.message : `${label} failed`)
|
|
87
|
+
} finally {
|
|
88
|
+
setPendingKey(null)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div style={{ display: 'grid', gap: 22 }}>
|
|
94
|
+
<PageHero
|
|
95
|
+
eyebrow="Outcome attribution"
|
|
96
|
+
title="Proof Control"
|
|
97
|
+
description="Review whether interventions, transfers, topology changes, semantic adoption, and evolution effects actually appear to be working. Proof stays bounded and operator-governed rather than pretending to know more than the evidence supports."
|
|
98
|
+
chips={[
|
|
99
|
+
{ label: `${dashboard.summary.total} proof records`, tone: 'blue' },
|
|
100
|
+
{ label: `${dashboard.summary.effective} effective`, tone: dashboard.summary.effective > 0 ? 'green' : 'neutral' },
|
|
101
|
+
{ label: `${dashboard.summary.mixed} mixed`, tone: dashboard.summary.mixed > 0 ? 'purple' : 'neutral' },
|
|
102
|
+
{ label: `${dashboard.summary.regressed} regressed`, tone: dashboard.summary.regressed > 0 ? 'yellow' : 'neutral' },
|
|
103
|
+
{ label: `${dashboard.summary.reviewOpen} open review`, tone: dashboard.summary.reviewOpen > 0 ? 'yellow' : 'green' },
|
|
104
|
+
{ label: `${dashboard.summary.verified} verified`, tone: dashboard.summary.verified > 0 ? 'green' : 'neutral' },
|
|
105
|
+
]}
|
|
106
|
+
actions={
|
|
107
|
+
<div style={{ display: 'grid', gap: 12 }}>
|
|
108
|
+
<div className="hero-note-card">
|
|
109
|
+
<div className="hero-note-label">Bounded proof layer</div>
|
|
110
|
+
<div className="hero-note-title">Derived first, reviewed explicitly</div>
|
|
111
|
+
<div className="hero-note-copy">The proof layer unifies evolution impact, semantic adoption, transfer, interventions, and topology execution without claiming direct causality when the evidence is only partial.</div>
|
|
112
|
+
</div>
|
|
113
|
+
<SurfaceJumpLinks surface="proof" variant="compact" title="Proof handoffs" />
|
|
114
|
+
</div>
|
|
115
|
+
}
|
|
116
|
+
/>
|
|
117
|
+
|
|
118
|
+
<OperatorLoopTrail surface="proof" />
|
|
119
|
+
|
|
120
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
|
|
121
|
+
<MetricCard label="Effective" value={dashboard.summary.effective} sublabel={`${dashboard.summary.verified} verified • ${dashboard.summary.reviewOpen} waiting for review`} tone={dashboard.summary.effective > 0 ? 'green' : 'neutral'} icon="✓" />
|
|
122
|
+
<MetricCard label="Mixed" value={dashboard.summary.mixed} sublabel="partial or conflicting downstream evidence" tone={dashboard.summary.mixed > 0 ? 'purple' : 'neutral'} icon="⇄" />
|
|
123
|
+
<MetricCard label="Regressed" value={dashboard.summary.regressed} sublabel={`${dashboard.summary.contested} contested • explicit failed or rolled-back cases`} tone={dashboard.summary.regressed > 0 ? 'yellow' : 'neutral'} icon="!" />
|
|
124
|
+
<MetricCard label="Measuring" value={dashboard.summary.measuring} sublabel={`${dashboard.summary.insufficientEvidence} insufficient-evidence`} tone={dashboard.summary.measuring > 0 ? 'blue' : 'neutral'} icon="◎" />
|
|
125
|
+
<MetricCard label="Open review" value={dashboard.summary.reviewOpen} sublabel={`${dashboard.summary.deferred} deferred • ${dashboard.summary.verified} verified`} tone={dashboard.summary.reviewOpen > 0 ? 'yellow' : 'green'} icon="◇" />
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<SectionFrame
|
|
129
|
+
eyebrow="Coverage"
|
|
130
|
+
title="Proof now spans the live brain loop"
|
|
131
|
+
description="Milestone 10 stops prove from being only metrics. It unifies evidence review across response, transfer, topology, semantic adoption, and existing evolution measurement."
|
|
132
|
+
>
|
|
133
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 12 }}>
|
|
134
|
+
{dashboard.byTargetType.length > 0 ? dashboard.byTargetType.map((entry) => (
|
|
135
|
+
<div key={entry.targetType} className="guide-dimension-card" style={{ borderLeftColor: `var(--${toneForTarget(entry.targetType) === 'neutral' ? 'text-muted' : toneForTarget(entry.targetType)})` }}>
|
|
136
|
+
<div style={{ fontSize: 12, fontWeight: 700, color: 'var(--text)' }}>{labelForTarget(entry.targetType)}</div>
|
|
137
|
+
<div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 8, lineHeight: 1.7 }}>
|
|
138
|
+
{entry.total} total • {entry.effective} effective • {entry.mixed} mixed • {entry.regressed} regressed • {entry.measuring} measuring
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
)) : (
|
|
142
|
+
<NextStepEmptyState
|
|
143
|
+
title="No proof targets yet"
|
|
144
|
+
description="Create live interventions, semantic adoption, or topology execution first. Proof becomes useful when HelixEvo has real actions and downstream evidence to evaluate."
|
|
145
|
+
command="helixevo proof --status"
|
|
146
|
+
pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
|
|
147
|
+
guideLink={{ label: 'Guide · Closed-Loop Metrics', anchor: 'metrics', tone: 'blue' }}
|
|
148
|
+
/>
|
|
149
|
+
)}
|
|
150
|
+
</div>
|
|
151
|
+
</SectionFrame>
|
|
152
|
+
|
|
153
|
+
<SectionFrame
|
|
154
|
+
eyebrow="Review queue"
|
|
155
|
+
title="Open proof review"
|
|
156
|
+
description="Derived proof stays operator-governed. Verify, defer, or contest proof records explicitly instead of treating heuristics as unquestionable truth."
|
|
157
|
+
>
|
|
158
|
+
<div style={{ display: 'grid', gap: 12 }}>
|
|
159
|
+
{dashboard.reviewQueue.length > 0 ? dashboard.reviewQueue.map((record) => (
|
|
160
|
+
<div key={record.id} style={{ padding: '16px 18px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.74)' }}>
|
|
161
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' }}>
|
|
162
|
+
<div style={{ display: 'grid', gap: 4, flex: 1 }}>
|
|
163
|
+
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)' }}>{record.title}</div>
|
|
164
|
+
<div style={{ fontSize: 12, color: 'var(--text-dim)', lineHeight: 1.6 }}>{record.summary}</div>
|
|
165
|
+
</div>
|
|
166
|
+
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
|
|
167
|
+
<span className={`badge badge-${toneForTarget(record.targetType)}`}>{labelForTarget(record.targetType)}</span>
|
|
168
|
+
<span className={`badge badge-${toneForOutcome(record.outcomeState)}`}>{labelForOutcome(record.outcomeState)}</span>
|
|
169
|
+
<span className="badge badge-gray">{(record.confidence * 100).toFixed(0)}% confidence</span>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 12 }}>
|
|
174
|
+
<span className="badge badge-gray">created {formatDate(record.createdAt)}</span>
|
|
175
|
+
<span className="badge badge-gray">activity {formatDate(record.lastActivityAt)}</span>
|
|
176
|
+
{(record.relatedProjectIds ?? []).slice(0, 3).map((projectId) => <span key={`${record.id}-${projectId}`} className="badge badge-gray">{projectId}</span>)}
|
|
177
|
+
{(record.semanticConceptIds ?? []).slice(0, 2).map((conceptId) => <span key={`${record.id}-${conceptId}`} className="badge badge-green">{conceptId}</span>)}
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<div style={{ display: 'grid', gap: 6, marginTop: 12 }}>
|
|
181
|
+
{record.reasons.slice(0, 3).map((reason, idx) => (
|
|
182
|
+
<div key={`${record.id}-${idx}`} className="signal-text">• {reason}</div>
|
|
183
|
+
))}
|
|
184
|
+
{record.recommendedAction ? <div className="signal-text">→ {record.recommendedAction}</div> : null}
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 14 }}>
|
|
188
|
+
<button onClick={() => runReview(record.id, 'verify', `verify ${record.title}`)} disabled={pendingKey === record.id} className="badge badge-green" style={{ border: 'none', cursor: 'pointer' }}>Verify</button>
|
|
189
|
+
<button onClick={() => runReview(record.id, 'defer', `defer ${record.title}`)} disabled={pendingKey === record.id} className="badge badge-purple" style={{ border: 'none', cursor: 'pointer' }}>Defer</button>
|
|
190
|
+
<button onClick={() => runReview(record.id, 'contest', `contest ${record.title}`)} disabled={pendingKey === record.id} className="badge badge-yellow" style={{ border: 'none', cursor: 'pointer' }}>Contest</button>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
)) : (
|
|
194
|
+
<NextStepEmptyState
|
|
195
|
+
title="No open proof reviews"
|
|
196
|
+
description="Either the proof layer has no records yet or every current record has already been verified, deferred, or contested."
|
|
197
|
+
command="helixevo proof --status --verbose"
|
|
198
|
+
pageLink={{ label: 'Open Ontology', href: '/ontology', tone: 'green' }}
|
|
199
|
+
guideLink={{ label: 'Guide · Closed-Loop Metrics', anchor: 'metrics', tone: 'blue' }}
|
|
200
|
+
/>
|
|
201
|
+
)}
|
|
202
|
+
</div>
|
|
203
|
+
</SectionFrame>
|
|
204
|
+
|
|
205
|
+
<div className="grid-2">
|
|
206
|
+
<SectionFrame
|
|
207
|
+
eyebrow="Verified"
|
|
208
|
+
title="Recent verified proof"
|
|
209
|
+
description="Operator-verified records become the most trustworthy proof layer inside the current bounded system."
|
|
210
|
+
>
|
|
211
|
+
<div style={{ display: 'grid', gap: 10 }}>
|
|
212
|
+
{dashboard.recentVerified.length > 0 ? dashboard.recentVerified.map((record) => (
|
|
213
|
+
<div key={record.id} style={{ padding: '14px 16px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.72)' }}>
|
|
214
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
|
215
|
+
<div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{record.title}</div>
|
|
216
|
+
<span className="badge badge-green">verified</span>
|
|
217
|
+
</div>
|
|
218
|
+
<div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.6 }}>{record.summary}</div>
|
|
219
|
+
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 10 }}>
|
|
220
|
+
<span className={`badge badge-${toneForOutcome(record.outcomeState)}`}>{labelForOutcome(record.outcomeState)}</span>
|
|
221
|
+
<span className="badge badge-gray">{labelForTarget(record.targetType)}</span>
|
|
222
|
+
<span className="badge badge-gray">{formatDate(record.latestReview?.decidedAt)}</span>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
)) : <div className="signal-text">No verified proof records yet.</div>}
|
|
226
|
+
</div>
|
|
227
|
+
</SectionFrame>
|
|
228
|
+
|
|
229
|
+
<SectionFrame
|
|
230
|
+
eyebrow="Contested"
|
|
231
|
+
title="Recent contested proof"
|
|
232
|
+
description="Contest records when the derived attribution is too strong, too weak, or simply not aligned with operator judgment."
|
|
233
|
+
>
|
|
234
|
+
<div style={{ display: 'grid', gap: 10 }}>
|
|
235
|
+
{dashboard.recentContested.length > 0 ? dashboard.recentContested.map((record) => (
|
|
236
|
+
<div key={record.id} style={{ padding: '14px 16px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.72)' }}>
|
|
237
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
|
238
|
+
<div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{record.title}</div>
|
|
239
|
+
<span className="badge badge-yellow">contested</span>
|
|
240
|
+
</div>
|
|
241
|
+
<div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.6 }}>{record.summary}</div>
|
|
242
|
+
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 10 }}>
|
|
243
|
+
<span className={`badge badge-${toneForOutcome(record.outcomeState)}`}>{labelForOutcome(record.outcomeState)}</span>
|
|
244
|
+
<span className="badge badge-gray">{labelForTarget(record.targetType)}</span>
|
|
245
|
+
<span className="badge badge-gray">{formatDate(record.latestReview?.decidedAt)}</span>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
)) : <div className="signal-text">No contested proof records yet.</div>}
|
|
249
|
+
</div>
|
|
250
|
+
</SectionFrame>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<SectionFrame
|
|
254
|
+
eyebrow="Ledger"
|
|
255
|
+
title="All proof records"
|
|
256
|
+
description="A unified view across intervention, transfer, structural, semantic, and evolution evidence."
|
|
257
|
+
>
|
|
258
|
+
<div style={{ display: 'grid', gap: 12 }}>
|
|
259
|
+
{dashboard.records.length > 0 ? dashboard.records.map((record) => (
|
|
260
|
+
<div key={record.id} style={{ padding: '14px 16px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.72)' }}>
|
|
261
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' }}>
|
|
262
|
+
<div style={{ display: 'grid', gap: 4, flex: 1 }}>
|
|
263
|
+
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)' }}>{record.title}</div>
|
|
264
|
+
<div style={{ fontSize: 12, color: 'var(--text-dim)', lineHeight: 1.6 }}>{record.summary}</div>
|
|
265
|
+
</div>
|
|
266
|
+
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
|
|
267
|
+
<span className={`badge badge-${toneForTarget(record.targetType)}`}>{labelForTarget(record.targetType)}</span>
|
|
268
|
+
<span className={`badge badge-${toneForOutcome(record.outcomeState)}`}>{labelForOutcome(record.outcomeState)}</span>
|
|
269
|
+
<span className="badge badge-gray">{record.reviewStatus}</span>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
{record.latestReview?.rationale ? <div className="signal-text" style={{ marginTop: 10 }}>review rationale · {record.latestReview.rationale}</div> : null}
|
|
273
|
+
</div>
|
|
274
|
+
)) : null}
|
|
275
|
+
</div>
|
|
276
|
+
</SectionFrame>
|
|
277
|
+
|
|
278
|
+
<ConsolePanel
|
|
279
|
+
title="Proof console"
|
|
280
|
+
tone={consoleTone(runState)}
|
|
281
|
+
actions={<span className="badge badge-gray">{runState === 'running' ? 'running' : runState === 'success' ? 'success' : runState === 'error' ? 'error' : 'idle'}</span>}
|
|
282
|
+
>
|
|
283
|
+
<pre style={{ margin: 0, whiteSpace: 'pre-wrap', fontSize: 12, lineHeight: 1.7, color: 'var(--text-dim)' }}>
|
|
284
|
+
{runState === 'running'
|
|
285
|
+
? 'Recording proof review…\n\n' + (output || '')
|
|
286
|
+
: runState === 'success'
|
|
287
|
+
? (output || 'Proof review completed.')
|
|
288
|
+
: runState === 'error'
|
|
289
|
+
? (output || 'Proof review failed.')
|
|
290
|
+
: 'Use this surface to review derived proof records once HelixEvo has enough downstream evidence.'}
|
|
291
|
+
</pre>
|
|
292
|
+
</ConsolePanel>
|
|
293
|
+
</div>
|
|
294
|
+
)
|
|
295
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import ProofClient from './client'
|
|
2
|
+
import { loadProofDashboardSummary } from '@/lib/proof'
|
|
3
|
+
|
|
4
|
+
export const dynamic = 'force-dynamic'
|
|
5
|
+
|
|
6
|
+
export default function ProofPage() {
|
|
7
|
+
const dashboard = loadProofDashboardSummary()
|
|
8
|
+
return <ProofClient initialDashboard={dashboard} />
|
|
9
|
+
}
|
|
@@ -10,6 +10,7 @@ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
|
|
|
10
10
|
import { SurfaceJumpLinks } from '@/components/surface-jump-links'
|
|
11
11
|
import { NextStepEmptyState } from '@/components/next-step-empty-state'
|
|
12
12
|
import type { GovernanceModeName, GovernanceState, TopologyDashboardSummary, TopologyReviewDecisionStatus, TopologyReviewStatus } from '@/lib/data'
|
|
13
|
+
import type { ProofDashboardSummary } from '@/lib/proof'
|
|
13
14
|
|
|
14
15
|
type RunState = 'idle' | 'running' | 'success' | 'error' | 'stopped'
|
|
15
16
|
|
|
@@ -65,9 +66,11 @@ function consoleTone(state: RunState): 'neutral' | 'green' | 'red' | 'yellow' {
|
|
|
65
66
|
export default function TopologyClient({
|
|
66
67
|
initialDashboard,
|
|
67
68
|
initialGovernanceState,
|
|
69
|
+
proof,
|
|
68
70
|
}: {
|
|
69
71
|
initialDashboard: TopologyDashboardSummary
|
|
70
72
|
initialGovernanceState: GovernanceState
|
|
73
|
+
proof: ProofDashboardSummary
|
|
71
74
|
}) {
|
|
72
75
|
const [dashboard, setDashboard] = useState(initialDashboard)
|
|
73
76
|
const [governanceState, setGovernanceState] = useState(initialGovernanceState)
|
|
@@ -244,6 +247,7 @@ export default function TopologyClient({
|
|
|
244
247
|
{ label: `${dashboard.summary.open} open reviews`, tone: dashboard.summary.open > 0 ? 'yellow' : 'green' },
|
|
245
248
|
{ label: `${dashboard.execution.prepared} prepared`, tone: dashboard.execution.prepared > 0 ? 'blue' : 'neutral' },
|
|
246
249
|
{ label: `${dashboard.execution.applied} applied`, tone: dashboard.execution.applied > 0 ? 'green' : 'neutral' },
|
|
250
|
+
{ label: `${proof.summary.reviewOpen} proof review`, tone: proof.summary.reviewOpen > 0 ? 'yellow' : proof.summary.effective > 0 ? 'green' : 'neutral' },
|
|
247
251
|
{ label: formatMode(dashboard.governance.activeMode), tone: toneForMode(dashboard.governance.activeMode) },
|
|
248
252
|
{ label: dashboard.governance.source === 'operator-selected' ? 'operator-steered' : 'derived mode', tone: dashboard.governance.source === 'operator-selected' ? 'purple' : 'neutral' },
|
|
249
253
|
]}
|
|
@@ -253,6 +257,10 @@ export default function TopologyClient({
|
|
|
253
257
|
<div className="hero-note-label">Active governance profile</div>
|
|
254
258
|
<div className="hero-note-title">{formatMode(dashboard.governance.activeMode)}</div>
|
|
255
259
|
<div className="hero-note-copy">{dashboard.governance.profile.explanation}</div>
|
|
260
|
+
<div style={{ marginTop: 8, display: 'flex', gap: 6, flexWrap: 'wrap' }}>
|
|
261
|
+
<span className="badge badge-gray">{proof.summary.effective} effective records</span>
|
|
262
|
+
<Link href="/proof" className="badge badge-gray" style={{ textDecoration: 'none' }}>open proof</Link>
|
|
263
|
+
</div>
|
|
256
264
|
</div>
|
|
257
265
|
<div style={{ display: 'grid', gap: 10 }}>
|
|
258
266
|
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
|
|
@@ -271,6 +279,7 @@ export default function TopologyClient({
|
|
|
271
279
|
<MetricCard label="Accepted ready" value={dashboard.acceptedReady.length} sublabel="accepted candidates not yet prepared for execution" tone={dashboard.acceptedReady.length > 0 ? 'blue' : 'neutral'} icon="✓" />
|
|
272
280
|
<MetricCard label="Prepared plans" value={dashboard.execution.prepared} sublabel={`${dashboard.execution.safeToApply} safe-to-apply • ${dashboard.execution.prepareOnly} prepare-only`} tone={dashboard.execution.prepared > 0 ? 'blue' : 'neutral'} icon="◇" />
|
|
273
281
|
<MetricCard label="Applied plans" value={dashboard.execution.applied} sublabel={`${dashboard.execution.rolledBack} rolled back • ${dashboard.execution.artifacts} artifacts`} tone={dashboard.execution.applied > 0 ? 'green' : 'neutral'} icon="↑" />
|
|
282
|
+
<MetricCard label="Structural proof" value={proof.summary.reviewOpen} sublabel={`${proof.summary.effective} effective • ${proof.summary.regressed} regressed`} tone={proof.summary.reviewOpen > 0 ? 'yellow' : proof.summary.effective > 0 ? 'green' : 'neutral'} icon="◇" />
|
|
274
283
|
<MetricCard label="Manual-route backlog" value={dashboard.summary.generatedFromManualReview} sublabel="pressure routed into actual operator review" tone="purple" icon="!" />
|
|
275
284
|
<MetricCard label="Snapshots" value={dashboard.execution.snapshots} sublabel="before/after state preserved for reviewed execution" tone="purple" icon="◎" />
|
|
276
285
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loadGovernanceState, loadTopologyDashboardSummary } from '@/lib/data'
|
|
2
|
+
import { loadProofDashboardSummary } from '@/lib/proof'
|
|
2
3
|
import TopologyClient from './client'
|
|
3
4
|
|
|
4
5
|
export const dynamic = 'force-dynamic'
|
|
@@ -6,5 +7,6 @@ export const dynamic = 'force-dynamic'
|
|
|
6
7
|
export default function TopologyPage() {
|
|
7
8
|
const dashboard = loadTopologyDashboardSummary()
|
|
8
9
|
const governanceState = loadGovernanceState()
|
|
9
|
-
|
|
10
|
+
const proof = loadProofDashboardSummary()
|
|
11
|
+
return <TopologyClient initialDashboard={dashboard} initialGovernanceState={governanceState} proof={proof} />
|
|
10
12
|
}
|
|
@@ -14,6 +14,7 @@ const OPERATE_NAV: NavItem[] = [
|
|
|
14
14
|
{ href: '/projects', label: 'Projects', icon: 'M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z' },
|
|
15
15
|
{ href: '/research', label: 'Research', icon: 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z' },
|
|
16
16
|
{ href: '/coevolution', label: 'Co-Evolution', icon: 'M4 12h4m8 0h4M12 4v4m0 8v4M7.05 7.05l2.83 2.83m4.24 4.24l2.83 2.83m0-9.9l-2.83 2.83m-4.24 4.24l-2.83 2.83' },
|
|
17
|
+
{ href: '/proof', label: 'Proof', icon: 'M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z' },
|
|
17
18
|
]
|
|
18
19
|
|
|
19
20
|
const STRUCTURE_NAV: NavItem[] = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type LoopStageId = 'observe' | 'route' | 'adopt' | 'restructure' | 'prove'
|
|
2
|
-
export type SurfaceKey = 'overview' | 'projects' | 'research' | 'coevolution' | 'ontology' | 'topology'
|
|
2
|
+
export type SurfaceKey = 'overview' | 'projects' | 'research' | 'coevolution' | 'ontology' | 'topology' | 'proof'
|
|
3
3
|
export type SurfaceTone = 'blue' | 'green' | 'purple' | 'yellow' | 'neutral'
|
|
4
4
|
export type GuideAnchorId = 'quickstart' | 'brainstack' | 'loop' | 'semanticcontrol' | 'surfaces' | 'commands' | 'maturity' | 'metrics'
|
|
5
5
|
|
|
@@ -66,9 +66,9 @@ export const LOOP_STAGES: LoopStageMeta[] = [
|
|
|
66
66
|
{
|
|
67
67
|
id: 'prove',
|
|
68
68
|
label: 'Prove',
|
|
69
|
-
href: '/
|
|
69
|
+
href: '/proof',
|
|
70
70
|
tone: 'neutral',
|
|
71
|
-
description: '
|
|
71
|
+
description: 'Review bounded outcome attribution, proof decisions, and the live evidence ledger.',
|
|
72
72
|
},
|
|
73
73
|
]
|
|
74
74
|
|
|
@@ -97,6 +97,7 @@ export const SURFACE_LOOP_CONFIG: Record<SurfaceKey, SurfaceLoopConfig> = {
|
|
|
97
97
|
{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple', description: 'Inspect governed routing and the active response backlog.' },
|
|
98
98
|
{ label: 'Open Ontology', href: '/ontology', tone: 'green', description: 'Inspect semantic adoption, frontier review, and concept consumers.' },
|
|
99
99
|
{ label: 'Open Topology', href: '/topology', tone: 'yellow', description: 'Review structural candidates, preparation, and rollbackable execution.' },
|
|
100
|
+
{ label: 'Open Proof', href: '/proof', tone: 'neutral', description: 'Review what appears to be working, regressing, or still measuring.' },
|
|
100
101
|
],
|
|
101
102
|
guideLinks: [
|
|
102
103
|
{ label: 'Read Quick Start', anchor: 'quickstart', tone: 'blue', description: 'See the shortest operator path into the live brain loop.' },
|
|
@@ -143,6 +144,7 @@ export const SURFACE_LOOP_CONFIG: Record<SurfaceKey, SurfaceLoopConfig> = {
|
|
|
143
144
|
{ label: 'Open Ontology', href: '/ontology', tone: 'green', description: 'Inspect which approved concepts are influencing current route rationale.' },
|
|
144
145
|
{ label: 'Open Topology', href: '/topology', tone: 'yellow', description: 'Escalate mixed-signal structural demand into review and execution.' },
|
|
145
146
|
{ label: 'Open Research', href: '/research', tone: 'blue', description: 'Run or inspect the discovery lane when research is the governed response.' },
|
|
147
|
+
{ label: 'Open Proof', href: '/proof', tone: 'neutral', description: 'See whether routed interventions and transfer appear effective yet.' },
|
|
146
148
|
],
|
|
147
149
|
guideLinks: [
|
|
148
150
|
{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green', description: 'See how semantic adoption shapes route explanation without bypassing governance.' },
|
|
@@ -158,6 +160,7 @@ export const SURFACE_LOOP_CONFIG: Record<SurfaceKey, SurfaceLoopConfig> = {
|
|
|
158
160
|
{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple', description: 'See where active concepts are influencing current route rationale.' },
|
|
159
161
|
{ label: 'Open Topology', href: '/topology', tone: 'yellow', description: 'Compare semantic adoption with structural review and execution.' },
|
|
160
162
|
{ label: 'Open Skill Network', href: '/network', tone: 'blue', description: 'Inspect semantic context alongside graph relationships and inspector detail.' },
|
|
163
|
+
{ label: 'Open Proof', href: '/proof', tone: 'neutral', description: 'Review semantic-adoption effectiveness without overclaiming causality.' },
|
|
161
164
|
],
|
|
162
165
|
guideLinks: [
|
|
163
166
|
{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green', description: 'Read the post-M8 / post-M9 ontology lifecycle and operator playbooks.' },
|
|
@@ -173,12 +176,29 @@ export const SURFACE_LOOP_CONFIG: Record<SurfaceKey, SurfaceLoopConfig> = {
|
|
|
173
176
|
{ label: 'Open Ontology', href: '/ontology', tone: 'green', description: 'Check the semantic families clustering around current structural candidates.' },
|
|
174
177
|
{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple', description: 'Return to the governed response backlog feeding structural review.' },
|
|
175
178
|
{ label: 'Open Skill Network', href: '/network', tone: 'blue', description: 'Inspect the graph context around the candidates being reviewed or applied.' },
|
|
179
|
+
{ label: 'Open Proof', href: '/proof', tone: 'neutral', description: 'Review whether structural execution appears effective, mixed, or regressed.' },
|
|
176
180
|
],
|
|
177
181
|
guideLinks: [
|
|
178
182
|
{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'purple', description: 'See how topology fits the rest of the dashboard operator loop.' },
|
|
179
183
|
{ label: 'Guide · Maturity & Safety', anchor: 'maturity', tone: 'yellow', description: 'Review the current bounded-safe-execution limits before structural action.' },
|
|
180
184
|
],
|
|
181
185
|
},
|
|
186
|
+
proof: {
|
|
187
|
+
key: 'proof',
|
|
188
|
+
label: 'Proof',
|
|
189
|
+
stage: 'prove',
|
|
190
|
+
context: 'Proof is where bounded outcome attribution becomes explicit operator review across interventions, semantics, transfer, topology, and evolution.',
|
|
191
|
+
adjacentLinks: [
|
|
192
|
+
{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple', description: 'Compare proof verdicts with the active response backlog and route state.' },
|
|
193
|
+
{ label: 'Open Ontology', href: '/ontology', tone: 'green', description: 'Inspect semantic-adoption evidence alongside concept review and deprecation risk.' },
|
|
194
|
+
{ label: 'Open Topology', href: '/topology', tone: 'yellow', description: 'Compare structural execution outcomes with their reviewed execution history.' },
|
|
195
|
+
{ label: 'Open Overview', href: '/', tone: 'blue', description: 'Return to the cockpit after reviewing what appears to be working.' },
|
|
196
|
+
],
|
|
197
|
+
guideLinks: [
|
|
198
|
+
{ label: 'Guide · Closed-Loop Metrics', anchor: 'metrics', tone: 'blue', description: 'Read how metrics and proof fit together inside the prove stage.' },
|
|
199
|
+
{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'purple', description: 'See where Proof sits in the dashboard operator loop.' },
|
|
200
|
+
],
|
|
201
|
+
},
|
|
182
202
|
}
|
|
183
203
|
|
|
184
204
|
export function getSurfaceLoopConfig(surface: SurfaceKey) {
|