@evomap/evolver-core 2.0.0-beta.19 → 2.0.0-beta.22

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.
Files changed (160) hide show
  1. package/assets/gep/genes.jsonl +5 -5
  2. package/dist/algo/bans.d.ts +10 -1
  3. package/dist/algo/bans.js +56 -6
  4. package/dist/algo/candidateAssembly.d.ts +25 -2
  5. package/dist/algo/candidateAssembly.js +143 -20
  6. package/dist/algo/capabilityCandidates.js +10 -0
  7. package/dist/algo/cycleEngine.d.ts +40 -5
  8. package/dist/algo/cycleEngine.js +277 -37
  9. package/dist/algo/evolutionEvent.d.ts +26 -0
  10. package/dist/algo/evolutionEvent.js +32 -0
  11. package/dist/algo/exploration.d.ts +7 -0
  12. package/dist/algo/exploration.js +16 -3
  13. package/dist/algo/geneHealth.d.ts +34 -1
  14. package/dist/algo/geneHealth.js +42 -0
  15. package/dist/algo/geneIntake.d.ts +46 -1
  16. package/dist/algo/geneIntake.js +121 -10
  17. package/dist/algo/geneSelection.d.ts +115 -6
  18. package/dist/algo/geneSelection.js +459 -32
  19. package/dist/algo/index.d.ts +4 -1
  20. package/dist/algo/index.js +4 -1
  21. package/dist/algo/kautoProjection.d.ts +41 -0
  22. package/dist/algo/kautoProjection.js +95 -0
  23. package/dist/algo/kautoValidator.d.ts +68 -0
  24. package/dist/algo/kautoValidator.js +256 -0
  25. package/dist/algo/orchestrator.d.ts +14 -1
  26. package/dist/algo/orchestrator.js +9 -2
  27. package/dist/algo/solidify.d.ts +11 -2
  28. package/dist/algo/solidify.js +37 -7
  29. package/dist/algo/ucb1.d.ts +53 -0
  30. package/dist/algo/ucb1.js +156 -0
  31. package/dist/assetrepair/hubRejection.d.ts +12 -0
  32. package/dist/assetrepair/hubRejection.js +109 -0
  33. package/dist/assetrepair/index.d.ts +2 -0
  34. package/dist/assetrepair/index.js +2 -0
  35. package/dist/assetrepair/repair.d.ts +33 -0
  36. package/dist/assetrepair/repair.js +155 -0
  37. package/dist/assetstore/assetSidecarRecords.js +5 -1
  38. package/dist/assetstore/assetStoreHealth.d.ts +2 -3
  39. package/dist/assetstore/assetStoreHealth.js +4 -10
  40. package/dist/assetstore/foreignJsonlSource.d.ts +48 -0
  41. package/dist/assetstore/foreignJsonlSource.js +150 -0
  42. package/dist/assetstore/index.d.ts +3 -0
  43. package/dist/assetstore/index.js +3 -0
  44. package/dist/assetstore/learningHistory.js +3 -3
  45. package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
  46. package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
  47. package/dist/assetstore/localJsonl.d.ts +8 -0
  48. package/dist/assetstore/localJsonl.js +128 -3
  49. package/dist/assetstore/provenance.d.ts +38 -3
  50. package/dist/assetstore/provenance.js +103 -45
  51. package/dist/assetstore/provider.d.ts +4 -0
  52. package/dist/assetstore/reviewFilter.d.ts +19 -1
  53. package/dist/assetstore/reviewFilter.js +36 -0
  54. package/dist/assetstore/unionReadStore.d.ts +25 -0
  55. package/dist/assetstore/unionReadStore.js +119 -0
  56. package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
  57. package/dist/benchmark/antiGeneBenchmark.js +4 -3
  58. package/dist/benchmark/antiGeneRollout.d.ts +2 -0
  59. package/dist/benchmark/antiGeneRollout.js +4 -3
  60. package/dist/benchmark/index.d.ts +2 -1
  61. package/dist/benchmark/index.js +2 -1
  62. package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
  63. package/dist/benchmark/selectionFlatAbstention.js +481 -0
  64. package/dist/bootstrap/envFingerprint.d.ts +9 -0
  65. package/dist/bootstrap/envFingerprint.js +5 -0
  66. package/dist/bootstrap/index.d.ts +2 -1
  67. package/dist/bootstrap/index.js +2 -1
  68. package/dist/bootstrap/lifecycleBootstrap.d.ts +111 -0
  69. package/dist/bootstrap/lifecycleBootstrap.js +433 -0
  70. package/dist/bootstrap/v1EnvCompat.d.ts +3 -0
  71. package/dist/bootstrap/v1EnvCompat.js +48 -1
  72. package/dist/events/eventArchive.d.ts +2 -0
  73. package/dist/events/eventArchive.js +13 -3
  74. package/dist/events/eventSchema.d.ts +7 -7
  75. package/dist/events/eventStore.d.ts +2 -0
  76. package/dist/events/eventStore.js +5 -1
  77. package/dist/events/ingest.d.ts +2 -1
  78. package/dist/events/ingest.js +6 -0
  79. package/dist/exec/autoExec.d.ts +30 -3
  80. package/dist/exec/autoExec.js +294 -29
  81. package/dist/exec/autonomousCycle.d.ts +7 -0
  82. package/dist/exec/autonomousCycle.js +2 -0
  83. package/dist/exec/claudeBridge.d.ts +28 -6
  84. package/dist/exec/claudeBridge.js +411 -258
  85. package/dist/exec/executionBinding.d.ts +414 -0
  86. package/dist/exec/executionBinding.js +588 -0
  87. package/dist/exec/index.d.ts +1 -0
  88. package/dist/exec/index.js +1 -0
  89. package/dist/exec/proofOfWork.d.ts +1 -1
  90. package/dist/exec/proofOfWork.js +2 -2
  91. package/dist/exec/runnerRegistry.d.ts +5 -0
  92. package/dist/exec/runnerRegistry.js +54 -14
  93. package/dist/hub/capability.d.ts +40 -1
  94. package/dist/hub/conversationDistiller.d.ts +19 -0
  95. package/dist/hub/conversationDistiller.js +115 -37
  96. package/dist/hub/fake.d.ts +1 -0
  97. package/dist/hub/fake.js +1 -0
  98. package/dist/hub/index.d.ts +1 -0
  99. package/dist/hub/index.js +1 -0
  100. package/dist/hub/recipeCompose.d.ts +27 -0
  101. package/dist/hub/recipeCompose.js +90 -0
  102. package/dist/hub/sanitize.js +119 -5
  103. package/dist/index.d.ts +2 -0
  104. package/dist/index.js +2 -0
  105. package/dist/mailbox/ipcServer.d.ts +2 -0
  106. package/dist/mailbox/ipcServer.js +20 -0
  107. package/dist/mailbox/store.d.ts +52 -2
  108. package/dist/mailbox/store.js +546 -81
  109. package/dist/modelCompatibility.d.ts +164 -0
  110. package/dist/modelCompatibility.js +309 -0
  111. package/dist/observers/valueDigestObserver.d.ts +9 -0
  112. package/dist/observers/valueDigestObserver.js +35 -2
  113. package/dist/ops/cleanup.js +1 -1
  114. package/dist/ops/evolutionGraphProjection.d.ts +20 -0
  115. package/dist/ops/evolutionGraphProjection.js +315 -0
  116. package/dist/ops/index.d.ts +2 -1
  117. package/dist/ops/index.js +2 -1
  118. package/dist/ops/selfUpdate.d.ts +8 -0
  119. package/dist/ops/selfUpdate.js +24 -8
  120. package/dist/ops/valueOutreach.d.ts +3 -1
  121. package/dist/ops/valueOutreach.js +5 -1
  122. package/dist/personality/schema.d.ts +18 -18
  123. package/dist/schema/evolutionGraph.d.ts +784 -0
  124. package/dist/schema/evolutionGraph.js +187 -0
  125. package/dist/schema/index.d.ts +1 -0
  126. package/dist/schema/index.js +1 -0
  127. package/dist/schema/proofOfWork.d.ts +125 -6
  128. package/dist/schema/proofOfWork.js +102 -4
  129. package/dist/shadow/shadowHub.js +1 -0
  130. package/dist/signals/expand.d.ts +15 -1
  131. package/dist/signals/expand.js +148 -0
  132. package/dist/signals/index.d.ts +3 -1
  133. package/dist/signals/index.js +3 -1
  134. package/dist/signals/scopeVocabulary.d.ts +75 -0
  135. package/dist/signals/scopeVocabulary.js +91 -0
  136. package/dist/signals/taskDomain.d.ts +22 -0
  137. package/dist/signals/taskDomain.js +43 -0
  138. package/dist/trace/learningTrace.d.ts +7 -0
  139. package/dist/trace/learningTrace.js +22 -0
  140. package/dist/trace/trajectory.d.ts +8 -0
  141. package/dist/trace/trajectory.js +14 -2
  142. package/dist/util/fileLock.d.ts +92 -5
  143. package/dist/util/fileLock.js +809 -70
  144. package/dist/util/index.d.ts +2 -1
  145. package/dist/util/index.js +1 -1
  146. package/dist/verify/index.d.ts +2 -1
  147. package/dist/verify/index.js +1 -1
  148. package/dist/verify/sandboxRunner.d.ts +2 -0
  149. package/dist/verify/sandboxRunner.js +154 -10
  150. package/dist/verify/sandboxedValidation.d.ts +7 -2
  151. package/dist/verify/sandboxedValidation.js +102 -24
  152. package/dist/verify/validation.d.ts +24 -3
  153. package/dist/verify/validation.js +141 -24
  154. package/dist/wire/geneHints.d.ts +88 -16
  155. package/dist/wire/geneHints.js +124 -15
  156. package/dist/wire/index.d.ts +8 -3
  157. package/dist/wire/index.js +2 -2
  158. package/dist/wire/schemaGate.d.ts +21 -0
  159. package/dist/wire/schemaGate.js +119 -10
  160. package/package.json +5 -4
