@evomap/evolver-core 2.0.0-beta.9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/algo/candidateAssembly.d.ts +7 -2
- package/dist/algo/candidateAssembly.js +81 -13
- package/dist/algo/capabilityCandidates.js +10 -0
- package/dist/algo/cycleEngine.d.ts +23 -2
- package/dist/algo/cycleEngine.js +236 -36
- package/dist/algo/exploration.d.ts +7 -0
- package/dist/algo/exploration.js +16 -3
- package/dist/algo/geneHealth.d.ts +2 -2
- package/dist/algo/geneHealth.js +5 -4
- package/dist/algo/geneSelection.d.ts +63 -5
- package/dist/algo/geneSelection.js +330 -30
- package/dist/algo/index.d.ts +2 -0
- package/dist/algo/index.js +2 -0
- package/dist/algo/orchestrator.d.ts +8 -1
- package/dist/algo/orchestrator.js +15 -3
- package/dist/algo/publishEligibility.d.ts +34 -0
- package/dist/algo/publishEligibility.js +52 -0
- package/dist/algo/ucb1.d.ts +53 -0
- package/dist/algo/ucb1.js +156 -0
- package/dist/assetstore/assetSidecarRecords.d.ts +7 -2
- package/dist/assetstore/assetSidecarRecords.js +238 -0
- package/dist/assetstore/assetSidecarRecovery.js +2 -2
- package/dist/assetstore/assetStoreHealth.d.ts +6 -0
- package/dist/assetstore/assetStoreHealth.js +56 -14
- package/dist/assetstore/assetStoreStorage.d.ts +1 -1
- package/dist/assetstore/assetStoreStorage.js +27 -9
- package/dist/assetstore/assetSyncLedger.d.ts +86 -0
- package/dist/assetstore/assetSyncLedger.js +683 -4
- package/dist/assetstore/index.d.ts +1 -0
- package/dist/assetstore/index.js +1 -0
- package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
- package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
- package/dist/assetstore/localJsonl.d.ts +4 -2
- package/dist/assetstore/localJsonl.js +89 -9
- package/dist/assetstore/provenance.d.ts +80 -4
- package/dist/assetstore/provenance.js +313 -5
- package/dist/assetstore/provider.d.ts +58 -1
- package/dist/assetstore/provider.js +97 -6
- package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
- package/dist/benchmark/antiGeneBenchmark.js +4 -3
- package/dist/benchmark/antiGeneRollout.d.ts +2 -0
- package/dist/benchmark/antiGeneRollout.js +4 -3
- package/dist/benchmark/index.d.ts +2 -1
- package/dist/benchmark/index.js +2 -1
- package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
- package/dist/benchmark/selectionFlatAbstention.js +481 -0
- package/dist/bootstrap/envFingerprint.d.ts +9 -0
- package/dist/bootstrap/envFingerprint.js +5 -0
- package/dist/bootstrap/index.d.ts +2 -1
- package/dist/bootstrap/index.js +2 -1
- package/dist/bootstrap/v1EnvCompat.d.ts +111 -0
- package/dist/bootstrap/v1EnvCompat.js +280 -0
- package/dist/events/eventArchive.d.ts +2 -0
- package/dist/events/eventArchive.js +13 -3
- package/dist/events/eventSchema.d.ts +7 -7
- package/dist/events/eventStore.d.ts +2 -0
- package/dist/events/eventStore.js +5 -1
- package/dist/events/ingest.d.ts +1 -0
- package/dist/events/ingest.js +1 -0
- package/dist/events/paths.d.ts +3 -1
- package/dist/events/paths.js +4 -0
- package/dist/events/public.d.ts +2 -2
- package/dist/events/public.js +2 -2
- package/dist/events/reports.d.ts +2 -0
- package/dist/events/reports.js +4 -0
- package/dist/exec/autoExec.d.ts +43 -2
- package/dist/exec/autoExec.js +76 -9
- package/dist/exec/autonomousCycle.d.ts +22 -4
- package/dist/exec/autonomousCycle.js +64 -13
- package/dist/exec/claudeBridge.d.ts +32 -7
- package/dist/exec/claudeBridge.js +281 -29
- package/dist/exec/prompt.js +5 -1
- package/dist/exec/runnerRegistry.d.ts +68 -26
- package/dist/exec/runnerRegistry.js +307 -72
- package/dist/exec/selfPr.js +1 -7
- package/dist/feedback/envelope.d.ts +61 -0
- package/dist/feedback/envelope.js +168 -0
- package/dist/feedback/index.d.ts +1 -0
- package/dist/feedback/index.js +1 -0
- package/dist/hooks/hooks.js +1 -0
- package/dist/hub/assetCallLog.d.ts +35 -1
- package/dist/hub/assetCallLog.js +124 -1
- package/dist/hub/bindings.d.ts +8 -1
- package/dist/hub/bindings.js +17 -6
- package/dist/hub/capability.d.ts +90 -3
- package/dist/hub/fake.d.ts +2 -2
- package/dist/hub/fake.js +1 -1
- package/dist/hub/questionGenerator.d.ts +5 -1
- package/dist/hub/questionGenerator.js +8 -6
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -1
- package/dist/mailbox/dispatch.d.ts +1 -1
- package/dist/mailbox/dispatch.js +22 -6
- package/dist/mailbox/envelope.d.ts +7 -1
- package/dist/mailbox/envelope.js +9 -2
- package/dist/mailbox/ipcServer.d.ts +10 -2
- package/dist/mailbox/ipcServer.js +163 -13
- package/dist/mailbox/store.d.ts +89 -3
- package/dist/mailbox/store.js +895 -41
- package/dist/ops/evolutionGraphProjection.d.ts +20 -0
- package/dist/ops/evolutionGraphProjection.js +315 -0
- package/dist/ops/index.d.ts +2 -1
- package/dist/ops/index.js +2 -1
- package/dist/ops/selfUpdate.d.ts +8 -0
- package/dist/ops/selfUpdate.js +24 -8
- package/dist/personality/schema.d.ts +16 -16
- package/dist/schema/evolutionGraph.d.ts +784 -0
- package/dist/schema/evolutionGraph.js +187 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/signal.d.ts +3 -3
- package/dist/schema/signal.js +1 -1
- package/dist/signals/curriculum.d.ts +55 -0
- package/dist/signals/curriculum.js +202 -0
- package/dist/signals/cycleHistoryFromEvents.js +17 -8
- package/dist/signals/expand.d.ts +15 -1
- package/dist/signals/expand.js +169 -1
- package/dist/signals/extractor.d.ts +2 -2
- package/dist/signals/extractor.js +31 -6
- package/dist/signals/index.d.ts +3 -1
- package/dist/signals/index.js +3 -1
- package/dist/signals/metaSignals.d.ts +4 -0
- package/dist/signals/metaSignals.js +42 -0
- package/dist/signals/signalGate.js +1 -1
- package/dist/signals/taskDomain.d.ts +22 -0
- package/dist/signals/taskDomain.js +43 -0
- package/dist/strategy/constraintAblation.js +115 -369
- package/dist/strategy/constraintAblationPredicates.d.ts +31 -0
- package/dist/strategy/constraintAblationPredicates.js +339 -0
- package/dist/trace/index.d.ts +3 -1
- package/dist/trace/index.js +3 -1
- package/dist/trace/learningTrace.d.ts +209 -0
- package/dist/trace/learningTrace.js +276 -0
- package/dist/trace/proxyTurns.d.ts +31 -0
- package/dist/trace/proxyTurns.js +137 -0
- package/dist/verify/sandboxRunner.d.ts +28 -0
- package/dist/verify/sandboxRunner.js +218 -19
- package/dist/verify/sandboxedValidation.d.ts +9 -0
- package/dist/verify/sandboxedValidation.js +113 -13
- package/dist/verify/validation.d.ts +11 -1
- package/dist/verify/validation.js +31 -0
- package/package.json +5 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type EvolutionGraph } from '../schema/evolutionGraph.js';
|
|
2
|
+
/** The minimal root_event view this projector reads (structurally matches events' ReportEvent). */
|
|
3
|
+
export interface EvolutionGraphSourceEvent {
|
|
4
|
+
type: string;
|
|
5
|
+
seq: number;
|
|
6
|
+
ts: string;
|
|
7
|
+
payload?: Record<string, unknown> | undefined;
|
|
8
|
+
human?: {
|
|
9
|
+
title?: string | undefined;
|
|
10
|
+
} | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface ProjectEvolutionGraphOptions {
|
|
13
|
+
/** Stable identifier for the produced snapshot. */
|
|
14
|
+
graphId?: string;
|
|
15
|
+
/** Snapshot timestamp; defaults to the newest projected event so the projection stays deterministic. */
|
|
16
|
+
generatedAt?: string;
|
|
17
|
+
/** Bound on scanned events (newest window wins) so a long history cannot make the projection unbounded. */
|
|
18
|
+
maxEvents?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function projectEvolutionGraph(events: readonly EvolutionGraphSourceEvent[], options?: ProjectEvolutionGraphOptions): EvolutionGraph;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
// Read-only Evolution Graph projection over already-emitted root_events.
|
|
2
|
+
//
|
|
3
|
+
// PURE: a function over a root-event snapshot. It never appends events, writes assets, or mutates selection —
|
|
4
|
+
// projecting is strictly an observability concern (same posture as ops/reuseOutcomes.ts). The graph it returns is
|
|
5
|
+
// evidence for "which variant was selected on what basis, and was that later contradicted", not a new actuator.
|
|
6
|
+
//
|
|
7
|
+
// Every edge carries provenance back to the root_event seq that justified it, so a dashboard card can always be
|
|
8
|
+
// traced to a specific emitted event instead of a narrative summary.
|
|
9
|
+
import { deriveEvolutionGraphDashboardSummary, EVOLUTION_GRAPH_SCHEMA_VERSION, } from '../schema/evolutionGraph.js';
|
|
10
|
+
import { HOST_SUPPRESS_CLASSES } from '../algo/cycleFailureClassifier.js';
|
|
11
|
+
const DEFAULT_MAX_EVENTS = 5_000;
|
|
12
|
+
const MAX_LABEL = 120;
|
|
13
|
+
const RESOLUTION_STATUSES = new Set([
|
|
14
|
+
'pending',
|
|
15
|
+
'suppressed_observationally',
|
|
16
|
+
'resolved_by_evidence',
|
|
17
|
+
'regressed',
|
|
18
|
+
'inconclusive',
|
|
19
|
+
]);
|
|
20
|
+
export function projectEvolutionGraph(events, options = {}) {
|
|
21
|
+
const maxEvents = boundedLimit(options.maxEvents, DEFAULT_MAX_EVENTS);
|
|
22
|
+
const window = events.length > maxEvents ? events.slice(events.length - maxEvents) : events;
|
|
23
|
+
const builder = new GraphBuilder();
|
|
24
|
+
for (const event of window)
|
|
25
|
+
builder.absorb(event);
|
|
26
|
+
const nodes = builder.nodes();
|
|
27
|
+
const edges = builder.edges();
|
|
28
|
+
const newestTs = window.length > 0 ? text(window[window.length - 1]?.ts) : '';
|
|
29
|
+
return {
|
|
30
|
+
schemaVersion: EVOLUTION_GRAPH_SCHEMA_VERSION,
|
|
31
|
+
graphId: options.graphId ?? 'graph:evolution:root-events',
|
|
32
|
+
generatedAt: options.generatedAt ?? (isoTimestamp(newestTs) ?? '1970-01-01T00:00:00.000Z'),
|
|
33
|
+
nodes,
|
|
34
|
+
edges,
|
|
35
|
+
dashboard: deriveEvolutionGraphDashboardSummary({ nodes, edges }),
|
|
36
|
+
extensions: {},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
class GraphBuilder {
|
|
40
|
+
nodesById = new Map();
|
|
41
|
+
edgesById = new Map();
|
|
42
|
+
variantByLifecycle = new Map();
|
|
43
|
+
/** cycleId can be reused; only events in the current lifecycle may share evidence or graph nodes. */
|
|
44
|
+
lifecycleByCycle = new Map();
|
|
45
|
+
nodes() {
|
|
46
|
+
return [...this.nodesById.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
47
|
+
}
|
|
48
|
+
edges() {
|
|
49
|
+
return [...this.edgesById.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
50
|
+
}
|
|
51
|
+
absorb(event) {
|
|
52
|
+
const at = isoTimestamp(text(event.ts));
|
|
53
|
+
if (!at)
|
|
54
|
+
return;
|
|
55
|
+
const payload = event.payload ?? {};
|
|
56
|
+
const cycleId = opaqueId(payload['cycleId']);
|
|
57
|
+
switch (event.type) {
|
|
58
|
+
case 'cycle.started': {
|
|
59
|
+
if (cycleId)
|
|
60
|
+
this.beginLifecycle(cycleId);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
case 'capsule.produced': {
|
|
64
|
+
if (!cycleId)
|
|
65
|
+
return;
|
|
66
|
+
const capsuleId = opaqueId(payload['capsuleId']);
|
|
67
|
+
const status = resolutionStatus(payload['resolutionStatus']);
|
|
68
|
+
if (!capsuleId || !status)
|
|
69
|
+
return;
|
|
70
|
+
const lifecycle = this.activeLifecycle(cycleId);
|
|
71
|
+
lifecycle.capsule = {
|
|
72
|
+
capsuleId,
|
|
73
|
+
resolutionStatus: status,
|
|
74
|
+
producedValue: payload['producedValue'] === true,
|
|
75
|
+
event,
|
|
76
|
+
};
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
case 'decision.gene_selected': {
|
|
80
|
+
if (!cycleId)
|
|
81
|
+
return;
|
|
82
|
+
const lifecycle = this.decisionLifecycle(cycleId, event);
|
|
83
|
+
const variant = this.variant(lifecycle, at);
|
|
84
|
+
const gene = opaqueId(payload['selectedAssetId']) ?? opaqueId(payload['selectedGeneId']);
|
|
85
|
+
if (gene) {
|
|
86
|
+
const spec = this.node(`spec:${gene}`, 'spec', `gene ${gene}`, at);
|
|
87
|
+
this.edge('derivation', spec, variant, at, event, 'variant derived from the selected gene');
|
|
88
|
+
}
|
|
89
|
+
const selection = this.node(`selection:${lifecycle.key}`, 'selection', `selection for cycle ${cycleId}`, at);
|
|
90
|
+
const reason = text(payload['selectedReason']) || text(event.human?.title) || 'gene selected by cycle engine';
|
|
91
|
+
this.edge('selected', variant, selection, at, event, reason);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
case 'mutation.built': {
|
|
95
|
+
if (!cycleId)
|
|
96
|
+
return;
|
|
97
|
+
const lifecycle = this.activeLifecycle(cycleId);
|
|
98
|
+
if (!lifecycle.key)
|
|
99
|
+
return;
|
|
100
|
+
const variant = this.variant(lifecycle, at);
|
|
101
|
+
const mutationId = opaqueId(payload['mutationId']);
|
|
102
|
+
if (!mutationId)
|
|
103
|
+
return;
|
|
104
|
+
const code = this.node(`code:${mutationId}`, 'code', `mutation ${mutationId}`, at);
|
|
105
|
+
this.edge('derivation', variant, code, at, event, 'variant produced a mutation');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
case 'cycle.solidified': {
|
|
109
|
+
if (!cycleId)
|
|
110
|
+
return;
|
|
111
|
+
const lifecycle = this.activeLifecycle(cycleId);
|
|
112
|
+
lifecycle.terminal = true;
|
|
113
|
+
if (!lifecycle.key)
|
|
114
|
+
return;
|
|
115
|
+
const score = terminalOutcomeScore(payload['outcome'], 'success');
|
|
116
|
+
if (score === null)
|
|
117
|
+
return;
|
|
118
|
+
const variant = this.variant(lifecycle, at);
|
|
119
|
+
const run = this.node(`run:${lifecycle.key}`, 'run', `cycle ${cycleId}`, at);
|
|
120
|
+
this.edge('evaluated_by', variant, run, at, event, 'cycle completed with a measured outcome');
|
|
121
|
+
const evidence = this.matchingCapsuleEvidence(lifecycle, payload, true);
|
|
122
|
+
if (evidence?.resolutionStatus === 'resolved_by_evidence'
|
|
123
|
+
&& evidence.producedValue
|
|
124
|
+
&& payload['producedValue'] === true) {
|
|
125
|
+
this.edge('fixed', variant, run, at, event, 'cycle resolved by output-backed validation evidence', {
|
|
126
|
+
metric: 'cycle_outcome_score',
|
|
127
|
+
after: score,
|
|
128
|
+
direction: 'improved',
|
|
129
|
+
}, [evidence.event]);
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
case 'cycle.failed': {
|
|
134
|
+
if (!cycleId)
|
|
135
|
+
return;
|
|
136
|
+
const lifecycle = this.activeLifecycle(cycleId);
|
|
137
|
+
lifecycle.terminal = true;
|
|
138
|
+
if (!lifecycle.key)
|
|
139
|
+
return;
|
|
140
|
+
const score = terminalOutcomeScore(payload['outcome'], 'failed');
|
|
141
|
+
const failureClass = text(payload['failure_class']);
|
|
142
|
+
if (score === null || text(payload['failureKind']) || suppressesFailure(failureClass))
|
|
143
|
+
return;
|
|
144
|
+
const variant = this.variant(lifecycle, at);
|
|
145
|
+
const run = this.node(`run:${lifecycle.key}`, 'run', `cycle ${cycleId}`, at);
|
|
146
|
+
this.edge('evaluated_by', variant, run, at, event, 'cycle completed with a measured failed outcome');
|
|
147
|
+
const capsule = this.matchingCapsuleEvidence(lifecycle, payload);
|
|
148
|
+
const inlineStatus = resolutionStatus(payload['resolutionStatus']);
|
|
149
|
+
if (hasOwn(payload, 'resolutionStatus') && !inlineStatus)
|
|
150
|
+
return;
|
|
151
|
+
const status = inlineStatus ?? capsule?.resolutionStatus ?? null;
|
|
152
|
+
if (inlineStatus && capsule && inlineStatus !== capsule.resolutionStatus)
|
|
153
|
+
return;
|
|
154
|
+
if (status === 'regressed') {
|
|
155
|
+
this.edge('regressed', variant, run, at, event, failureClass || 'measured cycle regression', {
|
|
156
|
+
metric: 'cycle_outcome_score',
|
|
157
|
+
after: score,
|
|
158
|
+
direction: 'regressed',
|
|
159
|
+
}, capsule ? [capsule.event] : []);
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
case 'cycle.aborted': {
|
|
164
|
+
if (cycleId)
|
|
165
|
+
this.activeLifecycle(cycleId).terminal = true;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
case 'value.reuse_outcome': {
|
|
169
|
+
const assetId = opaqueId(payload['assetId']);
|
|
170
|
+
if (!assetId)
|
|
171
|
+
return;
|
|
172
|
+
const spec = this.node(`spec:${assetId}`, 'spec', `gene ${assetId}`, at);
|
|
173
|
+
const feedback = this.node(`feedback:${assetId}:${event.seq}`, 'feedback', `reuse outcome ${text(payload['outcome']) || 'negative'}`, at);
|
|
174
|
+
this.edge('derivation', feedback, spec, at, event, 'reuse feedback recorded against the gene');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
case 'anti_gene.rollout_result': {
|
|
178
|
+
const suite = opaqueId(payload['suite']) ?? `seq-${event.seq}`;
|
|
179
|
+
const test = this.node(`test:${suite}`, 'test', `anti-gene rollout ${suite}`, at);
|
|
180
|
+
const verdict = text(payload['verdict']);
|
|
181
|
+
const variant = this.node(`variant:rollout:${suite}`, 'variant', `anti-gene arm ${suite}`, at);
|
|
182
|
+
this.edge('evaluated_by', variant, test, at, event, verdict || 'anti-gene rollout evaluated');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
default:
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
beginLifecycle(cycleId) {
|
|
190
|
+
const lifecycle = {
|
|
191
|
+
cycleId,
|
|
192
|
+
key: '',
|
|
193
|
+
decisionSeen: false,
|
|
194
|
+
capsule: null,
|
|
195
|
+
terminal: false,
|
|
196
|
+
};
|
|
197
|
+
this.lifecycleByCycle.set(cycleId, lifecycle);
|
|
198
|
+
return lifecycle;
|
|
199
|
+
}
|
|
200
|
+
activeLifecycle(cycleId) {
|
|
201
|
+
const current = this.lifecycleByCycle.get(cycleId);
|
|
202
|
+
return !current || current.terminal ? this.beginLifecycle(cycleId) : current;
|
|
203
|
+
}
|
|
204
|
+
decisionLifecycle(cycleId, event) {
|
|
205
|
+
let lifecycle = this.lifecycleByCycle.get(cycleId);
|
|
206
|
+
if (!lifecycle || lifecycle.decisionSeen || lifecycle.capsule || lifecycle.terminal) {
|
|
207
|
+
lifecycle = this.beginLifecycle(cycleId);
|
|
208
|
+
}
|
|
209
|
+
lifecycle.key = `${cycleId}:seq:${event.seq}`;
|
|
210
|
+
lifecycle.decisionSeen = true;
|
|
211
|
+
lifecycle.capsule = null;
|
|
212
|
+
return lifecycle;
|
|
213
|
+
}
|
|
214
|
+
variant(lifecycle, at) {
|
|
215
|
+
const existing = this.variantByLifecycle.get(lifecycle.key);
|
|
216
|
+
if (existing)
|
|
217
|
+
return this.nodesById.get(existing);
|
|
218
|
+
const node = this.node(`variant:${lifecycle.key}`, 'variant', `variant from cycle ${lifecycle.cycleId}`, at);
|
|
219
|
+
this.variantByLifecycle.set(lifecycle.key, node.id);
|
|
220
|
+
return node;
|
|
221
|
+
}
|
|
222
|
+
matchingCapsuleEvidence(lifecycle, payload, requireCapsuleId = false) {
|
|
223
|
+
const evidence = lifecycle.capsule;
|
|
224
|
+
if (!evidence)
|
|
225
|
+
return null;
|
|
226
|
+
if (!hasOwn(payload, 'capsuleId'))
|
|
227
|
+
return requireCapsuleId ? null : evidence;
|
|
228
|
+
const capsuleId = opaqueId(payload['capsuleId']);
|
|
229
|
+
return !capsuleId || capsuleId !== evidence.capsuleId ? null : evidence;
|
|
230
|
+
}
|
|
231
|
+
node(id, kind, label, at) {
|
|
232
|
+
const existing = this.nodesById.get(id);
|
|
233
|
+
if (existing)
|
|
234
|
+
return existing;
|
|
235
|
+
const node = {
|
|
236
|
+
id,
|
|
237
|
+
kind,
|
|
238
|
+
label: label.slice(0, MAX_LABEL) || id,
|
|
239
|
+
createdAt: at,
|
|
240
|
+
metrics: [],
|
|
241
|
+
tags: [],
|
|
242
|
+
extensions: {},
|
|
243
|
+
};
|
|
244
|
+
this.nodesById.set(id, node);
|
|
245
|
+
return node;
|
|
246
|
+
}
|
|
247
|
+
edge(kind, from, to, at, event, reason, metricDelta, supportingEvents = []) {
|
|
248
|
+
const id = `edge:${kind}:${from.id}->${to.id}:${event.seq}`;
|
|
249
|
+
if (this.edgesById.has(id))
|
|
250
|
+
return;
|
|
251
|
+
this.edgesById.set(id, {
|
|
252
|
+
id,
|
|
253
|
+
kind,
|
|
254
|
+
from: from.id,
|
|
255
|
+
to: to.id,
|
|
256
|
+
createdAt: at,
|
|
257
|
+
provenance: provenanceFor([...supportingEvents, event]),
|
|
258
|
+
...(metricDelta ? { metricDelta } : {}),
|
|
259
|
+
reason: reason.slice(0, MAX_LABEL),
|
|
260
|
+
extensions: {},
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function boundedLimit(value, fallback) {
|
|
265
|
+
if (!Number.isFinite(value) || value === undefined || value <= 0)
|
|
266
|
+
return fallback;
|
|
267
|
+
return Math.min(fallback, Math.floor(value));
|
|
268
|
+
}
|
|
269
|
+
function text(value) {
|
|
270
|
+
return typeof value === 'string' ? value.replace(/[\r\n\t]+/g, ' ').trim() : '';
|
|
271
|
+
}
|
|
272
|
+
/** Opaque local identifiers only: no control characters, bounded, so a graph id cannot smuggle payload text. */
|
|
273
|
+
function opaqueId(value) {
|
|
274
|
+
const candidate = text(value);
|
|
275
|
+
if (!candidate || candidate.length > 160)
|
|
276
|
+
return null;
|
|
277
|
+
return /^[A-Za-z0-9][A-Za-z0-9:._-]*$/.test(candidate) ? candidate : null;
|
|
278
|
+
}
|
|
279
|
+
function isoTimestamp(value) {
|
|
280
|
+
if (!value)
|
|
281
|
+
return null;
|
|
282
|
+
const parsed = Date.parse(value);
|
|
283
|
+
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null;
|
|
284
|
+
}
|
|
285
|
+
function terminalOutcomeScore(value, expectedStatus) {
|
|
286
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
287
|
+
return null;
|
|
288
|
+
const outcome = value;
|
|
289
|
+
if (outcome['status'] !== expectedStatus)
|
|
290
|
+
return null;
|
|
291
|
+
const score = outcome['score'];
|
|
292
|
+
return typeof score === 'number' && Number.isFinite(score) ? score : null;
|
|
293
|
+
}
|
|
294
|
+
function resolutionStatus(value) {
|
|
295
|
+
return typeof value === 'string' && RESOLUTION_STATUSES.has(value)
|
|
296
|
+
? value
|
|
297
|
+
: null;
|
|
298
|
+
}
|
|
299
|
+
function suppressesFailure(value) {
|
|
300
|
+
return value !== '' && HOST_SUPPRESS_CLASSES.has(value);
|
|
301
|
+
}
|
|
302
|
+
function hasOwn(value, key) {
|
|
303
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
304
|
+
}
|
|
305
|
+
function provenanceFor(events) {
|
|
306
|
+
const seen = new Set();
|
|
307
|
+
return events.flatMap((event) => {
|
|
308
|
+
const capturedAt = isoTimestamp(text(event.ts));
|
|
309
|
+
const ref = `seq:${event.seq}`;
|
|
310
|
+
if (!capturedAt || seen.has(ref))
|
|
311
|
+
return [];
|
|
312
|
+
seen.add(ref);
|
|
313
|
+
return [{ kind: 'root_event', ref, capturedAt, summary: event.type }];
|
|
314
|
+
});
|
|
315
|
+
}
|
package/dist/ops/index.d.ts
CHANGED
package/dist/ops/index.js
CHANGED
package/dist/ops/selfUpdate.d.ts
CHANGED
|
@@ -91,6 +91,14 @@ export interface DownloadedArtifact {
|
|
|
91
91
|
/** Or a precomputed lowercase-hex sha256, if the caller hashed during streaming (avoids buffering). */
|
|
92
92
|
sha256?: string;
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Parse a configured public key (PEM, raw 32-byte base64, SPKI DER base64, or a KeyObject) into a node KeyObject.
|
|
96
|
+
*
|
|
97
|
+
* The base64 forms mirror scripts/release-update-manifest.mjs parsePublicKey exactly: the release pipeline and the
|
|
98
|
+
* built-in channel key ship the full SPKI DER blob (44 bytes for Ed25519), while operator overrides may supply the
|
|
99
|
+
* bare 32-byte raw key. Anything that does not decode to a valid Ed25519 SPKI key throws (fail-closed).
|
|
100
|
+
*/
|
|
101
|
+
export declare function toPublicKey(publicKey: string | KeyObject): KeyObject;
|
|
94
102
|
/**
|
|
95
103
|
* Verify downloaded artifacts against the manifest. PURE + deterministic (takes already-read bytes/hashes; does
|
|
96
104
|
* NO I/O). Two layers:
|
package/dist/ops/selfUpdate.js
CHANGED
|
@@ -224,19 +224,35 @@ export function canonicalManifestBytes(manifest) {
|
|
|
224
224
|
};
|
|
225
225
|
return new TextEncoder().encode(JSON.stringify(canonical));
|
|
226
226
|
}
|
|
227
|
-
/**
|
|
228
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Parse a configured public key (PEM, raw 32-byte base64, SPKI DER base64, or a KeyObject) into a node KeyObject.
|
|
229
|
+
*
|
|
230
|
+
* The base64 forms mirror scripts/release-update-manifest.mjs parsePublicKey exactly: the release pipeline and the
|
|
231
|
+
* built-in channel key ship the full SPKI DER blob (44 bytes for Ed25519), while operator overrides may supply the
|
|
232
|
+
* bare 32-byte raw key. Anything that does not decode to a valid Ed25519 SPKI key throws (fail-closed).
|
|
233
|
+
*/
|
|
234
|
+
export function toPublicKey(publicKey) {
|
|
229
235
|
if (typeof publicKey !== 'string')
|
|
230
236
|
return publicKey;
|
|
231
237
|
const trimmed = publicKey.trim();
|
|
232
238
|
if (trimmed.includes('BEGIN PUBLIC KEY'))
|
|
233
239
|
return createPublicKey(trimmed);
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
+
const decoded = Buffer.from(trimmed, 'base64');
|
|
241
|
+
// Raw 32-byte Ed25519 key, base64 → wrap in DER SPKI so createPublicKey accepts it;
|
|
242
|
+
// any other length is assumed to already be a full SPKI DER blob.
|
|
243
|
+
const der = decoded.length === 32
|
|
244
|
+
? Buffer.concat([Buffer.from('302a300506032b6570032100', 'hex'), decoded])
|
|
245
|
+
: decoded;
|
|
246
|
+
let key;
|
|
247
|
+
try {
|
|
248
|
+
key = createPublicKey({ key: der, format: 'der', type: 'spki' });
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
throw new Error('ed25519 public key must be a raw 32-byte or SPKI DER base64 key');
|
|
252
|
+
}
|
|
253
|
+
if (key.asymmetricKeyType !== 'ed25519')
|
|
254
|
+
throw new Error('ed25519 public key must be an Ed25519 key');
|
|
255
|
+
return key;
|
|
240
256
|
}
|
|
241
257
|
/** Verify the signature over the complete canonical manifest when a public key is configured. */
|
|
242
258
|
function verifyConfiguredManifestSignature(manifest, publicKey) {
|
|
@@ -169,6 +169,13 @@ export declare const personalityModel: z.ZodObject<{
|
|
|
169
169
|
extensions: Record<string, unknown>;
|
|
170
170
|
updatedAt: string | null;
|
|
171
171
|
version: 1;
|
|
172
|
+
stats: Record<string, {
|
|
173
|
+
success: number;
|
|
174
|
+
updatedAt: string | null;
|
|
175
|
+
fail: number;
|
|
176
|
+
n: number;
|
|
177
|
+
avgScore: number;
|
|
178
|
+
}>;
|
|
172
179
|
current: {
|
|
173
180
|
type: "PersonalityState";
|
|
174
181
|
rigor: number;
|
|
@@ -177,13 +184,6 @@ export declare const personalityModel: z.ZodObject<{
|
|
|
177
184
|
risk_tolerance: number;
|
|
178
185
|
obedience: number;
|
|
179
186
|
};
|
|
180
|
-
stats: Record<string, {
|
|
181
|
-
success: number;
|
|
182
|
-
updatedAt: string | null;
|
|
183
|
-
fail: number;
|
|
184
|
-
n: number;
|
|
185
|
-
avgScore: number;
|
|
186
|
-
}>;
|
|
187
187
|
history: {
|
|
188
188
|
at: string;
|
|
189
189
|
score: number | null;
|
|
@@ -195,6 +195,13 @@ export declare const personalityModel: z.ZodObject<{
|
|
|
195
195
|
extensions?: Record<string, unknown> | undefined;
|
|
196
196
|
updatedAt?: string | null | undefined;
|
|
197
197
|
version?: 1 | undefined;
|
|
198
|
+
stats?: Record<string, {
|
|
199
|
+
success?: number | undefined;
|
|
200
|
+
updatedAt?: string | null | undefined;
|
|
201
|
+
fail?: number | undefined;
|
|
202
|
+
n?: number | undefined;
|
|
203
|
+
avgScore?: number | undefined;
|
|
204
|
+
}> | undefined;
|
|
198
205
|
current?: {
|
|
199
206
|
type?: "PersonalityState" | undefined;
|
|
200
207
|
rigor?: number | undefined;
|
|
@@ -203,13 +210,6 @@ export declare const personalityModel: z.ZodObject<{
|
|
|
203
210
|
risk_tolerance?: number | undefined;
|
|
204
211
|
obedience?: number | undefined;
|
|
205
212
|
} | undefined;
|
|
206
|
-
stats?: Record<string, {
|
|
207
|
-
success?: number | undefined;
|
|
208
|
-
updatedAt?: string | null | undefined;
|
|
209
|
-
fail?: number | undefined;
|
|
210
|
-
n?: number | undefined;
|
|
211
|
-
avgScore?: number | undefined;
|
|
212
|
-
}> | undefined;
|
|
213
213
|
history?: {
|
|
214
214
|
at: string;
|
|
215
215
|
outcome: string;
|
|
@@ -227,12 +227,12 @@ export declare const personalityMutation: z.ZodObject<{
|
|
|
227
227
|
reason: z.ZodDefault<z.ZodString>;
|
|
228
228
|
}, "strip", z.ZodTypeAny, {
|
|
229
229
|
type: "PersonalityMutation";
|
|
230
|
+
delta: number;
|
|
230
231
|
reason: string;
|
|
231
232
|
param: "rigor" | "creativity" | "verbosity" | "risk_tolerance" | "obedience";
|
|
232
|
-
delta: number;
|
|
233
233
|
}, {
|
|
234
|
-
param: "rigor" | "creativity" | "verbosity" | "risk_tolerance" | "obedience";
|
|
235
234
|
delta: number;
|
|
235
|
+
param: "rigor" | "creativity" | "verbosity" | "risk_tolerance" | "obedience";
|
|
236
236
|
type?: "PersonalityMutation" | undefined;
|
|
237
237
|
reason?: string | undefined;
|
|
238
238
|
}>;
|