@sdd-method/author-cli 0.17.2 → 0.17.3

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.
@@ -198,7 +198,7 @@ export function parseSurfaces(evidence) {
198
198
  claim = "generated";
199
199
  }
200
200
  });
201
- const base = { present: true, none: false, generated: false, noneServed: null, entries: [], problems: [] };
201
+ const base = { present: true, none: false, generated: false, noneServed: null, repoClaims: [], entries: [], problems: [] };
202
202
  if (at < 0)
203
203
  return { ...base, present: false };
204
204
  if (claim === "none")
@@ -208,18 +208,12 @@ export function parseSurfaces(evidence) {
208
208
  if (claim === "none served") {
209
209
  // `**Surfaces:** none served (scheduled)`: the service serves no contract; what drives it is named, from a
210
210
  // closed vocabulary, so the claim says why and cannot be left vague.
211
- const m = /none\s+served\s*\(([^)]*)\)\s*\.?\s*$/i.exec(lines[at]);
212
- const triggers = m ? m[1].split(",").map((t) => t.trim()).filter((t) => t !== "") : [];
213
211
  const problems = [];
214
- if (!m || triggers.length === 0)
215
- problems.push(`"none served" names what drives the service: "**Surfaces:** none served (${NONE_SERVED_TRIGGERS.join(" | ")})"`);
216
- for (const t of triggers) {
217
- if (!NONE_SERVED_TRIGGERS.includes(t))
218
- problems.push(`"none served (${t})": "${t}" is not one of ${NONE_SERVED_TRIGGERS.join(", ")}`);
219
- }
212
+ const triggers = noneServedTriggers(lines[at], "**Surfaces:** none served", problems);
220
213
  return { ...base, noneServed: triggers, problems };
221
214
  }
222
215
  const entries = [];
216
+ const repoClaims = [];
223
217
  const problems = [];
224
218
  for (const line of lines.slice(at + 1)) {
225
219
  if (line.trim() === "" && entries.length + problems.length === 0)
@@ -234,6 +228,12 @@ export function parseSurfaces(evidence) {
234
228
  }
235
229
  const contract = m[1].trim();
236
230
  const status = m[2].split(";")[0].trim();
231
+ if (/^none\s+served\b/i.test(status)) {
232
+ // `- <repo>: none served (<trigger>)`: that observed repository serves no contract (sdm-wz6a); the list's other
233
+ // items still account for the contracts the other observed repositories serve.
234
+ repoClaims.push({ repo: contract, triggers: noneServedTriggers(status, `- ${contract}: none served`, problems) });
235
+ continue;
236
+ }
237
237
  const excluded = /^excluded\s*,\s*(.+)$/i.exec(status);
238
238
  if (/^covered at transport$/i.test(status)) {
239
239
  if (contract.includes("*"))
@@ -251,9 +251,21 @@ export function parseSurfaces(evidence) {
251
251
  problems.push(`"${contract}: ${status}" is neither "covered at transport" nor "excluded, <reason>"`);
252
252
  }
253
253
  }
254
- if (entries.length + problems.length === 0)
254
+ if (entries.length + repoClaims.length + problems.length === 0)
255
255
  problems.push('the **Surfaces:** line lists no contract; a baseline that admits no behaviour writes "**Surfaces:** none"');
256
- return { present: true, none: false, generated: false, noneServed: null, entries, problems };
256
+ return { present: true, none: false, generated: false, noneServed: null, repoClaims, entries, problems };
257
+ }
258
+ /** The triggers of a `none served (<trigger>[, <trigger>])` claim, reporting a missing or unknown one. */
259
+ function noneServedTriggers(text, form, problems) {
260
+ const m = /none\s+served\s*\(([^)]*)\)\s*\.?\s*$/i.exec(text);
261
+ const triggers = m ? m[1].split(",").map((t) => t.trim()).filter((t) => t !== "") : [];
262
+ if (!m || triggers.length === 0)
263
+ problems.push(`"none served" names what drives the service: "${form} (${NONE_SERVED_TRIGGERS.join(" | ")})"`);
264
+ for (const t of triggers) {
265
+ if (!NONE_SERVED_TRIGGERS.includes(t))
266
+ problems.push(`"none served (${t})": "${t}" is not one of ${NONE_SERVED_TRIGGERS.join(", ")}`);
267
+ }
268
+ return triggers;
257
269
  }
258
270
  /**
259
271
  * A generator's baseline (agreement-record-schema.yaml, Baselines: generated behaviour) serves no contract; its
@@ -1010,8 +1010,25 @@ export async function checkBehaviourStore(repo, options = {}) {
1010
1010
  const repos = observedIn(evidence);
1011
1011
  if (repos.length === 0)
1012
1012
  out.push(`${dir}/baseline-evidence.md: Surfaces cannot be cross-checked: no **Observed in:** line names a repository`);
1013
+ // `- <repo>: none served (<trigger>)` items (sdm-wz6a): each names an observed repository the catalogue records
1014
+ // serving no contract; one serving a contract lists its contracts instead.
1015
+ const claimed = new Set();
1016
+ for (const c of parsed.repoClaims) {
1017
+ if (!repos.includes(c.repo)) {
1018
+ out.push(`${dir}/baseline-evidence.md: Surfaces: "- ${c.repo}: none served" names a repository **Observed in:** does not (${repos.join(", ") || "none"})`);
1019
+ continue;
1020
+ }
1021
+ const served = servedBy.get(c.repo)?.served ?? [];
1022
+ if (served.length > 0) {
1023
+ out.push(`${dir}/baseline-evidence.md: Surfaces: "- ${c.repo}: none served", but ${c.repo} serves ${served.length} contract(s) (catalogues/repo_contract.csv: ${served.slice(0, 3).map((x) => x.id).join(", ")}${served.length > 3 ? ", ..." : ""}); list each, covered at transport or excluded with a reason`);
1024
+ continue;
1025
+ }
1026
+ claimed.add(c.repo);
1027
+ }
1013
1028
  for (const r of repos) {
1014
1029
  const known = servedBy.get(r);
1030
+ if (claimed.has(r))
1031
+ continue;
1015
1032
  if ((known?.served ?? []).length === 0) {
1016
1033
  const consumed = known?.consumed ? ` (it consumes ${known.consumed}, which a baseline does not list)` : "";
1017
1034
  out.push(`${dir}/baseline-evidence.md: Surfaces cannot be cross-checked: the catalogue records no contract that ${r} serves${consumed}; declare the contracts it serves in its repo-config`);
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "0.18.2",
3
- "built_against_sdd_cli": "5.4.2"
2
+ "version": "0.18.3",
3
+ "built_against_sdd_cli": "5.4.3"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "5.4.2",
3
- "built_against_sdd_cli": "5.4.2"
2
+ "version": "5.4.3",
3
+ "built_against_sdd_cli": "5.4.3"
4
4
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sdd-method/author-cli",
3
- "version": "0.17.2",
4
- "sddCliVersion": "5.4.2",
3
+ "version": "0.17.3",
4
+ "sddCliVersion": "5.4.3",
5
5
  "description": "Re-author one SDD's content — scaffold, plan, contracts, conformance, api-surface, snapshots, briefings, catalogue check — plus every read-only verify verb. Ships only the code those verbs reach; it cannot sync the baseline or rebuild the catalogues. Maintenance is in @sdd-method/maintain-cli, administration in @sdd-method/sdd-cli.",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",