helixevo 0.8.1 → 0.9.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 CHANGED
@@ -4,6 +4,17 @@ All notable changes to HelixEvo are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.0] - 2026-03-25
8
+
9
+ ### Added
10
+ - Proof steering summaries with explicit evidence tiers — `trusted`, `caution`, `bounded`, and `candidate` — so proved outcomes can be surfaced as route-level and semantic-control influence instead of remaining only a descriptive ledger
11
+ - Candidate-vs-priority proof queue separation so dry-run and insufficient-evidence records stay visible without crowding higher-leverage review
12
+
13
+ ### Changed
14
+ - Pressure route recommendations now consume bounded proof steering after semantic influence, allowing weak evidence to stay bounded, cautionary evidence to bias toward review, and verified/effective evidence to strengthen trust modestly
15
+ - Overview, Proof, and Co-Evolution now expose prove-to-steer closure directly, including trusted/caution lane visibility and proof-aware route rationale
16
+ - `status`, `proof --status --verbose`, and the public README now describe Proof as a bounded steering input into the next governed loop rather than only a post-action review surface
17
+
7
18
  ## [0.8.1] - 2026-03-25
8
19
 
9
20
  ### Changed
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # HelixEvo
2
2
 
3
- Co-evolving skill and project brain for AI agents. HelixEvo captures failures, traces activations, models pressure, routes governed responses, promotes cross-project transfer, reviews structural topology changes, safely executes accepted topology transitions with rollback, lets approved ontology concepts become active semantic consumers inside the live control loop, and now exposes a first-class proof layer for bounded outcome attribution across the brain loop.
3
+ Co-evolving skill and project brain for AI agents. HelixEvo captures failures, traces activations, models pressure, routes governed responses, promotes cross-project transfer, reviews structural topology changes, safely executes accepted topology transitions with rollback, lets approved ontology concepts become active semantic consumers inside the live control loop, and now turns Proof into a bounded steering input for future control instead of a descriptive layer alone.
4
4
 
5
5
  ## How it works
6
6
 
@@ -87,7 +87,7 @@ helixevo dashboard
87
87
  |---------|-------------|
88
88
  | `helixevo watch` | Always-on learning: auto-capture + auto-evolve |
89
89
  | `helixevo metrics` | Correction rates, skill trends, evolution impact |
90
- | `helixevo proof` | Outcome attribution and proof review across interventions, transfer, topology, ontology, and evolution |
90
+ | `helixevo proof` | Outcome attribution, proof review, and steering summaries across interventions, transfer, topology, ontology, and evolution |
91
91
  | `helixevo health` | Network health: cohesion, coverage, balance, transfer |
92
92
  | `helixevo init` | Import existing skills + generate skill tests |
93
93
  | `helixevo capture <session>` | Extract failures from a session file |
@@ -199,10 +199,10 @@ helixevo dashboard --port 3900
199
199
  **Tabs:**
200
200
  - **Overview** — Premium control cockpit with frontier signals, brain foundation, provider-control truth, semantic backbone, ontology adoption visibility, proof review visibility, pressure counts, topology review visibility, and prepared/applied structural state
201
201
  - **Skill Network** — Interactive graph, premium inspector, co-evolution routing signals, and topology review/execution handoff links
202
- - **Co-Evolution** — Operator cockpit for routed pressure response, governance mode visibility, promotion queues, transfer evidence, semantic route influence, and topology handoff
202
+ - **Co-Evolution** — Operator cockpit for routed pressure response, governance mode visibility, promotion queues, transfer evidence, semantic route influence, proof-aware route rationale, and topology handoff
203
203
  - **Ontology** — Semantic control surface for kernel visibility, frontier concept review, approved ontology extensions, adoption coverage, deprecation risk, and native ontology change events
204
204
  - **Topology** — Governance steering plus a persistent operator pipeline for review → prepare → apply → rollback across merge / split / promote / rewire / consolidate candidates
205
- - **Proof** — Outcome-attribution and proof-review cockpit for bounded effectiveness review across interventions, transfer, topology execution, semantic adoption, and evolution impact
205
+ - **Proof** — Outcome-attribution, review, and proof-steering cockpit for bounded effectiveness across interventions, transfer, topology execution, semantic adoption, and evolution impact
206
206
  - **Projects** — Project intake studio, live project analysis, gap routing, per-project pressure hotspots, and promotion feeders
207
207
  - **Evolution** — Timeline of evolution runs with judge scores, artifact provenance, and activation-aware context
208
208
  - **Research** — Knowledge buffer plus a live “why research now” handoff from current pressure, governed routing, and recurring gaps
@@ -249,7 +249,7 @@ Failures → Cluster → Propose → Replay → Multi-Judge → Regression → C
249
249
  - **Governance steering** lets the operator pin or release the active adaptation mode rather than relying only on derived routing.
250
250
  - **Topology review** persists merge / split / promote / rewire / consolidate candidates so manual review is a real workflow.
251
251
  - **Reviewed topology execution** turns accepted safe candidates into prepared plans, snapshot-backed applies, and rollbackable structural transitions.
252
- - **Proof control** turns bounded outcome attribution into an explicit operator layer where interventions, transfer, topology execution, semantic adoption, and evolution impact can be verified, deferred, or contested.
252
+ - **Proof control** turns bounded outcome attribution into an explicit operator layer where interventions, transfer, topology execution, semantic adoption, and evolution impact can be verified, deferred, or contested, then fed back into future control through bounded proof steering.
253
253
  - **Evolution artifacts** preserve proposal-level evidence so the dashboard can show what changed, why, and with what provenance.
