@domandigital/craft 0.23.0 → 0.23.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @domandigital/craft
2
2
 
3
+ ## 0.23.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 297ee1b: `trailing-contrast` no longer goes quiet on a sentence that follows one `not-just-but` blocks (DOM-1358, catalogue 2026.10.8). The check that keeps one sentence from being reported twice looked back a fixed 80 characters and could reach the sentence before; it now reads only the sentence the match sits in. Found by running the released `copy-check` over the 92EL lines: "Edge matters for game servers, not registration." went unreported when it came straight after the gerund pair.
8
+
3
9
  ## 0.23.0
4
10
 
5
11
  ### Minor Changes
package/CHARACTER.md CHANGED
@@ -1470,7 +1470,7 @@ Generated from the package. Run `pnpm --filter @domandigital/craft run docs`
1470
1470
  after changing an entry; a test fails until you do.
1471
1471
 
1472
1472
  <!-- craft:catalogue:start -->
1473
- Catalogue version `2026.10.7`, 76 tells.
1473
+ Catalogue version `2026.10.8`, 76 tells.
1474
1474
 
1475
1475
  | Id | Gen | Surface | Severity | Tell | Why it is a default |
1476
1476
  | --- | --- | --- | --- | --- | --- |
@@ -9,10 +9,10 @@ import {
9
9
  snapshotPage,
10
10
  snapshotUrl,
11
11
  snapshotUrls
12
- } from "./chunk-A7KUKNX6.js";
12
+ } from "./chunk-ZV3FPQPM.js";
13
13
  import "./chunk-JYNXGCYZ.js";
14
- import "./chunk-3LCBLDAO.js";
15
- import "./chunk-KIBDFRHT.js";
14
+ import "./chunk-GA3AJN67.js";
15
+ import "./chunk-EHMEMSM2.js";
16
16
  import "./chunk-QYBAVU3P.js";
