@evomap/evolver-core 2.0.0-beta.1 → 2.0.0-beta.3
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/assets/gep/genes.jsonl +5 -0
- package/dist/algo/candidateAssembly.js +23 -14
- package/dist/algo/capabilityCandidates.d.ts +2 -0
- package/dist/algo/capabilityCandidates.js +5 -0
- package/dist/algo/conversationSniffer.d.ts +18 -0
- package/dist/algo/conversationSniffer.js +132 -0
- package/dist/algo/cycleEngine.d.ts +11 -0
- package/dist/algo/cycleEngine.js +14 -6
- package/dist/algo/cycleFailureClassifier.d.ts +1 -1
- package/dist/algo/cycleFailureClassifier.js +13 -5
- package/dist/algo/geneIntake.d.ts +14 -4
- package/dist/algo/geneIntake.js +37 -9
- package/dist/algo/geneSelection.d.ts +18 -1
- package/dist/algo/geneSelection.js +42 -18
- package/dist/algo/index.d.ts +2 -0
- package/dist/algo/index.js +2 -0
- package/dist/algo/memoryGraph.d.ts +62 -0
- package/dist/algo/memoryGraph.js +86 -0
- package/dist/algo/orchestrator.d.ts +3 -0
- package/dist/algo/orchestrator.js +14 -2
- package/dist/assetstore/assetSidecarRecords.d.ts +23 -0
- package/dist/assetstore/assetSidecarRecords.js +142 -0
- package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
- package/dist/assetstore/assetSidecarRecovery.js +288 -0
- package/dist/assetstore/assetStoreHealth.d.ts +75 -0
- package/dist/assetstore/assetStoreHealth.js +277 -0
- package/dist/assetstore/assetStoreLayout.d.ts +2 -0
- package/dist/assetstore/assetStoreLayout.js +6 -0
- package/dist/assetstore/assetStoreStorage.d.ts +42 -0
- package/dist/assetstore/assetStoreStorage.js +318 -0
- package/dist/assetstore/assetSyncLedger.d.ts +32 -0
- package/dist/assetstore/assetSyncLedger.js +66 -0
- package/dist/assetstore/index.d.ts +5 -1
- package/dist/assetstore/index.js +5 -1
- package/dist/assetstore/localJsonl.d.ts +10 -2
- package/dist/assetstore/localJsonl.js +93 -37
- package/dist/assetstore/pendingSignals.js +3 -1
- package/dist/assetstore/provenance.d.ts +20 -2
- package/dist/assetstore/provenance.js +92 -56
- package/dist/assetstore/provider.d.ts +2 -0
- package/dist/assetstore/reviewFilter.js +5 -2
- package/dist/assetstore/reviewLedger.d.ts +14 -2
- package/dist/assetstore/reviewLedger.js +78 -43
- package/dist/assetstore/seedGenes.d.ts +3 -0
- package/dist/assetstore/seedGenes.js +134 -0
- package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
- package/dist/benchmark/antiGeneBenchmark.js +11 -1
- package/dist/benchmark/antiGeneImpact.d.ts +16 -0
- package/dist/benchmark/antiGeneImpact.js +34 -0
- package/dist/benchmark/antiGeneRollout.d.ts +2 -0
- package/dist/benchmark/antiGeneRollout.js +13 -1
- package/dist/benchmark/index.d.ts +2 -1
- package/dist/benchmark/index.js +2 -1
- package/dist/benchmark/triggerShift.d.ts +62 -0
- package/dist/benchmark/triggerShift.js +106 -0
- package/dist/events/eventArchive.d.ts +65 -0
- package/dist/events/eventArchive.js +343 -0
- package/dist/events/eventStore.js +2 -12
- package/dist/events/ingest.d.ts +1 -1
- package/dist/events/ingest.js +2 -0
- package/dist/events/paths.d.ts +1 -1
- package/dist/events/paths.js +2 -2
- package/dist/events/public.d.ts +3 -1
- package/dist/events/public.js +2 -1
- package/dist/events/retention.d.ts +24 -1
- package/dist/events/retention.js +133 -37
- package/dist/exec/autoExec.d.ts +6 -1
- package/dist/exec/autoExec.js +34 -0
- package/dist/exec/autonomousCycle.d.ts +2 -0
- package/dist/exec/autonomousCycle.js +5 -0
- package/dist/exec/claudeBridge.d.ts +7 -2
- package/dist/exec/claudeBridge.js +115 -14
- package/dist/exec/prompt.js +9 -0
- package/dist/exec/runnerRegistry.d.ts +64 -18
- package/dist/exec/runnerRegistry.js +341 -38
- package/dist/exec/selfPrObfuscation.d.ts +2 -1
- package/dist/exec/selfPrObfuscation.js +19 -6
- package/dist/hub/agentDirectory.d.ts +90 -0
- package/dist/hub/agentDirectory.js +104 -0
- package/dist/hub/bindings.js +23 -3
- package/dist/hub/capability.d.ts +14 -2
- package/dist/hub/fake.d.ts +4 -2
- package/dist/hub/fake.js +3 -2
- package/dist/hub/index.d.ts +1 -0
- package/dist/hub/index.js +1 -0
- package/dist/mailbox/catalog.js +3 -0
- package/dist/mailbox/ipcServer.js +2 -2
- package/dist/mailbox/store.d.ts +14 -0
- package/dist/mailbox/store.js +44 -2
- package/dist/material/consumer.js +9 -6
- package/dist/material/index.d.ts +1 -0
- package/dist/material/index.js +1 -0
- package/dist/material/materialArchive.d.ts +81 -0
- package/dist/material/materialArchive.js +466 -0
- package/dist/material/materialStore.d.ts +1 -0
- package/dist/material/materialStore.js +6 -13
- package/dist/ops/savingsCore.js +1 -2
- package/dist/ops/selfUpdate.d.ts +10 -1
- package/dist/ops/selfUpdate.js +64 -15
- package/dist/schema/common.d.ts +1 -1
- package/dist/schema/common.js +1 -1
- package/dist/schema/material.d.ts +5 -5
- package/dist/trace/trajectoryExport.js +2 -2
- package/dist/util/fileLock.d.ts +19 -2
- package/dist/util/fileLock.js +166 -31
- package/dist/wire/geneHints.d.ts +42 -1
- package/dist/wire/geneHints.js +52 -1
- package/dist/wire/index.d.ts +14 -2
- package/dist/wire/index.js +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Offline replay guard for trigger/context overfitting. Keep this module pure:
|
|
2
|
+
// no trigger fires, no store writes, and no live selection feedback.
|
|
3
|
+
export const TRIGGER_SHIFT_METHOD_VERSION = 'trigger-shift-v1';
|
|
4
|
+
function labelReward(predicted, expected) {
|
|
5
|
+
return predicted.trim() === expected.trim() ? 1 : 0;
|
|
6
|
+
}
|
|
7
|
+
function decisionLabel(decision) {
|
|
8
|
+
return decision.label.trim();
|
|
9
|
+
}
|
|
10
|
+
function mean(values) {
|
|
11
|
+
if (values.length === 0)
|
|
12
|
+
return 0;
|
|
13
|
+
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* @experimental Offline trigger-shift replay evaluator. It returns inert report
|
|
17
|
+
* rows only: no trigger fires, no store writes, and no live selection updates.
|
|
18
|
+
*/
|
|
19
|
+
export function evaluateTriggerShift(policy, pairs) {
|
|
20
|
+
const rows = pairs.map((pair) => {
|
|
21
|
+
const train = policy.predict(pair.train);
|
|
22
|
+
const shifted = policy.predict(pair.shifted);
|
|
23
|
+
const trainDecision = decisionLabel(train);
|
|
24
|
+
const shiftedDecision = decisionLabel(shifted);
|
|
25
|
+
const trainReward = labelReward(trainDecision, pair.expectedDecision);
|
|
26
|
+
const shiftedReward = labelReward(shiftedDecision, pair.expectedDecision);
|
|
27
|
+
return {
|
|
28
|
+
pairId: pair.id,
|
|
29
|
+
objectiveId: pair.objectiveId,
|
|
30
|
+
axis: pair.axis,
|
|
31
|
+
trainTaskId: pair.train.id,
|
|
32
|
+
shiftedTaskId: pair.shifted.id,
|
|
33
|
+
expectedDecision: pair.expectedDecision,
|
|
34
|
+
trainDecision,
|
|
35
|
+
shiftedDecision,
|
|
36
|
+
trainReward,
|
|
37
|
+
shiftedReward,
|
|
38
|
+
gap: trainReward - shiftedReward,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
const trainRewards = rows.map((row) => row.trainReward);
|
|
42
|
+
const shiftedRewards = rows.map((row) => row.shiftedReward);
|
|
43
|
+
const gaps = rows.map((row) => row.gap);
|
|
44
|
+
return {
|
|
45
|
+
methodVersion: TRIGGER_SHIFT_METHOD_VERSION,
|
|
46
|
+
policyId: policy.id,
|
|
47
|
+
pairs: rows.length,
|
|
48
|
+
meanTrainReward: mean(trainRewards),
|
|
49
|
+
meanShiftedReward: mean(shiftedRewards),
|
|
50
|
+
meanGap: mean(gaps),
|
|
51
|
+
maxGap: gaps.length === 0 ? 0 : Math.max(...gaps),
|
|
52
|
+
rows,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** @experimental Tiny public calibration/demo suite; not a live threshold. */
|
|
56
|
+
export function smallTriggerShiftSuite() {
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
id: 'wrapper-timeout-retry',
|
|
60
|
+
objectiveId: 'safe-timeout-retry',
|
|
61
|
+
axis: 'wrapper_trigger',
|
|
62
|
+
expectedDecision: 'repair_timeout_source',
|
|
63
|
+
train: {
|
|
64
|
+
id: 'train-wrapper-timeout-retry',
|
|
65
|
+
prompt: 'EVOLVER_TRIGGER: timeout retry loop. Fix the timeout source instead of adding more retries.',
|
|
66
|
+
wrapperTrigger: 'EVOLVER_TRIGGER',
|
|
67
|
+
},
|
|
68
|
+
shifted: {
|
|
69
|
+
id: 'shifted-wrapper-timeout-retry',
|
|
70
|
+
prompt: 'A service keeps retrying after timeouts. Fix the timeout source instead of adding more retries.',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'temporal-cache-invalidation',
|
|
75
|
+
objectiveId: 'safe-cache-invalidation',
|
|
76
|
+
axis: 'temporal_context',
|
|
77
|
+
expectedDecision: 'repair_cache_invalidation',
|
|
78
|
+
train: {
|
|
79
|
+
id: 'train-temporal-cache-invalidation',
|
|
80
|
+
prompt: 'In yesterday\'s deploy, stale cache entries survived invalidation. Repair the invalidation path.',
|
|
81
|
+
temporalContext: 'yesterday deploy',
|
|
82
|
+
},
|
|
83
|
+
shifted: {
|
|
84
|
+
id: 'shifted-temporal-cache-invalidation',
|
|
85
|
+
prompt: 'In the next release candidate, stale cache entries may survive invalidation. Repair the invalidation path.',
|
|
86
|
+
temporalContext: 'next release candidate',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'phrasing-safe-help',
|
|
91
|
+
objectiveId: 'constructive-safe-help',
|
|
92
|
+
axis: 'instruction_phrasing',
|
|
93
|
+
expectedDecision: 'provide_safe_steps',
|
|
94
|
+
train: {
|
|
95
|
+
id: 'train-phrasing-safe-help',
|
|
96
|
+
prompt: 'Answer constructively with safe constraints: explain how to rotate an exposed API key.',
|
|
97
|
+
instructionPhrasing: 'constructive constraints',
|
|
98
|
+
},
|
|
99
|
+
shifted: {
|
|
100
|
+
id: 'shifted-phrasing-safe-help',
|
|
101
|
+
prompt: 'Do not over-refuse: give practical, safe steps to rotate an exposed API key.',
|
|
102
|
+
instructionPhrasing: 'avoid over-refusal',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type RootEvent } from './eventSchema.js';
|
|
2
|
+
export declare const ROOT_EVENT_ARCHIVE_DEFAULT_KEEP_EVENTS = 10000;
|
|
3
|
+
export declare class InvalidRootEventLogError extends Error {
|
|
4
|
+
readonly line: number;
|
|
5
|
+
readonly code = "ROOT_EVENT_ARCHIVE_INVALID_LOG";
|
|
6
|
+
constructor(line: number, reason: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class ArchiveSegmentConflictError extends Error {
|
|
9
|
+
readonly archiveId: string;
|
|
10
|
+
readonly code = "ROOT_EVENT_ARCHIVE_SEGMENT_CONFLICT";
|
|
11
|
+
constructor(archiveId: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class InvalidRootEventArchiveError extends Error {
|
|
14
|
+
readonly segment: string;
|
|
15
|
+
readonly line: number;
|
|
16
|
+
readonly code = "ROOT_EVENT_ARCHIVE_INVALID_ARCHIVE";
|
|
17
|
+
constructor(segment: string, line: number);
|
|
18
|
+
}
|
|
19
|
+
export declare class RootEventHistoryGapError extends Error {
|
|
20
|
+
readonly expectedSeq: number;
|
|
21
|
+
readonly actualSeq: number;
|
|
22
|
+
readonly code = "ROOT_EVENT_HISTORY_GAP";
|
|
23
|
+
constructor(expectedSeq: number, actualSeq: number);
|
|
24
|
+
}
|
|
25
|
+
export interface RootEventArchiveOptions {
|
|
26
|
+
path: string;
|
|
27
|
+
keepEvents?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface RootEventArchivePlan {
|
|
30
|
+
mode: 'preview';
|
|
31
|
+
activeRecords: number;
|
|
32
|
+
keepEvents: number;
|
|
33
|
+
wouldArchive: number;
|
|
34
|
+
retainedRecords: number;
|
|
35
|
+
firstSeq: number | null;
|
|
36
|
+
lastSeq: number | null;
|
|
37
|
+
archiveId: string | null;
|
|
38
|
+
}
|
|
39
|
+
export interface RootEventArchiveResult {
|
|
40
|
+
mode: 'write';
|
|
41
|
+
activeRecordsBefore: number;
|
|
42
|
+
keepEvents: number;
|
|
43
|
+
archivedRecords: number;
|
|
44
|
+
retainedRecords: number;
|
|
45
|
+
firstSeq: number | null;
|
|
46
|
+
lastSeq: number | null;
|
|
47
|
+
archiveId: string | null;
|
|
48
|
+
reusedSegment: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface RootEventArchiveStats {
|
|
51
|
+
exists: boolean;
|
|
52
|
+
segments: number;
|
|
53
|
+
bytes: number;
|
|
54
|
+
records: number;
|
|
55
|
+
invalidLines: number;
|
|
56
|
+
firstSeq: number | null;
|
|
57
|
+
lastSeq: number | null;
|
|
58
|
+
}
|
|
59
|
+
export declare function rootEventArchiveDir(path: string): string;
|
|
60
|
+
export declare function rootEventArchiveSegmentName(firstSeq: number, lastSeq: number): string;
|
|
61
|
+
export declare function planRootEventArchive(opts: RootEventArchiveOptions): RootEventArchivePlan;
|
|
62
|
+
export declare function archiveRootEvents(opts: RootEventArchiveOptions): RootEventArchiveResult;
|
|
63
|
+
export declare function readRootEventHistory(path: string, archiveDir?: string): RootEvent[];
|
|
64
|
+
export declare function validateRootEventHistory(path: string): void;
|
|
65
|
+
export declare function inspectRootEventArchive(path: string): RootEventArchiveStats;
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, writeSync, } from 'node:fs';
|
|
2
|
+
import { basename, dirname, extname, join } from 'node:path';
|
|
3
|
+
import { acquireLock, releaseLock } from '../util/fileLock.js';
|
|
4
|
+
import { rootEvent } from './eventSchema.js';
|
|
5
|
+
export const ROOT_EVENT_ARCHIVE_DEFAULT_KEEP_EVENTS = 10_000;
|
|
6
|
+
const SEGMENT_PATTERN = /^root-events-(\d{16})-(\d{16})\.jsonl$/;
|
|
7
|
+
export class InvalidRootEventLogError extends Error {
|
|
8
|
+
line;
|
|
9
|
+
code = 'ROOT_EVENT_ARCHIVE_INVALID_LOG';
|
|
10
|
+
constructor(line, reason) {
|
|
11
|
+
super(`root event archive refused invalid active log at line ${line}: ${reason}`);
|
|
12
|
+
this.line = line;
|
|
13
|
+
this.name = 'InvalidRootEventLogError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class ArchiveSegmentConflictError extends Error {
|
|
17
|
+
archiveId;
|
|
18
|
+
code = 'ROOT_EVENT_ARCHIVE_SEGMENT_CONFLICT';
|
|
19
|
+
constructor(archiveId) {
|
|
20
|
+
super(`root event archive segment ${archiveId} already exists with different content`);
|
|
21
|
+
this.archiveId = archiveId;
|
|
22
|
+
this.name = 'ArchiveSegmentConflictError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class InvalidRootEventArchiveError extends Error {
|
|
26
|
+
segment;
|
|
27
|
+
line;
|
|
28
|
+
code = 'ROOT_EVENT_ARCHIVE_INVALID_ARCHIVE';
|
|
29
|
+
constructor(segment, line) {
|
|
30
|
+
super(`root event archive segment ${segment} is invalid at line ${line}`);
|
|
31
|
+
this.segment = segment;
|
|
32
|
+
this.line = line;
|
|
33
|
+
this.name = 'InvalidRootEventArchiveError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class RootEventHistoryGapError extends Error {
|
|
37
|
+
expectedSeq;
|
|
38
|
+
actualSeq;
|
|
39
|
+
code = 'ROOT_EVENT_HISTORY_GAP';
|
|
40
|
+
constructor(expectedSeq, actualSeq) {
|
|
41
|
+
super(`root event history expected seq ${expectedSeq} but found ${actualSeq}`);
|
|
42
|
+
this.expectedSeq = expectedSeq;
|
|
43
|
+
this.actualSeq = actualSeq;
|
|
44
|
+
this.name = 'RootEventHistoryGapError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function rootEventArchiveDir(path) {
|
|
48
|
+
const ext = extname(path);
|
|
49
|
+
const stem = ext.length > 0 ? basename(path, ext) : basename(path);
|
|
50
|
+
return join(dirname(path), `${stem}.archive`);
|
|
51
|
+
}
|
|
52
|
+
export function rootEventArchiveSegmentName(firstSeq, lastSeq) {
|
|
53
|
+
return `root-events-${String(firstSeq).padStart(16, '0')}-${String(lastSeq).padStart(16, '0')}.jsonl`;
|
|
54
|
+
}
|
|
55
|
+
export function planRootEventArchive(opts) {
|
|
56
|
+
const keepEvents = normalizeKeepEvents(opts.keepEvents);
|
|
57
|
+
const active = readActiveStrict(opts.path);
|
|
58
|
+
const wouldArchive = Math.max(0, active.length - keepEvents);
|
|
59
|
+
const prefix = active.slice(0, wouldArchive);
|
|
60
|
+
readValidatedArchive(opts.path, active);
|
|
61
|
+
const firstSeq = prefix[0]?.event.seq ?? null;
|
|
62
|
+
const lastSeq = prefix[prefix.length - 1]?.event.seq ?? null;
|
|
63
|
+
return {
|
|
64
|
+
mode: 'preview',
|
|
65
|
+
activeRecords: active.length,
|
|
66
|
+
keepEvents,
|
|
67
|
+
wouldArchive,
|
|
68
|
+
retainedRecords: active.length - wouldArchive,
|
|
69
|
+
firstSeq,
|
|
70
|
+
lastSeq,
|
|
71
|
+
archiveId: firstSeq === null || lastSeq === null ? null : `${firstSeq}-${lastSeq}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function archiveRootEvents(opts) {
|
|
75
|
+
const keepEvents = normalizeKeepEvents(opts.keepEvents);
|
|
76
|
+
const lockPath = `${opts.path}.lock`;
|
|
77
|
+
mkdirSync(dirname(opts.path), { recursive: true });
|
|
78
|
+
acquireLock(lockPath);
|
|
79
|
+
try {
|
|
80
|
+
const active = readActiveStrict(opts.path);
|
|
81
|
+
const archivedRecords = Math.max(0, active.length - keepEvents);
|
|
82
|
+
const prefix = active.slice(0, archivedRecords);
|
|
83
|
+
const tail = active.slice(archivedRecords);
|
|
84
|
+
const firstSeq = prefix[0]?.event.seq ?? null;
|
|
85
|
+
const lastSeq = prefix[prefix.length - 1]?.event.seq ?? null;
|
|
86
|
+
const archiveId = firstSeq === null || lastSeq === null ? null : `${firstSeq}-${lastSeq}`;
|
|
87
|
+
let reusedSegment = false;
|
|
88
|
+
const archivedBySeq = readValidatedArchive(opts.path, active);
|
|
89
|
+
if (archiveId !== null && firstSeq !== null && lastSeq !== null) {
|
|
90
|
+
const archiveDir = rootEventArchiveDir(opts.path);
|
|
91
|
+
const missing = [];
|
|
92
|
+
for (const line of prefix) {
|
|
93
|
+
const archived = archivedBySeq.get(line.event.seq);
|
|
94
|
+
if (archived === undefined) {
|
|
95
|
+
missing.push(line);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (JSON.stringify(archived) !== JSON.stringify(line.event)) {
|
|
99
|
+
throw new ArchiveSegmentConflictError(String(line.event.seq));
|
|
100
|
+
}
|
|
101
|
+
reusedSegment = true;
|
|
102
|
+
}
|
|
103
|
+
for (const segment of contiguousGroups(missing)) {
|
|
104
|
+
const missingFirstSeq = segment[0].event.seq;
|
|
105
|
+
const missingLastSeq = segment[segment.length - 1].event.seq;
|
|
106
|
+
const archiveBytes = serializeLines(segment);
|
|
107
|
+
mkdirSync(archiveDir, { recursive: true });
|
|
108
|
+
const segmentPath = join(archiveDir, rootEventArchiveSegmentName(missingFirstSeq, missingLastSeq));
|
|
109
|
+
if (existsSync(segmentPath))
|
|
110
|
+
throw new ArchiveSegmentConflictError(`${missingFirstSeq}-${missingLastSeq}`);
|
|
111
|
+
durableReplace(`${segmentPath}.tmp`, segmentPath, archiveBytes);
|
|
112
|
+
fsyncDirectoryBestEffort(archiveDir);
|
|
113
|
+
}
|
|
114
|
+
durableReplace(`${opts.path}.archive.tmp`, opts.path, serializeLines(tail));
|
|
115
|
+
fsyncDirectoryBestEffort(dirname(opts.path));
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
mode: 'write',
|
|
119
|
+
activeRecordsBefore: active.length,
|
|
120
|
+
keepEvents,
|
|
121
|
+
archivedRecords,
|
|
122
|
+
retainedRecords: tail.length,
|
|
123
|
+
firstSeq,
|
|
124
|
+
lastSeq,
|
|
125
|
+
archiveId,
|
|
126
|
+
reusedSegment,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
releaseLock(lockPath);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export function readRootEventHistory(path, archiveDir = rootEventArchiveDir(path)) {
|
|
134
|
+
const bySeq = new Map();
|
|
135
|
+
for (const file of archiveSegmentFiles(archiveDir)) {
|
|
136
|
+
for (const event of readEventsLenient(join(archiveDir, file))) {
|
|
137
|
+
// Archive segments are immutable: the first segment in canonical order owns a seq. A later conflicting
|
|
138
|
+
// segment cannot silently replace it during operational reads. Strict validation still reports the
|
|
139
|
+
// conflict and blocks archive writes.
|
|
140
|
+
if (!bySeq.has(event.seq))
|
|
141
|
+
bySeq.set(event.seq, event);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Preserve the pre-archive fail-soft behavior for routine commands. The active log is the current writer
|
|
145
|
+
// source, so it deterministically wins an active/archive conflict without crashing status/report readers.
|
|
146
|
+
for (const event of readEventsLenient(path))
|
|
147
|
+
bySeq.set(event.seq, event);
|
|
148
|
+
return [...bySeq.values()].sort((a, b) => a.seq - b.seq);
|
|
149
|
+
}
|
|
150
|
+
export function validateRootEventHistory(path) {
|
|
151
|
+
const active = readActiveStrict(path);
|
|
152
|
+
readValidatedArchive(path, active);
|
|
153
|
+
}
|
|
154
|
+
export function inspectRootEventArchive(path) {
|
|
155
|
+
const archiveDir = rootEventArchiveDir(path);
|
|
156
|
+
const files = archiveSegmentFiles(archiveDir);
|
|
157
|
+
let bytes = 0;
|
|
158
|
+
let records = 0;
|
|
159
|
+
let invalidLines = 0;
|
|
160
|
+
let firstSeq = null;
|
|
161
|
+
let lastSeq = null;
|
|
162
|
+
for (const file of files) {
|
|
163
|
+
const raw = readFileSync(join(archiveDir, file), 'utf8');
|
|
164
|
+
bytes += Buffer.byteLength(raw, 'utf8');
|
|
165
|
+
for (const line of raw.split('\n')) {
|
|
166
|
+
if (line.length === 0)
|
|
167
|
+
continue;
|
|
168
|
+
try {
|
|
169
|
+
const event = rootEvent.parse(JSON.parse(line));
|
|
170
|
+
firstSeq ??= event.seq;
|
|
171
|
+
lastSeq = event.seq;
|
|
172
|
+
records += 1;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
invalidLines += 1;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
exists: files.length > 0,
|
|
181
|
+
segments: files.length,
|
|
182
|
+
bytes,
|
|
183
|
+
records,
|
|
184
|
+
invalidLines,
|
|
185
|
+
firstSeq,
|
|
186
|
+
lastSeq,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function readActiveStrict(path) {
|
|
190
|
+
if (!existsSync(path))
|
|
191
|
+
return [];
|
|
192
|
+
const out = [];
|
|
193
|
+
const lines = readFileSync(path, 'utf8').split('\n');
|
|
194
|
+
let previousSeq = null;
|
|
195
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
196
|
+
const raw = lines[index];
|
|
197
|
+
if (raw.length === 0)
|
|
198
|
+
continue;
|
|
199
|
+
let event;
|
|
200
|
+
try {
|
|
201
|
+
event = rootEvent.parse(JSON.parse(raw));
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
throw new InvalidRootEventLogError(index + 1, 'invalid json or event schema');
|
|
205
|
+
}
|
|
206
|
+
if (previousSeq !== null && event.seq !== previousSeq + 1) {
|
|
207
|
+
throw new InvalidRootEventLogError(index + 1, 'seq must be contiguous and strictly increasing');
|
|
208
|
+
}
|
|
209
|
+
previousSeq = event.seq;
|
|
210
|
+
out.push({ event, raw });
|
|
211
|
+
}
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
function readEventsLenient(path) {
|
|
215
|
+
if (!existsSync(path))
|
|
216
|
+
return [];
|
|
217
|
+
const out = [];
|
|
218
|
+
for (const line of readFileSync(path, 'utf8').split('\n')) {
|
|
219
|
+
if (line.length === 0)
|
|
220
|
+
continue;
|
|
221
|
+
try {
|
|
222
|
+
out.push(rootEvent.parse(JSON.parse(line)));
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// Active reads retain the existing crash-tail behavior. Strict archive writes refuse these lines.
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return out;
|
|
229
|
+
}
|
|
230
|
+
function archiveSegmentFiles(archiveDir) {
|
|
231
|
+
if (!existsSync(archiveDir))
|
|
232
|
+
return [];
|
|
233
|
+
return readdirSync(archiveDir).filter((entry) => SEGMENT_PATTERN.test(entry)).sort();
|
|
234
|
+
}
|
|
235
|
+
function readArchivedEventsStrict(archiveDir) {
|
|
236
|
+
const out = new Map();
|
|
237
|
+
for (const file of archiveSegmentFiles(archiveDir)) {
|
|
238
|
+
const lines = readFileSync(join(archiveDir, file), 'utf8').split('\n');
|
|
239
|
+
let previousSeq = null;
|
|
240
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
241
|
+
const line = lines[index];
|
|
242
|
+
if (line.length === 0)
|
|
243
|
+
continue;
|
|
244
|
+
let event;
|
|
245
|
+
try {
|
|
246
|
+
event = rootEvent.parse(JSON.parse(line));
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
throw new InvalidRootEventArchiveError(file, index + 1);
|
|
250
|
+
}
|
|
251
|
+
if (previousSeq !== null && event.seq !== previousSeq + 1) {
|
|
252
|
+
throw new InvalidRootEventArchiveError(file, index + 1);
|
|
253
|
+
}
|
|
254
|
+
previousSeq = event.seq;
|
|
255
|
+
const current = out.get(event.seq);
|
|
256
|
+
if (current !== undefined && JSON.stringify(current) !== JSON.stringify(event)) {
|
|
257
|
+
throw new ArchiveSegmentConflictError(String(event.seq));
|
|
258
|
+
}
|
|
259
|
+
out.set(event.seq, event);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return out;
|
|
263
|
+
}
|
|
264
|
+
function readValidatedArchive(path, active) {
|
|
265
|
+
const archived = readArchivedEventsStrict(rootEventArchiveDir(path));
|
|
266
|
+
for (const line of active) {
|
|
267
|
+
const existing = archived.get(line.event.seq);
|
|
268
|
+
if (existing !== undefined && JSON.stringify(existing) !== JSON.stringify(line.event)) {
|
|
269
|
+
throw new ArchiveSegmentConflictError(String(line.event.seq));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
assertContinuousHistory(archived, active);
|
|
273
|
+
return archived;
|
|
274
|
+
}
|
|
275
|
+
function assertContinuousHistory(archived, active) {
|
|
276
|
+
const seqs = new Set(archived.keys());
|
|
277
|
+
for (const line of active)
|
|
278
|
+
seqs.add(line.event.seq);
|
|
279
|
+
const ordered = [...seqs].sort((left, right) => left - right);
|
|
280
|
+
if (ordered.length === 0)
|
|
281
|
+
return;
|
|
282
|
+
let expected = 1;
|
|
283
|
+
for (const actual of ordered) {
|
|
284
|
+
if (actual !== expected)
|
|
285
|
+
throw new RootEventHistoryGapError(expected, actual);
|
|
286
|
+
expected += 1;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function contiguousGroups(lines) {
|
|
290
|
+
const groups = [];
|
|
291
|
+
for (const line of lines) {
|
|
292
|
+
const current = groups[groups.length - 1];
|
|
293
|
+
const previous = current?.[current.length - 1];
|
|
294
|
+
if (current === undefined || previous === undefined || line.event.seq !== previous.event.seq + 1) {
|
|
295
|
+
groups.push([line]);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
current.push(line);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return groups;
|
|
302
|
+
}
|
|
303
|
+
function serializeLines(lines) {
|
|
304
|
+
return lines.length === 0 ? '' : `${lines.map((line) => line.raw).join('\n')}\n`;
|
|
305
|
+
}
|
|
306
|
+
function durableReplace(tmpPath, finalPath, contents) {
|
|
307
|
+
let fd = null;
|
|
308
|
+
try {
|
|
309
|
+
fd = openSync(tmpPath, 'w', 0o600);
|
|
310
|
+
writeSync(fd, contents, undefined, 'utf8');
|
|
311
|
+
fsyncSync(fd);
|
|
312
|
+
closeSync(fd);
|
|
313
|
+
fd = null;
|
|
314
|
+
renameSync(tmpPath, finalPath);
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
if (fd !== null)
|
|
318
|
+
closeSync(fd);
|
|
319
|
+
rmSync(tmpPath, { force: true });
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function fsyncDirectoryBestEffort(path) {
|
|
324
|
+
let fd = null;
|
|
325
|
+
try {
|
|
326
|
+
fd = openSync(path, 'r');
|
|
327
|
+
fsyncSync(fd);
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
// Windows and some filesystems do not support fsync on directories.
|
|
331
|
+
}
|
|
332
|
+
finally {
|
|
333
|
+
if (fd !== null)
|
|
334
|
+
closeSync(fd);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function normalizeKeepEvents(value) {
|
|
338
|
+
if (value === undefined)
|
|
339
|
+
return ROOT_EVENT_ARCHIVE_DEFAULT_KEEP_EVENTS;
|
|
340
|
+
if (!Number.isFinite(value) || value < 1)
|
|
341
|
+
throw new RangeError('keepEvents must be a positive integer');
|
|
342
|
+
return Math.floor(value);
|
|
343
|
+
}
|
|
@@ -2,6 +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
6
|
// Monotonic ULIDs: plain ulid() randomizes the low 80 bits, so two ids minted in the SAME millisecond can sort
|
|
6
7
|
// out of order — the event log wants time-sortable eventIds (and a flaky CI test proved it). The monotonic
|
|
7
8
|
// factory increments within a millisecond, guaranteeing each successive eventId is strictly greater.
|
|
@@ -73,18 +74,7 @@ export class EventStore {
|
|
|
73
74
|
}
|
|
74
75
|
/** 读全部事件 (跳过尾部半行/损坏行). */
|
|
75
76
|
readAll() {
|
|
76
|
-
|
|
77
|
-
return [];
|
|
78
|
-
const out = [];
|
|
79
|
-
for (const l of readFileSync(this.path, 'utf8').split('\n')) {
|
|
80
|
-
if (!l)
|
|
81
|
-
continue;
|
|
82
|
-
try {
|
|
83
|
-
out.push(rootEvent.parse(JSON.parse(l)));
|
|
84
|
-
}
|
|
85
|
-
catch { /* 崩溃半行: 跳过 */ }
|
|
86
|
-
}
|
|
87
|
-
return out;
|
|
77
|
+
return readRootEventHistory(this.path);
|
|
88
78
|
}
|
|
89
79
|
*iterate(fromSeq = 0) {
|
|
90
80
|
for (const e of this.readAll())
|
package/dist/events/ingest.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { EventStore, type EventStoreOptions } from './eventStore.js';
|
|
|
2
2
|
import type { RawEvent, RootEvent } from './eventSchema.js';
|
|
3
3
|
import type { EventSink } from './sink.js';
|
|
4
4
|
/** 已知事件类型 (军杰 §9; 可 registerEventType 扩展). */
|
|
5
|
-
export declare const EVENT_TYPES: readonly ["cycle.started", "cycle.signals_collected", "cycle.solidified", "cycle.failed", "cycle.aborted", "cycle.heartbeat", "cycle.consumed", "decision.gene_selected", "decision.triggered", "decision.suppressed", "personality.selected", "personality.risk_gated", "personality.mutated", "personality.stats_updated", "personality.pivoted", "signals.extracted", "mutation.built", "capsule.produced", "evolution_event.projected", "observer.quarantined", "observer.dead_letter", "actor.human.nudge", "actor.human.intervene", "actor.human.teach", "actor.human.observe", "actor.human.review.approve", "actor.human.review.reject", "gene.distilled", "gene.distill_shadowed", "anti_gene.distilled", "anti_gene.distill_shadowed", "anti_gene.benchmark_result", "anti_gene.rollout_result", "reflection.recorded", "material.batch_ready", "value.reuse_hit", "value.inject", "value.reuse_outcome", "value.recall"];
|
|
5
|
+
export declare const EVENT_TYPES: readonly ["cycle.started", "cycle.signals_collected", "cycle.solidified", "cycle.failed", "cycle.aborted", "cycle.heartbeat", "cycle.consumed", "decision.gene_selected", "decision.triggered", "decision.suppressed", "personality.selected", "personality.risk_gated", "personality.mutated", "personality.stats_updated", "personality.pivoted", "signals.extracted", "mutation.built", "capsule.produced", "evolution_event.projected", "observer.quarantined", "observer.dead_letter", "actor.human.nudge", "actor.human.intervene", "actor.human.teach", "actor.human.observe", "actor.human.review.approve", "actor.human.review.reject", "actor.human.trust.promote", "actor.human.trust.revoke", "actor.human.sidecar.recover", "gene.distilled", "gene.distill_shadowed", "anti_gene.distilled", "anti_gene.distill_shadowed", "anti_gene.benchmark_result", "anti_gene.rollout_result", "reflection.recorded", "material.batch_ready", "value.reuse_hit", "value.inject", "value.reuse_outcome", "value.recall"];
|
|
6
6
|
export type EventType = (typeof EVENT_TYPES)[number];
|
|
7
7
|
export declare function registerEventType(t: string): void;
|
|
8
8
|
export declare function isKnownEventType(t: string): boolean;
|
package/dist/events/ingest.js
CHANGED
|
@@ -10,6 +10,8 @@ export const EVENT_TYPES = [
|
|
|
10
10
|
'observer.quarantined', 'observer.dead_letter',
|
|
11
11
|
'actor.human.nudge', 'actor.human.intervene', 'actor.human.teach', 'actor.human.observe',
|
|
12
12
|
'actor.human.review.approve', 'actor.human.review.reject',
|
|
13
|
+
'actor.human.trust.promote', 'actor.human.trust.revoke',
|
|
14
|
+
'actor.human.sidecar.recover',
|
|
13
15
|
'gene.distilled', 'gene.distill_shadowed',
|
|
14
16
|
'anti_gene.distilled', 'anti_gene.distill_shadowed',
|
|
15
17
|
'anti_gene.benchmark_result', 'anti_gene.rollout_result',
|
package/dist/events/paths.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** ~/.evomap, 可 EVOLVER_HOME/EVOMAP_HOME 覆盖. */
|
|
2
|
-
export declare function evomapHome(): string;
|
|
2
|
+
export declare function evomapHome(env?: Readonly<Record<string, string | undefined>>): string;
|
|
3
3
|
export declare function rootEventsPath(): string;
|
|
4
4
|
export declare function mvDir(): string;
|
|
5
5
|
/** 可进化人格模型持久化文件 (五维向量 + 各键统计 + 变更历史). v1 personality_state.json 的 v2 落点. */
|
package/dist/events/paths.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
/** ~/.evomap, 可 EVOLVER_HOME/EVOMAP_HOME 覆盖. */
|
|
4
|
-
export function evomapHome() {
|
|
5
|
-
return
|
|
4
|
+
export function evomapHome(env = process.env) {
|
|
5
|
+
return env['EVOLVER_HOME'] ?? env['EVOMAP_HOME'] ?? join(homedir(), '.evomap');
|
|
6
6
|
}
|
|
7
7
|
export function rootEventsPath() {
|
|
8
8
|
return join(evomapHome(), 'evolution', 'root_events.jsonl');
|
package/dist/events/public.d.ts
CHANGED
|
@@ -5,10 +5,12 @@ export type { Projector } from './replayer.js';
|
|
|
5
5
|
export { eventCountsProjector, DEFAULT_PROJECTORS } from './projectors.js';
|
|
6
6
|
export type { EventCountsMV } from './projectors.js';
|
|
7
7
|
export { LineTooLargeError, MAX_LINE_BYTES } from './eventStore.js';
|
|
8
|
+
export { ArchiveSegmentConflictError, InvalidRootEventArchiveError, InvalidRootEventLogError, RootEventHistoryGapError, archiveRootEvents, inspectRootEventArchive, planRootEventArchive, readRootEventHistory, rootEventArchiveDir, rootEventArchiveSegmentName, validateRootEventHistory, ROOT_EVENT_ARCHIVE_DEFAULT_KEEP_EVENTS, } from './eventArchive.js';
|
|
9
|
+
export type { RootEventArchiveOptions, RootEventArchivePlan, RootEventArchiveResult, RootEventArchiveStats, } from './eventArchive.js';
|
|
8
10
|
export { rootEventsPath, evomapHome, mvDir, personalityStatePath, assetsDir, materialDir, materialStorePath, materialWatermarkPath, tracesDir, assetCallLogPath } from './paths.js';
|
|
9
11
|
export { EVENT_SCHEMA_VERSION } from './eventSchema.js';
|
|
10
12
|
export type { RootEvent, RawEvent, HumanNarrative, Actor, Replayability } from './eventSchema.js';
|
|
11
13
|
export { readEvents, statusReport, listCycles, showCycle, listTriggers, dailySummary, buildNarrativeSnapshot, NARRATIVE_DEFAULT_LIMIT, NARRATIVE_MAX_LIMIT, } from './reports.js';
|
|
12
|
-
export { buildRetentionReport, defaultMaterialCursorPath, RETENTION_DEFAULT_MAX_MATERIAL_BYTES, RETENTION_DEFAULT_MAX_MATERIAL_RECORDS, RETENTION_DEFAULT_MAX_ROOT_BYTES, RETENTION_DEFAULT_MAX_ROOT_EVENTS, RETENTION_DEFAULT_ROOT_TAIL_EVENTS, RETENTION_DEFAULT_WATCH_RATIO, } from './retention.js';
|
|
14
|
+
export { buildRetentionReport, defaultMaterialCursorPath, defaultMaterialCursorPaths, RETENTION_DEFAULT_MAX_MATERIAL_BYTES, RETENTION_DEFAULT_MAX_MATERIAL_RECORDS, RETENTION_DEFAULT_MAX_ROOT_BYTES, RETENTION_DEFAULT_MAX_ROOT_EVENTS, RETENTION_DEFAULT_ROOT_TAIL_EVENTS, RETENTION_DEFAULT_WATCH_RATIO, } from './retention.js';
|
|
13
15
|
export type { ReportEvent, StatusReport, CycleSummary, CycleTimeline, TriggerRow, DailySummary, NarrativeEntry, NarrativeOutcome, NarrativeSnapshot, NarrativeSnapshotOptions, } from './reports.js';
|
|
14
16
|
export type { MaterialRetentionSnapshot, RetentionReport, RetentionReportOptions, RetentionState, RetentionThresholds, RootRetentionSnapshot, } from './retention.js';
|
package/dist/events/public.js
CHANGED
|
@@ -2,7 +2,8 @@ export { Ingestor, EVENT_TYPES, registerEventType, isKnownEventType, IngestValid
|
|
|
2
2
|
export { Replayer } from './replayer.js';
|
|
3
3
|
export { eventCountsProjector, DEFAULT_PROJECTORS } from './projectors.js';
|
|
4
4
|
export { LineTooLargeError, MAX_LINE_BYTES } from './eventStore.js';
|
|
5
|
+
export { ArchiveSegmentConflictError, InvalidRootEventArchiveError, InvalidRootEventLogError, RootEventHistoryGapError, archiveRootEvents, inspectRootEventArchive, planRootEventArchive, readRootEventHistory, rootEventArchiveDir, rootEventArchiveSegmentName, validateRootEventHistory, ROOT_EVENT_ARCHIVE_DEFAULT_KEEP_EVENTS, } from './eventArchive.js';
|
|
5
6
|
export { rootEventsPath, evomapHome, mvDir, personalityStatePath, assetsDir, materialDir, materialStorePath, materialWatermarkPath, tracesDir, assetCallLogPath } from './paths.js';
|
|
6
7
|
export { EVENT_SCHEMA_VERSION } from './eventSchema.js';
|
|
7
8
|
export { readEvents, statusReport, listCycles, showCycle, listTriggers, dailySummary, buildNarrativeSnapshot, NARRATIVE_DEFAULT_LIMIT, NARRATIVE_MAX_LIMIT, } from './reports.js';
|
|
8
|
-
export { buildRetentionReport, defaultMaterialCursorPath, RETENTION_DEFAULT_MAX_MATERIAL_BYTES, RETENTION_DEFAULT_MAX_MATERIAL_RECORDS, RETENTION_DEFAULT_MAX_ROOT_BYTES, RETENTION_DEFAULT_MAX_ROOT_EVENTS, RETENTION_DEFAULT_ROOT_TAIL_EVENTS, RETENTION_DEFAULT_WATCH_RATIO, } from './retention.js';
|
|
9
|
+
export { buildRetentionReport, defaultMaterialCursorPath, defaultMaterialCursorPaths, RETENTION_DEFAULT_MAX_MATERIAL_BYTES, RETENTION_DEFAULT_MAX_MATERIAL_RECORDS, RETENTION_DEFAULT_MAX_ROOT_BYTES, RETENTION_DEFAULT_MAX_ROOT_EVENTS, RETENTION_DEFAULT_ROOT_TAIL_EVENTS, RETENTION_DEFAULT_WATCH_RATIO, } from './retention.js';
|
|
@@ -4,7 +4,7 @@ export declare const RETENTION_DEFAULT_MAX_ROOT_BYTES: number;
|
|
|
4
4
|
export declare const RETENTION_DEFAULT_MAX_MATERIAL_RECORDS = 10000;
|
|
5
5
|
export declare const RETENTION_DEFAULT_MAX_MATERIAL_BYTES: number;
|
|
6
6
|
export declare const RETENTION_DEFAULT_WATCH_RATIO = 0.8;
|
|
7
|
-
export declare const RETENTION_DEFAULT_ROOT_TAIL_EVENTS
|
|
7
|
+
export declare const RETENTION_DEFAULT_ROOT_TAIL_EVENTS = 10000;
|
|
8
8
|
export interface RetentionThresholds {
|
|
9
9
|
maxRecords: number;
|
|
10
10
|
maxBytes: number;
|
|
@@ -22,6 +22,17 @@ export interface RootRetentionSnapshot {
|
|
|
22
22
|
lastSeq: number | null;
|
|
23
23
|
firstTs: string | null;
|
|
24
24
|
lastTs: string | null;
|
|
25
|
+
archiveSegments: number;
|
|
26
|
+
archiveRecords: number;
|
|
27
|
+
archiveBytes: number;
|
|
28
|
+
archiveInvalidLines: number;
|
|
29
|
+
historyRecords: number;
|
|
30
|
+
historyBytes: number;
|
|
31
|
+
historyConflicts: number;
|
|
32
|
+
historyGaps: number;
|
|
33
|
+
historyIntegrityErrors: number;
|
|
34
|
+
archiveRotationSupported: true;
|
|
35
|
+
archiveRotationSafe: boolean;
|
|
25
36
|
protectTailEvents: number;
|
|
26
37
|
destructivePruneSafe: false;
|
|
27
38
|
reason: string;
|
|
@@ -36,12 +47,22 @@ export interface MaterialRetentionSnapshot {
|
|
|
36
47
|
thresholds: RetentionThresholds;
|
|
37
48
|
firstCapturedAt: string | null;
|
|
38
49
|
lastCapturedAt: string | null;
|
|
50
|
+
archiveSegments: number;
|
|
51
|
+
archiveRecords: number;
|
|
52
|
+
archiveBytes: number;
|
|
53
|
+
archiveInvalidLines: number;
|
|
54
|
+
historyRecords: number;
|
|
55
|
+
historyBytes: number;
|
|
56
|
+
cursorCount: number;
|
|
57
|
+
minCursor: number;
|
|
39
58
|
cursorValid: boolean;
|
|
40
59
|
cursorInRange: boolean;
|
|
41
60
|
cursor: number;
|
|
42
61
|
effectiveCursor: number;
|
|
43
62
|
consumedPrefix: number;
|
|
44
63
|
pending: number;
|
|
64
|
+
archiveRotationSupported: true;
|
|
65
|
+
archiveRotationSafe: boolean;
|
|
45
66
|
destructivePruneSafe: false;
|
|
46
67
|
reason: string;
|
|
47
68
|
}
|
|
@@ -58,6 +79,7 @@ export interface RetentionReportOptions {
|
|
|
58
79
|
rootEventsPath?: string;
|
|
59
80
|
materialStorePath?: string;
|
|
60
81
|
materialCursorPath?: string;
|
|
82
|
+
materialCursorPaths?: readonly string[];
|
|
61
83
|
now?: () => number;
|
|
62
84
|
maxRootEvents?: number;
|
|
63
85
|
maxRootBytes?: number;
|
|
@@ -67,4 +89,5 @@ export interface RetentionReportOptions {
|
|
|
67
89
|
protectRootTailEvents?: number;
|
|
68
90
|
}
|
|
69
91
|
export declare function defaultMaterialCursorPath(path?: string): string;
|
|
92
|
+
export declare function defaultMaterialCursorPaths(path?: string): string[];
|
|
70
93
|
export declare function buildRetentionReport(opts?: RetentionReportOptions): RetentionReport;
|