helixevo 0.6.0 → 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.
@@ -6,7 +6,11 @@ import { ConsolePanel } from '@/components/console-panel'
6
6
  import { MetricCard } from '@/components/metric-card'
7
7
  import { PageHero } from '@/components/page-hero'
8
8
  import { SectionFrame } from '@/components/section-frame'
9
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
10
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
11
+ import { NextStepEmptyState } from '@/components/next-step-empty-state'
9
12
  import type { OntologyControlDashboardSummary, OntologyReviewDecisionStatus } from '@/lib/data'
13
+ import type { ProofDashboardSummary } from '@/lib/proof'
10
14
 
11
15
  type RunState = 'idle' | 'running' | 'success' | 'error'
12
16
 
@@ -32,7 +36,7 @@ function formatMode(value: string) {
32
36
  return value.replace(/-/g, ' ')
33
37
  }
34
38
 
35
- export default function OntologyClient({ initialDashboard }: { initialDashboard: OntologyControlDashboardSummary }) {
39
+ export default function OntologyClient({ initialDashboard, proof }: { initialDashboard: OntologyControlDashboardSummary; proof: ProofDashboardSummary }) {
36
40
  const [dashboard, setDashboard] = useState(initialDashboard)
37
41
  const [runState, setRunState] = useState<RunState>('idle')
38
42
  const [output, setOutput] = useState('')
@@ -77,6 +81,7 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
77
81
  { label: `${dashboard.summary.extensions} approved extensions`, tone: dashboard.summary.extensions > 0 ? 'blue' : 'neutral' },
78
82
  { label: `${dashboard.adoption.activeConcepts} active concepts`, tone: dashboard.adoption.activeConcepts > 0 ? 'green' : 'neutral' },
79
83
  { label: `${dashboard.adoption.routesInfluenced} semantically influenced routes`, tone: dashboard.adoption.routesInfluenced > 0 ? 'purple' : 'neutral' },
84
+ { label: `${proof.summary.reviewOpen} proof review`, tone: proof.summary.reviewOpen > 0 ? 'yellow' : proof.summary.effective > 0 ? 'green' : 'neutral' },
80
85
  { label: formatMode(dashboard.governance.activeMode), tone: dashboard.governance.activeMode === 'transfer-focused' ? 'purple' : dashboard.governance.activeMode === 'project-critical' ? 'yellow' : 'blue' },
81
86
  ]}
82
87
  actions={
@@ -85,22 +90,30 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
85
90
  <div className="hero-note-label">Native ontology state</div>
86
91
  <div className="hero-note-title">Kernel + review + semantic adoption</div>
87
92
  <div className="hero-note-copy">Use this surface to move from frontier hypotheses into approved extensions, inspect active semantic consumers, and manage deprecation with operator-visible risk rather than hidden drift.</div>
93
+ <div style={{ marginTop: 8, display: 'flex', gap: 6, flexWrap: 'wrap' }}>
94
+ <Link href="/proof" className="badge badge-gray" style={{ textDecoration: 'none' }}>open proof</Link>
95
+ <span className="badge badge-gray">{proof.summary.effective} effective records live</span>
96
+ </div>
88
97
  </div>
89
- <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
90
- <button onClick={() => runAction('refresh', {}, 'ontology refresh')} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Refresh ontology frontier</button>
91
- <Link href="/coevolution" className="badge badge-gray">Open co-evolution</Link>
92
- <Link href="/topology" className="badge badge-gray">Open topology</Link>
98
+ <div style={{ display: 'grid', gap: 10 }}>
99
+ <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
100
+ <button onClick={() => runAction('refresh', {}, 'ontology refresh')} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Refresh ontology frontier</button>
101
+ </div>
102
+ <SurfaceJumpLinks surface="ontology" variant="compact" title="Semantic handoffs" />
93
103
  </div>
94
104
  </div>
95
105
  }
