helixevo 0.9.0 → 0.10.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 +11 -0
- package/README.md +8 -1
- package/dashboard/app/api/run/route.ts +1 -0
- package/dashboard/app/coevolution/client.tsx +18 -1
- package/dashboard/app/commands/page.tsx +22 -0
- package/dashboard/app/page.tsx +107 -3
- package/dashboard/app/proof/client.tsx +168 -30
- package/dashboard/app/proof/page.tsx +3 -1
- package/dashboard/lib/data.ts +31 -3
- package/dashboard/lib/proof.ts +386 -15
- package/dashboard/lib/theory.ts +70 -0
- package/dist/cli.js +1937 -127
- package/package.json +2 -2
- package/dashboard/lib/release-spotlight.ts +0 -17
|
@@ -9,6 +9,7 @@ import { PageHero } from '@/components/page-hero'
|
|
|
9
9
|
import { SectionFrame } from '@/components/section-frame'
|
|
10
10
|
import { SurfaceJumpLinks } from '@/components/surface-jump-links'
|
|
11
11
|
import type { ProofDashboardSummary, ProofOutcomeState, ProofReviewDecisionStatus, ProofTargetType } from '@/lib/proof'
|
|
12
|
+
import type { TheoryConformanceRunResult } from '@/lib/theory'
|
|
12
13
|
|
|
13
14
|
type RunState = 'idle' | 'running' | 'success' | 'error'
|
|
14
15
|
|
|
@@ -46,6 +47,14 @@ function toneForSteeringTier(tier: 'trusted' | 'caution' | 'bounded' | 'candidat
|
|
|
46
47
|
return 'neutral'
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
function toneForClosureState(state: ProofDashboardSummary['records'][number]['closureState'] | ProofDashboardSummary['steering']['routeLanes'][number]['closureState']) {
|
|
51
|
+
if (state === 'trusted-with-debt') return 'yellow'
|
|
52
|
+
if (state === 'stalled') return 'yellow'
|
|
53
|
+
if (state === 'needs-review') return 'blue'
|
|
54
|
+
if (state === 'needs-evidence') return 'neutral'
|
|
55
|
+
return 'green'
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
function labelForSteeringLane(lane: ProofDashboardSummary['steering']['routeLanes'][number] | ProofDashboardSummary['steering']['semanticLanes'][number]) {
|
|
50
59
|
return lane.route ? lane.route.replace(/-/g, ' ') : lane.conceptId ?? lane.laneKey
|
|
51
60
|
}
|
|
@@ -62,7 +71,64 @@ function consoleTone(state: RunState): 'neutral' | 'green' | 'red' | 'yellow' {
|
|
|
62
71
|
return 'neutral'
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
function toneForConformance(verdict: TheoryConformanceRunResult['verdict']) {
|
|
75
|
+
if (verdict === 'pass') return 'green'
|
|
76
|
+
if (verdict === 'bounded-pass') return 'yellow'
|
|
77
|
+
if (verdict === 'fail') return 'red'
|
|
78
|
+
return 'neutral'
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getConformanceHeadline(result: TheoryConformanceRunResult | null) {
|
|
82
|
+
if (!result) {
|
|
83
|
+
return {
|
|
84
|
+
label: 'Not run yet',
|
|
85
|
+
title: 'No automated brain verification recorded',
|
|
86
|
+
copy: 'Run helixevo verify-brain to generate the first contract-backed theory-conformance verdict for this installation.',
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const failing = result.scenarios.find((scenario) => scenario.verdict === 'fail')
|
|
91
|
+
if (failing) {
|
|
92
|
+
return {
|
|
93
|
+
label: 'Failing scenario',
|
|
94
|
+
title: `${failing.scenarioId} · ${failing.title}`,
|
|
95
|
+
copy: failing.summary,
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const bounded = result.scenarios.find((scenario) => scenario.verdict === 'bounded-pass' || scenario.verdict === 'inconclusive')
|
|
100
|
+
if (bounded) {
|
|
101
|
+
return {
|
|
102
|
+
label: 'Bounded scenario',
|
|
103
|
+
title: `${bounded.scenarioId} · ${bounded.title}`,
|
|
104
|
+
copy: bounded.summary,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
label: 'Latest run',
|
|
110
|
+
title: 'All executed theory scenarios passed',
|
|
111
|
+
copy: result.summary,
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
65
115
|
function getRecommendedProofMove(dashboard: ProofDashboardSummary) {
|
|
116
|
+
const stalledGroup = dashboard.closureDebtGroups.find((group) => group.closureState === 'stalled')
|
|
117
|
+
if (stalledGroup) {
|
|
118
|
+
return {
|
|
119
|
+
label: 'Resolve stalled debt',
|
|
120
|
+
title: stalledGroup.title,
|
|
121
|
+
copy: 'Some proof debt has aged long enough that it now needs explicit revisit instead of passive waiting. Clear the stalled group before treating the proof layer as healthy.',
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const trustedWithDebt = dashboard.steering.routeLanes.find((lane) => lane.trustedWithDebt)
|
|
125
|
+
if (trustedWithDebt) {
|
|
126
|
+
return {
|
|
127
|
+
label: 'Trusted, but not closed',
|
|
128
|
+
title: labelForSteeringLane(trustedWithDebt),
|
|
129
|
+
copy: trustedWithDebt.debtSummary ?? 'A trusted lane still carries unresolved debt behind it. Review the debt before treating the lane as fully settled.',
|
|
130
|
+
}
|
|
131
|
+
}
|
|
66
132
|
const cautionLane = dashboard.steering.routeLanes.find((lane) => lane.evidenceTier === 'caution')
|
|
67
133
|
if (cautionLane) {
|
|
68
134
|
return {
|
|
@@ -79,6 +145,14 @@ function getRecommendedProofMove(dashboard: ProofDashboardSummary) {
|
|
|
79
145
|
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.',
|
|
80
146
|
}
|
|
81
147
|
}
|
|
148
|
+
const evidenceDebt = dashboard.closureDebtGroups.find((group) => group.closureState === 'needs-evidence')
|
|
149
|
+
if (evidenceDebt) {
|
|
150
|
+
return {
|
|
151
|
+
label: 'Harvest missing evidence',
|
|
152
|
+
title: evidenceDebt.title,
|
|
153
|
+
copy: evidenceDebt.summary,
|
|
154
|
+
}
|
|
155
|
+
}
|
|
82
156
|
if (dashboard.summary.measuring > 0) {
|
|
83
157
|
return {
|
|
84
158
|
label: 'Let evidence mature',
|
|
@@ -86,13 +160,6 @@ function getRecommendedProofMove(dashboard: ProofDashboardSummary) {
|
|
|
86
160
|
copy: 'A measuring record is active but still too recent or incomplete for a stronger claim. Let downstream evidence accumulate before over-interpreting it.',
|
|
87
161
|
}
|
|
88
162
|
}
|
|
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
|
-
}
|
|
96
163
|
return {
|
|
97
164
|
label: 'Seed proof',
|
|
98
165
|
title: 'No proof targets yet',
|
|
@@ -100,12 +167,15 @@ function getRecommendedProofMove(dashboard: ProofDashboardSummary) {
|
|
|
100
167
|
}
|
|
101
168
|
}
|
|
102
169
|
|
|
103
|
-
export default function ProofClient({ initialDashboard }: { initialDashboard: ProofDashboardSummary }) {
|
|
170
|
+
export default function ProofClient({ initialDashboard, initialConformance }: { initialDashboard: ProofDashboardSummary; initialConformance: TheoryConformanceRunResult | null }) {
|
|
104
171
|
const [dashboard, setDashboard] = useState(initialDashboard)
|
|
105
172
|
const [runState, setRunState] = useState<RunState>('idle')
|
|
106
173
|
const [output, setOutput] = useState('')
|
|
107
174
|
const [pendingKey, setPendingKey] = useState<string | null>(null)
|
|
108
175
|
const recommendedMove = getRecommendedProofMove(dashboard)
|
|
176
|
+
const conformanceHeadline = getConformanceHeadline(initialConformance)
|
|
177
|
+
const evidenceDebtGroups = dashboard.closureDebtGroups.filter((group) => group.closureState === 'needs-evidence')
|
|
178
|
+
const stalledDebtGroups = dashboard.closureDebtGroups.filter((group) => group.closureState === 'stalled')
|
|
109
179
|
|
|
110
180
|
const runReview = async (recordId: string, decision: ProofReviewDecisionStatus, label: string) => {
|
|
111
181
|
setPendingKey(recordId)
|
|
@@ -148,10 +218,10 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
|
|
|
148
218
|
chips={[
|
|
149
219
|
{ label: `${dashboard.summary.total} proof records`, tone: 'blue' },
|
|
150
220
|
{ label: `${dashboard.steering.trustedLanes} trusted lanes`, tone: dashboard.steering.trustedLanes > 0 ? 'green' : 'neutral' },
|
|
151
|
-
{ label: `${dashboard.steering.
|
|
152
|
-
{ label: `${dashboard.summary.
|
|
153
|
-
{ label: `${dashboard.
|
|
154
|
-
{ label: `${dashboard.summary.
|
|
221
|
+
{ label: `${dashboard.steering.trustedWithDebtLanes} trusted with debt`, tone: dashboard.steering.trustedWithDebtLanes > 0 ? 'yellow' : 'neutral' },
|
|
222
|
+
{ label: `${dashboard.summary.needsReview} need review`, tone: dashboard.summary.needsReview > 0 ? 'blue' : 'neutral' },
|
|
223
|
+
{ label: `${dashboard.summary.needsEvidence} need evidence`, tone: dashboard.summary.needsEvidence > 0 ? 'neutral' : 'green' },
|
|
224
|
+
{ label: `${dashboard.summary.stalled} stalled`, tone: dashboard.summary.stalled > 0 ? 'yellow' : 'neutral' },
|
|
155
225
|
]}
|
|
156
226
|
actions={
|
|
157
227
|
<div style={{ display: 'grid', gap: 12 }}>
|
|
@@ -169,12 +239,46 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
|
|
|
169
239
|
|
|
170
240
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
|
|
171
241
|
<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="
|
|
173
|
-
<MetricCard label="
|
|
174
|
-
<MetricCard label="
|
|
175
|
-
<MetricCard label="
|
|
242
|
+
<MetricCard label="Trusted with debt" value={dashboard.steering.trustedWithDebtLanes} sublabel="lanes that look strong on top but still carry unresolved closure debt" tone={dashboard.steering.trustedWithDebtLanes > 0 ? 'yellow' : 'neutral'} icon="!" />
|
|
243
|
+
<MetricCard label="Needs review" value={dashboard.summary.needsReview} sublabel={`${dashboard.reviewQueue.length} high-leverage queue items`} tone={dashboard.summary.needsReview > 0 ? 'blue' : 'green'} icon="◇" />
|
|
244
|
+
<MetricCard label="Needs evidence" value={dashboard.summary.needsEvidence} sublabel={`${evidenceDebtGroups.length} grouped debt area${evidenceDebtGroups.length === 1 ? '' : 's'}`} tone={dashboard.summary.needsEvidence > 0 ? 'neutral' : 'green'} icon="◌" />
|
|
245
|
+
<MetricCard label="Stalled debt" value={dashboard.summary.stalled} sublabel={`${stalledDebtGroups.length} stalled group${stalledDebtGroups.length === 1 ? '' : 's'}`} tone={dashboard.summary.stalled > 0 ? 'yellow' : 'green'} icon="◎" />
|
|
176
246
|
</div>
|
|
177
247
|
|
|
248
|
+
<SectionFrame
|
|
249
|
+
eyebrow="Automated brain verification"
|
|
250
|
+
title="Latest theory-conformance verdict"
|
|
251
|
+
description="The prove layer is now complemented by an explicit contract-backed verification run. This does not replace proof review; it checks whether the current brain still behaves according to the bounded theory contract."
|
|
252
|
+
tone="blue"
|
|
253
|
+
>
|
|
254
|
+
{initialConformance ? (
|
|
255
|
+
<div className="grid-2" style={{ gap: 16 }}>
|
|
256
|
+
<div className="hero-note-card">
|
|
257
|
+
<div className="hero-note-label">{conformanceHeadline.label}</div>
|
|
258
|
+
<div className="hero-note-title">{conformanceHeadline.title}</div>
|
|
259
|
+
<div className="hero-note-copy">{conformanceHeadline.copy}</div>
|
|
260
|
+
{initialConformance.reportPath ? (
|
|
261
|
+
<div className="signal-text" style={{ marginTop: 10 }}>report · {initialConformance.reportPath}</div>
|
|
262
|
+
) : null}
|
|
263
|
+
</div>
|
|
264
|
+
<div style={{ display: 'grid', gap: 12 }}>
|
|
265
|
+
<MetricCard label="Verdict" value={initialConformance.verdict} sublabel={`${initialConformance.totals.passed} pass • ${initialConformance.totals.boundedPass} bounded • ${initialConformance.totals.failed} fail • ${initialConformance.totals.inconclusive} inconclusive`} tone={toneForConformance(initialConformance.verdict)} icon="◎" />
|
|
266
|
+
<MetricCard label="Scenarios" value={initialConformance.totals.scenarios} sublabel={`${initialConformance.totals.assertions} assertions across isolated + live suites`} tone="blue" icon="◇" />
|
|
267
|
+
<MetricCard label="Latest mode" value={initialConformance.mode} sublabel={initialConformance.releaseMode ? 'release-grade handling enabled' : 'standard operator run'} tone="purple" icon="⇄" />
|
|
268
|
+
<div className="signal-text">{initialConformance.nextActions[0] ?? 'Run helixevo verify-brain --verbose to inspect the full latest result.'}</div>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
) : (
|
|
272
|
+
<NextStepEmptyState
|
|
273
|
+
title="No automated verification run yet"
|
|
274
|
+
description="Run helixevo verify-brain to generate the first contract-backed theory-conformance verdict for this installation."
|
|
275
|
+
command="helixevo verify-brain --verbose"
|
|
276
|
+
pageLink={{ label: 'Open Commands', href: '/commands', tone: 'blue' }}
|
|
277
|
+
guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'purple' }}
|
|
278
|
+
/>
|
|
279
|
+
)}
|
|
280
|
+
</SectionFrame>
|
|
281
|
+
|
|
178
282
|
<SectionFrame
|
|
179
283
|
eyebrow="Meaning"
|
|
180
284
|
title="What these proof states mean operationally"
|
|
@@ -210,7 +314,7 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
|
|
|
210
314
|
<div className="summary-row-main">
|
|
211
315
|
<div className="summary-row-title">{labelForSteeringLane(lane)}</div>
|
|
212
316
|
<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>
|
|
317
|
+
<div className="summary-row-meta" style={{ marginTop: 6 }}>{lane.debtSummary ?? lane.reasons[0] ?? 'Proof steering keeps this lane bounded.'}</div>
|
|
214
318
|
</div>
|
|
215
319
|
<span className={`hero-chip hero-chip-${toneForSteeringTier(lane.evidenceTier)}`}>{lane.evidenceTier}</span>
|
|
216
320
|
</div>
|
|
@@ -219,8 +323,9 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
|
|
|
219
323
|
</div>
|
|
220
324
|
<div style={{ display: 'grid', gap: 12 }}>
|
|
221
325
|
<MetricCard label="Priority review" value={dashboard.steering.priorityReview} sublabel={`${dashboard.reviewQueue.length} high-leverage queue items`} tone={dashboard.steering.priorityReview > 0 ? 'yellow' : 'green'} icon="◇" />
|
|
326
|
+
<MetricCard label="Evidence debt" value={dashboard.summary.needsEvidence} sublabel={`${evidenceDebtGroups.length} grouped area${evidenceDebtGroups.length === 1 ? '' : 's'} still need stronger downstream evidence`} tone={dashboard.summary.needsEvidence > 0 ? 'neutral' : 'green'} icon="◌" />
|
|
222
327
|
<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">
|
|
328
|
+
<div className="signal-text">High-priority review and evidence debt are now separate concepts: some records already deserve review, while others still need more live downstream evidence first.</div>
|
|
224
329
|
</div>
|
|
225
330
|
</div>
|
|
226
331
|
</SectionFrame>
|
|
@@ -235,7 +340,7 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
|
|
|
235
340
|
<div key={entry.targetType} className="guide-dimension-card" style={{ borderLeftColor: `var(--${toneForTarget(entry.targetType) === 'neutral' ? 'text-muted' : toneForTarget(entry.targetType)})` }}>
|
|
236
341
|
<div style={{ fontSize: 12, fontWeight: 700, color: 'var(--text)' }}>{labelForTarget(entry.targetType)}</div>
|
|
237
342
|
<div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 8, lineHeight: 1.7 }}>
|
|
238
|
-
{entry.total} total • {entry.effective} effective • {entry.mixed} mixed • {entry.regressed} regressed • {entry.
|
|
343
|
+
{entry.total} total • {entry.effective} effective • {entry.mixed} mixed • {entry.regressed} regressed • {entry.needsEvidence} need evidence • {entry.needsReview} need review • {entry.stalled} stalled
|
|
239
344
|
</div>
|
|
240
345
|
</div>
|
|
241
346
|
)) : (
|
|
@@ -281,6 +386,8 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
|
|
|
281
386
|
{record.reasons.slice(0, 3).map((reason, idx) => (
|
|
282
387
|
<div key={`${record.id}-${idx}`} className="signal-text">• {reason}</div>
|
|
283
388
|
))}
|
|
389
|
+
<div className="signal-text">closure · {record.closureState} · {record.closureSummary}</div>
|
|
390
|
+
{record.closureNeeds[0] ? <div className="signal-text">needs · {record.closureNeeds[0]}</div> : null}
|
|
284
391
|
{record.recommendedAction ? <div className="signal-text">→ {record.recommendedAction}</div> : null}
|
|
285
392
|
</div>
|
|
286
393
|
|
|
@@ -303,27 +410,55 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
|
|
|
303
410
|
</SectionFrame>
|
|
304
411
|
|
|
305
412
|
<SectionFrame
|
|
306
|
-
eyebrow="
|
|
307
|
-
title="
|
|
308
|
-
description="
|
|
413
|
+
eyebrow="Evidence debt"
|
|
414
|
+
title="What proof still needs stronger evidence"
|
|
415
|
+
description="Repeated dry-run and low-closure records stay visible here as grouped debt areas. They should not compete with high-leverage review as if they were unrelated proof units."
|
|
309
416
|
>
|
|
310
417
|
<div style={{ display: 'grid', gap: 10 }}>
|
|
311
|
-
{
|
|
312
|
-
<div key={
|
|
418
|
+
{evidenceDebtGroups.length > 0 ? evidenceDebtGroups.map((group) => (
|
|
419
|
+
<div key={group.groupKey} style={{ padding: '14px 16px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.72)' }}>
|
|
313
420
|
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
|
314
|
-
<div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{
|
|
315
|
-
<span className="badge badge-gray">
|
|
421
|
+
<div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{group.title}</div>
|
|
422
|
+
<span className="badge badge-gray">{group.recordCount} record{group.recordCount === 1 ? '' : 's'}</span>
|
|
423
|
+
</div>
|
|
424
|
+
<div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.6 }}>{group.summary}</div>
|
|
425
|
+
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 10 }}>
|
|
426
|
+
{group.route ? <span className="badge badge-purple">{group.route}</span> : null}
|
|
427
|
+
{group.relatedCapabilities.slice(0, 2).map((capability) => <span key={`${group.groupKey}-${capability}`} className="badge badge-gray">{capability}</span>)}
|
|
428
|
+
{group.relatedMotifIds.slice(0, 2).map((motifId) => <span key={`${group.groupKey}-${motifId}`} className="badge badge-gray">{motifId.replace(/^motif_/, '')}</span>)}
|
|
316
429
|
</div>
|
|
317
|
-
<div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.6 }}>{record.summary}</div>
|
|
318
430
|
<div style={{ display: 'grid', gap: 6, marginTop: 10 }}>
|
|
319
|
-
{
|
|
320
|
-
{
|
|
431
|
+
{group.needs.slice(0, 2).map((need, idx) => <div key={`${group.groupKey}-need-${idx}`} className="signal-text">• {need}</div>)}
|
|
432
|
+
{group.examples.length > 0 ? <div className="signal-text">examples · {group.examples.join(' • ')}</div> : null}
|
|
321
433
|
</div>
|
|
322
434
|
</div>
|
|
323
|
-
)) : <div className="signal-text">No
|
|
435
|
+
)) : <div className="signal-text">No current evidence debt groups. The proof layer is either empty or stronger records are already moving into review/settled paths.</div>}
|
|
324
436
|
</div>
|
|
325
437
|
</SectionFrame>
|
|
326
438
|
|
|
439
|
+
{stalledDebtGroups.length > 0 ? (
|
|
440
|
+
<SectionFrame
|
|
441
|
+
eyebrow="Stalled debt"
|
|
442
|
+
title="Proof that is aging without closure"
|
|
443
|
+
description="These debt groups have remained open long enough that the operator should explicitly revisit them instead of assuming more time alone will improve the proof state."
|
|
444
|
+
>
|
|
445
|
+
<div style={{ display: 'grid', gap: 10 }}>
|
|
446
|
+
{stalledDebtGroups.map((group) => (
|
|
447
|
+
<div key={group.groupKey} style={{ padding: '14px 16px', borderRadius: 18, border: '1px solid var(--border)', background: 'rgba(255,255,255,0.72)' }}>
|
|
448
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
|
449
|
+
<div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{group.title}</div>
|
|
450
|
+
<span className="badge badge-yellow">stalled</span>
|
|
451
|
+
</div>
|
|
452
|
+
<div style={{ fontSize: 12, color: 'var(--text-dim)', marginTop: 6, lineHeight: 1.6 }}>{group.summary}</div>
|
|
453
|
+
<div style={{ display: 'grid', gap: 6, marginTop: 10 }}>
|
|
454
|
+
{group.needs.slice(0, 2).map((need, idx) => <div key={`${group.groupKey}-stalled-${idx}`} className="signal-text">• {need}</div>)}
|
|
455
|
+
</div>
|
|
456
|
+
</div>
|
|
457
|
+
))}
|
|
458
|
+
</div>
|
|
459
|
+
</SectionFrame>
|
|
460
|
+
) : null}
|
|
461
|
+
|
|
327
462
|
<div className="grid-2">
|
|
328
463
|
<SectionFrame
|
|
329
464
|
eyebrow="Verified"
|
|
@@ -389,8 +524,11 @@ export default function ProofClient({ initialDashboard }: { initialDashboard: Pr
|
|
|
389
524
|
<span className={`badge badge-${toneForTarget(record.targetType)}`}>{labelForTarget(record.targetType)}</span>
|
|
390
525
|
<span className={`badge badge-${toneForOutcome(record.outcomeState)}`}>{labelForOutcome(record.outcomeState)}</span>
|
|
391
526
|
<span className="badge badge-gray">{record.reviewStatus}</span>
|
|
527
|
+
<span className={`badge badge-${toneForClosureState(record.closureState)}`}>{record.closureState}</span>
|
|
392
528
|
</div>
|
|
393
529
|
</div>
|
|
530
|
+
<div className="signal-text" style={{ marginTop: 10 }}>closure · {record.closureSummary}</div>
|
|
531
|
+
{record.closureNeeds[0] ? <div className="signal-text" style={{ marginTop: 6 }}>needs · {record.closureNeeds[0]}</div> : null}
|
|
394
532
|
{record.latestReview?.rationale ? <div className="signal-text" style={{ marginTop: 10 }}>review rationale · {record.latestReview.rationale}</div> : null}
|
|
395
533
|
</div>
|
|
396
534
|
)) : null}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import ProofClient from './client'
|
|
2
2
|
import { loadProofDashboardSummary } from '@/lib/proof'
|
|
3
|
+
import { loadLatestTheoryConformanceResult } from '@/lib/theory'
|
|
3
4
|
|
|
4
5
|
export const dynamic = 'force-dynamic'
|
|
5
6
|
|
|
6
7
|
export default function ProofPage() {
|
|
7
8
|
const dashboard = loadProofDashboardSummary()
|
|
8
|
-
|
|
9
|
+
const conformance = loadLatestTheoryConformanceResult()
|
|
10
|
+
return <ProofClient initialDashboard={dashboard} initialConformance={conformance} />
|
|
9
11
|
}
|
package/dashboard/lib/data.ts
CHANGED
|
@@ -199,6 +199,8 @@ export interface PressureRouteRecommendation {
|
|
|
199
199
|
proofSummary?: string
|
|
200
200
|
proofReasons?: string[]
|
|
201
201
|
proofLaneKeys?: string[]
|
|
202
|
+
proofClosureState?: import('./proof').ProofLaneClosureState
|
|
203
|
+
proofDebtSummary?: string
|
|
202
204
|
}
|
|
203
205
|
|
|
204
206
|
export interface PressureIntervention {
|
|
@@ -1442,7 +1444,7 @@ export function loadResolvedTopologyApplyPlans(): ResolvedTopologyApplyPlan[] {
|
|
|
1442
1444
|
const existing = latestByPlan.get(record.planId)
|
|
1443
1445
|
const recordAt = record.executedAt ?? record.rolledBackAt ?? record.createdAt
|
|
1444
1446
|
const existingAt = existing ? (existing.executedAt ?? existing.rolledBackAt ?? existing.createdAt) : ''
|
|
1445
|
-
if (!existing || recordAt
|
|
1447
|
+
if (!existing || recordAt >= existingAt) latestByPlan.set(record.planId, record)
|
|
1446
1448
|
}
|
|
1447
1449
|
return plans
|
|
1448
1450
|
.map((plan) => {
|
|
@@ -2054,6 +2056,19 @@ function strongerProofTier(current: ProofSteeringTier | undefined, next: ProofSt
|
|
|
2054
2056
|
return proofTierWeight(next) > proofTierWeight(current) ? next : current
|
|
2055
2057
|
}
|
|
2056
2058
|
|
|
2059
|
+
function proofClosureWeight(state: import('./proof').ProofLaneClosureState | undefined): number {
|
|
2060
|
+
if (state === 'trusted-with-debt') return 5
|
|
2061
|
+
if (state === 'stalled') return 4
|
|
2062
|
+
if (state === 'needs-review') return 3
|
|
2063
|
+
if (state === 'needs-evidence') return 2
|
|
2064
|
+
return 1
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
function strongerProofClosureState(current: import('./proof').ProofLaneClosureState | undefined, next: import('./proof').ProofLaneClosureState): import('./proof').ProofLaneClosureState {
|
|
2068
|
+
if (!current) return next
|
|
2069
|
+
return proofClosureWeight(next) > proofClosureWeight(current) ? next : current
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2057
2072
|
function applyProofInfluenceToRoute(params: {
|
|
2058
2073
|
recommendation: PressureRouteRecommendation
|
|
2059
2074
|
signal: PressureSignal
|
|
@@ -2071,6 +2086,8 @@ function applyProofInfluenceToRoute(params: {
|
|
|
2071
2086
|
const proofLaneKeys: string[] = []
|
|
2072
2087
|
let proofSummary: string | undefined
|
|
2073
2088
|
let proofTier: ProofSteeringTier | undefined
|
|
2089
|
+
let proofClosureState: import('./proof').ProofLaneClosureState | undefined
|
|
2090
|
+
let proofDebtSummary: string | undefined
|
|
2074
2091
|
let proofInfluence: 'none' | 'explanatory' | 'weighted' = 'none'
|
|
2075
2092
|
|
|
2076
2093
|
const routeLane = proofSteering.byRoute[recommendation.route]
|
|
@@ -2079,11 +2096,14 @@ function applyProofInfluenceToRoute(params: {
|
|
|
2079
2096
|
proofReasons.push(...routeLane.reasons.slice(0, 2))
|
|
2080
2097
|
proofSummary = proofSummary ?? routeLane.summary
|
|
2081
2098
|
proofTier = strongerProofTier(proofTier, routeLane.evidenceTier)
|
|
2099
|
+
proofClosureState = strongerProofClosureState(proofClosureState, routeLane.closureState)
|
|
2100
|
+
proofDebtSummary = proofDebtSummary ?? routeLane.debtSummary
|
|
2082
2101
|
|
|
2083
2102
|
if (routeLane.evidenceTier === 'trusted') {
|
|
2084
|
-
confidence = Math.min(0.95, confidence + (routeLane.score >= 4 ? 0.06 : 0.04))
|
|
2103
|
+
confidence = Math.min(0.95, confidence + (routeLane.trustedWithDebt ? 0.04 : routeLane.score >= 4 ? 0.06 : 0.04))
|
|
2085
2104
|
proofInfluence = 'weighted'
|
|
2086
2105
|
reasons.push(`Proof steering: ${routeLane.summary}`)
|
|
2106
|
+
if (routeLane.debtSummary) reasons.push(`Proof debt: ${routeLane.debtSummary}`)
|
|
2087
2107
|
} else if (routeLane.evidenceTier === 'caution') {
|
|
2088
2108
|
if (recommendation.route !== 'manual-review' && routeLane.score <= -3 && (recommendation.route === 'generalize' || recommendation.route === 'evolve')) {
|
|
2089
2109
|
route = 'manual-review'
|
|
@@ -2091,14 +2111,17 @@ function applyProofInfluenceToRoute(params: {
|
|
|
2091
2111
|
confidence = Math.max(0.66, confidence - 0.02)
|
|
2092
2112
|
proofInfluence = 'weighted'
|
|
2093
2113
|
reasons.push(`Proof steering: ${routeLane.summary} Governance now prefers explicit operator review before retrying ${recommendation.route}.`)
|
|
2114
|
+
if (routeLane.debtSummary) reasons.push(`Proof debt: ${routeLane.debtSummary}`)
|
|
2094
2115
|
} else {
|
|
2095
2116
|
confidence = Math.max(0.4, confidence - 0.08)
|
|
2096
2117
|
proofInfluence = 'weighted'
|
|
2097
2118
|
reasons.push(`Proof steering: ${routeLane.summary}`)
|
|
2119
|
+
if (routeLane.debtSummary) reasons.push(`Proof debt: ${routeLane.debtSummary}`)
|
|
2098
2120
|
}
|
|
2099
2121
|
} else {
|
|
2100
2122
|
if (proofInfluence === 'none') proofInfluence = 'explanatory'
|
|
2101
2123
|
reasons.push(`Proof steering: ${routeLane.summary}`)
|
|
2124
|
+
if (routeLane.debtSummary) reasons.push(`Proof debt: ${routeLane.debtSummary}`)
|
|
2102
2125
|
}
|
|
2103
2126
|
}
|
|
2104
2127
|
|
|
@@ -2111,10 +2134,13 @@ function applyProofInfluenceToRoute(params: {
|
|
|
2111
2134
|
proofReasons.push(...strongestConceptLane.reasons.slice(0, 2))
|
|
2112
2135
|
proofSummary = proofSummary ?? strongestConceptLane.summary
|
|
2113
2136
|
proofTier = strongerProofTier(proofTier, strongestConceptLane.evidenceTier)
|
|
2137
|
+
proofClosureState = strongerProofClosureState(proofClosureState, strongestConceptLane.closureState)
|
|
2138
|
+
proofDebtSummary = proofDebtSummary ?? strongestConceptLane.debtSummary
|
|
2114
2139
|
if (strongestConceptLane.evidenceTier === 'trusted') {
|
|
2115
|
-
confidence = Math.min(0.95, confidence + 0.02)
|
|
2140
|
+
confidence = Math.min(0.95, confidence + (strongestConceptLane.trustedWithDebt ? 0.01 : 0.02))
|
|
2116
2141
|
proofInfluence = 'weighted'
|
|
2117
2142
|
reasons.push(`Proof steering: ${strongestConceptLane.summary}`)
|
|
2143
|
+
if (strongestConceptLane.debtSummary) reasons.push(`Proof debt: ${strongestConceptLane.debtSummary}`)
|
|
2118
2144
|
} else if (strongestConceptLane.evidenceTier === 'caution') {
|
|
2119
2145
|
confidence = Math.max(0.4, confidence - 0.03)
|
|
2120
2146
|
if (proofInfluence === 'none') proofInfluence = 'weighted'
|
|
@@ -2137,6 +2163,8 @@ function applyProofInfluenceToRoute(params: {
|
|
|
2137
2163
|
proofSummary,
|
|
2138
2164
|
proofReasons: [...new Set(proofReasons)].slice(0, 4),
|
|
2139
2165
|
proofLaneKeys: [...new Set(proofLaneKeys)],
|
|
2166
|
+
proofClosureState,
|
|
2167
|
+
proofDebtSummary,
|
|
2140
2168
|
}
|
|
2141
2169
|
}
|
|
2142
2170
|
|