ushman-ledger 1.2.1 → 1.2.2
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/ARCHITECTURE.md +79 -0
- package/README.md +87 -0
- package/TROUBLESHOOTING.md +170 -0
- package/dist/blobs.d.ts +3 -0
- package/dist/blobs.d.ts.map +1 -1
- package/dist/blobs.js +41 -15
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +85 -27
- package/dist/coverage.d.ts.map +1 -1
- package/dist/coverage.js +3 -2
- package/dist/doctor.d.ts +17 -4
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +224 -57
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +23 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/list.d.ts +2 -1
- package/dist/list.d.ts.map +1 -1
- package/dist/list.js +19 -9
- package/dist/patch-resolver.d.ts.map +1 -1
- package/dist/patch-resolver.js +193 -53
- package/dist/read-index.d.ts.map +1 -1
- package/dist/read-index.js +6 -5
- package/dist/record.d.ts.map +1 -1
- package/dist/record.js +2 -1
- package/dist/runtime-config.d.ts +12 -0
- package/dist/runtime-config.d.ts.map +1 -0
- package/dist/runtime-config.js +83 -0
- package/dist/storage/filesystem.d.ts +1 -0
- package/dist/storage/filesystem.d.ts.map +1 -1
- package/dist/storage/filesystem.js +33 -3
- package/dist/text-lines.d.ts +8 -0
- package/dist/text-lines.d.ts.map +1 -0
- package/dist/text-lines.js +20 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -1
- package/package.json +4 -2
package/dist/doctor.js
CHANGED
|
@@ -5,71 +5,202 @@ import { sha256File } from "./json.js";
|
|
|
5
5
|
import { getOrderedEntryLocations, readManifestEntryBatch } from "./list.js";
|
|
6
6
|
import { isReadIndexCurrent, readReadIndex } from "./read-index.js";
|
|
7
7
|
import { loadLedgerState } from "./recovery.js";
|
|
8
|
+
import { getLedgerRuntimeConfig } from "./runtime-config.js";
|
|
8
9
|
import { readManifest } from "./storage/filesystem.js";
|
|
9
|
-
const BLOB_HASH_CONCURRENCY = 16;
|
|
10
10
|
const CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1_000;
|
|
11
|
-
const ENTRY_READ_BATCH_SIZE = 32;
|
|
12
11
|
const OPEN_ISSUE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1_000;
|
|
13
|
-
const
|
|
12
|
+
export const DOCTOR_FINDING_CODES = [
|
|
13
|
+
'blob-corrupt',
|
|
14
|
+
'blob-missing',
|
|
15
|
+
'blob-unreadable',
|
|
16
|
+
'change-log-rollback-missing-target',
|
|
17
|
+
'change-log-smoke-failure-missing-rollback-plan',
|
|
18
|
+
'manifest-entry-count-mismatch',
|
|
19
|
+
'manifest-entry-location-missing',
|
|
20
|
+
'manifest-entry-missing-on-disk',
|
|
21
|
+
'manifest-last-sequence-mismatch',
|
|
22
|
+
'manifest-per-phase-latest-mismatch',
|
|
23
|
+
'manifest-phase-mismatch',
|
|
24
|
+
'manifest-sequence-mismatch',
|
|
25
|
+
'open-issue-stale',
|
|
26
|
+
'phase-prev-entry-mismatch',
|
|
27
|
+
'pre-change-checkpoint-stale',
|
|
28
|
+
'read-failure',
|
|
29
|
+
];
|
|
30
|
+
const createFinding = ({ code, message, metadata, remediation, }) => ({
|
|
31
|
+
code,
|
|
32
|
+
message,
|
|
33
|
+
metadata,
|
|
34
|
+
remediation,
|
|
35
|
+
});
|
|
36
|
+
const buildDoctorReport = (findings) => ({
|
|
37
|
+
checkedAt: new Date().toISOString(),
|
|
38
|
+
findings: [...findings],
|
|
39
|
+
issueCount: findings.length,
|
|
40
|
+
issues: findings.map((finding) => finding.message),
|
|
41
|
+
ok: findings.length === 0,
|
|
42
|
+
});
|
|
43
|
+
const pushFinding = (findings, finding) => {
|
|
44
|
+
findings.push(finding);
|
|
45
|
+
};
|
|
46
|
+
const isMissingPathError = (error) => {
|
|
47
|
+
const code = error.code;
|
|
48
|
+
return code === 'ENOENT' || code === 'ENOTDIR';
|
|
49
|
+
};
|
|
50
|
+
const buildReadFailure = (error) => buildDoctorReport([
|
|
51
|
+
createFinding({
|
|
52
|
+
code: 'read-failure',
|
|
53
|
+
message: `Failed to read ledger state: ${error instanceof Error ? error.message ?? error.name : String(error)}.`,
|
|
54
|
+
remediation: 'Re-open the ledger or rerun the command first so recovery can reconcile pending state. If the error persists, repair or restore the invalid manifest/read-index JSON before archiving.',
|
|
55
|
+
}),
|
|
56
|
+
]);
|
|
57
|
+
const isChangeLogEntry = (entry) => entry.kind === 'change-log';
|
|
58
|
+
const isOpenIssueNote = (entry) => entry.kind === 'note' && entry.subkind === 'open-issue';
|
|
59
|
+
const checkPrevChain = (entry, findings, previousByPhase) => {
|
|
14
60
|
const expectedPrev = previousByPhase.get(entry.phase) ?? null;
|
|
15
61
|
if (entry.prevEntryId !== expectedPrev) {
|
|
16
|
-
|
|
62
|
+
pushFinding(findings, createFinding({
|
|
63
|
+
code: 'phase-prev-entry-mismatch',
|
|
64
|
+
message: `Phase ${entry.phase} has broken prevEntryId chain at ${entry.id}: expected ${expectedPrev ?? 'null'}, found ${entry.prevEntryId ?? 'null'}.`,
|
|
65
|
+
metadata: {
|
|
66
|
+
entryId: entry.id,
|
|
67
|
+
expectedPrevEntryId: expectedPrev,
|
|
68
|
+
foundPrevEntryId: entry.prevEntryId,
|
|
69
|
+
phase: entry.phase,
|
|
70
|
+
},
|
|
71
|
+
remediation: 'Restore the edited entry or repair the phase chain so prevEntryId matches append order. Use a correction entry for content fixes instead of hand-editing ledger history.',
|
|
72
|
+
}));
|
|
17
73
|
}
|
|
18
74
|
previousByPhase.set(entry.phase, entry.id);
|
|
19
75
|
};
|
|
20
76
|
const checkBlobPresence = async (workspaceRoot, blobChecks) => {
|
|
21
|
-
const
|
|
77
|
+
const { blobHashConcurrency } = getLedgerRuntimeConfig();
|
|
78
|
+
const groupedBlobChecks = new Map();
|
|
79
|
+
for (const { blobHash, entryId } of blobChecks) {
|
|
80
|
+
const entryIds = groupedBlobChecks.get(blobHash) ?? [];
|
|
81
|
+
entryIds.push(entryId);
|
|
82
|
+
groupedBlobChecks.set(blobHash, entryIds);
|
|
83
|
+
}
|
|
84
|
+
const results = await mapWithConcurrencyLimit([...groupedBlobChecks.entries()], blobHashConcurrency, async ([blobHash, entryIds]) => {
|
|
85
|
+
const blobPath = resolveBlobPath(workspaceRoot, blobHash);
|
|
22
86
|
try {
|
|
23
|
-
const blobPath = resolveBlobPath(workspaceRoot, blobHash);
|
|
24
87
|
await stat(blobPath);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (!isMissingPathError(error)) {
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
return entryIds.map((entryId) => createFinding({
|
|
94
|
+
code: 'blob-missing',
|
|
95
|
+
message: `Missing blob ${blobHash} for ${entryId}.`,
|
|
96
|
+
metadata: {
|
|
97
|
+
blobSha256: blobHash,
|
|
98
|
+
entryId,
|
|
99
|
+
},
|
|
100
|
+
remediation: 'Restore the missing blob file under .lab/ledger/blobs/ or recreate the patch entry from the original diff before archiving.',
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
25
104
|
const actualHash = await sha256File(blobPath);
|
|
26
105
|
if (actualHash !== blobHash) {
|
|
27
|
-
return
|
|
106
|
+
return entryIds.map((entryId) => createFinding({
|
|
107
|
+
code: 'blob-corrupt',
|
|
108
|
+
message: `Blob ${blobHash} for ${entryId} is corrupted (found ${actualHash}).`,
|
|
109
|
+
metadata: {
|
|
110
|
+
actualSha256: actualHash,
|
|
111
|
+
blobSha256: blobHash,
|
|
112
|
+
entryId,
|
|
113
|
+
},
|
|
114
|
+
remediation: 'Restore the original blob content under .lab/ledger/blobs/ or recreate the patch entry from the original diff before archiving.',
|
|
115
|
+
}));
|
|
28
116
|
}
|
|
29
|
-
return
|
|
117
|
+
return [];
|
|
30
118
|
}
|
|
31
|
-
catch {
|
|
32
|
-
return
|
|
119
|
+
catch (error) {
|
|
120
|
+
return entryIds.map((entryId) => createFinding({
|
|
121
|
+
code: 'blob-unreadable',
|
|
122
|
+
message: `Blob ${blobHash} for ${entryId} could not be read: ${error instanceof Error ? error.message : String(error)}.`,
|
|
123
|
+
metadata: {
|
|
124
|
+
blobSha256: blobHash,
|
|
125
|
+
entryId,
|
|
126
|
+
},
|
|
127
|
+
remediation: 'Fix the filesystem permission or read error first, then rerun doctor so blob integrity can be verified before archiving.',
|
|
128
|
+
}));
|
|
33
129
|
}
|
|
34
130
|
});
|
|
35
|
-
return results.
|
|
131
|
+
return results.flat();
|
|
36
132
|
};
|
|
37
|
-
const checkManifestCounts = (manifest, entryCount) => {
|
|
38
|
-
const issues = [];
|
|
133
|
+
const checkManifestCounts = (findings, manifest, entryCount) => {
|
|
39
134
|
if (manifest.entryCount !== entryCount) {
|
|
40
|
-
|
|
135
|
+
pushFinding(findings, createFinding({
|
|
136
|
+
code: 'manifest-entry-count-mismatch',
|
|
137
|
+
message: `Manifest entryCount ${manifest.entryCount} does not match disk entries ${entryCount}.`,
|
|
138
|
+
metadata: {
|
|
139
|
+
diskEntryCount: entryCount,
|
|
140
|
+
manifestEntryCount: manifest.entryCount,
|
|
141
|
+
},
|
|
142
|
+
remediation: 'Rerun the command or reopen the ledger so recovery can replay pending commits. If the mismatch persists, compare manifest.json with the on-disk phase entries and repair the missing location or file.',
|
|
143
|
+
}));
|
|
41
144
|
}
|
|
42
145
|
if (manifest.lastSequence !== entryCount) {
|
|
43
|
-
|
|
146
|
+
pushFinding(findings, createFinding({
|
|
147
|
+
code: 'manifest-last-sequence-mismatch',
|
|
148
|
+
message: `Manifest lastSequence ${manifest.lastSequence} does not match disk entries ${entryCount}.`,
|
|
149
|
+
metadata: {
|
|
150
|
+
diskEntryCount: entryCount,
|
|
151
|
+
manifestLastSequence: manifest.lastSequence,
|
|
152
|
+
},
|
|
153
|
+
remediation: 'Repair manifest.json so lastSequence matches the highest durable append sequence after recovery completes.',
|
|
154
|
+
}));
|
|
44
155
|
}
|
|
45
|
-
return issues;
|
|
46
156
|
};
|
|
47
|
-
const finalizeManifestChecks = ({ entryCount,
|
|
48
|
-
|
|
157
|
+
const finalizeManifestChecks = ({ entryCount, findings, latestByPhase, manifest, unseenManifestEntryIds, }) => {
|
|
158
|
+
checkManifestCounts(findings, manifest, entryCount);
|
|
49
159
|
for (const entryId of unseenManifestEntryIds) {
|
|
50
|
-
|
|
160
|
+
pushFinding(findings, createFinding({
|
|
161
|
+
code: 'manifest-entry-missing-on-disk',
|
|
162
|
+
message: `Manifest entry location points to missing disk entry ${entryId}.`,
|
|
163
|
+
metadata: { entryId },
|
|
164
|
+
remediation: 'Restore the missing entry file or repair manifest.entryLocations so every referenced entry id exists on disk before archiving.',
|
|
165
|
+
}));
|
|
51
166
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
167
|
+
const phasesToCheck = new Set([...Object.keys(manifest.perPhaseLatest), ...latestByPhase.keys()]);
|
|
168
|
+
for (const phase of phasesToCheck) {
|
|
169
|
+
const latest = latestByPhase.get(phase);
|
|
170
|
+
const expectedEntryId = latest?.entryId ?? null;
|
|
171
|
+
const foundEntryId = manifest.perPhaseLatest[phase] ?? null;
|
|
172
|
+
if (foundEntryId !== expectedEntryId) {
|
|
173
|
+
pushFinding(findings, createFinding({
|
|
174
|
+
code: 'manifest-per-phase-latest-mismatch',
|
|
175
|
+
message: `Manifest perPhaseLatest mismatch for ${phase}: expected ${expectedEntryId ?? 'missing'}, found ${foundEntryId ?? 'missing'}.`,
|
|
176
|
+
metadata: {
|
|
177
|
+
expectedEntryId,
|
|
178
|
+
foundEntryId,
|
|
179
|
+
phase,
|
|
180
|
+
},
|
|
181
|
+
remediation: 'Repair perPhaseLatest so each phase points at the newest durable entry in that phase.',
|
|
182
|
+
}));
|
|
55
183
|
}
|
|
56
184
|
}
|
|
57
185
|
};
|
|
58
|
-
const checkManifestSequenceOrder = (entryLocations,
|
|
186
|
+
const checkManifestSequenceOrder = (entryLocations, findings) => {
|
|
59
187
|
for (let index = 0; index < entryLocations.length; index += 1) {
|
|
60
188
|
const [entryId, location] = entryLocations[index];
|
|
61
189
|
const expectedSequence = index + 1;
|
|
62
190
|
if (location.sequence !== expectedSequence) {
|
|
63
|
-
|
|
191
|
+
pushFinding(findings, createFinding({
|
|
192
|
+
code: 'manifest-sequence-mismatch',
|
|
193
|
+
message: `Manifest sequence mismatch for ${entryId}: expected ${expectedSequence}, found ${location.sequence}.`,
|
|
194
|
+
metadata: {
|
|
195
|
+
entryId,
|
|
196
|
+
expectedSequence,
|
|
197
|
+
foundSequence: location.sequence,
|
|
198
|
+
},
|
|
199
|
+
remediation: 'Repair manifest.entryLocations so sequences remain contiguous and match append order.',
|
|
200
|
+
}));
|
|
64
201
|
}
|
|
65
202
|
}
|
|
66
203
|
};
|
|
67
|
-
const buildReadFailure = (error) => ({
|
|
68
|
-
issues: [`Failed to read ledger state: ${error instanceof Error ? (error.message ?? error.name) : String(error)}.`],
|
|
69
|
-
ok: false,
|
|
70
|
-
});
|
|
71
|
-
const isChangeLogEntry = (entry) => entry.kind === 'change-log';
|
|
72
|
-
const isOpenIssueNote = (entry) => entry.kind === 'note' && entry.subkind === 'open-issue';
|
|
73
204
|
const trackResolutionLinks = (entry, resolvedLedgerIds) => {
|
|
74
205
|
if (entry.links.correctsLedgerId) {
|
|
75
206
|
resolvedLedgerIds.add(entry.links.correctsLedgerId);
|
|
@@ -87,7 +218,7 @@ const trackIdempotencyEntry = (entry, entriesByIdempotencyKey) => {
|
|
|
87
218
|
existingEntries.push({ id: entry.id, ts: entry.ts });
|
|
88
219
|
entriesByIdempotencyKey.set(idempotencyKey, existingEntries);
|
|
89
220
|
};
|
|
90
|
-
const checkChangeLogWarnings = ({ checkpointEntries, entriesByIdempotencyKey,
|
|
221
|
+
const checkChangeLogWarnings = ({ checkpointEntries, entriesByIdempotencyKey, findings, nowMs, openIssueEntries, resolvedLedgerIds, }) => {
|
|
91
222
|
for (const checkpointEntry of checkpointEntries) {
|
|
92
223
|
const ageMs = nowMs - Date.parse(checkpointEntry.ts);
|
|
93
224
|
if (ageMs <= CHECKPOINT_MAX_AGE_MS) {
|
|
@@ -97,7 +228,15 @@ const checkChangeLogWarnings = ({ checkpointEntries, entriesByIdempotencyKey, is
|
|
|
97
228
|
const hasFollowUp = typeof idempotencyKey === 'string' &&
|
|
98
229
|
(entriesByIdempotencyKey.get(idempotencyKey) ?? []).some((candidate) => candidate.id !== checkpointEntry.id && candidate.ts >= checkpointEntry.ts);
|
|
99
230
|
if (!hasFollowUp) {
|
|
100
|
-
|
|
231
|
+
pushFinding(findings, createFinding({
|
|
232
|
+
code: 'pre-change-checkpoint-stale',
|
|
233
|
+
message: `Pre-change checkpoint ${checkpointEntry.id} is older than 24h and has no follow-up entry with matching idempotencyKey.`,
|
|
234
|
+
metadata: {
|
|
235
|
+
entryId: checkpointEntry.id,
|
|
236
|
+
idempotencyKey: idempotencyKey ?? null,
|
|
237
|
+
},
|
|
238
|
+
remediation: 'Append a follow-up change-log entry with the same idempotency key, or close the stale checkpoint with a correction entry explaining the abandoned work.',
|
|
239
|
+
}));
|
|
101
240
|
}
|
|
102
241
|
}
|
|
103
242
|
for (const openIssueEntry of openIssueEntries) {
|
|
@@ -105,17 +244,36 @@ const checkChangeLogWarnings = ({ checkpointEntries, entriesByIdempotencyKey, is
|
|
|
105
244
|
if (ageMs <= OPEN_ISSUE_MAX_AGE_MS || resolvedLedgerIds.has(openIssueEntry.id)) {
|
|
106
245
|
continue;
|
|
107
246
|
}
|
|
108
|
-
|
|
247
|
+
pushFinding(findings, createFinding({
|
|
248
|
+
code: 'open-issue-stale',
|
|
249
|
+
message: `Open issue note ${openIssueEntry.id} is older than 30 days and has no resolution link.`,
|
|
250
|
+
metadata: { entryId: openIssueEntry.id },
|
|
251
|
+
remediation: 'Append a correction or superseding note that links back to the open issue once the follow-up is complete.',
|
|
252
|
+
}));
|
|
109
253
|
}
|
|
110
254
|
};
|
|
111
|
-
const inspectManifestLocation = ({ entry,
|
|
255
|
+
const inspectManifestLocation = ({ entry, findings, latestByPhase, manifest, }) => {
|
|
112
256
|
const manifestLocation = manifest.entryLocations[entry.id];
|
|
113
257
|
if (!manifestLocation) {
|
|
114
|
-
|
|
258
|
+
pushFinding(findings, createFinding({
|
|
259
|
+
code: 'manifest-entry-location-missing',
|
|
260
|
+
message: `Manifest is missing entry location for ${entry.id}.`,
|
|
261
|
+
metadata: { entryId: entry.id },
|
|
262
|
+
remediation: 'Repair manifest.entryLocations so every durable entry has a phase/sequence location before archiving.',
|
|
263
|
+
}));
|
|
115
264
|
return null;
|
|
116
265
|
}
|
|
117
266
|
if (manifestLocation.phase !== entry.phase) {
|
|
118
|
-
|
|
267
|
+
pushFinding(findings, createFinding({
|
|
268
|
+
code: 'manifest-phase-mismatch',
|
|
269
|
+
message: `Manifest phase mismatch for ${entry.id}: expected ${entry.phase}, found ${manifestLocation.phase}.`,
|
|
270
|
+
metadata: {
|
|
271
|
+
entryId: entry.id,
|
|
272
|
+
expectedPhase: entry.phase,
|
|
273
|
+
foundPhase: manifestLocation.phase,
|
|
274
|
+
},
|
|
275
|
+
remediation: 'Move the entry back to the correct phase directory or repair manifest.entryLocations so the recorded phase matches the stored entry.',
|
|
276
|
+
}));
|
|
119
277
|
}
|
|
120
278
|
const currentLatest = latestByPhase.get(entry.phase);
|
|
121
279
|
if (!currentLatest || manifestLocation.sequence > currentLatest.sequence) {
|
|
@@ -123,16 +281,26 @@ const inspectManifestLocation = ({ entry, issues, latestByPhase, manifest, }) =>
|
|
|
123
281
|
}
|
|
124
282
|
return manifestLocation;
|
|
125
283
|
};
|
|
126
|
-
const inspectNarrativeEntry = ({ checkpointEntries, entry,
|
|
284
|
+
const inspectNarrativeEntry = ({ checkpointEntries, entry, findings, openIssueEntries, }) => {
|
|
127
285
|
if (isChangeLogEntry(entry)) {
|
|
128
286
|
if (entry.subkind === 'pre-change-checkpoint') {
|
|
129
287
|
checkpointEntries.push(entry);
|
|
130
288
|
}
|
|
131
289
|
if (entry.smokeResult === 'fail' && !entry.rollbackPlan) {
|
|
132
|
-
|
|
290
|
+
pushFinding(findings, createFinding({
|
|
291
|
+
code: 'change-log-smoke-failure-missing-rollback-plan',
|
|
292
|
+
message: `Change-log entry ${entry.id} has smokeResult=fail but no rollbackPlan.`,
|
|
293
|
+
metadata: { entryId: entry.id },
|
|
294
|
+
remediation: 'Append a correction or follow-up change-log entry documenting the rollback plan before treating the failure as closed.',
|
|
295
|
+
}));
|
|
133
296
|
}
|
|
134
297
|
if (entry.subkind === 'rollback' && !entry.rollsBack) {
|
|
135
|
-
|
|
298
|
+
pushFinding(findings, createFinding({
|
|
299
|
+
code: 'change-log-rollback-missing-target',
|
|
300
|
+
message: `Change-log rollback entry ${entry.id} is missing rollsBack.`,
|
|
301
|
+
metadata: { entryId: entry.id },
|
|
302
|
+
remediation: 'Append a correction or replacement rollback entry with rollsBack pointing at the reverted ledger entry id.',
|
|
303
|
+
}));
|
|
136
304
|
}
|
|
137
305
|
}
|
|
138
306
|
if (isOpenIssueNote(entry)) {
|
|
@@ -147,14 +315,14 @@ const inspectPatchEntry = ({ blobChecks, entry, }) => {
|
|
|
147
315
|
blobChecks.push({ blobHash, entryId: entry.id });
|
|
148
316
|
}
|
|
149
317
|
};
|
|
150
|
-
const inspectDoctorEntry = ({ blobChecks, checkpointEntries,
|
|
318
|
+
const inspectDoctorEntry = ({ blobChecks, checkpointEntries, entriesByIdempotencyKey, entry, findings, latestByPhase, manifest, openIssueEntries, previousByPhase, resolvedLedgerIds, unseenManifestEntryIds, }) => {
|
|
151
319
|
unseenManifestEntryIds.delete(entry.id);
|
|
152
|
-
checkPrevChain(entry,
|
|
320
|
+
checkPrevChain(entry, findings, previousByPhase);
|
|
153
321
|
trackIdempotencyEntry(entry, entriesByIdempotencyKey);
|
|
154
322
|
trackResolutionLinks(entry, resolvedLedgerIds);
|
|
155
323
|
if (!inspectManifestLocation({
|
|
156
324
|
entry,
|
|
157
|
-
|
|
325
|
+
findings,
|
|
158
326
|
latestByPhase,
|
|
159
327
|
manifest,
|
|
160
328
|
})) {
|
|
@@ -163,7 +331,7 @@ const inspectDoctorEntry = ({ blobChecks, checkpointEntries, entry, entriesByIde
|
|
|
163
331
|
inspectNarrativeEntry({
|
|
164
332
|
checkpointEntries,
|
|
165
333
|
entry,
|
|
166
|
-
|
|
334
|
+
findings,
|
|
167
335
|
openIssueEntries,
|
|
168
336
|
});
|
|
169
337
|
inspectPatchEntry({
|
|
@@ -172,7 +340,7 @@ const inspectDoctorEntry = ({ blobChecks, checkpointEntries, entry, entriesByIde
|
|
|
172
340
|
});
|
|
173
341
|
};
|
|
174
342
|
const collectDoctorState = async (workspaceRoot, manifest, readIndex) => {
|
|
175
|
-
const
|
|
343
|
+
const findings = [];
|
|
176
344
|
const previousByPhase = new Map();
|
|
177
345
|
const latestByPhase = new Map();
|
|
178
346
|
const unseenManifestEntryIds = new Set(Object.keys(manifest.entryLocations));
|
|
@@ -183,13 +351,15 @@ const collectDoctorState = async (workspaceRoot, manifest, readIndex) => {
|
|
|
183
351
|
const resolvedLedgerIds = new Set();
|
|
184
352
|
let entryCount = 0;
|
|
185
353
|
const nowMs = Date.now();
|
|
354
|
+
const { scanBatchSize, scanConcurrency } = getLedgerRuntimeConfig();
|
|
186
355
|
const orderedEntries = getOrderedEntryLocations(manifest, readIndex, {});
|
|
187
|
-
checkManifestSequenceOrder(orderedEntries,
|
|
188
|
-
for (let index = 0; index < orderedEntries.length; index +=
|
|
189
|
-
const batch = orderedEntries.slice(index, index +
|
|
356
|
+
checkManifestSequenceOrder(orderedEntries, findings);
|
|
357
|
+
for (let index = 0; index < orderedEntries.length; index += scanBatchSize) {
|
|
358
|
+
const batch = orderedEntries.slice(index, index + scanBatchSize);
|
|
190
359
|
const resolvedEntries = await readManifestEntryBatch({
|
|
191
360
|
allowMissing: true,
|
|
192
361
|
entryLocations: batch,
|
|
362
|
+
entryReadConcurrency: scanConcurrency,
|
|
193
363
|
workspaceRoot,
|
|
194
364
|
});
|
|
195
365
|
for (const resolvedEntry of resolvedEntries) {
|
|
@@ -202,7 +372,7 @@ const collectDoctorState = async (workspaceRoot, manifest, readIndex) => {
|
|
|
202
372
|
checkpointEntries,
|
|
203
373
|
entriesByIdempotencyKey,
|
|
204
374
|
entry: resolvedEntry.entry,
|
|
205
|
-
|
|
375
|
+
findings,
|
|
206
376
|
latestByPhase,
|
|
207
377
|
manifest,
|
|
208
378
|
openIssueEntries,
|
|
@@ -215,7 +385,7 @@ const collectDoctorState = async (workspaceRoot, manifest, readIndex) => {
|
|
|
215
385
|
checkChangeLogWarnings({
|
|
216
386
|
checkpointEntries,
|
|
217
387
|
entriesByIdempotencyKey,
|
|
218
|
-
|
|
388
|
+
findings,
|
|
219
389
|
nowMs,
|
|
220
390
|
openIssueEntries,
|
|
221
391
|
resolvedLedgerIds,
|
|
@@ -223,7 +393,7 @@ const collectDoctorState = async (workspaceRoot, manifest, readIndex) => {
|
|
|
223
393
|
return {
|
|
224
394
|
blobChecks,
|
|
225
395
|
entryCount,
|
|
226
|
-
|
|
396
|
+
findings,
|
|
227
397
|
latestByPhase,
|
|
228
398
|
unseenManifestEntryIds,
|
|
229
399
|
};
|
|
@@ -256,17 +426,14 @@ export const runLedgerDoctor = async (workspaceRoot, options = {}) => {
|
|
|
256
426
|
catch (error) {
|
|
257
427
|
return buildReadFailure(error);
|
|
258
428
|
}
|
|
259
|
-
const { blobChecks, entryCount,
|
|
260
|
-
|
|
429
|
+
const { blobChecks, entryCount, findings, latestByPhase, unseenManifestEntryIds } = doctorState;
|
|
430
|
+
findings.push(...(await checkBlobPresence(workspaceRoot, blobChecks)));
|
|
261
431
|
finalizeManifestChecks({
|
|
262
432
|
entryCount,
|
|
263
|
-
|
|
433
|
+
findings,
|
|
264
434
|
latestByPhase,
|
|
265
435
|
manifest: preparedState.manifest,
|
|
266
436
|
unseenManifestEntryIds,
|
|
267
437
|
});
|
|
268
|
-
return
|
|
269
|
-
issues,
|
|
270
|
-
ok: issues.length === 0,
|
|
271
|
-
};
|
|
438
|
+
return buildDoctorReport(findings);
|
|
272
439
|
};
|
package/dist/helpers.d.ts
CHANGED
|
@@ -4,4 +4,5 @@ export declare const createWorkspaceFixture: () => Promise<{
|
|
|
4
4
|
}>;
|
|
5
5
|
export declare const ageFile: (filePath: string, ageMs?: number) => Promise<void>;
|
|
6
6
|
export declare const waitForFile: (filePath: string, timeoutMs?: number) => Promise<void>;
|
|
7
|
+
export declare const withEnvOverrides: <Value>(overrides: Record<string, string | undefined>, action: () => Promise<Value>) => Promise<Value>;
|
|
7
8
|
//# sourceMappingURL=helpers.d.ts.map
|
package/dist/helpers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB;;;EAuBlC,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,UAAU,MAAM,EAAE,cAAc,kBAG7D,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,UAAU,MAAM,EAAE,kBAAiB,kBAcpE,CAAC"}
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB;;;EAuBlC,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,UAAU,MAAM,EAAE,cAAc,kBAG7D,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,UAAU,MAAM,EAAE,kBAAiB,kBAcpE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,KAAK,EACxC,WAAW,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAC7C,QAAQ,MAAM,OAAO,CAAC,KAAK,CAAC,mBAuB/B,CAAC"}
|
package/dist/helpers.js
CHANGED
|
@@ -36,3 +36,26 @@ export const waitForFile = async (filePath, timeoutMs = 1_000) => {
|
|
|
36
36
|
}
|
|
37
37
|
throw new Error(`Timed out waiting for file: ${filePath}`);
|
|
38
38
|
};
|
|
39
|
+
export const withEnvOverrides = async (overrides, action) => {
|
|
40
|
+
const previousValues = new Map();
|
|
41
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
42
|
+
previousValues.set(key, process.env[key]);
|
|
43
|
+
if (value === undefined) {
|
|
44
|
+
delete process.env[key];
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
process.env[key] = value;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
return await action();
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
for (const [key, value] of previousValues.entries()) {
|
|
54
|
+
if (value === undefined) {
|
|
55
|
+
delete process.env[key];
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
process.env[key] = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { type BuildRecordInput, buildChangeLogRecord, buildCorrectionRecord, buildOperatorDecisionRecord, buildStripDecisionRevertedRecord, buildValidatorResultRecord, } from './builders.ts';
|
|
2
2
|
export { runLedgerCli } from './cli.ts';
|
|
3
3
|
export { type CoverageReport, computeCoverage } from './coverage.ts';
|
|
4
|
+
export { DOCTOR_FINDING_CODES, type DoctorFinding, type DoctorFindingCode, type DoctorFindingMetadataValue, type DoctorReport, runLedgerDoctor, } from './doctor.ts';
|
|
4
5
|
export { type LedgerHandle, type LedgerRenderOptions, type LedgerRenderToOptions, openLedger, type RenderTarget, type RenderWriter, } from './handle.ts';
|
|
5
6
|
export type { LedgerFilter } from './list.ts';
|
|
7
|
+
export { type LedgerRuntimeConfig, getLedgerRuntimeConfig, validateLedgerRuntimeConfig } from './runtime-config.ts';
|
|
6
8
|
export { appendCleanupWaveNote, appendDecompositionWaveNote, appendNote, appendOpenIssueNote, appendSemanticCleanupSummaryNote, appendVerifiedFlowNote, type NoteBody, } from './note.ts';
|
|
7
9
|
export { deriveFilesChangedFromPatch } from './patch-resolver.ts';
|
|
8
10
|
export { type AgentPatchDiff, AgentPatchDiffSchema, AgentPatchEntrySchema, AgentPatchRecordSchema, type ChangeLogEntry, ChangeLogEntrySchema, type ChangeLogFileChange, ChangeLogFileChangeSchema, type ChangeLogParityStatus, ChangeLogParityStatusSchema, type ChangeLogRecord, ChangeLogRecordSchema, type ChangeLogSmokeResult, ChangeLogSmokeResultSchema, type ChangeLogSubkind, ChangeLogSubkindSchema, CorrectionEntrySchema, CorrectionRecordSchema, EmitterSchema, type LedgerEntry, LedgerEntrySchema, type LedgerKind, type LedgerLinks, LedgerLinksSchema, type LedgerPhase, LedgerPhaseSchema, type LedgerRecord, LedgerRecordSchema, type NoteEntry, NoteEntrySchema, type OperatorDecisionAction, OperatorDecisionActionSchema, OperatorDecisionEntrySchema, type OperatorDecisionPayload, OperatorDecisionPayloadSchema, OperatorDecisionRecordSchema, OperatorPatchEntrySchema, OperatorPatchRecordSchema, parseLedgerEntry, parseLedgerRecord, RuntimeEventEntrySchema, StripDecisionRevertedEntrySchema, type StripDecisionRevertedPayload, StripDecisionRevertedPayloadSchema, StripDecisionRevertedRecordSchema, ToolInvocationEntrySchema, ToolInvocationRecordSchema, ValidatorResultEntrySchema, ValidatorResultRecordSchema, } from './schema/entry.ts';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,gBAAgB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC3B,gCAAgC,EAChC,0BAA0B,GAC7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,KAAK,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,UAAU,EACV,KAAK,YAAY,EACjB,KAAK,YAAY,GACpB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACH,qBAAqB,EACrB,2BAA2B,EAC3B,UAAU,EACV,mBAAmB,EACnB,gCAAgC,EAChC,sBAAsB,EACtB,KAAK,QAAQ,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EACH,KAAK,cAAc,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,cAAc,EACnB,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,qBAAqB,EAC1B,2BAA2B,EAC3B,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,0BAA0B,EAC1B,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,YAAY,EACjB,kBAAkB,EAClB,KAAK,SAAS,EACd,eAAe,EACf,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,KAAK,uBAAuB,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,EACvB,gCAAgC,EAChC,KAAK,4BAA4B,EACjC,kCAAkC,EAClC,iCAAiC,EACjC,yBAAyB,EACzB,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,gBAAgB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC3B,gCAAgC,EAChC,0BAA0B,GAC7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,KAAK,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EACH,oBAAoB,EACpB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EACjB,eAAe,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,UAAU,EACV,KAAK,YAAY,EACjB,KAAK,YAAY,GACpB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,mBAAmB,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AACpH,OAAO,EACH,qBAAqB,EACrB,2BAA2B,EAC3B,UAAU,EACV,mBAAmB,EACnB,gCAAgC,EAChC,sBAAsB,EACtB,KAAK,QAAQ,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EACH,KAAK,cAAc,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,cAAc,EACnB,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,qBAAqB,EAC1B,2BAA2B,EAC3B,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,0BAA0B,EAC1B,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,YAAY,EACjB,kBAAkB,EAClB,KAAK,SAAS,EACd,eAAe,EACf,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,KAAK,uBAAuB,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,EACvB,gCAAgC,EAChC,KAAK,4BAA4B,EACjC,kCAAkC,EAClC,iCAAiC,EACjC,yBAAyB,EACzB,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,WAAW,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { buildChangeLogRecord, buildCorrectionRecord, buildOperatorDecisionRecord, buildStripDecisionRevertedRecord, buildValidatorResultRecord, } from "./builders.js";
|
|
2
2
|
export { runLedgerCli } from "./cli.js";
|
|
3
3
|
export { computeCoverage } from "./coverage.js";
|
|
4
|
+
export { DOCTOR_FINDING_CODES, runLedgerDoctor, } from "./doctor.js";
|
|
4
5
|
export { openLedger, } from "./handle.js";
|
|
6
|
+
export { getLedgerRuntimeConfig, validateLedgerRuntimeConfig } from "./runtime-config.js";
|
|
5
7
|
export { appendCleanupWaveNote, appendDecompositionWaveNote, appendNote, appendOpenIssueNote, appendSemanticCleanupSummaryNote, appendVerifiedFlowNote, } from "./note.js";
|
|
6
8
|
export { deriveFilesChangedFromPatch } from "./patch-resolver.js";
|
|
7
9
|
export { AgentPatchDiffSchema, AgentPatchEntrySchema, AgentPatchRecordSchema, ChangeLogEntrySchema, ChangeLogFileChangeSchema, ChangeLogParityStatusSchema, ChangeLogRecordSchema, ChangeLogSmokeResultSchema, ChangeLogSubkindSchema, CorrectionEntrySchema, CorrectionRecordSchema, EmitterSchema, LedgerEntrySchema, LedgerLinksSchema, LedgerPhaseSchema, LedgerRecordSchema, NoteEntrySchema, OperatorDecisionActionSchema, OperatorDecisionEntrySchema, OperatorDecisionPayloadSchema, OperatorDecisionRecordSchema, OperatorPatchEntrySchema, OperatorPatchRecordSchema, parseLedgerEntry, parseLedgerRecord, RuntimeEventEntrySchema, StripDecisionRevertedEntrySchema, StripDecisionRevertedPayloadSchema, StripDecisionRevertedRecordSchema, ToolInvocationEntrySchema, ToolInvocationRecordSchema, ValidatorResultEntrySchema, ValidatorResultRecordSchema, } from "./schema/entry.js";
|
package/dist/list.d.ts
CHANGED
|
@@ -8,9 +8,10 @@ export type LedgerFilter = {
|
|
|
8
8
|
readonly since?: string;
|
|
9
9
|
};
|
|
10
10
|
export declare const getOrderedEntryLocations: (manifest: LedgerManifest, readIndex: LedgerReadIndex, filter: LedgerFilter, direction?: "asc" | "desc") => ManifestEntryLocation[];
|
|
11
|
-
export declare const readManifestEntryBatch: ({ allowMissing, entryLocations, workspaceRoot, }: {
|
|
11
|
+
export declare const readManifestEntryBatch: ({ allowMissing, entryLocations, entryReadConcurrency, workspaceRoot, }: {
|
|
12
12
|
readonly allowMissing?: boolean;
|
|
13
13
|
readonly entryLocations: readonly ManifestEntryLocation[];
|
|
14
|
+
readonly entryReadConcurrency?: number;
|
|
14
15
|
readonly workspaceRoot: string;
|
|
15
16
|
}) => Promise<({
|
|
16
17
|
entry: {
|
package/dist/list.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"AACA,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAG7B,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"AACA,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAG7B,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAoB,MAAM,mBAAmB,CAAC;AAC1G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,MAAM,YAAY,GAAG;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAgDF,eAAO,MAAM,wBAAwB,GACjC,UAAU,cAAc,EACxB,WAAW,eAAe,EAC1B,QAAQ,YAAY,EACpB,YAAW,KAAK,GAAG,MAAc,4BAgBpC,CAAC;AAiCF,eAAO,MAAM,sBAAsB,GAAU,wEAK1C;IACC,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC1D,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAClC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAQI,CAAC;AAsDN,eAAO,MAAM,0BAA0B,GACnC,eAAe,MAAM,EACrB,UAAU,cAAc,EACxB,WAAW,eAAe,EAC1B,SAAQ,YAAiB,EACzB,YAAW,KAAK,GAAG,MAAc,KAClC,aAAa,CAAC,WAAW,CAoC3B,CAAC;AAEF,eAAO,MAAM,WAAW,GACpB,eAAe,MAAM,EACrB,SAAQ,YAAiB,KAC1B,aAAa,CAAC,WAAW,CAG3B,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,eAAe,MAAM,EAAE,SAAQ,YAAiB,KAAG,OAAO,CAAC,WAAW,EAAE,CAM5G,CAAC"}
|
package/dist/list.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mapWithConcurrencyLimit } from "./async.js";
|
|
2
2
|
import { matchesReadIndexFilter, } from "./read-index.js";
|
|
3
|
+
import { getLedgerRuntimeConfig } from "./runtime-config.js";
|
|
3
4
|
import { loadLedgerState } from "./recovery.js";
|
|
4
5
|
import { parseLedgerEntry } from "./schema/entry.js";
|
|
5
6
|
import { readPhaseEntryText } from "./storage/filesystem.js";
|
|
@@ -15,8 +16,6 @@ const matchesFilter = (entry, filter) => {
|
|
|
15
16
|
}
|
|
16
17
|
return true;
|
|
17
18
|
};
|
|
18
|
-
const ENTRY_READ_BATCH_SIZE = 32;
|
|
19
|
-
const ENTRY_READ_CONCURRENCY = 16;
|
|
20
19
|
const getFilteredReadIndexEntries = ({ direction, filter, manifest, readIndex, }) => {
|
|
21
20
|
const sourceEntries = direction === 'asc' ? readIndex.entries : [...readIndex.entries].reverse();
|
|
22
21
|
const filteredEntries = [];
|
|
@@ -71,20 +70,21 @@ const readManifestEntry = async ({ allowMissing, entryId, location, workspaceRoo
|
|
|
71
70
|
throw error;
|
|
72
71
|
}
|
|
73
72
|
};
|
|
74
|
-
export const readManifestEntryBatch = async ({ allowMissing = false, entryLocations, workspaceRoot, }) => mapWithConcurrencyLimit(entryLocations,
|
|
73
|
+
export const readManifestEntryBatch = async ({ allowMissing = false, entryLocations, entryReadConcurrency = getLedgerRuntimeConfig().scanConcurrency, workspaceRoot, }) => mapWithConcurrencyLimit(entryLocations, entryReadConcurrency, async ([entryId, location]) => readManifestEntry({
|
|
75
74
|
allowMissing,
|
|
76
75
|
entryId,
|
|
77
76
|
location,
|
|
78
77
|
workspaceRoot,
|
|
79
78
|
}));
|
|
80
|
-
const collectLimitedEntries = async ({ direction, filter, manifest, readIndex, workspaceRoot, }) => {
|
|
79
|
+
const collectLimitedEntries = async ({ batchSize, direction, entryReadConcurrency, filter, manifest, readIndex, workspaceRoot, }) => {
|
|
81
80
|
const collectedEntries = [];
|
|
82
81
|
const orderedEntries = getOrderedEntryLocations(manifest, readIndex, filter, 'desc');
|
|
83
82
|
const limit = filter.limit ?? 0;
|
|
84
|
-
for (let index = 0; index < orderedEntries.length && collectedEntries.length < limit; index +=
|
|
85
|
-
const batch = orderedEntries.slice(index, index +
|
|
83
|
+
for (let index = 0; index < orderedEntries.length && collectedEntries.length < limit; index += batchSize) {
|
|
84
|
+
const batch = orderedEntries.slice(index, index + batchSize);
|
|
86
85
|
const resolvedEntries = await readManifestEntryBatch({
|
|
87
86
|
entryLocations: batch,
|
|
87
|
+
entryReadConcurrency,
|
|
88
88
|
workspaceRoot,
|
|
89
89
|
});
|
|
90
90
|
for (const resolvedEntry of resolvedEntries) {
|
|
@@ -105,17 +105,27 @@ const collectLimitedEntries = async ({ direction, filter, manifest, readIndex, w
|
|
|
105
105
|
return collectedEntries;
|
|
106
106
|
};
|
|
107
107
|
export const iterateEntriesFromManifest = async function* (workspaceRoot, manifest, readIndex, filter = {}, direction = 'asc') {
|
|
108
|
+
const { scanBatchSize, scanConcurrency } = getLedgerRuntimeConfig();
|
|
108
109
|
if (filter.limit) {
|
|
109
|
-
for (const entry of await collectLimitedEntries({
|
|
110
|
+
for (const entry of await collectLimitedEntries({
|
|
111
|
+
batchSize: scanBatchSize,
|
|
112
|
+
direction,
|
|
113
|
+
entryReadConcurrency: scanConcurrency,
|
|
114
|
+
filter,
|
|
115
|
+
manifest,
|
|
116
|
+
readIndex,
|
|
117
|
+
workspaceRoot,
|
|
118
|
+
})) {
|
|
110
119
|
yield entry;
|
|
111
120
|
}
|
|
112
121
|
return;
|
|
113
122
|
}
|
|
114
123
|
const orderedEntries = getOrderedEntryLocations(manifest, readIndex, filter, direction);
|
|
115
|
-
for (let index = 0; index < orderedEntries.length; index +=
|
|
116
|
-
const batch = orderedEntries.slice(index, index +
|
|
124
|
+
for (let index = 0; index < orderedEntries.length; index += scanBatchSize) {
|
|
125
|
+
const batch = orderedEntries.slice(index, index + scanBatchSize);
|
|
117
126
|
const resolvedEntries = await readManifestEntryBatch({
|
|
118
127
|
entryLocations: batch,
|
|
128
|
+
entryReadConcurrency: scanConcurrency,
|
|
119
129
|
workspaceRoot,
|
|
120
130
|
});
|
|
121
131
|
for (const resolvedEntry of resolvedEntries) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch-resolver.d.ts","sourceRoot":"","sources":["../src/patch-resolver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"patch-resolver.d.ts","sourceRoot":"","sources":["../src/patch-resolver.ts"],"names":[],"mappings":"AASA,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,YAAY,EAEpB,MAAM,mBAAmB,CAAC;AAK3B,KAAK,gBAAgB,GAAG,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,CAAC;AACvE,KAAK,mBAAmB,GAAG,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,CAAC;AAQ7E,KAAK,wBAAwB,GAAG,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC,GAAG;IACxF,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;CAC/B,CAAC;AACF,KAAK,2BAA2B,GAAG,IAAI,CAAC,mBAAmB,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC,GAAG;IAC9F,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,wBAAwB,GAAG,2BAA2B,CAAC;AAsTzF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,GAAI,WAAW,MAAM,KAAG,mBAAmB,EAuClF,CAAC;AAmBF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;AACtC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC"}
|