helixevo 0.5.0 → 0.6.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/dist/cli.js CHANGED
@@ -10024,6 +10024,7 @@ function refreshTopologyReviewCandidates() {
10024
10024
  }
10025
10025
  function loadResolvedTopologyReviewCandidates() {
10026
10026
  const candidates = loadStoredTopologyReviewCandidates();
10027
+ const concepts = activeOntologyExtensions();
10027
10028
  const latestDecisionByCandidate = new Map;
10028
10029
  for (const decision of loadTopologyReviewDecisions()) {
10029
10030
  const existing = latestDecisionByCandidate.get(decision.candidateId);
@@ -10034,10 +10035,18 @@ function loadResolvedTopologyReviewCandidates() {
10034
10035
  return candidates.map((candidate) => {
10035
10036
  const latestDecision = latestDecisionByCandidate.get(candidate.id);
10036
10037
  const status = latestDecision?.decision ?? "open";
10038
+ const semanticBindings = matchTopologyOntologyBindings({
10039
+ ...candidate,
10040
+ status,
10041
+ latestDecision,
10042
+ lastActivityAt: maxTimestamp(candidate.lastObservedAt, latestDecision?.decidedAt)
10043
+ }, concepts);
10037
10044
  return {
10038
10045
  ...candidate,
10039
10046
  status,
10040
10047
  latestDecision,
10048
+ semanticBindings,
10049
+ semanticConceptIds: uniqueStrings(semanticBindings.map((binding) => binding.conceptId)),
10041
10050
  lastActivityAt: maxTimestamp(candidate.lastObservedAt, latestDecision?.decidedAt)
10042
10051
  };
10043
10052
  }).sort((a, b) => topologyStatusRank(b.status) - topologyStatusRank(a.status) || priorityRank(b.priority) - priorityRank(a.priority) || b.confidence - a.confidence || b.lastActivityAt.localeCompare(a.lastActivityAt) || a.title.localeCompare(b.title));
@@ -10450,6 +10459,7 @@ function deprecateOntologyExtension(params) {
10450
10459
  if (!current)
10451
10460
  return null;
10452
10461
  const governance = getActiveGovernanceSummary();
10462
+ const adoption = loadResolvedOntologyExtensions().find((entry) => entry.id === params.conceptId);
10453
10463
  const deprecated = {
10454
10464
  ...current,
10455
10465
  status: "deprecated",
@@ -10459,12 +10469,13 @@ function deprecateOntologyExtension(params) {
10459
10469
  deprecated,
10460
10470
  ...extensions.filter((entry) => entry.id !== params.conceptId)
10461
10471
  ]);
10472
+ const consumerWarning = adoption && adoption.adoptionCount > 0 ? ` Warning: ${adoption.adoptionCount} active semantic consumer${adoption.adoptionCount === 1 ? "" : "s"} were visible before deprecation.` : "";
10462
10473
  appendOntologyChangeEvent({
10463
10474
  id: `ontology_change_deprecated_${slugFragment(current.id)}_${Date.now()}`,
10464
10475
  timestamp: new Date().toISOString(),
10465
10476
  changeType: "concept-deprecated",
10466
10477
  conceptIds: [current.id],
10467
- reason: params.rationale.trim() || `Deprecated ontology extension ${current.name}`,
10478
+ reason: (params.rationale.trim() || `Deprecated ontology extension ${current.name}`) + consumerWarning,
10468
10479
  evidenceIds: current.evidenceIds,
10469
10480
  approvedBy: "operator",
10470
10481
  ontologyVersion: ONTOLOGY_SPEC_VERSION
@@ -10473,19 +10484,37 @@ function deprecateOntologyExtension(params) {
10473
10484
  concept: deprecated,
10474
10485
  operation: "deprecate",
10475
10486
  sourceId: `${current.id}:deprecate`,
10476
- summary: `Deprecated ontology extension ${deprecated.name} under ${governance.activeMode} governance.`,
10487
+ summary: `Deprecated ontology extension ${deprecated.name} under ${governance.activeMode} governance.${consumerWarning}`,
10477
10488
  metrics: {
10478
10489
  observations: deprecated.observationCount ?? 0,
10479
- confidence: deprecated.confidence ?? 0
10490
+ confidence: deprecated.confidence ?? 0,
10491
+ adoptionCount: adoption?.adoptionCount ?? 0
10480
10492
  }
10481
10493
  });
10482
- return deprecated;
10494
+ const resolved = loadResolvedOntologyExtensions().find((entry) => entry.id === params.conceptId);
10495
+ if (resolved) {
10496
+ return {
10497
+ ...resolved,
10498
+ warning: consumerWarning.trim() || resolved.warning,
10499
+ adoptionCount: adoption?.adoptionCount ?? resolved.adoptionCount
10500
+ };
10501
+ }
10502
+ return {
10503
+ ...deprecated,
10504
+ semanticBindings: [],
10505
+ adoptionCount: adoption?.adoptionCount ?? 0,
10506
+ bindingsByTargetType: adoption?.bindingsByTargetType ?? emptyOntologyBindingCounts(),
10507
+ lastActivityAt: deprecated.lastObservedAt ?? deprecated.createdAt,
10508
+ warning: consumerWarning.trim() || undefined
10509
+ };
10483
10510
  }
10484
10511
  function getOntologyReviewSummary() {
10485
10512
  const kernel = loadOntologyKernelSnapshot();
10486
10513
  const extensions = loadOntologyExtensions();
10514
+ const resolvedExtensions = loadResolvedOntologyExtensions();
10487
10515
  const frontier = loadResolvedOntologyFrontierConcepts();
10488
10516
  const changeEvents = loadOntologyChangeEvents();
10517
+ const adoption = getOntologyAdoptionSummary();
10489
10518
  const byConceptKind = ontologyKindCounts();
10490
10519
  for (const concept of [...extensions, ...frontier]) {
10491
10520
  byConceptKind[concept.conceptKind] = (byConceptKind[concept.conceptKind] ?? 0) + 1;
@@ -10501,9 +10530,10 @@ function getOntologyReviewSummary() {
10501
10530
  deprecated: extensions.filter((concept) => concept.status === "deprecated").length,
10502
10531
  changeEvents: changeEvents.length,
10503
10532
  byConceptKind,
10533
+ adoption,
10504
10534
  backlog: frontier.filter((concept) => concept.reviewStatus === "open" || concept.reviewStatus === "deferred").slice(0, 10),
10505
10535
  recentChanges: changeEvents.slice(0, 10),
10506
- recentExtensions: extensions.slice(0, 8)
10536
+ recentExtensions: resolvedExtensions.slice(0, 8)
10507
10537
  };
10508
10538
  }
10509
10539
  function buildDerivedEvolutionArtifact(iteration, proposal) {
@@ -10629,7 +10659,15 @@ function loadPressureInterventions() {
10629
10659
  return loadNativePressureInterventions().slice().sort((a, b) => (b.completedAt ?? b.createdAt).localeCompare(a.completedAt ?? a.createdAt));
10630
10660
  }
10631
10661
  function loadTransferEvents() {
10632
- return loadNativeTransferEvents().slice().sort((a, b) => b.timestamp.localeCompare(a.timestamp));
10662
+ const concepts = activeOntologyExtensions();
10663
+ return loadNativeTransferEvents().slice().map((event) => {
10664
+ const semanticBindings = matchTransferOntologyBindings(event, concepts);
10665
+ return {
10666
+ ...event,
10667
+ semanticBindings,
10668
+ semanticConceptIds: uniqueStrings(semanticBindings.map((binding) => binding.conceptId))
10669
+ };
10670
+ }).sort((a, b) => b.timestamp.localeCompare(a.timestamp));
10633
10671
  }
10634
10672
  function normalizePressureValue(value) {
10635
10673
  return (value ?? "").trim().toLowerCase().replace(/[\s_/]+/g, "-");
@@ -10764,16 +10802,301 @@ function deriveGovernanceSummary(pressureSignals = loadPressureSignals(), interv
10764
10802
  function getActiveGovernanceSummary() {
10765
10803
  return deriveGovernanceSummary();
10766
10804
  }
10805
+ function emptyOntologyBindingCounts() {
10806
+ return {};
10807
+ }
10808
+ function ontologyReviewKeyBody(reviewKey) {
10809
+ return normalizePressureValue((reviewKey ?? "").split(":").slice(1).join("-"));
10810
+ }
10811
+ function ontologyMotifTerm(motifId) {
10812
+ return normalizePressureValue(motifId.replace(/^motif_/, ""));
10813
+ }
10814
+ function ontologyConceptTerms(concept) {
10815
+ return uniqueStrings([
10816
+ normalizePressureValue(concept.name),
10817
+ ...(concept.aliases ?? []).map((alias) => normalizePressureValue(alias)),
10818
+ normalizePressureValue(concept.reviewKey),
10819
+ ontologyReviewKeyBody(concept.reviewKey),
10820
+ ...(concept.relatedMotifIds ?? []).map((id) => ontologyMotifTerm(id)),
10821
+ ...(concept.derivedFromKinds ?? []).map((value) => normalizePressureValue(value))
10822
+ ].filter(Boolean));
10823
+ }
10824
+ function ontologyBindingId(conceptId, targetType, targetId, sourceKind) {
10825
+ return `ontology_binding_${slugFragment(conceptId)}_${targetType}_${slugFragment(targetId)}_${sourceKind}`;
10826
+ }
10827
+ function buildOntologyBinding(params) {
10828
+ return {
10829
+ id: ontologyBindingId(params.concept.id, params.targetType, params.targetId, params.sourceKind),
10830
+ conceptId: params.concept.id,
10831
+ conceptName: params.concept.name,
10832
+ conceptKind: params.concept.conceptKind,
10833
+ targetType: params.targetType,
10834
+ targetId: params.targetId,
10835
+ sourceKind: params.sourceKind,
10836
+ confidence: Math.min(0.95, Math.max(0.5, params.confidence)),
10837
+ reasons: params.reasons,
10838
+ effectSummary: params.effectSummary
10839
+ };
10840
+ }
10841
+ function dedupeOntologyBindings(bindings) {
10842
+ const byKey = new Map;
10843
+ for (const binding of bindings) {
10844
+ const key = `${binding.conceptId}::${binding.targetType}::${binding.targetId}`;
10845
+ const existing = byKey.get(key);
10846
+ if (!existing || binding.confidence > existing.confidence)
10847
+ byKey.set(key, binding);
10848
+ }
10849
+ return [...byKey.values()].sort((a, b) => b.confidence - a.confidence || a.conceptName.localeCompare(b.conceptName)).slice(0, 4);
10850
+ }
10851
+ function activeOntologyExtensions() {
10852
+ return loadOntologyExtensions().filter((concept) => concept.status === "active");
10853
+ }
10854
+ function matchSignalOntologyBindings(signal, motifIds, concepts) {
10855
+ const capability = normalizePressureValue(signal.capability);
10856
+ const region = normalizePressureValue(signal.region);
10857
+ const kind = normalizePressureValue(signal.kind);
10858
+ const motifTerms = uniqueStrings(motifIds.map((id) => ontologyMotifTerm(id)).filter(Boolean));
10859
+ const bindings = [];
10860
+ for (const concept of concepts) {
10861
+ const terms = ontologyConceptTerms(concept);
10862
+ if (concept.conceptKind === "capability") {
10863
+ if (capability && terms.includes(capability)) {
10864
+ bindings.push(buildOntologyBinding({
10865
+ concept,
10866
+ targetType: "pressure-signal",
10867
+ targetId: signal.id,
10868
+ sourceKind: "capability-match",
10869
+ confidence: 0.86,
10870
+ reasons: [`Signal capability ${signal.capability} matches approved capability concept ${concept.name}.`],
10871
+ effectSummary: "Sharpens project or capability interpretation for this pressure signal."
10872
+ }));
10873
+ continue;
10874
+ }
10875
+ if (region && terms.includes(region)) {
10876
+ bindings.push(buildOntologyBinding({
10877
+ concept,
10878
+ targetType: "pressure-signal",
10879
+ targetId: signal.id,
10880
+ sourceKind: "pressure-region",
10881
+ confidence: 0.74,
10882
+ reasons: [`Signal region ${signal.region} aligns with approved capability concept ${concept.name}.`],
10883
+ effectSummary: "Adds semantic coverage to a recurring pressure region."
10884
+ }));
10885
+ }
10886
+ continue;
10887
+ }
10888
+ if (concept.conceptKind === "pressure-type") {
10889
+ if ((concept.relatedMotifIds ?? []).some((id) => motifIds.includes(id))) {
10890
+ bindings.push(buildOntologyBinding({
10891
+ concept,
10892
+ targetType: "pressure-signal",
10893
+ targetId: signal.id,
10894
+ sourceKind: "motif-match",
10895
+ confidence: 0.9,
10896
+ reasons: [`Signal participates in approved motif family ${concept.name}.`],
10897
+ effectSummary: "Marks this signal as part of an approved recurring pressure family."
10898
+ }));
10899
+ continue;
10900
+ }
10901
+ if (motifTerms.some((term) => terms.includes(term))) {
10902
+ bindings.push(buildOntologyBinding({
10903
+ concept,
10904
+ targetType: "pressure-signal",
10905
+ targetId: signal.id,
10906
+ sourceKind: "motif-match",
10907
+ confidence: 0.84,
10908
+ reasons: [`Signal motif region aligns with approved pressure family ${concept.name}.`],
10909
+ effectSummary: "Carries an approved recurring pressure family into live signal interpretation."
10910
+ }));
10911
+ continue;
10912
+ }
10913
+ if (kind && terms.includes(kind)) {
10914
+ bindings.push(buildOntologyBinding({
10915
+ concept,
10916
+ targetType: "pressure-signal",
10917
+ targetId: signal.id,
10918
+ sourceKind: "pressure-region",
10919
+ confidence: 0.78,
10920
+ reasons: [`Signal kind ${signal.kind} matches approved pressure family ${concept.name}.`],
10921
+ effectSummary: "Adds semantic identity to recurring pressure of the same kind."
10922
+ }));
10923
+ }
10924
+ }
10925
+ }
10926
+ return dedupeOntologyBindings(bindings);
10927
+ }
10928
+ function matchMotifOntologyBindings(motif, concepts) {
10929
+ const capability = normalizePressureValue(motif.capability);
10930
+ const key = normalizePressureValue(motif.key);
10931
+ const kind = normalizePressureValue(motif.kind);
10932
+ const bindings = [];
10933
+ for (const concept of concepts) {
10934
+ const terms = ontologyConceptTerms(concept);
10935
+ if (concept.conceptKind === "capability" && capability && terms.includes(capability)) {
10936
+ bindings.push(buildOntologyBinding({
10937
+ concept,
10938
+ targetType: "pressure-motif",
10939
+ targetId: motif.id,
10940
+ sourceKind: "capability-match",
10941
+ confidence: 0.84,
10942
+ reasons: [`Motif capability ${motif.capability} matches approved capability concept ${concept.name}.`],
10943
+ effectSummary: "Makes recurring capability pressure visible as semantic adoption."
10944
+ }));
10945
+ continue;
10946
+ }
10947
+ if (concept.conceptKind === "pressure-type") {
10948
+ if ((concept.relatedMotifIds ?? []).includes(motif.id)) {
10949
+ bindings.push(buildOntologyBinding({
10950
+ concept,
10951
+ targetType: "pressure-motif",
10952
+ targetId: motif.id,
10953
+ sourceKind: "motif-match",
10954
+ confidence: 0.92,
10955
+ reasons: [`Motif ${motif.key} directly matches approved pressure family ${concept.name}.`],
10956
+ effectSummary: "Confirms this recurring motif is an approved semantic family."
10957
+ }));
10958
+ continue;
10959
+ }
10960
+ if ([key, kind].filter(Boolean).some((value) => terms.includes(value))) {
10961
+ bindings.push(buildOntologyBinding({
10962
+ concept,
10963
+ targetType: "pressure-motif",
10964
+ targetId: motif.id,
10965
+ sourceKind: "pressure-region",
10966
+ confidence: 0.86,
10967
+ reasons: [`Motif identity aligns with approved pressure family ${concept.name}.`],
10968
+ effectSummary: "Carries approved semantic family identity into motif-level routing."
10969
+ }));
10970
+ }
10971
+ }
10972
+ }
10973
+ return dedupeOntologyBindings(bindings);
10974
+ }
10975
+ function matchTransferOntologyBindings(event, concepts) {
10976
+ const capabilityTerms = uniqueStrings((event.capabilityIds ?? []).map((value) => normalizePressureValue(value)).filter(Boolean));
10977
+ const motifTerms = uniqueStrings((event.motifIds ?? []).map((value) => ontologyMotifTerm(value)).filter(Boolean));
10978
+ const bindings = [];
10979
+ for (const concept of concepts) {
10980
+ const terms = ontologyConceptTerms(concept);
10981
+ if (concept.conceptKind === "capability" && capabilityTerms.some((value) => terms.includes(value))) {
10982
+ bindings.push(buildOntologyBinding({
10983
+ concept,
10984
+ targetType: "transfer-event",
10985
+ targetId: event.id,
10986
+ sourceKind: "capability-match",
10987
+ confidence: 0.82,
10988
+ reasons: [`Transfer capabilities align with approved concept ${concept.name}.`],
10989
+ effectSummary: "Shows semantic adoption through reusable transfer evidence."
10990
+ }));
10991
+ continue;
10992
+ }
10993
+ if (concept.conceptKind === "pressure-type") {
10994
+ if ((concept.relatedMotifIds ?? []).some((id) => (event.motifIds ?? []).includes(id))) {
10995
+ bindings.push(buildOntologyBinding({
10996
+ concept,
10997
+ targetType: "transfer-event",
10998
+ targetId: event.id,
10999
+ sourceKind: "transfer-motif",
11000
+ confidence: 0.88,
11001
+ reasons: [`Transfer realizes approved recurring family ${concept.name}.`],
11002
+ effectSummary: "Connects realized transfer evidence to an approved recurring pressure family."
11003
+ }));
11004
+ continue;
11005
+ }
11006
+ if (motifTerms.some((value) => terms.includes(value))) {
11007
+ bindings.push(buildOntologyBinding({
11008
+ concept,
11009
+ targetType: "transfer-event",
11010
+ targetId: event.id,
11011
+ sourceKind: "transfer-motif",
11012
+ confidence: 0.8,
11013
+ reasons: [`Transfer motif linkage aligns with approved family ${concept.name}.`],
11014
+ effectSummary: "Carries approved semantic family identity into realized transfer outcomes."
11015
+ }));
11016
+ }
11017
+ }
11018
+ }
11019
+ return dedupeOntologyBindings(bindings);
11020
+ }
11021
+ function matchTopologyOntologyBindings(candidate, concepts) {
11022
+ const descriptor = normalizePressureValue(topologyMotifDescriptor(candidate) ?? candidate.changeType);
11023
+ const bindings = [];
11024
+ for (const concept of concepts) {
11025
+ const terms = ontologyConceptTerms(concept);
11026
+ if (concept.conceptKind === "topology-motif" && descriptor && terms.includes(descriptor)) {
11027
+ bindings.push(buildOntologyBinding({
11028
+ concept,
11029
+ targetType: "topology-review",
11030
+ targetId: candidate.id,
11031
+ sourceKind: "topology-descriptor",
11032
+ confidence: 0.86,
11033
+ reasons: [`Topology review descriptor ${descriptor} aligns with approved topology concept ${concept.name}.`],
11034
+ effectSummary: "Adds semantic identity to recurring structural review patterns."
11035
+ }));
11036
+ continue;
11037
+ }
11038
+ if (concept.conceptKind === "pressure-type" && (concept.relatedMotifIds ?? []).some((id) => (candidate.relatedMotifIds ?? []).includes(id))) {
11039
+ bindings.push(buildOntologyBinding({
11040
+ concept,
11041
+ targetType: "topology-review",
11042
+ targetId: candidate.id,
11043
+ sourceKind: "motif-match",
11044
+ confidence: 0.72,
11045
+ reasons: [`Topology candidate inherits recurring pressure motif semantics from approved family ${concept.name}.`],
11046
+ effectSummary: "Links structural review back to an approved recurring pressure family."
11047
+ }));
11048
+ }
11049
+ }
11050
+ return dedupeOntologyBindings(bindings);
11051
+ }
11052
+ function applyOntologyInfluenceToRoute(params) {
11053
+ const { recommendation, signal, semanticBindings, governanceProfile } = params;
11054
+ if (semanticBindings.length === 0)
11055
+ return recommendation;
11056
+ const conceptIds = uniqueStrings(semanticBindings.map((binding) => binding.conceptId));
11057
+ const conceptNames = uniqueStrings(semanticBindings.map((binding) => binding.conceptName));
11058
+ const hasCapability = semanticBindings.some((binding) => binding.conceptKind === "capability");
11059
+ const hasPressureType = semanticBindings.some((binding) => binding.conceptKind === "pressure-type");
11060
+ const hasTopologyMotif = semanticBindings.some((binding) => binding.conceptKind === "topology-motif");
11061
+ const reasons = [...recommendation.reasons];
11062
+ let confidence = recommendation.confidence;
11063
+ let semanticInfluence = "explanatory";
11064
+ if (recommendation.route === "generalize" && hasPressureType && governanceProfile.riskTolerance >= 0.4 && governanceProfile.reviewThreshold <= 0.82) {
11065
+ confidence = Math.min(0.95, confidence + 0.04);
11066
+ semanticInfluence = "weighted";
11067
+ reasons.push(`Approved semantic family ${conceptNames.join(", ")} reinforces network-level reuse inside the current governance envelope.`);
11068
+ } else if (recommendation.route === "specialize" && hasCapability && signal.projectId && governanceProfile.reviewThreshold <= 0.86) {
11069
+ confidence = Math.min(0.95, confidence + 0.03);
11070
+ semanticInfluence = "weighted";
11071
+ reasons.push(`Approved capability concept ${conceptNames.join(", ")} sharpens project-bounded specialization without widening scope.`);
11072
+ } else if (recommendation.route === "evolve" && hasPressureType && signal.relatedFailureId) {
11073
+ confidence = Math.min(0.95, confidence + 0.02);
11074
+ semanticInfluence = "weighted";
11075
+ reasons.push(`Approved semantic family ${conceptNames.join(", ")} sharpens this failure-linked repair lane.`);
11076
+ } else if (recommendation.route === "manual-review" && (hasTopologyMotif || hasPressureType)) {
11077
+ reasons.push(`Approved semantic family ${conceptNames.join(", ")} confirms the pattern is real, but governance still prefers explicit operator review.`);
11078
+ } else {
11079
+ reasons.push(`Approved semantic family ${conceptNames.join(", ")} is visible here, but current governance/evidence still keeps the route bounded to ${recommendation.route}.`);
11080
+ }
11081
+ return {
11082
+ ...recommendation,
11083
+ confidence,
11084
+ reasons,
11085
+ semanticInfluence,
11086
+ semanticConceptIds: conceptIds
11087
+ };
11088
+ }
10767
11089
  function buildRouteRecommendation(params) {
10768
- const { signal, relatedSignals, linkedInterventions, governanceMode } = params;
11090
+ const { signal, relatedSignals, linkedInterventions, governanceMode, governanceProfile, semanticBindings } = params;
10769
11091
  const projectSpread = new Set(relatedSignals.map((entry) => entry.projectId ?? entry.projectPath).filter(Boolean)).size;
10770
11092
  const recurrenceCount = relatedSignals.length;
10771
11093
  const activeTypes = [...new Set(linkedInterventions.map((intervention) => intervention.interventionType))];
10772
11094
  const reasons = [];
11095
+ let recommendation;
10773
11096
  if (activeTypes.length >= 3 && !linkedInterventions.some((intervention) => intervention.status === "completed" && intervention.impact === "resolving")) {
10774
11097
  reasons.push("Multiple intervention lanes already touch this pressure region without clear closure.");
10775
11098
  reasons.push("Operator review is safer than blindly piling on another automated response.");
10776
- return {
11099
+ recommendation = {
10777
11100
  route: "manual-review",
10778
11101
  scope: projectSpread >= 2 ? "network" : signal.projectId ? "project" : "local",
10779
11102
  confidence: 0.58,
@@ -10781,25 +11104,21 @@ function buildRouteRecommendation(params) {
10781
11104
  triggeredBy: "mixed-signal",
10782
11105
  reasons
10783
11106
  };
10784
- }
10785
- if (projectSpread >= 2 && recurrenceCount >= 2) {
11107
+ } else if (projectSpread >= 2 && recurrenceCount >= 2 && governanceMode !== "project-critical") {
10786
11108
  reasons.push(`This pressure region repeats across ${projectSpread} projects.`);
10787
11109
  reasons.push("A network-level abstraction can absorb repeated local demand more efficiently than one-off fixes.");
10788
- if (governanceMode !== "project-critical") {
10789
- return {
10790
- route: "generalize",
10791
- scope: "network",
10792
- confidence: Math.min(0.95, 0.7 + Math.min(0.15, (projectSpread - 1) * 0.08)),
10793
- governanceMode,
10794
- triggeredBy: "recurring-cross-project-gap",
10795
- reasons
10796
- };
10797
- }
10798
- }
10799
- if (signal.projectId && signal.priority === "high" && signal.suggestedAction === "specialize") {
11110
+ recommendation = {
11111
+ route: "generalize",
11112
+ scope: "network",
11113
+ confidence: Math.min(0.95, 0.7 + Math.min(0.15, (projectSpread - 1) * 0.08)),
11114
+ governanceMode,
11115
+ triggeredBy: "recurring-cross-project-gap",
11116
+ reasons
11117
+ };
11118
+ } else if (signal.projectId && signal.priority === "high" && signal.suggestedAction === "specialize") {
10800
11119
  reasons.push("The pressure is high priority and bounded to a known project context.");
10801
11120
  reasons.push("Project-layer adaptation is the shortest truthful path to response.");
10802
- return {
11121
+ recommendation = {
10803
11122
  route: "specialize",
10804
11123
  scope: "project",
10805
11124
  confidence: 0.82,
@@ -10807,11 +11126,10 @@ function buildRouteRecommendation(params) {
10807
11126
  triggeredBy: "high-priority-local-gap",
10808
11127
  reasons
10809
11128
  };
10810
- }
10811
- if (signal.relatedFailureId && signal.severity >= 0.8) {
11129
+ } else if (signal.relatedFailureId && signal.severity >= 0.8) {
10812
11130
  reasons.push("This pressure is tied to a concrete failure with strong corrective evidence.");
10813
11131
  reasons.push("An evolution proposal can test a direct skill-level response against replay and regression evidence.");
10814
- return {
11132
+ recommendation = {
10815
11133
  route: "evolve",
10816
11134
  scope: signal.projectId ? "project" : "local",
10817
11135
  confidence: 0.78,
@@ -10819,11 +11137,10 @@ function buildRouteRecommendation(params) {
10819
11137
  triggeredBy: "accepted-iteration-pattern",
10820
11138
  reasons
10821
11139
  };
10822
- }
10823
- if (governanceMode === "exploration" || signal.suggestedAction === "research" || !signal.projectId) {
11140
+ } else if (governanceMode === "exploration" || signal.suggestedAction === "research" || !signal.projectId) {
10824
11141
  reasons.push("The pressure still looks under-specified or capability-oriented.");
10825
11142
  reasons.push("Research is the best way to widen evidence before committing to structural change.");
10826
- return {
11143
+ recommendation = {
10827
11144
  route: "research",
10828
11145
  scope: signal.projectId ? "project" : "local",
10829
11146
  confidence: 0.68,
@@ -10831,11 +11148,10 @@ function buildRouteRecommendation(params) {
10831
11148
  triggeredBy: "insufficient-evidence",
10832
11149
  reasons
10833
11150
  };
10834
- }
10835
- if (signal.projectId) {
11151
+ } else if (signal.projectId) {
10836
11152
  reasons.push("The pressure is project-scoped and can likely be handled without network-wide promotion yet.");
10837
11153
  reasons.push("Specialization is the most direct bounded intervention available.");
10838
- return {
11154
+ recommendation = {
10839
11155
  route: "specialize",
10840
11156
  scope: "project",
10841
11157
  confidence: 0.7,
@@ -10843,17 +11159,24 @@ function buildRouteRecommendation(params) {
10843
11159
  triggeredBy: "project-bounded-recurrence",
10844
11160
  reasons
10845
11161
  };
11162
+ } else {
11163
+ reasons.push("No single route is dominant from the current evidence.");
11164
+ reasons.push("Research keeps the loop moving while preserving optionality.");
11165
+ recommendation = {
11166
+ route: "research",
11167
+ scope: "local",
11168
+ confidence: 0.6,
11169
+ governanceMode,
11170
+ triggeredBy: "insufficient-evidence",
11171
+ reasons
11172
+ };
10846
11173
  }
10847
- reasons.push("No single route is dominant from the current evidence.");
10848
- reasons.push("Research keeps the loop moving while preserving optionality.");
10849
- return {
10850
- route: "research",
10851
- scope: "local",
10852
- confidence: 0.6,
10853
- governanceMode,
10854
- triggeredBy: "insufficient-evidence",
10855
- reasons
10856
- };
11174
+ return applyOntologyInfluenceToRoute({
11175
+ recommendation,
11176
+ signal,
11177
+ semanticBindings,
11178
+ governanceProfile
11179
+ });
10857
11180
  }
10858
11181
  function interventionEvidenceAccepted(intervention, acceptedProposalIds, acceptedArtifactIds, realizedTransferEventIds) {
10859
11182
  if (intervention.status !== "completed" || intervention.impact !== "resolving")
@@ -10882,6 +11205,7 @@ function loadResolvedPressureSignals() {
10882
11205
  const history = loadHistory();
10883
11206
  const artifacts = loadEvolutionArtifacts();
10884
11207
  const governance = deriveGovernanceSummary(pressureSignals, interventions);
11208
+ const concepts = activeOntologyExtensions();
10885
11209
  const acceptedProposalIds = new Set(history.iterations.flatMap((iteration) => iteration.proposals).filter((proposal) => proposal.outcome === "accepted").map((proposal) => proposal.id));
10886
11210
  const acceptedArtifactIds = new Set(artifacts.filter((artifact) => artifact.outcome === "accepted").map((artifact) => artifact.id));
10887
11211
  const realizedTransferEventIds = new Set(transferEvents.filter((event) => event.status === "realized").map((event) => event.id));
@@ -10908,17 +11232,22 @@ function loadResolvedPressureSignals() {
10908
11232
  const relatedSignals = signalsByRegion.get(pressureRegionKey(signal)) ?? [signal];
10909
11233
  const projectSpread = new Set(relatedSignals.map((entry) => entry.projectId ?? entry.projectPath).filter(Boolean)).size;
10910
11234
  const motifIds = relatedSignals.length >= 2 || projectSpread >= 2 ? [motifIdForSignal(signal)] : [];
11235
+ const semanticBindings = matchSignalOntologyBindings(signal, motifIds, concepts);
10911
11236
  const routeRecommendation = buildRouteRecommendation({
10912
11237
  signal,
10913
11238
  relatedSignals,
10914
11239
  linkedInterventions,
10915
- governanceMode: governance.activeMode
11240
+ governanceMode: governance.activeMode,
11241
+ governanceProfile: governance.profile,
11242
+ semanticBindings
10916
11243
  });
10917
11244
  const lifecycle = addressingInterventions.length > 0 || signal.status === "addressed" ? "addressed" : activeInterventions.length > 0 ? "in-progress" : hasNewerEquivalentSignal ? "stale" : "open";
10918
11245
  const lastActivityAt = [signal.detectedAt, latestInterventionAt].filter(Boolean).sort((a, b) => b.localeCompare(a))[0] ?? signal.detectedAt;
10919
11246
  const interventionTypes = [...new Set(linkedInterventions.map((intervention) => intervention.interventionType))];
10920
11247
  const addressedAt = addressingInterventions.map((intervention) => intervention.completedAt ?? intervention.createdAt).sort((a, b) => b.localeCompare(a))[0];
10921
- const responseSummary = lifecycle === "addressed" ? `Addressed by ${interventionTypes.join(", ") || "linked intervention"} evidence` : lifecycle === "in-progress" ? `Response underway via ${interventionTypes.join(", ")}` : lifecycle === "stale" ? "Superseded by newer pressure in the same project/capability region" : `No linked response yet • recommend ${routeRecommendation.route}`;
11248
+ const semanticNames = uniqueStrings(semanticBindings.map((binding) => binding.conceptName));
11249
+ const semanticNote = semanticNames.length > 0 ? ` • semantic family ${semanticNames.join(", ")}` : "";
11250
+ const responseSummary = lifecycle === "addressed" ? `Addressed by ${interventionTypes.join(", ") || "linked intervention"} evidence${semanticNote}` : lifecycle === "in-progress" ? `Response underway via ${interventionTypes.join(", ")}${semanticNote}` : lifecycle === "stale" ? "Superseded by newer pressure in the same project/capability region" : `No linked response yet • recommend ${routeRecommendation.route}${semanticNote}`;
10922
11251
  return {
10923
11252
  ...signal,
10924
11253
  lifecycle,
@@ -10926,6 +11255,8 @@ function loadResolvedPressureSignals() {
10926
11255
  interventionTypes,
10927
11256
  motifIds,
10928
11257
  routeRecommendation,
11258
+ semanticBindings,
11259
+ semanticConceptIds: uniqueStrings(semanticBindings.map((binding) => binding.conceptId)),
10929
11260
  lastActivityAt,
10930
11261
  addressedAt,
10931
11262
  responseSummary
@@ -10936,6 +11267,7 @@ function loadPressureMotifs() {
10936
11267
  const resolvedSignals = loadResolvedPressureSignals();
10937
11268
  const interventions = loadPressureInterventions();
10938
11269
  const transferEvents = loadTransferEvents();
11270
+ const concepts = activeOntologyExtensions();
10939
11271
  const groups = new Map;
10940
11272
  for (const signal of resolvedSignals) {
10941
11273
  const regionKey = pressureRegionKey(signal);
@@ -10980,7 +11312,15 @@ function loadPressureMotifs() {
10980
11312
  const linkedInterventionIds = linkedInterventions.map((intervention) => intervention.id);
10981
11313
  const linkedTransferEventIds = linkedTransferEvents.map((event) => event.id);
10982
11314
  const highPriorityCount = signals.filter((signal) => signal.priority === "high").length;
10983
- const responseSummary = lifecycle === "addressed" ? realizedTransfers.length > 0 ? "Promoted into reusable transfer evidence" : "All linked pressure in this recurring region is addressed" : lifecycle === "in-progress" ? `Promotion or response underway via ${interventionTypes.join(", ") || "linked intervention"}` : lifecycle === "stale" ? "Recurring pressure has been superseded by newer equivalent signals" : `Recurring demand is waiting for ${recommendation.route}`;
11315
+ const semanticBindings = matchMotifOntologyBindings({
11316
+ id: motifId,
11317
+ key: regionKey,
11318
+ kind: signals[0]?.kind ?? regionKey,
11319
+ capability
11320
+ }, concepts);
11321
+ const semanticNames = uniqueStrings(semanticBindings.map((binding) => binding.conceptName));
11322
+ const semanticNote = semanticNames.length > 0 ? ` • semantic family ${semanticNames.join(", ")}` : "";
11323
+ const responseSummary = lifecycle === "addressed" ? realizedTransfers.length > 0 ? `Promoted into reusable transfer evidence${semanticNote}` : `All linked pressure in this recurring region is addressed${semanticNote}` : lifecycle === "in-progress" ? `Promotion or response underway via ${interventionTypes.join(", ") || "linked intervention"}${semanticNote}` : lifecycle === "stale" ? "Recurring pressure has been superseded by newer equivalent signals" : `Recurring demand is waiting for ${recommendation.route}${semanticNote}`;
10984
11324
  motifs.push({
10985
11325
  id: motifId,
10986
11326
  key: regionKey,
@@ -10999,6 +11339,8 @@ function loadPressureMotifs() {
10999
11339
  suggestedRoute: recommendation,
11000
11340
  lifecycle,
11001
11341
  interventionTypes,
11342
+ semanticBindings,
11343
+ semanticConceptIds: uniqueStrings(semanticBindings.map((binding) => binding.conceptId)),
11002
11344
  lastActivityAt,
11003
11345
  addressedAt,
11004
11346
  responseSummary
@@ -11009,6 +11351,116 @@ function loadPressureMotifs() {
11009
11351
  return lifecycleWeight(b.lifecycle) - lifecycleWeight(a.lifecycle) || b.highPriorityCount - a.highPriorityCount || b.recurrenceCount - a.recurrenceCount || b.lastActivityAt.localeCompare(a.lastActivityAt);
11010
11352
  });
11011
11353
  }
11354
+ function collectOntologyAdoptionState() {
11355
+ const extensions = loadOntologyExtensions();
11356
+ const activeExtensions = extensions.filter((concept) => concept.status === "active");
11357
+ const byConceptKind = ontologyKindCounts();
11358
+ const bindingsByTargetType = emptyOntologyBindingCounts();
11359
+ const consumerMap = new Map;
11360
+ const conceptById = new Map(extensions.map((concept) => [concept.id, concept]));
11361
+ function ensureConsumer(concept) {
11362
+ const existing = consumerMap.get(concept.id);
11363
+ if (existing)
11364
+ return existing;
11365
+ const created = {
11366
+ conceptId: concept.id,
11367
+ conceptName: concept.name,
11368
+ conceptKind: concept.conceptKind,
11369
+ status: concept.status,
11370
+ totalBindings: 0,
11371
+ bindingsByTargetType: emptyOntologyBindingCounts(),
11372
+ activeTargetIds: [],
11373
+ lastActivityAt: concept.lastObservedAt ?? concept.createdAt
11374
+ };
11375
+ consumerMap.set(concept.id, created);
11376
+ return created;
11377
+ }
11378
+ function registerBinding(binding) {
11379
+ const concept = conceptById.get(binding.conceptId);
11380
+ if (!concept || concept.status !== "active")
11381
+ return;
11382
+ const consumer = ensureConsumer(concept);
11383
+ consumer.totalBindings += 1;
11384
+ consumer.bindingsByTargetType[binding.targetType] = (consumer.bindingsByTargetType[binding.targetType] ?? 0) + 1;
11385
+ if (!consumer.activeTargetIds.includes(binding.targetId) && consumer.activeTargetIds.length < 12) {
11386
+ consumer.activeTargetIds.push(binding.targetId);
11387
+ }
11388
+ consumer.lastActivityAt = maxTimestamp(consumer.lastActivityAt, concept.lastObservedAt, concept.createdAt);
11389
+ bindingsByTargetType[binding.targetType] = (bindingsByTargetType[binding.targetType] ?? 0) + 1;
11390
+ byConceptKind[concept.conceptKind] = (byConceptKind[concept.conceptKind] ?? 0) + 1;
11391
+ }
11392
+ const signals = loadResolvedPressureSignals();
11393
+ for (const signal of signals) {
11394
+ for (const binding of signal.semanticBindings ?? [])
11395
+ registerBinding(binding);
11396
+ if (signal.routeRecommendation?.semanticConceptIds?.length) {
11397
+ for (const conceptId of signal.routeRecommendation.semanticConceptIds) {
11398
+ const concept = conceptById.get(conceptId);
11399
+ if (!concept || concept.status !== "active")
11400
+ continue;
11401
+ registerBinding(buildOntologyBinding({
11402
+ concept,
11403
+ targetType: "route-recommendation",
11404
+ targetId: `${signal.id}:route`,
11405
+ sourceKind: "pressure-region",
11406
+ confidence: signal.routeRecommendation.semanticInfluence === "weighted" ? 0.82 : 0.72,
11407
+ reasons: signal.routeRecommendation.reasons.slice(0, 2),
11408
+ effectSummary: `Route recommendation ${signal.routeRecommendation.route} is semantically informed by ${concept.name}.`
11409
+ }));
11410
+ }
11411
+ }
11412
+ }
11413
+ for (const motif of loadPressureMotifs()) {
11414
+ for (const binding of motif.semanticBindings ?? [])
11415
+ registerBinding(binding);
11416
+ }
11417
+ for (const event of loadTransferEvents()) {
11418
+ for (const binding of event.semanticBindings ?? [])
11419
+ registerBinding(binding);
11420
+ }
11421
+ for (const candidate of loadResolvedTopologyReviewCandidates()) {
11422
+ for (const binding of candidate.semanticBindings ?? [])
11423
+ registerBinding(binding);
11424
+ }
11425
+ const activeConsumers = [...consumerMap.values()].sort((a, b) => b.totalBindings - a.totalBindings || (b.lastActivityAt ?? "").localeCompare(a.lastActivityAt ?? ""));
11426
+ const atRiskConcepts = activeConsumers.filter((consumer) => consumer.totalBindings > 0).map((consumer) => ({
11427
+ ...consumer,
11428
+ warning: `${consumer.totalBindings} active consumer${consumer.totalBindings === 1 ? "" : "s"} would be affected by deprecating ${consumer.conceptName}.`
11429
+ }));
11430
+ return {
11431
+ summary: {
11432
+ activeConcepts: activeConsumers.length,
11433
+ unusedExtensions: activeExtensions.filter((concept) => !consumerMap.has(concept.id)).length,
11434
+ totalBindings: activeConsumers.reduce((sum, consumer) => sum + consumer.totalBindings, 0),
11435
+ routesInfluenced: signals.filter((signal) => signal.routeRecommendation?.semanticInfluence && signal.routeRecommendation.semanticInfluence !== "none").length,
11436
+ conceptsWithConsumers: activeConsumers.length,
11437
+ conceptsAtDeprecationRisk: atRiskConcepts.length,
11438
+ bindingsByTargetType,
11439
+ usageByConceptKind: byConceptKind,
11440
+ topActiveConcepts: activeConsumers.slice(0, 8),
11441
+ atRiskConcepts: atRiskConcepts.slice(0, 8)
11442
+ },
11443
+ consumerMap: new Map(activeConsumers.map((consumer) => [consumer.conceptId, consumer]))
11444
+ };
11445
+ }
11446
+ function getOntologyAdoptionSummary() {
11447
+ return collectOntologyAdoptionState().summary;
11448
+ }
11449
+ function loadResolvedOntologyExtensions() {
11450
+ const extensions = loadOntologyExtensions();
11451
+ const { consumerMap } = collectOntologyAdoptionState();
11452
+ return extensions.map((concept) => {
11453
+ const consumer = consumerMap.get(concept.id);
11454
+ return {
11455
+ ...concept,
11456
+ semanticBindings: [],
11457
+ adoptionCount: consumer?.totalBindings ?? 0,
11458
+ bindingsByTargetType: consumer?.bindingsByTargetType ?? emptyOntologyBindingCounts(),
11459
+ lastActivityAt: maxTimestamp(concept.lastObservedAt, consumer?.lastActivityAt, concept.createdAt),
11460
+ warning: consumer?.warning
11461
+ };
11462
+ }).sort((a, b) => b.adoptionCount - a.adoptionCount || b.lastActivityAt.localeCompare(a.lastActivityAt) || a.name.localeCompare(b.name));
11463
+ }
11012
11464
  function matchPressureSignals(filters) {
11013
11465
  const capabilities = new Set((filters.capabilities ?? []).map((value) => normalizePressureValue(value)));
11014
11466
  const relatedFailureIds = new Set(filters.relatedFailureIds ?? []);
@@ -16373,6 +16825,8 @@ function printStatus2() {
16373
16825
  console.log(` Extensions: ${summary.extensions} active • ${summary.deprecated} deprecated`);
16374
16826
  console.log(` Frontier: ${summary.frontier} total • ${summary.reviewOpen} open • ${summary.deferred} deferred • ${summary.rejected} rejected`);
16375
16827
  console.log(` Change log: ${summary.changeEvents} events`);
16828
+ console.log(` Adoption: ${summary.adoption.activeConcepts} active concepts • ${summary.adoption.totalBindings} bindings • ${summary.adoption.routesInfluenced} routes influenced`);
16829
+ console.log(` Coverage: ${summary.adoption.unusedExtensions} unused extensions • ${summary.adoption.conceptsAtDeprecationRisk} deprecation-sensitive concepts`);
16376
16830
  if (summary.backlog.length > 0) {
16377
16831
  console.log(`
16378
16832
  Frontier concepts ready for review`);
@@ -16384,7 +16838,8 @@ function printStatus2() {
16384
16838
  console.log(`
16385
16839
  Approved extensions`);
16386
16840
  for (const concept of summary.recentExtensions.slice(0, 5)) {
16387
- console.log(` • ${concept.id} (${concept.conceptKind})${concept.status}`);
16841
+ const warning = concept.warning ? " deprecation risk" : "";
16842
+ console.log(` • ${concept.id} (${concept.conceptKind}) • ${concept.status} • ${concept.adoptionCount} bindings${warning}`);
16388
16843
  }
16389
16844
  }
16390
16845
  console.log();
@@ -16452,14 +16907,18 @@ async function ontologyCommand(options) {
16452
16907
  ✓ Deprecated ontology extension: ${concept.id}`);
16453
16908
  console.log(` kind: ${concept.conceptKind}`);
16454
16909
  console.log(` status: ${concept.status}`);
16910
+ if (concept.warning) {
16911
+ console.log(` warning: ${concept.warning}`);
16912
+ }
16455
16913
  console.log();
16456
16914
  return;
16457
16915
  }
16458
16916
  printStatus2();
16459
16917
  if (options.verbose) {
16918
+ const summary = getOntologyReviewSummary();
16460
16919
  const frontier = loadResolvedOntologyFrontierConcepts().slice(0, 8);
16461
16920
  const changes = loadOntologyChangeEvents().slice(0, 8);
16462
- const extensions = loadOntologyExtensions().slice(0, 8);
16921
+ const extensions = loadResolvedOntologyExtensions().slice(0, 8);
16463
16922
  if (frontier.length > 0) {
16464
16923
  console.log(" Recent frontier concepts");
16465
16924
  for (const concept of frontier) {
@@ -16470,7 +16929,26 @@ async function ontologyCommand(options) {
16470
16929
  if (extensions.length > 0) {
16471
16930
  console.log(" Recent approved extensions");
16472
16931
  for (const concept of extensions) {
16473
- console.log(` • ${concept.id} ${concept.conceptKind} • ${concept.status}`);
16932
+ const warning = concept.warning ? ` • ${concept.warning}` : "";
16933
+ console.log(` • ${concept.id} • ${concept.conceptKind} • ${concept.status} • ${concept.adoptionCount} bindings${warning}`);
16934
+ }
16935
+ console.log();
16936
+ }
16937
+ if (summary.adoption.topActiveConcepts.length > 0) {
16938
+ console.log(" Top active concepts");
16939
+ for (const concept of summary.adoption.topActiveConcepts) {
16940
+ console.log(` • ${concept.conceptId} • ${concept.totalBindings} bindings • ${Object.entries(concept.bindingsByTargetType).map(([target, count]) => `${target}:${count}`).join(" • ")}`);
16941
+ }
16942
+ console.log();
16943
+ }
16944
+ if (summary.adoption.unusedExtensions > 0) {
16945
+ console.log(` Unused approved extensions: ${summary.adoption.unusedExtensions}`);
16946
+ console.log();
16947
+ }
16948
+ if (summary.adoption.atRiskConcepts.length > 0) {
16949
+ console.log(" Deprecation-sensitive concepts");
16950
+ for (const concept of summary.adoption.atRiskConcepts) {
16951
+ console.log(` • ${concept.conceptId} • ${concept.warning}`);
16474
16952
  }
16475
16953
  console.log();
16476
16954
  }
@@ -16507,6 +16985,7 @@ Examples:
16507
16985
  $ helixevo topology --prepare <id> Prepare an accepted topology candidate
16508
16986
  $ helixevo topology --apply <planId> Apply a safe prepared topology plan
16509
16987
  $ helixevo topology --rollback <planId> Roll back an applied topology plan
16988
+ $ helixevo ontology --status --verbose Show frontier, extension, adoption, and deprecation-risk visibility
16510
16989
  $ helixevo ontology --refresh Derive frontier concepts from recurring evidence
16511
16990
  $ helixevo ontology --review <id> --decision promote
16512
16991
  Promote a reviewed frontier concept into approved extensions
@@ -16533,7 +17012,7 @@ program2.command("health").description("Assess network health: cohesion, coverag
16533
17012
  program2.command("metrics").description("Show correction rates, skill trends, and evolution impact").option("--verbose", "Show detailed per-skill breakdown").action(metricsCommand);
16534
17013
  program2.command("project-setup").description("Analyze a project folder and match it against your skill set").argument("<path>", "Path to the project folder").option("--verbose", "Show detailed analysis").option("--dry-run", "Analyze without saving project profile").action(projectSetupCommand);
16535
17014
  program2.command("topology").description("Reviewed topology execution control [--status] [--prepare <candidateId>] [--apply <planId>] [--rollback <planId>]").option("--status", "Show topology review and execution state").option("--prepare <candidateId>", "Prepare an accepted topology review candidate").option("--apply <planId>", "Apply a safe prepared topology plan").option("--rollback <planId>", "Roll back an applied topology plan").option("--verbose", "Show detailed topology plan state").action(topologyCommand);
16536
- program2.command("ontology").description("Governed ontology frontier control [--status] [--refresh] [--review <conceptId>] [--decision <promote|reject|defer>] [--deprecate <conceptId>]").option("--status", "Show ontology kernel, frontier, and extension state").option("--refresh", "Derive frontier concepts from recurring runtime evidence").option("--review <conceptId>", "Review a frontier concept").option("--decision <decision>", "Decision for --review: promote, reject, or defer").option("--rationale <text>", "Optional rationale for review or deprecate actions").option("--deprecate <conceptId>", "Deprecate an approved ontology extension").option("--verbose", "Show detailed ontology frontier state").action(ontologyCommand);
17015
+ program2.command("ontology").description("Governed ontology frontier and semantic adoption control [--status] [--refresh] [--review <conceptId>] [--decision <promote|reject|defer>] [--deprecate <conceptId>]").option("--status", "Show ontology kernel, frontier, and extension state").option("--refresh", "Derive frontier concepts from recurring runtime evidence").option("--review <conceptId>", "Review a frontier concept").option("--decision <decision>", "Decision for --review: promote, reject, or defer").option("--rationale <text>", "Optional rationale for review or deprecate actions").option("--deprecate <conceptId>", "Deprecate an approved ontology extension").option("--verbose", "Show detailed ontology frontier state").action(ontologyCommand);
16537
17016
  program2.hook("postAction", () => {
16538
17017
  checkForUpdates().catch(() => {});
16539
17018
  });