helixevo 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,6 +16,20 @@ function readJsonl<T>(filename: string): T[] {
16
16
  return readFileSync(path, 'utf-8').trim().split('\n').filter(Boolean).map(l => JSON.parse(l))
17
17
  }
18
18
 
19
+ function readOntologyJson<T>(filename: string, fallback: T): T {
20
+ const path = join(SG_DIR, 'ontology', filename)
21
+ if (!existsSync(path)) return fallback
22
+ return JSON.parse(readFileSync(path, 'utf-8'))
23
+ }
24
+
25
+ function readOntologyJsonl<T>(filename: string): T[] {
26
+ const path = join(SG_DIR, 'ontology', filename)
27
+ if (!existsSync(path)) return []
28
+ const raw = readFileSync(path, 'utf-8').trim()
29
+ if (!raw) return []
30
+ return raw.split('\n').filter(Boolean).map((l) => JSON.parse(l))
31
+ }
32
+
19
33
  // ─── Types ──────────────────────────────────────────────────────
20
34
 
21
35
  export type CognitiveRole = 'generalist' | 'specialist' | 'hybrid'
@@ -78,7 +92,7 @@ export interface CanaryEntry {
78
92
  skillSlug: string; version: string; deployedAt: string; expiresAt: string
79
93
  }
80
94
 
81
- export type ArtifactProvenance = 'native-evolution' | 'native-topology' | 'derived-history'
95
+ export type ArtifactProvenance = 'native-evolution' | 'native-topology' | 'native-ontology' | 'derived-history'
82
96
  export type ActivationProvenance = 'capture-derived' | 'project-analysis' | 'derived-failure'
83
97
  export type PressureProvenance = 'failure-native' | 'project-analysis-native' | 'failure-derived' | 'profile-gap-derived'
84
98
 
@@ -497,9 +511,79 @@ export interface TopologyDashboardSummary {
497
511
  candidates: ResolvedTopologyReviewCandidate[]
498
512
  }
499
513
 