96
106
  />
97
107
 
108
+ <OperatorLoopTrail surface="ontology" />
109
+
98
110
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
99
111
  <MetricCard label="Kernel concepts" value={dashboard.summary.kernelConcepts} sublabel={`${dashboard.kernel.relationFamilies.length} relation families`} tone="purple" icon="◎" />
100
112
  <MetricCard label="Frontier hypotheses" value={dashboard.summary.frontier} sublabel={`${dashboard.summary.reviewOpen} open • ${dashboard.summary.deferred} deferred`} tone={dashboard.summary.reviewOpen > 0 ? 'yellow' : 'neutral'} icon="◇" />
101
113
  <MetricCard label="Approved extensions" value={dashboard.summary.extensions} sublabel={`${dashboard.summary.deprecated} deprecated • ${dashboard.adoption.unusedExtensions} unused`} tone={dashboard.summary.extensions > 0 ? 'blue' : 'neutral'} icon="↑" />
102
114
  <MetricCard label="Active semantic concepts" value={dashboard.adoption.activeConcepts} sublabel={`${dashboard.adoption.totalBindings} bindings • ${dashboard.adoption.routesInfluenced} routed influences`} tone={dashboard.adoption.activeConcepts > 0 ? 'green' : 'neutral'} icon="⇄" />
103
115
  <MetricCard label="Deprecation-sensitive" value={dashboard.adoption.conceptsAtDeprecationRisk} sublabel="approved concepts with live consumers" tone={dashboard.adoption.conceptsAtDeprecationRisk > 0 ? 'yellow' : 'neutral'} icon="!" />
116
+ <MetricCard label="Semantic proof review" value={proof.summary.reviewOpen} sublabel={`${proof.summary.effective} effective • ${proof.summary.mixed} mixed`} tone={proof.summary.reviewOpen > 0 ? 'yellow' : proof.summary.effective > 0 ? 'green' : 'neutral'} icon="◇" />
104
117
  <MetricCard label="Concept changes" value={dashboard.summary.changeEvents} sublabel={`${dashboard.summary.promoted} promoted • ${dashboard.summary.rejected} rejected`} tone={dashboard.summary.changeEvents > 0 ? 'green' : 'neutral'} icon="⇄" />
105
118
  </div>
106
119
 
@@ -198,10 +211,13 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
198
211
  </div>
199
212
  </div>
200
213
  )) : (
201
- <div className="empty-state" style={{ padding: 24 }}>
202
- <div className="empty-state-title">No ontology frontier concepts yet</div>
203
- <div className="empty-state-desc">Run “Refresh ontology frontier after pressure motifs, project gaps, or topology review patterns accumulate.</div>
204
- </div>
214
+ <NextStepEmptyState
215
+ title="No ontology frontier concepts yet"
216
+ description="Run a frontier refresh after pressure motifs, project gaps, or topology review patterns accumulate. Frontier creation is the first step before any concept can become active semantic control."
217
+ command="helixevo ontology --refresh"
218
+ pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
219
+ guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
220
+ />
205
221
  )}
206
222
  </div>
207
223
  </SectionFrame>
@@ -240,10 +256,13 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
240
256
  {concept.warning ? <div className="signal-text" style={{ marginTop: 10 }}>• {concept.warning}</div> : null}
241
257
  </div>
242
258
  )) : (
243
- <div className="empty-state" style={{ padding: 24 }}>
244
- <div className="empty-state-title">No approved extensions yet</div>
245
- <div className="empty-state-desc">Promoted frontier concepts will appear here once they pass semantic review.</div>
246
- </div>
259
+ <NextStepEmptyState
260
+ title="No approved extensions yet"
261
+ description="Approved extensions appear after frontier concepts pass semantic review. Promotion is what turns reviewed ontology into live semantic adoption."
262
+ command="helixevo ontology --review <conceptId> --decision promote"
263
+ pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
264
+ guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
265
+ />
247
266
  )}