@@ -0,0 +1,433 @@
1
+ import { posix, win32 } from 'node:path';
2
+ import { parseFileLockProcessStartIdentity, sameFileLockProcessStartIdentity, } from '../util/fileLock.js';
3
+ export const LIFECYCLE_BOOTSTRAP_MARKER_SCHEMA = 'evolver.lifecycle-bootstrap.v1';
4
+ export const LIFECYCLE_BOOTSTRAP_LEGACY_BINDING = 'legacy-v907';
5
+ export const LIFECYCLE_BOOTSTRAP_LEGACY_ENV_FILE_STATE_ROOT_PROOF = 'legacy-v907-env-file';
6
+ export const LIFECYCLE_BOOTSTRAP_DEADLINE_ENV = 'EVOLVER_INTERNAL_BOOTSTRAP_DEADLINE_MS';
7
+ export const LIFECYCLE_BOOTSTRAP_TRANSACTION_ENV = 'EVOLVER_INTERNAL_BOOTSTRAP_TRANSACTION_ID';
8
+ export const LIFECYCLE_BOOTSTRAP_SUCCESS_FILE = 'bootstrap.json';
9
+ export const LIFECYCLE_BOOTSTRAP_JOURNAL_FILE = 'bootstrap-transaction.json';
10
+ export const LIFECYCLE_BOOTSTRAP_OWNER_LOCK_FILE = 'bootstrap-owner.lock';
11
+ export const LIFECYCLE_BOOTSTRAP_READINESS_FILE = 'bootstrap-readiness.json';
12
+ export const LIFECYCLE_BOOTSTRAP_READINESS_LOCK_FILE = 'bootstrap-readiness.lock';
13
+ export const LIFECYCLE_BOOTSTRAP_READINESS_SCHEMA = 'evolver.lifecycle-bootstrap-readiness.v1';
14
+ export const LIFECYCLE_BOOTSTRAP_MANUAL_TRANSITION_FILE = 'bootstrap-manual-transition.json';
15
+ export const LIFECYCLE_BOOTSTRAP_MANUAL_TRANSITION_SCHEMA = 'evolver.lifecycle-bootstrap-manual-transition.v1';
16
+ export const MAX_LIFECYCLE_BOOTSTRAP_MANUAL_TRANSITION_BYTES = 4 * 1024;
17
+ export const LIFECYCLE_BOOTSTRAP_REGISTRATION_INTENT_FILE = 'bootstrap-registration.intent.json';
18
+ export const LIFECYCLE_BOOTSTRAP_REGISTRATION_INTENT_TERMINAL_FILE = 'bootstrap-registration.intent.terminal';
19
+ export const LIFECYCLE_BOOTSTRAP_REGISTRATION_INTENT_CLEARING_FILE = 'bootstrap-registration.intent.clearing';
20
+ export const LIFECYCLE_BOOTSTRAP_REGISTRATION_INTENT_SCHEMA = 'evolver.bootstrap-registration-intent.v1';
21
+ export const LIFECYCLE_BOOTSTRAP_REGISTRATION_TOKEN_ENV = 'EVOLVER_INTERNAL_BOOTSTRAP_REGISTRATION_TOKEN';
22
+ export const MAX_LIFECYCLE_BOOTSTRAP_REGISTRATION_INTENT_BYTES = 4 * 1024;
23
+ const TARGETS = new Set(['launchd', 'systemd', 'windows']);
24
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
25
+ const SHA256_RE = /^[0-9a-f]{64}$/;
26
+ function canonicalBootstrapPath(path, target) {
27
+ return target === 'windows'
28
+ ? win32.isAbsolute(path) && win32.normalize(path) === path
29
+ : posix.isAbsolute(path) && posix.normalize(path) === path;
30
+ }
31
+ function bootstrapPathKey(path, target) {
32
+ return target === 'windows' ? win32.normalize(path).toLowerCase() : path;
33
+ }
34
+ function boundedText(value, maxLength) {
35
+ if (typeof value !== 'string' || value.length === 0 || value.length > maxLength)
36
+ return false;
37
+ for (let index = 0; index < value.length; index += 1) {
38
+ const code = value.charCodeAt(index);
39
+ if (code <= 0x1f || code === 0x7f)
40
+ return false;
41
+ }
42
+ return true;
43
+ }
44
+ function exactRecordKeys(record, expected) {
45
+ const actual = Object.keys(record).sort();
46
+ const sortedExpected = [...expected].sort();
47
+ return actual.length === sortedExpected.length
48
+ && actual.every((key, index) => key === sortedExpected[index]);
49
+ }
50
+ function exactIsoTimestamp(value) {
51
+ if (typeof value !== 'string')
52
+ return false;
53
+ const parsed = Date.parse(value);
54
+ return Number.isFinite(parsed) && new Date(parsed).toISOString() === value;
55
+ }
56
+ export function parseLifecycleBootstrapRegistrationToken(value) {
57
+ return typeof value === 'string' && UUID_RE.test(value) ? value : undefined;
58
+ }
59
+ function exactProcessStartIdentityKeys(value) {
60
+ if (!value || typeof value !== 'object' || Array.isArray(value))
61
+ return false;
62
+ const record = value;
63
+ if (record['source'] === 'linux-proc') {
64
+ return exactRecordKeys(record, ['source', 'bootId', 'startTicks']);
65
+ }
66
+ if (record['source'] === 'windows-powershell') {
67
+ return exactRecordKeys(record, ['source', 'startTimeTicks']);
68
+ }
69
+ if (record['source'] === 'darwin-ps') {
70
+ return exactRecordKeys(record, ['source', 'startTime']);
71
+ }
72
+ return false;
73
+ }
74
+ export function parseLifecycleBootstrapManualTransition(value) {
75
+ if (!value || typeof value !== 'object' || Array.isArray(value))
76
+ return undefined;
77
+ const record = value;
78
+ if (!exactRecordKeys(record, ['schema', 'transitionId', 'removedTransactionId', 'target', 'service', 'createdAt'])
79
+ || record['schema'] !== LIFECYCLE_BOOTSTRAP_MANUAL_TRANSITION_SCHEMA
80
+ || typeof record['transitionId'] !== 'string' || !UUID_RE.test(record['transitionId'])
81
+ || typeof record['removedTransactionId'] !== 'string'
82
+ || !UUID_RE.test(record['removedTransactionId'])
83
+ || typeof record['target'] !== 'string'
84
+ || !TARGETS.has(record['target'])
85
+ || !boundedText(record['service'], 128)
86
+ || !exactIsoTimestamp(record['createdAt'])) {
87
+ return undefined;
88
+ }
89
+ return {
90
+ schema: LIFECYCLE_BOOTSTRAP_MANUAL_TRANSITION_SCHEMA,
91
+ transitionId: record['transitionId'],
92
+ removedTransactionId: record['removedTransactionId'],
93
+ target: record['target'],
94
+ service: record['service'],
95
+ createdAt: record['createdAt'],
96
+ };
97
+ }
98
+ export function parseLifecycleBootstrapManualTransitionJson(raw) {
99
+ try {
100
+ return parseLifecycleBootstrapManualTransition(JSON.parse(raw));
101
+ }
102
+ catch {
103
+ return undefined;
104
+ }
105
+ }
106
+ export function parseLifecycleBootstrapRegistrationIntent(value) {
107
+ if (!value || typeof value !== 'object' || Array.isArray(value))
108
+ return undefined;
109
+ const record = value;
110
+ const ownerValue = record['owner'];
111
+ if (record['schema'] !== LIFECYCLE_BOOTSTRAP_REGISTRATION_INTENT_SCHEMA
112
+ || !ownerValue || typeof ownerValue !== 'object' || Array.isArray(ownerValue)
113
+ || !exactRecordKeys(ownerValue, ['pid', 'token', 'processStartIdentity'])
114
+ || !Number.isSafeInteger(ownerValue['pid'])
115
+ || ownerValue['pid'] <= 0
116
+ || !parseLifecycleBootstrapRegistrationToken(ownerValue['token'])
117
+ || !exactProcessStartIdentityKeys(ownerValue['processStartIdentity'])
118
+ || !exactIsoTimestamp(record['createdAt'])) {
119
+ return undefined;
120
+ }
121
+ const processStartIdentity = parseFileLockProcessStartIdentity(ownerValue['processStartIdentity']);
122
+ if (!processStartIdentity)
123
+ return undefined;
124
+ const owner = {
125
+ pid: ownerValue['pid'],
126
+ token: ownerValue['token'],
127
+ processStartIdentity,
128
+ };
129
+ const base = {
130
+ schema: LIFECYCLE_BOOTSTRAP_REGISTRATION_INTENT_SCHEMA,
131
+ owner,
132
+ createdAt: record['createdAt'],
133
+ };
134
+ if (record['state'] === 'registering') {
135
+ if (!exactRecordKeys(record, ['schema', 'state', 'owner', 'createdAt']))
136
+ return undefined;
137
+ return { ...base, state: 'registering' };
138
+ }
139
+ const terminalOutcomes = new Set([
140
+ 'committed',
141
+ 'rolled_back',
142
+ 'no_child',
143
+ 'cancelled',
144
+ ]);
145
+ if (record['state'] !== 'terminal'
146
+ || typeof record['outcome'] !== 'string'
147
+ || !terminalOutcomes.has(record['outcome'])
148
+ || !exactIsoTimestamp(record['terminalAt'])) {
149
+ return undefined;
150
+ }
151
+ const outcome = record['outcome'];
152
+ if (outcome === 'committed') {
153
+ if (!exactRecordKeys(record, ['schema', 'state', 'owner', 'createdAt', 'outcome', 'terminalAt', 'transactionId'])
154
+ || typeof record['transactionId'] !== 'string'
155
+ || !UUID_RE.test(record['transactionId'])) {
156
+ return undefined;
157
+ }
158
+ return {
159
+ ...base,
160
+ state: 'terminal',
161
+ outcome,
162
+ terminalAt: record['terminalAt'],
163
+ transactionId: record['transactionId'],
164
+ };
165
+ }
166
+ if (!exactRecordKeys(record, ['schema', 'state', 'owner', 'createdAt', 'outcome', 'terminalAt'])
167
+ || record['transactionId'] !== undefined) {
168
+ return undefined;
169
+ }
170
+ return { ...base, state: 'terminal', outcome, terminalAt: record['terminalAt'] };
171
+ }
172
+ export function parseLifecycleBootstrapRegistrationIntentJson(raw) {
173
+ try {
174
+ return parseLifecycleBootstrapRegistrationIntent(JSON.parse(raw));
175
+ }
176
+ catch {
177
+ return undefined;
178
+ }
179
+ }
180
+ export function parseLifecycleBootstrapMarker(value) {
181
+ if (!value || typeof value !== 'object' || Array.isArray(value))
182
+ return undefined;
183
+ const record = value;
184
+ if (record['schema'] !== LIFECYCLE_BOOTSTRAP_MARKER_SCHEMA)
185
+ return undefined;
186
+ const markerKeys = [
187
+ 'schema',
188
+ 'transactionId',
189
+ 'bootstrappedAt',
190
+ 'target',
191
+ 'service',
192
+ 'files',
193
+ 'managerArtifactPath',
194
+ 'artifacts',
195
+ ...(record['managerBindingKind'] === undefined ? [] : ['managerBindingKind']),
196
+ ...(record['preservedArtifacts'] === undefined ? [] : ['preservedArtifacts']),
197
+ ...(record['legacyStateRootProof'] === undefined ? [] : ['legacyStateRootProof']),
198
+ ];
199
+ if (!exactRecordKeys(record, markerKeys))
200
+ return undefined;
201
+ if (typeof record['transactionId'] !== 'string' || !UUID_RE.test(record['transactionId']))
202
+ return undefined;
203
+ if (typeof record['bootstrappedAt'] !== 'string' || Number.isNaN(Date.parse(record['bootstrappedAt'])))
204
+ return undefined;
205
+ if (typeof record['target'] !== 'string' || !TARGETS.has(record['target']))
206
+ return undefined;
207
+ if (!boundedText(record['service'], 128))
208
+ return undefined;
209
+ if (!Array.isArray(record['files']) || record['files'].length === 0 || record['files'].length > 32)
210
+ return undefined;
211
+ if (!record['files'].every((file) => boundedText(file, 4_096)))
212
+ return undefined;
213
+ const files = record['files'];
214
+ const target = record['target'];
215
+ if (files.some((file) => !canonicalBootstrapPath(file, target)))
216
+ return undefined;
217
+ const pathKeys = files.map((file) => bootstrapPathKey(file, target));
218
+ if (new Set(pathKeys).size !== pathKeys.length)
219
+ return undefined;
220
+ if (!boundedText(record['managerArtifactPath'], 4_096)
221
+ || !canonicalBootstrapPath(record['managerArtifactPath'], target)
222
+ || !pathKeys.includes(bootstrapPathKey(record['managerArtifactPath'], target)))
223
+ return undefined;
224
+ const managerBindingKind = record['managerBindingKind'];
225
+ if (managerBindingKind !== undefined
226
+ && managerBindingKind !== 'transaction'
227
+ && managerBindingKind !== LIFECYCLE_BOOTSTRAP_LEGACY_BINDING)
228
+ return undefined;
229
+ if (!Array.isArray(record['artifacts']))
230
+ return undefined;
231
+ const parseArtifact = (artifact) => {
232
+ if (!artifact || typeof artifact !== 'object' || Array.isArray(artifact))
233
+ return undefined;
234
+ const value = artifact;
235
+ if (!exactRecordKeys(value, ['path', 'size', 'sha256', 'device', 'inode']))
236
+ return undefined;
237
+ if (!boundedText(value['path'], 4_096) || !canonicalBootstrapPath(value['path'], target)
238
+ || !Number.isSafeInteger(value['size']) || value['size'] < 0
239
+ || typeof value['sha256'] !== 'string' || !SHA256_RE.test(value['sha256']))
240
+ return undefined;
241
+ if (typeof value['device'] !== 'string' || !/^[0-9]+$/.test(value['device'])
242
+ || BigInt(value['device']) <= 0n
243
+ || typeof value['inode'] !== 'string' || !/^[0-9]+$/.test(value['inode'])
244
+ || BigInt(value['inode']) <= 0n)
245
+ return undefined;
246
+ return {
247
+ path: value['path'],
248
+ size: value['size'],
249
+ sha256: value['sha256'],
250
+ device: value['device'],
251
+ inode: value['inode'],
252
+ };
253
+ };
254
+ const artifacts = record['artifacts'].map(parseArtifact);
255
+ const preservedArtifacts = record['preservedArtifacts'] === undefined
256
+ ? []
257
+ : Array.isArray(record['preservedArtifacts'])
258
+ ? record['preservedArtifacts'].map(parseArtifact)
259
+ : [undefined];
260
+ if (record['preservedArtifacts'] !== undefined
261
+ && (managerBindingKind !== LIFECYCLE_BOOTSTRAP_LEGACY_BINDING
262
+ || preservedArtifacts.length === 0))
263
+ return undefined;
264
+ const legacyStateRootProofValue = record['legacyStateRootProof'];
265
+ let legacyStateRootProof;
266
+ if (legacyStateRootProofValue !== undefined) {
267
+ if (managerBindingKind !== LIFECYCLE_BOOTSTRAP_LEGACY_BINDING
268
+ || !legacyStateRootProofValue
269
+ || typeof legacyStateRootProofValue !== 'object'
270
+ || Array.isArray(legacyStateRootProofValue))
271
+ return undefined;
272
+ const proof = legacyStateRootProofValue;
273
+ if (!exactRecordKeys(proof, ['kind', 'envFilePath', 'stateDir'])
274
+ || proof['kind'] !== LIFECYCLE_BOOTSTRAP_LEGACY_ENV_FILE_STATE_ROOT_PROOF
275
+ || !boundedText(proof['envFilePath'], 4_096)
276
+ || !canonicalBootstrapPath(proof['envFilePath'], target)
277
+ || !boundedText(proof['stateDir'], 4_096)
278
+ || !canonicalBootstrapPath(proof['stateDir'], target))
279
+ return undefined;
280
+ legacyStateRootProof = {
281
+ kind: LIFECYCLE_BOOTSTRAP_LEGACY_ENV_FILE_STATE_ROOT_PROOF,
282
+ envFilePath: proof['envFilePath'],
283
+ stateDir: proof['stateDir'],
284
+ };
285
+ }
286
+ if (managerBindingKind !== LIFECYCLE_BOOTSTRAP_LEGACY_BINDING
287
+ && artifacts.length !== files.length)
288
+ return undefined;
289
+ const receipts = [...artifacts, ...preservedArtifacts];
290
+ if (receipts.length !== files.length
291
+ || receipts.some((artifact) => artifact === undefined)
292
+ || receipts.some((artifact, index) => bootstrapPathKey(artifact.path, target) !== pathKeys[index]))
293
+ return undefined;
294
+ const ownedKeys = new Set(artifacts.map((artifact) => bootstrapPathKey(artifact.path, target)));
295
+ if (!ownedKeys.has(bootstrapPathKey(record['managerArtifactPath'], target)))
296
+ return undefined;
297
+ if (legacyStateRootProof) {
298
+ const proofKey = bootstrapPathKey(legacyStateRootProof.envFilePath, target);
299
+ const preservedKeys = new Set(preservedArtifacts.map((artifact) => bootstrapPathKey(artifact.path, target)));
300
+ if (!preservedKeys.has(proofKey) || ownedKeys.has(proofKey))
301
+ return undefined;
302
+ }
303
+ return {
304
+ schema: LIFECYCLE_BOOTSTRAP_MARKER_SCHEMA,
305
+ transactionId: record['transactionId'],
306
+ bootstrappedAt: record['bootstrappedAt'],
307
+ target,
308
+ service: record['service'],
309
+ files: [...files],
310
+ managerArtifactPath: record['managerArtifactPath'],
311
+ ...(managerBindingKind === undefined ? {} : {
312
+ managerBindingKind: managerBindingKind,
313
+ }),
314
+ artifacts: artifacts,
315
+ ...(preservedArtifacts.length === 0 ? {} : {
316
+ preservedArtifacts: preservedArtifacts,
317
+ }),
318
+ ...(legacyStateRootProof ? { legacyStateRootProof } : {}),
319
+ };
320
+ }
321
+ export function parseLegacyLifecycleBootstrapMarker(value) {
322
+ if (!value || typeof value !== 'object' || Array.isArray(value))
323
+ return undefined;
324
+ const record = value;
325
+ if (!exactRecordKeys(record, ['bootstrappedAt', 'target', 'service', 'files'])
326
+ || !exactIsoTimestamp(record['bootstrappedAt'])
327
+ || typeof record['target'] !== 'string'
328
+ || !TARGETS.has(record['target'])
329
+ || !boundedText(record['service'], 128)
330
+ || !Array.isArray(record['files'])
331
+ || record['files'].length === 0
332
+ || record['files'].length > 32
333
+ || !record['files'].every((file) => boundedText(file, 4_096)))
334
+ return undefined;
335
+ const target = record['target'];
336
+ const service = record['service'];
337
+ const expectedService = target === 'systemd'
338
+ ? 'systemd-user'
339
+ : target === 'launchd'
340
+ ? 'launchd'
341
+ : 'windows-scheduled-task';
342
+ const files = record['files'];
343
+ if (service !== expectedService
344
+ || files.some((file) => !canonicalBootstrapPath(file, target)))
345
+ return undefined;
346
+ const pathKeys = files.map((file) => bootstrapPathKey(file, target));
347
+ if (new Set(pathKeys).size !== pathKeys.length)
348
+ return undefined;
349
+ return {
350
+ bootstrappedAt: record['bootstrappedAt'],
351
+ target,
352
+ service,
353
+ files: [...files],
354
+ };
355
+ }
356
+ export function parseLegacyLifecycleBootstrapMarkerJson(raw) {
357
+ try {
358
+ return parseLegacyLifecycleBootstrapMarker(JSON.parse(raw));
359
+ }
360
+ catch {
361
+ return undefined;
362
+ }
363
+ }
364
+ export function parseLifecycleBootstrapMarkerJson(raw) {
365
+ try {
366
+ return parseLifecycleBootstrapMarker(JSON.parse(raw));
367
+ }
368
+ catch {
369
+ return undefined;
370
+ }
371
+ }
372
+ export function parseLifecycleBootstrapReadiness(value) {
373
+ if (!value || typeof value !== 'object' || Array.isArray(value))
374
+ return undefined;
375
+ const record = value;
376
+ if (!exactRecordKeys(record, [
377
+ 'schema',
378
+ 'transactionId',
379
+ 'pid',
380
+ 'pidProcessStartIdentity',
381
+ 'supervisorPid',
382
+ 'supervisorProcessStartIdentity',
383
+ 'startedAt',
384
+ 'ipcUrl',
385
+ ])
386
+ || record['schema'] !== LIFECYCLE_BOOTSTRAP_READINESS_SCHEMA
387
+ || typeof record['transactionId'] !== 'string' || !UUID_RE.test(record['transactionId'])
388
+ || !Number.isSafeInteger(record['pid']) || record['pid'] <= 0
389
+ || !Number.isSafeInteger(record['supervisorPid']) || record['supervisorPid'] <= 0
390
+ || !exactProcessStartIdentityKeys(record['pidProcessStartIdentity'])
391
+ || !exactProcessStartIdentityKeys(record['supervisorProcessStartIdentity'])
392
+ || !exactIsoTimestamp(record['startedAt'])
393
+ || !boundedText(record['ipcUrl'], 2_048))
394
+ return undefined;
395
+ const pidProcessStartIdentity = parseFileLockProcessStartIdentity(record['pidProcessStartIdentity']);
396
+ const supervisorProcessStartIdentity = parseFileLockProcessStartIdentity(record['supervisorProcessStartIdentity']);
397
+ if (!pidProcessStartIdentity || !supervisorProcessStartIdentity)
398
+ return undefined;
399
+ if (record['pid'] === record['supervisorPid']
400
+ && !sameFileLockProcessStartIdentity(pidProcessStartIdentity, supervisorProcessStartIdentity))
401
+ return undefined;
402
+ try {
403
+ const url = new URL(record['ipcUrl']);
404
+ const port = Number(url.port);
405
+ if (url.protocol !== 'http:' || !['127.0.0.1', '[::1]'].includes(url.hostname.toLowerCase())
406
+ || !Number.isSafeInteger(port) || port <= 0 || port > 65_535
407
+ || url.username !== '' || url.password !== '' || url.pathname !== '/'
408
+ || url.search !== '' || url.hash !== '') {
409
+ return undefined;
410
+ }
411
+ }
412
+ catch {
413
+ return undefined;
414
+ }
415
+ return {
416
+ schema: LIFECYCLE_BOOTSTRAP_READINESS_SCHEMA,
417
+ transactionId: record['transactionId'],
418
+ pid: record['pid'],
419
+ pidProcessStartIdentity,
420
+ supervisorPid: record['supervisorPid'],
421
+ supervisorProcessStartIdentity,
422
+ startedAt: record['startedAt'],
423
+ ipcUrl: record['ipcUrl'],
424
+ };
425
+ }
426
+ export function parseLifecycleBootstrapReadinessJson(raw) {
427
+ try {
428
+ return parseLifecycleBootstrapReadiness(JSON.parse(raw));
429
+ }
430
+ catch {
431
+ return undefined;
432
+ }
433
+ }
@@ -14,6 +14,8 @@
14
14
  * | `OPENCLAW_WORKSPACE` | *(manual)* | Partial V2 support does not preserve V1 workspace and bridge semantics |
