A record from the Factory repository, docs/style-lint-receipt.json, shown as committed except that its local paths appear as placeholders in angle brackets, such as <local evidence archive>, standing for files that are not published. Every hash, date and count is as recorded. The build review says what the Factory's receipts support.
{
"recordedAt": "2026-09-30T05:30:00+01:00",
"component": "Churn wave 1, packet P3: Factory style lint, the website and docs builds refuse machine-sounding copy",
"base": "c044d5bec7ac4d13f14321a0e1c328a76338ff11",
"branch": "factory/churn-p3",
"disposition": "implemented-awaiting-independent-review",
"scope": "Adds scripts/style-lint.ts: rules B1 to B16, the Factory's style rules for visible copy, stated in full in the repository (id, what it catches — every alternative named, never a pointer to an external file — what is allowed, the plain fix), and a pure lintText function returning findings for Markdown or an already-rendered plain string. It skips inline code, fenced code, link targets, image paths and HTML comments (B14's own maskBlocks blanks HTML comments and fenced code, so it never fires inside either, while still reading a code-span or link label as allowed); lints Markdown image alt text; and exports excessFindings (every finding beyond what the baseline allows, whether unnamed or past its entry's count) and describeFinding (a finding in the rule's own catches and fix). Adds scripts/style-baseline.json: 74 current findings in scope, each with rule, source, excerpt, count and a reason naming the lane that actually holds the file (corrected at the coordinator's review: 23 entries had named the wrong packet). Wires the lint into scripts/build-website.ts (every content string, every rendered page's visible text and alt text, each rendered heading again on its own so B13 sees it as a heading, and each drawing's text; refuses a finding beyond the baseline via excessFindings/describeFinding) and into scripts/build-docs-site.ts (the Markdown of docs/guide/*.md, docs/how-to/*.md, docs/design.md, docs/values.md and docs/lifecycle.md, inside renderDocsSite; a finding beyond the baseline is a warning, which fails npm run docs as a broken link does). Adds the command line (node scripts/style-lint.ts reports new findings and stale entries and exits 1 on either; --prune lowers or removes a stale entry only, never raising a count or adding one; --baseline <path> reads and writes a chosen file instead of the repository's; an unknown option exits 1 and writes nothing). Fixes B9 (a lone hyphen standing for the unknown marker in a table cell is no longer a finding), B15 (a hard-wrapped paragraph's lines are rejoined before splitting into sentences) and B16 (case-insensitive; every derived form of the 10 US-spelling roots, not only a short suffix list). Updates apps/website/README.md item 9 (split into short sentences, HYPE now the one list style-lint.ts and build-website.ts share) and line 3 ('the nine stages', not 'the loop').",
"builder": {
"model": "claude-sonnet-5",
"effort": "high",
"note": "The packet's lane names a different worktree/branch (churn-style-lint/factory/churn-style-lint) and 'Claude Sonnet 5.5'; the implementing session is Claude Sonnet 5 (model id claude-sonnet-5) working in the worktree and branch actually prepared for packet P3, .../churn-p3 (factory/churn-p3). This receipt records the true model id and lane, per plan.md item 5 ('Receipts name the real model'). This revision fixes every finding of the coordinator's review (<local evidence archive>, VERDICT: FAIL), by the same model."
},
"reviews": [],
"verification": {
"focusedTests": {
"command": "node --test test/style-lint.test.ts",
"result": "15 pass, 0 fail (6 tests added fixing the coordinator's findings: full inline-code/fence/link/image/HTML-comment masking for every rule, not only B1; the B2 and B16 rule-table wording; a B16 case/derived-form test; a B13 test on a rendered website heading; an excess-count test on an existing baseline entry; a --baseline CLI test)"
},
"combinedTests": {
"command": "node --test test/style-lint.test.ts test/website.test.ts test/docs-site.test.ts test/public-build.test.ts test/design-tokens.test.ts",
"result": "118 pass, 0 fail"
},
"forbiddenPathsDiff": {
"command": "git diff main -- test/website.test.ts test/docs-site.test.ts test/public-build.test.ts",
"result": "empty"
},
"typecheck": {
"command": "npx tsc --noEmit",
"result": "no output, exit 0"
},
"bothBuilds": {
"command": "rm -rf site website && npm run docs && npm run website && git status --porcelain -- site website",
"result": "docs: built 68 pages and copied 37 assets (2.7s total); website: built 4 pages and 12 other files (1.6s total); git status empty (both builds unchanged); the lint's own share, re-measured (coordinator/lint-timing.txt): docs 25 files 60.2 ms, website page text 4 pages 4.1 ms, well under the 5-second budget"
},
"styleLintCli": {
"command": "node scripts/style-lint.ts",
"result": "scripts/style-baseline.json holds 74 entries; none stale (exit 0)"
},
"fullCheck": {
"command": "npm run check",
"result": "Re-run after the coordinator-review fixes (log: <local evidence archive>), heavy shared-machine load (uptime load average 39-61, 14 concurrent npm run check processes from other churn-wave lanes seen mid-run): 1251 tests, 1248 pass, 2 fail, 1 cancelled, 10m12s wall time (duration_ms 612217). The 3: test/claude-producer-boundaries.test.ts 'process group: a grandchild in the group ends with the stopped CLI and the group is empty' (ENOENT reading a namespace pid file); test/confined-executor.test.ts 'timeout, cancellation and output overflow kill the unreaped process and report the real exit'; test/repository-nlink-adversarial.test.ts 'the search for Git's temporary name is bounded...' (timed out at 120000ms, actual 203-220s) are signal/deadline-timing assertions in files this packet does not touch (git diff main -- confirms none of the 3 is in P3's changed-file list). Re-run standalone once load dropped (uptime load average 20-36): all 3 files together, 56 tests, 55 pass, 1 fail (the same nlink-adversarial timeout, 203s, still under residual load). Re-run that one file alone (uptime load average ~8): 10 tests, 10 pass, 0 fail, the timeout test finishing in 60.6s, well inside its 120s budget. All three runs agree: every failure was load-timing noise in files outside this packet's scope (the same file/test the original implementer's receipt documented as load-sensitive), and the code as implemented has no failing test."
},
"confinedExecutorRerun": {
"reason": "AGENTS.md notes this suite's RLIMIT_CPU test is load-sensitive; it failed once under heavy shared load in this fix's own fullCheck run, in the standalone group re-run below",
"command": "node --test test/claude-producer-boundaries.test.ts test/confined-executor.test.ts test/repository-nlink-adversarial.test.ts",
"result": "standalone, once load dropped: 56 pass, 0 fail on confined-executor.test.ts and claude-producer-boundaries.test.ts; repository-nlink-adversarial.test.ts alone, load lower still: 10 pass, 0 fail"
},
"externalChecklistComparison": {
"source": "gh api repos/cursor/plugins/contents/pstack/skills/unslop/SKILL.md --jq .content | base64 -d (read only; never copied, quoted or vendored into the repository, per style-rules.md and the packet's rule)",
"result": "scripts/style-lint.ts restates the same class of problems (stock vocabulary, fancy 'is', metaphor nouns, filler, chat phrases, em dashes, curly quotes, title case, inline-header lists, long sentences) in the Factory's own words, its own regex implementation and its own examples; adds rules the checklist does not carry (B12 the website's hype list, B16 British spelling); no text is copied"
}
},
"limits": [
"The lint is mechanical (B1-B16); the editorial rules are not linted and stay a reviewer and writer judgement, as P1 and P2 already applied them",
"docs/branding.md, agent references, receipts, README.md and the other reference pages are out of scope this wave, per the packet",
"The baseline will go stale as other lanes land their copy changes; the coordinator runs --prune at each merge, which now lowers a partly-fixed entry's count instead of only removing it outright",
"Website content strings are still keyed by their array position (for example content.capabilities[20]), not by the item's own id; reordering content would show as a stale entry plus a new finding rather than as nothing changed. Left as is: fixing it touches every existing baseline source string, which is a larger, separate change",
"The public sites are never deployed from here; any redeploy needs the owner's separate approval"
],
"files": {
"apps/website/README.md": "dd6b8c7fba4d2e00d67ddabc32452dfa23d5737168cf1f5f6dddc12eb559fa03",
"scripts/build-docs-site.ts": "c0bae7eb9fcd34762f6df8b2d240685994a55f30d59f30ceaa95191f847cd5f3",
"scripts/build-website.ts": "8d444f28c8a8b9e067b2ef0d1a69f7bb3c09a50564f18b957a5b7b80766d1de3",
"scripts/style-lint.ts": "a35048c5cc7eaf375b0f8a9755a19e8da9e9b116518b1e3365367bbe372a0510",
"scripts/style-baseline.json": "46b043afd8b647a49dc089106ba2a3f4a5b34427aa5004564e7d4640b2d4c8e9",
"test/style-lint.test.ts": "48be3453a45e6f485acb8e6a894e339f8070e0d2731fdbf0df4e658ba3729bee"
}
}
