@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.
Files changed (97) hide show
  1. package/dist/index.d.ts.map +1 -1
  2. package/dist/index.js +2 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/lib/catalogue/graph-run.d.ts +1 -28
  5. package/dist/lib/catalogue/graph-run.d.ts.map +1 -1
  6. package/dist/lib/catalogue/graph-run.js +3 -57
  7. package/dist/lib/catalogue/graph-run.js.map +1 -1
  8. package/dist/lib/catalogue/impact-run.d.ts +1 -1
  9. package/dist/lib/catalogue/impact-run.d.ts.map +1 -1
  10. package/dist/lib/catalogue/impact-run.js +1 -1
  11. package/dist/lib/catalogue/impact-run.js.map +1 -1
  12. package/dist/lib/catalogue/relationship-semantics.d.ts +29 -0
  13. package/dist/lib/catalogue/relationship-semantics.d.ts.map +1 -0
  14. package/dist/lib/catalogue/relationship-semantics.js +66 -0
  15. package/dist/lib/catalogue/relationship-semantics.js.map +1 -0
  16. package/dist/lib/pack/index.d.ts +1 -9
  17. package/dist/lib/pack/index.d.ts.map +1 -1
  18. package/dist/lib/pack/index.js +2 -53
  19. package/dist/lib/pack/index.js.map +1 -1
  20. package/dist/lib/pack/log.d.ts +6 -0
  21. package/dist/lib/pack/log.d.ts.map +1 -0
  22. package/dist/lib/pack/log.js +18 -0
  23. package/dist/lib/pack/log.js.map +1 -0
  24. package/dist/lib/pack/validate.d.ts +10 -0
  25. package/dist/lib/pack/validate.d.ts.map +1 -0
  26. package/dist/lib/pack/validate.js +49 -0
  27. package/dist/lib/pack/validate.js.map +1 -0
  28. package/dist/lib/snapshot/advance.d.ts +39 -0
  29. package/dist/lib/snapshot/advance.d.ts.map +1 -0
  30. package/dist/lib/snapshot/advance.js +253 -0
  31. package/dist/lib/snapshot/advance.js.map +1 -0
  32. package/dist/lib/snapshot/catalogue-diff.d.ts +21 -0
  33. package/dist/lib/snapshot/catalogue-diff.d.ts.map +1 -0
  34. package/dist/lib/snapshot/catalogue-diff.js +133 -0
  35. package/dist/lib/snapshot/catalogue-diff.js.map +1 -0
  36. package/dist/lib/snapshot/diff.d.ts +73 -0
  37. package/dist/lib/snapshot/diff.d.ts.map +1 -0
  38. package/dist/lib/snapshot/diff.js +177 -0
  39. package/dist/lib/snapshot/diff.js.map +1 -0
  40. package/dist/lib/snapshot/fold.d.ts +14 -0
  41. package/dist/lib/snapshot/fold.d.ts.map +1 -0
  42. package/dist/lib/snapshot/fold.js +106 -0
  43. package/dist/lib/snapshot/fold.js.map +1 -0
  44. package/dist/lib/snapshot/land.d.ts +21 -0
  45. package/dist/lib/snapshot/land.d.ts.map +1 -0
  46. package/dist/lib/snapshot/land.js +160 -0
  47. package/dist/lib/snapshot/land.js.map +1 -0
  48. package/dist/lib/snapshot/manifest.d.ts +59 -0
  49. package/dist/lib/snapshot/manifest.d.ts.map +1 -0
  50. package/dist/lib/snapshot/manifest.js +152 -0
  51. package/dist/lib/snapshot/manifest.js.map +1 -0
  52. package/dist/lib/snapshot/targets.d.ts +26 -0
  53. package/dist/lib/snapshot/targets.d.ts.map +1 -0
  54. package/dist/lib/snapshot/targets.js +121 -0
  55. package/dist/lib/snapshot/targets.js.map +1 -0
  56. package/dist/lib/snapshot/verify.d.ts +18 -0
  57. package/dist/lib/snapshot/verify.d.ts.map +1 -0
  58. package/dist/lib/snapshot/verify.js +82 -0
  59. package/dist/lib/snapshot/verify.js.map +1 -0
  60. package/dist/verbs/catalogue-verify.d.ts +6 -0
  61. package/dist/verbs/catalogue-verify.d.ts.map +1 -0
  62. package/dist/verbs/catalogue-verify.js +114 -0
  63. package/dist/verbs/catalogue-verify.js.map +1 -0
  64. package/dist/verbs/catalogue.d.ts.map +1 -1
  65. package/dist/verbs/catalogue.js +15 -90
  66. package/dist/verbs/catalogue.js.map +1 -1
  67. package/dist/verbs/pack-validate.d.ts +3 -0
  68. package/dist/verbs/pack-validate.d.ts.map +1 -0
  69. package/dist/verbs/pack-validate.js +17 -0
  70. package/dist/verbs/pack-validate.js.map +1 -0
  71. package/dist/verbs/pack.d.ts.map +1 -1
  72. package/dist/verbs/pack.js +3 -10
  73. package/dist/verbs/pack.js.map +1 -1
  74. package/dist/verbs/snapshot.d.ts +3 -0
  75. package/dist/verbs/snapshot.d.ts.map +1 -0
  76. package/dist/verbs/snapshot.js +119 -0
  77. package/dist/verbs/snapshot.js.map +1 -0
  78. package/dist/verify-bin.d.ts +3 -0
  79. package/dist/verify-bin.d.ts.map +1 -0
  80. package/dist/verify-bin.js +8 -0
  81. package/dist/verify-bin.js.map +1 -0
  82. package/dist/verify-program.d.ts +14 -0
  83. package/dist/verify-program.d.ts.map +1 -0
  84. package/dist/verify-program.js +115 -0
  85. package/dist/verify-program.js.map +1 -0
  86. package/package.json +3 -3
  87. package/scripts/build-verify-package.mjs +199 -0
  88. package/scripts/verify-acceptance.sh +178 -0
  89. package/dist/conformance-bin.d.ts +0 -3
  90. package/dist/conformance-bin.d.ts.map +0 -1
  91. package/dist/conformance-bin.js +0 -8
  92. package/dist/conformance-bin.js.map +0 -1
  93. package/dist/conformance-program.d.ts +0 -6
  94. package/dist/conformance-program.d.ts.map +0 -1
  95. package/dist/conformance-program.js +0 -59
  96. package/dist/conformance-program.js.map +0 -1
  97. package/scripts/build-conformance-package.mjs +0 -57