248
267
  </div>
249
268
  </SectionFrame>
@@ -267,10 +286,13 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
267
286
  </div>
268
287
  </div>
269
288
  )) : (
270
- <div className="empty-state" style={{ padding: 24 }}>
271
- <div className="empty-state-title">No ontology changes logged yet</div>
272
- <div className="empty-state-desc">Refresh the frontier or review a concept to create the first native ontology events.</div>
273
- </div>
289
+ <NextStepEmptyState
290
+ title="No ontology changes logged yet"
291
+ description="Refresh the frontier or review a concept to create the first native ontology events and start a visible semantic history instead of hidden drift."
292
+ command="helixevo ontology --refresh"
293
+ pageLink={{ label: 'Open Topology', href: '/topology', tone: 'yellow' }}
294
+ guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
295
+ />
274
296
  )}
275
297
  </div>
276
298
  </SectionFrame>
@@ -1,9 +1,11 @@
1
1
  import OntologyClient from './client'
2
2
  import { loadOntologyControlSummary } from '@/lib/data'
3
+ import { loadProofDashboardSummary } from '@/lib/proof'
3
4
 
4
5
  export const dynamic = 'force-dynamic'
5
6
 
6
7
  export default function OntologyPage() {
7
8
  const dashboard = loadOntologyControlSummary()
8
- return <OntologyClient initialDashboard={dashboard} />
9
+ const proof = loadProofDashboardSummary()
10
+ return <OntologyClient initialDashboard={dashboard} proof={proof} />
9
11
  }
@@ -1,9 +1,13 @@
1
1
  import Link from 'next/link'
2
2
  import { getDashboardSummary, getOntologyDashboardSummary, loadCoEvolutionSummary, loadFailures, loadFrontier, loadGraph, loadHistory, listProjects } from '@/lib/data'
3
+ import { loadProofDashboardSummary } from '@/lib/proof'
3
4
  import { OverviewActions } from '@/components/overview-actions'
4
5
  import { PageHero } from '@/components/page-hero'
5
6
  import { MetricCard } from '@/components/metric-card'
6
7
  import { SectionFrame } from '@/components/section-frame'
8
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
9
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
10
+ import { CURRENT_RELEASE_SPOTLIGHT } from '@/lib/release-spotlight'
7
11
 
8
12
  export const dynamic = 'force-dynamic'
9
13
 
@@ -17,6 +21,7 @@ export default function Overview() {
17
21
  const summary = getDashboardSummary()
18
22
  const ontology = getOntologyDashboardSummary()
19
23
  const coevolution = loadCoEvolutionSummary()
24
+ const proof = loadProofDashboardSummary()
20
25
  const frontier = loadFrontier()
21
26
  const history = loadHistory()
22
27
  const graph = loadGraph()
@@ -39,6 +44,7 @@ export default function Overview() {
39
44
  { label: `${coevolution.pressureMotifs.promotionReady} promotion-ready motifs`, tone: coevolution.pressureMotifs.promotionReady > 0 ? 'purple' : 'neutral' },
40
45
  { label: `${coevolution.topologyReviews.open} topology reviews`, tone: coevolution.topologyReviews.open > 0 ? 'yellow' : 'green' },
41
46
  { label: `${coevolution.topologyExecution.prepared} prepared structural plans`, tone: coevolution.topologyExecution.prepared > 0 ? 'blue' : 'neutral' },
47
+ { label: `${proof.summary.reviewOpen} proof reviews`, tone: proof.summary.reviewOpen > 0 ? 'yellow' : proof.summary.effective > 0 ? 'green' : 'neutral' },
42
48
  { label: `mode: ${coevolution.governance.activeMode.replace(/-/g, ' ')}`, tone: coevolution.governance.activeMode === 'transfer-focused' ? 'purple' : coevolution.governance.activeMode === 'project-critical' ? 'yellow' : 'blue' },
43
49
  ]}
