helixevo 0.4.1 → 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/CHANGELOG.md +26 -0
- package/README.md +20 -4
- package/dashboard/app/api/ontology/route.ts +89 -0
- package/dashboard/app/coevolution/client.tsx +32 -2
- package/dashboard/app/coevolution/page.tsx +3 -2
- package/dashboard/app/commands/page.tsx +80 -3
- package/dashboard/app/guide/page.tsx +80 -7
- package/dashboard/app/ontology/client.tsx +295 -0
- package/dashboard/app/ontology/page.tsx +9 -0
- package/dashboard/app/page.tsx +22 -2
- package/dashboard/app/topology/client.tsx +4 -0
- package/dashboard/components/sidebar-nav.tsx +10 -5
- package/dashboard/lib/data.ts +953 -53
- package/dist/cli.js +1133 -41
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9489,6 +9489,48 @@ function writeJson(filename, data) {
|
|
|
9489
9489
|
ensureDir(dirname(path));
|
|
9490
9490
|
writeFileSync3(path, JSON.stringify(data, null, 2));
|
|
9491
9491
|
}
|
|
9492
|
+
function getOntologyPath(filename) {
|
|
9493
|
+
return join3(getHelixDir(), "ontology", filename);
|
|
9494
|
+
}
|
|
9495
|
+
function readOntologyJson(filename, fallback) {
|
|
9496
|
+
const path = getOntologyPath(filename);
|
|
9497
|
+
if (!existsSync3(path))
|
|
9498
|
+
return fallback;
|
|
9499
|
+
return JSON.parse(readFileSync3(path, "utf-8"));
|
|
9500
|
+
}
|
|
9501
|
+
function writeOntologyJson(filename, data) {
|
|
9502
|
+
const path = getOntologyPath(filename);
|
|
9503
|
+
ensureDir(dirname(path));
|
|
9504
|
+
writeFileSync3(path, JSON.stringify(data, null, 2));
|
|
9505
|
+
}
|
|
9506
|
+
function readOntologyJsonl(filename) {
|
|
9507
|
+
const path = getOntologyPath(filename);
|
|
9508
|
+
if (!existsSync3(path))
|
|
9509
|
+
return [];
|
|
9510
|
+
const raw = readFileSync3(path, "utf-8").trim();
|
|
9511
|
+
if (!raw)
|
|
9512
|
+
return [];
|
|
9513
|
+
return raw.split(`
|
|
9514
|
+
`).filter(Boolean).map((line) => JSON.parse(line));
|
|
9515
|
+
}
|
|
9516
|
+
function appendOntologyJsonl(filename, record) {
|
|
9517
|
+
const path = getOntologyPath(filename);
|
|
9518
|
+
ensureDir(dirname(path));
|
|
9519
|
+
appendFileSync(path, JSON.stringify(record) + `
|
|
9520
|
+
`);
|
|
9521
|
+
}
|
|
9522
|
+
function kernelSnapshot() {
|
|
9523
|
+
return {
|
|
9524
|
+
version: ONTOLOGY_V0_SPEC.version,
|
|
9525
|
+
updatedAt: new Date().toISOString(),
|
|
9526
|
+
pillars: [...ONTOLOGY_V0_SPEC.pillars],
|
|
9527
|
+
layers: [...ONTOLOGY_V0_SPEC.layers],
|
|
9528
|
+
entityNames: [...ONTOLOGY_V0_SPEC.entityNames],
|
|
9529
|
+
relationFamilies: [...ONTOLOGY_V0_SPEC.relationFamilies],
|
|
9530
|
+
mutationOperations: [...ONTOLOGY_V0_SPEC.mutationOperations],
|
|
9531
|
+
invariantIds: [...ONTOLOGY_V0_SPEC.invariantIds]
|
|
9532
|
+
};
|
|
9533
|
+
}
|
|
9492
9534
|
function loadFailures() {
|
|
9493
9535
|
return readJsonl("failures.jsonl");
|
|
9494
9536
|
}
|
|
@@ -9982,6 +10024,7 @@ function refreshTopologyReviewCandidates() {
|
|
|
9982
10024
|
}
|
|
9983
10025
|
function loadResolvedTopologyReviewCandidates() {
|
|
9984
10026
|
const candidates = loadStoredTopologyReviewCandidates();
|
|
10027
|
+
const concepts = activeOntologyExtensions();
|
|
9985
10028
|
const latestDecisionByCandidate = new Map;
|
|
9986
10029
|
for (const decision of loadTopologyReviewDecisions()) {
|
|
9987
10030
|
const existing = latestDecisionByCandidate.get(decision.candidateId);
|
|
@@ -9992,10 +10035,18 @@ function loadResolvedTopologyReviewCandidates() {
|
|
|
9992
10035
|
return candidates.map((candidate) => {
|
|
9993
10036
|
const latestDecision = latestDecisionByCandidate.get(candidate.id);
|
|
9994
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);
|
|
9995
10044
|
return {
|
|
9996
10045
|
...candidate,
|
|
9997
10046
|
status,
|
|
9998
10047
|
latestDecision,
|
|
10048
|
+
semanticBindings,
|
|
10049
|
+
semanticConceptIds: uniqueStrings(semanticBindings.map((binding) => binding.conceptId)),
|
|
9999
10050
|
lastActivityAt: maxTimestamp(candidate.lastObservedAt, latestDecision?.decidedAt)
|
|
10000
10051
|
};
|
|
10001
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));
|
|
@@ -10019,6 +10070,472 @@ function getTopologyReviewSummary() {
|
|
|
10019
10070
|
recentDecisions: candidates.filter((candidate) => candidate.status !== "open").slice(0, 8)
|
|
10020
10071
|
};
|
|
10021
10072
|
}
|
|
10073
|
+
function slugFragment(value) {
|
|
10074
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 72) || "concept";
|
|
10075
|
+
}
|
|
10076
|
+
function ontologyKindCounts() {
|
|
10077
|
+
return {};
|
|
10078
|
+
}
|
|
10079
|
+
function ontologyStatusRank(status) {
|
|
10080
|
+
return status === "open" ? 4 : status === "deferred" ? 3 : status === "rejected" ? 2 : 1;
|
|
10081
|
+
}
|
|
10082
|
+
function mergeConcept(existing, next) {
|
|
10083
|
+
return {
|
|
10084
|
+
...existing,
|
|
10085
|
+
...next,
|
|
10086
|
+
createdAt: existing.createdAt,
|
|
10087
|
+
aliases: uniqueStrings([...existing.aliases ?? [], ...next.aliases ?? []]),
|
|
10088
|
+
promotionCriteria: uniqueStrings([...existing.promotionCriteria ?? [], ...next.promotionCriteria ?? []]),
|
|
10089
|
+
projectIds: uniqueStrings([...existing.projectIds ?? [], ...next.projectIds ?? []]),
|
|
10090
|
+
evidenceIds: uniqueStrings([...existing.evidenceIds ?? [], ...next.evidenceIds ?? []]),
|
|
10091
|
+
relatedSignalIds: uniqueStrings([...existing.relatedSignalIds ?? [], ...next.relatedSignalIds ?? []]),
|
|
10092
|
+
relatedMotifIds: uniqueStrings([...existing.relatedMotifIds ?? [], ...next.relatedMotifIds ?? []]),
|
|
10093
|
+
relatedReviewIds: uniqueStrings([...existing.relatedReviewIds ?? [], ...next.relatedReviewIds ?? []]),
|
|
10094
|
+
relatedTransferEventIds: uniqueStrings([...existing.relatedTransferEventIds ?? [], ...next.relatedTransferEventIds ?? []]),
|
|
10095
|
+
derivedFromKinds: uniqueStrings([...existing.derivedFromKinds ?? [], ...next.derivedFromKinds ?? []]),
|
|
10096
|
+
observationCount: Math.max(existing.observationCount ?? 0, next.observationCount ?? 0),
|
|
10097
|
+
confidence: Math.max(existing.confidence ?? 0, next.confidence ?? 0),
|
|
10098
|
+
lastObservedAt: maxTimestamp(existing.lastObservedAt, next.lastObservedAt, existing.createdAt, next.createdAt),
|
|
10099
|
+
sourceSummary: next.sourceSummary ?? existing.sourceSummary,
|
|
10100
|
+
migrationMap: { ...existing.migrationMap ?? {}, ...next.migrationMap ?? {} }
|
|
10101
|
+
};
|
|
10102
|
+
}
|
|
10103
|
+
function conceptArtifactSummary(action, concept) {
|
|
10104
|
+
return `${action} ontology ${concept.conceptKind} concept ${concept.name} using ${concept.observationCount ?? 0} supporting observations.`;
|
|
10105
|
+
}
|
|
10106
|
+
function appendOntologyArtifact(params) {
|
|
10107
|
+
const artifact = {
|
|
10108
|
+
id: `ontology_artifact_${slugFragment(params.concept.id)}_${Date.now()}`,
|
|
10109
|
+
createdAt: new Date().toISOString(),
|
|
10110
|
+
artifactType: "ontology-review",
|
|
10111
|
+
provenance: "native-ontology",
|
|
10112
|
+
title: `${params.concept.name} · ontology ${params.operation}`,
|
|
10113
|
+
summary: params.summary,
|
|
10114
|
+
sourceId: params.sourceId,
|
|
10115
|
+
operation: `ontology:${params.operation}`,
|
|
10116
|
+
metrics: params.metrics
|
|
10117
|
+
};
|
|
10118
|
+
appendEvolutionArtifact(artifact);
|
|
10119
|
+
return artifact.id;
|
|
10120
|
+
}
|
|
10121
|
+
function loadOntologyKernelSnapshot() {
|
|
10122
|
+
return readOntologyJson("kernel.json", kernelSnapshot());
|
|
10123
|
+
}
|
|
10124
|
+
function materializeOntologyKernelSnapshot() {
|
|
10125
|
+
const snapshot = { ...kernelSnapshot(), updatedAt: new Date().toISOString() };
|
|
10126
|
+
writeOntologyJson("kernel.json", snapshot);
|
|
10127
|
+
return snapshot;
|
|
10128
|
+
}
|
|
10129
|
+
function loadOntologyExtensions() {
|
|
10130
|
+
return readOntologyJson("extensions.json", []).slice().sort((a, b) => (b.lastObservedAt ?? b.createdAt).localeCompare(a.lastObservedAt ?? a.createdAt) || a.name.localeCompare(b.name));
|
|
10131
|
+
}
|
|
10132
|
+
function saveOntologyExtensions(concepts) {
|
|
10133
|
+
writeOntologyJson("extensions.json", concepts);
|
|
10134
|
+
}
|
|
10135
|
+
function loadOntologyFrontier() {
|
|
10136
|
+
return readOntologyJson("frontier.json", []).slice().sort((a, b) => (b.lastObservedAt ?? b.createdAt).localeCompare(a.lastObservedAt ?? a.createdAt) || a.name.localeCompare(b.name));
|
|
10137
|
+
}
|
|
10138
|
+
function saveOntologyFrontier(concepts) {
|
|
10139
|
+
writeOntologyJson("frontier.json", concepts);
|
|
10140
|
+
}
|
|
10141
|
+
function loadOntologyReviewDecisions() {
|
|
10142
|
+
return readOntologyJsonl("reviews.jsonl").slice().sort((a, b) => b.decidedAt.localeCompare(a.decidedAt));
|
|
10143
|
+
}
|
|
10144
|
+
function appendOntologyReviewDecision(decision) {
|
|
10145
|
+
appendOntologyJsonl("reviews.jsonl", decision);
|
|
10146
|
+
}
|
|
10147
|
+
function loadOntologyChangeEvents() {
|
|
10148
|
+
return readOntologyJsonl("change-log.jsonl").slice().sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
10149
|
+
}
|
|
10150
|
+
function appendOntologyChangeEvent(event) {
|
|
10151
|
+
appendOntologyJsonl("change-log.jsonl", event);
|
|
10152
|
+
}
|
|
10153
|
+
function buildCapabilityFrontierConcept() {
|
|
10154
|
+
const signalsByCapability = new Map;
|
|
10155
|
+
for (const signal of loadPressureSignals()) {
|
|
10156
|
+
const key = signal.capability?.trim() || signal.region?.trim();
|
|
10157
|
+
if (!key)
|
|
10158
|
+
continue;
|
|
10159
|
+
const normalized = slugFragment(key);
|
|
10160
|
+
const list = signalsByCapability.get(normalized) ?? [];
|
|
10161
|
+
list.push(signal);
|
|
10162
|
+
signalsByCapability.set(normalized, list);
|
|
10163
|
+
}
|
|
10164
|
+
return [...signalsByCapability.entries()].flatMap(([normalized, signals]) => {
|
|
10165
|
+
const distinctProjects = uniqueStrings(signals.map((signal) => signal.projectId ?? signal.projectPath));
|
|
10166
|
+
if (signals.length < 3 && distinctProjects.length < 2)
|
|
10167
|
+
return [];
|
|
10168
|
+
const first = signals[0];
|
|
10169
|
+
const capabilityName = first.capability?.trim() || first.region?.trim() || normalized;
|
|
10170
|
+
return [{
|
|
10171
|
+
id: `ontology_capability_${normalized}`,
|
|
10172
|
+
name: capabilityName.replace(/-/g, " "),
|
|
10173
|
+
conceptKind: "capability",
|
|
10174
|
+
layer: "frontier",
|
|
10175
|
+
status: "provisional",
|
|
10176
|
+
createdAt: new Date().toISOString(),
|
|
10177
|
+
description: `Recurring capability pressure around ${capabilityName}.`,
|
|
10178
|
+
promotionCriteria: [
|
|
10179
|
+
"Recurs across time or more than one meaningful project context",
|
|
10180
|
+
"Improves pressure explanation or project-gap attribution",
|
|
10181
|
+
"Cannot be expressed cleanly by the current capability vocabulary alone"
|
|
10182
|
+
],
|
|
10183
|
+
reviewKey: `capability:${normalized}`,
|
|
10184
|
+
lastObservedAt: signals.map((signal) => signal.detectedAt).sort().at(-1),
|
|
10185
|
+
sourceSummary: `Derived from ${signals.length} pressure signals across ${Math.max(1, distinctProjects.length)} contexts.`,
|
|
10186
|
+
projectIds: distinctProjects,
|
|
10187
|
+
evidenceIds: uniqueStrings(signals.map((signal) => signal.id)),
|
|
10188
|
+
observationCount: signals.length,
|
|
10189
|
+
confidence: Math.min(0.95, 0.52 + Math.min(0.28, signals.length * 0.05) + Math.min(0.12, distinctProjects.length * 0.08)),
|
|
10190
|
+
relatedSignalIds: uniqueStrings(signals.map((signal) => signal.id)),
|
|
10191
|
+
derivedFromKinds: ["project-analysis-pressure", "capability-gap"],
|
|
10192
|
+
aliases: [capabilityName],
|
|
10193
|
+
migrationMap: {}
|
|
10194
|
+
}];
|
|
10195
|
+
});
|
|
10196
|
+
}
|
|
10197
|
+
function buildPressureTypeFrontierConcepts() {
|
|
10198
|
+
return loadPressureMotifs().flatMap((motif) => {
|
|
10199
|
+
if (motif.recurrenceCount < 3 && motif.projectIds.length < 2)
|
|
10200
|
+
return [];
|
|
10201
|
+
const capabilityPart = motif.capability ? ` ${motif.capability}` : "";
|
|
10202
|
+
const normalized = slugFragment(`${motif.kind}-${motif.capability ?? motif.key}`);
|
|
10203
|
+
return [{
|
|
10204
|
+
id: `ontology_pressure_${normalized}`,
|
|
10205
|
+
name: `${motif.kind}${capabilityPart}`.trim().replace(/-/g, " "),
|
|
10206
|
+
conceptKind: "pressure-type",
|
|
10207
|
+
layer: "frontier",
|
|
10208
|
+
status: "provisional",
|
|
10209
|
+
createdAt: new Date().toISOString(),
|
|
10210
|
+
description: motif.description,
|
|
10211
|
+
promotionCriteria: [
|
|
10212
|
+
"Recurs above isolated single-signal behavior",
|
|
10213
|
+
"Improves route recommendation explanation",
|
|
10214
|
+
"Supports at least one operational use-case in co-evolution control"
|
|
10215
|
+
],
|
|
10216
|
+
reviewKey: `pressure:${normalized}`,
|
|
10217
|
+
lastObservedAt: motif.lastActivityAt,
|
|
10218
|
+
sourceSummary: `Derived from motif ${motif.key} with ${motif.recurrenceCount} observations across ${motif.projectIds.length} projects.`,
|
|
10219
|
+
projectIds: motif.projectIds,
|
|
10220
|
+
evidenceIds: uniqueStrings([...motif.pressureSignalIds, ...motif.linkedInterventionIds, ...motif.linkedTransferEventIds]),
|
|
10221
|
+
observationCount: motif.recurrenceCount,
|
|
10222
|
+
confidence: Math.min(0.95, 0.56 + Math.min(0.2, motif.recurrenceCount * 0.04) + Math.min(0.12, motif.projectIds.length * 0.06)),
|
|
10223
|
+
relatedSignalIds: motif.pressureSignalIds,
|
|
10224
|
+
relatedMotifIds: [motif.id],
|
|
10225
|
+
relatedTransferEventIds: motif.linkedTransferEventIds,
|
|
10226
|
+
derivedFromKinds: ["pressure-motif"],
|
|
10227
|
+
aliases: [motif.kind, motif.key],
|
|
10228
|
+
migrationMap: {}
|
|
10229
|
+
}];
|
|
10230
|
+
});
|
|
10231
|
+
}
|
|
10232
|
+
function topologyMotifDescriptor(candidate) {
|
|
10233
|
+
if (candidate.changeType === "split" && candidate.title.startsWith("Split overloaded skill:"))
|
|
10234
|
+
return "overloaded-skill-split-pressure";
|
|
10235
|
+
if (candidate.changeType === "rewire" && candidate.title.startsWith("Resolve conflicting pair:"))
|
|
10236
|
+
return "conflict-rewire-pressure";
|
|
10237
|
+
if (candidate.changeType === "promote" && candidate.title.startsWith("Promote recurring motif:"))
|
|
10238
|
+
return "motif-promotion-pressure";
|
|
10239
|
+
if (candidate.changeType === "merge" && candidate.title.startsWith("Merge overlap:"))
|
|
10240
|
+
return "overlap-merge-pressure";
|
|
10241
|
+
if (candidate.changeType === "consolidate")
|
|
10242
|
+
return "consolidation-pressure";
|
|
10243
|
+
return null;
|
|
10244
|
+
}
|
|
10245
|
+
function buildTopologyMotifFrontierConcepts() {
|
|
10246
|
+
const grouped = new Map;
|
|
10247
|
+
for (const candidate of loadResolvedTopologyReviewCandidates()) {
|
|
10248
|
+
const descriptor = topologyMotifDescriptor(candidate);
|
|
10249
|
+
if (!descriptor)
|
|
10250
|
+
continue;
|
|
10251
|
+
const list = grouped.get(descriptor) ?? [];
|
|
10252
|
+
list.push(candidate);
|
|
10253
|
+
grouped.set(descriptor, list);
|
|
10254
|
+
}
|
|
10255
|
+
return [...grouped.entries()].flatMap(([descriptor, candidates]) => {
|
|
10256
|
+
if (candidates.length < 2)
|
|
10257
|
+
return [];
|
|
10258
|
+
const first = candidates[0];
|
|
10259
|
+
return [{
|
|
10260
|
+
id: `ontology_topology_${slugFragment(descriptor)}`,
|
|
10261
|
+
name: descriptor.replace(/-/g, " "),
|
|
10262
|
+
conceptKind: "topology-motif",
|
|
10263
|
+
layer: "frontier",
|
|
10264
|
+
status: "provisional",
|
|
10265
|
+
createdAt: new Date().toISOString(),
|
|
10266
|
+
description: `Recurring structural review pattern: ${descriptor.replace(/-/g, " ")}.`,
|
|
10267
|
+
promotionCriteria: [
|
|
10268
|
+
"Recurs across multiple structural review candidates",
|
|
10269
|
+
"Improves topology review explanation or triage",
|
|
10270
|
+
"Supports a bounded operational use-case in the topology control surface"
|
|
10271
|
+
],
|
|
10272
|
+
reviewKey: `topology:${slugFragment(descriptor)}`,
|
|
10273
|
+
lastObservedAt: candidates.map((candidate) => candidate.lastActivityAt).sort().at(-1),
|
|
10274
|
+
sourceSummary: `Derived from ${candidates.length} reviewed topology candidates of type ${first.changeType}.`,
|
|
10275
|
+
projectIds: uniqueStrings(candidates.flatMap((candidate) => candidate.projectIds ?? [])),
|
|
10276
|
+
evidenceIds: uniqueStrings(candidates.flatMap((candidate) => [...candidate.evidence, candidate.id])),
|
|
10277
|
+
observationCount: candidates.length,
|
|
10278
|
+
confidence: Math.min(0.92, 0.55 + Math.min(0.24, candidates.length * 0.08)),
|
|
10279
|
+
relatedReviewIds: candidates.map((candidate) => candidate.id),
|
|
10280
|
+
relatedMotifIds: uniqueStrings(candidates.flatMap((candidate) => candidate.relatedMotifIds ?? [])),
|
|
10281
|
+
relatedTransferEventIds: uniqueStrings(candidates.flatMap((candidate) => candidate.relatedTransferEventIds ?? [])),
|
|
10282
|
+
derivedFromKinds: ["topology-review"],
|
|
10283
|
+
aliases: [first.changeType, descriptor],
|
|
10284
|
+
migrationMap: {}
|
|
10285
|
+
}];
|
|
10286
|
+
});
|
|
10287
|
+
}
|
|
10288
|
+
function deriveOntologyFrontierConcepts() {
|
|
10289
|
+
const byKey = new Map;
|
|
10290
|
+
for (const concept of [
|
|
10291
|
+
...buildCapabilityFrontierConcept(),
|
|
10292
|
+
...buildPressureTypeFrontierConcepts(),
|
|
10293
|
+
...buildTopologyMotifFrontierConcepts()
|
|
10294
|
+
]) {
|
|
10295
|
+
const key = concept.reviewKey ?? concept.id;
|
|
10296
|
+
const current = byKey.get(key);
|
|
10297
|
+
byKey.set(key, current ? mergeConcept(current, concept) : concept);
|
|
10298
|
+
}
|
|
10299
|
+
return [...byKey.values()].filter((concept) => (concept.evidenceIds?.length ?? 0) > 0).sort((a, b) => (b.confidence ?? 0) - (a.confidence ?? 0) || (b.observationCount ?? 0) - (a.observationCount ?? 0) || (b.lastObservedAt ?? "").localeCompare(a.lastObservedAt ?? "")).slice(0, 10);
|
|
10300
|
+
}
|
|
10301
|
+
function refreshOntologyFrontier() {
|
|
10302
|
+
materializeOntologyKernelSnapshot();
|
|
10303
|
+
const existing = loadOntologyFrontier();
|
|
10304
|
+
const extensions = loadOntologyExtensions();
|
|
10305
|
+
const promotedKeys = new Set(extensions.map((concept) => concept.reviewKey ?? concept.id));
|
|
10306
|
+
const existingByKey = new Map(existing.map((concept) => [concept.reviewKey ?? concept.id, concept]));
|
|
10307
|
+
const derived = deriveOntologyFrontierConcepts().filter((concept) => !promotedKeys.has(concept.reviewKey ?? concept.id));
|
|
10308
|
+
let created = 0;
|
|
10309
|
+
let updated = 0;
|
|
10310
|
+
for (const concept of derived) {
|
|
10311
|
+
const key = concept.reviewKey ?? concept.id;
|
|
10312
|
+
const current = existingByKey.get(key);
|
|
10313
|
+
if (!current) {
|
|
10314
|
+
existingByKey.set(key, concept);
|
|
10315
|
+
created += 1;
|
|
10316
|
+
appendOntologyChangeEvent({
|
|
10317
|
+
id: `ontology_change_hypothesized_${slugFragment(concept.id)}_${Date.now()}`,
|
|
10318
|
+
timestamp: new Date().toISOString(),
|
|
10319
|
+
changeType: "concept-hypothesized",
|
|
10320
|
+
conceptIds: [concept.id],
|
|
10321
|
+
reason: concept.sourceSummary ?? conceptArtifactSummary("Hypothesized", concept),
|
|
10322
|
+
evidenceIds: concept.evidenceIds,
|
|
10323
|
+
ontologyVersion: ONTOLOGY_SPEC_VERSION
|
|
10324
|
+
});
|
|
10325
|
+
appendOntologyArtifact({
|
|
10326
|
+
concept,
|
|
10327
|
+
operation: "refresh",
|
|
10328
|
+
sourceId: concept.id,
|
|
10329
|
+
summary: conceptArtifactSummary("Hypothesized", concept),
|
|
10330
|
+
metrics: {
|
|
10331
|
+
observations: concept.observationCount ?? 0,
|
|
10332
|
+
confidence: concept.confidence ?? 0,
|
|
10333
|
+
evidence: concept.evidenceIds?.length ?? 0
|
|
10334
|
+
}
|
|
10335
|
+
});
|
|
10336
|
+
continue;
|
|
10337
|
+
}
|
|
10338
|
+
existingByKey.set(key, mergeConcept(current, concept));
|
|
10339
|
+
updated += 1;
|
|
10340
|
+
}
|
|
10341
|
+
const frontier = [...existingByKey.values()].filter((concept) => !promotedKeys.has(concept.reviewKey ?? concept.id)).sort((a, b) => (b.lastObservedAt ?? b.createdAt).localeCompare(a.lastObservedAt ?? a.createdAt) || a.name.localeCompare(b.name));
|
|
10342
|
+
saveOntologyFrontier(frontier);
|
|
10343
|
+
const resolved = loadResolvedOntologyFrontierConcepts();
|
|
10344
|
+
return {
|
|
10345
|
+
created,
|
|
10346
|
+
updated,
|
|
10347
|
+
total: resolved.length,
|
|
10348
|
+
open: resolved.filter((concept) => concept.reviewStatus === "open").length,
|
|
10349
|
+
concepts: resolved
|
|
10350
|
+
};
|
|
10351
|
+
}
|
|
10352
|
+
function loadResolvedOntologyFrontierConcepts() {
|
|
10353
|
+
const concepts = loadOntologyFrontier();
|
|
10354
|
+
const latestDecisionByConcept = new Map;
|
|
10355
|
+
for (const decision of loadOntologyReviewDecisions()) {
|
|
10356
|
+
const existing = latestDecisionByConcept.get(decision.conceptId);
|
|
10357
|
+
if (!existing || decision.decidedAt > existing.decidedAt)
|
|
10358
|
+
latestDecisionByConcept.set(decision.conceptId, decision);
|
|
10359
|
+
}
|
|
10360
|
+
return concepts.map((concept) => {
|
|
10361
|
+
const latestReview = latestDecisionByConcept.get(concept.id);
|
|
10362
|
+
const reviewStatus = latestReview?.decision === "promote" ? "promoted" : latestReview?.decision === "reject" ? "rejected" : latestReview?.decision === "defer" ? "deferred" : "open";
|
|
10363
|
+
return {
|
|
10364
|
+
...concept,
|
|
10365
|
+
reviewStatus,
|
|
10366
|
+
latestReview,
|
|
10367
|
+
lastActivityAt: maxTimestamp(concept.lastObservedAt, latestReview?.decidedAt, concept.createdAt)
|
|
10368
|
+
};
|
|
10369
|
+
}).sort((a, b) => ontologyStatusRank(b.reviewStatus) - ontologyStatusRank(a.reviewStatus) || (b.confidence ?? 0) - (a.confidence ?? 0) || (b.observationCount ?? 0) - (a.observationCount ?? 0) || b.lastActivityAt.localeCompare(a.lastActivityAt) || a.name.localeCompare(b.name));
|
|
10370
|
+
}
|
|
10371
|
+
function reviewOntologyConcept(params) {
|
|
10372
|
+
const frontier = loadOntologyFrontier();
|
|
10373
|
+
const concept = frontier.find((entry) => entry.id === params.conceptId);
|
|
10374
|
+
if (!concept)
|
|
10375
|
+
return { concept: null, extension: null };
|
|
10376
|
+
const governance = getActiveGovernanceSummary();
|
|
10377
|
+
const decision = {
|
|
10378
|
+
id: `ontology_review_${params.decision}_${slugFragment(params.conceptId)}_${Date.now()}`,
|
|
10379
|
+
conceptId: params.conceptId,
|
|
10380
|
+
decision: params.decision,
|
|
10381
|
+
decidedAt: new Date().toISOString(),
|
|
10382
|
+
governanceMode: governance.activeMode,
|
|
10383
|
+
rationale: params.rationale.trim() || `${params.decision} ontology concept via operator review`,
|
|
10384
|
+
decidedBy: "operator"
|
|
10385
|
+
};
|
|
10386
|
+
appendOntologyReviewDecision(decision);
|
|
10387
|
+
if (params.decision === "promote") {
|
|
10388
|
+
const extensions = loadOntologyExtensions();
|
|
10389
|
+
const promotedConcept = {
|
|
10390
|
+
...concept,
|
|
10391
|
+
layer: "extension",
|
|
10392
|
+
status: "active",
|
|
10393
|
+
migrationMap: { ...concept.migrationMap ?? {}, [concept.id]: concept.id },
|
|
10394
|
+
aliases: uniqueStrings([...concept.aliases ?? [], concept.name]),
|
|
10395
|
+
lastObservedAt: maxTimestamp(concept.lastObservedAt, decision.decidedAt)
|
|
10396
|
+
};
|
|
10397
|
+
saveOntologyExtensions([
|
|
10398
|
+
promotedConcept,
|
|
10399
|
+
...extensions.filter((entry) => entry.id !== concept.id)
|
|
10400
|
+
]);
|
|
10401
|
+
saveOntologyFrontier(frontier.filter((entry) => entry.id !== concept.id));
|
|
10402
|
+
appendOntologyChangeEvent({
|
|
10403
|
+
id: `ontology_change_promoted_${slugFragment(concept.id)}_${Date.now()}`,
|
|
10404
|
+
timestamp: decision.decidedAt,
|
|
10405
|
+
changeType: "concept-promoted",
|
|
10406
|
+
conceptIds: [concept.id],
|
|
10407
|
+
reason: decision.rationale,
|
|
10408
|
+
evidenceIds: concept.evidenceIds,
|
|
10409
|
+
approvedBy: decision.decidedBy,
|
|
10410
|
+
ontologyVersion: ONTOLOGY_SPEC_VERSION
|
|
10411
|
+
});
|
|
10412
|
+
appendOntologyArtifact({
|
|
10413
|
+
concept: promotedConcept,
|
|
10414
|
+
operation: "promote",
|
|
10415
|
+
sourceId: decision.id,
|
|
10416
|
+
summary: conceptArtifactSummary("Promoted", promotedConcept),
|
|
10417
|
+
metrics: {
|
|
10418
|
+
observations: promotedConcept.observationCount ?? 0,
|
|
10419
|
+
confidence: promotedConcept.confidence ?? 0,
|
|
10420
|
+
evidence: promotedConcept.evidenceIds?.length ?? 0
|
|
10421
|
+
}
|
|
10422
|
+
});
|
|
10423
|
+
return {
|
|
10424
|
+
concept: null,
|
|
10425
|
+
extension: promotedConcept
|
|
10426
|
+
};
|
|
10427
|
+
}
|
|
10428
|
+
if (params.decision === "reject") {
|
|
10429
|
+
appendOntologyChangeEvent({
|
|
10430
|
+
id: `ontology_change_rejected_${slugFragment(concept.id)}_${Date.now()}`,
|
|
10431
|
+
timestamp: decision.decidedAt,
|
|
10432
|
+
changeType: "concept-rejected",
|
|
10433
|
+
conceptIds: [concept.id],
|
|
10434
|
+
reason: decision.rationale,
|
|
10435
|
+
evidenceIds: concept.evidenceIds,
|
|
10436
|
+
approvedBy: decision.decidedBy,
|
|
10437
|
+
ontologyVersion: ONTOLOGY_SPEC_VERSION
|
|
10438
|
+
});
|
|
10439
|
+
appendOntologyArtifact({
|
|
10440
|
+
concept,
|
|
10441
|
+
operation: "reject",
|
|
10442
|
+
sourceId: decision.id,
|
|
10443
|
+
summary: conceptArtifactSummary("Rejected", concept),
|
|
10444
|
+
metrics: {
|
|
10445
|
+
observations: concept.observationCount ?? 0,
|
|
10446
|
+
confidence: concept.confidence ?? 0,
|
|
10447
|
+
evidence: concept.evidenceIds?.length ?? 0
|
|
10448
|
+
}
|
|
10449
|
+
});
|
|
10450
|
+
}
|
|
10451
|
+
return {
|
|
10452
|
+
concept: loadResolvedOntologyFrontierConcepts().find((entry) => entry.id === params.conceptId) ?? null,
|
|
10453
|
+
extension: null
|
|
10454
|
+
};
|
|
10455
|
+
}
|
|
10456
|
+
function deprecateOntologyExtension(params) {
|
|
10457
|
+
const extensions = loadOntologyExtensions();
|
|
10458
|
+
const current = extensions.find((entry) => entry.id === params.conceptId);
|
|
10459
|
+
if (!current)
|
|
10460
|
+
return null;
|
|
10461
|
+
const governance = getActiveGovernanceSummary();
|
|
10462
|
+
const adoption = loadResolvedOntologyExtensions().find((entry) => entry.id === params.conceptId);
|
|
10463
|
+
const deprecated = {
|
|
10464
|
+
...current,
|
|
10465
|
+
status: "deprecated",
|
|
10466
|
+
lastObservedAt: maxTimestamp(current.lastObservedAt, new Date().toISOString())
|
|
10467
|
+
};
|
|
10468
|
+
saveOntologyExtensions([
|
|
10469
|
+
deprecated,
|
|
10470
|
+
...extensions.filter((entry) => entry.id !== params.conceptId)
|
|
10471
|
+
]);
|
|
10472
|
+
const consumerWarning = adoption && adoption.adoptionCount > 0 ? ` Warning: ${adoption.adoptionCount} active semantic consumer${adoption.adoptionCount === 1 ? "" : "s"} were visible before deprecation.` : "";
|
|
10473
|
+
appendOntologyChangeEvent({
|
|
10474
|
+
id: `ontology_change_deprecated_${slugFragment(current.id)}_${Date.now()}`,
|
|
10475
|
+
timestamp: new Date().toISOString(),
|
|
10476
|
+
changeType: "concept-deprecated",
|
|
10477
|
+
conceptIds: [current.id],
|
|
10478
|
+
reason: (params.rationale.trim() || `Deprecated ontology extension ${current.name}`) + consumerWarning,
|
|
10479
|
+
evidenceIds: current.evidenceIds,
|
|
10480
|
+
approvedBy: "operator",
|
|
10481
|
+
ontologyVersion: ONTOLOGY_SPEC_VERSION
|
|
10482
|
+
});
|
|
10483
|
+
appendOntologyArtifact({
|
|
10484
|
+
concept: deprecated,
|
|
10485
|
+
operation: "deprecate",
|
|
10486
|
+
sourceId: `${current.id}:deprecate`,
|
|
10487
|
+
summary: `Deprecated ontology extension ${deprecated.name} under ${governance.activeMode} governance.${consumerWarning}`,
|
|
10488
|
+
metrics: {
|
|
10489
|
+
observations: deprecated.observationCount ?? 0,
|
|
10490
|
+
confidence: deprecated.confidence ?? 0,
|
|
10491
|
+
adoptionCount: adoption?.adoptionCount ?? 0
|
|
10492
|
+
}
|
|
10493
|
+
});
|
|
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
|
+
};
|
|
10510
|
+
}
|
|
10511
|
+
function getOntologyReviewSummary() {
|
|
10512
|
+
const kernel = loadOntologyKernelSnapshot();
|
|
10513
|
+
const extensions = loadOntologyExtensions();
|
|
10514
|
+
const resolvedExtensions = loadResolvedOntologyExtensions();
|
|
10515
|
+
const frontier = loadResolvedOntologyFrontierConcepts();
|
|
10516
|
+
const changeEvents = loadOntologyChangeEvents();
|
|
10517
|
+
const adoption = getOntologyAdoptionSummary();
|
|
10518
|
+
const byConceptKind = ontologyKindCounts();
|
|
10519
|
+
for (const concept of [...extensions, ...frontier]) {
|
|
10520
|
+
byConceptKind[concept.conceptKind] = (byConceptKind[concept.conceptKind] ?? 0) + 1;
|
|
10521
|
+
}
|
|
10522
|
+
return {
|
|
10523
|
+
kernelConcepts: kernel.entityNames.length,
|
|
10524
|
+
extensions: extensions.length,
|
|
10525
|
+
frontier: frontier.length,
|
|
10526
|
+
reviewOpen: frontier.filter((concept) => concept.reviewStatus === "open").length,
|
|
10527
|
+
promoted: extensions.filter((concept) => concept.status === "active").length,
|
|
10528
|
+
rejected: frontier.filter((concept) => concept.reviewStatus === "rejected").length,
|
|
10529
|
+
deferred: frontier.filter((concept) => concept.reviewStatus === "deferred").length,
|
|
10530
|
+
deprecated: extensions.filter((concept) => concept.status === "deprecated").length,
|
|
10531
|
+
changeEvents: changeEvents.length,
|
|
10532
|
+
byConceptKind,
|
|
10533
|
+
adoption,
|
|
10534
|
+
backlog: frontier.filter((concept) => concept.reviewStatus === "open" || concept.reviewStatus === "deferred").slice(0, 10),
|
|
10535
|
+
recentChanges: changeEvents.slice(0, 10),
|
|
10536
|
+
recentExtensions: resolvedExtensions.slice(0, 8)
|
|
10537
|
+
};
|
|
10538
|
+
}
|
|
10022
10539
|
function buildDerivedEvolutionArtifact(iteration, proposal) {
|
|
10023
10540
|
return {
|
|
10024
10541
|
id: `artifact_derived_${iteration.id}_${proposal.id}`,
|
|
@@ -10142,7 +10659,15 @@ function loadPressureInterventions() {
|
|
|
10142
10659
|
return loadNativePressureInterventions().slice().sort((a, b) => (b.completedAt ?? b.createdAt).localeCompare(a.completedAt ?? a.createdAt));
|
|
10143
10660
|
}
|
|
10144
10661
|
function loadTransferEvents() {
|
|
10145
|
-
|
|
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));
|
|
10146
10671
|
}
|
|
10147
10672
|
function normalizePressureValue(value) {
|
|
10148
10673
|
return (value ?? "").trim().toLowerCase().replace(/[\s_/]+/g, "-");
|
|
@@ -10277,16 +10802,301 @@ function deriveGovernanceSummary(pressureSignals = loadPressureSignals(), interv
|
|
|
10277
10802
|
function getActiveGovernanceSummary() {
|
|
10278
10803
|
return deriveGovernanceSummary();
|
|
10279
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
|
+
}
|
|
10280
11089
|
function buildRouteRecommendation(params) {
|
|
10281
|
-
const { signal, relatedSignals, linkedInterventions, governanceMode } = params;
|
|
11090
|
+
const { signal, relatedSignals, linkedInterventions, governanceMode, governanceProfile, semanticBindings } = params;
|
|
10282
11091
|
const projectSpread = new Set(relatedSignals.map((entry) => entry.projectId ?? entry.projectPath).filter(Boolean)).size;
|
|
10283
11092
|
const recurrenceCount = relatedSignals.length;
|
|
10284
11093
|
const activeTypes = [...new Set(linkedInterventions.map((intervention) => intervention.interventionType))];
|
|
10285
11094
|
const reasons = [];
|
|
11095
|
+
let recommendation;
|
|
10286
11096
|
if (activeTypes.length >= 3 && !linkedInterventions.some((intervention) => intervention.status === "completed" && intervention.impact === "resolving")) {
|
|
10287
11097
|
reasons.push("Multiple intervention lanes already touch this pressure region without clear closure.");
|
|
10288
11098
|
reasons.push("Operator review is safer than blindly piling on another automated response.");
|
|
10289
|
-
|
|
11099
|
+
recommendation = {
|
|
10290
11100
|
route: "manual-review",
|
|
10291
11101
|
scope: projectSpread >= 2 ? "network" : signal.projectId ? "project" : "local",
|
|
10292
11102
|
confidence: 0.58,
|
|
@@ -10294,25 +11104,21 @@ function buildRouteRecommendation(params) {
|
|
|
10294
11104
|
triggeredBy: "mixed-signal",
|
|
10295
11105
|
reasons
|
|
10296
11106
|
};
|
|
10297
|
-
}
|
|
10298
|
-
if (projectSpread >= 2 && recurrenceCount >= 2) {
|
|
11107
|
+
} else if (projectSpread >= 2 && recurrenceCount >= 2 && governanceMode !== "project-critical") {
|
|
10299
11108
|
reasons.push(`This pressure region repeats across ${projectSpread} projects.`);
|
|
10300
11109
|
reasons.push("A network-level abstraction can absorb repeated local demand more efficiently than one-off fixes.");
|
|
10301
|
-
|
|
10302
|
-
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10306
|
-
|
|
10307
|
-
|
|
10308
|
-
|
|
10309
|
-
|
|
10310
|
-
}
|
|
10311
|
-
}
|
|
10312
|
-
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") {
|
|
10313
11119
|
reasons.push("The pressure is high priority and bounded to a known project context.");
|
|
10314
11120
|
reasons.push("Project-layer adaptation is the shortest truthful path to response.");
|
|
10315
|
-
|
|
11121
|
+
recommendation = {
|
|
10316
11122
|
route: "specialize",
|
|
10317
11123
|
scope: "project",
|
|
10318
11124
|
confidence: 0.82,
|
|
@@ -10320,11 +11126,10 @@ function buildRouteRecommendation(params) {
|
|
|
10320
11126
|
triggeredBy: "high-priority-local-gap",
|
|
10321
11127
|
reasons
|
|
10322
11128
|
};
|
|
10323
|
-
}
|
|
10324
|
-
if (signal.relatedFailureId && signal.severity >= 0.8) {
|
|
11129
|
+
} else if (signal.relatedFailureId && signal.severity >= 0.8) {
|
|
10325
11130
|
reasons.push("This pressure is tied to a concrete failure with strong corrective evidence.");
|
|
10326
11131
|
reasons.push("An evolution proposal can test a direct skill-level response against replay and regression evidence.");
|
|
10327
|
-
|
|
11132
|
+
recommendation = {
|
|
10328
11133
|
route: "evolve",
|
|
10329
11134
|
scope: signal.projectId ? "project" : "local",
|
|
10330
11135
|
confidence: 0.78,
|
|
@@ -10332,11 +11137,10 @@ function buildRouteRecommendation(params) {
|
|
|
10332
11137
|
triggeredBy: "accepted-iteration-pattern",
|
|
10333
11138
|
reasons
|
|
10334
11139
|
};
|
|
10335
|
-
}
|
|
10336
|
-
if (governanceMode === "exploration" || signal.suggestedAction === "research" || !signal.projectId) {
|
|
11140
|
+
} else if (governanceMode === "exploration" || signal.suggestedAction === "research" || !signal.projectId) {
|
|
10337
11141
|
reasons.push("The pressure still looks under-specified or capability-oriented.");
|
|
10338
11142
|
reasons.push("Research is the best way to widen evidence before committing to structural change.");
|
|
10339
|
-
|
|
11143
|
+
recommendation = {
|
|
10340
11144
|
route: "research",
|
|
10341
11145
|
scope: signal.projectId ? "project" : "local",
|
|
10342
11146
|
confidence: 0.68,
|
|
@@ -10344,11 +11148,10 @@ function buildRouteRecommendation(params) {
|
|
|
10344
11148
|
triggeredBy: "insufficient-evidence",
|
|
10345
11149
|
reasons
|
|
10346
11150
|
};
|
|
10347
|
-
}
|
|
10348
|
-
if (signal.projectId) {
|
|
11151
|
+
} else if (signal.projectId) {
|
|
10349
11152
|
reasons.push("The pressure is project-scoped and can likely be handled without network-wide promotion yet.");
|
|
10350
11153
|
reasons.push("Specialization is the most direct bounded intervention available.");
|
|
10351
|
-
|
|
11154
|
+
recommendation = {
|
|
10352
11155
|
route: "specialize",
|
|
10353
11156
|
scope: "project",
|
|
10354
11157
|
confidence: 0.7,
|
|
@@ -10356,17 +11159,24 @@ function buildRouteRecommendation(params) {
|
|
|
10356
11159
|
triggeredBy: "project-bounded-recurrence",
|
|
10357
11160
|
reasons
|
|
10358
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
|
+
};
|
|
10359
11173
|
}
|
|
10360
|
-
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10366
|
-
governanceMode,
|
|
10367
|
-
triggeredBy: "insufficient-evidence",
|
|
10368
|
-
reasons
|
|
10369
|
-
};
|
|
11174
|
+
return applyOntologyInfluenceToRoute({
|
|
11175
|
+
recommendation,
|
|
11176
|
+
signal,
|
|
11177
|
+
semanticBindings,
|
|
11178
|
+
governanceProfile
|
|
11179
|
+
});
|
|
10370
11180
|
}
|
|
10371
11181
|
function interventionEvidenceAccepted(intervention, acceptedProposalIds, acceptedArtifactIds, realizedTransferEventIds) {
|
|
10372
11182
|
if (intervention.status !== "completed" || intervention.impact !== "resolving")
|
|
@@ -10395,6 +11205,7 @@ function loadResolvedPressureSignals() {
|
|
|
10395
11205
|
const history = loadHistory();
|
|
10396
11206
|
const artifacts = loadEvolutionArtifacts();
|
|
10397
11207
|
const governance = deriveGovernanceSummary(pressureSignals, interventions);
|
|
11208
|
+
const concepts = activeOntologyExtensions();
|
|
10398
11209
|
const acceptedProposalIds = new Set(history.iterations.flatMap((iteration) => iteration.proposals).filter((proposal) => proposal.outcome === "accepted").map((proposal) => proposal.id));
|
|
10399
11210
|
const acceptedArtifactIds = new Set(artifacts.filter((artifact) => artifact.outcome === "accepted").map((artifact) => artifact.id));
|
|
10400
11211
|
const realizedTransferEventIds = new Set(transferEvents.filter((event) => event.status === "realized").map((event) => event.id));
|
|
@@ -10421,17 +11232,22 @@ function loadResolvedPressureSignals() {
|
|
|
10421
11232
|
const relatedSignals = signalsByRegion.get(pressureRegionKey(signal)) ?? [signal];
|
|
10422
11233
|
const projectSpread = new Set(relatedSignals.map((entry) => entry.projectId ?? entry.projectPath).filter(Boolean)).size;
|
|
10423
11234
|
const motifIds = relatedSignals.length >= 2 || projectSpread >= 2 ? [motifIdForSignal(signal)] : [];
|
|
11235
|
+
const semanticBindings = matchSignalOntologyBindings(signal, motifIds, concepts);
|
|
10424
11236
|
const routeRecommendation = buildRouteRecommendation({
|
|
10425
11237
|
signal,
|
|
10426
11238
|
relatedSignals,
|
|
10427
11239
|
linkedInterventions,
|
|
10428
|
-
governanceMode: governance.activeMode
|
|
11240
|
+
governanceMode: governance.activeMode,
|
|
11241
|
+
governanceProfile: governance.profile,
|
|
11242
|
+
semanticBindings
|
|
10429
11243
|
});
|
|
10430
11244
|
const lifecycle = addressingInterventions.length > 0 || signal.status === "addressed" ? "addressed" : activeInterventions.length > 0 ? "in-progress" : hasNewerEquivalentSignal ? "stale" : "open";
|
|
10431
11245
|
const lastActivityAt = [signal.detectedAt, latestInterventionAt].filter(Boolean).sort((a, b) => b.localeCompare(a))[0] ?? signal.detectedAt;
|
|
10432
11246
|
const interventionTypes = [...new Set(linkedInterventions.map((intervention) => intervention.interventionType))];
|
|
10433
11247
|
const addressedAt = addressingInterventions.map((intervention) => intervention.completedAt ?? intervention.createdAt).sort((a, b) => b.localeCompare(a))[0];
|
|
10434
|
-
const
|
|
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}`;
|
|
10435
11251
|
return {
|
|
10436
11252
|
...signal,
|
|
10437
11253
|
lifecycle,
|
|
@@ -10439,6 +11255,8 @@ function loadResolvedPressureSignals() {
|
|
|
10439
11255
|
interventionTypes,
|
|
10440
11256
|
motifIds,
|
|
10441
11257
|
routeRecommendation,
|
|
11258
|
+
semanticBindings,
|
|
11259
|
+
semanticConceptIds: uniqueStrings(semanticBindings.map((binding) => binding.conceptId)),
|
|
10442
11260
|
lastActivityAt,
|
|
10443
11261
|
addressedAt,
|
|
10444
11262
|
responseSummary
|
|
@@ -10449,6 +11267,7 @@ function loadPressureMotifs() {
|
|
|
10449
11267
|
const resolvedSignals = loadResolvedPressureSignals();
|
|
10450
11268
|
const interventions = loadPressureInterventions();
|
|
10451
11269
|
const transferEvents = loadTransferEvents();
|
|
11270
|
+
const concepts = activeOntologyExtensions();
|
|
10452
11271
|
const groups = new Map;
|
|
10453
11272
|
for (const signal of resolvedSignals) {
|
|
10454
11273
|
const regionKey = pressureRegionKey(signal);
|
|
@@ -10493,7 +11312,15 @@ function loadPressureMotifs() {
|
|
|
10493
11312
|
const linkedInterventionIds = linkedInterventions.map((intervention) => intervention.id);
|
|
10494
11313
|
const linkedTransferEventIds = linkedTransferEvents.map((event) => event.id);
|
|
10495
11314
|
const highPriorityCount = signals.filter((signal) => signal.priority === "high").length;
|
|
10496
|
-
const
|
|
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}`;
|
|
10497
11324
|
motifs.push({
|
|
10498
11325
|
id: motifId,
|
|
10499
11326
|
key: regionKey,
|
|
@@ -10512,6 +11339,8 @@ function loadPressureMotifs() {
|
|
|
10512
11339
|
suggestedRoute: recommendation,
|
|
10513
11340
|
lifecycle,
|
|
10514
11341
|
interventionTypes,
|
|
11342
|
+
semanticBindings,
|
|
11343
|
+
semanticConceptIds: uniqueStrings(semanticBindings.map((binding) => binding.conceptId)),
|
|
10515
11344
|
lastActivityAt,
|
|
10516
11345
|
addressedAt,
|
|
10517
11346
|
responseSummary
|
|
@@ -10522,6 +11351,116 @@ function loadPressureMotifs() {
|
|
|
10522
11351
|
return lifecycleWeight(b.lifecycle) - lifecycleWeight(a.lifecycle) || b.highPriorityCount - a.highPriorityCount || b.recurrenceCount - a.recurrenceCount || b.lastActivityAt.localeCompare(a.lastActivityAt);
|
|
10523
11352
|
});
|
|
10524
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
|
+
}
|
|
10525
11464
|
function matchPressureSignals(filters) {
|
|
10526
11465
|
const capabilities = new Set((filters.capabilities ?? []).map((value) => normalizePressureValue(value)));
|
|
10527
11466
|
const relatedFailureIds = new Set(filters.relatedFailureIds ?? []);
|
|
@@ -15875,9 +16814,157 @@ async function topologyCommand(options) {
|
|
|
15875
16814
|
}
|
|
15876
16815
|
}
|
|
15877
16816
|
|
|
16817
|
+
// src/commands/ontology.ts
|
|
16818
|
+
init_data();
|
|
16819
|
+
function printStatus2() {
|
|
16820
|
+
const summary = getOntologyReviewSummary();
|
|
16821
|
+
console.log(`
|
|
16822
|
+
Ontology Frontier`);
|
|
16823
|
+
console.log(" ────────────────────────────────────────");
|
|
16824
|
+
console.log(` Kernel: ${summary.kernelConcepts} canonical entities`);
|
|
16825
|
+
console.log(` Extensions: ${summary.extensions} active • ${summary.deprecated} deprecated`);
|
|
16826
|
+
console.log(` Frontier: ${summary.frontier} total • ${summary.reviewOpen} open • ${summary.deferred} deferred • ${summary.rejected} rejected`);
|
|
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`);
|
|
16830
|
+
if (summary.backlog.length > 0) {
|
|
16831
|
+
console.log(`
|
|
16832
|
+
Frontier concepts ready for review`);
|
|
16833
|
+
for (const concept of summary.backlog.slice(0, 5)) {
|
|
16834
|
+
console.log(` • ${concept.id} (${concept.conceptKind}) • ${concept.reviewStatus}`);
|
|
16835
|
+
}
|
|
16836
|
+
}
|
|
16837
|
+
if (summary.recentExtensions.length > 0) {
|
|
16838
|
+
console.log(`
|
|
16839
|
+
Approved extensions`);
|
|
16840
|
+
for (const concept of summary.recentExtensions.slice(0, 5)) {
|
|
16841
|
+
const warning = concept.warning ? " • deprecation risk" : "";
|
|
16842
|
+
console.log(` • ${concept.id} (${concept.conceptKind}) • ${concept.status} • ${concept.adoptionCount} bindings${warning}`);
|
|
16843
|
+
}
|
|
16844
|
+
}
|
|
16845
|
+
console.log();
|
|
16846
|
+
}
|
|
16847
|
+
async function ontologyCommand(options) {
|
|
16848
|
+
materializeOntologyKernelSnapshot();
|
|
16849
|
+
const actions = [
|
|
16850
|
+
options.refresh ? "refresh" : null,
|
|
16851
|
+
options.review ? "review" : null,
|
|
16852
|
+
options.deprecate ? "deprecate" : null
|
|
16853
|
+
].filter(Boolean);
|
|
16854
|
+
if (actions.length > 1) {
|
|
16855
|
+
throw new Error("Use only one of --refresh, --review, or --deprecate at a time");
|
|
16856
|
+
}
|
|
16857
|
+
if (options.refresh) {
|
|
16858
|
+
const result = refreshOntologyFrontier();
|
|
16859
|
+
console.log(`
|
|
16860
|
+
✓ Refreshed ontology frontier`);
|
|
16861
|
+
console.log(` created: ${result.created}`);
|
|
16862
|
+
console.log(` updated: ${result.updated}`);
|
|
16863
|
+
console.log(` frontier total: ${result.total}`);
|
|
16864
|
+
console.log(` open review: ${result.open}`);
|
|
16865
|
+
if (options.verbose && result.concepts.length > 0) {
|
|
16866
|
+
for (const concept of result.concepts.slice(0, 8)) {
|
|
16867
|
+
console.log(` • ${concept.id} (${concept.conceptKind}) • ${concept.observationCount ?? 0} obs • ${(concept.confidence ?? 0).toFixed(2)} conf`);
|
|
16868
|
+
}
|
|
16869
|
+
}
|
|
16870
|
+
console.log();
|
|
16871
|
+
return;
|
|
16872
|
+
}
|
|
16873
|
+
if (options.review) {
|
|
16874
|
+
if (!options.decision) {
|
|
16875
|
+
throw new Error("--decision <promote|reject|defer> is required with --review");
|
|
16876
|
+
}
|
|
16877
|
+
const result = reviewOntologyConcept({
|
|
16878
|
+
conceptId: options.review,
|
|
16879
|
+
decision: options.decision,
|
|
16880
|
+
rationale: options.rationale ?? `${options.decision} ontology concept via CLI review`
|
|
16881
|
+
});
|
|
16882
|
+
if (!result.concept && !result.extension) {
|
|
16883
|
+
throw new Error(`Unknown ontology frontier concept: ${options.review}`);
|
|
16884
|
+
}
|
|
16885
|
+
console.log(`
|
|
16886
|
+
✓ Recorded ontology review: ${options.review}`);
|
|
16887
|
+
console.log(` decision: ${options.decision}`);
|
|
16888
|
+
if (result.extension) {
|
|
16889
|
+
console.log(` promoted extension: ${result.extension.id}`);
|
|
16890
|
+
console.log(` status: ${result.extension.status}`);
|
|
16891
|
+
} else if (result.concept) {
|
|
16892
|
+
console.log(` review status: ${result.concept.reviewStatus}`);
|
|
16893
|
+
console.log(` concept kind: ${result.concept.conceptKind}`);
|
|
16894
|
+
}
|
|
16895
|
+
console.log();
|
|
16896
|
+
return;
|
|
16897
|
+
}
|
|
16898
|
+
if (options.deprecate) {
|
|
16899
|
+
const concept = deprecateOntologyExtension({
|
|
16900
|
+
conceptId: options.deprecate,
|
|
16901
|
+
rationale: options.rationale ?? `Deprecated ontology extension ${options.deprecate} via CLI`
|
|
16902
|
+
});
|
|
16903
|
+
if (!concept) {
|
|
16904
|
+
throw new Error(`Unknown ontology extension: ${options.deprecate}`);
|
|
16905
|
+
}
|
|
16906
|
+
console.log(`
|
|
16907
|
+
✓ Deprecated ontology extension: ${concept.id}`);
|
|
16908
|
+
console.log(` kind: ${concept.conceptKind}`);
|
|
16909
|
+
console.log(` status: ${concept.status}`);
|
|
16910
|
+
if (concept.warning) {
|
|
16911
|
+
console.log(` warning: ${concept.warning}`);
|
|
16912
|
+
}
|
|
16913
|
+
console.log();
|
|
16914
|
+
return;
|
|
16915
|
+
}
|
|
16916
|
+
printStatus2();
|
|
16917
|
+
if (options.verbose) {
|
|
16918
|
+
const summary = getOntologyReviewSummary();
|
|
16919
|
+
const frontier = loadResolvedOntologyFrontierConcepts().slice(0, 8);
|
|
16920
|
+
const changes = loadOntologyChangeEvents().slice(0, 8);
|
|
16921
|
+
const extensions = loadResolvedOntologyExtensions().slice(0, 8);
|
|
16922
|
+
if (frontier.length > 0) {
|
|
16923
|
+
console.log(" Recent frontier concepts");
|
|
16924
|
+
for (const concept of frontier) {
|
|
16925
|
+
console.log(` • ${concept.id} • ${concept.conceptKind} • ${concept.reviewStatus} • ${concept.observationCount ?? 0} obs`);
|
|
16926
|
+
}
|
|
16927
|
+
console.log();
|
|
16928
|
+
}
|
|
16929
|
+
if (extensions.length > 0) {
|
|
16930
|
+
console.log(" Recent approved extensions");
|
|
16931
|
+
for (const concept of extensions) {
|
|
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}`);
|
|
16952
|
+
}
|
|
16953
|
+
console.log();
|
|
16954
|
+
}
|
|
16955
|
+
if (changes.length > 0) {
|
|
16956
|
+
console.log(" Recent ontology changes");
|
|
16957
|
+
for (const event of changes) {
|
|
16958
|
+
console.log(` • ${event.changeType} • ${event.conceptIds.join(", ")} • ${event.timestamp}`);
|
|
16959
|
+
}
|
|
16960
|
+
console.log();
|
|
16961
|
+
}
|
|
16962
|
+
}
|
|
16963
|
+
}
|
|
16964
|
+
|
|
15878
16965
|
// src/cli.ts
|
|
15879
16966
|
var program2 = new Command;
|
|
15880
|
-
program2.name("helixevo").description("
|
|
16967
|
+
program2.name("helixevo").description("Co-evolving skill and project brain for AI agents").version(VERSION).addHelpText("after", `
|
|
15881
16968
|
Examples:
|
|
15882
16969
|
$ helixevo watch Always-on learning (auto-capture + auto-evolve)
|
|
15883
16970
|
$ helixevo watch --project myapp Watch with project context
|
|
@@ -15898,6 +16985,10 @@ Examples:
|
|
|
15898
16985
|
$ helixevo topology --prepare <id> Prepare an accepted topology candidate
|
|
15899
16986
|
$ helixevo topology --apply <planId> Apply a safe prepared topology plan
|
|
15900
16987
|
$ helixevo topology --rollback <planId> Roll back an applied topology plan
|
|
16988
|
+
$ helixevo ontology --status --verbose Show frontier, extension, adoption, and deprecation-risk visibility
|
|
16989
|
+
$ helixevo ontology --refresh Derive frontier concepts from recurring evidence
|
|
16990
|
+
$ helixevo ontology --review <id> --decision promote
|
|
16991
|
+
Promote a reviewed frontier concept into approved extensions
|
|
15901
16992
|
$ helixevo report --days 7 Weekly evolution report
|
|
15902
16993
|
$ helixevo capture <session.json> Extract failures from session`);
|
|
15903
16994
|
program2.command("init").description("Import existing skills + generate skill tests").option("--skills-paths <paths...>", "Paths to scan for existing skills").option("--skip-tests", "Skip skill test generation").action(initCommand);
|
|
@@ -15921,6 +17012,7 @@ program2.command("health").description("Assess network health: cohesion, coverag
|
|
|
15921
17012
|
program2.command("metrics").description("Show correction rates, skill trends, and evolution impact").option("--verbose", "Show detailed per-skill breakdown").action(metricsCommand);
|
|
15922
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);
|
|
15923
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);
|
|
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);
|
|
15924
17016
|
program2.hook("postAction", () => {
|
|
15925
17017
|
checkForUpdates().catch(() => {});
|
|
15926
17018
|
});
|