@@ -0,0 +1,177 @@
1
+ // `sdd-cli snapshot diff` — the member and file delta between two baselines,
2
+ // written as delta.yaml's skeleton (delta-reverse.md §4 and §6).
3
+ //
4
+ // Members are classified from the two MANIFESTS, never the folder trees: a
5
+ // carried member is absent from T1's tree and present in the set, and a tree
6
+ // diff calls it removed. A prior member that T1's manifest neither lists nor
7
+ // records in members_removed is refused — the manifest is incomplete.
8
+ //
9
+ // Findings are one per changed member × evidence class, at `status: proposed`,
10
+ // with classification / spec_impact / targets left for judgement. Once any
11
+ // finding carries judgement, diff refuses to rewrite the file.
12
+ import { readFile, writeFile } from "node:fs/promises";
13
+ import { join } from "node:path";
14
+ import { parse, stringify } from "yaml";
15
+ import { SnapshotError, diffTrees, exists, hashTree, memberBytesDir, readManifest, } from "./manifest.js";
16
+ /**
17
+ * A deliberately coarse, documented path classifier. It groups files so each
18
+ * finding is reviewable; it does not decide what a change means (that is
19
+ * classification, which is judgement). First match wins.
20
+ */
21
+ export const EVIDENCE_CLASSES = [
22
+ ["contracts", /\.(avsc|proto|graphql|wsdl|xsd)$|(^|\/)(openapi|swagger|asyncapi)[^/]*\.(ya?ml|json)$/i],
23
+ ["tests", /(^|\/)(test|tests|__tests__|spec|it|e2e)\/|\.(test|spec)\.[a-z]+$|Tests?\.[a-z]+$/i],
24
+ ["infrastructure", /\.(tf|tfvars|bicep)$|(^|\/)(helm|charts|k8s|kubernetes|deploy|deployment|terraform)\//i],
25
+ ["build", /(^|\/)(pom\.xml|build\.gradle(\.kts)?|settings\.gradle(\.kts)?|package\.json|package-lock\.json|yarn\.lock|pnpm-lock\.yaml|go\.mod|go\.sum|Cargo\.toml|Dockerfile[^/]*|Makefile|\.csproj|.*\.sln)$|(^|\/)\.(github|gitlab-ci|circleci)|Jenkinsfile$|bitbucket-pipelines\.yml$/i],
26
+ ["configuration", /\.(ya?ml|properties|json|toml|ini|conf|env|config)$/i],
27
+ ["documentation", /\.(md|adoc|rst|txt)$/i],
28
+ ["source", /./],
29
+ ];
30
+ export function evidenceClass(path) {
31
+ for (const [name, re] of EVIDENCE_CLASSES)
32
+ if (re.test(path))
33
+ return name;
34
+ return "source";
35
+ }
36
+ export function deltaPath(areaRoot, id) {
37
+ return join(areaRoot, id, "delta.yaml");
38
+ }
39
+ /** Findings that already carry judgement — the reason diff will not rewrite. */
40
+ export function judgedFindings(existing) {
41
+ const findings = existing?.findings;
42
+ if (!Array.isArray(findings))
43
+ return [];
44
+ return findings.flatMap((f, i) => {
45
+ const x = f;
46
+ const judged = (x.status !== undefined && x.status !== "proposed") ||
47
+ (x.classification !== undefined && x.classification !== null) ||
48
+ (x.spec_impact !== undefined && x.spec_impact !== null);
49
+ return judged ? [String(x.id ?? `findings[${i}]`)] : [];
50
+ });
51
+ }
52
+ export async function runSnapshotDiff(inputs, write) {
53
+ try {
54
+ const d = await snapshotDiff(inputs);
55
+ write(`${d.from_snapshot} → ${d.to_snapshot}: ${d.members_changed.length} changed, ${d.members_unchanged} unchanged, ` +
56
+ `${d.members_added.length} added, ${d.members_removed.length} removed, ${d.members_carried.length} carried; ` +
57
+ `${d.findings.length} finding(s) at status proposed → ${deltaPath(inputs.areaRoot, inputs.to)}\n`);
58
+ return { exitCode: 0 };
59
+ }
60
+ catch (e) {
61
+ if (e instanceof SnapshotError) {
62
+ write(`REFUSED: ${e.message}\n`);
63
+ return { exitCode: 1 };
64
+ }
65
+ throw e;
66
+ }
67
+ }
68
+ export async function snapshotDiff(inputs) {
69
+ const { areaRoot, to } = inputs;
70
+ const t1 = await readManifest(areaRoot, to);
71
+ const fromId = inputs.from ?? t1.prior_snapshot;
72
+ if (!fromId)
73
+ throw new SnapshotError(`${to} has no prior_snapshot; pass --from`);
74
+ const t0 = await readManifest(areaRoot, fromId);
75
+ const out = deltaPath(areaRoot, to);
76
+ if (await exists(out)) {
77
+ const judged = judgedFindings(parse(await readFile(out, "utf8")));
78
+ if (judged.length > 0) {
79
+ throw new SnapshotError(`${out} already holds judgement on ${judged.length} finding(s) (${judged.slice(0, 5).join(", ")}${judged.length > 5 ? ", …" : ""}) — diff will not overwrite it`);
80
+ }
81
+ }
82
+ const delta = await computeDelta(areaRoot, t0, t1);
83
+ const header = "# Snapshot delta -- reverse/workflows/delta-reverse.md §6. Skeleton written by `sdd-cli snapshot diff`;\n" +
84
+ "# classification, spec_impact and targets are judgement (steps 5-6). Once any is set, diff will not rewrite this file.\n";
85
+ await writeFile(out, header + stringify(delta, { lineWidth: 0 }));
86
+ return delta;
87
+ }
88
+ export async function computeDelta(areaRoot, t0, t1) {
89
+ const t0ByKey = new Map(t0.members.map((m) => [m.canonical_repo_key, m]));
90
+ const t1Keys = new Set(t1.members.map((m) => m.canonical_repo_key));
91
+ const removedKeys = new Set((t1.members_removed ?? []).map((r) => r.canonical_repo_key));
92
+ const unaccounted = t0.members.filter((m) => !t1Keys.has(m.canonical_repo_key) && !removedKeys.has(m.canonical_repo_key));
93
+ if (unaccounted.length > 0) {
94
+ throw new SnapshotError(`${t1.snapshot_id}'s manifest does not account for ${unaccounted.map((m) => m.canonical_repo_key).join(", ")} from ${t0.snapshot_id} — ` +
95
+ "each must be a member (carried or re-observed) or in members_removed[]");
96
+ }
97
+ const delta = {
98
+ implementation: t1.implementation,
99
+ from_snapshot: t0.snapshot_id,
100
+ to_snapshot: t1.snapshot_id,
101
+ members_changed: [],
102
+ members_added: [],
103
+ members_removed: (t1.members_removed ?? []).map((r) => ({ canonical_repo_key: r.canonical_repo_key, last_revision: r.last_revision, reason: r.reason })),
104
+ members_carried: [],
105
+ members_unchanged: 0,
106
+ disposition: null,
107
+ impact: null,
108
+ findings: [],
109
+ open_questions: [],
110
+ };
111
+ for (const m of t1.members) {
112
+ const p = t0ByKey.get(m.canonical_repo_key);
113
+ if (!p) {
114
+ delta.members_added.push({ canonical_repo_key: m.canonical_repo_key, to_revision: m.source_revision });
115
+ // A new member gets the full seeding sequence, not a delta — but what the
116
+ // seeding writes must still trace to a finding, so it gets one.
117
+ delta.findings.push(memberFinding(m.canonical_repo_key, "member-added", `new member at ${m.source_revision}: seed it (full sequence), then target what it grounds`));
118
+ continue;
119
+ }
120
+ if (m.carried_from !== undefined) {
121
+ delta.members_carried.push({ canonical_repo_key: m.canonical_repo_key, carried_from: m.carried_from, carried_reason: m.carried_reason ?? "" });
122
+ delta.members_unchanged++;
123
+ continue;
124
+ }
125
+ if (p.source_revision === m.source_revision) {
126
+ delta.members_unchanged++;
127
+ continue;
128
+ }
129
+ const files = diffTrees(await hashTree(memberBytesDir(areaRoot, t0, p)), await hashTree(memberBytesDir(areaRoot, t1, m)));
130
+ delta.members_changed.push({
131
+ canonical_repo_key: m.canonical_repo_key,
132
+ from_revision: p.source_revision,
133
+ to_revision: m.source_revision,
134
+ files: { added: files.added.length, removed: files.removed.length, modified: files.modified.length },
135
+ });
136
+ const byClass = new Map();
137
+ for (const kind of ["added", "removed", "modified"]) {
138
+ for (const f of files[kind]) {
139
+ const c = evidenceClass(f);
140
+ if (!byClass.has(c))
141
+ byClass.set(c, { added: [], removed: [], modified: [] });
142
+ byClass.get(c)[kind].push(f);
143
+ }
144
+ }
145
+ for (const [c, fs] of [...byClass].sort(([a], [b]) => a.localeCompare(b))) {
146
+ delta.findings.push({
147
+ id: `${m.canonical_repo_key}.${c}`,
148
+ member: m.canonical_repo_key,
149
+ evidence_class: c,
150
+ status: "proposed",
151
+ classification: null,
152
+ spec_impact: null,
153
+ summary: `${fs.added.length} added, ${fs.removed.length} removed, ${fs.modified.length} modified ${c} file(s)`,
154
+ files: fs,
155
+ targets: [],
156
+ });
157
+ }
158
+ }
159
+ for (const r of t1.members_removed ?? []) {
160
+ delta.findings.push(memberFinding(r.canonical_repo_key, "member-removed", `left the set (${r.reason}); a removed member is not a removed capability until you have checked where the capability went`));
161
+ }
162
+ return delta;
163
+ }
164
+ function memberFinding(member, kind, summary) {
165
+ return {
166
+ id: `${member}.${kind}`,
167
+ member,
168
+ evidence_class: kind,
169
+ status: "proposed",
170
+ classification: null,
171
+ spec_impact: null,
172
+ summary,
173
+ files: { added: [], removed: [], modified: [] },
174
+ targets: [],
175
+ };
176
+ }
177
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/lib/snapshot/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ type Writer = (s: string) => void;
2
+ export interface FoldInputs {
3
+ areaRoot: string;
4
+ id?: string;
5
+ implementation?: string;
6
+ keys?: ReadonlyMap<string, string>;
7
+ scanRoots?: readonly string[];
8
+ today?: string;
9
+ }
10
+ export declare function runSnapshotFold(inputs: FoldInputs, write: Writer): Promise<{
11
+ exitCode: number;
12
+ }>;
13
+ export {};
14
+ //# sourceMappingURL=fold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../../../src/lib/snapshot/fold.ts"],"names":[],"mappings":"AAwBA,KAAK,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAElC,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmCD,wBAAsB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAyDtG"}
@@ -0,0 +1,106 @@
1
+ // `sdd-cli snapshot fold` — move a flat `source/<repo>@<rev>/` area into its
2
+ // first dated baseline (delta-reverse.md §1), once per area.
3
+ //
4
+ // Then it LISTS every reference to the old paths it can find under the scan
5
+ // roots — relative and absolute alike, since citations use both and a search
6
+ // for one form misses the other. The list is a print, not a control: nothing
7
+ // fails if a reference is left, so the report says so. Scan the whole estate,
8
+ // not only the owning SDD — other SDDs cite this area's baselines.
9
+ import { mkdir, readdir, readFile, rename, stat, writeFile } from "node:fs/promises";
10
+ import { join, relative, sep } from "node:path";
11
+ import { stringify } from "yaml";
12
+ import { SnapshotError, baselineIds, exists, isIsoDate, manifestPath, memberFolders, splitFolder, } from "./manifest.js";
13
+ const SKIP = new Set([".git", "node_modules"]);
14
+ const TEXT = /\.(md|ya?ml|json|txt|adoc|csv|properties|toml)$/i;
15
+ async function references(root, folders, id) {
16
+ const out = [];
17
+ async function walk(dir) {
18
+ let entries;
19
+ try {
20
+ entries = await readdir(dir, { withFileTypes: true });
21
+ }
22
+ catch {
23
+ return;
24
+ }
25
+ for (const e of entries) {
26
+ const full = join(dir, e.name);
27
+ if (e.isDirectory()) {
28
+ if (!SKIP.has(e.name) && !isIsoDate(e.name))
29
+ await walk(full);
30
+ }
31
+ else if (e.isFile() && TEXT.test(e.name) && (await stat(full)).size <= 4 * 1024 * 1024) {
32
+ const lines = (await readFile(full, "utf8")).split("\n");
33
+ lines.forEach((line, i) => {
34
+ for (const f of folders) {
35
+ if (line.includes(f) && !line.includes(`${id}/${f}`)) {
36
+ out.push(`${relative(root, full).split(sep).join("/")}:${i + 1}: ${f}`);
37
+ break;
38
+ }
39
+ }
40
+ });
41
+ }
42
+ }
43
+ }
44
+ await walk(root);
45
+ return out;
46
+ }
47
+ export async function runSnapshotFold(inputs, write) {
48
+ try {
49
+ const { areaRoot, id } = inputs;
50
+ const today = inputs.today ?? new Date().toISOString().slice(0, 10);
51
+ if (id === undefined)
52
+ throw new SnapshotError("--id is required: the date the flat exports were OBSERVED");
53
+ if (!isIsoDate(id) || id > today)
54
+ throw new SnapshotError(`--id '${id}' is not a past or present YYYY-MM-DD date`);
55
+ if (!inputs.implementation)
56
+ throw new SnapshotError("--implementation is required: the durable system identity (M-ADR 0181 §2.5)");
57
+ const existing = await baselineIds(areaRoot);
58
+ for (const b of existing) {
59
+ if (await exists(manifestPath(areaRoot, b)))
60
+ throw new SnapshotError(`${areaRoot} is already folded (baseline ${b} has a manifest)`);
61
+ }
62
+ const folders = await memberFolders(areaRoot);
63
+ if (folders.length === 0)
64
+ throw new SnapshotError(`no flat <repo>@<revision>/ folders directly under ${areaRoot}`);
65
+ const members = folders.map((f) => {
66
+ const { stem, revision } = splitFolder(f);
67
+ return {
68
+ canonical_repo_key: inputs.keys?.get(f) ?? stem.replace(/-(master|main|develop|trunk)$/, ""),
69
+ exported_folder_name: f,
70
+ source_revision: revision,
71
+ };
72
+ });
73
+ const target = join(areaRoot, id);
74
+ if (await exists(target))
75
+ throw new SnapshotError(`${target} already exists`);
76
+ await mkdir(target);
77
+ for (const f of folders)
78
+ await rename(join(areaRoot, f), join(target, f));
79
+ const manifest = { snapshot_id: id, observed_at: id, implementation: inputs.implementation, prior_snapshot: null, members };
80
+ await writeFile(manifestPath(areaRoot, id), "# Implementation-set snapshot (baseline) -- written by `sdd-cli snapshot fold`.\n" + stringify(manifest, { lineWidth: 0 }));
81
+ write(`folded ${folders.length} member(s) into ${target}\n`);
82
+ const roots = inputs.scanRoots ?? [];
83
+ if (roots.length === 0) {
84
+ write("WARNING: no --scan roots given, so no references were listed. Every citation of the old paths is now stale.\n");
85
+ return { exitCode: 0 };
86
+ }
87
+ let n = 0;
88
+ for (const r of roots) {
89
+ for (const hit of await references(r, folders, id)) {
90
+ write(` ${r}/${hit}\n`);
91
+ n++;
92
+ }
93
+ }
94
+ write(`${n} line(s) still cite a pre-fold path. This list is a print, not a control: nothing fails if one is left — ` +
95
+ "re-point each (reverse-metadata source_path first) and check it resolves on disk.\n");
96
+ return { exitCode: 0 };
97
+ }
98
+ catch (e) {
99
+ if (e instanceof SnapshotError) {
100
+ write(`REFUSED: ${e.message}\n`);
101
+ return { exitCode: 1 };
102
+ }
103
+ throw e;
104
+ }
105
+ }
106
+ //# sourceMappingURL=fold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold.js","sourceRoot":"","sources":["../../../src/lib/snapshot/fold.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { type CredentialScan, type SnapshotManifest } from "./manifest.js";
2
+ type Writer = (s: string) => void;
3
+ export interface LandInputs {
4
+ areaRoot: string;
5
+ id?: string;
6
+ prior?: string;
7
+ implementation?: string;
8
+ memberDates?: ReadonlyMap<string, string>;
9
+ carried?: ReadonlyMap<string, string>;
10
+ removed?: ReadonlyMap<string, string>;
11
+ keys?: ReadonlyMap<string, string>;
12
+ credentialScan?: Partial<CredentialScan>;
13
+ notes?: string;
14
+ today?: string;
15
+ }
16
+ export declare function runSnapshotLand(inputs: LandInputs, write: Writer): Promise<{
17
+ exitCode: number;
18
+ }>;
19
+ export declare function land(inputs: LandInputs, write: Writer): Promise<SnapshotManifest>;
20
+ export {};
21
+ //# sourceMappingURL=land.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"land.d.ts","sourceRoot":"","sources":["../../../src/lib/snapshot/land.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,gBAAgB,EAYtB,MAAM,eAAe,CAAC;AAEvB,KAAK,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAElC,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,cAAc,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,wBAAsB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAYtG;AAED,wBAAsB,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkIvF"}
@@ -0,0 +1,160 @@
1
+ // `sdd-cli snapshot land` — write T1's set manifest (delta-reverse.md §2).
2
+ //
3
+ // Refusals, each a failure a hand run actually made:
4
+ // - no --id, or an id in the future: the baseline id is the OBSERVATION date and
5
+ // has no default, so the processing date cannot slip in unasked;
6
+ // - a member observed after the set date;
7
+ // - a prior member absent from the export and not declared carried (with a
8
+ // reason) or removed (with a reason) — never left to be inferred;
9
+ // - a member re-exported at the same revision whose bytes differ;
10
+ // - no recorded credential scan, or one whose result is not `clean`;
11
+ // - an existing snapshot.yaml (no overwrite).
12
+ import { writeFile } from "node:fs/promises";
13
+ import { join } from "node:path";
14
+ import { stringify } from "yaml";
15
+ import { SnapshotError, baselineIds, diffTrees, exists, hashTree, isIsoDate, manifestPath, memberBytesDir, memberFolders, readManifest, splitFolder, } from "./manifest.js";
16
+ const BRANCH_SUFFIX = /-(master|main|develop|trunk)$/;
17
+ export async function runSnapshotLand(inputs, write) {
18
+ try {
19
+ const m = await land(inputs, write);
20
+ write(`landed ${m.snapshot_id}: ${m.members.length} member(s), ${m.members_removed?.length ?? 0} removed\n`);
21
+ return { exitCode: 0 };
22
+ }
23
+ catch (e) {
24
+ if (e instanceof SnapshotError) {
25
+ write(`REFUSED: ${e.message}\n`);
26
+ return { exitCode: 1 };
27
+ }
28
+ throw e;
29
+ }
30
+ }
31
+ export async function land(inputs, write) {
32
+ const { areaRoot } = inputs;
33
+ const today = inputs.today ?? new Date().toISOString().slice(0, 10);
34
+ const id = inputs.id;
35
+ if (id === undefined) {
36
+ throw new SnapshotError("--id is required: the date the snapshot was OBSERVED. It has no default, so the date it was processed cannot stand in for it.");
37
+ }
38
+ if (!isIsoDate(id))
39
+ throw new SnapshotError(`--id '${id}' is not a YYYY-MM-DD date`);
40
+ if (id > today)
41
+ throw new SnapshotError(`--id ${id} is in the future (today is ${today})`);
42
+ const dir = join(areaRoot, id);
43
+ if (!(await exists(dir)))
44
+ throw new SnapshotError(`no baseline folder ${dir} — export the members into it first`);
45
+ if (await exists(manifestPath(areaRoot, id))) {
46
+ throw new SnapshotError(`${manifestPath(areaRoot, id)} already exists — land does not overwrite a manifest`);
47
+ }
48
+ const priorId = inputs.prior ?? (await baselineIds(areaRoot)).filter((b) => b < id).pop();
49
+ const prior = priorId === undefined ? null : await readManifest(areaRoot, priorId);
50
+ const implementation = inputs.implementation ?? prior?.implementation;
51
+ if (!implementation)
52
+ throw new SnapshotError("--implementation is required when there is no prior baseline");
53
+ const scan = inputs.credentialScan;
54
+ if (!scan || !scan.tool || !scan.version || !scan.date || !scan.result) {
55
+ throw new SnapshotError("a credential scan must be recorded before anything reads the tree: --credential-scan tool=…,version=…,date=YYYY-MM-DD,result=clean");
56
+ }
57
+ if (!isIsoDate(scan.date))
58
+ throw new SnapshotError(`credential scan date '${scan.date}' is not YYYY-MM-DD`);
59
+ if (scan.result !== "clean")
60
+ throw new SnapshotError(`credential scan result is '${scan.result}', not 'clean' — remediate before landing`);
61
+ const priorByKey = new Map((prior?.members ?? []).map((m) => [m.canonical_repo_key, m]));
62
+ const priorByStem = new Map((prior?.members ?? []).flatMap((m) => {
63
+ const s = splitFolder(m.exported_folder_name);
64
+ return s ? [[s.stem, m.canonical_repo_key]] : [];
65
+ }));
66
+ const members = [];
67
+ const seen = new Set();
68
+ for (const folder of await memberFolders(dir)) {
69
+ const { stem, revision } = splitFolder(folder);
70
+ let key = inputs.keys?.get(folder) ?? priorByStem.get(stem);
71
+ if (key === undefined) {
72
+ key = stem.replace(BRANCH_SUFFIX, "");
73
+ write(`note: ${folder} is new; canonical_repo_key derived as '${key}' (override with --key ${folder}=<key>)\n`);
74
+ }
75
+ if (seen.has(key))
76
+ throw new SnapshotError(`two member folders resolve to canonical_repo_key '${key}'`);
77
+ seen.add(key);
78
+ const entry = { canonical_repo_key: key, exported_folder_name: folder, source_revision: revision };
79
+ const md = inputs.memberDates?.get(key);
80
+ if (md !== undefined) {
81
+ if (!isIsoDate(md))
82
+ throw new SnapshotError(`--member-date ${key}=${md} is not YYYY-MM-DD`);
83
+ if (md > id)
84
+ throw new SnapshotError(`member ${key} observed ${md}, after the set date ${id}`);
85
+ if (md !== id)
86
+ entry.observed_at = md;
87
+ }
88
+ const p = priorByKey.get(key);
89
+ if (prior && p && p.source_revision === revision) {
90
+ const before = await hashTree(memberBytesDir(areaRoot, prior, p));
91
+ const after = await hashTree(join(dir, folder));
92
+ const d = diffTrees(before, after);
93
+ const changed = d.added.length + d.removed.length + d.modified.length;
94
+ if (changed > 0) {
95
+ throw new SnapshotError(`${key} was re-exported at the same revision ${revision} as ${prior.snapshot_id}, but ${changed} file(s) differ — one of the two exports is not what its name says`);
96
+ }
97
+ entry.reverified_at = md ?? id;
98
+ entry.reverification = `re-exported at the same revision as ${prior.snapshot_id}; ${after.size} file(s) byte-identical`;
99
+ }
100
+ members.push(entry);
101
+ }
102
+ const removed = [];
103
+ const unaccounted = [];
104
+ for (const p of prior?.members ?? []) {
105
+ if (seen.has(p.canonical_repo_key))
106
+ continue;
107
+ const reasonCarried = inputs.carried?.get(p.canonical_repo_key);
108
+ const reasonRemoved = inputs.removed?.get(p.canonical_repo_key);
109
+ if (reasonCarried && reasonRemoved) {
110
+ throw new SnapshotError(`${p.canonical_repo_key} is declared both carried and removed`);
111
+ }
112
+ if (reasonCarried) {
113
+ members.push({
114
+ canonical_repo_key: p.canonical_repo_key,
115
+ exported_folder_name: p.exported_folder_name,
116
+ source_revision: p.source_revision,
117
+ carried_from: p.carried_from ?? prior.snapshot_id,
118
+ carried_reason: reasonCarried,
119
+ ...(p.role_hint ? { role_hint: p.role_hint } : {}),
120
+ });
121
+ }
122
+ else if (reasonRemoved) {
123
+ removed.push({
124
+ canonical_repo_key: p.canonical_repo_key,
125
+ last_revision: p.source_revision,
126
+ last_observed: p.carried_from ?? prior.snapshot_id,
127
+ reason: reasonRemoved,
128
+ });
129
+ }
130
+ else {
131
+ unaccounted.push(p.canonical_repo_key);
132
+ }
133
+ }
134
+ if (unaccounted.length > 0) {
135
+ throw new SnapshotError(`${unaccounted.length} member(s) of ${priorId} are absent from this export and not accounted for: ${unaccounted.join(", ")}.\n` +
136
+ " Declare each --carried <key>=<why it was not re-observed> or --removed <key>=<why it left>. " +
137
+ "An absence nobody can explain yet is an open question: carry it with that as its reason, and never let it be inferred.");
138
+ }
139
+ for (const [flag, map] of [["--carried", inputs.carried], ["--removed", inputs.removed]]) {
140
+ for (const k of map?.keys() ?? []) {
141
+ if (!priorByKey.has(k) || seen.has(k))
142
+ throw new SnapshotError(`${flag} ${k}: not a member of ${priorId ?? "the prior baseline"} that is absent from this export`);
143
+ }
144
+ }
145
+ const manifest = {
146
+ snapshot_id: id,
147
+ observed_at: id,
148
+ implementation,
149
+ prior_snapshot: priorId ?? null,
150
+ members,
151
+ ...(removed.length > 0 ? { members_removed: removed } : {}),
152
+ credential_scan: scan,
153
+ ...(inputs.notes ? { notes: inputs.notes } : {}),
154
+ };
155
+ const header = "# Implementation-set snapshot (baseline) -- reverse/artifact-conventions.md \"Implementation-Set Snapshots\".\n" +
156
+ "# Written by `sdd-cli snapshot land`.\n";
157
+ await writeFile(manifestPath(areaRoot, id), header + stringify(manifest, { lineWidth: 0 }));
158
+ return manifest;
159
+ }
160
+ //# sourceMappingURL=land.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"land.js","sourceRoot":"","sources":["../../../src/lib/snapshot/land.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ export interface ManifestMember {
2
+ canonical_repo_key: string;
3
+ exported_folder_name: string;
4
+ source_revision: string;
5
+ observed_at?: string;
6
+ carried_from?: string;
7
+ carried_reason?: string;
8
+ reverified_at?: string;
9
+ reverification?: string;
10
+ role_hint?: string;
11
+ }
12
+ export interface RemovedMember {
13
+ canonical_repo_key: string;
14
+ last_revision: string;
15
+ last_observed?: string;
16
+ reason: string;
17
+ }
18
+ export interface CredentialScan {
19
+ tool: string;
20
+ version: string;
21
+ date: string;
22
+ result: string;
23
+ }
24
+ export interface SnapshotManifest {
25
+ snapshot_id: string;
26
+ observed_at: string;
27
+ implementation: string;
28
+ prior_snapshot: string | null;
29
+ members: ManifestMember[];
30
+ members_removed?: RemovedMember[];
31
+ credential_scan?: CredentialScan;
32
+ notes?: string;
33
+ }
34
+ export declare class SnapshotError extends Error {
35
+ }
36
+ export declare function isIsoDate(s: unknown): s is string;
37
+ /** `name-branch@rev` → { stem: "name-branch", revision: "rev" }. */
38
+ export declare function splitFolder(folder: string): {
39
+ stem: string;
40
+ revision: string;
41
+ } | null;
42
+ /** Member folders (`*@*` directories) directly under a baseline directory. */
43
+ export declare function memberFolders(baselineDir: string): Promise<string[]>;
44
+ /** Dated baseline ids under an area, ascending. */
45
+ export declare function baselineIds(areaRoot: string): Promise<string[]>;
46
+ export declare function exists(p: string): Promise<boolean>;
47
+ export declare function manifestPath(areaRoot: string, id: string): string;
48
+ export declare function readManifest(areaRoot: string, id: string): Promise<SnapshotManifest>;
49
+ /** Where a member's bytes live: its own baseline, or the one it was carried from. */
50
+ export declare function memberBytesDir(areaRoot: string, manifest: SnapshotManifest, m: ManifestMember): string;
51
+ /** relative path → sha256 for every file under a directory. */
52
+ export declare function hashTree(root: string): Promise<Map<string, string>>;
53
+ export interface FileDelta {
54
+ added: string[];
55
+ removed: string[];
56
+ modified: string[];
57
+ }
58
+ export declare function diffTrees(before: Map<string, string>, after: Map<string, string>): FileDelta;
59
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/lib/snapshot/manifest.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,aAAa,EAAE,CAAC;IAClC,eAAe,CAAC,EAAE,cAAc,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAc,SAAQ,KAAK;CAAG;AAI3C,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAIjD;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAIrF;AAED,8EAA8E;AAC9E,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAM1E;AAED,mDAAmD;AACnD,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAMrE;AAED,wBAAsB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOxD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyC1F;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CAEtG;AAED,+DAA+D;AAC/D,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgBzE;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAW5F"}