44
50
  actions={
@@ -57,14 +63,40 @@ export default function Overview() {
57
63
  }
58
64
  />
59
65
 
66
+ <OperatorLoopTrail surface="overview" />
67
+
60
68
  <div className="grid-5">
61
69
  <MetricCard label="Total skills" value={summary.skills.total} sublabel={`${summary.skills.evolved} evolved • ${summary.skillTests} skill tests`} tone="purple" href="/network" icon="◆" />
62
70
  <MetricCard label="Accepted proposals" value={summary.evolution.accepted} sublabel={`${summary.evolution.rejected} rejected`} tone="green" href="/evolution" icon="✓" />
63
71
  <MetricCard label="Unresolved corrections" value={summary.failures.unresolved} sublabel={`out of ${summary.failures.total} captured failures`} tone={summary.failures.unresolved > 0 ? 'yellow' : 'green'} href={summary.failures.unresolved > 0 ? '#attention' : '/evolution'} icon="!" />
64
72
  <MetricCard label="Discoveries" value={summary.buffer.discoveries} sublabel={`${summary.buffer.drafts} drafts in progress`} tone="blue" href="/research" icon="◎" />
65
73
  <MetricCard label="Frontier candidates" value={frontier.programs.length} sublabel={`${summary.canaries} active canaries`} tone="neutral" href="/frontier" icon="▲" />
74
+ <MetricCard label="Proof review" 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'} href="/proof" icon="◇" />
66
75
  </div>
67
76
 
77
+ <SectionFrame
78
+ eyebrow={`Release spotlight · v${CURRENT_RELEASE_SPOTLIGHT.version}`}
79
+ title={CURRENT_RELEASE_SPOTLIGHT.title}
80
+ description={CURRENT_RELEASE_SPOTLIGHT.summary}
81
+ tone="blue"
82
+ >
83
+ <div className="grid-2" style={{ gap: 16 }}>
84
+ <div style={{ display: 'grid', gap: 10 }}>
85
+ {CURRENT_RELEASE_SPOTLIGHT.bullets.map((item) => (
86
+ <div key={item} className="signal-text">• {item}</div>
87
+ ))}
88
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 4 }}>
89
+ {CURRENT_RELEASE_SPOTLIGHT.nextActions.map((action) => (
90
+ <Link key={action.href} href={action.href} className={`hero-chip hero-chip-${action.tone}`} style={{ textDecoration: 'none' }}>
91
+ {action.label}
92
+ </Link>
93
+ ))}
94
+ </div>
95
+ </div>
96
+ <SurfaceJumpLinks surface="overview" variant="panel" title="Jump into the updated loop" />
97
+ </div>
98
+ </SectionFrame>
99
+
68
100
  <SectionFrame
69
101
  eyebrow="Execution layer"
70
102
  title="Quick actions"
