@domandigital/craft 0.6.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @domandigital/craft
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2b6f823: The house copy standard moves into craft. `COPY.md` ships in the package, `craft copy --gate` applies the house policy (the blocking tier fails the run), and `craft tells list --json` publishes each copy tell's house tier so `copy-check` reads the policy instead of keeping its own list. Catalogue 2026.09.4 adds the density tier (`phrase-density`, `aphorism-density`, `contraction-scarcity`, `sentence-rhythm`, `repeated-sentence`, `heading-shape`, `heading-echo`) and four review tells from research (`ing-tail`, `vague-attribution`, `closing-summary`, `false-range`), all warn. The emoji tell now catches sparkles, the green tick box and other emoji in the older symbol blocks.
8
+
9
+ Words inside a URL or a Markdown link target are no longer read as copy, so a slug such as `/seamless-booking` no longer blocks.
10
+
11
+ - 7765dda: Catalogue 2026.09.6, tuned against the Doman Digital site's live Sanity content. `chatbot-residue` reads a run of ChatGPT citation tokens as one finding, through the invisible private-use characters ChatGPT wraps them in. `placeholder` skips a placeholder inside quotation marks, which is a template being taught. `vague-attribution` skips a claim that names its source or carries a footnote or link. `inline-label-list` fires only when the text after the label is six words or fewer, so a definition list passes.
12
+ - ef5b85b: Catalogue 2026.09.5. Four more review tells: `chatbot-residue` (pasted chat replies, chat citation tokens, links tracked `utm_source=chatgpt.com`), `placeholder` (`[Insert ...]`, lorem ipsum, `TODO_PLACEHOLDER`, including a placeholder that is a whole element), `question-reveal` and `inline-label-list`. New command `craft copy compare <before> <after>`: the preservation gate, listing the protected facts (prices, numbers, dates, times, phones, emails, links, postcodes, names) a rewrite lost or added, exit 1 if any. Exported as `compareFacts` and `protectedFacts`.
13
+
14
+ ## 0.7.0
15
+
16
+ ### Minor Changes
17
+
18
+ - dbdef56: Signal 2, the counterfactual. `craft null build --brief "..." --out <dir>` asks `claude -p` for about 20 home pages from the brief alone, renders and fingerprints each, and writes `null.json`. `craft audit <url> --null <dir>` scores how typical a page is against them: the share of the model's own pages that sit further out than this one, typical at 0.10 or above, with the choices it shares with most of them. `craft tells harvest <dir>` lists what recurs across null pages and which tell already catches it, so the next generation of tells comes from what the model builds now. `snapshotUrls` in `@domandigital/craft/audit` snapshots several pages through one browser. The rendered reveal check now also reads the text blocks inside a section, so reveals on cards two levels down are no longer read as a still page.
19
+ - f765c69: Signal 3, the estate. `craft estate add <url | snapshot.json> --id <id>` fingerprints a shipped site into `estate.json`; `craft estate compare` lists every pair, or one site against the rest, closest first, and marks siblings: two sites closer together than two pages Claude builds for one brief (0.31, or measured again from `--null`). What a pair shares is named in plain words ("Fraunces headline", "no accent"). `--strict` exits 1 on a sibling. `craft direction propose --estate estate.json` reads the register. The fingerprint no longer takes a small painted patch, such as a floating chat button, for the accent: a painted colour needs a panel's worth of area.
20
+ - f3c3dc0: The character report. `craft report <url | snapshot.json>` reads a site against all three signals and the reason rule (`--repo`, `--null`, `--estate`, `--direction`) and gives a verdict: default, mixed, decided, or unproven when something was not measured. The actions come in retrofit order, one per choice, with every reason that points at it. `craft retrofit` writes them as a Markdown checklist that names the art-direction choice settling each change, shows the decided value, and ends with what to leave alone. `characterReport` and `retrofitPlan` are exported. System font keywords such as `ui-monospace` no longer read as CSS variable names.
21
+
22
+ ### Patch Changes
23
+
24
+ - 235b558: Export the copy catalogue's word and phrase lists as portable JSON
25
+ (`wordListsJson()`, checked in at `word-lists.json`), so a non-TypeScript
26
+ consumer can source from them instead of duplicating them by hand.
27
+
28
+ `claude-kit`'s `copy_check.py` hardcoded its own copies of these same lists
29
+ and had drifted from this package (documented in claude-kit's
30
+ `house-style/copy-rules.md`, "Note the enforcement gap"). `word-lists.json` is
31
+ the file that ends the drift: `install/sync-copy-wordlists.sh` on that side
32
+ copies it in verbatim, the same shape `sync-craft-standard.sh` already uses
33
+ for `STANDARD.md`.
34
+
35
+ No tell's detection or severity changed. Regenerate the checked-in file with
36
+ `pnpm --filter @domandigital/craft run docs` after editing any list in
37
+ `tells/copy.ts`.
38
+
3
39
  ## 0.6.0
