@sdd-method/sdd-cli 1.29.1 → 1.30.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/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/catalogue/graph-run.d.ts +1 -28
- package/dist/lib/catalogue/graph-run.d.ts.map +1 -1
- package/dist/lib/catalogue/graph-run.js +3 -57
- package/dist/lib/catalogue/graph-run.js.map +1 -1
- package/dist/lib/catalogue/impact-run.d.ts +1 -1
- package/dist/lib/catalogue/impact-run.d.ts.map +1 -1
- package/dist/lib/catalogue/impact-run.js +1 -1
- package/dist/lib/catalogue/impact-run.js.map +1 -1
- package/dist/lib/catalogue/relationship-semantics.d.ts +29 -0
- package/dist/lib/catalogue/relationship-semantics.d.ts.map +1 -0
- package/dist/lib/catalogue/relationship-semantics.js +66 -0
- package/dist/lib/catalogue/relationship-semantics.js.map +1 -0
- package/dist/lib/pack/index.d.ts +1 -9
- package/dist/lib/pack/index.d.ts.map +1 -1
- package/dist/lib/pack/index.js +2 -53
- package/dist/lib/pack/index.js.map +1 -1
- package/dist/lib/pack/log.d.ts +6 -0
- package/dist/lib/pack/log.d.ts.map +1 -0
- package/dist/lib/pack/log.js +18 -0
- package/dist/lib/pack/log.js.map +1 -0
- package/dist/lib/pack/validate.d.ts +10 -0
- package/dist/lib/pack/validate.d.ts.map +1 -0
- package/dist/lib/pack/validate.js +49 -0
- package/dist/lib/pack/validate.js.map +1 -0
- package/dist/lib/snapshot/advance.d.ts +39 -0
- package/dist/lib/snapshot/advance.d.ts.map +1 -0
- package/dist/lib/snapshot/advance.js +253 -0
- package/dist/lib/snapshot/advance.js.map +1 -0
- package/dist/lib/snapshot/catalogue-diff.d.ts +21 -0
- package/dist/lib/snapshot/catalogue-diff.d.ts.map +1 -0
- package/dist/lib/snapshot/catalogue-diff.js +133 -0
- package/dist/lib/snapshot/catalogue-diff.js.map +1 -0
- package/dist/lib/snapshot/diff.d.ts +73 -0
- package/dist/lib/snapshot/diff.d.ts.map +1 -0
- package/dist/lib/snapshot/diff.js +177 -0
- package/dist/lib/snapshot/diff.js.map +1 -0
- package/dist/lib/snapshot/fold.d.ts +14 -0
- package/dist/lib/snapshot/fold.d.ts.map +1 -0
- package/dist/lib/snapshot/fold.js +106 -0
- package/dist/lib/snapshot/fold.js.map +1 -0
- package/dist/lib/snapshot/land.d.ts +21 -0
- package/dist/lib/snapshot/land.d.ts.map +1 -0
- package/dist/lib/snapshot/land.js +160 -0
- package/dist/lib/snapshot/land.js.map +1 -0
- package/dist/lib/snapshot/manifest.d.ts +59 -0
- package/dist/lib/snapshot/manifest.d.ts.map +1 -0
- package/dist/lib/snapshot/manifest.js +152 -0
- package/dist/lib/snapshot/manifest.js.map +1 -0
- package/dist/lib/snapshot/targets.d.ts +26 -0
- package/dist/lib/snapshot/targets.d.ts.map +1 -0
- package/dist/lib/snapshot/targets.js +121 -0
- package/dist/lib/snapshot/targets.js.map +1 -0
- package/dist/lib/snapshot/verify.d.ts +18 -0
- package/dist/lib/snapshot/verify.d.ts.map +1 -0
- package/dist/lib/snapshot/verify.js +82 -0
- package/dist/lib/snapshot/verify.js.map +1 -0
- package/dist/verbs/catalogue-verify.d.ts +6 -0
- package/dist/verbs/catalogue-verify.d.ts.map +1 -0
- package/dist/verbs/catalogue-verify.js +114 -0
- package/dist/verbs/catalogue-verify.js.map +1 -0
- package/dist/verbs/catalogue.d.ts.map +1 -1
- package/dist/verbs/catalogue.js +15 -90
- package/dist/verbs/catalogue.js.map +1 -1
- package/dist/verbs/pack-validate.d.ts +3 -0
- package/dist/verbs/pack-validate.d.ts.map +1 -0
- package/dist/verbs/pack-validate.js +17 -0
- package/dist/verbs/pack-validate.js.map +1 -0
- package/dist/verbs/pack.d.ts.map +1 -1
- package/dist/verbs/pack.js +3 -10
- package/dist/verbs/pack.js.map +1 -1
- package/dist/verbs/snapshot.d.ts +3 -0
- package/dist/verbs/snapshot.d.ts.map +1 -0
- package/dist/verbs/snapshot.js +119 -0
- package/dist/verbs/snapshot.js.map +1 -0
- package/dist/verify-bin.d.ts +3 -0
- package/dist/verify-bin.d.ts.map +1 -0
- package/dist/verify-bin.js +8 -0
- package/dist/verify-bin.js.map +1 -0
- package/dist/verify-program.d.ts +14 -0
- package/dist/verify-program.d.ts.map +1 -0
- package/dist/verify-program.js +115 -0
- package/dist/verify-program.js.map +1 -0
- package/package.json +3 -3
- package/scripts/build-verify-package.mjs +199 -0
- package/scripts/verify-acceptance.sh +178 -0
- package/dist/conformance-bin.d.ts +0 -3
- package/dist/conformance-bin.d.ts.map +0 -1
- package/dist/conformance-bin.js +0 -8
- package/dist/conformance-bin.js.map +0 -1
- package/dist/conformance-program.d.ts +0 -6
- package/dist/conformance-program.d.ts.map +0 -1
- package/dist/conformance-program.js +0 -59
- package/dist/conformance-program.js.map +0 -1
- package/scripts/build-conformance-package.mjs +0 -57
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
type Writer = (s: string) => void;
|
|
2
|
+
export declare const REVERSE_STATUSES: readonly ["classified", "reversed"];
|
|
3
|
+
export declare const IMPACTS: readonly ["none", "repo-minor", "repo-major", "product-major"];
|
|
4
|
+
export interface AdvanceInputs {
|
|
5
|
+
sddPath: string;
|
|
6
|
+
areaRoot: string;
|
|
7
|
+
to: string;
|
|
8
|
+
members?: readonly string[];
|
|
9
|
+
migrateHistory?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface Plan {
|
|
12
|
+
key: string;
|
|
13
|
+
dir: string;
|
|
14
|
+
history: Record<string, unknown>;
|
|
15
|
+
migrated: boolean;
|
|
16
|
+
metadataText: string;
|
|
17
|
+
entry: Record<string, unknown>;
|
|
18
|
+
metadata: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
export declare function runSnapshotAdvance(inputs: AdvanceInputs, write: Writer): Promise<{
|
|
21
|
+
exitCode: number;
|
|
22
|
+
}>;
|
|
23
|
+
/** Convert a legacy `entries:` history. Only `phase: scan` rows convert mechanically. */
|
|
24
|
+
export declare function migrateLegacy(legacy: {
|
|
25
|
+
entries?: unknown[];
|
|
26
|
+
}, metadata: Record<string, unknown>): Record<string, unknown>;
|
|
27
|
+
/** Re-point a source_path at another baseline and folder; null if it has no dated segment. */
|
|
28
|
+
export declare function repoint(sourcePath: string, newBaseline: string, newFolder: string): string | null;
|
|
29
|
+
export declare function advance(inputs: AdvanceInputs, write: Writer): Promise<Plan[]>;
|
|
30
|
+
/** Replace (or append) top-level `key: value` lines, leaving every other byte alone. */
|
|
31
|
+
export declare function setTopLevelScalars(text: string, values: Readonly<Record<string, string>>): string;
|
|
32
|
+
/**
|
|
33
|
+
* Append one entry to a `history:` list that ends the file, at the list's own
|
|
34
|
+
* indentation. Falls back to a document edit when `history:` is not the last
|
|
35
|
+
* top-level key; the caller's post-write check covers both paths.
|
|
36
|
+
*/
|
|
37
|
+
export declare function appendHistoryEntry(text: string, entry: Record<string, unknown>): string;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=advance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advance.d.ts","sourceRoot":"","sources":["../../../src/lib/snapshot/advance.ts"],"names":[],"mappings":"AAiCA,KAAK,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAElC,eAAO,MAAM,gBAAgB,qCAAsC,CAAC;AACpE,eAAO,MAAM,OAAO,gEAAiE,CAAC;AAEtF,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,IAAI;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAY5G;AAgBD,yFAAyF;AACzF,wBAAgB,aAAa,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBzH;AAgBD,8FAA8F;AAC9F,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKjG;AAED,wBAAsB,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CA0HnF;AAMD,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAQjG;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAavF"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// `sdd-cli snapshot advance` — move each member's evidence pin to T1 and
|
|
2
|
+
// append one history entry (delta-reverse.md §8).
|
|
3
|
+
//
|
|
4
|
+
// Refusals, each a failure a hand run made:
|
|
5
|
+
// - no delta.yaml for T1 (the pin advanced before the diff existed);
|
|
6
|
+
// - no `impact` recorded (step 5a not done);
|
|
7
|
+
// - a legacy `entries:` history, unless --migrate-history converts it first;
|
|
8
|
+
// - a `phase:` key or a `reverse_status` outside {classified, reversed};
|
|
9
|
+
// - a source_path with no dated baseline segment (the area is not folded).
|
|
10
|
+
// It checks everything before it writes anything, and it only ever APPENDS:
|
|
11
|
+
// after writing it re-reads each history and asserts the prior entries are
|
|
12
|
+
// unchanged and exactly one was added. Entries are never cut or rewritten —
|
|
13
|
+
// for an unchanged member the T0 and T1 entries share folder name and
|
|
14
|
+
// revision, so any edit keyed on those removes both.
|
|
15
|
+
import { isDeepStrictEqual } from "node:util";
|
|
16
|
+
import { readdir, readFile, writeFile } from "node:fs/promises";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { parse, parseDocument, stringify } from "yaml";
|
|
19
|
+
// Both writers below edit TEXT, not a re-serialised document: re-serialising
|
|
20
|
+
// reflows every long string in the file, so an evidence pin would arrive with
|
|
21
|
+
// unrelated churn in lines the tool had no business touching.
|
|
22
|
+
import { deltaPath } from "./diff.js";
|
|
23
|
+
import { SnapshotError, exists, isIsoDate, readManifest, splitFolder, } from "./manifest.js";
|
|
24
|
+
export const REVERSE_STATUSES = ["classified", "reversed"];
|
|
25
|
+
export const IMPACTS = ["none", "repo-minor", "repo-major", "product-major"];
|
|
26
|
+
export async function runSnapshotAdvance(inputs, write) {
|
|
27
|
+
try {
|
|
28
|
+
const plans = await advance(inputs, write);
|
|
29
|
+
write(`advanced ${plans.length} member(s) to ${inputs.to}\n`);
|
|
30
|
+
return { exitCode: 0 };
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
if (e instanceof SnapshotError) {
|
|
34
|
+
write(`REFUSED (nothing written): ${e.message}\n`);
|
|
35
|
+
return { exitCode: 1 };
|
|
36
|
+
}
|
|
37
|
+
throw e;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function evidenceDirs(sddPath) {
|
|
41
|
+
const out = new Map();
|
|
42
|
+
const repos = join(sddPath, "repos");
|
|
43
|
+
if (!(await exists(repos)))
|
|
44
|
+
return out;
|
|
45
|
+
for (const e of await readdir(repos, { withFileTypes: true })) {
|
|
46
|
+
if (!e.isDirectory())
|
|
47
|
+
continue;
|
|
48
|
+
const md = join(repos, e.name, "reverse-metadata.yaml");
|
|
49
|
+
if (!(await exists(md)))
|
|
50
|
+
continue;
|
|
51
|
+
const key = parse(await readFile(md, "utf8"))?.canonical_repo_key;
|
|
52
|
+
out.set(key ?? e.name, join(repos, e.name));
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/** Convert a legacy `entries:` history. Only `phase: scan` rows convert mechanically. */
|
|
57
|
+
export function migrateLegacy(legacy, metadata) {
|
|
58
|
+
const entries = (legacy.entries ?? []);
|
|
59
|
+
const other = entries.filter((e) => e.phase !== undefined && e.phase !== "scan");
|
|
60
|
+
if (other.length > 0) {
|
|
61
|
+
throw new SnapshotError(`legacy history has ${other.length} row(s) with phase other than 'scan' (${[...new Set(other.map((e) => String(e.phase)))].join(", ")}): ` +
|
|
62
|
+
"which snapshot each describes cannot be derived, so convert those by hand");
|
|
63
|
+
}
|
|
64
|
+
const identity = ["exported_folder_name", "exported_branch", "source_revision", "source_path"];
|
|
65
|
+
for (const f of identity)
|
|
66
|
+
if (!metadata[f])
|
|
67
|
+
throw new SnapshotError(`cannot migrate: reverse-metadata.yaml has no ${f}`);
|
|
68
|
+
return {
|
|
69
|
+
canonical_repo_key: metadata.canonical_repo_key,
|
|
70
|
+
history: entries.map((e) => ({
|
|
71
|
+
...Object.fromEntries(identity.map((f) => [f, metadata[f]])),
|
|
72
|
+
scanned_at: e.date,
|
|
73
|
+
reverse_status: "reversed",
|
|
74
|
+
notes: `${String(e.notes ?? "").trim()} (Migrated from the legacy entries: shape — originally phase: ${String(e.phase ?? "unset")}, actor: ${String(e.actor ?? "unset")}; identity fields taken from reverse-metadata.yaml at migration.)`.trim(),
|
|
75
|
+
})),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function checkHistory(file, h) {
|
|
79
|
+
const problems = [];
|
|
80
|
+
const hist = h.history;
|
|
81
|
+
if (!Array.isArray(hist))
|
|
82
|
+
return [`${file}: no history[] list`];
|
|
83
|
+
for (const [i, e] of hist.entries()) {
|
|
84
|
+
if (e.phase !== undefined)
|
|
85
|
+
problems.push(`${file}: history[${i}] has a 'phase' key — not a field of the convention`);
|
|
86
|
+
const s = e.reverse_status;
|
|
87
|
+
if (s !== undefined && !REVERSE_STATUSES.includes(s)) {
|
|
88
|
+
problems.push(`${file}: history[${i}].reverse_status '${String(s)}' is not one of ${REVERSE_STATUSES.join(", ")}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return problems;
|
|
92
|
+
}
|
|
93
|
+
/** Re-point a source_path at another baseline and folder; null if it has no dated segment. */
|
|
94
|
+
export function repoint(sourcePath, newBaseline, newFolder) {
|
|
95
|
+
const parts = sourcePath.split("/");
|
|
96
|
+
const i = parts.findIndex((p) => isIsoDate(p));
|
|
97
|
+
if (i < 0)
|
|
98
|
+
return null;
|
|
99
|
+
return [...parts.slice(0, i), newBaseline, newFolder].join("/");
|
|
100
|
+
}
|
|
101
|
+
export async function advance(inputs, write) {
|
|
102
|
+
const { sddPath, areaRoot, to } = inputs;
|
|
103
|
+
const t1 = await readManifest(areaRoot, to);
|
|
104
|
+
const dp = deltaPath(areaRoot, to);
|
|
105
|
+
if (!(await exists(dp))) {
|
|
106
|
+
throw new SnapshotError(`no ${dp}: the pin advances after the delta is recorded (run snapshot diff, then classify)`);
|
|
107
|
+
}
|
|
108
|
+
const delta = parse(await readFile(dp, "utf8"));
|
|
109
|
+
if (!delta.impact)
|
|
110
|
+
throw new SnapshotError(`${dp} has no impact: classify first (delta-reverse.md §5a)`);
|
|
111
|
+
const impactOk = (v) => IMPACTS.includes(v);
|
|
112
|
+
if (!impactOk(delta.impact))
|
|
113
|
+
throw new SnapshotError(`${dp}: impact '${delta.impact}' is not one of ${IMPACTS.join(", ")}`);
|
|
114
|
+
const changed = new Map((delta.members_changed ?? []).map((c) => [c.canonical_repo_key, c]));
|
|
115
|
+
const dirs = await evidenceDirs(sddPath);
|
|
116
|
+
const wanted = inputs.members ? new Set(inputs.members) : null;
|
|
117
|
+
const problems = [];
|
|
118
|
+
const plans = [];
|
|
119
|
+
for (const m of t1.members) {
|
|
120
|
+
if (wanted && !wanted.has(m.canonical_repo_key))
|
|
121
|
+
continue;
|
|
122
|
+
if (m.carried_from !== undefined)
|
|
123
|
+
continue; // carried: no new entry — the manifest records where its bytes are
|
|
124
|
+
const key = m.canonical_repo_key;
|
|
125
|
+
const dir = dirs.get(key);
|
|
126
|
+
if (!dir) {
|
|
127
|
+
problems.push(`${key}: no repos/*/reverse-metadata.yaml with this canonical_repo_key — a new member is seeded (step 7) before its pin advances`);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const hFile = join(dir, "reverse-history.yaml");
|
|
131
|
+
const mFile = join(dir, "reverse-metadata.yaml");
|
|
132
|
+
const metadataText = await readFile(mFile, "utf8");
|
|
133
|
+
const metadata = parse(metadataText);
|
|
134
|
+
let history = (await exists(hFile)) ? parse(await readFile(hFile, "utf8")) : { canonical_repo_key: key, history: [] };
|
|
135
|
+
let migrated = false;
|
|
136
|
+
if (Array.isArray(history.entries)) {
|
|
137
|
+
if (!inputs.migrateHistory) {
|
|
138
|
+
problems.push(`${hFile}: legacy entries: history — pass --migrate-history to convert it first`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
history = migrateLegacy(history, metadata);
|
|
143
|
+
migrated = true;
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
problems.push(`${hFile}: ${e.message}`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
problems.push(...checkHistory(hFile, history));
|
|
151
|
+
const hist = history.history;
|
|
152
|
+
const last = hist[hist.length - 1];
|
|
153
|
+
const scannedAt = m.observed_at ?? t1.observed_at;
|
|
154
|
+
if (last && last.exported_folder_name === m.exported_folder_name && last.scanned_at === scannedAt) {
|
|
155
|
+
write(`${key}: already at ${to} — skipped\n`);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const newPath = repoint(String(metadata.source_path ?? ""), to, m.exported_folder_name);
|
|
159
|
+
if (newPath === null) {
|
|
160
|
+
problems.push(`${mFile}: source_path '${metadata.source_path}' has no dated baseline segment — fold the area first`);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const sameRevision = String(metadata.source_revision) === m.source_revision;
|
|
164
|
+
const impact = sameRevision ? "none" : (changed.get(key)?.impact ?? delta.impact);
|
|
165
|
+
if (!impactOk(impact))
|
|
166
|
+
problems.push(`${dp}: ${key} impact '${impact}' is not one of ${IMPACTS.join(", ")}`);
|
|
167
|
+
const findingIds = (delta.findings ?? []).filter((f) => f.member === key).map((f) => f.id);
|
|
168
|
+
const branch = splitFolder(m.exported_folder_name)?.stem.match(/-(master|main|develop|trunk)$/)?.[1] ?? metadata.exported_branch;
|
|
169
|
+
const entry = {
|
|
170
|
+
exported_folder_name: m.exported_folder_name,
|
|
171
|
+
...(branch ? { exported_branch: branch } : {}),
|
|
172
|
+
source_revision: m.source_revision,
|
|
173
|
+
source_path: newPath,
|
|
174
|
+
scanned_at: scannedAt,
|
|
175
|
+
reverse_status: "reversed",
|
|
176
|
+
impact,
|
|
177
|
+
...(sameRevision
|
|
178
|
+
? { impact_rationale: `re-observed at the same revision (${describeReverification(m)})` }
|
|
179
|
+
: delta.impact_rationale
|
|
180
|
+
? { impact_rationale: delta.impact_rationale }
|
|
181
|
+
: {}),
|
|
182
|
+
notes: `advanced to ${to} from ${delta.from_snapshot ?? t1.prior_snapshot} by sdd-cli snapshot advance; findings: ${findingIds.length > 0 ? findingIds.join(", ") : "none"}`,
|
|
183
|
+
};
|
|
184
|
+
plans.push({
|
|
185
|
+
key,
|
|
186
|
+
dir,
|
|
187
|
+
history,
|
|
188
|
+
migrated,
|
|
189
|
+
metadataText,
|
|
190
|
+
entry,
|
|
191
|
+
metadata: {
|
|
192
|
+
source_path: newPath,
|
|
193
|
+
exported_folder_name: m.exported_folder_name,
|
|
194
|
+
source_revision: m.source_revision,
|
|
195
|
+
scanned_at: scannedAt,
|
|
196
|
+
...(branch ? { exported_branch: branch } : {}),
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (problems.length > 0)
|
|
201
|
+
throw new SnapshotError(`${problems.length} problem(s):\n - ${problems.join("\n - ")}`);
|
|
202
|
+
for (const p of plans) {
|
|
203
|
+
const hFile = join(p.dir, "reverse-history.yaml");
|
|
204
|
+
const before = structuredClone(p.history.history ?? []);
|
|
205
|
+
if (p.migrated || !(await exists(hFile))) {
|
|
206
|
+
const h = { ...p.history, history: [...before, p.entry] };
|
|
207
|
+
await writeFile(hFile, stringify(h, { lineWidth: 0 }));
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
await writeFile(hFile, appendHistoryEntry(await readFile(hFile, "utf8"), p.entry));
|
|
211
|
+
}
|
|
212
|
+
const after = parse(await readFile(hFile, "utf8")).history;
|
|
213
|
+
if (after.length !== before.length + 1 || !isDeepStrictEqual(after.slice(0, before.length), before)) {
|
|
214
|
+
throw new Error(`${hFile}: post-write check failed — prior entries changed or not exactly one appended`);
|
|
215
|
+
}
|
|
216
|
+
await writeFile(join(p.dir, "reverse-metadata.yaml"), setTopLevelScalars(p.metadataText, p.metadata));
|
|
217
|
+
write(`${p.key}: ${p.migrated ? "history migrated, " : ""}pin → ${p.metadata.exported_folder_name} (impact ${String(p.entry.impact)})\n`);
|
|
218
|
+
}
|
|
219
|
+
return plans;
|
|
220
|
+
}
|
|
221
|
+
function describeReverification(m) {
|
|
222
|
+
return m.reverification ?? `revision ${m.source_revision} unchanged`;
|
|
223
|
+
}
|
|
224
|
+
/** Replace (or append) top-level `key: value` lines, leaving every other byte alone. */
|
|
225
|
+
export function setTopLevelScalars(text, values) {
|
|
226
|
+
let out = text;
|
|
227
|
+
for (const [k, v] of Object.entries(values)) {
|
|
228
|
+
const line = `${k}: ${stringify(v).trimEnd()}`;
|
|
229
|
+
const re = new RegExp(`^${k}:[^\\n]*$`, "m");
|
|
230
|
+
out = re.test(out) ? out.replace(re, line) : `${out.replace(/\n*$/, "\n")}${line}\n`;
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Append one entry to a `history:` list that ends the file, at the list's own
|
|
236
|
+
* indentation. Falls back to a document edit when `history:` is not the last
|
|
237
|
+
* top-level key; the caller's post-write check covers both paths.
|
|
238
|
+
*/
|
|
239
|
+
export function appendHistoryEntry(text, entry) {
|
|
240
|
+
const lines = text.replace(/\n*$/, "").split("\n");
|
|
241
|
+
const h = lines.findIndex((l) => /^history:\s*$/.test(l));
|
|
242
|
+
const laterTopLevel = h >= 0 && lines.slice(h + 1).some((l) => /^[A-Za-z_][\w-]*:/.test(l));
|
|
243
|
+
const item = lines.slice(h + 1).find((l) => /^\s*- /.test(l));
|
|
244
|
+
if (h < 0 || laterTopLevel || item === undefined) {
|
|
245
|
+
const doc = parseDocument(text);
|
|
246
|
+
doc.addIn(["history"], doc.createNode(entry));
|
|
247
|
+
return doc.toString({ lineWidth: 0 });
|
|
248
|
+
}
|
|
249
|
+
const indent = item.match(/^(\s*)- /)[1];
|
|
250
|
+
const body = stringify([entry], { lineWidth: 0 }).trimEnd().split("\n").map((l) => indent + l).join("\n");
|
|
251
|
+
return `${lines.join("\n")}\n${body}\n`;
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=advance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advance.js","sourceRoot":"","sources":["../../../src/lib/snapshot/advance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Writer = (s: string) => void;
|
|
2
|
+
export interface CatalogueDiffInputs {
|
|
3
|
+
sddPath: string;
|
|
4
|
+
from: string;
|
|
5
|
+
attribute: string;
|
|
6
|
+
}
|
|
7
|
+
/** Every file changed since `ref`, tracked or untracked. */
|
|
8
|
+
export declare function changedFiles(sddPath: string, ref: string): Promise<string[]>;
|
|
9
|
+
/** The changed files that must be attributed: minus catalogues and advance's pin bookkeeping. */
|
|
10
|
+
export declare function changedSourceFiles(sddPath: string, ref: string): Promise<string[]>;
|
|
11
|
+
export declare function targetSet(delta: unknown): string[];
|
|
12
|
+
export declare function attributed(file: string, targets: readonly string[]): boolean;
|
|
13
|
+
export declare function rowDelta(before: readonly string[], after: readonly string[]): {
|
|
14
|
+
added: number;
|
|
15
|
+
removed: number;
|
|
16
|
+
};
|
|
17
|
+
export declare function runCatalogueDiff(inputs: CatalogueDiffInputs, write: Writer): Promise<{
|
|
18
|
+
exitCode: number;
|
|
19
|
+
}>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=catalogue-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalogue-diff.d.ts","sourceRoot":"","sources":["../../../src/lib/snapshot/catalogue-diff.ts"],"names":[],"mappings":"AA2BA,KAAK,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAElC,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAQD,4DAA4D;AAC5D,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAIlF;AAED,iGAAiG;AACjG,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAExF;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAUlD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAE5E;AAYD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAYhH;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgDhH"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// `sdd-cli catalogue diff` — the catalogue consequence of a snapshot update,
|
|
2
|
+
// attributed at FILE grain (reverse-snapshot-delta step 10).
|
|
3
|
+
//
|
|
4
|
+
// It BUILDS both sides itself, in this one process: BEFORE from `git archive
|
|
5
|
+
// <ref>` of the SDD, AFTER from the working tree, each into a temporary output
|
|
6
|
+
// directory. Committed catalogues are never read — they are as old as their last
|
|
7
|
+
// build — and one process means one CLI, so a CLI change between the builds
|
|
8
|
+
// cannot appear as changed rows. Nothing is written into the SDD, its catalogues
|
|
9
|
+
// or its .git.
|
|
10
|
+
//
|
|
11
|
+
// Attribution is at file grain because catalogue rows carry no source-file
|
|
12
|
+
// provenance, so "every row names a finding" is not checkable:
|
|
13
|
+
// - every SDD source file changed since <ref> must appear in some finding's
|
|
14
|
+
// targets (the pin bookkeeping `snapshot advance` writes is exempt);
|
|
15
|
+
// - catalogue rows that changed while NO file changed (bookkeeping included)
|
|
16
|
+
// are unattributed by construction — the builder moved, not the snapshot.
|
|
17
|
+
// Exit 1 on any unattributed change.
|
|
18
|
+
import { execFile as execFileCb } from "node:child_process";
|
|
19
|
+
import { mkdir, mkdtemp, readdir, readFile, rm } from "node:fs/promises";
|
|
20
|
+
import { tmpdir } from "node:os";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { promisify } from "node:util";
|
|
23
|
+
import { parse } from "yaml";
|
|
24
|
+
import { runCatalogueBuild } from "../catalogue/build.js";
|
|
25
|
+
const execFile = promisify(execFileCb);
|
|
26
|
+
const EXEMPT = [/^catalogues\//, /^repos\/[^/]+\/reverse-(history|metadata)\.yaml$/];
|
|
27
|
+
async function git(cwd, args) {
|
|
28
|
+
return (await execFile("git", ["-C", cwd, ...args], { maxBuffer: 64 * 1024 * 1024 })).stdout;
|
|
29
|
+
}
|
|
30
|
+
/** Every file changed since `ref`, tracked or untracked. */
|
|
31
|
+
export async function changedFiles(sddPath, ref) {
|
|
32
|
+
const tracked = (await git(sddPath, ["diff", "--name-only", ref, "--"])).split("\n");
|
|
33
|
+
const untracked = (await git(sddPath, ["ls-files", "--others", "--exclude-standard"])).split("\n");
|
|
34
|
+
return [...new Set([...tracked, ...untracked].filter((p) => p !== ""))].sort();
|
|
35
|
+
}
|
|
36
|
+
/** The changed files that must be attributed: minus catalogues and advance's pin bookkeeping. */
|
|
37
|
+
export async function changedSourceFiles(sddPath, ref) {
|
|
38
|
+
return (await changedFiles(sddPath, ref)).filter((p) => !EXEMPT.some((re) => re.test(p)));
|
|
39
|
+
}
|
|
40
|
+
export function targetSet(delta) {
|
|
41
|
+
const findings = delta?.findings ?? [];
|
|
42
|
+
const out = new Set();
|
|
43
|
+
for (const f of findings) {
|
|
44
|
+
for (const t of f.targets ?? []) {
|
|
45
|
+
if (typeof t === "string")
|
|
46
|
+
out.add(t);
|
|
47
|
+
else if (t && typeof t === "object" && typeof t.artefact === "string")
|
|
48
|
+
out.add(t.artefact);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return [...out];
|
|
52
|
+
}
|
|
53
|
+
export function attributed(file, targets) {
|
|
54
|
+
return targets.some((t) => t === file || (t.endsWith("/") && file.startsWith(t)));
|
|
55
|
+
}
|
|
56
|
+
async function rowSets(dir) {
|
|
57
|
+
const out = new Map();
|
|
58
|
+
for (const f of await readdir(dir)) {
|
|
59
|
+
if (!f.endsWith(".csv"))
|
|
60
|
+
continue;
|
|
61
|
+
const lines = (await readFile(join(dir, f), "utf8")).split("\n").filter((l) => l !== "");
|
|
62
|
+
out.set(f.replace(/\.csv$/, ""), lines.slice(1));
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
export function rowDelta(before, after) {
|
|
67
|
+
const count = new Map();
|
|
68
|
+
for (const r of before)
|
|
69
|
+
count.set(r, (count.get(r) ?? 0) + 1);
|
|
70
|
+
let added = 0;
|
|
71
|
+
for (const r of after) {
|
|
72
|
+
const c = count.get(r) ?? 0;
|
|
73
|
+
if (c > 0)
|
|
74
|
+
count.set(r, c - 1);
|
|
75
|
+
else
|
|
76
|
+
added++;
|
|
77
|
+
}
|
|
78
|
+
let removed = 0;
|
|
79
|
+
for (const c of count.values())
|
|
80
|
+
removed += c;
|
|
81
|
+
return { added, removed };
|
|
82
|
+
}
|
|
83
|
+
export async function runCatalogueDiff(inputs, write) {
|
|
84
|
+
const { sddPath, from } = inputs;
|
|
85
|
+
const delta = parse(await readFile(inputs.attribute, "utf8"));
|
|
86
|
+
const targets = targetSet(delta);
|
|
87
|
+
const work = await mkdtemp(join(tmpdir(), "sdd-cli-catalogue-diff-"));
|
|
88
|
+
try {
|
|
89
|
+
await git(sddPath, ["rev-parse", "--verify", `${from}^{commit}`]);
|
|
90
|
+
const beforeTree = join(work, "before-tree");
|
|
91
|
+
await mkdir(beforeTree);
|
|
92
|
+
await execFile("git", ["-C", sddPath, "archive", "-o", join(work, "before.tar"), from]);
|
|
93
|
+
await execFile("tar", ["-xf", join(work, "before.tar"), "-C", beforeTree]);
|
|
94
|
+
const sink = () => { };
|
|
95
|
+
const b = await runCatalogueBuild({ sddPath: beforeTree, outDir: join(work, "before") }, sink);
|
|
96
|
+
const a = await runCatalogueBuild({ sddPath, outDir: join(work, "after") }, sink);
|
|
97
|
+
write(`built both sides in one process (schema ${a.schemaVersion}); before exit ${b.exitCode}, after exit ${a.exitCode}\n`);
|
|
98
|
+
const before = await rowSets(join(work, "before"));
|
|
99
|
+
const after = await rowSets(join(work, "after"));
|
|
100
|
+
const changedCatalogues = [];
|
|
101
|
+
for (const name of [...new Set([...before.keys(), ...after.keys()])].sort()) {
|
|
102
|
+
const d = rowDelta(before.get(name) ?? [], after.get(name) ?? []);
|
|
103
|
+
if (d.added + d.removed > 0)
|
|
104
|
+
changedCatalogues.push([name, d]);
|
|
105
|
+
}
|
|
106
|
+
const all = (await changedFiles(sddPath, from)).filter((p) => !p.startsWith("catalogues/"));
|
|
107
|
+
const files = all.filter((p) => !EXEMPT.some((re) => re.test(p)));
|
|
108
|
+
const unattributed = files.filter((f) => !attributed(f, targets));
|
|
109
|
+
write(`\nsource files changed since ${from}: ${files.length} (${files.length - unattributed.length} attributed to a finding's targets)\n`);
|
|
110
|
+
for (const f of unattributed)
|
|
111
|
+
write(` UNATTRIBUTED ${f}\n`);
|
|
112
|
+
write(`\ncatalogues with changed rows: ${changedCatalogues.length}\n`);
|
|
113
|
+
for (const [name, d] of changedCatalogues)
|
|
114
|
+
write(` ${name}: +${d.added} -${d.removed}\n`);
|
|
115
|
+
let failed = unattributed.length > 0;
|
|
116
|
+
// Exempt files (the pin bookkeeping) are excused from attribution, not from
|
|
117
|
+
// feeding catalogues: they count here, or advance's own edits look like drift.
|
|
118
|
+
if (all.length === 0 && changedCatalogues.length > 0) {
|
|
119
|
+
write("\nUNATTRIBUTED: catalogue rows changed while no file did — that is the builder, not the snapshot\n");
|
|
120
|
+
failed = true;
|
|
121
|
+
}
|
|
122
|
+
if (failed) {
|
|
123
|
+
write("\nFAIL: each unattributed change is an unrecorded finding or an unintended edit — resolve which\n");
|
|
124
|
+
return { exitCode: 1 };
|
|
125
|
+
}
|
|
126
|
+
write("\nPASS: every changed source file is a target of some finding\n");
|
|
127
|
+
return { exitCode: 0 };
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
await rm(work, { recursive: true, force: true });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=catalogue-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalogue-diff.js","sourceRoot":"","sources":["../../../src/lib/snapshot/catalogue-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type SnapshotManifest } from "./manifest.js";
|
|
2
|
+
type Writer = (s: string) => void;
|
|
3
|
+
export interface DiffInputs {
|
|
4
|
+
areaRoot: string;
|
|
5
|
+
to: string;
|
|
6
|
+
from?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A deliberately coarse, documented path classifier. It groups files so each
|
|
10
|
+
* finding is reviewable; it does not decide what a change means (that is
|
|
11
|
+
* classification, which is judgement). First match wins.
|
|
12
|
+
*/
|
|
13
|
+
export declare const EVIDENCE_CLASSES: ReadonlyArray<readonly [string, RegExp]>;
|
|
14
|
+
export declare function evidenceClass(path: string): string;
|
|
15
|
+
export interface DeltaFinding {
|
|
16
|
+
id: string;
|
|
17
|
+
member: string;
|
|
18
|
+
evidence_class: string;
|
|
19
|
+
status: "proposed" | "noted" | "closed";
|
|
20
|
+
classification: string | null;
|
|
21
|
+
spec_impact: string | null;
|
|
22
|
+
summary: string;
|
|
23
|
+
files: {
|
|
24
|
+
added: string[];
|
|
25
|
+
removed: string[];
|
|
26
|
+
modified: string[];
|
|
27
|
+
};
|
|
28
|
+
targets: unknown[];
|
|
29
|
+
}
|
|
30
|
+
export interface DeltaYaml {
|
|
31
|
+
implementation: string;
|
|
32
|
+
from_snapshot: string;
|
|
33
|
+
to_snapshot: string;
|
|
34
|
+
members_changed: Array<{
|
|
35
|
+
canonical_repo_key: string;
|
|
36
|
+
from_revision: string;
|
|
37
|
+
to_revision: string;
|
|
38
|
+
files: {
|
|
39
|
+
added: number;
|
|
40
|
+
removed: number;
|
|
41
|
+
modified: number;
|
|
42
|
+
};
|
|
43
|
+
}>;
|
|
44
|
+
members_added: Array<{
|
|
45
|
+
canonical_repo_key: string;
|
|
46
|
+
to_revision: string;
|
|
47
|
+
}>;
|
|
48
|
+
members_removed: Array<{
|
|
49
|
+
canonical_repo_key: string;
|
|
50
|
+
last_revision: string;
|
|
51
|
+
reason: string;
|
|
52
|
+
}>;
|
|
53
|
+
members_carried: Array<{
|
|
54
|
+
canonical_repo_key: string;
|
|
55
|
+
carried_from: string;
|
|
56
|
+
carried_reason: string;
|
|
57
|
+
}>;
|
|
58
|
+
members_unchanged: number;
|
|
59
|
+
disposition: string | null;
|
|
60
|
+
impact: string | null;
|
|
61
|
+
findings: DeltaFinding[];
|
|
62
|
+
open_questions: unknown[];
|
|
63
|
+
}
|
|
64
|
+
export declare function deltaPath(areaRoot: string, id: string): string;
|
|
65
|
+
/** Findings that already carry judgement — the reason diff will not rewrite. */
|
|
66
|
+
export declare function judgedFindings(existing: unknown): string[];
|
|
67
|
+
export declare function runSnapshotDiff(inputs: DiffInputs, write: Writer): Promise<{
|
|
68
|
+
exitCode: number;
|
|
69
|
+
}>;
|
|
70
|
+
export declare function snapshotDiff(inputs: DiffInputs): Promise<DeltaYaml>;
|
|
71
|
+
export declare function computeDelta(areaRoot: string, t0: SnapshotManifest, t1: SnapshotManifest): Promise<DeltaYaml>;
|
|
72
|
+
export {};
|
|
73
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/lib/snapshot/diff.ts"],"names":[],"mappings":"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"}
|