helixevo 0.6.1 → 0.7.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 +12 -0
- package/README.md +9 -2
- package/dashboard/app/api/proof/route.ts +71 -0
- package/dashboard/app/api/run/route.ts +1 -0
- package/dashboard/app/coevolution/client.tsx +6 -1
- package/dashboard/app/coevolution/page.tsx +3 -1
- package/dashboard/app/commands/page.tsx +32 -5
- package/dashboard/app/guide/page.tsx +34 -21
- package/dashboard/app/ontology/client.tsx +8 -1
- package/dashboard/app/ontology/page.tsx +3 -1
- package/dashboard/app/page.tsx +6 -0
- package/dashboard/app/proof/client.tsx +295 -0
- package/dashboard/app/proof/page.tsx +9 -0
- package/dashboard/app/topology/client.tsx +9 -0
- package/dashboard/app/topology/page.tsx +3 -1
- package/dashboard/components/sidebar-nav.tsx +1 -0
- package/dashboard/lib/loop-map.ts +23 -3
- package/dashboard/lib/proof.ts +577 -0
- package/dashboard/lib/release-spotlight.ts +10 -10
- package/dist/cli.js +500 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -13330,6 +13330,7 @@ async function statusCommand() {
|
|
|
13330
13330
|
} else {
|
|
13331
13331
|
console.log(` ○ Need ${5 - unresolved.length} more failures before next evolution`);
|
|
13332
13332
|
}
|
|
13333
|
+
console.log(" → Review broader outcome attribution with: helixevo proof --status");
|
|
13333
13334
|
console.log();
|
|
13334
13335
|
}
|
|
13335
13336
|
|
|
@@ -13421,6 +13422,12 @@ async function reportCommand(options) {
|
|
|
13421
13422
|
report += `- **${s.slug}**${evolved}
|
|
13422
13423
|
`;
|
|
13423
13424
|
}
|
|
13425
|
+
report += `
|
|
13426
|
+
## Next Operator Step
|
|
13427
|
+
|
|
13428
|
+
`;
|
|
13429
|
+
report += `- Run **helixevo proof --status** to inspect outcome attribution across interventions, topology, ontology, and evolution evidence.
|
|
13430
|
+
`;
|
|
13424
13431
|
const outputPath = options.output ?? join10(getHelixDir(), "reports", `${date}.md`);
|
|
13425
13432
|
ensureDir(join10(getHelixDir(), "reports"));
|
|
13426
13433
|
writeFileSync6(outputPath, report);
|
|
@@ -16092,6 +16099,8 @@ async function metricsCommand(options) {
|
|
|
16092
16099
|
}
|
|
16093
16100
|
console.log();
|
|
16094
16101
|
}
|
|
16102
|
+
console.log(' → For broader intervention / topology / ontology outcome review, run "helixevo proof --status"');
|
|
16103
|
+
console.log();
|
|
16095
16104
|
}
|
|
16096
16105
|
|
|
16097
16106
|
// src/commands/project-setup.ts
|
|
@@ -16962,6 +16971,493 @@ async function ontologyCommand(options) {
|
|
|
16962
16971
|
}
|
|
16963
16972
|
}
|
|
16964
16973
|
|
|
16974
|
+
// src/core/proof.ts
|
|
16975
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
|
|
16976
|
+
import { join as join22 } from "node:path";
|
|
16977
|
+
init_config();
|
|
16978
|
+
init_data();
|
|
16979
|
+
var PROOF_REVIEW_FILE = "proof-reviews.jsonl";
|
|
16980
|
+
var MEASURING_WINDOW_DAYS = 2;
|
|
16981
|
+
function proofPath() {
|
|
16982
|
+
return join22(getHelixDir(), PROOF_REVIEW_FILE);
|
|
16983
|
+
}
|
|
16984
|
+
function uniqueStrings3(values) {
|
|
16985
|
+
return [...new Set(values.filter((value) => Boolean(value && value.trim())))];
|
|
16986
|
+
}
|
|
16987
|
+
function maxTimestamp2(...values) {
|
|
16988
|
+
const filtered = values.filter((value) => Boolean(value)).sort();
|
|
16989
|
+
return filtered[filtered.length - 1] ?? new Date(0).toISOString();
|
|
16990
|
+
}
|
|
16991
|
+
function ageDays(value) {
|
|
16992
|
+
if (!value)
|
|
16993
|
+
return Number.POSITIVE_INFINITY;
|
|
16994
|
+
return (Date.now() - new Date(value).getTime()) / (1000 * 60 * 60 * 24);
|
|
16995
|
+
}
|
|
16996
|
+
function buildRecordId(targetType, targetId) {
|
|
16997
|
+
return `${targetType}:${targetId}`;
|
|
16998
|
+
}
|
|
16999
|
+
function readProofReviews() {
|
|
17000
|
+
const path = proofPath();
|
|
17001
|
+
if (!existsSync17(path))
|
|
17002
|
+
return [];
|
|
17003
|
+
const raw = readFileSync14(path, "utf-8").trim();
|
|
17004
|
+
if (!raw)
|
|
17005
|
+
return [];
|
|
17006
|
+
return raw.split(`
|
|
17007
|
+
`).filter(Boolean).map((line) => JSON.parse(line));
|
|
17008
|
+
}
|
|
17009
|
+
function loadProofReviews() {
|
|
17010
|
+
return readProofReviews().sort((a, b) => b.decidedAt.localeCompare(a.decidedAt));
|
|
17011
|
+
}
|
|
17012
|
+
function appendProofReview(record) {
|
|
17013
|
+
appendJsonl(PROOF_REVIEW_FILE, record);
|
|
17014
|
+
}
|
|
17015
|
+
function reviewStatusFor(decision) {
|
|
17016
|
+
if (!decision)
|
|
17017
|
+
return "open";
|
|
17018
|
+
if (decision.decision === "verify")
|
|
17019
|
+
return "verified";
|
|
17020
|
+
if (decision.decision === "defer")
|
|
17021
|
+
return "deferred";
|
|
17022
|
+
return "contested";
|
|
17023
|
+
}
|
|
17024
|
+
function confidenceFor(outcome, evidenceCount) {
|
|
17025
|
+
const base = outcome === "effective" ? 0.76 : outcome === "regressed" ? 0.82 : outcome === "mixed" ? 0.64 : outcome === "measuring" ? 0.52 : 0.42;
|
|
17026
|
+
return Math.min(0.96, base + Math.min(evidenceCount, 8) * 0.035);
|
|
17027
|
+
}
|
|
17028
|
+
function evaluateLifecycleOutcome(items, targetAt, explicitRegression = false) {
|
|
17029
|
+
if (explicitRegression)
|
|
17030
|
+
return "regressed";
|
|
17031
|
+
const addressed = items.filter((item) => item.lifecycle === "addressed").length;
|
|
17032
|
+
const active = items.filter((item) => item.lifecycle === "open" || item.lifecycle === "in-progress").length;
|
|
17033
|
+
if (items.length === 0) {
|
|
17034
|
+
return ageDays(targetAt) <= MEASURING_WINDOW_DAYS ? "measuring" : "insufficient-evidence";
|
|
17035
|
+
}
|
|
17036
|
+
if (addressed > 0 && active === 0)
|
|
17037
|
+
return "effective";
|
|
17038
|
+
if (addressed > 0 && active > 0)
|
|
17039
|
+
return "mixed";
|
|
17040
|
+
if (ageDays(targetAt) <= MEASURING_WINDOW_DAYS)
|
|
17041
|
+
return "measuring";
|
|
17042
|
+
return "insufficient-evidence";
|
|
17043
|
+
}
|
|
17044
|
+
function latestReviewByRecord() {
|
|
17045
|
+
const latest = new Map;
|
|
17046
|
+
for (const review of loadProofReviews()) {
|
|
17047
|
+
const existing = latest.get(review.recordId);
|
|
17048
|
+
if (!existing || review.decidedAt > existing.decidedAt) {
|
|
17049
|
+
latest.set(review.recordId, review);
|
|
17050
|
+
}
|
|
17051
|
+
}
|
|
17052
|
+
return latest;
|
|
17053
|
+
}
|
|
17054
|
+
function buildInterventionProofRecords() {
|
|
17055
|
+
const signals = loadResolvedPressureSignals();
|
|
17056
|
+
const motifs = loadPressureMotifs();
|
|
17057
|
+
return loadPressureInterventions().map((intervention) => {
|
|
17058
|
+
const linkedSignals = signals.filter((signal) => intervention.pressureSignalIds?.includes(signal.id) || signal.linkedInterventions.some((linked) => linked.id === intervention.id));
|
|
17059
|
+
const linkedMotifs = motifs.filter((motif) => intervention.motifIds?.includes(motif.id) || motif.linkedInterventionIds.includes(intervention.id));
|
|
17060
|
+
const targetAt = intervention.completedAt ?? intervention.createdAt;
|
|
17061
|
+
const lifecycleItems = [...linkedSignals, ...linkedMotifs];
|
|
17062
|
+
const outcomeState = intervention.status === "failed" ? "regressed" : intervention.status === "dry-run" ? "insufficient-evidence" : evaluateLifecycleOutcome(lifecycleItems, targetAt);
|
|
17063
|
+
const evidenceCount = linkedSignals.length + linkedMotifs.length;
|
|
17064
|
+
const reasons = [
|
|
17065
|
+
`${intervention.interventionType} recorded as ${intervention.status} with ${evidenceCount} linked pressure target${evidenceCount === 1 ? "" : "s"}.`,
|
|
17066
|
+
outcomeState === "effective" ? "All linked pressure evidence currently resolves to addressed state." : outcomeState === "mixed" ? "Linked pressure evidence is split between addressed and still-active states." : outcomeState === "regressed" ? "The intervention failed explicitly, so proof treats it as regressed." : outcomeState === "measuring" ? "The intervention is still too recent or too active for a stronger proof verdict." : intervention.status === "dry-run" ? "Dry-run interventions do not create live effect evidence." : "Linked evidence is too weak to attribute a stronger effect safely."
|
|
17067
|
+
];
|
|
17068
|
+
return {
|
|
17069
|
+
id: buildRecordId("pressure-intervention", intervention.id),
|
|
17070
|
+
targetType: "pressure-intervention",
|
|
17071
|
+
targetId: intervention.id,
|
|
17072
|
+
title: `${intervention.interventionType} intervention`,
|
|
17073
|
+
summary: intervention.reasonSummary,
|
|
17074
|
+
createdAt: intervention.createdAt,
|
|
17075
|
+
lastActivityAt: maxTimestamp2(intervention.completedAt, ...linkedSignals.map((signal) => signal.lastActivityAt), ...linkedMotifs.map((motif) => motif.lastActivityAt), intervention.createdAt),
|
|
17076
|
+
outcomeState,
|
|
17077
|
+
reviewStatus: "open",
|
|
17078
|
+
confidence: confidenceFor(outcomeState, evidenceCount),
|
|
17079
|
+
reasons,
|
|
17080
|
+
metrics: {
|
|
17081
|
+
linkedSignals: linkedSignals.length,
|
|
17082
|
+
linkedMotifs: linkedMotifs.length,
|
|
17083
|
+
addressed: lifecycleItems.filter((item) => item.lifecycle === "addressed").length
|
|
17084
|
+
},
|
|
17085
|
+
relatedProjectIds: uniqueStrings3([intervention.projectId, ...linkedSignals.map((signal) => signal.projectId), ...linkedMotifs.flatMap((motif) => motif.projectIds)]),
|
|
17086
|
+
relatedSignalIds: linkedSignals.map((signal) => signal.id),
|
|
17087
|
+
relatedMotifIds: linkedMotifs.map((motif) => motif.id),
|
|
17088
|
+
relatedTransferEventIds: uniqueStrings3([
|
|
17089
|
+
...intervention.relatedTransferEventIds ?? [],
|
|
17090
|
+
...linkedMotifs.flatMap((motif) => motif.linkedTransferEventIds ?? [])
|
|
17091
|
+
]),
|
|
17092
|
+
semanticConceptIds: uniqueStrings3([
|
|
17093
|
+
...linkedSignals.flatMap((signal) => signal.semanticConceptIds ?? []),
|
|
17094
|
+
...linkedMotifs.flatMap((motif) => motif.semanticConceptIds ?? [])
|
|
17095
|
+
]),
|
|
17096
|
+
recommendedAction: outcomeState === "effective" ? "Verify if this resolving pattern should remain a trusted lane." : outcomeState === "mixed" ? "Inspect Co-Evolution and compare remaining active pressure before re-routing." : outcomeState === "regressed" ? "Inspect Co-Evolution for a different governed response or manual review." : outcomeState === "measuring" ? "Let the intervention age or accumulate more downstream evidence before review." : "Link stronger downstream evidence before treating this intervention as proven."
|
|
17097
|
+
};
|
|
17098
|
+
});
|
|
17099
|
+
}
|
|
17100
|
+
function buildTransferProofRecords() {
|
|
17101
|
+
const motifs = loadPressureMotifs();
|
|
17102
|
+
const signals = loadResolvedPressureSignals();
|
|
17103
|
+
return loadTransferEvents().filter((event) => event.status === "realized").map((event) => {
|
|
17104
|
+
const linkedMotifs = motifs.filter((motif) => event.motifIds?.includes(motif.id) || motif.linkedTransferEventIds.includes(event.id));
|
|
17105
|
+
const linkedSignals = signals.filter((signal) => signal.motifIds?.some((motifId) => event.motifIds?.includes(motifId)));
|
|
17106
|
+
const lifecycleItems = [...linkedSignals, ...linkedMotifs];
|
|
17107
|
+
const outcomeState = evaluateLifecycleOutcome(lifecycleItems, event.timestamp);
|
|
17108
|
+
const evidenceCount = linkedSignals.length + linkedMotifs.length;
|
|
17109
|
+
const reasons = [
|
|
17110
|
+
`${event.transferType} transfer is realized and linked to ${linkedMotifs.length} motifs plus ${linkedSignals.length} correlated signals.`,
|
|
17111
|
+
outcomeState === "effective" ? "Linked motif pressure currently resolves cleanly to addressed state." : outcomeState === "mixed" ? "Some linked motif pressure is addressed, but some remains active." : outcomeState === "measuring" ? "The realized transfer is still recent enough that proof stays in measuring mode." : "Transfer evidence exists, but downstream relief is too weak to call it effective yet."
|
|
17112
|
+
];
|
|
17113
|
+
return {
|
|
17114
|
+
id: buildRecordId("transfer-event", event.id),
|
|
17115
|
+
targetType: "transfer-event",
|
|
17116
|
+
targetId: event.id,
|
|
17117
|
+
title: `${event.transferType} transfer`,
|
|
17118
|
+
summary: event.summary ?? "Realized transfer event",
|
|
17119
|
+
createdAt: event.timestamp,
|
|
17120
|
+
lastActivityAt: maxTimestamp2(event.timestamp, ...linkedSignals.map((signal) => signal.lastActivityAt), ...linkedMotifs.map((motif) => motif.lastActivityAt)),
|
|
17121
|
+
outcomeState,
|
|
17122
|
+
reviewStatus: "open",
|
|
17123
|
+
confidence: confidenceFor(outcomeState, evidenceCount),
|
|
17124
|
+
reasons,
|
|
17125
|
+
metrics: {
|
|
17126
|
+
linkedSignals: linkedSignals.length,
|
|
17127
|
+
linkedMotifs: linkedMotifs.length,
|
|
17128
|
+
addressed: lifecycleItems.filter((item) => item.lifecycle === "addressed").length
|
|
17129
|
+
},
|
|
17130
|
+
relatedProjectIds: uniqueStrings3([event.sourceProjectId, event.targetProjectId, ...linkedMotifs.flatMap((motif) => motif.projectIds)]),
|
|
17131
|
+
relatedSignalIds: linkedSignals.map((signal) => signal.id),
|
|
17132
|
+
relatedMotifIds: linkedMotifs.map((motif) => motif.id),
|
|
17133
|
+
relatedTransferEventIds: [event.id],
|
|
17134
|
+
semanticConceptIds: uniqueStrings3([
|
|
17135
|
+
...event.semanticConceptIds ?? [],
|
|
17136
|
+
...linkedSignals.flatMap((signal) => signal.semanticConceptIds ?? []),
|
|
17137
|
+
...linkedMotifs.flatMap((motif) => motif.semanticConceptIds ?? [])
|
|
17138
|
+
]),
|
|
17139
|
+
recommendedAction: outcomeState === "effective" ? "Verify whether this transfer pattern should be treated as proven reusable evidence." : outcomeState === "mixed" ? "Inspect remaining active motifs before treating this transfer as fully proven." : outcomeState === "measuring" ? "Wait for more motif pressure movement before review." : "Accumulate more downstream motif or signal relief before verifying this transfer."
|
|
17140
|
+
};
|
|
17141
|
+
});
|
|
17142
|
+
}
|
|
17143
|
+
function buildTopologyProofRecords() {
|
|
17144
|
+
const candidatesById = new Map(loadResolvedTopologyReviewCandidates().map((candidate) => [candidate.id, candidate]));
|
|
17145
|
+
const signals = loadResolvedPressureSignals();
|
|
17146
|
+
const motifs = loadPressureMotifs();
|
|
17147
|
+
return loadResolvedTopologyApplyPlans().map((plan) => {
|
|
17148
|
+
const candidate = candidatesById.get(plan.candidateId);
|
|
17149
|
+
const latestStatus = plan.latestStatus;
|
|
17150
|
+
const linkedSignals = signals.filter((signal) => candidate?.relatedSignalIds?.includes(signal.id));
|
|
17151
|
+
const linkedMotifs = motifs.filter((motif) => candidate?.relatedMotifIds?.includes(motif.id));
|
|
17152
|
+
const lifecycleItems = [...linkedSignals, ...linkedMotifs];
|
|
17153
|
+
const targetAt = plan.latestExecution?.executedAt ?? plan.createdAt;
|
|
17154
|
+
const explicitRegression = latestStatus === "rolled-back" || latestStatus === "failed";
|
|
17155
|
+
const outcomeState = latestStatus === "pending" || latestStatus === "prepared" ? "measuring" : evaluateLifecycleOutcome(lifecycleItems, targetAt, explicitRegression);
|
|
17156
|
+
const evidenceCount = linkedSignals.length + linkedMotifs.length;
|
|
17157
|
+
const reasons = [
|
|
17158
|
+
`${plan.changeType} topology plan is currently ${latestStatus}.`,
|
|
17159
|
+
explicitRegression ? "Rollback or failed execution is treated as explicit negative evidence." : outcomeState === "effective" ? "Linked structural pressure currently resolves to addressed state after apply." : outcomeState === "mixed" ? "Structural apply has some correlated relief, but not a clean closure." : outcomeState === "measuring" ? "Prepared or recently applied topology changes remain in measuring mode until more evidence accrues." : "There is not enough downstream structural-pressure evidence for a stronger verdict yet."
|
|
17160
|
+
];
|
|
17161
|
+
return {
|
|
17162
|
+
id: buildRecordId("topology-execution", plan.id),
|
|
17163
|
+
targetType: "topology-execution",
|
|
17164
|
+
targetId: plan.id,
|
|
17165
|
+
title: `${plan.changeType} topology execution`,
|
|
17166
|
+
summary: plan.reasonSummary,
|
|
17167
|
+
createdAt: plan.createdAt,
|
|
17168
|
+
lastActivityAt: maxTimestamp2(plan.lastActivityAt, candidate?.lastActivityAt, ...linkedSignals.map((signal) => signal.lastActivityAt), ...linkedMotifs.map((motif) => motif.lastActivityAt)),
|
|
17169
|
+
outcomeState,
|
|
17170
|
+
reviewStatus: "open",
|
|
17171
|
+
confidence: confidenceFor(outcomeState, evidenceCount + (latestStatus === "applied" ? 1 : 0)),
|
|
17172
|
+
reasons,
|
|
17173
|
+
metrics: {
|
|
17174
|
+
linkedSignals: linkedSignals.length,
|
|
17175
|
+
linkedMotifs: linkedMotifs.length,
|
|
17176
|
+
safeToApply: plan.safeToApply ? 1 : 0
|
|
17177
|
+
},
|
|
17178
|
+
relatedProjectIds: uniqueStrings3(candidate?.projectIds ?? []),
|
|
17179
|
+
relatedSignalIds: linkedSignals.map((signal) => signal.id),
|
|
17180
|
+
relatedMotifIds: linkedMotifs.map((motif) => motif.id),
|
|
17181
|
+
relatedTransferEventIds: candidate?.relatedTransferEventIds ?? [],
|
|
17182
|
+
semanticConceptIds: uniqueStrings3([
|
|
17183
|
+
...candidate?.semanticConceptIds ?? [],
|
|
17184
|
+
...linkedSignals.flatMap((signal) => signal.semanticConceptIds ?? []),
|
|
17185
|
+
...linkedMotifs.flatMap((motif) => motif.semanticConceptIds ?? [])
|
|
17186
|
+
]),
|
|
17187
|
+
recommendedAction: outcomeState === "effective" ? "Verify this topology change if the structural relief looks durable." : outcomeState === "mixed" ? "Inspect Topology and Co-Evolution together before trusting this execution fully." : outcomeState === "regressed" ? "Inspect the execution notes and rollback path before retrying." : outcomeState === "measuring" ? "Wait for more downstream pressure movement before review." : "Link stronger post-apply evidence before verifying this structural change."
|
|
17188
|
+
};
|
|
17189
|
+
});
|
|
17190
|
+
}
|
|
17191
|
+
function buildOntologyProofRecords() {
|
|
17192
|
+
const signals = loadResolvedPressureSignals();
|
|
17193
|
+
const motifs = loadPressureMotifs();
|
|
17194
|
+
const transfers = loadTransferEvents();
|
|
17195
|
+
const topologyCandidates = loadResolvedTopologyReviewCandidates();
|
|
17196
|
+
return loadResolvedOntologyExtensions().filter((concept) => concept.status === "active").map((concept) => {
|
|
17197
|
+
const boundSignals = signals.filter((signal) => signal.semanticConceptIds?.includes(concept.id));
|
|
17198
|
+
const boundMotifs = motifs.filter((motif) => motif.semanticConceptIds?.includes(concept.id));
|
|
17199
|
+
const boundTransfers = transfers.filter((event) => event.semanticConceptIds?.includes(concept.id));
|
|
17200
|
+
const boundTopology = topologyCandidates.filter((candidate) => candidate.semanticConceptIds?.includes(concept.id));
|
|
17201
|
+
const lifecycleItems = [...boundSignals, ...boundMotifs];
|
|
17202
|
+
const evidenceCount = concept.adoptionCount + boundTransfers.length + boundTopology.length;
|
|
17203
|
+
const outcomeState = concept.adoptionCount === 0 ? ageDays(concept.createdAt) <= MEASURING_WINDOW_DAYS ? "measuring" : "insufficient-evidence" : evaluateLifecycleOutcome(lifecycleItems, concept.lastActivityAt);
|
|
17204
|
+
const reasons = [
|
|
17205
|
+
`${concept.name} currently has ${concept.adoptionCount} semantic bindings across live consumers.`,
|
|
17206
|
+
outcomeState === "effective" ? "Correlated semantic consumers now align with addressed downstream pressure evidence." : outcomeState === "mixed" ? "Semantic adoption is active, but downstream pressure evidence remains mixed." : outcomeState === "measuring" ? "Semantic adoption is live but still too recent or incomplete for a stronger claim." : "This record is treated as semantic-adoption evidence, not strong direct causality proof."
|
|
17207
|
+
];
|
|
17208
|
+
return {
|
|
17209
|
+
id: buildRecordId("ontology-extension", concept.id),
|
|
17210
|
+
targetType: "ontology-extension",
|
|
17211
|
+
targetId: concept.id,
|
|
17212
|
+
title: `${concept.name} semantic adoption`,
|
|
17213
|
+
summary: concept.description ?? concept.sourceSummary ?? "Approved ontology extension",
|
|
17214
|
+
createdAt: concept.createdAt,
|
|
17215
|
+
lastActivityAt: maxTimestamp2(concept.lastActivityAt, ...boundSignals.map((signal) => signal.lastActivityAt), ...boundMotifs.map((motif) => motif.lastActivityAt)),
|
|
17216
|
+
outcomeState,
|
|
17217
|
+
reviewStatus: "open",
|
|
17218
|
+
confidence: Math.min(0.88, confidenceFor(outcomeState, evidenceCount) - 0.04),
|
|
17219
|
+
reasons,
|
|
17220
|
+
metrics: {
|
|
17221
|
+
adoptionCount: concept.adoptionCount,
|
|
17222
|
+
boundSignals: boundSignals.length,
|
|
17223
|
+
boundMotifs: boundMotifs.length,
|
|
17224
|
+
boundTransfers: boundTransfers.length,
|
|
17225
|
+
boundTopology: boundTopology.length
|
|
17226
|
+
},
|
|
17227
|
+
relatedProjectIds: uniqueStrings3([
|
|
17228
|
+
...concept.projectIds ?? [],
|
|
17229
|
+
...boundSignals.map((signal) => signal.projectId),
|
|
17230
|
+
...boundMotifs.flatMap((motif) => motif.projectIds)
|
|
17231
|
+
]),
|
|
17232
|
+
relatedSignalIds: boundSignals.map((signal) => signal.id),
|
|
17233
|
+
relatedMotifIds: boundMotifs.map((motif) => motif.id),
|
|
17234
|
+
relatedTransferEventIds: boundTransfers.map((event) => event.id),
|
|
17235
|
+
semanticConceptIds: [concept.id],
|
|
17236
|
+
recommendedAction: outcomeState === "effective" ? "Verify this concept if semantic adoption looks stable enough to trust." : outcomeState === "mixed" ? "Inspect Ontology and Co-Evolution together before treating this concept as proven." : outcomeState === "measuring" ? "Let semantic adoption spread or age before review." : "Treat this as bounded semantic-adoption evidence until stronger downstream relief appears."
|
|
17237
|
+
};
|
|
17238
|
+
});
|
|
17239
|
+
}
|
|
17240
|
+
function buildEvolutionProofRecords() {
|
|
17241
|
+
const impacts = getMetricsSummary().evolutionImpact;
|
|
17242
|
+
return impacts.map((impact) => {
|
|
17243
|
+
const age = ageDays(impact.evolvedAt);
|
|
17244
|
+
const outcomeState = impact.samplesAfter <= 0 ? age <= MEASURING_WINDOW_DAYS ? "measuring" : "insufficient-evidence" : age <= MEASURING_WINDOW_DAYS || impact.samplesAfter < 3 ? "measuring" : impact.improvement < -10 ? "effective" : impact.improvement > 10 ? "regressed" : "mixed";
|
|
17245
|
+
const reasons = [
|
|
17246
|
+
`${impact.skillSlug} generation ${impact.generation} has ${impact.samplesBefore} baseline failures and ${impact.samplesAfter} post-evolution samples.`,
|
|
17247
|
+
outcomeState === "effective" ? "Measured failure rate dropped enough to clear the effectiveness threshold." : outcomeState === "regressed" ? "Measured failure rate increased enough to count as regression." : outcomeState === "mixed" ? "The run changed behavior, but not enough for a clean positive or negative verdict." : outcomeState === "measuring" ? "The evolution record is still collecting enough post-change evidence." : "There is not enough post-change sample depth for a stronger verdict."
|
|
17248
|
+
];
|
|
17249
|
+
const targetId = `${impact.skillSlug}:${impact.generation}:${impact.evolvedAt}`;
|
|
17250
|
+
return {
|
|
17251
|
+
id: buildRecordId("evolution-impact", targetId),
|
|
17252
|
+
targetType: "evolution-impact",
|
|
17253
|
+
targetId,
|
|
17254
|
+
title: `${impact.skillSlug} evolution impact`,
|
|
17255
|
+
summary: `Generation ${impact.generation} evolution baseline recorded at ${impact.evolvedAt}.`,
|
|
17256
|
+
createdAt: impact.evolvedAt,
|
|
17257
|
+
lastActivityAt: impact.evolvedAt,
|
|
17258
|
+
outcomeState,
|
|
17259
|
+
reviewStatus: "open",
|
|
17260
|
+
confidence: confidenceFor(outcomeState, impact.samplesBefore + impact.samplesAfter),
|
|
17261
|
+
reasons,
|
|
17262
|
+
metrics: {
|
|
17263
|
+
improvement: impact.improvement,
|
|
17264
|
+
samplesBefore: impact.samplesBefore,
|
|
17265
|
+
samplesAfter: impact.samplesAfter
|
|
17266
|
+
},
|
|
17267
|
+
recommendedAction: outcomeState === "effective" ? "Verify this evolution result if the lower correction rate looks durable." : outcomeState === "regressed" ? "Inspect evolution history and judges before trusting this mutation lane again." : outcomeState === "measuring" ? "Wait for more post-evolution samples before review." : "Use metrics alongside proof review before concluding anything stronger."
|
|
17268
|
+
};
|
|
17269
|
+
});
|
|
17270
|
+
}
|
|
17271
|
+
function loadResolvedProofRecords() {
|
|
17272
|
+
const reviewByRecord = latestReviewByRecord();
|
|
17273
|
+
const records = [
|
|
17274
|
+
...buildInterventionProofRecords(),
|
|
17275
|
+
...buildTransferProofRecords(),
|
|
17276
|
+
...buildTopologyProofRecords(),
|
|
17277
|
+
...buildOntologyProofRecords(),
|
|
17278
|
+
...buildEvolutionProofRecords()
|
|
17279
|
+
].map((record) => {
|
|
17280
|
+
const latestReview = reviewByRecord.get(record.id);
|
|
17281
|
+
return {
|
|
17282
|
+
...record,
|
|
17283
|
+
latestReview,
|
|
17284
|
+
reviewStatus: reviewStatusFor(latestReview)
|
|
17285
|
+
};
|
|
17286
|
+
});
|
|
17287
|
+
const outcomeWeight = (value) => value === "regressed" ? 5 : value === "mixed" ? 4 : value === "effective" ? 3 : value === "measuring" ? 2 : 1;
|
|
17288
|
+
const reviewWeight = (value) => value === "contested" ? 4 : value === "open" ? 3 : value === "deferred" ? 2 : 1;
|
|
17289
|
+
return records.sort((a, b) => reviewWeight(b.reviewStatus) - reviewWeight(a.reviewStatus) || outcomeWeight(b.outcomeState) - outcomeWeight(a.outcomeState) || b.lastActivityAt.localeCompare(a.lastActivityAt) || a.targetType.localeCompare(b.targetType));
|
|
17290
|
+
}
|
|
17291
|
+
function getProofSummary(records = loadResolvedProofRecords()) {
|
|
17292
|
+
const byTargetType = {
|
|
17293
|
+
"pressure-intervention": 0,
|
|
17294
|
+
"transfer-event": 0,
|
|
17295
|
+
"topology-execution": 0,
|
|
17296
|
+
"ontology-extension": 0,
|
|
17297
|
+
"evolution-impact": 0
|
|
17298
|
+
};
|
|
17299
|
+
for (const record of records) {
|
|
17300
|
+
byTargetType[record.targetType] += 1;
|
|
17301
|
+
}
|
|
17302
|
+
return {
|
|
17303
|
+
total: records.length,
|
|
17304
|
+
effective: records.filter((record) => record.outcomeState === "effective").length,
|
|
17305
|
+
mixed: records.filter((record) => record.outcomeState === "mixed").length,
|
|
17306
|
+
regressed: records.filter((record) => record.outcomeState === "regressed").length,
|
|
17307
|
+
measuring: records.filter((record) => record.outcomeState === "measuring").length,
|
|
17308
|
+
insufficientEvidence: records.filter((record) => record.outcomeState === "insufficient-evidence").length,
|
|
17309
|
+
reviewOpen: records.filter((record) => record.reviewStatus === "open").length,
|
|
17310
|
+
verified: records.filter((record) => record.reviewStatus === "verified").length,
|
|
17311
|
+
deferred: records.filter((record) => record.reviewStatus === "deferred").length,
|
|
17312
|
+
contested: records.filter((record) => record.reviewStatus === "contested").length,
|
|
17313
|
+
byTargetType
|
|
17314
|
+
};
|
|
17315
|
+
}
|
|
17316
|
+
function buildTargetBreakdown(records) {
|
|
17317
|
+
const targetTypes = [
|
|
17318
|
+
"pressure-intervention",
|
|
17319
|
+
"transfer-event",
|
|
17320
|
+
"topology-execution",
|
|
17321
|
+
"ontology-extension",
|
|
17322
|
+
"evolution-impact"
|
|
17323
|
+
];
|
|
17324
|
+
return targetTypes.map((targetType) => {
|
|
17325
|
+
const subset = records.filter((record) => record.targetType === targetType);
|
|
17326
|
+
return {
|
|
17327
|
+
targetType,
|
|
17328
|
+
total: subset.length,
|
|
17329
|
+
effective: subset.filter((record) => record.outcomeState === "effective").length,
|
|
17330
|
+
mixed: subset.filter((record) => record.outcomeState === "mixed").length,
|
|
17331
|
+
regressed: subset.filter((record) => record.outcomeState === "regressed").length,
|
|
17332
|
+
measuring: subset.filter((record) => record.outcomeState === "measuring").length,
|
|
17333
|
+
insufficientEvidence: subset.filter((record) => record.outcomeState === "insufficient-evidence").length
|
|
17334
|
+
};
|
|
17335
|
+
}).filter((entry) => entry.total > 0);
|
|
17336
|
+
}
|
|
17337
|
+
function loadProofDashboardSummary() {
|
|
17338
|
+
const records = loadResolvedProofRecords();
|
|
17339
|
+
return {
|
|
17340
|
+
summary: getProofSummary(records),
|
|
17341
|
+
records,
|
|
17342
|
+
reviewQueue: records.filter((record) => record.reviewStatus === "open").slice(0, 12),
|
|
17343
|
+
recentVerified: records.filter((record) => record.reviewStatus === "verified").slice(0, 8),
|
|
17344
|
+
recentContested: records.filter((record) => record.reviewStatus === "contested").slice(0, 8),
|
|
17345
|
+
byTargetType: buildTargetBreakdown(records)
|
|
17346
|
+
};
|
|
17347
|
+
}
|
|
17348
|
+
function reviewProofRecord(input) {
|
|
17349
|
+
const current = loadResolvedProofRecords().find((record) => record.id === input.recordId);
|
|
17350
|
+
if (!current) {
|
|
17351
|
+
throw new Error(`Unknown proof record: ${input.recordId}`);
|
|
17352
|
+
}
|
|
17353
|
+
appendProofReview({
|
|
17354
|
+
id: `proof_review_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
17355
|
+
recordId: current.id,
|
|
17356
|
+
targetType: current.targetType,
|
|
17357
|
+
targetId: current.targetId,
|
|
17358
|
+
decision: input.decision,
|
|
17359
|
+
decidedAt: new Date().toISOString(),
|
|
17360
|
+
rationale: input.rationale,
|
|
17361
|
+
decidedBy: input.decidedBy ?? "operator"
|
|
17362
|
+
});
|
|
17363
|
+
const refreshed = loadResolvedProofRecords().find((record) => record.id === input.recordId);
|
|
17364
|
+
if (!refreshed) {
|
|
17365
|
+
throw new Error(`Unable to reload proof record: ${input.recordId}`);
|
|
17366
|
+
}
|
|
17367
|
+
return refreshed;
|
|
17368
|
+
}
|
|
17369
|
+
|
|
17370
|
+
// src/commands/proof.ts
|
|
17371
|
+
function labelForTarget(targetType) {
|
|
17372
|
+
if (targetType === "pressure-intervention")
|
|
17373
|
+
return "interventions";
|
|
17374
|
+
if (targetType === "transfer-event")
|
|
17375
|
+
return "transfers";
|
|
17376
|
+
if (targetType === "topology-execution")
|
|
17377
|
+
return "topology";
|
|
17378
|
+
if (targetType === "ontology-extension")
|
|
17379
|
+
return "ontology";
|
|
17380
|
+
return "evolution";
|
|
17381
|
+
}
|
|
17382
|
+
function printStatus3(verbose = false) {
|
|
17383
|
+
const dashboard = loadProofDashboardSummary();
|
|
17384
|
+
const summary = dashboard.summary;
|
|
17385
|
+
console.log(`
|
|
17386
|
+
Proof Control`);
|
|
17387
|
+
console.log(" ────────────────────────────────────────");
|
|
17388
|
+
console.log(` Records: ${summary.total} total • ${summary.effective} effective • ${summary.mixed} mixed • ${summary.regressed} regressed`);
|
|
17389
|
+
console.log(` Measuring: ${summary.measuring} measuring • ${summary.insufficientEvidence} insufficient-evidence`);
|
|
17390
|
+
console.log(` Reviews: ${summary.reviewOpen} open • ${summary.verified} verified • ${summary.deferred} deferred • ${summary.contested} contested`);
|
|
17391
|
+
if (dashboard.byTargetType.length > 0) {
|
|
17392
|
+
console.log(`
|
|
17393
|
+
Coverage by target type`);
|
|
17394
|
+
for (const entry of dashboard.byTargetType) {
|
|
17395
|
+
console.log(` • ${labelForTarget(entry.targetType)}: ${entry.total} total • ${entry.effective} effective • ${entry.regressed} regressed`);
|
|
17396
|
+
}
|
|
17397
|
+
}
|
|
17398
|
+
if (dashboard.reviewQueue.length > 0) {
|
|
17399
|
+
console.log(`
|
|
17400
|
+
Review queue`);
|
|
17401
|
+
for (const record of dashboard.reviewQueue.slice(0, 6)) {
|
|
17402
|
+
console.log(` • ${record.id} • ${record.outcomeState} • ${record.title}`);
|
|
17403
|
+
}
|
|
17404
|
+
}
|
|
17405
|
+
console.log();
|
|
17406
|
+
if (verbose) {
|
|
17407
|
+
const detailed = dashboard.records.slice(0, 12);
|
|
17408
|
+
if (detailed.length > 0) {
|
|
17409
|
+
console.log(" Detailed proof records");
|
|
17410
|
+
for (const record of detailed) {
|
|
17411
|
+
const projects = (record.relatedProjectIds?.length ?? 0) > 0 ? ` • ${record.relatedProjectIds?.length} project${record.relatedProjectIds?.length === 1 ? "" : "s"}` : "";
|
|
17412
|
+
console.log(` • ${record.id}`);
|
|
17413
|
+
console.log(` ${record.targetType} • ${record.outcomeState} • ${record.reviewStatus}${projects}`);
|
|
17414
|
+
console.log(` ${record.summary}`);
|
|
17415
|
+
for (const reason of record.reasons.slice(0, 2)) {
|
|
17416
|
+
console.log(` - ${reason}`);
|
|
17417
|
+
}
|
|
17418
|
+
if (record.recommendedAction) {
|
|
17419
|
+
console.log(` next: ${record.recommendedAction}`);
|
|
17420
|
+
}
|
|
17421
|
+
}
|
|
17422
|
+
console.log();
|
|
17423
|
+
}
|
|
17424
|
+
}
|
|
17425
|
+
}
|
|
17426
|
+
async function proofCommand(options) {
|
|
17427
|
+
const actions = [options.review ? "review" : null].filter(Boolean);
|
|
17428
|
+
if (actions.length > 1) {
|
|
17429
|
+
throw new Error("Use only one proof action at a time");
|
|
17430
|
+
}
|
|
17431
|
+
if (options.review) {
|
|
17432
|
+
if (!options.decision) {
|
|
17433
|
+
throw new Error("--decision <verify|defer|contest> is required with --review");
|
|
17434
|
+
}
|
|
17435
|
+
const record = reviewProofRecord({
|
|
17436
|
+
recordId: options.review,
|
|
17437
|
+
decision: options.decision,
|
|
17438
|
+
rationale: options.rationale ?? `${options.decision} proof record via CLI review`,
|
|
17439
|
+
decidedBy: "operator"
|
|
17440
|
+
});
|
|
17441
|
+
console.log(`
|
|
17442
|
+
✓ Recorded proof review: ${record.id}`);
|
|
17443
|
+
console.log(` target: ${record.targetType}`);
|
|
17444
|
+
console.log(` outcome: ${record.outcomeState}`);
|
|
17445
|
+
console.log(` review: ${record.reviewStatus}`);
|
|
17446
|
+
if (record.recommendedAction) {
|
|
17447
|
+
console.log(` next: ${record.recommendedAction}`);
|
|
17448
|
+
}
|
|
17449
|
+
console.log();
|
|
17450
|
+
return;
|
|
17451
|
+
}
|
|
17452
|
+
printStatus3(options.verbose ?? false);
|
|
17453
|
+
if (!options.verbose) {
|
|
17454
|
+
const summary = getProofSummary();
|
|
17455
|
+
if (summary.total === 0) {
|
|
17456
|
+
console.log(" No proof records yet. Create pressure responses, semantic adoption, or topology execution first, then re-run `helixevo proof --status`.\n");
|
|
17457
|
+
}
|
|
17458
|
+
}
|
|
17459
|
+
}
|
|
17460
|
+
|
|
16965
17461
|
// src/cli.ts
|
|
16966
17462
|
var program2 = new Command;
|
|
16967
17463
|
program2.name("helixevo").description("Co-evolving skill and project brain for AI agents").version(VERSION).addHelpText("after", `
|
|
@@ -16989,6 +17485,9 @@ Examples:
|
|
|
16989
17485
|
$ helixevo ontology --refresh Derive frontier concepts from recurring evidence
|
|
16990
17486
|
$ helixevo ontology --review <id> --decision promote
|
|
16991
17487
|
Promote a reviewed frontier concept into approved extensions
|
|
17488
|
+
$ helixevo proof --status --verbose Review intervention, topology, ontology, and evolution proof state
|
|
17489
|
+
$ helixevo proof --review <id> --decision verify
|
|
17490
|
+
Verify a derived proof record after operator review
|
|
16992
17491
|
$ helixevo report --days 7 Weekly evolution report
|
|
16993
17492
|
$ helixevo capture <session.json> Extract failures from session`);
|
|
16994
17493
|
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);
|
|
@@ -17010,6 +17509,7 @@ program2.command("health").description("Assess network health: cohesion, coverag
|
|
|
17010
17509
|
printHealthReport2(health);
|
|
17011
17510
|
});
|
|
17012
17511
|
program2.command("metrics").description("Show correction rates, skill trends, and evolution impact").option("--verbose", "Show detailed per-skill breakdown").action(metricsCommand);
|
|
17512
|
+
program2.command("proof").description("Outcome attribution and proof review control [--status] [--review <recordId>] [--decision <verify|defer|contest>]").option("--status", "Show proof summary and open proof review state").option("--review <recordId>", "Review a derived proof record").option("--decision <decision>", "Decision for --review: verify, defer, or contest").option("--rationale <text>", "Optional rationale for the proof review decision").option("--verbose", "Show detailed proof records and derived reasons").action(proofCommand);
|
|
17013
17513
|
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);
|
|
17014
17514
|
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
17515
|
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);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helixevo",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Co-evolving skill and project brain for AI agents, with ontology-aware learning, governed response, rollbackable topology control, and a premium dashboard.",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Co-evolving skill and project brain for AI agents, with ontology-aware learning, governed response, rollbackable topology control, bounded proof control, and a premium dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"helixevo": "dist/cli.js"
|