254
254
 
255
255
  **Three-layer hierarchy:**
@@ -78,6 +78,11 @@ type Summary = {
78
78
  reasons: string[]
79
79
  semanticInfluence?: 'none' | 'explanatory' | 'weighted'
80
80
  semanticConceptIds?: string[]
81
+ proofInfluence?: 'none' | 'explanatory' | 'weighted'
82
+ proofTier?: 'trusted' | 'caution' | 'bounded' | 'candidate'
83
+ proofSummary?: string
84
+ proofReasons?: string[]
85
+ proofLaneKeys?: string[]
81
86
  }
82
87
  semanticConceptIds?: string[]
83
88
  }[]
@@ -103,6 +108,11 @@ type Summary = {
103
108
  reasons: string[]
104
109
  semanticInfluence?: 'none' | 'explanatory' | 'weighted'
105
110
  semanticConceptIds?: string[]
111
+ proofInfluence?: 'none' | 'explanatory' | 'weighted'
112
+ proofTier?: 'trusted' | 'caution' | 'bounded' | 'candidate'
113
+ proofSummary?: string
114
+ proofReasons?: string[]
115
+ proofLaneKeys?: string[]
106
116
  }
107
117
  semanticConceptIds?: string[]
108
118
  }[]
@@ -153,6 +163,14 @@ function toneForRoute(route: PressureInterventionType) {
153
163
  return 'gray'
154
164
  }
155
165
 