514
+ export type OntologyConceptKind = 'entity' | 'relation-subtype' | 'capability' | 'pressure-type' | 'topology-motif' | 'health-signal' | 'governance-pattern'
515
+ export type OntologyLayer = 'kernel' | 'extension' | 'frontier'
516
+ export type OntologyReviewDecisionStatus = 'promote' | 'reject' | 'defer'
517
+ export type OntologyReviewStatus = 'open' | 'promoted' | 'rejected' | 'deferred'
518
+
519
+ export interface OntologyKernelSnapshot {
520
+ version: string
521
+ updatedAt: string
522
+ pillars: string[]
523
+ layers: string[]
524
+ entityNames: string[]
525
+ relationFamilies: string[]
526
+ mutationOperations: string[]
527
+ invariantIds: string[]
528
+ }
529
+
530
+ export interface OntologyConcept {
531
+ id: string
532
+ name: string
533
+ conceptKind: OntologyConceptKind
534
+ layer: OntologyLayer
535
+ status: 'active' | 'provisional' | 'deprecated'
536
+ createdAt: string
537
+ parentConceptId?: string
538
+ description?: string
539
+ aliases?: string[]
540
+ promotionCriteria?: string[]
541
+ migrationMap?: Record<string, string>
542
+ reviewKey?: string
543
+ lastObservedAt?: string
544
+ sourceSummary?: string
545
+ projectIds?: string[]
546
+ evidenceIds?: string[]
547
+ observationCount?: number
548
+ confidence?: number
549
+ relatedSignalIds?: string[]
550
+ relatedMotifIds?: string[]
551
+ relatedReviewIds?: string[]
552
+ relatedTransferEventIds?: string[]
553
+ derivedFromKinds?: string[]
554
+ }
555
+
556
+ export interface OntologyReviewDecision {
557
+ id: string
558
+ conceptId: string
559
+ decision: OntologyReviewDecisionStatus
560
+ decidedAt: string
561
+ governanceMode: GovernanceModeName
562
+ rationale: string
563
+ decidedBy?: 'operator' | 'system'
564
+ }
565
+
566
+ export interface ResolvedOntologyConcept extends OntologyConcept {
567
+ reviewStatus: OntologyReviewStatus
568
+ latestReview?: OntologyReviewDecision
569
+ lastActivityAt: string
570
+ }
571
+
572
+ export interface OntologyChangeEvent {
573
+ id: string
574
+ timestamp: string
575
+ changeType: 'concept-hypothesized' | 'concept-promoted' | 'concept-rejected' | 'concept-split' | 'concept-merged' | 'concept-deprecated' | 'relation-refined' | 'mapping-migrated' | 'invariant-added' | 'invariant-relaxed'
576
+ conceptIds: string[]
577
+ reason: string
578
+ evidenceIds?: string[]
579
+ proposalId?: string
580
+ approvedBy?: string
581
+ ontologyVersion?: string
582
+ }
583
+
500
584
  export interface OntologyDashboardSummary {
501
585
  specVersion: string
502
- source: 'graph' | 'compat-derived'
586
+ source: 'graph' | 'compat-derived' | 'hybrid-native-derived'
503
587
  skillRoles: Record<CognitiveRole, number>
504
588
  stabilityStates: Record<StabilityState, number>
505
589
  plasticityStates: Record<PlasticityState, number>
@@ -551,6 +635,18 @@ export interface OntologyDashboardSummary {
551
635
  candidate: number
552
636
  rejected: number
553
637
  }
638
+ ontologyLoop: {
639
+ kernelConcepts: number
640
+ extensions: number
641
+ frontier: number
642
+ reviewOpen: number
643
+ promoted: number
644
+ rejected: number
645
+ deferred: number
646
+ deprecated: number
647
+ changeEvents: number
648
+ byConceptKind: Partial<Record<OntologyConceptKind, number>>
649
+ }
554
650
  governance: {
555
651
  activeMode: GovernanceModeName
556
652
  derivedMode: GovernanceModeName
@@ -590,6 +686,15 @@ export interface OntologyDashboardSummary {
590
686
  }
591
687
  }
592
688
 
689
+ export interface OntologyControlDashboardSummary {
690
+ governance: ActiveGovernanceSummary
691
+ kernel: OntologyKernelSnapshot
692
+ summary: OntologyDashboardSummary['ontologyLoop']
693
+ frontier: ResolvedOntologyConcept[]
694
+ extensions: OntologyConcept[]
695
+ recentChanges: OntologyChangeEvent[]
696
+ }
697
+
593
698
  const DASHBOARD_ONTOLOGY_SPEC_VERSION = '0.1.0'
594
699
 
595
700
  function emptyCounts<T extends string>(values: readonly T[]): Record<T, number> {
@@ -679,6 +784,207 @@ export function loadCanaries(): { entries: CanaryEntry[] } {
679
784
  return readJson<{ entries: CanaryEntry[] }>('canary-registry.json', { entries: [] })
680
785
  }
681
786
 
787
+ export function loadOntologyKernelSnapshot(): OntologyKernelSnapshot {
788
+ return readOntologyJson<OntologyKernelSnapshot>('kernel.json', {
789
+ version: DASHBOARD_ONTOLOGY_SPEC_VERSION,
790
+ updatedAt: '',
791
+ pillars: [
792
+ 'Operational World',
793
+ 'Perception / Pressure',
794
+ 'Working Memory / Activation',
795
+ 'Long-Term Memory',
796
+ 'Plasticity / Topology',
797
+ 'Evidence / Immune System',
798
+ 'Executive / Governance',
799
+ 'Metacognition / Health',
800
+ 'Time / Lineage',
801
+ ],
802
+ layers: ['kernel', 'extension', 'frontier'],
803
+ entityNames: [
804
+ 'ProjectRecord',
805
+ 'SessionRecord',
806
+ 'TaskRecord',
807
+ 'FailureRecord',
808
+ 'PressureSignal',
809
+ 'Capability',
810
+ 'SkillNode',
811
+ 'SkillRelation',
812
+ 'ActivationEvent',
813
+ 'MutationProposal',
814
+ 'TopologyChange',
815
+ 'EvidenceArtifact',
816
+ 'EvaluationResult',
817
+ 'TransferEvent',
818
+ 'GovernanceMode',
819
+ 'HealthMetric',
820
+ 'LineageRecord',
821
+ 'OntologyConcept',
822
+ 'OntologyChangeEvent',
823
+ ],
824
+ relationFamilies: [
825
+ 'belongs_to',
826
+ 'derived_from',
827
+ 'replaced_by',
828
+ 'parent_of',
829
+ 'child_of',
830
+ 'specializes',
831
+ 'generalizes_from',
832
+ 'depends_on',
833
+ 'enhances',
834
+ 'conflicts_with',
835
+ 'co_evolves_with',
836
+ 'covers',
837
+ 'activated_for',
838
+ 'suppressed_by',
839
+ 'contributed_to',
840
+ 'competed_with',
841
+ 'triggered_by',
842
+ 'validated_by',
843
+ 'contradicted_by',
844
+ 'survived_in',
845
+ 'requires_review',
846
+ 'proposed_due_to',
847
+ 'benefits',
848
+ 'transferred_to',
849
+ 'refined_by',
850
+ 'promoted_from',
851
+ 'executed_under',
852
+ 'deferred_by',
853
+ 'prioritized_by',
854
+ 'locked_by',
855
+ 'measures',
856
+ 'signals_weakness_in',
857
+ 'suggests_repair_for',
858
+ ],
859
+ mutationOperations: [
860
+ 'create_skill',
861
+ 'edit_skill',
862
+ 'specialize_skill',
863
+ 'generalize_skill',
864
+ 'promote_skill',
865
+ 'demote_skill',
866
+ 'retire_skill',
867
+ 'merge_skills',
868
+ 'split_skill',
869
+ 'rewire_relation',
870
+ 'prune_branch',
871
+ 'consolidate_cluster',
872
+ ],
873
+ invariantIds: [
874
+ 'accepted-change-requires-evidence',
875
+ 'specialist-requires-local-context',
876
+ 'promotion-requires-repeated-evidence',
877
+ 'relation-requires-family-and-confidence',
878
+ 'topology-change-preserves-lineage',
879
+ 'deprecated-state-remains-recoverable',
880
+ 'ontology-promotion-requires-migration',
881
+ 'frontier-concepts-stay-provisional',
882
+ 'transfer-requires-source-and-target',
883
+ 'high-risk-topology-change-requires-validation',
884
+ ],
885
+ })
886
+ }
887
+
888
+ export function loadOntologyExtensions(): OntologyConcept[] {
889
+ return readOntologyJson<OntologyConcept[]>('extensions.json', [])
890
+ .slice()
891
+ .sort((a, b) => (b.lastObservedAt ?? b.createdAt).localeCompare(a.lastObservedAt ?? a.createdAt) || a.name.localeCompare(b.name))
892
+ }
893
+
894
+ export function loadOntologyFrontier(): OntologyConcept[] {
895
+ return readOntologyJson<OntologyConcept[]>('frontier.json', [])
896
+ .slice()
897
+ .sort((a, b) => (b.lastObservedAt ?? b.createdAt).localeCompare(a.lastObservedAt ?? a.createdAt) || a.name.localeCompare(b.name))
898
+ }
899
+
900
+ export function loadOntologyReviewDecisions(): OntologyReviewDecision[] {
901
+ return readOntologyJsonl<OntologyReviewDecision>('reviews.jsonl')
902
+ .slice()
903
+ .sort((a, b) => b.decidedAt.localeCompare(a.decidedAt))
904
+ }
905
+
906
+ export function loadOntologyChangeEvents(): OntologyChangeEvent[] {
907
+ return readOntologyJsonl<OntologyChangeEvent>('change-log.jsonl')
908
+ .slice()
909
+ .sort((a, b) => b.timestamp.localeCompare(a.timestamp))
910
+ }
911
+
912
+ function ontologyStatusRank(status: OntologyReviewStatus): number {
913
+ return status === 'open' ? 4 : status === 'deferred' ? 3 : status === 'rejected' ? 2 : 1
914
+ }
915
+
916
+ export function loadResolvedOntologyFrontierConcepts(): ResolvedOntologyConcept[] {
917
+ const concepts = loadOntologyFrontier()
918
+ const latestByConcept = new Map<string, OntologyReviewDecision>()
919
+ for (const decision of loadOntologyReviewDecisions()) {
920
+ const existing = latestByConcept.get(decision.conceptId)
921
+ if (!existing || decision.decidedAt > existing.decidedAt) latestByConcept.set(decision.conceptId, decision)
922
+ }
923
+ return concepts
924
+ .map((concept) => {
925
+ const latestReview = latestByConcept.get(concept.id)
926
+ const reviewStatus: OntologyReviewStatus = latestReview?.decision === 'promote'
927
+ ? 'promoted'
928
+ : latestReview?.decision === 'reject'
929
+ ? 'rejected'
930
+ : latestReview?.decision === 'defer'
931
+ ? 'deferred'
932
+ : 'open'
933
+ return {
934
+ ...concept,
935
+ reviewStatus,
936
+ latestReview,
937
+ lastActivityAt: maxTimestamp(concept.lastObservedAt, latestReview?.decidedAt, concept.createdAt),
938
+ }
939
+ })
940
+ .sort((a, b) => ontologyStatusRank(b.reviewStatus) - ontologyStatusRank(a.reviewStatus)
941
+ || (b.confidence ?? 0) - (a.confidence ?? 0)
942
+ || (b.observationCount ?? 0) - (a.observationCount ?? 0)
943
+ || b.lastActivityAt.localeCompare(a.lastActivityAt)
944
+ || a.name.localeCompare(b.name))
945
+ }
946
+
947
+ function ontologyKindCounts(): Partial<Record<OntologyConceptKind, number>> {
948
+ return {}
949
+ }
950
+
951
+ export function getOntologyReviewSummary() {
952
+ const kernel = loadOntologyKernelSnapshot()
953
+ const frontier = loadResolvedOntologyFrontierConcepts()
954
+ const extensions = loadOntologyExtensions()
955
+ const changes = loadOntologyChangeEvents()
956
+ const byConceptKind = ontologyKindCounts()
957
+ for (const concept of [...frontier, ...extensions]) {
958
+ byConceptKind[concept.conceptKind] = (byConceptKind[concept.conceptKind] ?? 0) + 1
959
+ }
960
+ return {
961
+ kernelConcepts: kernel.entityNames.length,
962
+ extensions: extensions.length,
963
+ frontier: frontier.length,
964
+ reviewOpen: frontier.filter((concept) => concept.reviewStatus === 'open').length,
965
+ promoted: extensions.filter((concept) => concept.status === 'active').length,
966
+ rejected: frontier.filter((concept) => concept.reviewStatus === 'rejected').length,
967
+ deferred: frontier.filter((concept) => concept.reviewStatus === 'deferred').length,
968
+ deprecated: extensions.filter((concept) => concept.status === 'deprecated').length,
969
+ changeEvents: changes.length,
970
+ byConceptKind,
971
+ backlog: frontier.filter((concept) => concept.reviewStatus === 'open' || concept.reviewStatus === 'deferred').slice(0, 10),
972
+ recentChanges: changes.slice(0, 10),
973
+ recentExtensions: extensions.slice(0, 8),
974
+ }
975
+ }
976
+
977
+ export function loadOntologyControlSummary(): OntologyControlDashboardSummary {
978
+ return {
979
+ governance: getActiveGovernanceSummary(),
980
+ kernel: loadOntologyKernelSnapshot(),
981
+ summary: getOntologyReviewSummary(),
982
+ frontier: loadResolvedOntologyFrontierConcepts(),
983
+ extensions: loadOntologyExtensions(),
984
+ recentChanges: loadOntologyChangeEvents().slice(0, 10),
985
+ }
986
+ }
987
+
682
988
  export function loadSkillContent(slug: string): string {
683
989
  const path = join(SG_DIR, 'general', slug, 'SKILL.md')
684
990
  if (!existsSync(path)) return ''
@@ -1783,6 +2089,7 @@ export function loadOntologySummary(): OntologyDashboardSummary {
1783
2089
  const governance = getActiveGovernanceSummary()
1784
2090
  const topologyReviews = getTopologyReviewSummary()
1785
2091
  const topologyExecution = getTopologyExecutionSummary()
2092
+ const ontologyReview = getOntologyReviewSummary()
1786
2093
  const skillRoles = emptyCounts(['generalist', 'specialist', 'hybrid'] as const)
1787
2094
  const stabilityStates = emptyCounts(['stable', 'adaptive', 'experimental'] as const)
1788
2095
  const plasticityStates = emptyCounts(['consolidated', 'volatile', 'candidate'] as const)
@@ -1815,7 +2122,9 @@ export function loadOntologySummary(): OntologyDashboardSummary {
1815
2122
 
1816
2123
  return {
1817
2124
  specVersion: graph.ontologyVersion ?? DASHBOARD_ONTOLOGY_SPEC_VERSION,
1818
- source: graph.ontologyVersion ? 'graph' : 'compat-derived',
2125
+ source: ontologyReview.frontier > 0 || ontologyReview.extensions > 0 || ontologyReview.changeEvents > 0
2126
+ ? 'hybrid-native-derived'
2127
+ : graph.ontologyVersion ? 'graph' : 'compat-derived',
1819
2128
  skillRoles,
1820
2129
  stabilityStates,
1821
2130
  plasticityStates,
@@ -1832,7 +2141,7 @@ export function loadOntologySummary(): OntologyDashboardSummary {
1832
2141
  evidenceBackedProposals,
1833
2142
  artifacts: {
1834
2143
  total: artifacts.length,
1835
- native: artifacts.filter((artifact) => artifact.provenance === 'native-evolution').length,
2144
+ native: artifacts.filter((artifact) => artifact.provenance === 'native-evolution' || artifact.provenance === 'native-ontology').length,
1836
2145
  derived: artifacts.filter((artifact) => artifact.provenance === 'derived-history').length,
1837
2146
  },
1838
2147
  activationTraces: {
@@ -1873,6 +2182,18 @@ export function loadOntologySummary(): OntologyDashboardSummary {
1873
2182
  candidate: transferEvents.filter((event) => event.status === 'candidate').length,
1874
2183
  rejected: transferEvents.filter((event) => event.status === 'rejected').length,
1875
2184
  },
2185
+ ontologyLoop: {
2186
+ kernelConcepts: ontologyReview.kernelConcepts,
2187
+ extensions: ontologyReview.extensions,
2188
+ frontier: ontologyReview.frontier,
2189
+ reviewOpen: ontologyReview.reviewOpen,
2190
+ promoted: ontologyReview.promoted,
2191
+ rejected: ontologyReview.rejected,
2192
+ deferred: ontologyReview.deferred,
2193
+ deprecated: ontologyReview.deprecated,
2194
+ changeEvents: ontologyReview.changeEvents,
2195
+ byConceptKind: ontologyReview.byConceptKind,
2196
+ },
1876
2197
  governance: {
1877
2198
  activeMode: governance.activeMode,
1878
2199
  derivedMode: governance.derivedMode,