4
40
 
5
41
  ### Minor Changes
package/CHARACTER.md CHANGED
@@ -29,8 +29,8 @@ model defaults move.
29
29
  | Signal | Question | Status |
30
30
  | --- | --- | --- |
31
31
  | 1. Known tells | Does it use a choice on the catalogue below? | **Shipped**: source, copy, and on the rendered page for 18 tells (`craft audit`). |
32
- | 2. Counterfactual typicality | Would Claude have built this anyway, for this brief? | Planned. About 20 `claude -p` runs per brief; distance from those answers. |
33
- | 3. Distance from the estate | Does it look like the agency's other sites? | Fingerprint and distance shipped; the estate register is planned. The agency's biggest tell is its clients looking like siblings. |
32
+ | 2. Counterfactual typicality | Would Claude have built this anyway, for this brief? | **Shipped**: `craft null build` generates about 20 pages from the brief; `craft audit --null` scores a page against them. |
33
+ | 3. Distance from the estate | Does it look like the agency's other sites? | **Shipped**: `craft estate add` fingerprints each shipped site into `estate.json`; `craft estate compare` marks siblings. The agency's biggest tell is its clients looking like each other. |
34
34
 
35
35
  **The reason rule.** Every expressive choice records a `because`, with evidence
36
36
  from the client's real world: the shopfront, the van, the trade's own look, the
@@ -43,7 +43,7 @@ adds character rather than only removing tells. It lives in `art-direction.json`
43
43
  | --- | --- |
44
44
  | 1 | The first wave: indigo, blue-to-purple gradients, Inter, glass, three icon cards. |
45
45
  | 2 | What models moved to once the first wave was named: cream grounds and italic serifs, eyebrow chips, bento grids, marquees, intro cinematics. |
46
- | 3 | Whatever the harvester finds next. |
46
+ | 3 | Whatever `craft tells harvest` finds next in the null models, once a person has read it. |
47
47
 
48
48
  A report counts findings by generation, so it can say *which* wave a site was
49
49
  built in, not only that it has tells.
@@ -185,16 +185,110 @@ against different sets.
185
185
  Known limit: a computed font family is the family the stylesheet asked for.
186
186
  A face that failed to load is still reported under its name.
187
187
 