17
17
  export {
18
18
  PROVENANCE_BUDGET_MS,
package/dist/audit.cjs CHANGED
@@ -359,7 +359,9 @@ var PARALLEL_PAIR = [
359
359
  /^[ \t]*(?:#{1,6}[ \t]+)?[A-Z][\w'’-]*(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}(?:,[ \t]+(?!(?:and|or)\b)[\w'’-]+(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}){2,3}\.[ \t]*$/m
360
360
  ];
361
361
  var alreadyBlocked = (block, match, index) => {
362
- const sentence = block.text.slice(Math.max(0, index - 80), index + match.length);
362
+ const before = block.text.slice(0, index);
363
+ const start = Math.max(before.search(/[^.!?\n]*$/), 0);
364
+ const sentence = block.text.slice(start, index + match.length);
363
365
  return NEGATION.some((pattern) => pattern.test(sentence));
364
366
  };
365
367
  var DATA_ABSENCE = /\b(?:yet|found|available|configured|selected|assigned|scheduled|recorded|on file|to show|to display|results|match|matches|matching|data|in this period)\b/i;
@@ -788,7 +790,9 @@ var COPY_TELLS = [
788
790
  f("content/report.md", "Edge matters for game servers, not registration."),
789
791
  f("content/report.md", "Age 18 is the league's own threshold, not a legal one."),
790
792
  f("content/report.md", "Cloud computing means renting computing over the internet instead of owning it."),
791
- f("content/home.md", "Real Square data, not a vanity metric.")
793
+ f("content/home.md", "Real Square data, not a vanity metric."),
794
+ // Reported even straight after a sentence the blocking rule reports.
795
+ f("content/report.md", "That means renting services, not running servers.\n\nEdge matters for game servers, not registration.")
792
796
  ],
793
797
  pass: [
794
798
  f("content/home.md", "Rewire, retile and replumb a bathroom in five days."),
@@ -4263,7 +4267,7 @@ var IMAGERY_TELLS = [
4263
4267
  ];
4264
4268
 
4265
4269
  // src/character/check.ts
4266
- var CATALOGUE_VERSION = "2026.10.7";
4270
+ var CATALOGUE_VERSION = "2026.10.8";
4267
4271
  var CATALOGUE = [
4268
4272
  ...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
4269
4273
  ...SPECIFICITY_COPY_TELLS,
package/dist/audit.js CHANGED
@@ -324,7 +324,9 @@ var PARALLEL_PAIR = [
324
324
  /^[ \t]*(?:#{1,6}[ \t]+)?[A-Z][\w'’-]*(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}(?:,[ \t]+(?!(?:and|or)\b)[\w'’-]+(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}){2,3}\.[ \t]*$/m
325
325
  ];
326
326
  var alreadyBlocked = (block, match, index) => {
327
- const sentence = block.text.slice(Math.max(0, index - 80), index + match.length);
327
+ const before = block.text.slice(0, index);
328
+ const start = Math.max(before.search(/[^.!?\n]*$/), 0);
329
+ const sentence = block.text.slice(start, index + match.length);
328
330
  return NEGATION.some((pattern) => pattern.test(sentence));
329
331
  };
330
332
  var DATA_ABSENCE = /\b(?:yet|found|available|configured|selected|assigned|scheduled|recorded|on file|to show|to display|results|match|matches|matching|data|in this period)\b/i;
@@ -753,7 +755,9 @@ var COPY_TELLS = [
753
755
  f("content/report.md", "Edge matters for game servers, not registration."),
754
756
  f("content/report.md", "Age 18 is the league's own threshold, not a legal one."),
755
757
  f("content/report.md", "Cloud computing means renting computing over the internet instead of owning it."),
756
- f("content/home.md", "Real Square data, not a vanity metric.")
758
+ f("content/home.md", "Real Square data, not a vanity metric."),
759
+ // Reported even straight after a sentence the blocking rule reports.
760
+ f("content/report.md", "That means renting services, not running servers.\n\nEdge matters for game servers, not registration.")
757
761
  ],
758
762
  pass: [
759
763
  f("content/home.md", "Rewire, retile and replumb a bathroom in five days."),
@@ -4228,7 +4232,7 @@ var IMAGERY_TELLS = [
4228
4232
  ];
4229
4233
 
4230
4234
  // src/character/check.ts
4231
- var CATALOGUE_VERSION = "2026.10.7";
4235
+ var CATALOGUE_VERSION = "2026.10.8";
4232
4236
  var CATALOGUE = [
4233
4237
  ...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
4234
4238
  ...SPECIFICITY_COPY_TELLS,
@@ -10,10 +10,10 @@ import {
10
10
  levenshtein,
11
11
  normaliseFamily,
12
12
  parseColour
13
- } from "./chunk-3LCBLDAO.js";
13
+ } from "./chunk-GA3AJN67.js";
14
14
  import {
15
15
  TRADE_NOUNS
16
- } from "./chunk-KIBDFRHT.js";
16
+ } from "./chunk-EHMEMSM2.js";
17
17
 
18
18
  // src/direction/types.ts
19
19
  var DIRECTION_VERSION = 2;
@@ -747,7 +747,9 @@ var PARALLEL_PAIR = [
747
747
  /^[ \t]*(?:#{1,6}[ \t]+)?[A-Z][\w'’-]*(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}(?:,[ \t]+(?!(?:and|or)\b)[\w'’-]+(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}){2,3}\.[ \t]*$/m
748
748
  ];
749
749
  var alreadyBlocked = (block, match, index) => {
750
- const sentence = block.text.slice(Math.max(0, index - 80), index + match.length);
750
+ const before = block.text.slice(0, index);
751
+ const start = Math.max(before.search(/[^.!?\n]*$/), 0);
752
+ const sentence = block.text.slice(start, index + match.length);
751
753
  return NEGATION.some((pattern) => pattern.test(sentence));
752
754
  };
753
755
  var DATA_ABSENCE = /\b(?:yet|found|available|configured|selected|assigned|scheduled|recorded|on file|to show|to display|results|match|matches|matching|data|in this period)\b/i;
@@ -1176,7 +1178,9 @@ var COPY_TELLS = [
1176
1178
  f("content/report.md", "Edge matters for game servers, not registration."),
1177
1179
  f("content/report.md", "Age 18 is the league's own threshold, not a legal one."),
1178
1180
  f("content/report.md", "Cloud computing means renting computing over the internet instead of owning it."),
1179
- f("content/home.md", "Real Square data, not a vanity metric.")
1181
+ f("content/home.md", "Real Square data, not a vanity metric."),
1182
+ // Reported even straight after a sentence the blocking rule reports.
1183
+ f("content/report.md", "That means renting services, not running servers.\n\nEdge matters for game servers, not registration.")
1180
1184
  ],
1181
1185
  pass: [
1182
1186
  f("content/home.md", "Rewire, retile and replumb a bathroom in five days."),
@@ -9,7 +9,7 @@ import {
9
9
  parseFile,
10
10
  sentencesOf,
11
11
  specificity
12
- } from "./chunk-KIBDFRHT.js";
12
+ } from "./chunk-EHMEMSM2.js";
13
13
  import {
14
14
  SNAPSHOT_VERSION
15
15
  } from "./chunk-QYBAVU3P.js";
@@ -3195,7 +3195,7 @@ var IMAGERY_TELLS = [
3195
3195
  ];
3196
3196
 
3197
3197
  // src/character/check.ts
3198
- var CATALOGUE_VERSION = "2026.10.7";
3198
+ var CATALOGUE_VERSION = "2026.10.8";
3199
3199
  var CATALOGUE = [
3200
3200
  ...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
3201
3201
  ...SPECIFICITY_COPY_TELLS,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-OQXTQQAU.js";
4
4
  import {
5
5
  parseFlags
6
- } from "./chunk-KGEJ2TGT.js";
6
+ } from "./chunk-V3GJSISR.js";
7
7
  import {
8
8
  toJson
9
9
  } from "./chunk-QIEDBL4J.js";
@@ -22,10 +22,10 @@ import {
22
22
  hueSwatch,
23
23
  nullPrompt,
24
24
  scanSource
25
- } from "./chunk-3LCBLDAO.js";
25
+ } from "./chunk-GA3AJN67.js";
26
26
  import {
27
27
  extractStrings
28
- } from "./chunk-KIBDFRHT.js";
28
+ } from "./chunk-EHMEMSM2.js";
29
29
 
30
30
  // src/null/cli.ts
31
31
  import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
@@ -120,7 +120,7 @@ async function build(flags, io) {
120
120
  const toShoot = ids.filter((id) => existsSync(join(pages, `${id}.html`)) && !existsSync(join(shots, `${id}.json`)));
121
121
  if (toShoot.length) {
122
122
  io.out(`craft null: snapshotting ${toShoot.length} page${toShoot.length === 1 ? "" : "s"}`);
123
- const { snapshotUrls } = await import("./audit-CRTC7JSF.js");
123
+ const { snapshotUrls } = await import("./audit-DESBVHQJ.js");
124
124
  const results = await snapshotUrls(toShoot.map((id) => pathToFileURL(join(pages, `${id}.html`)).href));
125
125
  results.forEach((r, i) => {
126
126
  const id = toShoot[i];
@@ -241,7 +241,7 @@ async function importPages(flags, io) {
241
241
  const toShoot = pages.filter((p) => !existsSync(join(shots, `${p.id}.json`)));
242
242
  if (toShoot.length) {
243
243
  io.out(`craft null: snapshotting ${toShoot.length} page${toShoot.length === 1 ? "" : "s"} from ${flags.builder}`);
244
- const { snapshotUrls } = await import("./audit-CRTC7JSF.js");
244
+ const { snapshotUrls } = await import("./audit-DESBVHQJ.js");
245
245
  const servers = /* @__PURE__ */ new Map();
246
246
  try {
247
247
  for (const p of toShoot) if (!servers.has(p.root)) servers.set(p.root, await serveDir(p.root));
@@ -4,13 +4,13 @@ import {
4
4
  formatDirectionMatches,
5
5
  summariseDirection,
6
6
  validateDirection
7
- } from "./chunk-4NON4PVK.js";
7
+ } from "./chunk-7DPB5G4G.js";
8
8
  import {
9
9
  loadNull
10
- } from "./chunk-3LHIKF5L.js";
10
+ } from "./chunk-GDDBCHQR.js";
11
11
  import {
12
12
  parseFlags
13
- } from "./chunk-KGEJ2TGT.js";
13
+ } from "./chunk-V3GJSISR.js";
14
14
  import {
15
15
  toJson
16
16
  } from "./chunk-QIEDBL4J.js";
@@ -30,7 +30,7 @@ import {
30
30
  rhythmOf,
31
31
  shapeName,
32
32
  temperatureName
33
- } from "./chunk-3LCBLDAO.js";
33
+ } from "./chunk-GA3AJN67.js";
34
34
 
35
35
  // src/estate/cli.ts
36
36
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -133,7 +133,7 @@ async function snapshotOf(target, cwd) {
133
133
  return snap;
134
134
  }
135
135
  if (!/^https?:\/\//.test(target)) throw new Error(`${target} is neither a URL, a snapshot file, nor a site in the register`);
136
- const { snapshotUrl } = await import("./audit-CRTC7JSF.js");
136
+ const { snapshotUrl } = await import("./audit-DESBVHQJ.js");
137
137
  return snapshotUrl(target);
138
138
  }
139
139
  var line = (distance, sibling, shared) => `${distance.toFixed(2)}${sibling ? " SIBLING" : ""}${shared.length ? ` shares ${shared.join(", ")}` : ""}`;
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  snapshotUrl,
3
3
  snapshotUrls
4
- } from "./chunk-A7KUKNX6.js";
4
+ } from "./chunk-ZV3FPQPM.js";
5
5
  import {
6
6
  describeTypicality,
7
7
  loadNull
8
- } from "./chunk-3LHIKF5L.js";
8
+ } from "./chunk-GDDBCHQR.js";
9
9
  import {
10
10
  SOURCE_FILE,
11
11
  finish,
@@ -14,7 +14,7 @@ import {
14
14
  parseFlags,
15
15
  prepareReport,
16
16
  readPaths
17
- } from "./chunk-KGEJ2TGT.js";
17
+ } from "./chunk-V3GJSISR.js";
18
18
  import {
19
19
  toJson
20
20
  } from "./chunk-QIEDBL4J.js";
@@ -28,7 +28,7 @@ import {
28
28
  rhythmOf,
29
29
  scanSource,
30
30
  typicality
31
- } from "./chunk-3LCBLDAO.js";
31
+ } from "./chunk-GA3AJN67.js";
32
32
 
33
33
  // src/audit/cli.ts
34
34
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -10,7 +10,7 @@ import {
10
10
  holdHouseBlocks,
11
11
  houseRule,
12
12
  scanSource
13
- } from "./chunk-3LCBLDAO.js";
13
+ } from "./chunk-GA3AJN67.js";
14
14
  import {
15
15
  compareCompetitor,
16
16
  compareFacts,
@@ -21,7 +21,7 @@ import {
21
21
  pageCopy,
22
22
  protectedFacts,
23
23
  visibleText
24
- } from "./chunk-KIBDFRHT.js";
24
+ } from "./chunk-EHMEMSM2.js";
25
25
 
26
26
  // src/character/config.ts
27
27
  var DEFAULT_IGNORE = [".claude", ".agents", ".cursor"];
@@ -622,7 +622,7 @@ async function pageSnapshot(target, cwd) {
622
622
  return readSnapshot(JSON.parse(readFileSync(local, "utf8")), target);
623
623
  }
624
624
  if (!/^https?:\/\//.test(target)) throw new Error(`${target} is neither a URL nor a snapshot file`);
625
- const { snapshotUrl } = await import("./audit-CRTC7JSF.js");
625
+ const { snapshotUrl } = await import("./audit-DESBVHQJ.js");
626
626
  return snapshotUrl(target);
627
627
  }
628
628
  async function briefFor(flags, cwd) {
@@ -633,7 +633,7 @@ async function briefFor(flags, cwd) {
633
633
  if (typeof brief === "string" && brief.trim()) return brief;
634
634
  } else if (flags.direction) throw new Error(`no such file: ${flags.direction}`);
635
635
  if (flags.null) {
636
- const { loadNull } = await import("./cli-HWGSNSDD.js");
636
+ const { loadNull } = await import("./cli-36YQA6BP.js");
637
637
  return loadNull(flags.null, cwd).brief;
638
638
  }
639
639
  return void 0;
@@ -659,37 +659,37 @@ async function compareWithCompetitor(flags, io) {
659
659
  function run(argv, io) {
660
660
  const [command, ...rest] = argv;
661
661
  if (command === "direction") {
662
- return import("./cli-E2CFVIGZ.js").then((m) => m.runDirection(rest, io));
662
+ return import("./cli-TP5ZMJOL.js").then((m) => m.runDirection(rest, io));
663
663
  }
664
664
  if (command === "report" || command === "retrofit") {
665
- return import("./cli-TPV2EIIN.js").then((m) => m.runReport(command, rest, io));
665
+ return import("./cli-7IBKMUMM.js").then((m) => m.runReport(command, rest, io));
666
666
  }
667
667
  if (command === "register") {
668
- return import("./cli-YRRBBU27.js").then((m) => m.runRegister(rest, io));
668
+ return import("./cli-YOSHHLIV.js").then((m) => m.runRegister(rest, io));
669
669
  }
670
670
  if (command === "estate") {
671
- return import("./cli-X3RZE4GM.js").then((m) => m.runEstate(rest, io));
671
+ return import("./cli-RXXGSKD6.js").then((m) => m.runEstate(rest, io));
672
672
  }
673
673
  if (command === "null") {
674
- return import("./cli-HWGSNSDD.js").then((m) => m.runNull(rest, io));
674
+ return import("./cli-36YQA6BP.js").then((m) => m.runNull(rest, io));
675
675
  }
676
676
  if (command === "calibrate") {
677
- return import("./cli-ROVZDHVR.js").then((m) => m.runCalibrate(rest, io));
677
+ return import("./cli-FCFRPPHZ.js").then((m) => m.runCalibrate(rest, io));
678
678
  }
679
679
  if (command === "tells" && rest[0] === "harvest") {
680
- return import("./cli-HWGSNSDD.js").then((m) => m.runHarvest(rest, io)).catch((error) => {
680
+ return import("./cli-36YQA6BP.js").then((m) => m.runHarvest(rest, io)).catch((error) => {
681
681
  io.err(`craft: ${error.message}`);
682
682
  return 2;
683
683
  });
684
684
  }
685
685
  if (command === "phone-first") {
686
- return import("./cli-RHU3MAZY.js").then((m) => m.runPhoneFirst(rest, io));
686
+ return import("./cli-SOH4QMMW.js").then((m) => m.runPhoneFirst(rest, io));
687
687
  }
688
688
  if (command === "viewports") {
689
- return import("./viewports-cli-EAUVLHFJ.js").then((m) => m.runViewports(rest, io));
689
+ return import("./viewports-cli-ET664I2Y.js").then((m) => m.runViewports(rest, io));
690
690
  }
691
691
  if (command === "snapshot" || command === "audit") {
692
- return import("./cli-IYRJZWMN.js").then((m) => m.runAudit(command, rest, io));
692
+ return import("./cli-3PFEOEQI.js").then((m) => m.runAudit(command, rest, io));
693
693
  }
694
694
  if (!command || command === "help" || command === "--help" || command === "-h") {
695
695
  io.out(HELP);
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  auditSnapshot,
6
6
  fingerprint
7
- } from "./chunk-3LCBLDAO.js";
7
+ } from "./chunk-GA3AJN67.js";
8
8
  import {
9
9
  SNAPSHOT_VERSION
10
10
  } from "./chunk-QYBAVU3P.js";
@@ -9,13 +9,13 @@ import {
9
9
  runHarvest,
10
10
  runNull,
11
11
  serveDir
12
- } from "./chunk-3LHIKF5L.js";
12
+ } from "./chunk-GDDBCHQR.js";
13
13
  import "./chunk-OQXTQQAU.js";
14
- import "./chunk-KGEJ2TGT.js";
14
+ import "./chunk-V3GJSISR.js";
15
15
  import "./chunk-QIEDBL4J.js";
16
16
  import "./chunk-WUACK2HX.js";
17
- import "./chunk-3LCBLDAO.js";
18
- import "./chunk-KIBDFRHT.js";
17
+ import "./chunk-GA3AJN67.js";
18
+ import "./chunk-EHMEMSM2.js";
19
19
  import "./chunk-QYBAVU3P.js";
20
20
  export {
21
21
  describeTypicality,
@@ -4,16 +4,16 @@ import {
4
4
  merge,
5
5
  resolvePages,
6
6
  runAudit
7
- } from "./chunk-OTQQTXXK.js";
8
- import "./chunk-A7KUKNX6.js";
7
+ } from "./chunk-M5QSMIT6.js";
8
+ import "./chunk-ZV3FPQPM.js";
9
9
  import "./chunk-JYNXGCYZ.js";
10
- import "./chunk-3LHIKF5L.js";
10
+ import "./chunk-GDDBCHQR.js";
11
11
  import "./chunk-OQXTQQAU.js";
12
- import "./chunk-KGEJ2TGT.js";
12
+ import "./chunk-V3GJSISR.js";
13
13
  import "./chunk-QIEDBL4J.js";
14
14
  import "./chunk-WUACK2HX.js";
15
- import "./chunk-3LCBLDAO.js";
16
- import "./chunk-KIBDFRHT.js";
15
+ import "./chunk-GA3AJN67.js";
16
+ import "./chunk-EHMEMSM2.js";
17
17
  import "./chunk-QYBAVU3P.js";
18
18
  export {
19
19
  describeComponents,
@@ -3,21 +3,21 @@ import {
3
3
  } from "./chunk-OKVHWXYV.js";
4
4
  import {
5
5
  merge
6
- } from "./chunk-OTQQTXXK.js";
7
- import "./chunk-A7KUKNX6.js";
6
+ } from "./chunk-M5QSMIT6.js";
7
+ import "./chunk-ZV3FPQPM.js";
8
8
  import "./chunk-JYNXGCYZ.js";
9
9
  import {
10
10
  SIBLING_AT,
11
11
  compareToEstate,
12
12
  loadEstate
13
- } from "./chunk-Y2LGYHJ5.js";
13
+ } from "./chunk-LRWKKJIW.js";
14
14
  import {
15
15
  PAGE_TYPES,
16
16
  validateDirection
17
- } from "./chunk-4NON4PVK.js";
17
+ } from "./chunk-7DPB5G4G.js";
18
18
  import {
19
19
  loadNull
20
- } from "./chunk-3LHIKF5L.js";
20
+ } from "./chunk-GDDBCHQR.js";
21
21
  import "./chunk-OQXTQQAU.js";
22
22
  import {
23
23
  COPY_FILE,
@@ -28,7 +28,7 @@ import {
28
28
  loadExceptions,
29
29
  parseFlags,
30
30
  readPaths
31
- } from "./chunk-KGEJ2TGT.js";
31
+ } from "./chunk-V3GJSISR.js";
32
32
  import {
33
33
  toJson
34
34
  } from "./chunk-QIEDBL4J.js";
@@ -42,8 +42,8 @@ import {
42
42
  fingerprint,
43
43
  scanSource,
44
44
  typicality
45
- } from "./chunk-3LCBLDAO.js";
46
- import "./chunk-KIBDFRHT.js";
45
+ } from "./chunk-GA3AJN67.js";
46
+ import "./chunk-EHMEMSM2.js";
47
47
  import "./chunk-QYBAVU3P.js";
48
48
 
49
49
  // src/report/cli.ts
@@ -126,7 +126,7 @@ async function runReport(command, args, io) {
126
126
  if (/\.json$/i.test(target2) && existsSync(local)) {
127
127
  snap = readSnapshot(JSON.parse(readFileSync(local, "utf8")), target2);
128
128
  } else {
129
- const { snapshotUrl } = await import("./audit-CRTC7JSF.js");
129
+ const { snapshotUrl } = await import("./audit-DESBVHQJ.js");
130
130
  snap = await snapshotUrl(target2);
131
131
  }
132
132
  const fp = fingerprint(snap);
@@ -4,11 +4,11 @@ import {
4
4
  import {
5
5
  expandNullTargets,
6
6
  loadNull
7
- } from "./chunk-3LHIKF5L.js";
7
+ } from "./chunk-GDDBCHQR.js";
8
8
  import "./chunk-OQXTQQAU.js";
9
9
  import {
10
10
  parseFlags
11
- } from "./chunk-KGEJ2TGT.js";
11
+ } from "./chunk-V3GJSISR.js";
12
12
  import {
13
13
  toJson
14
14
  } from "./chunk-QIEDBL4J.js";
@@ -21,8 +21,8 @@ import {
21
21
  fingerprint,
22
22
  scanSource,
23
23
  typicality
24
- } from "./chunk-3LCBLDAO.js";
25
- import "./chunk-KIBDFRHT.js";
24
+ } from "./chunk-GA3AJN67.js";
25
+ import "./chunk-EHMEMSM2.js";
26
26
  import {
27
27
  SNAPSHOT_VERSION
28
28
  } from "./chunk-QYBAVU3P.js";
