ushman-ledger 1.2.1 → 1.3.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/AGENTS.md +7 -5
- package/ARCHITECTURE.md +85 -0
- package/CHANGELOG.md +11 -0
- package/README.md +114 -5
- package/TROUBLESHOOTING.md +184 -0
- package/dist/blobs.d.ts +3 -0
- package/dist/blobs.d.ts.map +1 -1
- package/dist/blobs.js +41 -15
- package/dist/builders.d.ts +33 -0
- package/dist/builders.d.ts.map +1 -1
- package/dist/builders.js +10 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +176 -59
- 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 +263 -62
- package/dist/handle.d.ts.map +1 -1
- package/dist/handle.js +67 -30
- 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 +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/list.d.ts +34 -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/process.d.ts +2 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +16 -0
- package/dist/read-index.d.ts +7 -7
- package/dist/read-index.d.ts.map +1 -1
- package/dist/read-index.js +18 -13
- package/dist/record.js +2 -2
- package/dist/recovery.d.ts +8 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +142 -30
- package/dist/render/retro.d.ts.map +1 -1
- package/dist/render/retro.js +4 -1
- package/dist/runtime-config.d.ts +14 -0
- package/dist/runtime-config.d.ts.map +1 -0
- package/dist/runtime-config.js +97 -0
- package/dist/schema/entry-core.d.ts +5 -2
- package/dist/schema/entry-core.d.ts.map +1 -1
- package/dist/schema/entry-core.js +3 -0
- package/dist/schema/entry-read.d.ts +57 -0
- package/dist/schema/entry-read.d.ts.map +1 -1
- package/dist/schema/entry-read.js +9 -1
- package/dist/schema/entry-write.d.ts +51 -0
- package/dist/schema/entry-write.d.ts.map +1 -1
- package/dist/schema/entry-write.js +9 -1
- package/dist/storage/filesystem.d.ts +15 -2
- package/dist/storage/filesystem.d.ts.map +1 -1
- package/dist/storage/filesystem.js +234 -37
- package/dist/storage/lock.d.ts.map +1 -1
- package/dist/storage/lock.js +38 -16
- 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/read-index.js
CHANGED
|
@@ -2,11 +2,10 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import * as v from 'valibot';
|
|
3
3
|
import { mapWithConcurrencyLimit } from "./async.js";
|
|
4
4
|
import { stableStringify } from "./json.js";
|
|
5
|
+
import { getLedgerRuntimeConfig } from "./runtime-config.js";
|
|
5
6
|
import { LEDGER_KINDS, parseLedgerEntry } from "./schema/entry.js";
|
|
6
7
|
import { readPhaseEntryText, resolveLedgerPaths, writeAtomicTextFile } from "./storage/filesystem.js";
|
|
7
8
|
const READ_INDEX_SCHEMA_VERSION = 'ushman-ledger-read-index/v1';
|
|
8
|
-
const ENTRY_READ_BATCH_SIZE = 32;
|
|
9
|
-
const ENTRY_READ_CONCURRENCY = 16;
|
|
10
9
|
const ReadIndexEntrySchema = v.object({
|
|
11
10
|
id: v.pipe(v.string(), v.minLength(1)),
|
|
12
11
|
kind: v.picklist(LEDGER_KINDS),
|
|
@@ -33,6 +32,15 @@ const buildReadIndexEntry = (entry) => ({
|
|
|
33
32
|
kind: entry.kind,
|
|
34
33
|
ts: entry.ts,
|
|
35
34
|
});
|
|
35
|
+
const getCoverageFilesForEntry = (entry) => {
|
|
36
|
+
if (entry.kind === 'stage-write') {
|
|
37
|
+
return [...new Set([entry.filePath, ...(entry.links.affectedFiles ?? [])])];
|
|
38
|
+
}
|
|
39
|
+
if (entry.kind === 'agent-patch' || entry.kind === 'operator-patch') {
|
|
40
|
+
return entry.links.affectedFiles ?? [];
|
|
41
|
+
}
|
|
42
|
+
return [];
|
|
43
|
+
};
|
|
36
44
|
const sortBySequence = (left, right) => left[1].sequence - right[1].sequence;
|
|
37
45
|
const getManifestSequenceLocations = (manifest) => Object.entries(manifest.entryLocations).sort(sortBySequence);
|
|
38
46
|
const mergeSortedUniquePaths = (existingPaths, additionalPaths) => {
|
|
@@ -83,27 +91,26 @@ const readIndexedEntry = async ({ entryId, phase, workspaceRoot, }) => {
|
|
|
83
91
|
const text = await readPhaseEntryText(workspaceRoot, phase, `${entryId}.json`);
|
|
84
92
|
return parseLedgerEntry(JSON.parse(text));
|
|
85
93
|
};
|
|
86
|
-
const readIndexedEntryBatch = async ({ entryLocations, workspaceRoot, }) => mapWithConcurrencyLimit(entryLocations,
|
|
94
|
+
const readIndexedEntryBatch = async ({ entryReadConcurrency, entryLocations, workspaceRoot, }) => mapWithConcurrencyLimit(entryLocations, entryReadConcurrency, async ([entryId, location]) => readIndexedEntry({
|
|
87
95
|
entryId,
|
|
88
96
|
phase: location.phase,
|
|
89
97
|
workspaceRoot,
|
|
90
98
|
}));
|
|
91
99
|
const collectCoveredFiles = (entry, coveredFiles) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
for (const affectedFile of entry.links.affectedFiles ?? []) {
|
|
96
|
-
coveredFiles.add(affectedFile);
|
|
100
|
+
for (const coveredFile of getCoverageFilesForEntry(entry)) {
|
|
101
|
+
coveredFiles.add(coveredFile);
|
|
97
102
|
}
|
|
98
103
|
};
|
|
99
104
|
export const buildReadIndexFromManifest = async (workspaceRoot, manifest) => {
|
|
105
|
+
const { readIndexRebuildBatchSize, readIndexRebuildConcurrency } = getLedgerRuntimeConfig();
|
|
100
106
|
const orderedEntryLocations = getManifestSequenceLocations(manifest);
|
|
101
107
|
const entries = [];
|
|
102
108
|
const coveredFiles = new Set();
|
|
103
|
-
for (let index = 0; index < orderedEntryLocations.length; index +=
|
|
104
|
-
const batch = orderedEntryLocations.slice(index, index +
|
|
109
|
+
for (let index = 0; index < orderedEntryLocations.length; index += readIndexRebuildBatchSize) {
|
|
110
|
+
const batch = orderedEntryLocations.slice(index, index + readIndexRebuildBatchSize);
|
|
105
111
|
const resolvedEntries = await readIndexedEntryBatch({
|
|
106
112
|
entryLocations: batch,
|
|
113
|
+
entryReadConcurrency: readIndexRebuildConcurrency,
|
|
107
114
|
workspaceRoot,
|
|
108
115
|
});
|
|
109
116
|
for (const entry of resolvedEntries) {
|
|
@@ -165,9 +172,7 @@ export const ensureReadIndexUnderLock = async (workspaceRoot, manifest) => {
|
|
|
165
172
|
};
|
|
166
173
|
export const appendEntryToReadIndex = ({ entry, readIndex, sequence, }) => {
|
|
167
174
|
const nextEntries = [...readIndex.entries, buildReadIndexEntry(entry)];
|
|
168
|
-
const nextCoveredFiles =
|
|
169
|
-
? mergeSortedUniquePaths(readIndex.coveredFiles, entry.links.affectedFiles ?? [])
|
|
170
|
-
: [...readIndex.coveredFiles];
|
|
175
|
+
const nextCoveredFiles = mergeSortedUniquePaths(readIndex.coveredFiles, getCoverageFilesForEntry(entry));
|
|
171
176
|
return buildReadIndex({
|
|
172
177
|
coveredFiles: nextCoveredFiles,
|
|
173
178
|
entries: nextEntries,
|
package/dist/record.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import * as v from 'valibot';
|
|
4
4
|
import { sha256Hex, stableStringify } from "./json.js";
|
|
5
|
-
import { updateManifestForEntry } from "./manifest-update.js";
|
|
5
|
+
import { getNextManifestSequence, updateManifestForEntry } from "./manifest-update.js";
|
|
6
6
|
import { resolvePatchRecord } from "./patch-resolver.js";
|
|
7
7
|
import { appendEntryToReadIndex, saveReadIndex } from "./read-index.js";
|
|
8
8
|
import { reconcileLedgerStateUnderLock, removePendingCommit, writePendingCommit } from "./recovery.js";
|
|
@@ -105,7 +105,7 @@ export const appendRecord = async (workspaceRoot, input) => {
|
|
|
105
105
|
id: existingId,
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
-
const nextSequence = manifest.lastSequence
|
|
108
|
+
const nextSequence = getNextManifestSequence(manifest.lastSequence);
|
|
109
109
|
const { idempotencyKey: _idempotencyKey, ...recordWithoutIdempotencyKey } = normalizedRecord;
|
|
110
110
|
const entryWithoutId = {
|
|
111
111
|
...recordWithoutIdempotencyKey,
|
package/dist/recovery.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { type LedgerReadIndex } from './read-index.ts';
|
|
2
2
|
import { type LedgerEntry } from './schema/entry.ts';
|
|
3
3
|
import type { LedgerManifest } from './schema/manifest.ts';
|
|
4
|
+
export type PendingCommitQuarantine = {
|
|
5
|
+
readonly commitPath: string;
|
|
6
|
+
readonly metadataPath: string | null;
|
|
7
|
+
readonly originalFileName: string;
|
|
8
|
+
readonly quarantinedAt: string | null;
|
|
9
|
+
readonly reason: string;
|
|
10
|
+
};
|
|
4
11
|
export type PreparedLedgerState = {
|
|
5
12
|
readonly manifest: LedgerManifest;
|
|
6
13
|
readonly readIndex: LedgerReadIndex;
|
|
@@ -12,6 +19,7 @@ export declare const writePendingCommit: ({ entry, logicalHash, manifest, worksp
|
|
|
12
19
|
readonly workspaceRoot: string;
|
|
13
20
|
}) => Promise<string>;
|
|
14
21
|
export declare const removePendingCommit: (filePath: string) => Promise<void>;
|
|
22
|
+
export declare const listPendingCommitQuarantines: (workspaceRoot: string) => Promise<PendingCommitQuarantine[]>;
|
|
15
23
|
export declare const reconcilePendingCommitsUnderLock: (workspaceRoot: string) => Promise<{
|
|
16
24
|
archives: {
|
|
17
25
|
createdAt: string;
|
package/dist/recovery.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAOA,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEjF,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA4C3D,MAAM,MAAM,uBAAuB,GAAG;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,mBAAmB,GAAG;IAC9B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;CACvC,CAAC;AAoNF,eAAO,MAAM,kBAAkB,GAAU,kDAKtC;IACC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAClC,oBAeA,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAU,UAAU,MAAM,kBAEzD,CAAC;AAaF,eAAO,MAAM,4BAA4B,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,uBAAuB,EAAE,CAsB3G,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAAU,eAAe,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuD3E,CAAC;AAEF,eAAO,MAAM,6BAA6B,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAQtG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAQxF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,eAAe,MAAM,kBAE7D,CAAC"}
|
package/dist/recovery.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { readdir, readFile, rename, rm, stat } from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import * as v from 'valibot';
|
|
5
|
+
import { mapWithConcurrencyLimit } from "./async.js";
|
|
4
6
|
import { reconcilePendingArchivesUnderLock } from "./archive-journal.js";
|
|
5
7
|
import { getNextManifestSequence, updateManifestForEntry } from "./manifest-update.js";
|
|
6
8
|
import { ensureReadIndexUnderLock } from "./read-index.js";
|
|
9
|
+
import { getLedgerRuntimeConfig } from "./runtime-config.js";
|
|
7
10
|
import { LedgerEntrySchema } from "./schema/entry.js";
|
|
8
11
|
import { cleanupStaleTempFiles, ensureLedgerDirectories, readManifest, resolveLedgerPaths, saveManifest, writeAtomicJsonFile, writeEntryFile, } from "./storage/filesystem.js";
|
|
9
12
|
import { acquireLock } from "./storage/lock.js";
|
|
10
13
|
const PendingCommitSchemaVersion = 'ushman-ledger-pending-commit/v1';
|
|
14
|
+
const PendingCommitQuarantineSchemaVersion = 'ushman-ledger-pending-commit-quarantine/v1';
|
|
11
15
|
// Pending commits capture the intended sequence and logical hash before the
|
|
12
16
|
// entry file and manifest update diverge, so recovery can replay safely.
|
|
13
17
|
const PendingCommitSchema = v.object({
|
|
@@ -18,6 +22,12 @@ const PendingCommitSchema = v.object({
|
|
|
18
22
|
schemaVersion: v.literal(PendingCommitSchemaVersion),
|
|
19
23
|
sequence: v.pipe(v.number(), v.integer(), v.minValue(1)),
|
|
20
24
|
});
|
|
25
|
+
const PendingCommitQuarantineMetadataSchema = v.object({
|
|
26
|
+
originalFileName: v.pipe(v.string(), v.minLength(1)),
|
|
27
|
+
quarantinedAt: v.pipe(v.string(), v.isoTimestamp()),
|
|
28
|
+
reason: v.pipe(v.string(), v.minLength(1)),
|
|
29
|
+
schemaVersion: v.literal(PendingCommitQuarantineSchemaVersion),
|
|
30
|
+
});
|
|
21
31
|
const formatSequence = (sequence) => sequence.toString().padStart(8, '0');
|
|
22
32
|
const PendingCommitFileNameSchema = v.object({
|
|
23
33
|
entryId: v.pipe(v.string(), v.minLength(1)),
|
|
@@ -29,10 +39,15 @@ const parsePendingCommitFileName = (name) => {
|
|
|
29
39
|
if (!match) {
|
|
30
40
|
return null;
|
|
31
41
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
try {
|
|
43
|
+
return v.parse(PendingCommitFileNameSchema, {
|
|
44
|
+
entryId: match[2],
|
|
45
|
+
sequence: Number.parseInt(match[1], 10),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
36
51
|
};
|
|
37
52
|
const readPendingCommit = async (filePath) => {
|
|
38
53
|
try {
|
|
@@ -43,32 +58,68 @@ const readPendingCommit = async (filePath) => {
|
|
|
43
58
|
throw new Error(`Invalid pending commit at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
44
59
|
}
|
|
45
60
|
};
|
|
46
|
-
const
|
|
61
|
+
const listPendingCommitFiles = async (workspaceRoot) => {
|
|
47
62
|
const paths = await ensureLedgerDirectories(workspaceRoot);
|
|
48
63
|
const entries = await readdir(paths.pendingCommitsDir, { withFileTypes: true });
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
const listing = {
|
|
65
|
+
invalidFiles: [],
|
|
66
|
+
pendingFiles: [],
|
|
67
|
+
};
|
|
68
|
+
for (const entry of entries) {
|
|
69
|
+
if (!entry.isFile() || !entry.name.endsWith('.json')) {
|
|
70
|
+
continue;
|
|
54
71
|
}
|
|
72
|
+
const filePath = path.join(paths.pendingCommitsDir, entry.name);
|
|
55
73
|
const parsed = parsePendingCommitFileName(entry.name);
|
|
56
74
|
if (!parsed) {
|
|
57
|
-
|
|
75
|
+
listing.invalidFiles.push({
|
|
76
|
+
filePath,
|
|
77
|
+
reason: `Invalid pending commit file name: ${entry.name}`,
|
|
78
|
+
});
|
|
79
|
+
continue;
|
|
58
80
|
}
|
|
59
|
-
|
|
81
|
+
listing.pendingFiles.push({
|
|
60
82
|
...parsed,
|
|
61
|
-
filePath
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
83
|
+
filePath,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
listing.pendingFiles.sort((left, right) => left.sequence === right.sequence ? left.entryId.localeCompare(right.entryId) : left.sequence - right.sequence);
|
|
87
|
+
return listing;
|
|
88
|
+
};
|
|
89
|
+
const formatRecoveryError = (error) => (error instanceof Error ? error.message : String(error));
|
|
90
|
+
const writeQuarantineMetadata = async ({ metadataPath, originalFileName, reason, }) => {
|
|
91
|
+
try {
|
|
92
|
+
await writeAtomicJsonFile(metadataPath, v.parse(PendingCommitQuarantineMetadataSchema, {
|
|
93
|
+
originalFileName,
|
|
94
|
+
quarantinedAt: new Date().toISOString(),
|
|
95
|
+
reason,
|
|
96
|
+
schemaVersion: PendingCommitQuarantineSchemaVersion,
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// The journal is already quarantined; metadata loss should not block recovery.
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const quarantinePendingCommit = async ({ filePath, reason, workspaceRoot, }) => {
|
|
104
|
+
const paths = await ensureLedgerDirectories(workspaceRoot);
|
|
105
|
+
const originalFileName = path.basename(filePath);
|
|
106
|
+
const quarantineBaseName = `${path.basename(filePath, '.json')}.quarantined.${Date.now()}.${randomUUID()}`;
|
|
107
|
+
const quarantinePath = path.join(paths.pendingCommitQuarantineDir, `${quarantineBaseName}.json`);
|
|
108
|
+
const metadataPath = path.join(paths.pendingCommitQuarantineDir, `${quarantineBaseName}.meta.json`);
|
|
109
|
+
try {
|
|
110
|
+
await rename(filePath, quarantinePath);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (error.code === 'ENOENT') {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
await writeQuarantineMetadata({
|
|
119
|
+
metadataPath,
|
|
120
|
+
originalFileName,
|
|
121
|
+
reason,
|
|
122
|
+
});
|
|
72
123
|
};
|
|
73
124
|
const ensurePendingCommitEntryFile = async (workspaceRoot, pending) => {
|
|
74
125
|
const entryPath = path.join(resolveLedgerPaths(workspaceRoot).phaseDir(pending.entry.phase), `${pending.entry.id}.json`);
|
|
@@ -141,21 +192,82 @@ export const writePendingCommit = async ({ entry, logicalHash, manifest, workspa
|
|
|
141
192
|
export const removePendingCommit = async (filePath) => {
|
|
142
193
|
await rm(filePath, { force: true });
|
|
143
194
|
};
|
|
195
|
+
const readQuarantineMetadata = async (metadataPath) => {
|
|
196
|
+
try {
|
|
197
|
+
const text = await readFile(metadataPath, 'utf8');
|
|
198
|
+
return v.parse(PendingCommitQuarantineMetadataSchema, JSON.parse(text));
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
export const listPendingCommitQuarantines = async (workspaceRoot) => {
|
|
205
|
+
const paths = await ensureLedgerDirectories(workspaceRoot);
|
|
206
|
+
const { scanConcurrency } = getLedgerRuntimeConfig();
|
|
207
|
+
const entries = await readdir(paths.pendingCommitQuarantineDir, { withFileTypes: true });
|
|
208
|
+
const quarantinedCommitFiles = entries
|
|
209
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.json') && !entry.name.endsWith('.meta.json'))
|
|
210
|
+
.map((entry) => entry.name)
|
|
211
|
+
.sort((left, right) => left.localeCompare(right));
|
|
212
|
+
return mapWithConcurrencyLimit(quarantinedCommitFiles, scanConcurrency, async (fileName) => {
|
|
213
|
+
const baseName = fileName.slice(0, -'.json'.length);
|
|
214
|
+
const commitPath = path.join(paths.pendingCommitQuarantineDir, fileName);
|
|
215
|
+
const metadataPath = path.join(paths.pendingCommitQuarantineDir, `${baseName}.meta.json`);
|
|
216
|
+
const metadata = await readQuarantineMetadata(metadataPath);
|
|
217
|
+
return {
|
|
218
|
+
commitPath,
|
|
219
|
+
metadataPath: metadata ? metadataPath : null,
|
|
220
|
+
originalFileName: metadata?.originalFileName ?? fileName,
|
|
221
|
+
quarantinedAt: metadata?.quarantinedAt ?? null,
|
|
222
|
+
reason: metadata?.reason ?? 'Missing or invalid pending commit quarantine metadata.',
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
};
|
|
144
226
|
export const reconcilePendingCommitsUnderLock = async (workspaceRoot) => {
|
|
145
227
|
await cleanupStaleTempFiles(workspaceRoot);
|
|
146
228
|
let manifest = await readManifest(workspaceRoot);
|
|
147
|
-
const
|
|
229
|
+
const { invalidFiles, pendingFiles } = await listPendingCommitFiles(workspaceRoot);
|
|
148
230
|
const processedPendingFiles = [];
|
|
149
231
|
let manifestChanged = false;
|
|
150
|
-
for (const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
232
|
+
for (const invalidFile of invalidFiles) {
|
|
233
|
+
await quarantinePendingCommit({
|
|
234
|
+
filePath: invalidFile.filePath,
|
|
235
|
+
reason: invalidFile.reason,
|
|
154
236
|
workspaceRoot,
|
|
155
237
|
});
|
|
238
|
+
}
|
|
239
|
+
for (const pendingCommitFile of pendingFiles) {
|
|
240
|
+
let pending;
|
|
241
|
+
try {
|
|
242
|
+
pending = await readPendingCommit(pendingCommitFile.filePath);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
await quarantinePendingCommit({
|
|
246
|
+
filePath: pendingCommitFile.filePath,
|
|
247
|
+
reason: formatRecoveryError(error),
|
|
248
|
+
workspaceRoot,
|
|
249
|
+
});
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
let replayed;
|
|
253
|
+
try {
|
|
254
|
+
replayed = await applyPendingCommit({
|
|
255
|
+
manifest,
|
|
256
|
+
pending,
|
|
257
|
+
workspaceRoot,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
await quarantinePendingCommit({
|
|
262
|
+
filePath: pendingCommitFile.filePath,
|
|
263
|
+
reason: formatRecoveryError(error),
|
|
264
|
+
workspaceRoot,
|
|
265
|
+
});
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
156
268
|
manifest = replayed.manifest;
|
|
157
269
|
manifestChanged = manifestChanged || replayed.didChangeManifest;
|
|
158
|
-
processedPendingFiles.push(
|
|
270
|
+
processedPendingFiles.push(pendingCommitFile.filePath);
|
|
159
271
|
}
|
|
160
272
|
if (manifestChanged) {
|
|
161
273
|
await saveManifest(workspaceRoot, manifest);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retro.d.ts","sourceRoot":"","sources":["../../src/render/retro.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"retro.d.ts","sourceRoot":"","sources":["../../src/render/retro.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA+HtD,eAAO,MAAM,mBAAmB,GAAU,wBAGvC;IACC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC9B,KAAG,OAAO,CAAC,MAAM,CAgDjB,CAAC"}
|
package/dist/render/retro.js
CHANGED
|
@@ -14,7 +14,10 @@ const createRetroBuckets = () => ({
|
|
|
14
14
|
});
|
|
15
15
|
const isProblemEntry = (entry) => (entry.kind === 'note' && entry.subkind === 'regression') ||
|
|
16
16
|
(entry.kind === 'runtime-event' && entry.level === 'error');
|
|
17
|
-
const isToolEntry = (entry) => entry.kind === 'tool-invocation' ||
|
|
17
|
+
const isToolEntry = (entry) => entry.kind === 'tool-invocation' ||
|
|
18
|
+
entry.kind === 'stage-write' ||
|
|
19
|
+
entry.kind === 'agent-patch' ||
|
|
20
|
+
entry.kind === 'operator-patch';
|
|
18
21
|
const isToolingEntry = (entry) => (entry.kind === 'note' && entry.subkind === 'automation') ||
|
|
19
22
|
(entry.kind === 'note' && entry.subkind === 'tooling-gap');
|
|
20
23
|
const isRetroNote = (entry) => entry.kind === 'note' && entry.subkind === 'retro';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type LedgerRuntimeConfig = {
|
|
2
|
+
readonly blobHashConcurrency: number;
|
|
3
|
+
readonly coverageFileStatConcurrency: number;
|
|
4
|
+
readonly doctorCheckpointMaxAgeMs: number;
|
|
5
|
+
readonly doctorOpenIssueMaxAgeMs: number;
|
|
6
|
+
readonly maxPatchBytes: number;
|
|
7
|
+
readonly readIndexRebuildBatchSize: number;
|
|
8
|
+
readonly readIndexRebuildConcurrency: number;
|
|
9
|
+
readonly scanBatchSize: number;
|
|
10
|
+
readonly scanConcurrency: number;
|
|
11
|
+
};
|
|
12
|
+
export declare const validateLedgerRuntimeConfig: (env?: NodeJS.ProcessEnv) => void;
|
|
13
|
+
export declare const getLedgerRuntimeConfig: (env?: NodeJS.ProcessEnv) => LedgerRuntimeConfig;
|
|
14
|
+
//# sourceMappingURL=runtime-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-config.d.ts","sourceRoot":"","sources":["../src/runtime-config.ts"],"names":[],"mappings":"AAoCA,MAAM,MAAM,mBAAmB,GAAG;IAC9B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,2BAA2B,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAC;IAC1C,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,yBAAyB,EAAE,MAAM,CAAC;IAC3C,QAAQ,CAAC,2BAA2B,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CACpC,CAAC;AAiEF,eAAO,MAAM,2BAA2B,GAAI,MAAK,MAAM,CAAC,UAAwB,SAE/E,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,mBAgB7E,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const DEFAULT_SCAN_BATCH_SIZE = 32;
|
|
2
|
+
const DEFAULT_SCAN_CONCURRENCY = 16;
|
|
3
|
+
const DEFAULT_MAX_PATCH_BYTES = 10 * 1024 * 1024;
|
|
4
|
+
const DEFAULT_DOCTOR_CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1_000;
|
|
5
|
+
const DEFAULT_DOCTOR_OPEN_ISSUE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1_000;
|
|
6
|
+
const RUNTIME_CONFIG_ENV_VARS = [
|
|
7
|
+
'USHMAN_LEDGER_BLOB_HASH_CONCURRENCY',
|
|
8
|
+
'USHMAN_LEDGER_COVERAGE_FILE_STAT_CONCURRENCY',
|
|
9
|
+
'USHMAN_LEDGER_DOCTOR_CHECKPOINT_MAX_AGE_MS',
|
|
10
|
+
'USHMAN_LEDGER_DOCTOR_OPEN_ISSUE_MAX_AGE_MS',
|
|
11
|
+
'USHMAN_LEDGER_MAX_PATCH_BYTES',
|
|
12
|
+
'USHMAN_LEDGER_READ_INDEX_REBUILD_BATCH_SIZE',
|
|
13
|
+
'USHMAN_LEDGER_READ_INDEX_REBUILD_CONCURRENCY',
|
|
14
|
+
'USHMAN_LEDGER_SCAN_BATCH_SIZE',
|
|
15
|
+
'USHMAN_LEDGER_SCAN_CONCURRENCY',
|
|
16
|
+
];
|
|
17
|
+
const parsePositiveIntegerEnv = ({ defaultValue, env, envVar, }) => {
|
|
18
|
+
const rawValue = env[envVar];
|
|
19
|
+
if (!rawValue) {
|
|
20
|
+
return defaultValue;
|
|
21
|
+
}
|
|
22
|
+
if (!/^[1-9]\d*$/u.test(rawValue)) {
|
|
23
|
+
throw new Error(`Invalid ${envVar} value: ${rawValue}. Expected a positive integer.`);
|
|
24
|
+
}
|
|
25
|
+
return Number.parseInt(rawValue, 10);
|
|
26
|
+
};
|
|
27
|
+
let processEnvRuntimeConfigCache;
|
|
28
|
+
const getRuntimeConfigSignature = (env) => RUNTIME_CONFIG_ENV_VARS.map((envVar) => `${envVar}=${env[envVar] ?? ''}`).join('\u0000');
|
|
29
|
+
const buildLedgerRuntimeConfig = (env) => {
|
|
30
|
+
const scanBatchSize = parsePositiveIntegerEnv({
|
|
31
|
+
defaultValue: DEFAULT_SCAN_BATCH_SIZE,
|
|
32
|
+
env,
|
|
33
|
+
envVar: 'USHMAN_LEDGER_SCAN_BATCH_SIZE',
|
|
34
|
+
});
|
|
35
|
+
const scanConcurrency = parsePositiveIntegerEnv({
|
|
36
|
+
defaultValue: DEFAULT_SCAN_CONCURRENCY,
|
|
37
|
+
env,
|
|
38
|
+
envVar: 'USHMAN_LEDGER_SCAN_CONCURRENCY',
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
blobHashConcurrency: parsePositiveIntegerEnv({
|
|
42
|
+
defaultValue: scanConcurrency,
|
|
43
|
+
env,
|
|
44
|
+
envVar: 'USHMAN_LEDGER_BLOB_HASH_CONCURRENCY',
|
|
45
|
+
}),
|
|
46
|
+
coverageFileStatConcurrency: parsePositiveIntegerEnv({
|
|
47
|
+
defaultValue: scanConcurrency,
|
|
48
|
+
env,
|
|
49
|
+
envVar: 'USHMAN_LEDGER_COVERAGE_FILE_STAT_CONCURRENCY',
|
|
50
|
+
}),
|
|
51
|
+
doctorCheckpointMaxAgeMs: parsePositiveIntegerEnv({
|
|
52
|
+
defaultValue: DEFAULT_DOCTOR_CHECKPOINT_MAX_AGE_MS,
|
|
53
|
+
env,
|
|
54
|
+
envVar: 'USHMAN_LEDGER_DOCTOR_CHECKPOINT_MAX_AGE_MS',
|
|
55
|
+
}),
|
|
56
|
+
doctorOpenIssueMaxAgeMs: parsePositiveIntegerEnv({
|
|
57
|
+
defaultValue: DEFAULT_DOCTOR_OPEN_ISSUE_MAX_AGE_MS,
|
|
58
|
+
env,
|
|
59
|
+
envVar: 'USHMAN_LEDGER_DOCTOR_OPEN_ISSUE_MAX_AGE_MS',
|
|
60
|
+
}),
|
|
61
|
+
maxPatchBytes: parsePositiveIntegerEnv({
|
|
62
|
+
defaultValue: DEFAULT_MAX_PATCH_BYTES,
|
|
63
|
+
env,
|
|
64
|
+
envVar: 'USHMAN_LEDGER_MAX_PATCH_BYTES',
|
|
65
|
+
}),
|
|
66
|
+
readIndexRebuildBatchSize: parsePositiveIntegerEnv({
|
|
67
|
+
defaultValue: scanBatchSize,
|
|
68
|
+
env,
|
|
69
|
+
envVar: 'USHMAN_LEDGER_READ_INDEX_REBUILD_BATCH_SIZE',
|
|
70
|
+
}),
|
|
71
|
+
readIndexRebuildConcurrency: parsePositiveIntegerEnv({
|
|
72
|
+
defaultValue: scanConcurrency,
|
|
73
|
+
env,
|
|
74
|
+
envVar: 'USHMAN_LEDGER_READ_INDEX_REBUILD_CONCURRENCY',
|
|
75
|
+
}),
|
|
76
|
+
scanBatchSize,
|
|
77
|
+
scanConcurrency,
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
export const validateLedgerRuntimeConfig = (env = process.env) => {
|
|
81
|
+
void getLedgerRuntimeConfig(env);
|
|
82
|
+
};
|
|
83
|
+
export const getLedgerRuntimeConfig = (env = process.env) => {
|
|
84
|
+
if (env !== process.env) {
|
|
85
|
+
return buildLedgerRuntimeConfig(env);
|
|
86
|
+
}
|
|
87
|
+
const signature = getRuntimeConfigSignature(env);
|
|
88
|
+
if (processEnvRuntimeConfigCache?.signature === signature) {
|
|
89
|
+
return processEnvRuntimeConfigCache.config;
|
|
90
|
+
}
|
|
91
|
+
const config = buildLedgerRuntimeConfig(env);
|
|
92
|
+
processEnvRuntimeConfigCache = {
|
|
93
|
+
config,
|
|
94
|
+
signature,
|
|
95
|
+
};
|
|
96
|
+
return config;
|
|
97
|
+
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
2
|
export declare const LedgerSchemaVersion: "ushman-ledger-entry/v1";
|
|
3
3
|
export declare const LEDGER_PHASES: readonly ["capture", "intake", "seed", "vendor-extract", "cleanup", "parity", "characterize", "equiv", "analyze", "recover", "ship", "migration"];
|
|
4
|
-
export declare const LEDGER_KINDS: readonly ["tool-invocation", "agent-patch", "operator-patch", "operator-decision", "validator-result", "runtime-event", "note", "correction", "strip-decision-reverted", "change-log"];
|
|
4
|
+
export declare const LEDGER_KINDS: readonly ["tool-invocation", "stage-write", "agent-patch", "operator-patch", "operator-decision", "validator-result", "runtime-event", "note", "correction", "strip-decision-reverted", "change-log"];
|
|
5
|
+
export declare const STAGE_WRITE_STAGES: readonly ["intake", "seed", "vendor-extract", "cleanup", "candidate-promotion"];
|
|
5
6
|
export declare const OPERATOR_DECISION_ACTIONS: readonly ["bypass-doctor", "skip-check", "override-strip-decision", "override-ship-state", "manual-parity-assertion", "ledger-hand-edit", "escalation"];
|
|
6
7
|
export declare const NonEmptyTrimmedStringSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
7
8
|
export declare const WorkspaceRelativePathSchema: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.CheckAction<string, "Expected a normalized workspace-relative path.">]>;
|
|
8
9
|
export declare const LedgerPhaseSchema: v.PicklistSchema<readonly ["capture", "intake", "seed", "vendor-extract", "cleanup", "parity", "characterize", "equiv", "analyze", "recover", "ship", "migration"], undefined>;
|
|
9
|
-
export declare const LedgerKindSchema: v.PicklistSchema<readonly ["tool-invocation", "agent-patch", "operator-patch", "operator-decision", "validator-result", "runtime-event", "note", "correction", "strip-decision-reverted", "change-log"], undefined>;
|
|
10
|
+
export declare const LedgerKindSchema: v.PicklistSchema<readonly ["tool-invocation", "stage-write", "agent-patch", "operator-patch", "operator-decision", "validator-result", "runtime-event", "note", "correction", "strip-decision-reverted", "change-log"], undefined>;
|
|
11
|
+
export declare const StageWriteStageSchema: v.PicklistSchema<readonly ["intake", "seed", "vendor-extract", "cleanup", "candidate-promotion"], undefined>;
|
|
10
12
|
export declare const OperatorDecisionActionSchema: v.PicklistSchema<readonly ["bypass-doctor", "skip-check", "override-strip-decision", "override-ship-state", "manual-parity-assertion", "ledger-hand-edit", "escalation"], undefined>;
|
|
11
13
|
export declare const ChangeLogSubkindSchema: v.PicklistSchema<readonly ["pre-change-checkpoint", "semantic-cleanup", "vendor-extract", "decomposition", "rollback", "hotfix", "smoke"], undefined>;
|
|
12
14
|
export declare const ChangeLogSmokeResultSchema: v.PicklistSchema<readonly ["pass", "fail", "partial", "not-run"], undefined>;
|
|
@@ -105,6 +107,7 @@ export type LedgerLinks = v.InferOutput<typeof LedgerLinksSchema>;
|
|
|
105
107
|
export type LedgerPhase = v.InferOutput<typeof LedgerPhaseSchema>;
|
|
106
108
|
export type OperatorDecisionAction = v.InferOutput<typeof OperatorDecisionActionSchema>;
|
|
107
109
|
export type OperatorDecisionPayload = v.InferOutput<typeof OperatorDecisionPayloadSchema>;
|
|
110
|
+
export type StageWriteStage = v.InferOutput<typeof StageWriteStageSchema>;
|
|
108
111
|
export type StripDecisionRevertedPayload = v.InferOutput<typeof StripDecisionRevertedPayloadSchema>;
|
|
109
112
|
export type WorkspaceRelativePath = v.InferOutput<typeof WorkspaceRelativePathSchema>;
|
|
110
113
|
//# sourceMappingURL=entry-core.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-core.d.ts","sourceRoot":"","sources":["../../src/schema/entry-core.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAE7B,eAAO,MAAM,mBAAmB,EAAG,wBAAiC,CAAC;AAErE,eAAO,MAAM,aAAa,mJAahB,CAAC;AAEX,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"entry-core.d.ts","sourceRoot":"","sources":["../../src/schema/entry-core.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAE7B,eAAO,MAAM,mBAAmB,EAAG,wBAAiC,CAAC;AAErE,eAAO,MAAM,aAAa,mJAahB,CAAC;AAEX,eAAO,MAAM,YAAY,uMAYf,CAAC;AAEX,eAAO,MAAM,kBAAkB,iFAAkF,CAAC;AAElH,eAAO,MAAM,yBAAyB,yJAQ5B,CAAC;AAiDX,eAAO,MAAM,2BAA2B,+GAA+C,CAAC;AAExF,eAAO,MAAM,2BAA2B,0KAIvC,CAAC;AAIF,eAAO,MAAM,iBAAiB,gLAA4B,CAAC;AAC3D,eAAO,MAAM,gBAAgB,oOAA2B,CAAC;AACzD,eAAO,MAAM,qBAAqB,8GAAiC,CAAC;AACpE,eAAO,MAAM,4BAA4B,sLAAwC,CAAC;AAElF,eAAO,MAAM,sBAAsB,uJAAkC,CAAC;AACtE,eAAO,MAAM,0BAA0B,8EAAuC,CAAC;AAC/E,eAAO,MAAM,2BAA2B,6EAAyC,CAAC;AAElF,eAAO,MAAM,aAAa;;;;aAIxB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;8BAa7B,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;CAUlC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;CAOlC,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;;;aAK/B,CAAC;AAEH,eAAO,MAAM,6BAA6B;;;;aAIxC,CAAC;AAEH,eAAO,MAAM,kCAAkC;;;;aAI7C,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;aAIpC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACxE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAClF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,2BAA2B,CAAC,CAAC;AACtF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACpF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC5E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAChE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAClE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAClE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,4BAA4B,CAAC,CAAC;AACxF,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAC1F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC1E,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,kCAAkC,CAAC,CAAC;AACpG,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|
|
@@ -17,6 +17,7 @@ export const LEDGER_PHASES = [
|
|
|
17
17
|
];
|
|
18
18
|
export const LEDGER_KINDS = [
|
|
19
19
|
'tool-invocation',
|
|
20
|
+
'stage-write',
|
|
20
21
|
'agent-patch',
|
|
21
22
|
'operator-patch',
|
|
22
23
|
'operator-decision',
|
|
@@ -27,6 +28,7 @@ export const LEDGER_KINDS = [
|
|
|
27
28
|
'strip-decision-reverted',
|
|
28
29
|
'change-log',
|
|
29
30
|
];
|
|
31
|
+
export const STAGE_WRITE_STAGES = ['intake', 'seed', 'vendor-extract', 'cleanup', 'candidate-promotion'];
|
|
30
32
|
export const OPERATOR_DECISION_ACTIONS = [
|
|
31
33
|
'bypass-doctor',
|
|
32
34
|
'skip-check',
|
|
@@ -80,6 +82,7 @@ export const WorkspaceRelativePathSchema = v.pipe(v.string(), v.minLength(1), v.
|
|
|
80
82
|
const SHA256HexSchema = v.pipe(v.string(), v.regex(SHA256_HEX_PATTERN, 'Expected a lowercase SHA-256 hex digest.'));
|
|
81
83
|
export const LedgerPhaseSchema = v.picklist(LEDGER_PHASES);
|
|
82
84
|
export const LedgerKindSchema = v.picklist(LEDGER_KINDS);
|
|
85
|
+
export const StageWriteStageSchema = v.picklist(STAGE_WRITE_STAGES);
|
|
83
86
|
export const OperatorDecisionActionSchema = v.picklist(OPERATOR_DECISION_ACTIONS);
|
|
84
87
|
const StripDecisionInvalidatedStageSchema = v.picklist(STRIP_DECISION_INVALIDATED_STAGES);
|
|
85
88
|
export const ChangeLogSubkindSchema = v.picklist(CHANGE_LOG_SUBKINDS);
|
|
@@ -28,6 +28,35 @@ export declare const ToolInvocationEntrySchema: v.ObjectSchema<{
|
|
|
28
28
|
readonly summary: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
29
29
|
readonly ts: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, undefined>]>;
|
|
30
30
|
}, undefined>;
|
|
31
|
+
export declare const StageWriteEntrySchema: v.ObjectSchema<{
|
|
32
|
+
readonly filePath: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.CheckAction<string, "Expected a normalized workspace-relative path.">]>;
|
|
33
|
+
readonly kind: v.LiteralSchema<"stage-write", undefined>;
|
|
34
|
+
readonly rationale: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
35
|
+
readonly stage: v.PicklistSchema<readonly ["intake", "seed", "vendor-extract", "cleanup", "candidate-promotion"], undefined>;
|
|
36
|
+
readonly details: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>, undefined>;
|
|
37
|
+
readonly emitter: v.ObjectSchema<{
|
|
38
|
+
readonly tool: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
39
|
+
readonly user: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
40
|
+
readonly version: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
41
|
+
}, undefined>;
|
|
42
|
+
readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
43
|
+
readonly links: v.OptionalSchema<v.ObjectWithRestSchema<{
|
|
44
|
+
readonly affectedFiles: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.CheckAction<string, "Expected a normalized workspace-relative path.">]>, undefined>, undefined>;
|
|
45
|
+
readonly blobs: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
46
|
+
readonly briefId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
47
|
+
readonly correctsLedgerId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
48
|
+
readonly gitRef: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
49
|
+
readonly idempotencyKey: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
50
|
+
readonly stripDecisionId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
51
|
+
readonly supersedesLedgerId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
52
|
+
readonly validatorVerdictId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
53
|
+
}, v.UnknownSchema, undefined>, {}>;
|
|
54
|
+
readonly phase: v.PicklistSchema<readonly ["capture", "intake", "seed", "vendor-extract", "cleanup", "parity", "characterize", "equiv", "analyze", "recover", "ship", "migration"], undefined>;
|
|
55
|
+
readonly prevEntryId: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
56
|
+
readonly schemaVersion: v.LiteralSchema<"ushman-ledger-entry/v1", undefined>;
|
|
57
|
+
readonly summary: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
58
|
+
readonly ts: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, undefined>]>;
|
|
59
|
+
}, undefined>;
|
|
31
60
|
export declare const AgentPatchEntrySchema: v.ObjectSchema<{
|
|
32
61
|
readonly agent: v.ObjectSchema<{
|
|
33
62
|
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
@@ -375,6 +404,34 @@ export declare const LedgerEntrySchema: v.VariantSchema<"kind", [v.ObjectSchema<
|
|
|
375
404
|
readonly schemaVersion: v.LiteralSchema<"ushman-ledger-entry/v1", undefined>;
|
|
376
405
|
readonly summary: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
377
406
|
readonly ts: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, undefined>]>;
|
|
407
|
+
}, undefined>, v.ObjectSchema<{
|
|
408
|
+
readonly filePath: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.CheckAction<string, "Expected a normalized workspace-relative path.">]>;
|
|
409
|
+
readonly kind: v.LiteralSchema<"stage-write", undefined>;
|
|
410
|
+
readonly rationale: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
411
|
+
readonly stage: v.PicklistSchema<readonly ["intake", "seed", "vendor-extract", "cleanup", "candidate-promotion"], undefined>;
|
|
412
|
+
readonly details: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>, undefined>;
|
|
413
|
+
readonly emitter: v.ObjectSchema<{
|
|
414
|
+
readonly tool: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
415
|
+
readonly user: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
416
|
+
readonly version: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
417
|
+
}, undefined>;
|
|
418
|
+
readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
419
|
+
readonly links: v.OptionalSchema<v.ObjectWithRestSchema<{
|
|
420
|
+
readonly affectedFiles: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.CheckAction<string, "Expected a normalized workspace-relative path.">]>, undefined>, undefined>;
|
|
421
|
+
readonly blobs: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
|
|
422
|
+
readonly briefId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
423
|
+
readonly correctsLedgerId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
424
|
+
readonly gitRef: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
425
|
+
readonly idempotencyKey: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
426
|
+
readonly stripDecisionId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
427
|
+
readonly supersedesLedgerId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
428
|
+
readonly validatorVerdictId: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
429
|
+
}, v.UnknownSchema, undefined>, {}>;
|
|
430
|
+
readonly phase: v.PicklistSchema<readonly ["capture", "intake", "seed", "vendor-extract", "cleanup", "parity", "characterize", "equiv", "analyze", "recover", "ship", "migration"], undefined>;
|
|
431
|
+
readonly prevEntryId: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>, undefined>;
|
|
432
|
+
readonly schemaVersion: v.LiteralSchema<"ushman-ledger-entry/v1", undefined>;
|
|
433
|
+
readonly summary: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
434
|
+
readonly ts: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, undefined>]>;
|
|
378
435
|
}, undefined>, v.ObjectSchema<{
|
|
379
436
|
readonly agent: v.ObjectSchema<{
|
|
380
437
|
readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-read.d.ts","sourceRoot":"","sources":["../../src/schema/entry-read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"entry-read.d.ts","sourceRoot":"","sources":["../../src/schema/entry-read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAgB7B,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAMpC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAMhC,CAAC;AAQH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAOhC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAMnC,CAAC;AAEH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAItC,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAOrC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAOlC,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;aAK1B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDAOjC,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAI3C,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAY/B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAY5B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACxE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAClE,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC"}
|