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.
@@ -10,6 +10,9 @@ import {
10
10
  loadResolvedTopologyReviewCandidates,
11
11
  loadResolvedOntologyExtensions,
12
12
  type PressureIntervention,
13
+ type PressureInterventionType,
14
+ type ProofSteeringInfluence,
15
+ type ProofSteeringTier,
13
16
  type ResolvedPressureSignal,
14
17
  type ResolvedPressureMotif,
15
18
  type ResolvedTransferEvent,
@@ -58,6 +61,8 @@ export interface ResolvedProofRecord {
58
61
  relatedMotifIds?: string[]
59
62
  relatedTransferEventIds?: string[]
60
63
  semanticConceptIds?: string[]
64
+ steeringRoutes?: PressureInterventionType[]
65
+ steeringConceptIds?: string[]
61
66
  recommendedAction?: string
62
67
  }
63
68
 
@@ -85,10 +90,43 @@ export interface ProofTargetBreakdown {
85
90
  insufficientEvidence: number
86
91
  }
87
92
 
93
+ export interface ProofSteeringLaneSummary {
94
+ laneKey: string
95
+ laneKind: 'route' | 'semantic'
96
+ route?: PressureInterventionType
97
+ conceptId?: string
98
+ targetTypes: ProofTargetType[]
99
+ evidenceTier: ProofSteeringTier
100
+ score: number
101
+ summary: string
102
+ reasons: string[]
103
+ recordIds: string[]
104
+ trustedCount: number
105
+ cautionCount: number
106
+ boundedCount: number
107
+ candidateCount: number
108
+ }
109
+
110
+ export interface ProofSteeringSummary {
111
+ trustedLanes: number
112
+ cautionLanes: number
113
+ boundedLanes: number
114
+ candidateLanes: number
115
+ priorityReview: number
116
+ routeLanes: ProofSteeringLaneSummary[]
117
+ semanticLanes: ProofSteeringLaneSummary[]
118
+ byRoute: Partial<Record<PressureInterventionType, ProofSteeringLaneSummary>>
119
+ byConceptId: Record<string, ProofSteeringLaneSummary>
120
+ highestPriority: ResolvedProofRecord[]
121
+ candidateEvidence: ResolvedProofRecord[]
122
+ }
123
+
88
124
  export interface ProofDashboardSummary {
89
125
  summary: ProofSummary
126
+ steering: ProofSteeringSummary
90
127
  records: ResolvedProofRecord[]
91
128
  reviewQueue: ResolvedProofRecord[]
129
+ candidateQueue: ResolvedProofRecord[]
92
130
  recentVerified: ResolvedProofRecord[]
93
131
  recentContested: ResolvedProofRecord[]
94
132
  byTargetType: ProofTargetBreakdown[]
@@ -186,8 +224,8 @@ function latestReviewByRecord(): Map<string, ProofReviewRecord> {
186
224
  }
187
225
 
188
226
  function buildInterventionProofRecords(): ResolvedProofRecord[] {
189
- const signals = loadResolvedPressureSignals()
190
- const motifs = loadPressureMotifs()
227
+ const signals = loadResolvedPressureSignals({ includeProofSteering: false })
228
+ const motifs = loadPressureMotifs({ includeProofSteering: false })
191
229
 
192
230
  return loadPressureInterventions().map((intervention) => {
193
231
  const linkedSignals = signals.filter((signal) =>
@@ -236,6 +274,7 @@ function buildInterventionProofRecords(): ResolvedProofRecord[] {
236
274
  linkedSignals: linkedSignals.length,
237
275
  linkedMotifs: linkedMotifs.length,
238
276
  addressed: lifecycleItems.filter((item) => item.lifecycle === 'addressed').length,
277
+ dryRun: intervention.status === 'dry-run' ? 1 : 0,
239
278
  },
240
279
  relatedProjectIds: uniqueStrings([intervention.projectId, ...linkedSignals.map((signal) => signal.projectId), ...linkedMotifs.flatMap((motif) => motif.projectIds)]),
241
280
  relatedSignalIds: linkedSignals.map((signal) => signal.id),
@@ -245,6 +284,7 @@ function buildInterventionProofRecords(): ResolvedProofRecord[] {
245
284
  ...linkedSignals.flatMap((signal) => signal.semanticConceptIds ?? []),
246
285
  ...linkedMotifs.flatMap((motif) => motif.semanticConceptIds ?? []),
247
286
  ]),
287
+ steeringRoutes: [intervention.interventionType],
248
288
  recommendedAction: outcomeState === 'effective'
249
289
  ? 'Verify if this resolving pattern should remain a trusted lane.'
250
290
  : outcomeState === 'mixed'
@@ -259,8 +299,8 @@ function buildInterventionProofRecords(): ResolvedProofRecord[] {
259
299
  }
260
300
 
261
301
  function buildTransferProofRecords(): ResolvedProofRecord[] {
262
- const motifs = loadPressureMotifs()
263
- const signals = loadResolvedPressureSignals()
302
+ const motifs = loadPressureMotifs({ includeProofSteering: false })
303
+ const signals = loadResolvedPressureSignals({ includeProofSteering: false })
264
304
 
265
305
  return loadTransferEvents()
266
306
  .filter((event) => event.status === 'realized')
@@ -306,6 +346,7 @@ function buildTransferProofRecords(): ResolvedProofRecord[] {
306
346
  ...linkedSignals.flatMap((signal) => signal.semanticConceptIds ?? []),
307
347
  ...linkedMotifs.flatMap((motif) => motif.semanticConceptIds ?? []),
308
348
  ]),
349
+ steeringRoutes: ['generalize'],
309
350
  recommendedAction: outcomeState === 'effective'
310
351
  ? 'Verify whether this transfer pattern should be treated as proven reusable evidence.'
311
352
  : outcomeState === 'mixed'
@@ -319,8 +360,8 @@ function buildTransferProofRecords(): ResolvedProofRecord[] {
319
360
 
320
361
  function buildTopologyProofRecords(): ResolvedProofRecord[] {
321
362
  const candidatesById = new Map(loadResolvedTopologyReviewCandidates().map((candidate) => [candidate.id, candidate]))
322
- const signals = loadResolvedPressureSignals()
323
- const motifs = loadPressureMotifs()
363
+ const signals = loadResolvedPressureSignals({ includeProofSteering: false })
364
+ const motifs = loadPressureMotifs({ includeProofSteering: false })
324
365
 
325
366
  return loadResolvedTopologyApplyPlans().map((plan) => {
326
367
  const candidate = candidatesById.get(plan.candidateId)
@@ -372,6 +413,7 @@ function buildTopologyProofRecords(): ResolvedProofRecord[] {
372
413
  ...linkedSignals.flatMap((signal) => signal.semanticConceptIds ?? []),
373
414
  ...linkedMotifs.flatMap((motif) => motif.semanticConceptIds ?? []),
374
415
  ]),
416
+ steeringRoutes: ['manual-review'],
375
417
  recommendedAction: outcomeState === 'effective'
376
418
  ? 'Verify this topology change if the structural relief looks durable.'
377
419
  : outcomeState === 'mixed'
@@ -386,12 +428,12 @@ function buildTopologyProofRecords(): ResolvedProofRecord[] {
386
428
  }
387
429
 
388
430
  function buildOntologyProofRecords(): ResolvedProofRecord[] {
389
- const signals = loadResolvedPressureSignals()
390
- const motifs = loadPressureMotifs()
431
+ const signals = loadResolvedPressureSignals({ includeProofSteering: false })
432
+ const motifs = loadPressureMotifs({ includeProofSteering: false })
391
433
  const transfers = loadTransferEvents()
392
434
  const topologyCandidates = loadResolvedTopologyReviewCandidates()
393
435
 
394
- return loadResolvedOntologyExtensions()
436
+ return loadResolvedOntologyExtensions({ includeProofSteering: false })
395
437
  .filter((concept) => concept.status === 'active')
396
438
  .map((concept) => {
397
439
  const boundSignals = signals.filter((signal) => signal.semanticConceptIds?.includes(concept.id))
@@ -437,6 +479,7 @@ function buildOntologyProofRecords(): ResolvedProofRecord[] {
437
479
  relatedMotifIds: boundMotifs.map((motif) => motif.id),
438
480
  relatedTransferEventIds: boundTransfers.map((event) => event.id),
439
481
  semanticConceptIds: [concept.id],
482
+ steeringConceptIds: [concept.id],
440
483
  recommendedAction: outcomeState === 'effective'
441
484
  ? 'Verify this concept if semantic adoption looks stable enough to trust.'
442
485
  : outcomeState === 'mixed'
@@ -490,6 +533,7 @@ function buildEvolutionProofRecords(): ResolvedProofRecord[] {
490
533
  samplesBefore: impact.samplesBefore,
491
534
  samplesAfter: impact.samplesAfter,
492
535
  },
536
+ steeringRoutes: ['evolve'],
493
537
  recommendedAction: outcomeState === 'effective'
494
538
  ? 'Verify this evolution result if the lower correction rate looks durable.'
495
539
  : outcomeState === 'regressed'
@@ -501,6 +545,216 @@ function buildEvolutionProofRecords(): ResolvedProofRecord[] {
501
545
  })
502
546
  }
503
547
 
548
+
549
+ function routeLabel(route: PressureInterventionType): string {
550
+ return route.replace(/-/g, ' ')
551
+ }
552
+
553
+ function steeringMetaForRecord(record: ResolvedProofRecord): { tier: ProofSteeringTier; score: number; summary: string } {
554
+ const dryRun = record.metrics?.dryRun === 1
555
+ if (dryRun) {
556
+ return {
557
+ tier: 'candidate',
558
+ score: 0,
559
+ summary: 'Dry-run proof remains candidate-only evidence until live downstream effects exist.',
560
+ }
561
+ }
562
+ if (record.reviewStatus === 'contested' && record.outcomeState === 'regressed') {
563
+ return {
564
+ tier: 'caution',
565
+ score: -4,
566
+ summary: 'Contested regressed proof strongly increases caution and review bias on this lane.',
567
+ }
568
+ }
569
+ if (record.reviewStatus === 'verified' && record.outcomeState === 'regressed') {
570
+ return {
571
+ tier: 'caution',
572
+ score: -4,
573
+ summary: 'Verified regressed proof strongly increases caution on this lane.',
574
+ }
575
+ }
576
+ if (record.reviewStatus === 'contested') {
577
+ return {
578
+ tier: 'caution',
579
+ score: -3,
580
+ summary: 'Contested proof should bias the system toward caution and re-review.',
581
+ }
582
+ }
583
+ if (record.outcomeState === 'regressed') {
584
+ return {
585
+ tier: 'caution',
586
+ score: -3,
587
+ summary: 'Regressed proof should make this lane less trusted until it is re-evaluated.',
588
+ }
589
+ }
590
+ if (record.reviewStatus === 'verified' && record.outcomeState === 'effective') {
591
+ return {
592
+ tier: 'trusted',
593
+ score: 4,
594
+ summary: 'Verified effective proof can strengthen trust in this lane.',
595
+ }
596
+ }
597
+ if (record.reviewStatus === 'verified' && record.outcomeState === 'mixed') {
598
+ return {
599
+ tier: 'bounded',
600
+ score: 1,
601
+ summary: 'Verified mixed proof adds signal, but still keeps steering bounded.',
602
+ }
603
+ }
604
+ if (record.outcomeState === 'effective') {
605
+ return {
606
+ tier: 'bounded',
607
+ score: 1,
608
+ summary: 'Effective evidence exists, but remains bounded until review strengthens trust.',
609
+ }
610
+ }
611
+ if (record.reviewStatus === 'deferred' || record.outcomeState === 'mixed' || record.outcomeState === 'measuring') {
612
+ return {
613
+ tier: 'bounded',
614
+ score: 0,
615
+ summary: 'This proof remains bounded and should guide review more than lane trust.',
616
+ }
617
+ }
618
+ return {
619
+ tier: 'candidate',
620
+ score: 0,
621
+ summary: 'Insufficient-evidence proof stays candidate-only until stronger downstream evidence appears.',
622
+ }
623
+ }
624
+
625
+ type MutableProofLane = {
626
+ laneKey: string
627
+ laneKind: 'route' | 'semantic'
628
+ route?: PressureInterventionType
629
+ conceptId?: string
630
+ targetTypes: Set<ProofTargetType>
631
+ recordIds: string[]
632
+ reasons: string[]
633
+ summaries: string[]
634
+ score: number
635
+ trustedCount: number
636
+ cautionCount: number
637
+ boundedCount: number
638
+ candidateCount: number
639
+ }
640
+
641
+ function laneTierWeight(tier: ProofSteeringTier): number {
642
+ return tier === 'caution' ? 4 : tier === 'trusted' ? 3 : tier === 'bounded' ? 2 : 1
643
+ }
644
+
645
+ function finalizeProofLane(lane: MutableProofLane): ProofSteeringLaneSummary {
646
+ const evidenceTier: ProofSteeringTier = lane.cautionCount > 0 && lane.score <= -2
647
+ ? 'caution'
648
+ : lane.trustedCount > 0 && lane.score >= 3
649
+ ? 'trusted'
650
+ : lane.candidateCount > 0 && lane.trustedCount === 0 && lane.cautionCount === 0 && lane.boundedCount === 0
651
+ ? 'candidate'
652
+ : 'bounded'
653
+ const label = lane.route ? routeLabel(lane.route) : lane.conceptId ?? lane.laneKey
654
+ const summary = evidenceTier === 'caution'
655
+ ? `${label} now carries regressed or contested proof and should be treated more cautiously.`
656
+ : evidenceTier === 'trusted'
657
+ ? `${label} now carries verified/effective proof that can strengthen trust modestly.`
658
+ : evidenceTier === 'candidate'
659
+ ? `${label} currently has only dry-run or insufficient evidence and should stay bounded.`
660
+ : `${label} has some proof history, but steering should remain bounded.`
661
+ return {
662
+ laneKey: lane.laneKey,
663
+ laneKind: lane.laneKind,
664
+ route: lane.route,
665
+ conceptId: lane.conceptId,
666
+ targetTypes: [...lane.targetTypes.values()].sort(),
667
+ evidenceTier,
668
+ score: lane.score,
669
+ summary,
670
+ reasons: [...new Set([...lane.summaries, ...lane.reasons])].slice(0, 4),
671
+ recordIds: lane.recordIds,
672
+ trustedCount: lane.trustedCount,
673
+ cautionCount: lane.cautionCount,
674
+ boundedCount: lane.boundedCount,
675
+ candidateCount: lane.candidateCount,
676
+ }
677
+ }
678
+
679
+ export function loadProofSteeringSummary(records = loadResolvedProofRecords()): ProofSteeringSummary {
680
+ const routeMap = new Map<string, MutableProofLane>()
681
+ const conceptMap = new Map<string, MutableProofLane>()
682
+ const openRecords = records.filter((record) => record.reviewStatus === 'open')
683
+ const priorityReview = openRecords.filter((record) => steeringMetaForRecord(record).tier !== 'candidate')
684
+ const candidateEvidence = openRecords.filter((record) => steeringMetaForRecord(record).tier === 'candidate')
685
+
686
+ function applyToLane(lane: MutableProofLane, record: ResolvedProofRecord) {
687
+ const meta = steeringMetaForRecord(record)
688
+ lane.targetTypes.add(record.targetType)
689
+ lane.recordIds.push(record.id)
690
+ lane.score += meta.score
691
+ lane.reasons.push(...record.reasons.slice(0, 2))
692
+ lane.summaries.push(meta.summary)
693
+ if (meta.tier === 'trusted') lane.trustedCount += 1
694
+ else if (meta.tier === 'caution') lane.cautionCount += 1
695
+ else if (meta.tier === 'bounded') lane.boundedCount += 1
696
+ else lane.candidateCount += 1
697
+ }
698
+
699
+ for (const record of records) {
700
+ for (const route of record.steeringRoutes ?? []) {
701
+ const laneKey = `route:${route}`
702
+ const lane = routeMap.get(laneKey) ?? {
703
+ laneKey,
704
+ laneKind: 'route',
705
+ route,
706
+ targetTypes: new Set<ProofTargetType>(),
707
+ recordIds: [],
708
+ reasons: [],
709
+ summaries: [],
710
+ score: 0,
711
+ trustedCount: 0,
712
+ cautionCount: 0,
713
+ boundedCount: 0,
714
+ candidateCount: 0,
715
+ }
716
+ applyToLane(lane, record)
717
+ routeMap.set(laneKey, lane)
718
+ }
719
+ for (const conceptId of record.steeringConceptIds ?? []) {
720
+ const laneKey = `semantic:${conceptId}`
721
+ const lane = conceptMap.get(laneKey) ?? {
722
+ laneKey,
723
+ laneKind: 'semantic',
724
+ conceptId,
725
+ targetTypes: new Set<ProofTargetType>(),
726
+ recordIds: [],
727
+ reasons: [],
728
+ summaries: [],
729
+ score: 0,
730
+ trustedCount: 0,
731
+ cautionCount: 0,
732
+ boundedCount: 0,
733
+ candidateCount: 0,
734
+ }
735
+ applyToLane(lane, record)
736
+ conceptMap.set(laneKey, lane)
737
+ }
738
+ }
739
+
740
+ const routeLanes = [...routeMap.values()].map(finalizeProofLane).sort((a, b) => laneTierWeight(b.evidenceTier) - laneTierWeight(a.evidenceTier) || Math.abs(b.score) - Math.abs(a.score) || a.laneKey.localeCompare(b.laneKey))
741
+ const semanticLanes = [...conceptMap.values()].map(finalizeProofLane).sort((a, b) => laneTierWeight(b.evidenceTier) - laneTierWeight(a.evidenceTier) || Math.abs(b.score) - Math.abs(a.score) || a.laneKey.localeCompare(b.laneKey))
742
+
743
+ return {
744
+ trustedLanes: [...routeLanes, ...semanticLanes].filter((lane) => lane.evidenceTier === 'trusted').length,
745
+ cautionLanes: [...routeLanes, ...semanticLanes].filter((lane) => lane.evidenceTier === 'caution').length,
746
+ boundedLanes: [...routeLanes, ...semanticLanes].filter((lane) => lane.evidenceTier === 'bounded').length,
747
+ candidateLanes: [...routeLanes, ...semanticLanes].filter((lane) => lane.evidenceTier === 'candidate').length,
748
+ priorityReview: priorityReview.length,
749
+ routeLanes,
750
+ semanticLanes,
751
+ byRoute: Object.fromEntries(routeLanes.filter((lane) => lane.route).map((lane) => [lane.route!, lane])) as Partial<Record<PressureInterventionType, ProofSteeringLaneSummary>>,
752
+ byConceptId: Object.fromEntries(semanticLanes.filter((lane) => lane.conceptId).map((lane) => [lane.conceptId!, lane])),
753
+ highestPriority: priorityReview.slice(0, 8),
754
+ candidateEvidence: candidateEvidence.slice(0, 8),
755
+ }
756
+ }
757
+
504
758
  export function loadResolvedProofRecords(): ResolvedProofRecord[] {
505
759
  const latestReviews = latestReviewByRecord()
506
760
  const records = [
@@ -566,10 +820,13 @@ function buildTargetBreakdown(records: ResolvedProofRecord[]): ProofTargetBreakd
566
820
 
567
821
  export function loadProofDashboardSummary(): ProofDashboardSummary {
568
822
  const records = loadResolvedProofRecords()
823
+ const steering = loadProofSteeringSummary(records)
569
824
  return {
570
825
  summary: getProofSummary(records),
826
+ steering,
571
827
  records,
572
- reviewQueue: records.filter((record) => record.reviewStatus === 'open').slice(0, 12),
828
+ reviewQueue: steering.highestPriority,
829
+ candidateQueue: steering.candidateEvidence,
573
830
  recentVerified: records.filter((record) => record.reviewStatus === 'verified').slice(0, 8),
574
831
  recentContested: records.filter((record) => record.reviewStatus === 'contested').slice(0, 8),
575
832
  byTargetType: buildTargetBreakdown(records),