wendkeep 0.58.3 → 0.60.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 +93 -0
- package/README.en.md +45 -3
- package/README.md +45 -3
- package/bin/wendkeep.mjs +54 -6
- package/docs/en/commands/changes-and-verification.md +9 -3
- package/docs/en/commands/getting-started.md +7 -3
- package/docs/en/commands/memory.md +20 -2
- package/docs/en/commands/operating-profiles.md +173 -0
- package/docs/en/commands/sessions-and-import.md +8 -4
- package/docs/en/commands/verify.md +12 -6
- package/docs/pt-BR/commands/changes-and-verification.md +9 -4
- package/docs/pt-BR/commands/getting-started.md +7 -3
- package/docs/pt-BR/commands/memory.md +18 -2
- package/docs/pt-BR/commands/operating-profiles.md +171 -0
- package/docs/pt-BR/commands/sessions-and-import.md +7 -3
- package/docs/pt-BR/commands/verify.md +11 -5
- package/hooks/brain-core.mjs +159 -159
- package/hooks/brain-inject.mjs +83 -26
- package/hooks/brain-recall.mjs +32 -32
- package/hooks/brain-reindex.mjs +13 -13
- package/hooks/change-context.mjs +24 -10
- package/hooks/change-core.mjs +174 -37
- package/hooks/change-guard.mjs +115 -16
- package/hooks/change-nag.mjs +20 -5
- package/hooks/change-warn.mjs +27 -9
- package/hooks/decision-capture.mjs +1 -1
- package/hooks/derived-sections.mjs +1 -1
- package/hooks/flow-core.mjs +891 -0
- package/hooks/flow-protected-policy.mjs +218 -0
- package/hooks/frontmatter-repair.mjs +3 -1
- package/hooks/git-snapshot.mjs +722 -0
- package/hooks/import-sessions.mjs +10 -5
- package/hooks/memory-mode.mjs +63 -13
- package/hooks/memory-store.mjs +309 -69
- package/hooks/obsidian-common.mjs +39 -55
- package/hooks/operating-profile-runtime.mjs +157 -0
- package/hooks/plan-capture.mjs +14 -3
- package/hooks/sensors-core.mjs +15 -3
- package/hooks/session-backfill.mjs +7 -2
- package/hooks/session-ensure.mjs +6 -4
- package/hooks/session-iteration.mjs +65 -0
- package/hooks/session-memory-lifecycle.mjs +10 -5
- package/hooks/session-note-io.mjs +130 -15
- package/hooks/session-observability.mjs +4 -2
- package/hooks/session-stop.mjs +65 -19
- package/hooks/spec-core.mjs +91 -12
- package/hooks/subagent-stop.mjs +4 -1
- package/hooks/subagent-usage.mjs +2 -2
- package/hooks/task-log.mjs +3 -1
- package/hooks/token-usage.mjs +1 -1
- package/hooks/vault-health.mjs +183 -37
- package/hooks/vault-path-safety.mjs +2 -0
- package/hooks/vault-runtime-store.mjs +558 -0
- package/package.json +10 -3
- package/packages/cli/package.json +5 -0
- package/packages/harness/package.json +5 -0
- package/packages/integrations/package.json +5 -0
- package/packages/mcp/package.json +5 -0
- package/packages/pi/package.json +5 -0
- package/packages/vault/package.json +6 -0
- package/packages/vault/src/index.mjs +2 -0
- package/packages/vault/src/project-vault.mjs +327 -0
- package/packages/vault/src/vault-path-safety.mjs +558 -0
- package/src/change.mjs +2 -1
- package/src/flow.mjs +232 -0
- package/src/init.mjs +26 -3
- package/src/memory.mjs +785 -35
- package/src/operating-profile.mjs +133 -0
- package/src/profile.mjs +224 -0
- package/src/project-vault.mjs +2 -221
- package/src/rebuild-costs.mjs +11 -4
- package/src/skills-seed.mjs +38 -16
- package/src/sync-defs.mjs +16 -7
- package/src/sync.mjs +9 -1
- package/src/taxonomy.mjs +8 -0
- package/src/validate-memory.mjs +21 -8
- package/src/verify.mjs +12 -2
package/hooks/vault-health.mjs
CHANGED
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
import { getLocale } from './locale.mjs';
|
|
14
14
|
import { parseSharedMemory, validateMemoryEvent } from './memory-schema.mjs';
|
|
15
15
|
import { detectMemoryMode, LEGACY_MEMORY_WARNING } from './memory-mode.mjs';
|
|
16
|
-
import {
|
|
16
|
+
import { deriveMemoryProjection } from './memory-store.mjs';
|
|
17
|
+
import { assertVaultPathSafe, assertVaultPathsSafe } from './vault-path-safety.mjs';
|
|
17
18
|
import { validateMemoryBundle } from '../src/validate-memory.mjs';
|
|
18
19
|
|
|
19
20
|
const DEFAULT_PENDING_PATTERNS = [
|
|
@@ -100,10 +101,21 @@ function linkedNotesFromSession(content) {
|
|
|
100
101
|
const MEMORY_STATUS_COMMAND = 'wendkeep memory status --gate --vault <vault>';
|
|
101
102
|
const MEMORY_REPAIR_COMMAND = 'wendkeep memory repair --vault <vault>';
|
|
102
103
|
|
|
103
|
-
function readJsonLines(path, label) {
|
|
104
|
-
|
|
104
|
+
function readJsonLines(vaultBase, path, label) {
|
|
105
|
+
let checked;
|
|
106
|
+
try {
|
|
107
|
+
checked = assertVaultPathSafe(vaultBase, path, { expectedType: 'file', label });
|
|
108
|
+
} catch (error) {
|
|
109
|
+
return { items: [], errors: [`${label} inseguro: ${error?.message || error}`] };
|
|
110
|
+
}
|
|
111
|
+
if (!checked.exists) return { items: [], errors: [] };
|
|
105
112
|
let raw;
|
|
106
|
-
try {
|
|
113
|
+
try {
|
|
114
|
+
checked = assertVaultPathSafe(vaultBase, checked.target, {
|
|
115
|
+
allowMissing: false, expectedType: 'file', label,
|
|
116
|
+
});
|
|
117
|
+
raw = readFileSync(checked.target, 'utf8').replace(/\r\n/g, '\n');
|
|
118
|
+
}
|
|
107
119
|
catch (error) { return { items: [], errors: [`${label} ilegível: ${error?.message || error}`] }; }
|
|
108
120
|
const lines = raw.endsWith('\n') ? raw.split('\n').slice(0, -1) : raw.split('\n');
|
|
109
121
|
const items = [];
|
|
@@ -121,25 +133,107 @@ function readJsonLines(path, label) {
|
|
|
121
133
|
|
|
122
134
|
function inspectOutbox(vaultBase, projectId) {
|
|
123
135
|
const dir = join(vaultBase, '.brain', 'memory-outbox');
|
|
124
|
-
|
|
125
|
-
|
|
136
|
+
let checked;
|
|
137
|
+
try {
|
|
138
|
+
checked = assertVaultPathSafe(vaultBase, dir, {
|
|
139
|
+
expectedType: 'directory', label: 'outbox de memória',
|
|
140
|
+
});
|
|
141
|
+
} catch (error) {
|
|
142
|
+
return {
|
|
143
|
+
count: 0,
|
|
144
|
+
errors: [`outbox insegura: ${error?.message || error}`],
|
|
145
|
+
eventIds: new Set(),
|
|
146
|
+
eventsById: new Map(),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (!checked.exists) return {
|
|
150
|
+
count: 0, errors: [], eventIds: new Set(), eventsById: new Map(),
|
|
151
|
+
};
|
|
152
|
+
try {
|
|
153
|
+
checked = assertVaultPathSafe(vaultBase, checked.target, {
|
|
154
|
+
allowMissing: false, expectedType: 'directory', label: 'outbox de memória',
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
count: 0,
|
|
159
|
+
errors: [`outbox insegura: ${error?.message || error}`],
|
|
160
|
+
eventIds: new Set(),
|
|
161
|
+
eventsById: new Map(),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const files = readdirSync(checked.target).filter((name) => name.endsWith('.json')).sort();
|
|
126
165
|
const errors = [];
|
|
127
166
|
const eventIds = new Set();
|
|
167
|
+
const eventsById = new Map();
|
|
128
168
|
for (const name of files) {
|
|
129
|
-
const path = join(
|
|
169
|
+
const path = join(checked.target, name);
|
|
130
170
|
try {
|
|
131
|
-
const
|
|
171
|
+
const file = assertVaultPathSafe(vaultBase, path, {
|
|
172
|
+
allowMissing: false, expectedType: 'file', label: `evento ${name} da outbox`,
|
|
173
|
+
});
|
|
174
|
+
const event = JSON.parse(readFileSync(file.target, 'utf8'));
|
|
132
175
|
const validation = validateMemoryEvent(event, projectId ? { projectId } : {});
|
|
133
176
|
if (!validation.ok) errors.push(`${name}: ${validation.errors.join(' ')}`);
|
|
134
|
-
else
|
|
177
|
+
else {
|
|
178
|
+
eventIds.add(event.event_id);
|
|
179
|
+
eventsById.set(event.event_id, event);
|
|
180
|
+
}
|
|
135
181
|
} catch (error) {
|
|
136
182
|
errors.push(`${name}: JSON inválido: ${error.message}`);
|
|
137
183
|
}
|
|
138
184
|
}
|
|
139
|
-
return {
|
|
185
|
+
return {
|
|
186
|
+
count: files.length, errors, eventIds, eventsById,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function memoryMetrics() {
|
|
191
|
+
return {
|
|
192
|
+
schemaVersion: null,
|
|
193
|
+
revision: null,
|
|
194
|
+
eventCursor: null,
|
|
195
|
+
stateHash: null,
|
|
196
|
+
ledgerEvents: 0,
|
|
197
|
+
pendingOutbox: 0,
|
|
198
|
+
candidates: 0,
|
|
199
|
+
activeConflicts: 0,
|
|
200
|
+
};
|
|
140
201
|
}
|
|
141
202
|
|
|
142
|
-
function
|
|
203
|
+
function blockedMemoryBoundary(error) {
|
|
204
|
+
return {
|
|
205
|
+
ok: false,
|
|
206
|
+
status: 'blocked',
|
|
207
|
+
failures: [`Boundary física da memória insegura: ${error?.message || error}`],
|
|
208
|
+
warnings: [],
|
|
209
|
+
metrics: memoryMetrics(),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function preflightMemoryBundle(vaultBase) {
|
|
214
|
+
const brain = join(vaultBase, '.brain');
|
|
215
|
+
assertVaultPathSafe(vaultBase, brain, {
|
|
216
|
+
expectedType: 'directory', label: 'raiz .brain da memória',
|
|
217
|
+
});
|
|
218
|
+
assertVaultPathsSafe(vaultBase, [
|
|
219
|
+
'PROJECT.json', 'CORE.md', 'MEMORY_EVENTS.jsonl', 'SHARED_MEMORY.md',
|
|
220
|
+
'MEMORY_CANDIDATES.jsonl',
|
|
221
|
+
].map((name) => ({
|
|
222
|
+
path: join(brain, name), expectedType: 'file', label: `${name} ilegível ou inseguro`,
|
|
223
|
+
})));
|
|
224
|
+
const outbox = assertVaultPathSafe(vaultBase, join(brain, 'memory-outbox'), {
|
|
225
|
+
expectedType: 'directory', label: 'outbox de memória',
|
|
226
|
+
});
|
|
227
|
+
if (!outbox.exists) return;
|
|
228
|
+
const entries = readdirSync(outbox.target);
|
|
229
|
+
for (const name of entries) {
|
|
230
|
+
assertVaultPathSafe(vaultBase, join(outbox.target, name), {
|
|
231
|
+
allowMissing: false, label: `entrada ${name} da outbox de memória`,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function checkpointMatchesLedgerPrefix(checkpoint, eventIds, ledgerEvents, vaultBase) {
|
|
143
237
|
if (!checkpoint || typeof checkpoint !== 'object') return false;
|
|
144
238
|
if (!Number.isInteger(checkpoint.revision) || checkpoint.revision < 0) return false;
|
|
145
239
|
if (typeof checkpoint.event_cursor !== 'string' || !checkpoint.event_cursor) return false;
|
|
@@ -152,24 +246,32 @@ function checkpointMatchesLedgerPrefix(checkpoint, eventIds, ledgerEvents) {
|
|
|
152
246
|
if (eventIds.some((eventId) => !prefixIds.has(eventId))) return false;
|
|
153
247
|
|
|
154
248
|
try {
|
|
155
|
-
const replay =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
249
|
+
const replay = deriveMemoryProjection(vaultBase, prefix);
|
|
250
|
+
const causalMatches = checkpoint.causal_event_cursor === undefined
|
|
251
|
+
|| checkpoint.causal_event_cursor === replay.eventCursor;
|
|
252
|
+
return checkpoint.revision === replay.checkpoint.revision
|
|
253
|
+
&& checkpoint.event_cursor === replay.checkpoint.event_cursor
|
|
254
|
+
&& checkpoint.state_hash === replay.checkpoint.state_hash
|
|
255
|
+
&& causalMatches;
|
|
159
256
|
} catch {
|
|
160
257
|
return false;
|
|
161
258
|
}
|
|
162
259
|
}
|
|
163
260
|
|
|
164
|
-
function checkMemoryAttempts(registry, {
|
|
261
|
+
function checkMemoryAttempts(registry, {
|
|
262
|
+
vaultBase, ledgerEvents = [], outboxEventIds = new Set(), outboxEventsById = new Map(),
|
|
263
|
+
} = {}) {
|
|
165
264
|
const failures = [];
|
|
166
265
|
const warnings = [];
|
|
167
266
|
const ledgerEventIds = new Set(ledgerEvents.map((event) => event?.event_id).filter(Boolean));
|
|
168
|
-
const
|
|
169
|
-
.
|
|
170
|
-
.
|
|
171
|
-
|
|
172
|
-
|
|
267
|
+
const ledgerById = new Map(ledgerEvents
|
|
268
|
+
.filter((event) => event?.event_id)
|
|
269
|
+
.map((event) => [event.event_id, event]));
|
|
270
|
+
const attempts = Object.entries(registry?.sessions || {})
|
|
271
|
+
.map(([sessionId, entry]) => [sessionId, entry?.last_memory_attempt])
|
|
272
|
+
.filter(([, attempt]) => attempt && typeof attempt === 'object' && attempt.memory_mode === 'v2');
|
|
273
|
+
|
|
274
|
+
for (const [sessionId, attempt] of attempts) {
|
|
173
275
|
const state = String(attempt.state || '');
|
|
174
276
|
const disposition = String(attempt.disposition || '');
|
|
175
277
|
const eventIds = Array.isArray(attempt.event_ids)
|
|
@@ -201,6 +303,37 @@ function checkMemoryAttempts(registry, { ledgerEvents = [], outboxEventIds = new
|
|
|
201
303
|
continue;
|
|
202
304
|
}
|
|
203
305
|
|
|
306
|
+
const identity = {
|
|
307
|
+
canonical_session_id: sessionId,
|
|
308
|
+
activation_id: attempt.activation_id,
|
|
309
|
+
activation_epoch: attempt.activation_epoch,
|
|
310
|
+
source_turn_id: attempt.turn_id,
|
|
311
|
+
turn_sequence: attempt.turn_sequence,
|
|
312
|
+
};
|
|
313
|
+
const invalidAttemptFields = [];
|
|
314
|
+
if (attempt.canonical_session_id !== sessionId) invalidAttemptFields.push('canonical_session_id');
|
|
315
|
+
if (typeof attempt.activation_id !== 'string' || !attempt.activation_id) invalidAttemptFields.push('activation_id');
|
|
316
|
+
if (!Number.isInteger(attempt.activation_epoch) || attempt.activation_epoch < 0) invalidAttemptFields.push('activation_epoch');
|
|
317
|
+
if (typeof attempt.turn_id !== 'string' || !attempt.turn_id) invalidAttemptFields.push('turn_id');
|
|
318
|
+
if (!Number.isInteger(attempt.turn_sequence) || attempt.turn_sequence < 0) invalidAttemptFields.push('turn_sequence');
|
|
319
|
+
if (invalidAttemptFields.length) {
|
|
320
|
+
failures.push(`Attempt v2 da sessão ${sessionId} possui identidade causal inválida (${invalidAttemptFields.join(', ')}). Inspecione com: ${MEMORY_STATUS_COMMAND}.`);
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const causalMismatches = [];
|
|
324
|
+
for (const eventId of eventIds) {
|
|
325
|
+
const event = ledgerById.get(eventId) || outboxEventsById.get(eventId);
|
|
326
|
+
if (!event) continue;
|
|
327
|
+
const fields = Object.entries(identity)
|
|
328
|
+
.filter(([field, expected]) => event[field] !== expected)
|
|
329
|
+
.map(([field]) => field);
|
|
330
|
+
if (fields.length) causalMismatches.push(`${eventId}: ${fields.join(', ')}`);
|
|
331
|
+
}
|
|
332
|
+
if (causalMismatches.length) {
|
|
333
|
+
failures.push(`Attempt v2 da sessão ${sessionId} referencia evento(s) com identidade causal divergente (${causalMismatches.join('; ')}). Inspecione com: ${MEMORY_STATUS_COMMAND}.`);
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
|
|
204
337
|
if (state === 'enqueued' || state === 'degraded') {
|
|
205
338
|
const missing = eventIds.filter((eventId) => !ledgerEventIds.has(eventId) && !outboxEventIds.has(eventId));
|
|
206
339
|
if (missing.length) {
|
|
@@ -215,7 +348,7 @@ function checkMemoryAttempts(registry, { ledgerEvents = [], outboxEventIds = new
|
|
|
215
348
|
const outsideLedger = eventIds.filter((eventId) => !ledgerEventIds.has(eventId));
|
|
216
349
|
if (outsideLedger.length) {
|
|
217
350
|
failures.push(`Attempt projetado perdeu ${outsideLedger.length} evento(s) no ledger. Inspecione com: ${MEMORY_STATUS_COMMAND}.`);
|
|
218
|
-
} else if (!checkpointMatchesLedgerPrefix(attempt.checkpoint, eventIds, ledgerEvents)) {
|
|
351
|
+
} else if (!checkpointMatchesLedgerPrefix(attempt.checkpoint, eventIds, ledgerEvents, vaultBase)) {
|
|
219
352
|
failures.push(`Checkpoint do attempt projetado diverge do prefixo rederivado do ledger. Inspecione com: ${MEMORY_STATUS_COMMAND}.`);
|
|
220
353
|
}
|
|
221
354
|
continue;
|
|
@@ -232,24 +365,28 @@ function checkMemoryAttempts(registry, { ledgerEvents = [], outboxEventIds = new
|
|
|
232
365
|
* does not acquire MEMORY.lock or invoke the projector/repair paths.
|
|
233
366
|
*/
|
|
234
367
|
export function checkMemoryBundle(vaultBase, { registry } = {}) {
|
|
368
|
+
if (!existsSync(vaultBase)) {
|
|
369
|
+
return {
|
|
370
|
+
ok: false,
|
|
371
|
+
status: 'blocked',
|
|
372
|
+
failures: [`Vault not found: ${vaultBase}`],
|
|
373
|
+
warnings: [],
|
|
374
|
+
metrics: memoryMetrics(),
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
try { preflightMemoryBundle(vaultBase); }
|
|
378
|
+
catch (error) { return blockedMemoryBoundary(error); }
|
|
235
379
|
const brain = join(vaultBase, '.brain');
|
|
236
|
-
|
|
380
|
+
let mode;
|
|
381
|
+
try { mode = detectMemoryMode(vaultBase); }
|
|
382
|
+
catch (error) { return blockedMemoryBoundary(error); }
|
|
237
383
|
if (mode.mode === 'legacy') {
|
|
238
384
|
return {
|
|
239
385
|
ok: true,
|
|
240
386
|
status: 'legacy',
|
|
241
387
|
failures: [],
|
|
242
388
|
warnings: [LEGACY_MEMORY_WARNING],
|
|
243
|
-
metrics:
|
|
244
|
-
schemaVersion: null,
|
|
245
|
-
revision: null,
|
|
246
|
-
eventCursor: null,
|
|
247
|
-
stateHash: null,
|
|
248
|
-
ledgerEvents: 0,
|
|
249
|
-
pendingOutbox: 0,
|
|
250
|
-
candidates: 0,
|
|
251
|
-
activeConflicts: 0,
|
|
252
|
-
},
|
|
389
|
+
metrics: memoryMetrics(),
|
|
253
390
|
};
|
|
254
391
|
}
|
|
255
392
|
const bundle = validateMemoryBundle(vaultBase);
|
|
@@ -260,7 +397,9 @@ export function checkMemoryBundle(vaultBase, { registry } = {}) {
|
|
|
260
397
|
: { metadata: {} };
|
|
261
398
|
const metadata = parsedShared.metadata || {};
|
|
262
399
|
const outbox = inspectOutbox(vaultBase, bundle.project?.projectId);
|
|
263
|
-
const candidates = readJsonLines(
|
|
400
|
+
const candidates = readJsonLines(
|
|
401
|
+
vaultBase, join(brain, 'MEMORY_CANDIDATES.jsonl'), 'MEMORY_CANDIDATES.jsonl',
|
|
402
|
+
);
|
|
264
403
|
|
|
265
404
|
const ledgerCorrupt = (bundle.ledger?.errors || []).length > 0;
|
|
266
405
|
if (ledgerCorrupt) {
|
|
@@ -282,7 +421,7 @@ export function checkMemoryBundle(vaultBase, { registry } = {}) {
|
|
|
282
421
|
|
|
283
422
|
let replay = null;
|
|
284
423
|
if (bundle.ledger?.ok) {
|
|
285
|
-
try { replay =
|
|
424
|
+
try { replay = deriveMemoryProjection(vaultBase, bundle.ledger.events); }
|
|
286
425
|
catch (error) {
|
|
287
426
|
failures.push(`Ledger não pode ser reduzido: ${error.message}. Execute com segurança: ${MEMORY_REPAIR_COMMAND}.`);
|
|
288
427
|
}
|
|
@@ -290,16 +429,23 @@ export function checkMemoryBundle(vaultBase, { registry } = {}) {
|
|
|
290
429
|
if (replay && bundle.shared?.ok) {
|
|
291
430
|
const divergences = [];
|
|
292
431
|
if (metadata.revision !== replay.revision) divergences.push(`revision ${metadata.revision} != ${replay.revision}`);
|
|
293
|
-
if (metadata.event_cursor !== replay.
|
|
432
|
+
if (metadata.event_cursor !== replay.ledgerCursor) divergences.push(`event_cursor ${metadata.event_cursor} != ${replay.ledgerCursor}`);
|
|
294
433
|
if (metadata.state_hash !== replay.stateHash) divergences.push(`state_hash ${metadata.state_hash} != ${replay.stateHash}`);
|
|
295
434
|
if (divergences.length) {
|
|
296
435
|
failures.push(`Projeção SHARED stale/lag (${divergences.join('; ')}). Inspecione com: ${MEMORY_STATUS_COMMAND}.`);
|
|
297
436
|
}
|
|
298
437
|
}
|
|
299
438
|
|
|
300
|
-
|
|
439
|
+
let effectiveRegistry = registry;
|
|
440
|
+
if (!effectiveRegistry) {
|
|
441
|
+
try { effectiveRegistry = readSessionRegistry(vaultBase); }
|
|
442
|
+
catch (error) { failures.push(`SESSION_REGISTRY.json inseguro ou ilegível: ${error?.message || error}.`); }
|
|
443
|
+
}
|
|
444
|
+
const lifecycle = checkMemoryAttempts(effectiveRegistry || { version: 2, sessions: {} }, {
|
|
445
|
+
vaultBase,
|
|
301
446
|
ledgerEvents: bundle.ledger?.events || [],
|
|
302
447
|
outboxEventIds: outbox.eventIds,
|
|
448
|
+
outboxEventsById: outbox.eventsById,
|
|
303
449
|
});
|
|
304
450
|
failures.push(...lifecycle.failures);
|
|
305
451
|
warnings.push(...lifecycle.warnings);
|