@@ -188,7 +188,7 @@ async function runCalibrate(args, io) {
188
188
  if (toTake.length) {
189
189
  io.err(`craft calibrate: taking ${toTake.length} snapshot${toTake.length === 1 ? "" : "s"}`);
190
190
  try {
191
- const { snapshotUrls } = await import("./audit-CRTC7JSF.js");
191
+ const { snapshotUrls } = await import("./audit-DESBVHQJ.js");
192
192
  const results = await snapshotUrls(toTake.map((t) => t.url));
193
193
  results.forEach((r, i) => {
194
194
  const { entry, keep } = toTake[i];
@@ -4,15 +4,15 @@ import {
4
4
  formatPairs,
5
5
  loadEstate,
6
6
  runEstate
7
- } from "./chunk-Y2LGYHJ5.js";
8
- import "./chunk-4NON4PVK.js";
9
- import "./chunk-3LHIKF5L.js";
7
+ } from "./chunk-LRWKKJIW.js";
8
+ import "./chunk-7DPB5G4G.js";
9
+ import "./chunk-GDDBCHQR.js";
10
10
  import "./chunk-OQXTQQAU.js";
11
- import "./chunk-KGEJ2TGT.js";
11
+ import "./chunk-V3GJSISR.js";
12
12
  import "./chunk-QIEDBL4J.js";
13
13
  import "./chunk-WUACK2HX.js";
14
- import "./chunk-3LCBLDAO.js";
15
- import "./chunk-KIBDFRHT.js";
14
+ import "./chunk-GA3AJN67.js";
15
+ import "./chunk-EHMEMSM2.js";
16
16
  import "./chunk-QYBAVU3P.js";
17
17
  export {
18
18
  formatComponentPairs,
@@ -16,12 +16,12 @@ import {
16
16
  import {
17
17
  SOURCE_FILE,
18
18
  readPaths
19
- } from "./chunk-KGEJ2TGT.js";
19
+ } from "./chunk-V3GJSISR.js";
20
20
  import {
21
21
  toJson
22
22
  } from "./chunk-QIEDBL4J.js";
23
- import "./chunk-3LCBLDAO.js";
24
- import "./chunk-KIBDFRHT.js";
23
+ import "./chunk-GA3AJN67.js";
24
+ import "./chunk-EHMEMSM2.js";
25
25
  import "./chunk-QYBAVU3P.js";
26
26
 
27
27
  // src/phone/cli.ts
@@ -19,10 +19,10 @@ import {
19
19
  checkReason,
20
20
  researchPrompt,
21
21
  validateDirection
22
- } from "./chunk-4NON4PVK.js";
22
+ } from "./chunk-7DPB5G4G.js";
23
23
  import {
24
24
  parseFlags
25
- } from "./chunk-KGEJ2TGT.js";
25
+ } from "./chunk-V3GJSISR.js";
26
26
  import {
27
27
  toJson
28
28
  } from "./chunk-QIEDBL4J.js";
@@ -38,8 +38,8 @@ import {
38
38
  isCream,
39
39
  oklchToRgb,
40
40
  parseColour
41
- } from "./chunk-3LCBLDAO.js";
42
- import "./chunk-KIBDFRHT.js";
41
+ } from "./chunk-GA3AJN67.js";
42
+ import "./chunk-EHMEMSM2.js";
43
43
  import "./chunk-QYBAVU3P.js";
44
44
 
45
45
  // src/direction/cli.ts
@@ -484,7 +484,7 @@ var readJson = (path) => JSON.parse(readFileSync(path, "utf8"));
484
484
  async function snapshotFrom(target, cwd) {
485
485
  if (!target) return void 0;
486
486
  if (/^https?:\/\//.test(target)) {
487
- const { snapshotUrl } = await import("./audit-CRTC7JSF.js");
487
+ const { snapshotUrl } = await import("./audit-DESBVHQJ.js");
488
488
  return snapshotUrl(target);
489
489
  }
490
490
  return readSnapshot(readJson(resolve(cwd, target)), target);
@@ -9,7 +9,7 @@ import {
9
9
  STOCK_PHRASES,
10
10
  countWords,
11
11
  specificity
12
- } from "./chunk-KIBDFRHT.js";
12
+ } from "./chunk-EHMEMSM2.js";
13
13
 
14
14
  // src/register/cli.ts
15
15
  import { existsSync, readFileSync } from "fs";
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  run
4
- } from "./chunk-KGEJ2TGT.js";
4
+ } from "./chunk-V3GJSISR.js";
5
5
  import "./chunk-QIEDBL4J.js";