188
+ ## The counterfactual
189
+
190
+ A list of tells goes stale; the model does not. So signal 2 asks the model
191
+ directly: given this brief and nothing else, what would you build?
192
+
193
+ ```bash
194
+ craft null build --brief "RMP Electrical, electricians based in Uxbridge ..." --out null/rmp
195
+ craft audit https://www.rmp-electrical.co.uk --null null/rmp
196
+ ```
197
+
198
+ `null build` runs `claude -p` about 20 times (`--runs`), from an empty folder
199
+ with no tools, settings, skills or MCP servers, so each page is what the model
200
+ builds from the brief alone. The prompt is recorded in `null.json` and says
201
+ nothing about how the page should look. Each page is rendered, snapshotted and
202
+ fingerprinted like any other. A reply that is a note instead of a page is kept
203
+ as `NN.reply.txt` and generated again. The build is resumable: run the same
204
+ command to fill in anything that failed. `--brief` can come from
205
+ `art-direction.json` with `--direction`.
206
+
207
+ **Typicality** is a page's mean fingerprint distance to its three nearest null
208
+ pages, ranked against the same measure for every null page against the
209
+ others. A score of 0.40 means 40% of the model's own pages sit further from
210
+ the rest than this one does. A page is typical at 0.10 or above, so a page the
211
+ model built is flagged nine times in ten by construction, and the threshold
212
+ comes from the model's own spread rather than a number picked here. The report
213
+ lists what the page shares with most of the null ("display Inter, 14 of 20"),
214
+ which is where to start changing it.
215
+
216
+ **The harvest** reads null models the other way round. `craft tells harvest
217
+ calibration/null` lists the choices that recur across the null pages (faces,
218
+ accent families, grounds, button shapes, openings, phrases) and says which
219
+ tell already catches each. The ones nothing catches are the candidates for
220
+ generation 3. A phrase has to turn up across more than one brief, so a trade's
221
+ own words do not count, and navigation labels, form labels and the legal footer
222
+ are left out as page grammar. Nothing is added to the catalogue automatically:
223
+ a candidate becomes a tell with a flag case and a pass case like every other.
224
+
225
+ Known limits: a user-level `CLAUDE.md` on the machine that builds the null
226
+ still reaches the model. The null is only as current as its build date; rebuild
227
+ it when the model changes.
228
+
229
+ ## The estate
230
+
231
+ The agency's biggest tell is not on any one site. It is its clients looking
232
+ like each other. `estate.json` holds one fingerprint per shipped site:
233
+
234
+ ```bash
235
+ craft estate add https://www.rmp-electrical.co.uk --id rmp --client "RMP Electrical"
236
+ craft estate compare # every pair, closest first
237
+ craft estate compare rmp # one site against the rest
238
+ craft estate compare https://staging.example.test # a new build before it ships
239
+ ```
240
+
241
+ **Siblings** are two sites closer together than two pages Claude builds for
242
+ the same brief usually are: the median of that distance over the null models,
243
+ 0.31 on 2026-09-23 (`--null` measures it again from any null models given).
244
+ If a barber and an electrician look more alike than two drafts of one barber,
245
+ neither look was chosen. The report says what the pair shares in plain words
246
+ ("Fraunces headline", "no accent", "pill buttons"), which is where to start
247
+ pulling them apart. A sibling is a warning; `--strict` exits 1 on one, for a
248
+ pipeline that has decided to hold the line.
249
+
250
+ `craft direction propose --estate estate.json` reads the register too, so a
251
+ proposed accent steers away from one a sibling already uses.
252
+
253
+ ## The character report
254
+
255
+ `craft report` reads one site against everything above and gives a verdict:
256
+
257
+ ```bash
258
+ craft report https://www.rmp-electrical.co.uk --repo . --null null/rmp --estate ../estate.json
259
+ craft retrofit https://www.rmp-electrical.co.uk --repo . --null null/rmp --estate ../estate.json --out RETROFIT.md
260
+ ```
261
+
262
+ | Verdict | When |
263
+ |---|---|
264
+ | default | Two or more signals raised: three or more design tells, typical of the brief's null, a sibling in the estate, or fewer than five choices decided with a reason. |
265
+ | mixed | One raised. |
266
+ | decided | None raised, and all four measured. |
267
+ | unproven | None raised, but something was not measured. Unverified is never a pass. |
268
+
269
+ The actions come in the order a retrofit works: decide first, then type,
270
+ colour, shape, effects, motion, how sections look, and copy. Where a tell, the
271
+ null model and a sibling all point at one choice, they are one action with
272
+ three reasons. Sharing a white page or a still one with the null is never
273
+ an action: that would reward strangeness.
274
+
275
+ `craft retrofit` writes the same as a checklist. Each change names the
276
+ art-direction choice that settles it, and shows the decided value and its
277
+ reason, or says it waits on that decision. It ends with what to leave alone:
278
+ navigation, the order of sections, where the call to action sits.
279
+
188
280
  ## The house copy rules live here
