helixevo 0.2.40 → 0.3.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.
@@ -1,5 +1,5 @@
1
1
  import Link from 'next/link'
2
- import { getDashboardSummary, loadFailures, loadFrontier, loadGraph, loadHistory, listProjects } from '@/lib/data'
2
+ import { getDashboardSummary, getOntologyDashboardSummary, loadCoEvolutionSummary, loadFailures, loadFrontier, loadGraph, loadHistory, listProjects } from '@/lib/data'
3
3
  import { OverviewActions } from '@/components/overview-actions'
4
4
  import { PageHero } from '@/components/page-hero'
5
5
  import { MetricCard } from '@/components/metric-card'
@@ -15,6 +15,8 @@ function scoreColor(score: number) {
15
15
 
16
16
  export default function Overview() {
17
17
  const summary = getDashboardSummary()
18
+ const ontology = getOntologyDashboardSummary()
19
+ const coevolution = loadCoEvolutionSummary()
18
20
  const frontier = loadFrontier()
19
21
  const history = loadHistory()
20
22
  const graph = loadGraph()
@@ -74,6 +76,60 @@ export default function Overview() {
74
76
  />
75
77
  </SectionFrame>
76
78
 
79
+ <SectionFrame
80
+ eyebrow="Brain foundation"
81
+ title="Semantic backbone"
82
+ 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."
83
+ actions={<span className="badge badge-gray">{ontology.source === 'graph' ? `Ontology ${ontology.specVersion}` : 'Compatibility-derived'}</span>}
84
+ >
85
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
86
+ <MetricCard
87
+ label="Generalist skills"
88
+ value={ontology.skillRoles.generalist}
89
+ sublabel={`${ontology.stabilityStates.stable} stable abstractions`}
90
+ tone="purple"
91
+ href="/network"
92
+ icon="◎"
93
+ />
94
+ <MetricCard
95
+ label="Project specialists"
96
+ value={ontology.skillRoles.specialist}
97
+ sublabel={`${ontology.plasticityStates.candidate} candidate rewires`}
98
+ tone="blue"
99
+ href="/projects"
100
+ icon="◉"
101
+ />
102
+ <MetricCard
103
+ label="Hybrid bridges"
104
+ value={ontology.skillRoles.hybrid}
105
+ sublabel={`${ontology.plasticityStates.volatile} volatile transitions`}
106
+ tone="green"
107
+ href="/network"
108
+ icon="⇄"
109
+ />
110
+ <MetricCard
111
+ label="Observed mutation verbs"
112
+ value={ontology.mutationOperationsObserved}
113
+ sublabel={ontology.observedMutationActions.length > 0 ? ontology.observedMutationActions.join(' • ') : 'Waiting for evolution history'}
114
+ tone="yellow"
115
+ href="/evolution"
116
+ icon="◇"
117
+ />
118
+ </div>
119
+
120
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 16 }}>
121
+ <span className="badge badge-gray">{ontology.relationFamiliesObserved} relation families live in the graph</span>
122
+ <span className="badge badge-gray">{ontology.evidenceBackedProposals} proposals already carry judge + regression evidence</span>
123
+ <span className="badge badge-gray">{ontology.artifacts.total} evolution artifacts ({ontology.artifacts.native} native • {ontology.artifacts.derived} derived)</span>
124
+ <span className="badge badge-gray">{ontology.activationTraces.total} activation traces ({ontology.activationTraces.native} native • {ontology.activationTraces.derived} derived)</span>
125
+ <span className="badge badge-gray">{ontology.pressureSignals.total} pressure signals ({ontology.pressureSignals.native} native • {ontology.pressureSignals.derived} derived)</span>
126
+ <span className="badge badge-gray">{coevolution.topProjects.length} pressured project hotspots</span>
127
+ <span className="badge badge-gray">{coevolution.crossProjectGapAreas.length} cross-project gap motifs</span>
128
+ <span className="badge badge-gray">{ontology.enrichedSkillNodes} skills carry explicit brain metadata</span>
129
+ <span className="badge badge-gray">{ontology.annotatedFailures.pressureSignals} failures annotated with pressure signals</span>
130
+ </div>
131
+ </SectionFrame>
132
+
77
133
  {unresolved.length > 0 ? (
78
134
  <SectionFrame
79
135
  eyebrow="Attention"
@@ -119,7 +119,7 @@ function formatDate(value: string) {
119
119
  return new Date(value).toLocaleDateString()
120
120
  }
121
121
 
122
- export default function ProjectsClient({ profiles, skillCount }: { profiles: ProjectProfile[]; skillCount: number }) {
122
+ export default function ProjectsClient({ profiles, skillCount, projectAnalysisTraces, pressureByProject }: { profiles: ProjectProfile[]; skillCount: number; projectAnalysisTraces: number; pressureByProject: Record<string, { projectId: string; totalSignals: number; nativeSignals: number; derivedSignals: number; highPrioritySignals: number; topCapabilities: string[] }> }) {
123
123
  const [inputMode, setInputMode] = useState<InputMode>('local')
124
124
  const [projectPath, setProjectPath] = useState('')
125
125
  const [githubUrl, setGithubUrl] = useState('')
@@ -338,7 +338,7 @@ export default function ProjectsClient({ profiles, skillCount }: { profiles: Pro
338
338
  }
339
339
  />
340
340
 
341
- <div className="grid-4" style={{ marginBottom: 24 }}>
341
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16, marginBottom: 24 }}>
342
342
  <MetricCard
343
343
  label="Portfolio"
344
344
  value={profiles.length}
@@ -351,6 +351,18 @@ export default function ProjectsClient({ profiles, skillCount }: { profiles: Pro
351
351
  sublabel={`Average matched-skill coverage across ${profiles.length || 1} project${profiles.length === 1 ? '' : 's'}`}
352
352
  tone="purple"
353
353
  />
354
+ <MetricCard
355
+ label="Project-analysis traces"
356
+ value={projectAnalysisTraces}
357
+ sublabel="Native activation snapshots captured from successful project analysis runs"
358
+ tone="green"
359
+ />
360
+ <MetricCard
361
+ label="Project pressure hotspots"
362
+ value={Object.keys(pressureByProject).length}
363
+ sublabel="Projects currently carrying persisted or compatibility-derived pressure signals"
364
+ tone="blue"
365
+ />
354
366
  <MetricCard
355
367
  label="High-priority gaps"
356
368
  value={aggregate.totalHighGaps}
@@ -724,6 +736,7 @@ export default function ProjectsClient({ profiles, skillCount }: { profiles: Pro
724
736
  {profiles.map(profile => {
725
737
  const highGaps = profile.gaps.filter(gap => gap.priority === 'high')
726
738
  const matchedPct = skillCount > 0 ? Math.round((profile.matchedSkills.length / skillCount) * 100) : 0
739
+ const projectPressure = pressureByProject[profile.name]
727
740
 
728
741
  return (
729
742
  <article key={profile.name} className="card" style={{ overflow: 'hidden' }}>
@@ -738,12 +751,18 @@ export default function ProjectsClient({ profiles, skillCount }: { profiles: Pro
738
751
  <span className={`hero-chip hero-chip-${profile.status === 'active' ? 'green' : 'blue'}`}>{profile.status}</span>
739
752
  <span className="hero-chip hero-chip-neutral">Analyzed {formatDate(profile.analyzedAt)}</span>
740
753
  <span className={`hero-chip hero-chip-${highGaps.length > 0 ? 'red' : 'green'}`}>{highGaps.length} high-priority gap{highGaps.length === 1 ? '' : 's'}</span>
754
+ {projectPressure ? (
755
+ <span className={`hero-chip hero-chip-${projectPressure.highPrioritySignals > 0 ? 'red' : 'blue'}`}>
756
+ {projectPressure.totalSignals} pressure signal{projectPressure.totalSignals === 1 ? '' : 's'}
757
+ </span>
758
+ ) : null}
741
759
  </div>
742
760
  <div style={{ fontSize: 24, fontWeight: 800, color: 'var(--text)', marginBottom: 8 }}>{profile.name}</div>
743
761
  <div style={{ fontSize: 13, color: 'var(--text-secondary)', lineHeight: 1.7, marginBottom: 12 }}>{profile.description}</div>
744
762
  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
745
763
  {profile.techStack.map(tech => <span key={tech} className="badge badge-gray">{tech}</span>)}
746
764
  {profile.domains.map(domain => <span key={domain} className="badge badge-blue">{domain}</span>)}
765
+ {projectPressure?.topCapabilities.map((capability) => <span key={`${profile.name}-${capability}`} className="badge badge-yellow">{capability}</span>)}
747
766
  </div>
748
767
  </div>
749
768
 
@@ -1,4 +1,4 @@
1
- import { loadAllProjectProfiles, loadGraph } from '@/lib/data'
1
+ import { loadActivationTraces, loadAllProjectProfiles, loadGraph, loadPressureSignals } from '@/lib/data'
2
2
  import ProjectsClient from './client'
3
3
 
4
4
  export const dynamic = 'force-dynamic'
@@ -6,7 +6,34 @@ export const dynamic = 'force-dynamic'
6
6
  export default function ProjectsPage() {
7
7
  const profiles = loadAllProjectProfiles()
8
8
  const graph = loadGraph()
9
+ const activationTraces = loadActivationTraces()
10
+ const pressureSignals = loadPressureSignals()
9
11
  const skillCount = graph.nodes.length
12
+ const projectAnalysisTraces = activationTraces.filter((trace) => trace.provenance === 'project-analysis').length
13
+ const pressureByProject = Object.fromEntries(
14
+ Object.entries(
15
+ pressureSignals.reduce<Record<string, { projectId: string; totalSignals: number; nativeSignals: number; derivedSignals: number; highPrioritySignals: number; topCapabilities: string[] }>>((acc, signal) => {
16
+ if (!signal.projectId) return acc
17
+ const existing = acc[signal.projectId] ?? {
18
+ projectId: signal.projectId,
19
+ totalSignals: 0,
20
+ nativeSignals: 0,
21
+ derivedSignals: 0,
22
+ highPrioritySignals: 0,
23
+ topCapabilities: [],
24
+ }
25
+ existing.totalSignals += 1
26
+ if (signal.provenance === 'failure-native' || signal.provenance === 'project-analysis-native') existing.nativeSignals += 1
27
+ else existing.derivedSignals += 1
28
+ if (signal.priority === 'high') existing.highPrioritySignals += 1
29
+ if (signal.capability && !existing.topCapabilities.includes(signal.capability) && existing.topCapabilities.length < 3) {
30
+ existing.topCapabilities.push(signal.capability)
31
+ }
32
+ acc[signal.projectId] = existing
33
+ return acc
34
+ }, {}),
35
+ ),
36
+ )
10
37
 
11
- return <ProjectsClient profiles={profiles} skillCount={skillCount} />
38
+ return <ProjectsClient profiles={profiles} skillCount={skillCount} projectAnalysisTraces={projectAnalysisTraces} pressureByProject={pressureByProject} />
12
39
  }
@@ -32,6 +32,12 @@ interface KnowledgeBuffer {
32
32
  interface Props {
33
33
  buffer: KnowledgeBuffer
34
34
  projects: string[]
35
+ coevolution: {
36
+ pressureSignals: { total: number; native: number; derived: number }
37
+ topProjects: { projectId: string; totalSignals: number; highPrioritySignals: number; topCapabilities: string[] }[]
38
+ crossProjectGapAreas: { area: string; projects: string[]; count: number }[]
39
+ activeRecommendations: { action: 'research' | 'specialize' | 'create'; count: number }[]
40
+ }
35
41
  }
36
42
 
37
43
  type RunState = 'idle' | 'running' | 'success' | 'error' | 'stopped'
@@ -78,7 +84,7 @@ function consoleTone(state: RunState): 'neutral' | 'green' | 'red' | 'yellow' {
78
84
  return 'neutral'
79
85
  }
80
86
 
81
- export default function ResearchClient({ buffer, projects }: Props) {
87
+ export default function ResearchClient({ buffer, projects, coevolution }: Props) {
82
88
  const [runState, setRunState] = useState<RunState>('idle')
83
89
  const [output, setOutput] = useState('')
84
90
  const abortRef = useRef<AbortController | null>(null)
@@ -178,6 +184,66 @@ export default function ResearchClient({ buffer, projects }: Props) {
178
184
  ]}
179
185
  />
180
186
 
187
+ <SectionFrame
188
+ eyebrow="Why research now"
189
+ title="Current pressure handoff"
190
+ description="Research becomes more valuable when recurring project pressure points to capability gaps that should generalize beyond one local context."
191
+ tone="blue"
192
+ >
193
+ <div className="grid-3">
194
+ <MetricCard
195
+ label="Pressure signals"
196
+ value={coevolution.pressureSignals.total}
197
+ sublabel={`${coevolution.pressureSignals.native} native • ${coevolution.pressureSignals.derived} derived`}
198
+ tone="blue"
199
+ icon="◎"
200
+ />
201
+ <MetricCard
202
+ label="Pressured projects"
203
+ value={coevolution.topProjects.length}
204
+ sublabel="Projects currently producing the strongest adaptation demand"
205
+ tone="purple"
206
+ icon="◉"
207
+ />
208
+ <MetricCard
209
+ label="Cross-project gap motifs"
210
+ value={coevolution.crossProjectGapAreas.length}
211
+ sublabel="Recurring capability gaps that research can help generalize"
212
+ tone="green"
213
+ icon="⇄"
214
+ />
215
+ </div>
216
+
217
+ <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.2fr) minmax(0, 1fr)', gap: 16, marginTop: 16 }}>
218
+ <div style={{ padding: '14px 16px', borderRadius: 18, background: 'rgba(255,255,255,0.7)', border: '1px solid var(--border)' }}>
219
+ <div className="section-label" style={{ marginBottom: 10 }}>Top gap motifs</div>
220
+ {coevolution.crossProjectGapAreas.length === 0 ? (
221
+ <div className="signal-text">Recurring cross-project gap motifs will appear here once the same capability pressure shows up across multiple projects.</div>
222
+ ) : (
223
+ <div style={{ display: 'grid', gap: 8 }}>
224
+ {coevolution.crossProjectGapAreas.slice(0, 4).map((entry) => (
225
+ <div key={entry.area} style={{ padding: '12px 14px', borderRadius: 16, background: 'rgba(97,93,86,0.06)', border: '1px solid var(--border)' }}>
226
+ <div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{entry.area}</div>
227
+ <div style={{ fontSize: 11.5, color: 'var(--text-dim)', marginTop: 4 }}>{entry.count} projects • {entry.projects.join(', ')}</div>
228
+ </div>
229
+ ))}
230
+ </div>
231
+ )}
232
+ </div>
233
+
234
+ <div style={{ padding: '14px 16px', borderRadius: 18, background: 'rgba(255,255,255,0.7)', border: '1px solid var(--border)' }}>
235
+ <div className="section-label" style={{ marginBottom: 10 }}>Recommended routing pressure</div>
236
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
237
+ {coevolution.activeRecommendations.length > 0 ? coevolution.activeRecommendations.map((entry) => (
238
+ <span key={entry.action} className={`hero-chip hero-chip-${entry.action === 'research' ? 'blue' : entry.action === 'specialize' ? 'green' : 'purple'}`}>
239
+ {entry.action} × {entry.count}
240
+ </span>
241
+ )) : <span className="badge badge-gray">No routed action pressure yet</span>}
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </SectionFrame>
246
+
181
247
  <SectionFrame
182
248
  eyebrow="Pipeline"
183
249
  title="How research works"
@@ -1,4 +1,4 @@
1
- import { loadBuffer, listProjects } from '@/lib/data'
1
+ import { loadBuffer, loadCoEvolutionSummary, listProjects } from '@/lib/data'
2
2
  import ResearchClient from './client'
3
3
 
4
4
  export const dynamic = 'force-dynamic'
@@ -6,6 +6,7 @@ export const dynamic = 'force-dynamic'
6
6
  export default function ResearchPage() {
7
7
  const buffer = loadBuffer()
8
8
  const projects = listProjects()
9
+ const coevolution = loadCoEvolutionSummary()
9
10
 
10
- return <ResearchClient buffer={buffer} projects={projects} />
11
+ return <ResearchClient buffer={buffer} projects={projects} coevolution={coevolution} />
11
12
  }