6
- import "./chunk-3LCBLDAO.js";
7
- import "./chunk-KIBDFRHT.js";
6
+ import "./chunk-GA3AJN67.js";
7
+ import "./chunk-EHMEMSM2.js";
8
8
  import "./chunk-QYBAVU3P.js";
9
9
 
10
10
  // src/cli.ts
package/dist/index.cjs CHANGED
@@ -2161,7 +2161,9 @@ var PARALLEL_PAIR = [
2161
2161
  /^[ \t]*(?:#{1,6}[ \t]+)?[A-Z][\w'’-]*(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}(?:,[ \t]+(?!(?:and|or)\b)[\w'’-]+(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}){2,3}\.[ \t]*$/m
2162
2162
  ];
2163
2163
  var alreadyBlocked = (block, match, index) => {
2164
- const sentence = block.text.slice(Math.max(0, index - 80), index + match.length);
2164
+ const before = block.text.slice(0, index);
2165
+ const start = Math.max(before.search(/[^.!?\n]*$/), 0);
2166
+ const sentence = block.text.slice(start, index + match.length);
2165
2167
  return NEGATION.some((pattern2) => pattern2.test(sentence));
2166
2168
  };
2167
2169
  var DATA_ABSENCE = /\b(?:yet|found|available|configured|selected|assigned|scheduled|recorded|on file|to show|to display|results|match|matches|matching|data|in this period)\b/i;
@@ -2590,7 +2592,9 @@ var COPY_TELLS = [
2590
2592
  f("content/report.md", "Edge matters for game servers, not registration."),
2591
2593
  f("content/report.md", "Age 18 is the league's own threshold, not a legal one."),
2592
2594
  f("content/report.md", "Cloud computing means renting computing over the internet instead of owning it."),
2593
- f("content/home.md", "Real Square data, not a vanity metric.")
2595
+ f("content/home.md", "Real Square data, not a vanity metric."),
2596
+ // Reported even straight after a sentence the blocking rule reports.
2597
+ f("content/report.md", "That means renting services, not running servers.\n\nEdge matters for game servers, not registration.")
2594
2598
  ],
2595
2599
  pass: [
2596
2600
  f("content/home.md", "Rewire, retile and replumb a bathroom in five days."),
@@ -6866,7 +6870,7 @@ var IMAGERY_TELLS = [
6866
6870
  ];
6867
6871
 
6868
6872
  // src/character/check.ts
6869
- var CATALOGUE_VERSION = "2026.10.7";
6873
+ var CATALOGUE_VERSION = "2026.10.8";
6870
6874
  var CATALOGUE = [
6871
6875
  ...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
6872
6876
  ...SPECIFICITY_COPY_TELLS,
package/dist/index.d.cts CHANGED
@@ -1252,7 +1252,7 @@ interface CheckReport {
1252
1252
  * Bumped whenever an entry is added, removed or its detection changes, so a
1253
1253
  * report can say which list it was judged against.
1254
1254
  */
1255
- declare const CATALOGUE_VERSION = "2026.10.7";
1255
+ declare const CATALOGUE_VERSION = "2026.10.8";
1256
1256
  declare const CATALOGUE: readonly Tell[];
1257
1257
  declare function tellById(id: string): Tell | undefined;
1258
1258
  /**
package/dist/index.d.ts CHANGED
@@ -1252,7 +1252,7 @@ interface CheckReport {
1252
1252
  * Bumped whenever an entry is added, removed or its detection changes, so a
1253
1253
  * report can say which list it was judged against.
1254
1254
  */
1255
- declare const CATALOGUE_VERSION = "2026.10.7";
1255
+ declare const CATALOGUE_VERSION = "2026.10.8";
1256
1256
  declare const CATALOGUE: readonly Tell[];
1257
1257
  declare function tellById(id: string): Tell | undefined;
1258
1258
  /**
package/dist/index.js CHANGED
@@ -1842,7 +1842,9 @@ var PARALLEL_PAIR = [
1842
1842
  /^[ \t]*(?:#{1,6}[ \t]+)?[A-Z][\w'’-]*(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}(?:,[ \t]+(?!(?:and|or)\b)[\w'’-]+(?:[ \t]+(?!(?:and|or)\b)[\w'’-]+){0,2}){2,3}\.[ \t]*$/m
1843
1843
  ];
1844
1844
  var alreadyBlocked = (block, match, index) => {
1845
- const sentence = block.text.slice(Math.max(0, index - 80), index + match.length);
1845
+ const before = block.text.slice(0, index);
1846
+ const start = Math.max(before.search(/[^.!?\n]*$/), 0);
1847
+ const sentence = block.text.slice(start, index + match.length);
1846
1848
  return NEGATION.some((pattern2) => pattern2.test(sentence));
1847
1849
  };
1848
1850
  var DATA_ABSENCE = /\b(?:yet|found|available|configured|selected|assigned|scheduled|recorded|on file|to show|to display|results|match|matches|matching|data|in this period)\b/i;
@@ -2271,7 +2273,9 @@ var COPY_TELLS = [
2271
2273
  f("content/report.md", "Edge matters for game servers, not registration."),
2272
2274
  f("content/report.md", "Age 18 is the league's own threshold, not a legal one."),
2273
2275
  f("content/report.md", "Cloud computing means renting computing over the internet instead of owning it."),
2274
- f("content/home.md", "Real Square data, not a vanity metric.")
2276
+ f("content/home.md", "Real Square data, not a vanity metric."),
2277
+ // Reported even straight after a sentence the blocking rule reports.
2278
+ f("content/report.md", "That means renting services, not running servers.\n\nEdge matters for game servers, not registration.")
2275
2279
  ],
2276
2280
  pass: [
2277
2281
  f("content/home.md", "Rewire, retile and replumb a bathroom in five days."),
@@ -6547,7 +6551,7 @@ var IMAGERY_TELLS = [
6547
6551
  ];
6548
6552
 
6549
6553
  // src/character/check.ts
6550
- var CATALOGUE_VERSION = "2026.10.7";
6554
+ var CATALOGUE_VERSION = "2026.10.8";
6551
6555
  var CATALOGUE = [
6552
6556
  ...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
6553
6557
  ...SPECIFICITY_COPY_TELLS,
@@ -16,13 +16,13 @@ import {
16
16
  } from "./chunk-XSKLVEI6.js";
17
17
  import {
18
18
  loadPlaywright
19
- } from "./chunk-A7KUKNX6.js";
19
+ } from "./chunk-ZV3FPQPM.js";
20
20
  import "./chunk-JYNXGCYZ.js";
21
21
  import {
22
22
  toJson
23
23
  } from "./chunk-QIEDBL4J.js";
24
- import "./chunk-3LCBLDAO.js";
25
- import "./chunk-KIBDFRHT.js";
24
+ import "./chunk-GA3AJN67.js";
25
+ import "./chunk-EHMEMSM2.js";
26
26
  import "./chunk-QYBAVU3P.js";
27
27
 
28
28
  // src/phone/viewports-cli.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domandigital/craft",
3
- "version": "0.23.0",
3
+ "version": "0.23.1",
4
4
  "private": false,
5
5
  "description": "The Doman Digital house craft standard as numbers: OKLCh colour ramps that snap to existing anchors, derived semantic tokens with measured WCAG and APCA contrast, one shared motion vocabulary for CSS and JS, and a base stylesheet. Zero dependencies.",
6
6
  "license": "Apache-2.0",
package/word-lists.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "catalogueVersion": "2026.10.7",
2
+ "catalogueVersion": "2026.10.8",
3
3
  "lists": {
4
4
  "aiWords": [
5
5
  "tapestry",