patchwork-os 1.2.0-beta.2.canary.783 → 1.2.0-beta.2.canary.784

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.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `patchwork evidence verify` — is the evidence spine internally intact?
3
+ *
4
+ * The offline reader ADR-0027 pairs with `appendChained`. Walks every ledger
5
+ * on `SPINE_LEDGERS` through `verifyLedgerChain` and reduces to one verdict.
6
+ *
7
+ * Unlike `patchwork evidence`, this one GATES: `ok: false` and exit 1 on any
8
+ * break, on a legacy-prefix mismatch, on a head sidecar that says the file
9
+ * used to be longer, and on a PENDING write-failure count — because a ledger
10
+ * that stopped writing is a different fact from a quiet day and this is the
11
+ * command that is supposed to say so.
12
+ *
13
+ * Prints counts and positions (line number, iseq) only, never a value. A line
14
+ * number is not operator data; a row is.
15
+ */
16
+ import { type ChainVerification } from "./ledgerChain.js";
17
+ export interface LedgerVerification extends ChainVerification {
18
+ key: string;
19
+ /** Relative to `dir` — what the report prints. */
20
+ file: string;
21
+ }
22
+ export interface EvidenceVerification {
23
+ dir: string;
24
+ ok: boolean;
25
+ ledgers: LedgerVerification[];
26
+ }
27
+ export declare function verifyEvidenceChains(dir?: string): EvidenceVerification;
28
+ export declare function formatEvidenceVerify(r: EvidenceVerification): string;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * `patchwork evidence verify` — is the evidence spine internally intact?
3
+ *
4
+ * The offline reader ADR-0027 pairs with `appendChained`. Walks every ledger
5
+ * on `SPINE_LEDGERS` through `verifyLedgerChain` and reduces to one verdict.
6
+ *
7
+ * Unlike `patchwork evidence`, this one GATES: `ok: false` and exit 1 on any
8
+ * break, on a legacy-prefix mismatch, on a head sidecar that says the file
9
+ * used to be longer, and on a PENDING write-failure count — because a ledger
10
+ * that stopped writing is a different fact from a quiet day and this is the
11
+ * command that is supposed to say so.
12
+ *
13
+ * Prints counts and positions (line number, iseq) only, never a value. A line
14
+ * number is not operator data; a row is.
15
+ */
16
+ import path from "node:path";
17
+ import { SPINE_LEDGERS } from "./evidenceCoverage.js";
18
+ import { verifyLedgerChain } from "./ledgerChain.js";
19
+ import { patchworkHome } from "./patchworkHome.js";
20
+ export function verifyEvidenceChains(dir = patchworkHome()) {
21
+ const ledgers = [];
22
+ for (const { key, file } of SPINE_LEDGERS) {
23
+ const v = verifyLedgerChain(path.join(dir, file));
24
+ ledgers.push({ ...v, key, file });
25
+ }
26
+ const ok = ledgers.every((l) => l.ok && l.writeFailedPending === 0);
27
+ return { dir, ok, ledgers };
28
+ }
29
+ export function formatEvidenceVerify(r) {
30
+ const L = [];
31
+ L.push("[evidence verify] is the spine internally intact?");
32
+ L.push(` ${r.dir}`);
33
+ L.push("");
34
+ for (const l of r.ledgers) {
35
+ if (l.absent) {
36
+ L.push(` ABSENT ${l.file}`);
37
+ continue;
38
+ }
39
+ const chainNote = l.chainedRows === 0 && l.legacyPrefix === "unchained"
40
+ ? `${l.legacyRows} legacy row(s), no chain yet`
41
+ : `${l.chainedRows} chained row(s), legacy prefix ${l.legacyPrefix}` +
42
+ (l.legacyRows > 0 ? ` (${l.legacyRows} row(s))` : "") +
43
+ (l.rotations > 0
44
+ ? `, ${l.droppedByRotation} row(s) removed by rotation`
45
+ : "") +
46
+ (l.writeFailedSealed > 0
47
+ ? `, ${l.writeFailedSealed} failed append(s) sealed`
48
+ : "") +
49
+ `, head ${l.head}`;
50
+ const state = !l.ok
51
+ ? "BROKEN"
52
+ : l.writeFailedPending > 0
53
+ ? "PENDING"
54
+ : "OK";
55
+ L.push(` ${state.padEnd(8)} ${l.file} ${chainNote}`);
56
+ for (const b of l.breaks) {
57
+ L.push(` ${b.kind} break at line ${b.line}` +
58
+ (b.iseq !== null ? ` (iseq ${b.iseq})` : ""));
59
+ }
60
+ if (l.legacyPrefix === "mismatch") {
61
+ L.push(" legacy prefix does not match the chain-start commitment");
62
+ }
63
+ if (l.writeFailedPending > 0) {
64
+ L.push(` ${l.writeFailedPending} append(s) failed since the last row landed — not yet sealed`);
65
+ }
66
+ }
67
+ L.push("");
68
+ L.push(r.ok
69
+ ? "STATUS: INTACT"
70
+ : "STATUS: NOT INTACT — a break, a mismatch, a shortened file or an unsealed failure above");
71
+ L.push("");
72
+ return L.join("\n");
73
+ }
74
+ //# sourceMappingURL=evidenceVerify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidenceVerify.js","sourceRoot":"","sources":["../src/evidenceVerify.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -4389,7 +4389,11 @@ if (process.argv[2] === "sweep") {
4389
4389
  if (process.argv[2] === "evidence") {
4390
4390
  const args = process.argv.slice(3);
4391
4391
  if (args.includes("--help") || args.includes("-h")) {
4392
- process.stdout.write("Usage: patchwork evidence [--dir <path>] [--json]\n\n" +
4392
+ process.stdout.write("Usage: patchwork evidence [verify] [--dir <path>] [--json]\n\n" +
4393
+ " verify is every spine ledger internally intact? (ADR-0027) Checks the\n" +
4394
+ " per-row hash chain, the legacy-prefix commitment, the head sidecar\n" +
4395
+ " and unsealed write failures. Exits 1 on any break — the only form\n" +
4396
+ " of this verb that gates.\n\n" +
4393
4397
  "How much of the evidence spine can actually be joined: per ledger, how many\n" +
4394
4398
  "rows carry a run id (correlationId) out of how many rows, and how many runs\n" +
4395
4399
  "appear in more than one ledger.\n\n" +
@@ -4404,6 +4408,18 @@ if (process.argv[2] === "evidence") {
4404
4408
  try {
4405
4409
  const dirIdx = args.indexOf("--dir");
4406
4410
  const dir = dirIdx !== -1 ? args[dirIdx + 1] : undefined;
4411
+ if (args[0] === "verify") {
4412
+ // ADR-0027. Unlike the bare verb this one GATES: exit 1 on any chain
4413
+ // break, legacy mismatch, shortened file or unsealed write failure,
4414
+ // with `ok: false` in the JSON so a cron job can act on it. Still
4415
+ // prints positions and counts only, never a value.
4416
+ const { verifyEvidenceChains, formatEvidenceVerify } = await import("./evidenceVerify.js");
4417
+ const r = dir ? verifyEvidenceChains(dir) : verifyEvidenceChains();
4418
+ process.stdout.write(args.includes("--json")
4419
+ ? `${JSON.stringify(r, null, 2)}\n`
4420
+ : formatEvidenceVerify(r));
4421
+ process.exit(r.ok ? 0 : 1);
4422
+ }
4407
4423
  const { evidenceCoverage, formatEvidenceCoverage } = await import("./evidenceCoverage.js");
4408
4424
  const { evidenceRelationships, formatEvidenceRelationships } = await import("./evidenceRelationships.js");
4409
4425
  const report = dir ? evidenceCoverage(dir) : evidenceCoverage();