189
281
 
190
- Since catalogue `2026.09.2` the rule lists of claude-kit's
191
- `house-style/copy-rules.md` are carried by tells in this catalogue:
192
- `ai-phrase`, `plainer-word`, `plain-english`, `buzzword`,
193
- `negative-reassurance`, `em-dash`, `emoji`, `not-just-but`, `no-x-no-y` and
194
- `no-x-badge` are its blocking tier; `review-phrase` and `vague-word` its review
195
- tier. craft ships all of them as `warn`. `copy-check` in claude-kit is a thin
196
- wrapper over `craft copy --json` and decides which tells fail a commit, so the
197
- lists exist once, here, with a test per entry.
282
+ The house copy standard is [COPY.md](./COPY.md), in this package. Its
283
+ blocking tier is carried by ten tells here: `ai-phrase`, `plainer-word`,
284
+ `plain-english`, `buzzword`, `negative-reassurance`, `em-dash`, `emoji`,
285
+ `not-just-but`, `no-x-no-y` and `no-x-badge`. craft ships every tell as
286
+ `warn`; the house policy in `src/character/house.ts` says which fail a commit,
287
+ and `craft copy --gate` applies it. `copy-check` in claude-kit is a thin
288
+ wrapper that reads the same policy from `craft tells list --json`, so the
289
+ lists and the policy exist once, here, with a test per entry. Since catalogue
290
+ `2026.09.4` the density tier and four research tells are here too, and since
291
+ `2026.09.5` four more, including `chatbot-residue` and `placeholder`. All review.
198
292
 
199
293
  The swap was checked against the old checker on 2,570 files across the seven
200
294
  client repos (2026-09-23). The old checker found 193 issues, craft finds every
@@ -212,9 +306,10 @@ reason that rule exists.
212
306
  The targets, recorded here with the date once each has been run:
213
307
 
214
308
  - **AI set** (pages generated by `claude -p` from about 20 briefs): 90% or more