15
15
  * | `EVOLVER_NO_PARENT_GIT` | *(none)* | V2 uses `EVOLVER_REPO_ROOT` or nearest Git root |
16
16
  * | `EVOLVER_VERBOSE` | *(none)* | V2 has no global switch; opt in to feature-specific diagnostics manually |
17
+ * | `EVOLVER_OPENAI_COMPATIBLE_BASE_URLS` | *(manual)* | Defensive compatibility spelling; canonical V1 used the EVOMAP-prefixed key |
18
+ * | `EVOMAP_OPENAI_COMPATIBLE_BASE_URLS` | *(manual)* | Canonical V1 compatible-origin allowlist; selected base and credential were separate |
17
19
  * | `EVOLVER_AUTO_ISSUE` | *(none)* | V2 creates local drafts; submit requires explicit approval-gated flow |
18
20
  * | `EVOLVER_ROLLBACK_MODE` | *(none)* | V2 uses worktree/snapshot/recovery policy |
19
21
  * | `WORKER_ENABLED` | *(none)* | No merchant-worker resolver in V2 |
@@ -98,6 +100,7 @@ export interface V1EnvTranslationReport {
98
100
  readonly manualCount: number;
99
101
  readonly removableCount: number;
100
102
  readonly githubTokenPresent: boolean;
103
+ readonly caveats?: readonly string[];
101
104
  }