166
+ function toneForProofTier(tier: 'trusted' | 'caution' | 'bounded' | 'candidate' | undefined) {
167
+ if (tier === 'trusted') return 'green'
168
+ if (tier === 'caution') return 'yellow'
169
+ if (tier === 'bounded') return 'blue'
170
+ if (tier === 'candidate') return 'gray'
171
+ return 'gray'
172
+ }
173
+
156
174
  function toneForMode(mode: Summary['governance']['activeMode']): 'blue' | 'green' | 'purple' | 'yellow' | 'neutral' {
157
175
  if (mode === 'transfer-focused') return 'purple'
158
176
  if (mode === 'project-critical') return 'yellow'
@@ -311,7 +329,7 @@ export default function CoEvolutionClient({ summary, ontology, proof }: Props) {
311
329
  <MetricCard label="Prepared topology" value={summary.topologyExecution.prepared} sublabel={`${summary.topologyExecution.applied} applied • ${summary.topologyExecution.rolledBack} rolled back`} tone={summary.topologyExecution.prepared > 0 ? 'blue' : summary.topologyExecution.applied > 0 ? 'green' : 'neutral'} icon="↑" />
312
330
  <MetricCard label="Active semantics" value={ontology.ontologyLoop.adoption.activeConcepts} sublabel={`${ontology.ontologyLoop.adoption.totalBindings} bindings • ${ontology.ontologyLoop.adoption.routesInfluenced} influenced routes`} tone={ontology.ontologyLoop.adoption.activeConcepts > 0 ? 'green' : 'neutral'} icon="◎" />
313
331
  <MetricCard label="Recorded interventions" value={summary.pressureInterventions.total} sublabel={`${summary.pressureInterventions.completed} completed • ${summary.pressureInterventions.dryRun} dry-run`} tone="blue" icon="↺" />
314
- <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'} icon="◇" />
332
+ <MetricCard label="Proof steering" value={proof.steering.priorityReview} sublabel={`${proof.steering.trustedLanes} trusted • ${proof.steering.cautionLanes} caution`} tone={proof.steering.cautionLanes > 0 ? 'yellow' : proof.steering.trustedLanes > 0 ? 'green' : proof.summary.reviewOpen > 0 ? 'blue' : 'neutral'} icon="◇" />
315
333
  <MetricCard label="Realized transfers" value={summary.recentTransfers.filter((event) => event.status === 'realized').length} sublabel={`${summary.pressureMotifs.addressed} motifs now addressed`} tone="green" icon="↑" />
316
334
  </div>
317
335
 
@@ -402,6 +420,7 @@ export default function CoEvolutionClient({ summary, ontology, proof }: Props) {
402
420
  <span className={`badge badge-${toneForLifecycle(motif.lifecycle)}`}>{motif.lifecycle}</span>
403
421
  <span className="badge badge-purple">recommend {motif.suggestedRoute.route}</span>
404
422
  <span className="badge badge-gray">confidence {(motif.suggestedRoute.confidence * 100).toFixed(0)}%</span>
423
+ {motif.suggestedRoute.proofTier ? <span className={`badge badge-${toneForProofTier(motif.suggestedRoute.proofTier)}`}>proof {motif.suggestedRoute.proofTier}</span> : null}
405
424
  {motif.suggestedRoute.semanticInfluence && motif.suggestedRoute.semanticInfluence !== 'none' ? <span className="badge badge-green">semantic {motif.suggestedRoute.semanticInfluence}</span> : null}
406
425
  {(motif.semanticConceptIds ?? []).slice(0, 2).map((conceptId) => <span key={`${motif.id}-${conceptId}`} className="badge badge-gray">{conceptId}</span>)}
407
426
  {motif.projectIds.slice(0, 3).map((projectId) => <span key={`${motif.id}-${projectId}`} className="badge badge-gray">{projectId}</span>)}
@@ -410,6 +429,7 @@ export default function CoEvolutionClient({ summary, ontology, proof }: Props) {
410
429
  {motif.suggestedRoute.reasons.slice(0, 2).map((reason, index) => (
411
430
  <div key={`${motif.id}-reason-${index}`} className="signal-text">• {reason}</div>
412
431
  ))}
432
+ {motif.suggestedRoute.proofSummary ? <div className="signal-text">→ {motif.suggestedRoute.proofSummary}</div> : null}
413
433
  </div>
414
434
  </div>
415
435
  </div>
@@ -551,6 +571,7 @@ export default function CoEvolutionClient({ summary, ontology, proof }: Props) {
551
571
  {signal.projectId ? <span className="badge badge-gray">{signal.projectId}</span> : null}
552
572
  {signal.routeRecommendation ? <span className={`badge badge-${toneForRoute(signal.routeRecommendation.route)}`}>recommend {signal.routeRecommendation.route}</span> : null}
553
573
  {signal.routeRecommendation ? <span className="badge badge-gray">{signal.routeRecommendation.scope}</span> : null}
574
+ {signal.routeRecommendation?.proofTier ? <span className={`badge badge-${toneForProofTier(signal.routeRecommendation.proofTier)}`}>proof {signal.routeRecommendation.proofTier}</span> : null}
554
575
  {signal.routeRecommendation?.semanticInfluence && signal.routeRecommendation.semanticInfluence !== 'none' ? <span className="badge badge-green">semantic {signal.routeRecommendation.semanticInfluence}</span> : null}
555
576
  {(signal.semanticConceptIds ?? []).slice(0, 2).map((conceptId) => <span key={`${signal.id}-${conceptId}`} className="badge badge-gray">{conceptId}</span>)}
556
577
  {signal.interventionTypes.map((type) => <span key={`${signal.id}-${type}`} className="badge badge-gray">{type}</span>)}
@@ -560,6 +581,7 @@ export default function CoEvolutionClient({ summary, ontology, proof }: Props) {
560
581
  {signal.routeRecommendation.reasons.slice(0, 2).map((reason, index) => (
561
582
  <div key={`${signal.id}-reason-${index}`} className="signal-text">• {reason}</div>
562
583
  ))}
584
+ {signal.routeRecommendation.proofSummary ? <div className="signal-text">→ {signal.routeRecommendation.proofSummary}</div> : null}
563
585
  </div>
564
586
  ) : null}
565
587
  </div>
@@ -31,6 +31,7 @@ function providerTone(status: 'healthy' | 'degraded' | 'unavailable' | 'unknown'
31
31
  function getPriorityActions(params: {
32
32
  unresolved: number
33
33
  proofOpen: number
34
+ proofCaution: number
34
35
  topologyOpen: number
35
36
  optimizeStatus: 'idle' | 'healthy' | 'partial' | 'failed'
36
37
  optimizeNextStep?: string
@@ -58,6 +59,15 @@ function getPriorityActions(params: {
58
59
  })
59
60
  }
60
61
 
62
+ if (params.proofCaution > 0) {
63
+ actions.push({
64
+ href: '/proof',
65
+ title: 'Inspect cautionary proof steering',
66
+ description: `${params.proofCaution} proof lane${params.proofCaution === 1 ? '' : 's'} currently reduce trust or increase review bias for the next control step.`,
67
+ tone: 'yellow',
68
+ })
69
+ }
70
+
61
71
  if (params.proofOpen > 0) {
62
72
  actions.push({
63
73
  href: '/proof',
@@ -134,6 +144,7 @@ export default function Overview() {
134
144
  const priorityActions = getPriorityActions({
135
145
  unresolved: summary.failures.unresolved,
136
146
  proofOpen: proof.summary.reviewOpen,
147
+ proofCaution: proof.steering.cautionLanes,
137
148
  topologyOpen: topologyControl.summary.open,
138
149
  optimizeStatus: topologyControl.optimizeStatus.status,
139
150
  optimizeNextStep: topologyControl.optimizeStatus.nextStep,
@@ -176,7 +187,7 @@ export default function Overview() {
176
187
 
177
188
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
178
189
  <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="!" />
179
- <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="◇" />
190
+ <MetricCard label="Proof review" value={proof.summary.reviewOpen} sublabel={`${proof.steering.trustedLanes} trusted lanes • ${proof.steering.cautionLanes} caution`} tone={proof.summary.reviewOpen > 0 ? 'yellow' : proof.steering.trustedLanes > 0 ? 'green' : proof.steering.cautionLanes > 0 ? 'yellow' : 'neutral'} href="/proof" icon="◇" />
180
191
  <MetricCard
181
192
  label="Open pressure"
182
193
  value={ontology.pressureLifecycle.open}
@@ -328,6 +339,34 @@ export default function Overview() {
328
339
  </SectionFrame>
329
340
  ) : null}
330
341
 
342
+ <SectionFrame
343
+ eyebrow="Proof steering"
344
+ title="What proved outcomes are changing now"
345
+ description="Proof now separates trusted, cautionary, bounded, and candidate evidence so the next governed loop can steer more honestly instead of treating every proof record as equally strong."
346
+ tone="blue"
347
+ actions={<Link href="/proof" className="badge badge-gray">Open proof control</Link>}
348
+ >
349
+ <div className="grid-2" style={{ gap: 16 }}>
350
+ <div className="summary-list">
351
+ {proof.steering.routeLanes.slice(0, 3).map((lane) => (
352
+ <div key={lane.laneKey} className="summary-row">
353
+ <div className="summary-row-main">
354
+ <div className="summary-row-title">{lane.route ? lane.route.replace(/-/g, ' ') : lane.conceptId ?? lane.laneKey}</div>
355
+ <div className="summary-row-meta">{lane.summary}</div>
356
+ </div>
357
+ <span className={`hero-chip hero-chip-${lane.evidenceTier === 'trusted' ? 'green' : lane.evidenceTier === 'caution' ? 'yellow' : lane.evidenceTier === 'bounded' ? 'blue' : 'neutral'}`}>{lane.evidenceTier}</span>
358
+ </div>
359
+ ))}
360
+ {proof.steering.routeLanes.length === 0 ? <div className="signal-text">No route-level proof steering yet.</div> : null}
361
+ </div>
362
+ <div style={{ display: 'grid', gap: 12 }}>
363
+ <MetricCard label="Trusted lanes" value={proof.steering.trustedLanes} sublabel={`${proof.summary.verified} verified records reinforce future trust`} tone={proof.steering.trustedLanes > 0 ? 'green' : 'neutral'} href="/proof" icon="✓" />
364
+ <MetricCard label="Caution lanes" value={proof.steering.cautionLanes} sublabel={`${proof.summary.regressed} regressed • ${proof.summary.contested} contested`} tone={proof.steering.cautionLanes > 0 ? 'yellow' : 'neutral'} href="/proof" icon="!" />
365
+ <div className="signal-text">Candidate evidence stays visible in Proof, but no longer dominates the highest-value steering surface.</div>
366
+ </div>
367
+ </div>
368
+ </SectionFrame>
369
+
331
370
  <SectionFrame
332
371
  eyebrow="Brain summary"
333
372
  title="Semantic backbone"
@@ -39,6 +39,17 @@ function labelForOutcome(outcome: ProofOutcomeState) {
39
39
  return outcome.replace(/-/g, ' ')
40
40
  }
41
41
 
42
+ function toneForSteeringTier(tier: 'trusted' | 'caution' | 'bounded' | 'candidate') {
43
+ if (tier === 'trusted') return 'green'
44
+ if (tier === 'caution') return 'yellow'
45
+ if (tier === 'bounded') return 'blue'
46
+ return 'neutral'
47
+ }
48
+
49
+ function labelForSteeringLane(lane: ProofDashboardSummary['steering']['routeLanes'][number] | ProofDashboardSummary['steering']['semanticLanes'][number]) {
50
+ return lane.route ? lane.route.replace(/-/g, ' ') : lane.conceptId ?? lane.laneKey
51
+ }
52
+
42
53
  function formatDate(value: string | undefined) {
43
54
  if (!value) return '—'
44
55
  return new Date(value).toLocaleString()
@@ -52,19 +63,20 @@ function consoleTone(state: RunState): 'neutral' | 'green' | 'red' | 'yellow' {
52
63
  }
53
64
 
54
65
  function getRecommendedProofMove(dashboard: ProofDashboardSummary) {
66
+ const cautionLane = dashboard.steering.routeLanes.find((lane) => lane.evidenceTier === 'caution')
67
+ if (cautionLane) {
68
+ return {
69
+ label: 'Caution first',
70
+ title: labelForSteeringLane(cautionLane),
71
+ copy: 'A cautionary proof lane should usually be reviewed before you trust that route again. Regressed or contested evidence now biases the next loop toward more care.',
72
+ }
73
+ }
55
74
  const firstOpen = dashboard.reviewQueue[0]
56
75
  if (firstOpen) {
57
76
  return {
58
77
  label: 'Review queue first',
59
78
  title: firstOpen.title,
60
- copy: 'Open proof records should usually be resolved before you treat the prove layer as settled. Verify, defer, or contest the most important record first.',
61
- }
62
- }
63
- if (dashboard.summary.regressed > 0) {
64
- return {
65
- label: 'Investigate regressed evidence',
66
- title: 'A regressed outcome needs explanation before retry',
67
- copy: 'Regressed records mean HelixEvo has explicit negative evidence. Inspect the linked structural or intervention path before repeating the same move.',
79
+ copy: 'High-leverage proof records should usually be resolved before you treat the prove layer as settled. Verify, defer, or contest the most important record first.',
68
80
  }
69
81
  }
70
82
  if (dashboard.summary.measuring > 0) {
@@ -74,6 +86,13 @@ function getRecommendedProofMove(dashboard: ProofDashboardSummary) {
74
86
  copy: 'A measuring record is active but still too recent or incomplete for a stronger claim. Let downstream evidence accumulate before over-interpreting it.',
75
87
  }
76
88
  }
89
+ if (dashboard.candidateQueue.length > 0) {
90
+ return {
91
+ label: 'Candidate evidence only',
92
+ title: 'Dry-run and insufficient evidence stay bounded',
93
+ copy: 'Candidate proof records should remain visible, but they should not steer the system strongly until stronger downstream evidence appears.',
94
+ }
95
+ }
77
96
  return {
78
97
  label: 'Seed proof',
79
98
  title: 'No proof targets yet',
@@ -128,10 +147,10 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
128
147
  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."
129
148
  chips={[
130
149
  { label: `${dashboard.summary.total} proof records`, tone: 'blue' },
131
- { label: `${dashboard.summary.effective} effective`, tone: dashboard.summary.effective > 0 ? 'green' : 'neutral' },
132
- { label: `${dashboard.summary.mixed} mixed`, tone: dashboard.summary.mixed > 0 ? 'purple' : 'neutral' },
133
- { label: `${dashboard.summary.regressed} regressed`, tone: dashboard.summary.regressed > 0 ? 'yellow' : 'neutral' },
150
+ { label: `${dashboard.steering.trustedLanes} trusted lanes`, tone: dashboard.steering.trustedLanes > 0 ? 'green' : 'neutral' },
151
+ { label: `${dashboard.steering.cautionLanes} caution lanes`, tone: dashboard.steering.cautionLanes > 0 ? 'yellow' : 'neutral' },
134
152
  { label: `${dashboard.summary.reviewOpen} open review`, tone: dashboard.summary.reviewOpen > 0 ? 'yellow' : 'green' },
153
+ { label: `${dashboard.steering.candidateLanes} candidate lanes`, tone: dashboard.steering.candidateLanes > 0 ? 'neutral' : 'green' },
135
154
  { label: `${dashboard.summary.verified} verified`, tone: dashboard.summary.verified > 0 ? 'green' : 'neutral' },
136
155
  ]}
137
156
  actions={
@@ -149,11 +168,11 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
149
168
  <OperatorLoopTrail surface="proof" />
150
169
 
151
170
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
152
- <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="✓" />
153
- <MetricCard label="Mixed" value={dashboard.summary.mixed} sublabel="partial or conflicting downstream evidence" tone={dashboard.summary.mixed > 0 ? 'purple' : 'neutral'} icon="" />
154
- <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="!" />
171
+ <MetricCard label="Trusted lanes" value={dashboard.steering.trustedLanes} sublabel={`${dashboard.summary.verified} verified records backing future trust`} tone={dashboard.steering.trustedLanes > 0 ? 'green' : 'neutral'} icon="✓" />
172
+ <MetricCard label="Caution lanes" value={dashboard.steering.cautionLanes} sublabel={`${dashboard.summary.regressed} regressed ${dashboard.summary.contested} contested`} tone={dashboard.steering.cautionLanes > 0 ? 'yellow' : 'neutral'} icon="!" />
155
173
  <MetricCard label="Measuring" value={dashboard.summary.measuring} sublabel={`${dashboard.summary.insufficientEvidence} insufficient-evidence`} tone={dashboard.summary.measuring > 0 ? 'blue' : 'neutral'} icon="◎" />
156
- <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="" />
174
+ <MetricCard label="Candidate evidence" value={dashboard.steering.candidateLanes} sublabel={`${dashboard.candidateQueue.length} open low-closure records`} tone={dashboard.steering.candidateLanes > 0 ? 'neutral' : 'green'} icon="" />
175
+ <MetricCard label="Open review" value={dashboard.summary.reviewOpen} sublabel={`${dashboard.steering.priorityReview} high-leverage • ${dashboard.summary.verified} verified`} tone={dashboard.summary.reviewOpen > 0 ? 'yellow' : 'green'} icon="◇" />
157
176
  </div>
158
177
 
159
178
  <SectionFrame
@@ -178,6 +197,34 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
178
197
  </div>
179
198
  </SectionFrame>
180
199
 
200
+ <SectionFrame
201
+ eyebrow="Steering"
202
+ title="What proof is changing about future control"
203
+ description="Proof now separates trusted, cautionary, bounded, and candidate evidence so the next governed loop can steer more honestly. Trusted lanes can strengthen confidence modestly, caution lanes bias toward more review, and candidate evidence stays bounded."
204
+ tone="blue"
205
+ >
206
+ <div className="grid-2" style={{ gap: 16 }}>
207
+ <div className="summary-list">
208
+ {dashboard.steering.routeLanes.slice(0, 4).map((lane) => (
209
+ <div key={lane.laneKey} className="summary-row">
210
+ <div className="summary-row-main">
211
+ <div className="summary-row-title">{labelForSteeringLane(lane)}</div>
212
+ <div className="summary-row-meta">{lane.summary}</div>
213
+ <div className="summary-row-meta" style={{ marginTop: 6 }}>{lane.reasons[0] ?? 'Proof steering keeps this lane bounded.'}</div>
214
+ </div>
215
+ <span className={`hero-chip hero-chip-${toneForSteeringTier(lane.evidenceTier)}`}>{lane.evidenceTier}</span>
216
+ </div>
217
+ ))}
218
+ {dashboard.steering.routeLanes.length === 0 ? <div className="signal-text">No route-level steering evidence yet.</div> : null}
219
+ </div>
220
+ <div style={{ display: 'grid', gap: 12 }}>
221
+ <MetricCard label="Priority review" value={dashboard.steering.priorityReview} sublabel={`${dashboard.reviewQueue.length} high-leverage queue items`} tone={dashboard.steering.priorityReview > 0 ? 'yellow' : 'green'} icon="◇" />
222
+ <MetricCard label="Semantic steering" value={dashboard.steering.semanticLanes.length} sublabel={`${dashboard.steering.semanticLanes.filter((lane) => lane.evidenceTier === 'trusted').length} trusted • ${dashboard.steering.semanticLanes.filter((lane) => lane.evidenceTier === 'caution').length} caution`} tone={dashboard.steering.semanticLanes.length > 0 ? 'purple' : 'neutral'} icon="◎" />
223
+ <div className="signal-text">Candidate evidence remains visible below, but it no longer dominates the highest-value proof review surface.</div>
224
+ </div>
225
+ </div>
226
+ </SectionFrame>
227
+
181
228
  <SectionFrame
182
229
  eyebrow="Coverage"
183
230
  title="Proof now spans the live brain loop"
@@ -255,6 +302,28 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
255
302
  </div>
256
303
  </SectionFrame>
257
304
 
305
+ <SectionFrame
306
+ eyebrow="Candidate evidence"
307
+ title="Dry-run and low-closure proof"
308
+ description="These records remain visible, but they should not steer the system strongly until stronger downstream evidence or explicit operator review exists."
309
+ >
310
+ <div style={{ display: 'grid', gap: 10 }}>
311
+ {dashboard.candidateQueue.length > 0 ? dashboard.candidateQueue.map((record) => (
312
+ <div key={record.id} style={{ padding: '14px 16px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.72)' }}>
313
+ <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
314
+ <div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{record.title}</div>
315
+ <span className="badge badge-gray">candidate</span>
316
+ </div>
317
+ <div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.6 }}>{record.summary}</div>
318
+ <div style={{ display: 'grid', gap: 6, marginTop: 10 }}>
319
+ {record.reasons.slice(0, 2).map((reason, idx) => <div key={`${record.id}-candidate-${idx}`} className="signal-text">• {reason}</div>)}
320
+ {record.recommendedAction ? <div className="signal-text">→ {record.recommendedAction}</div> : null}
321
+ </div>
322
+ </div>
323
+ )) : <div className="signal-text">No candidate-only proof records right now.</div>}
324
+ </div>
325
+ </SectionFrame>
326
+
258
327
  <div className="grid-2">
259
328
  <SectionFrame
260
329
  eyebrow="Verified"
@@ -30,6 +30,8 @@ function readOntologyJsonl<T>(filename: string): T[] {
30
30
  return raw.split('\n').filter(Boolean).map((l) => JSON.parse(l))
31
31
  }
32
32
 
33
+ import { loadProofSteeringSummary } from './proof'
34
+
33
35
  // ─── Types ──────────────────────────────────────────────────────
34
36
 
35
37
  export type CognitiveRole = 'generalist' | 'specialist' | 'hybrid'
@@ -180,6 +182,8 @@ export type PressureInterventionImpact = 'exploratory' | 'structural' | 'resolvi
180
182
  export type PressureLifecycleState = 'open' | 'in-progress' | 'addressed' | 'stale'
181
183
  export type PressureRouteScope = 'local' | 'project' | 'network'
182
184
  export type PressureRouteTrigger = 'high-priority-local-gap' | 'project-bounded-recurrence' | 'recurring-cross-project-gap' | 'overlapping-skills' | 'accepted-iteration-pattern' | 'insufficient-evidence' | 'mixed-signal'
185
+ export type ProofSteeringTier = 'trusted' | 'caution' | 'bounded' | 'candidate'
186
+ export type ProofSteeringInfluence = 'none' | 'explanatory' | 'weighted'
183
187
 
184
188
  export interface PressureRouteRecommendation {
185
189
  route: PressureInterventionType
@@ -190,6 +194,11 @@ export interface PressureRouteRecommendation {
190
194
  reasons: string[]
191
195
  semanticInfluence?: OntologySemanticInfluence
192
196
  semanticConceptIds?: string[]
197
+ proofInfluence?: ProofSteeringInfluence
198
+ proofTier?: ProofSteeringTier
199
+ proofSummary?: string
200
+ proofReasons?: string[]
201
+ proofLaneKeys?: string[]
193
202
  }
194
203
 
195
204
  export interface PressureIntervention {
@@ -2036,6 +2045,105 @@ function matchTopologyOntologyBindings(candidate: ResolvedTopologyReviewCandidat
2036
2045
  return dedupeOntologyBindings(bindings)
2037
2046
  }
2038
2047
 
2048
+ function proofTierWeight(tier: ProofSteeringTier): number {
2049
+ return tier === 'caution' ? 4 : tier === 'trusted' ? 3 : tier === 'bounded' ? 2 : 1
2050
+ }
2051
+
2052
+ function strongerProofTier(current: ProofSteeringTier | undefined, next: ProofSteeringTier): ProofSteeringTier {
2053
+ if (!current) return next
2054
+ return proofTierWeight(next) > proofTierWeight(current) ? next : current
2055
+ }
2056
+
2057
+ function applyProofInfluenceToRoute(params: {
2058
+ recommendation: PressureRouteRecommendation
2059
+ signal: PressureSignal
2060
+ semanticBindings: ResolvedOntologyBinding[]
2061
+ proofSteering: import('./proof').ProofSteeringSummary | null
2062
+ }): PressureRouteRecommendation {
2063
+ const { recommendation, semanticBindings, proofSteering } = params
2064
+ if (!proofSteering) return recommendation
2065
+
2066
+ let route = recommendation.route
2067
+ let confidence = recommendation.confidence
2068
+ let triggeredBy = recommendation.triggeredBy
2069
+ const reasons = [...recommendation.reasons]
2070
+ const proofReasons: string[] = []
2071
+ const proofLaneKeys: string[] = []
2072
+ let proofSummary: string | undefined
2073
+ let proofTier: ProofSteeringTier | undefined
2074
+ let proofInfluence: 'none' | 'explanatory' | 'weighted' = 'none'
2075
+
2076
+ const routeLane = proofSteering.byRoute[recommendation.route]
2077
+ if (routeLane) {
2078
+ proofLaneKeys.push(routeLane.laneKey)
2079
+ proofReasons.push(...routeLane.reasons.slice(0, 2))
2080
+ proofSummary = proofSummary ?? routeLane.summary
2081
+ proofTier = strongerProofTier(proofTier, routeLane.evidenceTier)
2082
+
2083
+ if (routeLane.evidenceTier === 'trusted') {
2084
+ confidence = Math.min(0.95, confidence + (routeLane.score >= 4 ? 0.06 : 0.04))
2085
+ proofInfluence = 'weighted'
2086
+ reasons.push(`Proof steering: ${routeLane.summary}`)
2087
+ } else if (routeLane.evidenceTier === 'caution') {
2088
+ if (recommendation.route !== 'manual-review' && routeLane.score <= -3 && (recommendation.route === 'generalize' || recommendation.route === 'evolve')) {
2089
+ route = 'manual-review'
2090
+ triggeredBy = 'mixed-signal'
2091
+ confidence = Math.max(0.66, confidence - 0.02)
2092
+ proofInfluence = 'weighted'
2093
+ reasons.push(`Proof steering: ${routeLane.summary} Governance now prefers explicit operator review before retrying ${recommendation.route}.`)
2094
+ } else {
2095
+ confidence = Math.max(0.4, confidence - 0.08)
2096
+ proofInfluence = 'weighted'
2097
+ reasons.push(`Proof steering: ${routeLane.summary}`)
2098
+ }
2099
+ } else {
2100
+ if (proofInfluence === 'none') proofInfluence = 'explanatory'
2101
+ reasons.push(`Proof steering: ${routeLane.summary}`)
2102
+ }
2103
+ }
2104
+
2105
+ const conceptIds = uniqueStrings([...(recommendation.semanticConceptIds ?? []), ...semanticBindings.map((binding) => binding.conceptId)])
2106
+ const conceptLanes = conceptIds.map((conceptId) => proofSteering.byConceptId[conceptId]).filter(Boolean)
2107
+ if (conceptLanes.length > 0) {
2108
+ const strongestConceptLane = [...conceptLanes].sort((a, b) => proofTierWeight(b.evidenceTier) - proofTierWeight(a.evidenceTier) || Math.abs(b.score) - Math.abs(a.score))[0]
2109
+ if (strongestConceptLane) {
2110
+ proofLaneKeys.push(strongestConceptLane.laneKey)
2111
+ proofReasons.push(...strongestConceptLane.reasons.slice(0, 2))
2112
+ proofSummary = proofSummary ?? strongestConceptLane.summary
2113
+ proofTier = strongerProofTier(proofTier, strongestConceptLane.evidenceTier)
2114
+ if (strongestConceptLane.evidenceTier === 'trusted') {
2115
+ confidence = Math.min(0.95, confidence + 0.02)
2116
+ proofInfluence = 'weighted'
2117
+ reasons.push(`Proof steering: ${strongestConceptLane.summary}`)
2118
+ } else if (strongestConceptLane.evidenceTier === 'caution') {
2119
+ confidence = Math.max(0.4, confidence - 0.03)
2120
+ if (proofInfluence === 'none') proofInfluence = 'weighted'
2121
+ reasons.push(`Proof steering: ${strongestConceptLane.summary}`)
2122
+ } else {
2123
+ if (proofInfluence === 'none') proofInfluence = 'explanatory'
2124
+ reasons.push(`Proof steering: ${strongestConceptLane.summary}`)
2125
+ }
2126
+ }
2127
+ }
2128
+
2129
+ return {
2130
+ ...recommendation,
2131
+ route,
2132
+ confidence,
2133
+ triggeredBy,
2134
+ reasons: [...new Set(reasons)].slice(0, 8),
2135
+ proofInfluence,
2136
+ proofTier,
2137
+ proofSummary,
2138
+ proofReasons: [...new Set(proofReasons)].slice(0, 4),
2139
+ proofLaneKeys: [...new Set(proofLaneKeys)],
2140
+ }
2141
+ }
2142
+
2143
+ type ProofSteeringLoadOptions = {
2144
+ includeProofSteering?: boolean
2145
+ }
2146
+
2039
2147
  function applyOntologyInfluenceToRoute(params: {
2040
2148
  recommendation: PressureRouteRecommendation
2041
2149
  signal: PressureSignal
@@ -2088,8 +2196,9 @@ function buildRouteRecommendation(params: {
2088
2196
  governanceMode: GovernanceModeName
2089
2197
  governanceProfile: GovernanceProfile
2090
2198
  semanticBindings: ResolvedOntologyBinding[]
2199
+ proofSteering: import('./proof').ProofSteeringSummary | null
2091
2200
  }): PressureRouteRecommendation {
2092
- const { signal, relatedSignals, linkedInterventions, governanceMode, governanceProfile, semanticBindings } = params
2201
+ const { signal, relatedSignals, linkedInterventions, governanceMode, governanceProfile, semanticBindings, proofSteering } = params
2093
2202
  const projectSpread = new Set(relatedSignals.map((entry) => entry.projectId ?? entry.projectPath).filter(Boolean)).size
2094
2203
  const recurrenceCount = relatedSignals.length
2095
2204
  const activeTypes = [...new Set(linkedInterventions.map((intervention) => intervention.interventionType))]
@@ -2175,12 +2284,19 @@ function buildRouteRecommendation(params: {
2175
2284
  }
2176
2285
  }
2177
2286
 
2178
- return applyOntologyInfluenceToRoute({
2287
+ const ontologyAware = applyOntologyInfluenceToRoute({
2179
2288
  recommendation,
2180
2289
  signal,
2181
2290
  semanticBindings,
2182
2291
  governanceProfile,
2183
2292
  })
2293
+
2294
+ return applyProofInfluenceToRoute({
2295
+ recommendation: ontologyAware,
2296
+ signal,
2297
+ semanticBindings,
2298
+ proofSteering,
2299
+ })
2184
2300
  }
2185
2301
 
2186
2302
  function interventionEvidenceAccepted(
@@ -2206,7 +2322,7 @@ function interventionKeepsPressureActive(impact: PressureInterventionImpact, sta
2206
2322
  return impact === 'exploratory' || impact === 'structural' || impact === 'resolving'
2207
2323
  }
2208
2324
 
2209
- export function loadResolvedPressureSignals(): ResolvedPressureSignal[] {
2325
+ export function loadResolvedPressureSignals(options: ProofSteeringLoadOptions = {}): ResolvedPressureSignal[] {
2210
2326
  const pressureSignals = loadPressureSignals()
2211
2327
  const interventions = loadPressureInterventions()
2212
2328
  const transferEvents = loadTransferEvents()
@@ -2214,6 +2330,7 @@ export function loadResolvedPressureSignals(): ResolvedPressureSignal[] {
2214
2330
  const artifacts = loadEvolutionArtifacts()
2215
2331
  const governance = deriveGovernanceSummary(pressureSignals, interventions)
2216
2332
  const concepts = activeOntologyExtensions()
2333
+ const proofSteering = options.includeProofSteering === false ? null : loadProofSteeringSummary()
2217
2334
  const acceptedProposalIds = new Set(
2218
2335
  history.iterations.flatMap((iteration) => iteration.proposals)
2219
2336
  .filter((proposal) => proposal.outcome === 'accepted')
@@ -2259,6 +2376,7 @@ export function loadResolvedPressureSignals(): ResolvedPressureSignal[] {
2259
2376
  governanceMode: governance.activeMode,
2260
2377
  governanceProfile: governance.profile,
2261
2378
  semanticBindings,
2379
+ proofSteering,
2262
2380
  })
2263
2381
 
2264
2382
  const lifecycle: PressureLifecycleState = addressingInterventions.length > 0 || signal.status === 'addressed'
@@ -2304,8 +2422,8 @@ function projectRoleForSkill(skillId: string, graph: SkillGraph): CognitiveRole
2304
2422
  return inferCognitiveRole(node)
2305
2423
  }
2306
2424
 
2307
- export function loadPressureMotifs(): ResolvedPressureMotif[] {
2308
- const resolvedSignals = loadResolvedPressureSignals()
2425
+ export function loadPressureMotifs(options: ProofSteeringLoadOptions = {}): ResolvedPressureMotif[] {
2426
+ const resolvedSignals = loadResolvedPressureSignals(options)
2309
2427
  const interventions = loadPressureInterventions()
2310
2428
  const transferEvents = loadTransferEvents()
2311
2429
  const governance = deriveGovernanceSummary()
@@ -2419,7 +2537,7 @@ export function loadPressureMotifs(): ResolvedPressureMotif[] {
2419
2537
  })
2420
2538
  }
2421
2539
 
2422
- function collectOntologyAdoptionState(): { summary: OntologyAdoptionSummary, consumerMap: Map<string, OntologyConsumerSummary> } {
2540
+ function collectOntologyAdoptionState(options: ProofSteeringLoadOptions = {}): { summary: OntologyAdoptionSummary, consumerMap: Map<string, OntologyConsumerSummary> } {
2423
2541
  const extensions = loadOntologyExtensions()
2424
2542
  const activeExtensions = extensions.filter((concept) => concept.status === 'active')
2425
2543
  const byConceptKind = ontologyKindCounts()
@@ -2458,7 +2576,7 @@ function collectOntologyAdoptionState(): { summary: OntologyAdoptionSummary, con
2458
2576
  byConceptKind[concept.conceptKind] = (byConceptKind[concept.conceptKind] ?? 0) + 1
2459
2577
  }
2460
2578
 
2461
- const signals = loadResolvedPressureSignals()
2579
+ const signals = loadResolvedPressureSignals(options)
2462
2580
  for (const signal of signals) {
2463
2581
  for (const binding of signal.semanticBindings ?? []) registerBinding(binding)
2464
2582
  if (signal.routeRecommendation?.semanticConceptIds?.length) {
@@ -2478,7 +2596,7 @@ function collectOntologyAdoptionState(): { summary: OntologyAdoptionSummary, con
2478
2596
  }
2479
2597
  }
2480
2598
 
2481
- for (const motif of loadPressureMotifs()) {
2599
+ for (const motif of loadPressureMotifs(options)) {
2482
2600
  for (const binding of motif.semanticBindings ?? []) registerBinding(binding)
2483
2601
  }
2484
2602
 
@@ -2517,13 +2635,13 @@ function collectOntologyAdoptionState(): { summary: OntologyAdoptionSummary, con
2517
2635
  }
2518
2636
  }
2519
2637
 
2520
- export function getOntologyAdoptionSummary(): OntologyAdoptionSummary {
2521
- return collectOntologyAdoptionState().summary
2638
+ export function getOntologyAdoptionSummary(options: ProofSteeringLoadOptions = {}): OntologyAdoptionSummary {
2639
+ return collectOntologyAdoptionState(options).summary
2522
2640
  }
2523
2641
 
2524
- export function loadResolvedOntologyExtensions(): ResolvedOntologyExtension[] {
2642
+ export function loadResolvedOntologyExtensions(options: ProofSteeringLoadOptions = {}): ResolvedOntologyExtension[] {
2525
2643
  const extensions = loadOntologyExtensions()
2526
- const { consumerMap } = collectOntologyAdoptionState()
2644
+ const { consumerMap } = collectOntologyAdoptionState(options)
2527
2645
  return extensions
2528
2646
  .map((concept) => {
2529
2647
  const consumer = consumerMap.get(concept.id)