215
- flagged as typical or tell-heavy. *Not yet run.*
309
+ flagged as typical or tell-heavy. **First run 2026-09-23: 19 of 20 (95%)**, below.
216
310
  - **Human set** (the ten references in claude-kit's `reference-set.md`): zero
217
- block hits and low typicality. *Not yet run.*
311
+ block hits and low typicality. **First run 2026-09-23: zero block hits, none
312
+ typical**, below.
218
313
  - **Estate baseline** (all seven client repos and live URLs): every hit read by
219
314
  a person before any rule blocks. **First run 2026-09-23**, below.
220
315
 
@@ -240,7 +335,7 @@ blocks; it is for a person to read.
240
335
  | `glass-panel` | 9 / · | 45 / · | 13 / · | | 1 / · | | |
241
336
  | `hero-then-proof` | 9 / · | 1 / R | · / R | | 1 / · | 1 / · | 2 / R |
242
337
  | `icon-tile-grid` | 1 / R | 9 / · | · / R | | · / R | | 1 / R |
243
- | `reveal-everywhere` | 1 / · | 1 / · | | | | | |
338
+ | `reveal-everywhere` | 1 / · | 1 / · | | | | · / R | |
244
339
  | `pill-everything` | 1 / R | 1 / · | 1 / · | | | | 1 / R |
245
340
  | `shadcn-dump` | | 1 / · | | | | | |
246
341
  | `cream-palette` | | 3 / · | | | | | 18 / R |
@@ -258,15 +353,17 @@ What it shows:
258
353
  - **The three survey findings reproduce where they can.** Sensphere's violet
259
354
  is found in source (18) and on its buttons; MMM's intro, glows and glass are
260
355
  in source and its intro and glows on the page; MMM reveals 60% of the
261
- sections below its fold on scroll, three of five, one short of the rendered
262
- threshold, and its source is over the reveal limit. Rise & Bloom's glass
356
+ sections below its fold on scroll, all three of them, one short of the
357
+ four the rendered rule needs, and its source is over the reveal limit. Rise & Bloom's glass
263
358
  hero and icon grid could not be checked: that repo is not attached to this
264
359
  session.
265
360
  - **Every site ships a reflex face.** Twelve of fourteen site-face pairs are
266
361
  on one of the two lists. Fraunces sets the headline on DD, HJ Beauty and RMP.
267
- - **DD and RMP are the closest pair** (fingerprint distance 0.46: Fraunces
268
- headlines, pill buttons, a green accent). Chair and Blade is furthest from
269
- everything (0.59 to 0.77). This is signal 3's first measurement.
362
+ - **DD and RMP were read as the closest pair** (0.46) on the first run, with
363
+ a green accent in common. DD's "green" was its floating WhatsApp button,
364
+ 48px square, the only saturated paint on a near-black and white page. The
365
+ fingerprint now needs a panel's worth of area before a painted colour
366
+ counts as the accent. The corrected pairs are under *The estate*, below.
270
367
  - **DD's violet is its brand.** Its 36 source hits wait for the exception in
271
368
  its `art-direction.json`.
272
369
 
@@ -280,16 +377,164 @@ False positives found and fixed in this run:
280
377
  `cormorantGaramond`) are now read back to the face's name, or every Next.js
281
378
  site would have passed the font tells.
282
379
 
380
+ - The rendered reveal check read only a section and its direct children.
381
+ Found through the null models (below): a reveal on the cards two levels
382
+ down read as a still page. It now reads the text blocks inside a section
383
+ too, ignoring anything fixed. Re-run the same day: Chair and Blade, which
384
+ has a `RevealWrapper`, now shows `reveal-everywhere` on the page (six of
385
+ nine sections below the fold).
386
+
283
387
  Not yet read by a person: the source counts for `icon-tile-stack` (MMM 93)
284
388
  and `glass-panel` (MMM 45) look high and are the first to check.
285
389
 