102
105
  /**
103
106
  * Build an offline V1→V2 env translation report.
@@ -14,6 +14,8 @@
14
14
  * | `OPENCLAW_WORKSPACE` | *(manual)* | Partial V2 support does not preserve V1 workspace and bridge semantics |
15
15
  * | `EVOLVER_NO_PARENT_GIT` | *(none)* | V2 uses `EVOLVER_REPO_ROOT` or nearest Git root |
16
16
  * | `EVOLVER_VERBOSE` | *(none)* | V2 has no global switch; opt in to feature-specific diagnostics manually |
17
+ * | `EVOLVER_OPENAI_COMPATIBLE_BASE_URLS` | *(manual)* | Defensive compatibility spelling; canonical V1 used the EVOMAP-prefixed key |
18
+ * | `EVOMAP_OPENAI_COMPATIBLE_BASE_URLS` | *(manual)* | Canonical V1 compatible-origin allowlist; selected base and credential were separate |
17
19
  * | `EVOLVER_AUTO_ISSUE` | *(none)* | V2 creates local drafts; submit requires explicit approval-gated flow |
18
20
  * | `EVOLVER_ROLLBACK_MODE` | *(none)* | V2 uses worktree/snapshot/recovery policy |
19
21
  * | `WORKER_ENABLED` | *(none)* | No merchant-worker resolver in V2 |
@@ -56,6 +58,27 @@ export const V1_DEPRECATION_TABLE = [
56
58
  guidance: 'V2 has no global verbose switch. Remove this variable and opt in to a ' +
57
59
  'feature-specific flag such as EVOLVER_HOOK_VERBOSE=1 only when hook diagnostics are needed.',
58
60
  },
61
+ {
62
+ v1Name: 'EVOLVER_OPENAI_COMPATIBLE_BASE_URLS',
63
+ v2Equivalent: null,
64
+ migrationAction: 'manual',
65
+ guidance: 'This compatibility spelling was not resolved by the canonical V1 runtime, but it is tracked defensively. ' +
66
+ 'V2 has no multi-base or arbitrary OpenAI-compatible resolver. Review the workload before cutover. ' +
67
+ 'While either legacy list key remains set, configure the exact canonical pair EVOLVER_LLM_OPENAI_BASE_URL ' +
68
+ 'and EVOLVER_LLM_OPENAI_API_KEY for one official https://*.api.openai.com/v1 endpoint. ' +
69
+ 'LiteLLM, OpenRouter, Azure OpenAI, MiniMax, DeepSeek, Moonshot, and custom endpoints are not drop-in routes; ' +
70
+ 'do not copy their credentials into the V2 OpenAI route.',
71
+ },
72
+ {
73
+ v1Name: 'EVOMAP_OPENAI_COMPATIBLE_BASE_URLS',
74
+ v2Equivalent: null,
75
+ migrationAction: 'manual',
76
+ guidance: 'Canonical V1 treated this comma-separated value as an allowed-origin list; EVOMAP_OPENAI_BASE_URL still selected one ' +
77
+ 'endpoint and EVOMAP_OPENAI_API_KEY or OPENAI_API_KEY supplied its credential. V2 requires a workload-by-workload review ' +
78
+ 'and has no automatic mapping. While the legacy list remains set, only the exact canonical pair ' +
79
+ 'EVOLVER_LLM_OPENAI_BASE_URL and EVOLVER_LLM_OPENAI_API_KEY acknowledges migration; otherwise keep the incompatible ' +
80
+ 'workload outside the V2 OpenAI route.',
81
+ },
59
82
  {
60
83
  v1Name: 'EVOLVER_AUTO_ISSUE',
61
84
  v2Equivalent: null,
@@ -109,6 +132,23 @@ export const V1_DEPRECATION_TABLE = [
109
132
  guidance: 'V2 LocalMemoryGraph retains three archives by default and prunes older archives automatically. ' +
110
133
  'There is no environment override; remove this variable.',
111
134
  },
135
+ {
136
+ v1Name: 'EVOLVER_ATP',
137
+ v2Equivalent: null,
138
+ migrationAction: 'manual',
139
+ guidance: 'V1 auto/on/off controlled merchant/provider lifecycle, which has no one-to-one V2 resolver. '
140
+ + 'Review the missing merchant workflow before removing this key. Do not map it to `evolver atp enable` '
141
+ + 'or EVOLVER_ATP_AUTOBUY; those controls authorize autonomous buyer spending. If V1 off meant no '
142
+ + 'provider or delivery activity, set EVOLVER_ATP_AUTODELIVER=off explicitly as hardening, not as an equivalent mapping.',
143
+ },
144
+ {
145
+ v1Name: 'EVOLVER_SESSION_SOURCE',
146
+ v2Equivalent: null,
147
+ migrationAction: 'manual',
148
+ guidance: 'V1 auto/cursor/openclaw/merge selected session collectors, which has no one-to-one V2 resolver. '
149
+ + 'Review the workload before removing this key. Supported trajectory export requires explicit runtime '
150
+ + 'discovery or transcript-directory controls; setting another aggregate key does not restore OpenClaw collection.',
151
+ },
112
152
  ];
113
153
  /**
114
154
  * Scan the provided environment for deprecated V1 env vars and return
@@ -173,6 +213,10 @@ export function checkV1EnvCompat(env = typeof process !== 'undefined' ? process.
173
213
  }
174
214
  return result;
175
215
  }
216
+ const V1_IMPLICIT_DEFAULT_CAVEATS = [
217
+ 'V1 treated unset EVOLVER_ATP and EVOLVER_SESSION_SOURCE as auto. A clean key scan therefore does not prove '
218
+ + 'merchant/provider or session-collection workflow parity; audit both before cutover.',
219
+ ];
176
220
  /**
177
221
  * Build an offline V1→V2 env translation report.
178
222
  * Does not write files; callers decide how to present or apply suggestions.
@@ -224,6 +268,7 @@ export function translateV1Env(env = typeof process !== 'undefined' ? process.en
224
268
  manualCount: suggestions.filter((s) => s.action === 'manual').length,
225
269
  removableCount: suggestions.filter((s) => s.action === 'remove').length,
226
270
  githubTokenPresent,
271
+ caveats: V1_IMPLICIT_DEFAULT_CAVEATS,
227
272
  };
228
273
  }
229
274
  /** Human-readable report (never prints secret-looking values; only key names + actions). */