@@ -187,8 +219,10 @@ export default function Overview() {
187
219
  <span className="badge badge-gray">deprecation risk → {ontology.ontologyLoop.adoption.conceptsAtDeprecationRisk} concepts • {ontology.ontologyLoop.adoption.unusedExtensions} unused extensions</span>
188
220
  <span className="badge badge-gray">topology → {ontology.topologyReviews.open} open • {ontology.topologyReviews.accepted} accepted • {ontology.topologyReviews.generatedFromManualReview} manual-route</span>
189
221
  <span className="badge badge-gray">execution → {ontology.topologyExecution.prepared} prepared • {ontology.topologyExecution.applied} applied • {ontology.topologyExecution.rolledBack} rolled back</span>
222
+ <span className="badge badge-gray">proof → {proof.summary.total} total • {proof.summary.effective} effective • {proof.summary.reviewOpen} open review</span>
190
223
  <Link href="/ontology" className="badge badge-blue" style={{ textDecoration: 'none' }}>Open ontology control</Link>
191
224
  <Link href="/topology" className="badge badge-blue" style={{ textDecoration: 'none' }}>Open topology control</Link>
225
+ <Link href="/proof" className="badge badge-blue" style={{ textDecoration: 'none' }}>Open proof control</Link>
192
226
  <span className="badge badge-gray">governance: {ontology.governance.activeMode.replace(/-/g, ' ')} ({ontology.governance.source})</span>
193
227
  <span className="badge badge-gray">routes → research {ontology.governedRoutes.research} • specialize {ontology.governedRoutes.specialize} • evolve {ontology.governedRoutes.evolve} • generalize {ontology.governedRoutes.generalize} • manual-review {ontology.governedRoutes['manual-review']}</span>
194
228
  <span className="badge badge-gray">{ontology.enrichedSkillNodes} skills carry explicit brain metadata</span>
@@ -6,6 +6,9 @@ import { ConsolePanel } from '@/components/console-panel'
6
6
  import { MetricCard } from '@/components/metric-card'
7
7
  import { PageHero } from '@/components/page-hero'
8
8
  import { SectionFrame } from '@/components/section-frame'
9
+ import { OperatorLoopTrail } from '@/components/operator-loop-trail'
10
+ import { SurfaceJumpLinks } from '@/components/surface-jump-links'
11
+ import { NextStepEmptyState } from '@/components/next-step-empty-state'
9
12
  import type { ProjectProfile } from '@/lib/data'
10
13
 
11
14
  type SetupState = 'idle' | 'analyzing' | 'done' | 'error' | 'cancelled'
@@ -364,18 +367,13 @@ export default function ProjectsClient({ profiles, skillCount, projectAnalysisTr
364
367
  <div className="hero-note-title">Analyze → Match → Gap scan → Action</div>
365
368
  <div className="hero-note-copy">Run a profile, review the skill fit, then send uncovered needs into Research or the Skill Network.</div>
366
369
  </div>
367
- <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
368
- <Link href="/network" style={buttonStyle('purple')}>
369
- Open Skill Network
370
- </Link>
371
- <Link href="/research" style={buttonStyle('blue')}>
372
- Open Research
373
- </Link>
374
- </div>
370
+ <SurfaceJumpLinks surface="projects" variant="compact" title="Observation handoffs" />
375
371
  </div>
376
372
  }
377
373
  />
378
374
 
375
+ <OperatorLoopTrail surface="projects" />
376
+
379
377
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16, marginBottom: 24 }}>
380
378
  <MetricCard
381
379
  label="Portfolio"
@@ -764,17 +762,13 @@ export default function ProjectsClient({ profiles, skillCount, projectAnalysisTr
764
762
  tone="yellow"
765
763
  >
766
764
  {profiles.length === 0 ? (
767
- <div className="empty-state">
768
- <div className="empty-state-icon">
769
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
770
- <path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
771
- </svg>
772
- </div>
773
- <div className="empty-state-title">No analyzed projects yet</div>
774
- <div className="empty-state-desc">
775
- Start with a local folder or GitHub repository. The resulting profile will show matched skills, uncovered gaps, and recommended next steps.
776
- </div>
777
- </div>
765
+ <NextStepEmptyState
766
+ title="No analyzed projects yet"
767
+ description={`Start with a local folder or GitHub repository. The resulting profile will show matched skills, uncovered gaps, activation traces, and the next routed action against your ${skillCount} current skills.`}
768
+ command="helixevo project-setup <path>"
769
+ pageLink={{ label: 'Open Research', href: '/research', tone: 'blue' }}
770
+ guideLink={{ label: 'Guide · Quick Start', anchor: 'quickstart', tone: 'purple' }}
771
+ />
778
772
  ) : (
779
773
  <div style={{ display: 'grid', gap: 18 }}>
780
774
  {profiles.map(profile => {
@@ -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
+ }