390
+ ### Signal 2 first read, 2026-09-23
391
+
392
+ Seven null models, one per estate brief, 20 pages each (140 pages), built
393
+ with `craft null build` from the briefs in `calibration/briefs.json`. Eight
394
+ replies were notes instead of pages and were generated again (kept as
395
+ `*.reply.txt`). Everything is in `calibration/null/`; `score.mjs` reproduces
396
+ the numbers and writes `results.json`.
397
+
398
+ **AI set.** Twenty briefs the null never saw (a dentist, a bakery, a
399
+ landscaper and so on), one page each, scored against all 140 null pages.
400
+ Flagged means typical (0.10 or above) or tell-heavy (three or more distinct
401
+ design tells), a rule fixed before any result was read.
402
+
403
+ | | Pages | Share |
404
+ |---|---|---|
405
+ | Flagged | 19 of 20 | 95% (target 90%) |
406
+ | Typical on its own | 13 of 20 | 65% |
407
+ | Tell-heavy on its own | 16 of 20 | 80% |
408
+
409
+ The one miss is the landscaper: dark forest green on a cream ground,
410
+ Cormorant Garamond over Karla, square buttons. Two tells (`cream-palette`,
411
+ `reflex-font-2`), one short of tell-heavy, and a score of 0.01 against the
412
+ pooled null because no estate brief is a garden business. Neither signal alone reaches the
413
+ target; together they do, which is the reason for having more than one.
414
+
415
+ **The model's look depends on the brief.** Each brief's null pages scored
416
+ against the other six briefs' pages are typical only 2 to 13 times in 20.
417
+ A barber and an electrician get different pages. So a site is scored against
418
+ the null built from its own brief, and pooling briefs is a weaker test.
419
+
420
+ **The estate against its own brief's null.** Score, then what it shares with
421
+ most of the null.
422
+
423
+ | Site | Score | Typical | Shares with the null |
424
+ |---|---|---|---|
425
+ | DD | 0.15 | yes | pill buttons (19 of 20), Fraunces headline (13 of 20) |
426
+ | Harrison James | 0.10 | yes, at the line | Inter body (18 of 20), yellow accent (16 of 20), white ground |
427
+ | MMM | 0.05 | no | white ground, radial glow (13 of 20), Cormorant Garamond (9 of 20) |
428
+ | HJ Beauty | 0.05 | no | white ground, Fraunces (5 of 20), marquee (5 of 20) |
429
+ | Chair and Blade | 0.05 | no | square buttons (18 of 20), Bebas Neue (9 of 20), dark ground |
430
+ | RMP | 0.05 | no | eyebrow chip (14 of 20), Manrope body |
431
+ | Sensphere | 0.00 | no | radial glow (10 of 20), Inter body |
432
+
433
+ Read with care: "not typical" says the site is not what Claude builds from
434
+ the brief today. It does not say the site was decided. Sensphere scores 0.00
435
+ and still carries five catalogue tells on the page, violet among them: Claude
436
+ no longer builds that look for this brief, but it is still a known tell. That
437
+ is what signal 1 is for. DD and Harrison James are the
438
+ two a model would most nearly have built unprompted.
439
+
440
+ **The harvest** (`calibration/null/harvest.txt`). No face outside the two
441
+ reflex lists is chosen by a quarter of the null pages, so the font lists still
442
+ cover what the model picks today: Inter 69 of 140, Fraunces 51, Poppins 36.
443
+ The catalogue tells the model still produces most: `reflex-font-2` 103 of
444
+ 140, `glass-panel` 100, `reflex-font` 94, `cream-palette` 81,
445
+ `pill-everything` 79. Candidates nothing catches yet, for a person to read:
446
+
447
+ - A coral or terracotta accent (around `#e77a63`): 66 of 140, five briefs.
448
+ - Phrases across five or more briefs: "done properly" (33 pages, six briefs),
449
+ "exactly what" (27, all seven), "who actually" (24, five), "within one
450
+ working day" (32, five), "rather than" (27, six).
451
+ - The opening "hero > hero > cards" (54 of 140) is how the section reader
452
+ splits a nav band from the hero, not a model habit. Not a candidate.
453
+
454
+ `glass-panel` at 100 of 140 includes source hits on blurred sticky navs, the
455
+ same false positive fixed on the rendered path. The source rule needs the same
456
+ fix before that count means anything.
457
+
458
+ ### Signal 3 first read, 2026-09-23
459
+
460
+ `craft estate add` on the seven live snapshots, then `craft estate compare
461
+ --null calibration/null/*` (the line measured again: 0.31). Register and output
462
+ in `calibration/estate/`.
463
+
464
+ | Pair | Distance | Shares |
465
+ |---|---|---|
466
+ | DD + HJ Beauty | **0.28, siblings** | no accent, Fraunces headline, no reveals |
467
+ | DD + RMP | 0.49 | Fraunces headline, grey ground, pill buttons |
468
+ | Harrison James + Sensphere | 0.50 | white ground, square buttons, no reveals |
469
+ | HJ Beauty + RMP | 0.56 | Fraunces headline |
470
+ | Chair and Blade + anything | 0.60 to 0.86 | at most a marquee (with HJ Beauty) |
471
+
472
+ One sibling pair in twenty-one, and it is the agency's own site with one of
473
+ its clients: the same Fraunces headline over a near-black and white page with
474
+ no colour of its own. Fraunces sets the headline on three of the seven. Chair
475
+ and Blade shares nothing with anyone but a marquee. Not yet read by a person.
476
+
477
+ ### Human set, 2026-09-23
478
+
479
+ The references in claude-kit's `reference-set.md`, live home pages, scored as
480
+ the AI set is: typicality against all seven null models pooled, and the
481
+ design tells on the rendered page. The tenth reference is "any
482
+ generated-looking site" and is left out by definition. Snapshots and
483
+ `score.mjs` in `calibration/human/`.
484
+
485
+ | Site | Score | Tells on the page | Flagged |
486
+ |---|---|---|---|
487
+ | Linear | 0.00 | 7: violet, grid, icon grid, marquee, glow, Inter, hairline shadow | tell-heavy |
488
+ | Stripe | 0.00 | 5: violet, blue-to-purple, glass, icon grid, glow | tell-heavy |
489
+ | DD | 0.00 | 4: icon grid, pills, glow, Fraunces | tell-heavy |
490
+ | animations.dev | 0.00 | 2: marquee, Inter | no |
491
+ | Utopia | 0.00 | 2: hero then proof, pills | no |
492
+ | APCA (Myndex) | 0.00 | 0 | no |
493
+ | rauno.me | 0.01 | 0 | no |
494
+ | StarrLuxury | 0.01 | not measured: a preview gate, not the site | |
495
+ | candy-aesthetics | 0.05 | not measured: "This preview has ended" | |
496
+
497
+ - **Zero block hits and none typical**: both targets met. Every score is 0.05
498
+ or under.
499
+ - **Three of the seven measured are tell-heavy.** Linear and Stripe are where
500
+ the first-wave look came from: the indigo, the glow, the gradient were
501
+ theirs before they were every model's. The tell list describes them too,
502
+ which is the reason no single signal decides the verdict.
503
+ - **The comparison is not like for like.** The null models are small-business
504
+ briefs; these are software and portfolio sites, so a low score is easier to
505
+ reach. A human set of small-business sites nobody generated is the better
506
+ test and is still to find.
507
+ - Both house demos had expired or gated previews on the day. They are not
508
+ measured, not clean.
509
+
510
+ ### Character report first read, 2026-09-23
511
+
512
+ `craft report` on each live snapshot with its repo, its own brief's null and
513
+ the register. Reports and retrofit plans are in `calibration/report/`.
514
+
515
+ | Site | Verdict | Raised | Actions |
516
+ |---|---|---|---|
517
+ | DD | default | tells (12), typical (0.15), sibling of HJ Beauty | 26 |
518
+ | HJ Beauty | default | tells (6), sibling of DD | 18 |
519
+ | MMM | mixed | tells (18) | 27 |
520
+ | Sensphere | mixed | tells (9) | 18 |
521
+ | Chair and Blade | mixed | tells (7) | 11 |
522
+ | RMP | mixed | tells (8) | 18 |
523
+ | Harrison James | mixed | typical (0.10) | 9 |
524
+
525
+ No site has an `art-direction.json`, so the reasons are not measured on any of
526
+ them and none can be *decided* yet. The first change after deciding is the
527
+ same on all seven: the display face. It is the estate's common default, and
528
+ the one choice the retrofits (phase G) should settle first. Not yet read by a
529
+ person.
530
+
286
531
  ## The catalogue