@@ -232,8 +277,10 @@ export function formatV1EnvTranslationReport(report) {
232
277
  'V1 → V2 env translation (offline, no writes):',
233
278
  ` detected_deprecated=${report.detectedCount} map=${report.mappableCount} manual=${report.manualCount} remove=${report.removableCount} github_token=${report.githubTokenPresent ? 'present' : 'absent'}`,
234
279
  ];
280
+ for (const caveat of report.caveats ?? [])
281
+ lines.push(` caveat: ${caveat}`);
235
282
  if (report.suggestions.length === 0) {
236
- lines.push(' (no V1-only knobs detected)');
283
+ lines.push(' (no explicit V1-only knobs detected)');
237
284
  return `${lines.join('\n')}\n`;
238
285
  }
239
286
  for (const s of report.suggestions) {
@@ -61,5 +61,7 @@ export declare function rootEventArchiveSegmentName(firstSeq: number, lastSeq: n
61
61
  export declare function planRootEventArchive(opts: RootEventArchiveOptions): RootEventArchivePlan;
62
62
  export declare function archiveRootEvents(opts: RootEventArchiveOptions): RootEventArchiveResult;
63
63
  export declare function readRootEventHistory(path: string, archiveDir?: string): RootEvent[];
64
+ /** Strict replay for control-plane decisions that must fail closed on partial or conflicting history. */
65
+ export declare function readRootEventHistoryStrict(path: string): RootEvent[];
64
66
  export declare function validateRootEventHistory(path: string): void;
65
67
  export declare function inspectRootEventArchive(path: string): RootEventArchiveStats;
@@ -131,6 +131,9 @@ export function archiveRootEvents(opts) {
131
131
  }
132
132
  }
133
133
  export function readRootEventHistory(path, archiveDir = rootEventArchiveDir(path)) {
134
+ // Snapshot active first. Writers publish archive segments before replacing active, so this prevents a reader
135
+ // from combining an old archive inventory with the new active tail and temporarily dropping the rotated prefix.
136
+ const active = readEventsLenient(path);
134
137
  const bySeq = new Map();
135
138
  for (const file of archiveSegmentFiles(archiveDir)) {
136
139
  for (const event of readEventsLenient(join(archiveDir, file))) {
@@ -143,13 +146,20 @@ export function readRootEventHistory(path, archiveDir = rootEventArchiveDir(path
143
146
  }
144
147
  // Preserve the pre-archive fail-soft behavior for routine commands. The active log is the current writer
145
148
  // source, so it deterministically wins an active/archive conflict without crashing status/report readers.
146
- for (const event of readEventsLenient(path))
149
+ for (const event of active)
147
150
  bySeq.set(event.seq, event);
148
151
  return [...bySeq.values()].sort((a, b) => a.seq - b.seq);
149
152
  }
150
- export function validateRootEventHistory(path) {
153
+ /** Strict replay for control-plane decisions that must fail closed on partial or conflicting history. */
154
+ export function readRootEventHistoryStrict(path) {
151
155
  const active = readActiveStrict(path);
152
- readValidatedArchive(path, active);
156
+ const bySeq = readValidatedArchive(path, active);
157
+ for (const line of active)
158
+ bySeq.set(line.event.seq, line.event);
159
+ return [...bySeq.values()].sort((left, right) => left.seq - right.seq);
160
+ }
161
+ export function validateRootEventHistory(path) {
162
+ void readRootEventHistoryStrict(path);
153
163
  }
154
164
  export function inspectRootEventArchive(path) {
155
165
  const archiveDir = rootEventArchiveDir(path);
@@ -81,6 +81,11 @@ export declare const rootEvent: z.ZodObject<{
81
81
  }>>;
82
82
  }, "strip", z.ZodTypeAny, {
83
83
  type: string;
84
+ actor: {
85
+ kind: "machine" | "human";
86
+ id?: string | undefined;
87
+ };
88
+ schemaVersion: string;
84
89
  ts: string;
85
90
  human: {
86
91
  severity: "warn" | "info" | "notice" | "error";
@@ -92,12 +97,7 @@ export declare const rootEvent: z.ZodObject<{
92
97
  };
93
98
  seq: number;
94
99
  eventId: string;
95
- schemaVersion: string;
96
100
  replayability: "deterministic" | "stochastic_recorded" | "stochastic_unreproducible";
97
- actor: {
98
- kind: "machine" | "human";
99
- id?: string | undefined;
100
- };
101
101
  payload?: unknown;
102
102
  }, {
103
103
  type: string;
@@ -113,12 +113,12 @@ export declare const rootEvent: z.ZodObject<{
113
113
  seq: number;
114
114
  eventId: string;
115
115
  payload?: unknown;
116
- schemaVersion?: string | undefined;
117
- replayability?: "deterministic" | "stochastic_recorded" | "stochastic_unreproducible" | undefined;
118
116
  actor?: {
119
117
  kind?: "machine" | "human" | undefined;
120
118
  id?: string | undefined;
121
119
  } | undefined;
120
+ schemaVersion?: string | undefined;
121
+ replayability?: "deterministic" | "stochastic_recorded" | "stochastic_unreproducible" | undefined;
122
122
  }>;
123
123
  export type RootEvent = z.infer<typeof rootEvent>;
124
124
  /** append 入参: seq/eventId/ts 由 store 生成. */
@@ -22,6 +22,8 @@ export declare class EventStore {
22
22
  private appendLocked;
23
23
  /** 读全部事件 (跳过尾部半行/损坏行). */
24
24
  readAll(): RootEvent[];
25
+ /** Fail-closed replay for decision policies that cannot safely consume a partial history. */
26
+ readAllStrict(): RootEvent[];
25
27
  iterate(fromSeq?: number): Generator<RootEvent>;
26
28
  tail(n?: number): RootEvent[];
27
29
  /** 截断尾部半行 (崩溃恢复). */
@@ -2,7 +2,7 @@ import { openSync, writeSync, fsyncSync, closeSync, statSync, readSync, mkdirSyn
2
2
  import { dirname } from 'node:path';
3
3
  import { monotonicFactory } from 'ulid';
4
4
  import { acquireLock, releaseLock } from '../util/fileLock.js';
5
- import { readRootEventHistory } from './eventArchive.js';
5
+ import { readRootEventHistory, readRootEventHistoryStrict } from './eventArchive.js';
6
6
  // Monotonic ULIDs: plain ulid() randomizes the low 80 bits, so two ids minted in the SAME millisecond can sort
7
7
  // out of order — the event log wants time-sortable eventIds (and a flaky CI test proved it). The monotonic
8
8
  // factory increments within a millisecond, guaranteeing each successive eventId is strictly greater.
@@ -76,6 +76,10 @@ export class EventStore {
76
76
  readAll() {
77
77
  return readRootEventHistory(this.path);
78
78
  }
79
+ /** Fail-closed replay for decision policies that cannot safely consume a partial history. */
80
+ readAllStrict() {
81
+ return readRootEventHistoryStrict(this.path);
82
+ }
79
83
  *iterate(fromSeq = 0) {
80
84
  for (const e of this.readAll())
81
85
  if (e.seq >= fromSeq)