patchwork-os 1.2.0-beta.3.canary.927 → 1.2.0-beta.3.canary.928
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/dist/evidenceVerify.d.ts +16 -1
- package/dist/evidenceVerify.js +51 -8
- package/dist/evidenceVerify.js.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/ledgerChain.d.ts +6 -2
- package/dist/ledgerChain.js +12 -1
- package/dist/ledgerChain.js.map +1 -1
- package/package.json +1 -1
package/dist/evidenceVerify.d.ts
CHANGED
|
@@ -23,6 +23,20 @@ export interface EvidenceVerification {
|
|
|
23
23
|
dir: string;
|
|
24
24
|
ok: boolean;
|
|
25
25
|
ledgers: LedgerVerification[];
|
|
26
|
+
/** Present ledgers whose chain was walked (chained rows > 0, or an intact legacy+chain file). */
|
|
27
|
+
verified: number;
|
|
28
|
+
/** No file and no sidecar: never written here. Legitimate for a ledger with no evidence yet. */
|
|
29
|
+
absent: number;
|
|
30
|
+
/** Present, legacy rows only, no chain-start yet. Non-fatal unless `expectChained`. */
|
|
31
|
+
unchained: number;
|
|
32
|
+
/** File gone, `.head` sidecar remains: deleted. Always a break. */
|
|
33
|
+
missingWithHead: number;
|
|
34
|
+
/** Whether `unchained` was treated as a failure. */
|
|
35
|
+
expectChained: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface VerifyEvidenceOpts {
|
|
38
|
+
/** Treat a legacy-only (never chained) ledger as NOT ok. */
|
|
39
|
+
expectChained?: boolean;
|
|
26
40
|
}
|
|
27
41
|
/**
|
|
28
42
|
* What `evidence verify` walks: the spine PLUS chained ledgers that are not
|
|
@@ -35,5 +49,6 @@ export declare const VERIFIED_LEDGERS: ReadonlyArray<{
|
|
|
35
49
|
key: string;
|
|
36
50
|
file: string;
|
|
37
51
|
}>;
|
|
38
|
-
export declare function
|
|
52
|
+
export declare function isUnchained(l: ChainVerification): boolean;
|
|
53
|
+
export declare function verifyEvidenceChains(dir?: string, opts?: VerifyEvidenceOpts): EvidenceVerification;
|
|
39
54
|
export declare function formatEvidenceVerify(r: EvidenceVerification): string;
|
package/dist/evidenceVerify.js
CHANGED
|
@@ -30,14 +30,36 @@ export const VERIFIED_LEDGERS = [
|
|
|
30
30
|
{ key: "run steps", file: "run_steps.jsonl" },
|
|
31
31
|
{ key: "pr outcomes", file: "pr_outcomes.jsonl" },
|
|
32
32
|
];
|
|
33
|
-
export function
|
|
33
|
+
export function isUnchained(l) {
|
|
34
|
+
return !l.absent && l.chainedRows === 0 && l.legacyPrefix === "unchained";
|
|
35
|
+
}
|
|
36
|
+
export function verifyEvidenceChains(dir = patchworkHome(), opts = {}) {
|
|
37
|
+
const expectChained = opts.expectChained === true;
|
|
34
38
|
const ledgers = [];
|
|
35
39
|
for (const { key, file } of VERIFIED_LEDGERS) {
|
|
36
40
|
const v = verifyLedgerChain(path.join(dir, file));
|
|
37
41
|
ledgers.push({ ...v, key, file });
|
|
38
42
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
43
|
+
const missingWithHead = ledgers.filter((l) => l.absent && l.head === "orphaned").length;
|
|
44
|
+
const absent = ledgers.filter((l) => l.absent && l.head !== "orphaned").length;
|
|
45
|
+
const unchained = ledgers.filter(isUnchained).length;
|
|
46
|
+
const verified = ledgers.filter((l) => !l.absent && !isUnchained(l)).length;
|
|
47
|
+
// Every ledger that exists must verify, a deleted one is a break, and a
|
|
48
|
+
// verdict over ZERO verified ledgers is not a verdict: a wrong --dir and a
|
|
49
|
+
// clean spine must not print the same word (audit 2026-10-15, H6).
|
|
50
|
+
const ok = ledgers.every((l) => l.ok && l.writeFailedPending === 0) &&
|
|
51
|
+
verified > 0 &&
|
|
52
|
+
(!expectChained || unchained === 0);
|
|
53
|
+
return {
|
|
54
|
+
dir,
|
|
55
|
+
ok,
|
|
56
|
+
ledgers,
|
|
57
|
+
verified,
|
|
58
|
+
absent,
|
|
59
|
+
unchained,
|
|
60
|
+
missingWithHead,
|
|
61
|
+
expectChained,
|
|
62
|
+
};
|
|
41
63
|
}
|
|
42
64
|
export function formatEvidenceVerify(r) {
|
|
43
65
|
const L = [];
|
|
@@ -45,11 +67,16 @@ export function formatEvidenceVerify(r) {
|
|
|
45
67
|
L.push(` ${r.dir}`);
|
|
46
68
|
L.push("");
|
|
47
69
|
for (const l of r.ledgers) {
|
|
70
|
+
if (l.absent && l.head === "orphaned") {
|
|
71
|
+
L.push(` MISSING ${l.file} file is gone but its .head sidecar remains — it used to exist`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
48
74
|
if (l.absent) {
|
|
49
75
|
L.push(` ABSENT ${l.file}`);
|
|
50
76
|
continue;
|
|
51
77
|
}
|
|
52
|
-
const
|
|
78
|
+
const unchained = isUnchained(l);
|
|
79
|
+
const chainNote = unchained
|
|
53
80
|
? `${l.legacyRows} legacy row(s), no chain yet`
|
|
54
81
|
: `${l.chainedRows} chained row(s), legacy prefix ${l.legacyPrefix}` +
|
|
55
82
|
(l.legacyRows > 0 ? ` (${l.legacyRows} row(s))` : "") +
|
|
@@ -64,7 +91,9 @@ export function formatEvidenceVerify(r) {
|
|
|
64
91
|
? "BROKEN"
|
|
65
92
|
: l.writeFailedPending > 0
|
|
66
93
|
? "PENDING"
|
|
67
|
-
:
|
|
94
|
+
: unchained
|
|
95
|
+
? "UNCHAINED"
|
|
96
|
+
: "OK";
|
|
68
97
|
L.push(` ${state.padEnd(8)} ${l.file} ${chainNote}`);
|
|
69
98
|
for (const b of l.breaks) {
|
|
70
99
|
L.push(` ${b.kind} break at line ${b.line}` +
|
|
@@ -78,9 +107,23 @@ export function formatEvidenceVerify(r) {
|
|
|
78
107
|
}
|
|
79
108
|
}
|
|
80
109
|
L.push("");
|
|
81
|
-
|
|
82
|
-
?
|
|
83
|
-
|
|
110
|
+
const counts = `${r.verified} of ${r.ledgers.length} verified, ${r.absent} absent` +
|
|
111
|
+
(r.unchained > 0 ? `, ${r.unchained} unchained` : "") +
|
|
112
|
+
(r.missingWithHead > 0 ? `, ${r.missingWithHead} missing` : "");
|
|
113
|
+
if (r.verified === 0 && r.missingWithHead === 0) {
|
|
114
|
+
L.push(`STATUS: NOTHING VERIFIED (${counts}) — no ledger found under this directory; a wrong --dir and a clean spine must not read the same`);
|
|
115
|
+
}
|
|
116
|
+
else if (r.ok) {
|
|
117
|
+
L.push(`STATUS: INTACT (${counts})`);
|
|
118
|
+
}
|
|
119
|
+
else if (r.expectChained &&
|
|
120
|
+
r.unchained > 0 &&
|
|
121
|
+
r.ledgers.every((l) => l.ok && l.writeFailedPending === 0)) {
|
|
122
|
+
L.push(`STATUS: NOT INTACT (${counts}) — --expect-chained and a ledger carries legacy rows only`);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
L.push(`STATUS: NOT INTACT (${counts}) — a break, a mismatch, a shortened or deleted file or an unsealed failure above`);
|
|
126
|
+
}
|
|
84
127
|
L.push("");
|
|
85
128
|
return L.join("\n");
|
|
86
129
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evidenceVerify.js","sourceRoot":"","sources":["../src/evidenceVerify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAA0B,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"evidenceVerify.js","sourceRoot":"","sources":["../src/evidenceVerify.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4494,7 +4494,7 @@ if (process.argv[2] === "sweep") {
|
|
|
4494
4494
|
if (process.argv[2] === "evidence") {
|
|
4495
4495
|
const args = process.argv.slice(3);
|
|
4496
4496
|
if (args.includes("--help") || args.includes("-h")) {
|
|
4497
|
-
process.stdout.write("Usage: patchwork evidence [verify] [--dir <path>] [--json]\n\n" +
|
|
4497
|
+
process.stdout.write("Usage: patchwork evidence [verify] [--dir <path>] [--json] [--expect-chained]\n\n" +
|
|
4498
4498
|
" verify is every spine ledger internally intact? (ADR-0027) Checks the\n" +
|
|
4499
4499
|
" per-row hash chain, the legacy-prefix commitment, the head sidecar\n" +
|
|
4500
4500
|
" and unsealed write failures. Exits 1 on any break — the only form\n" +
|
|
@@ -4506,7 +4506,8 @@ if (process.argv[2] === "evidence") {
|
|
|
4506
4506
|
"correlationId is a run's taskId and these ledgers hold real task titles and\n" +
|
|
4507
4507
|
"third-party record ids. A measurement may leave the machine; the rows may not.\n\n" +
|
|
4508
4508
|
" --dir <path> ledger directory (default: $PATCHWORK_HOME)\n" +
|
|
4509
|
-
" --json emit the raw report\n"
|
|
4509
|
+
" --json emit the raw report\n" +
|
|
4510
|
+
" --expect-chained (verify) a ledger with legacy rows and no chain is NOT ok\n");
|
|
4510
4511
|
process.exit(0);
|
|
4511
4512
|
}
|
|
4512
4513
|
(async () => {
|
|
@@ -4522,7 +4523,7 @@ if (process.argv[2] === "evidence") {
|
|
|
4522
4523
|
args,
|
|
4523
4524
|
subcommands: ["verify"],
|
|
4524
4525
|
valueFlags: ["--dir"],
|
|
4525
|
-
flags: ["--json"],
|
|
4526
|
+
flags: ["--json", "--expect-chained"],
|
|
4526
4527
|
});
|
|
4527
4528
|
const dirIdx = args.indexOf("--dir");
|
|
4528
4529
|
const dir = dirIdx !== -1 ? args[dirIdx + 1] : undefined;
|
|
@@ -4532,7 +4533,10 @@ if (process.argv[2] === "evidence") {
|
|
|
4532
4533
|
// with `ok: false` in the JSON so a cron job can act on it. Still
|
|
4533
4534
|
// prints positions and counts only, never a value.
|
|
4534
4535
|
const { verifyEvidenceChains, formatEvidenceVerify } = await import("./evidenceVerify.js");
|
|
4535
|
-
const
|
|
4536
|
+
const verifyOpts = { expectChained: args.includes("--expect-chained") };
|
|
4537
|
+
const r = dir
|
|
4538
|
+
? verifyEvidenceChains(dir, verifyOpts)
|
|
4539
|
+
: verifyEvidenceChains(undefined, verifyOpts);
|
|
4536
4540
|
process.stdout.write(args.includes("--json")
|
|
4537
4541
|
? `${JSON.stringify(r, null, 2)}\n`
|
|
4538
4542
|
: formatEvidenceVerify(r));
|