helixevo 0.4.0 → 0.5.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.
@@ -0,0 +1,247 @@
1
+ 'use client'
2
+
3
+ import Link from 'next/link'
4
+ import { useState } from 'react'
5
+ import { ConsolePanel } from '@/components/console-panel'
6
+ import { MetricCard } from '@/components/metric-card'
7
+ import { PageHero } from '@/components/page-hero'
8
+ import { SectionFrame } from '@/components/section-frame'
9
+ import type { OntologyControlDashboardSummary, OntologyReviewDecisionStatus } from '@/lib/data'
10
+
11
+ type RunState = 'idle' | 'running' | 'success' | 'error'
12
+
13
+ function consoleTone(state: RunState): 'neutral' | 'green' | 'red' | 'yellow' {
14
+ if (state === 'success') return 'green'
15
+ if (state === 'error') return 'red'
16
+ return 'neutral'
17
+ }
18
+
19
+ function toneForConcept(kind: string): 'blue' | 'green' | 'purple' | 'yellow' | 'neutral' {
20
+ if (kind === 'capability') return 'blue'
21
+ if (kind === 'pressure-type') return 'yellow'
22
+ if (kind === 'topology-motif') return 'purple'
23
+ return 'neutral'
24
+ }
25
+
26
+ function formatDate(value: string | undefined) {
27
+ if (!value) return '—'
28
+ return new Date(value).toLocaleString()
29
+ }
30
+
31
+ function formatMode(value: string) {
32
+ return value.replace(/-/g, ' ')
33
+ }
34
+
35
+ export default function OntologyClient({ initialDashboard }: { initialDashboard: OntologyControlDashboardSummary }) {
36
+ const [dashboard, setDashboard] = useState(initialDashboard)
37
+ const [runState, setRunState] = useState<RunState>('idle')
38
+ const [output, setOutput] = useState('')
39
+ const [pendingKey, setPendingKey] = useState<string | null>(null)
40
+
41
+ const runAction = async (action: 'refresh' | 'review' | 'deprecate', payload: { conceptId?: string; decision?: OntologyReviewDecisionStatus; rationale?: string }, label: string) => {
42
+ setPendingKey(payload.conceptId ?? action)
43
+ setRunState('running')
44
+ setOutput('')
45
+ try {
46
+ const res = await fetch('/api/ontology', {
47
+ method: 'POST',
48
+ headers: { 'Content-Type': 'application/json' },
49
+ body: JSON.stringify({ action, ...payload }),
50
+ })
51
+ const data = await res.json()
52
+ if (!res.ok || !data.success) {
53
+ setRunState('error')
54
+ setOutput(data.error ?? `${label} failed`)
55
+ return
56
+ }
57
+ setDashboard(data.dashboard)
58
+ setRunState('success')
59
+ setOutput(data.output || `${label} completed`)
60
+ } catch (err: unknown) {
61
+ setRunState('error')
62
+ setOutput(err instanceof Error ? err.message : `${label} failed`)
63
+ } finally {
64
+ setPendingKey(null)
65
+ }
66
+ }
67
+
68
+ return (
69
+ <div style={{ display: 'grid', gap: 22 }}>
70
+ <PageHero
71
+ eyebrow="Semantic plasticity"
72
+ title="Ontology Frontier Control"
73
+ description="Inspect the stable kernel, review frontier concept hypotheses derived from recurring evidence, promote durable concepts into approved extensions, and keep semantic plasticity governed rather than free-form."
74
+ chips={[
75
+ { label: `${dashboard.summary.frontier} frontier`, tone: dashboard.summary.frontier > 0 ? 'yellow' : 'neutral' },
76
+ { label: `${dashboard.summary.reviewOpen} open review`, tone: dashboard.summary.reviewOpen > 0 ? 'yellow' : 'green' },
77
+ { label: `${dashboard.summary.extensions} approved extensions`, tone: dashboard.summary.extensions > 0 ? 'blue' : 'neutral' },
78
+ { label: `${dashboard.summary.changeEvents} change events`, tone: dashboard.summary.changeEvents > 0 ? 'purple' : 'neutral' },
79
+ { label: formatMode(dashboard.governance.activeMode), tone: dashboard.governance.activeMode === 'transfer-focused' ? 'purple' : dashboard.governance.activeMode === 'project-critical' ? 'yellow' : 'blue' },
80
+ ]}
81
+ actions={
82
+ <div style={{ display: 'grid', gap: 12 }}>
83
+ <div className="hero-note-card">
84
+ <div className="hero-note-label">Native ontology state</div>
85
+ <div className="hero-note-title">Kernel + frontier + extensions</div>
86
+ <div className="hero-note-copy">Milestone 8 keeps the semantic kernel stable while letting new concepts emerge into a reviewable frontier before promotion.</div>
87
+ </div>
88
+ <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
89
+ <button onClick={() => runAction('refresh', {}, 'ontology refresh')} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Refresh ontology frontier</button>
90
+ <Link href="/coevolution" className="badge badge-gray">Open co-evolution</Link>
91
+ <Link href="/topology" className="badge badge-gray">Open topology</Link>
92
+ </div>
93
+ </div>
94
+ }
95
+ />
96
+
97
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
98
+ <MetricCard label="Kernel concepts" value={dashboard.summary.kernelConcepts} sublabel={`${dashboard.kernel.relationFamilies.length} relation families`} tone="purple" icon="◎" />
99
+ <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="◇" />
100
+ <MetricCard label="Approved extensions" value={dashboard.summary.extensions} sublabel={`${dashboard.summary.deprecated} deprecated`} tone={dashboard.summary.extensions > 0 ? 'blue' : 'neutral'} icon="↑" />
101
+ <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="⇄" />
102
+ </div>
103
+
104
+ <SectionFrame
105
+ eyebrow="Kernel"
106
+ title="Stable semantic anchor"
107
+ description="The kernel remains the constitutional layer. Milestone 8 does not mutate it directly; it materializes and exposes it while adding governed extension growth around it."
108
+ >
109
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
110
+ <span className="badge badge-gray">version {dashboard.kernel.version}</span>
111
+ <span className="badge badge-gray">{dashboard.kernel.entityNames.length} kernel entities</span>
112
+ <span className="badge badge-gray">{dashboard.kernel.mutationOperations.length} mutation operations</span>
113
+ <span className="badge badge-gray">{dashboard.kernel.invariantIds.length} invariants</span>
114
+ </div>
115
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 12, marginTop: 16 }}>
116
+ <div className="guide-dimension-card" style={{ borderLeftColor: 'var(--blue)' }}>
117
+ <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--blue)' }}>Kernel pillars</div>
118
+ <div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 8, lineHeight: 1.6 }}>{dashboard.kernel.pillars.join(' • ')}</div>
119
+ </div>
120
+ <div className="guide-dimension-card" style={{ borderLeftColor: 'var(--green)' }}>
121
+ <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--green)' }}>Allowed layers</div>
122
+ <div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 8, lineHeight: 1.6 }}>{dashboard.kernel.layers.join(' • ')}</div>
123
+ </div>
124
+ </div>
125
+ </SectionFrame>
126
+
127
+ <SectionFrame
128
+ eyebrow="Frontier"
129
+ title="Reviewable concept hypotheses"
130
+ description="These concepts remain provisional until reviewed. Promotion materializes an approved extension; reject and defer preserve semantic memory without silent drift."
131
+ >
132
+ <div style={{ display: 'grid', gap: 12 }}>
133
+ {dashboard.frontier.length > 0 ? dashboard.frontier.map((concept) => (
134
+ <div key={concept.id} style={{ padding: '16px 18px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.74)' }}>
135
+ <div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' }}>
136
+ <div style={{ display: 'grid', gap: 4, flex: 1 }}>
137
+ <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)' }}>{concept.name}</div>
138
+ <div style={{ fontSize: 12, color: 'var(--text-dim)', lineHeight: 1.6 }}>{concept.description ?? concept.sourceSummary ?? 'Provisional ontology hypothesis.'}</div>
139
+ </div>
140
+ <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
141
+ <span className={`badge badge-${toneForConcept(concept.conceptKind)}`}>{concept.conceptKind}</span>
142
+ <span className="badge badge-gray">{concept.reviewStatus}</span>
143
+ <span className="badge badge-gray">{concept.observationCount ?? 0} obs</span>
144
+ <span className="badge badge-gray">{((concept.confidence ?? 0) * 100).toFixed(0)}% confidence</span>
145
+ </div>
146
+ </div>
147
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 12 }}>
148
+ <span className="badge badge-gray">{(concept.projectIds?.length ?? 0)} projects</span>
149
+ <span className="badge badge-gray">{(concept.evidenceIds?.length ?? 0)} evidence ids</span>
150
+ <span className="badge badge-gray">last seen {formatDate(concept.lastObservedAt)}</span>
151
+ </div>
152
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 14 }}>
153
+ <button onClick={() => runAction('review', { conceptId: concept.id, decision: 'promote', rationale: `Promote ${concept.name} into approved ontology extension.` }, `promote ${concept.name}`)} disabled={pendingKey === concept.id} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Promote</button>
154
+ <button onClick={() => runAction('review', { conceptId: concept.id, decision: 'defer', rationale: `Defer ${concept.name} for more evidence.` }, `defer ${concept.name}`)} disabled={pendingKey === concept.id} className="badge badge-purple" style={{ border: 'none', cursor: 'pointer' }}>Defer</button>
155
+ <button onClick={() => runAction('review', { conceptId: concept.id, decision: 'reject', rationale: `Reject ${concept.name} as a weak or overlapping frontier concept.` }, `reject ${concept.name}`)} disabled={pendingKey === concept.id} className="badge badge-gray" style={{ border: 'none', cursor: 'pointer' }}>Reject</button>
156
+ </div>
157
+ </div>
158
+ )) : (
159
+ <div className="empty-state" style={{ padding: 24 }}>
160
+ <div className="empty-state-title">No ontology frontier concepts yet</div>
161
+ <div className="empty-state-desc">Run “Refresh ontology frontier” after pressure motifs, project gaps, or topology review patterns accumulate.</div>
162
+ </div>
163
+ )}
164
+ </div>
165
+ </SectionFrame>
166
+
167
+ <SectionFrame
168
+ eyebrow="Extensions"
169
+ title="Approved ontology extensions"
170
+ description="Promoted concepts live here as approved semantic vocabulary. Deprecation is bounded and explicit — there is no hidden semantic drift."
171
+ >
172
+ <div style={{ display: 'grid', gap: 12 }}>
173
+ {dashboard.extensions.length > 0 ? dashboard.extensions.map((concept) => (
174
+ <div key={concept.id} style={{ padding: '16px 18px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.74)' }}>
175
+ <div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' }}>
176
+ <div style={{ display: 'grid', gap: 4, flex: 1 }}>
177
+ <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--text)' }}>{concept.name}</div>
178
+ <div style={{ fontSize: 12, color: 'var(--text-dim)', lineHeight: 1.6 }}>{concept.description ?? concept.sourceSummary ?? 'Approved ontology extension.'}</div>
179
+ </div>
180
+ <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
181
+ <span className={`badge badge-${toneForConcept(concept.conceptKind)}`}>{concept.conceptKind}</span>
182
+ <span className="badge badge-gray">{concept.status}</span>
183
+ <span className="badge badge-gray">{(concept.evidenceIds?.length ?? 0)} evidence ids</span>
184
+ </div>
185
+ </div>
186
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 12 }}>
187
+ <span className="badge badge-gray">{(concept.projectIds?.length ?? 0)} projects</span>
188
+ <span className="badge badge-gray">created {formatDate(concept.createdAt)}</span>
189
+ {concept.status !== 'deprecated' ? (
190
+ <button onClick={() => runAction('deprecate', { conceptId: concept.id, rationale: `Deprecate ontology extension ${concept.name} after operator review.` }, `deprecate ${concept.name}`)} disabled={pendingKey === concept.id} className="badge badge-gray" style={{ border: 'none', cursor: 'pointer' }}>Deprecate</button>
191
+ ) : null}
192
+ </div>
193
+ </div>
194
+ )) : (
195
+ <div className="empty-state" style={{ padding: 24 }}>
196
+ <div className="empty-state-title">No approved extensions yet</div>
197
+ <div className="empty-state-desc">Promoted frontier concepts will appear here once they pass semantic review.</div>
198
+ </div>
199
+ )}
200
+ </div>
201
+ </SectionFrame>
202
+
203
+ <SectionFrame
204
+ eyebrow="Change log"
205
+ title="Recent semantic transitions"
206
+ description="Every meaningful ontology action should leave behind a visible change trail instead of becoming invisible semantic drift."
207
+ >
208
+ <div style={{ display: 'grid', gap: 10 }}>
209
+ {dashboard.recentChanges.length > 0 ? dashboard.recentChanges.map((event) => (
210
+ <div key={event.id} style={{ padding: '14px 16px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.72)' }}>
211
+ <div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
212
+ <div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{event.changeType}</div>
213
+ <span className="badge badge-gray">{formatDate(event.timestamp)}</span>
214
+ </div>
215
+ <div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.6 }}>{event.reason}</div>
216
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 10 }}>
217
+ <span className="badge badge-gray">{event.conceptIds.join(', ')}</span>
218
+ <span className="badge badge-gray">{(event.evidenceIds?.length ?? 0)} evidence ids</span>
219
+ </div>
220
+ </div>
221
+ )) : (
222
+ <div className="empty-state" style={{ padding: 24 }}>
223
+ <div className="empty-state-title">No ontology changes logged yet</div>
224
+ <div className="empty-state-desc">Refresh the frontier or review a concept to create the first native ontology events.</div>
225
+ </div>
226
+ )}
227
+ </div>
228
+ </SectionFrame>
229
+
230
+ <ConsolePanel
231
+ title="Ontology console"
232
+ tone={consoleTone(runState)}
233
+ actions={<span className="badge badge-gray">{runState === 'running' ? 'running' : runState === 'success' ? 'success' : runState === 'error' ? 'error' : 'idle'}</span>}
234
+ >
235
+ <pre style={{ margin: 0, whiteSpace: 'pre-wrap', fontSize: 12, lineHeight: 1.7, color: 'var(--text-dim)' }}>
236
+ {runState === 'running'
237
+ ? 'Running ontology control…\n\n' + (output || '')
238
+ : runState === 'success'
239
+ ? (output || 'Ontology action completed.')
240
+ : runState === 'error'
241
+ ? (output || 'Ontology action failed.')
242
+ : 'Refresh the frontier or review concepts to inspect semantic changes.'}
243
+ </pre>
244
+ </ConsolePanel>
245
+ </div>
246
+ )
247
+ }
@@ -0,0 +1,9 @@
1
+ import OntologyClient from './client'
2
+ import { loadOntologyControlSummary } from '@/lib/data'
3
+
4
+ export const dynamic = 'force-dynamic'
5
+
6
+ export default function OntologyPage() {
7
+ const dashboard = loadOntologyControlSummary()
8
+ return <OntologyClient initialDashboard={dashboard} />
9
+ }
@@ -83,8 +83,8 @@ export default function Overview() {
83
83
  <SectionFrame
84
84
  eyebrow="Brain foundation"
85
85
  title="Semantic backbone"
86
- description="A compatibility-era view of the living brain, derived from the current skill graph, evolution history, and captured failures while native ontology events are being wired in."
87
- actions={<span className="badge badge-gray">{ontology.source === 'graph' ? `Ontology ${ontology.specVersion}` : 'Compatibility-derived'}</span>}
86
+ description="A hybrid ontology view of the living brain, combining derived skill-graph semantics with native ontology frontier, extension, and semantic review activity."
87
+ actions={<span className="badge badge-gray">{ontology.source === 'hybrid-native-derived' ? `Ontology ${ontology.specVersion} · hybrid native + derived` : ontology.source === 'graph' ? `Ontology ${ontology.specVersion}` : 'Compatibility-derived'}</span>}
88
88
  >
89
89
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
90
90
  <MetricCard
@@ -143,6 +143,14 @@ export default function Overview() {
143
143
  href="/topology"
144
144
  icon="⇄"
145
145
  />
146
+ <MetricCard
147
+ label="Ontology frontier"
148
+ value={ontology.ontologyLoop.frontier}
149
+ sublabel={`${ontology.ontologyLoop.reviewOpen} open • ${ontology.ontologyLoop.extensions} approved extensions`}
150
+ tone={ontology.ontologyLoop.reviewOpen > 0 ? 'yellow' : ontology.ontologyLoop.extensions > 0 ? 'blue' : 'neutral'}
151
+ href="/ontology"
152
+ icon="◎"
153
+ />
146
154
  <MetricCard
147
155
  label="Observed mutation verbs"
148
156
  value={ontology.mutationOperationsObserved}
@@ -166,8 +174,10 @@ export default function Overview() {
166
174
  <span className="badge badge-gray">{coevolution.crossProjectGapAreas.length} cross-project gap motifs</span>
167
175
  <span className="badge badge-gray">{ontology.pressureMotifs.promotionReady} motifs currently recommend generalize</span>
168
176
  <span className="badge badge-gray">{ontology.transferEvents.total} transfer events logged ({ontology.transferEvents.realized} realized)</span>
177
+ <span className="badge badge-gray">ontology → {ontology.ontologyLoop.frontier} frontier • {ontology.ontologyLoop.extensions} extensions • {ontology.ontologyLoop.changeEvents} changes</span>
169
178
  <span className="badge badge-gray">topology → {ontology.topologyReviews.open} open • {ontology.topologyReviews.accepted} accepted • {ontology.topologyReviews.generatedFromManualReview} manual-route</span>
170
179
  <span className="badge badge-gray">execution → {ontology.topologyExecution.prepared} prepared • {ontology.topologyExecution.applied} applied • {ontology.topologyExecution.rolledBack} rolled back</span>
180
+ <Link href="/ontology" className="badge badge-blue" style={{ textDecoration: 'none' }}>Open ontology control</Link>
171
181
  <Link href="/topology" className="badge badge-blue" style={{ textDecoration: 'none' }}>Open topology control</Link>
172
182
  <span className="badge badge-gray">governance: {ontology.governance.activeMode.replace(/-/g, ' ')} ({ontology.governance.source})</span>
173
183
  <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>
@@ -253,6 +253,7 @@ export default function TopologyClient({
253
253
  </div>
254
254
  <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
255
255
  <button onClick={handleOptimize} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Run graph optimize</button>
256
+ <Link href="/ontology" className="badge badge-gray">Open ontology</Link>
256
257
  <Link href="/coevolution" className="badge badge-gray">Open co-evolution</Link>
257
258
  <Link href="/network" className="badge badge-gray">Open network</Link>
258
259
  </div>
@@ -12,6 +12,7 @@ interface NavItem {
12
12
  const WORKSPACE_NAV: NavItem[] = [
13
13
  { href: '/', label: 'Overview', icon: 'M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-4 0a1 1 0 01-1-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 01-1 1' },
14
14
  { href: '/network', label: 'Skill Network', icon: 'M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1' },
15
+ { href: '/ontology', label: 'Ontology', icon: 'M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3zm0 4.2l-4 2.25v4.95l4 2.25 4-2.25V9.45L12 7.2zm0 0V21' },
15
16
  { href: '/topology', label: 'Topology', icon: 'M4 7h6m4 0h6M7 4v6m10-6v6M5 17h14M12 10v10' },
16
17
  { 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
18
  { href: '/evolution', label: 'Evolution', icon: 'M13 7h8m0 0v8m0-8l-8 8-4-4-6 6' },