287
532
 
288
533
  Generated from the package. Run `pnpm --filter @domandigital/craft run docs`
289
534
  after changing an entry; a test fails until you do.
290
535
 
291
536
  <!-- craft:catalogue:start -->
292
- Catalogue version `2026.09.3`, 39 tells.
537
+ Catalogue version `2026.09.6`, 54 tells.
293
538
 
294
539
  | Id | Gen | Surface | Severity | Tell | Why it is a default |
295
540
  | --- | --- | --- | --- | --- | --- |
@@ -332,4 +577,19 @@ Catalogue version `2026.09.3`, 39 tells.
332
577
  | `no-x-badge` | 2 | copy | warn | 'No X' badge | 'No catch.', 'NO JARGON GUIDE': a short standalone 'No X' reads as a slapped-on kicker, and worse when the same one is reused across pieces. |
333
578
  | `staccato-triplet` | 2 | copy | warn | Staccato triplet | Three fragments in a row ('Fast. Friendly. Local.' or 'No fuss. No jargon. Just results.') is the second wave's favourite rhythm. |
334
579
  | `where-x-meets-y` | 2 | copy | warn | 'Where X meets Y' | 'Where luxury meets comfort' is a tagline shape that fits every business and so describes none. |
580
+ | `chatbot-residue` | 1 | copy | warn | Chatbot residue | 'Certainly! Here's a revised version', 'as an AI language model', a citeturn0search0 token, a link tracked utm_source=chatgpt.com: text that exists only because a chat reply was pasted whole. This is evidence, not style. |
581
+ | `placeholder` | 1 | copy | warn | Unfilled placeholder | '[Insert testimonial]', '[Your Name]', lorem ipsum, TODO_PLACEHOLDER: scaffolding a reader must never see, and the clearest sign a page shipped before anyone read it. |
582
+ | `question-reveal` | 2 | copy | warn | Staged reveal | 'The result? Faster growth.', 'What does this mean for you? It means...': the writer asks the reader's question for them and answers it. An infomercial hook, and a favourite of generated copy. |
583
+ | `inline-label-list` | 2 | copy | warn | Bold-label bullets | '**Speed:** Faster pages' three times in a row: a short label restated in a few words, the list shape generated copy defaults to. A definition list, with a real explanation after each label, is not this. |
584
+ | `ing-tail` | 2 | copy | warn | Empty -ing tail | '..., ensuring peace of mind', '..., highlighting our commitment': a participle tacked on the end that claims significance and names no mechanism. One of the most common shapes in the Wikipedia guide to AI writing. |
585
+ | `vague-attribution` | 1 | copy | warn | Unnamed source | 'Studies show', 'experts agree', 'it is widely known': a claim credited to nobody. A reader cannot check it, and the house proof rule forbids a claim nobody can check. |
586
+ | `closing-summary` | 1 | copy | warn | Closing summary | 'Overall,', 'In conclusion,', 'In short,': a paragraph that announces it is summing up, then restates what the reader has just read. |
587
+ | `false-range` | 1 | copy | warn | False range | 'From first-time buyers to seasoned investors alike' names two ends of no real scale, to sound as if it covers everyone. It describes nobody. |
588
+ | `phrase-density` | 2 | copy | warn | Leaned-on phrase | 'Rather than', 'actually', 'That is...' openers, participle triads: each is ordinary English once, and a document that uses one far above its rate has one move and repeats it. |
589
+ | `aphorism-density` | 2 | copy | warn | Aphorism cadence | Two clipped sentences alone on a line ('All of this already exists. The job is making it findable.') land once. Closing every section, they are a cadence a reader learns to hear. |
590
+ | `contraction-scarcity` | 1 | copy | warn | No contractions | A long document with almost no contractions reads stiff and machine-made. People write 'we're' and 'don't'. |
591
+ | `sentence-rhythm` | 2 | copy | warn | Metronomic rhythm | Sentence after sentence of the same length reads generated. A person's sentences run long, then short, then long again. |
592
+ | `repeated-sentence` | 1 | copy | warn | Repeated sentence | The same sentence on two pages, or the same nine words lightly edited, is one of the strongest signs a document was assembled rather than written. |
593
+ | `heading-shape` | 2 | copy | warn | One heading shape | Headings that all share one shape ('X, and Y', 'X, because Y', 'Keep, rewrite, consolidate, retire') read as a template filled in section by section. |
594
+ | `heading-echo` | 2 | copy | warn | Heading echoed | A heading repeated word for word as the first line under it spends the reader's attention twice on the same words. |
335
595
  <!-- craft:catalogue:end -->