You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A planted link can no longer redirect the project config
Security
The project config is read and written only inside its own folder. A link planted at the config file or at a folder above it (a junction on Windows, a symlink on POSIX) made the conductor read a file outside the project, and made scripts/configure.mjs read, back up and write outside it. hooks/coalface-conductor.js now accepts a project config only when its real path is exactly its folder's real path plus the literal path the walk built; a refused file counts as absent and the report names it with the reason "it resolves outside its folder" (a permission-denied file keeps "unreadable"); the Antigravity adapter shares the read. scripts/configure.mjs pins the config it finds, the file it writes and the .bak copy before anything is read or written, and on a refusal prints one FAIL line and writes nothing. Witnesses: hook tests 71 to 85, configure tests 16 to 25. Named residue: check and use are two acts, a hard link cannot be told from a file, and a differently cased existing folder on a case-insensitive volume is refused.
Changed
The conductor is wired in exec form (CWK2-027): hooks/hooks.json now sets "command": "node" with the script path in "args" instead of a shell string with escaped quotes. Claude Code 2.1.299 takes this form; the vendor hooks reference (code.claude.com/docs/en/hooks, read 2026-10-15) says path placeholders such as ${CLAUDE_PLUGIN_ROOT} are substituted into command and into each args element as plain strings, with no shell, and that node plus a script path works on every platform. CoalWash ships the same shape in v1.12.2. scripts/verify.mjs now checks it; platform-configs/hooks.json is the Antigravity template with its own schema and is unchanged.
The wallet's dollar invariant is stated as conditional (skills/coalface/SKILL.md Wallet and description, README.md): the swarm fits inside the estimated solo dollar cost only when worker tiers are cheaper than main (CoalTipple delegate-down, or a cheaper model the user sets); with the default main-equivalent workers it can exceed solo dollars, and no budget stop exists. The benchmark figures are unchanged.
The release canon is adopted by blob id for three files (scripts/verify-release-shape.test.mjs, scripts/secret-gate.test.mjs, .coderabbit.yaml), with the git-spawn census pins re-pinned to the new blobs. Fixture git no longer waits on an editor, a prompt or a signer, and never signs with the operator's key (internal release tooling and tests; no shipped change).
The release canon is re-adopted at .github690c2de (scripts/release-notes.mjs included, superseding its first adoption above), and the hold on scripts/release-notes.test.mjs is lifted. Adopted at the canon blob, scripts/release-notes.test.mjs (7e779ef8, canon, later than 690c2de), scripts/release-notes.mjs (f8d998d8), scripts/lib/release-shape.mjs (bfb29332), scripts/lib/release-shape.test.mjs (771a7e60) and .coderabbit.yaml (0d5a8860); scripts/verify-release-shape.test.mjs is fa8a730d. Neither release-notes file carries a census pin (internal release tooling and tests; no shipped change).
The secret scanner, the gate and both hooks are re-synced byte for byte:scripts/lib/secret-scan.mjs (270a21a2, unchanged) and scripts/secret-scan.test.mjs (a0319dcd) from Bankfire bd328f2, scripts/secret-gate.mjs (856956a1) and scripts/secret-gate.test.mjs (2f066650) from the .github canon, and .githooks/pre-commit and .githooks/pre-push whole at 1979bcaf. The gate and the hooks now state what the scan does not catch (a credential inside a URL or connection string, an HTTP authentication header whose token is not provider-shaped, a key split across lines), and SECURITY.md says the same (internal gate; no shipped change).
The git-spawn census is the flock's shared one, adopted by blob id (scripts/lib/git-env-census.mjs13f8d95c, its test 972d9ca8 and its vectors file 8147dd7a, from .github), and the room's own lexer census is removed. gitTestEnv is re-exported from scripts/lib/git-env.mjs so the census trusts it by name; the room's one pin (scripts/secret-gate.mjs, which keeps GIT_INDEX_FILE on purpose) lives in scripts/lib/git-spawn-room.mjs and is measured by scripts/git-env-census-room.test.mjs (internal gate; no shipped change).
The claude.ai ZIP workflow is re-copied from the canon (.github/workflows/claude-ai-zips.yml, blob 686f200a): while no stable Release exists, a workflow_dispatch with the newer pre-release tag and launch_form=true re-points the one launch-form Release (draft, empty its assets, move its tag); a tag push alone re-points nothing (internal release tooling; no shipped change).
The test runner is the flock's wave runner and judges the suite by the TAP: each test file runs as its own node --test --test-reporter=tap child through scripts/lib/wave-run.mjs (3119cb7d, with its test fd578cfd and the scripts/lib/stdout-sync.mjs preload 27bd81af) and admits files by the live machine reading (scripts/lib/machine-reading.mjs, 1c550b66, byte-equal to the skill's own copy), all adopted by blob id, under the heap cap, a clock per test, a clock per file and a whole-run deadline, and a file that exits 0 before its tests register is VACUOUS and the run is red. scripts/test-expect.json holds a count floor for every roster file but one and, for scripts/git-env-census-room.test.mjs, the expected test names, so a test that vanishes from a file that still exits 0 turns the run red (scripts/lib/suite-run.mjs; testing.md's TAP-names rule). The unreleased single node --test child with --test-force-exit that preceded it is removed (internal gate; no shipped change).
Fixed
The pointer gate reads code fences with one shared scanner (tilde fences and indented fences included), and a vX.Y.Z:path citation in the top entry is checked with git cat-file -e against that tag (internal gate; no shipped change).
A vX.Y.Z:path citation in a clone without that tag is a named SKIP, not a FAIL (internal gate; no shipped change).
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
A planted link can no longer redirect the project config
Security
scripts/configure.mjsread, back up and write outside it.hooks/coalface-conductor.jsnow accepts a project config only when its real path is exactly its folder's real path plus the literal path the walk built; a refused file counts as absent and the report names it with the reason "it resolves outside its folder" (a permission-denied file keeps "unreadable"); the Antigravity adapter shares the read.scripts/configure.mjspins the config it finds, the file it writes and the.bakcopy before anything is read or written, and on a refusal prints one FAIL line and writes nothing. Witnesses: hook tests 71 to 85, configure tests 16 to 25. Named residue: check and use are two acts, a hard link cannot be told from a file, and a differently cased existing folder on a case-insensitive volume is refused.Changed
hooks/hooks.jsonnow sets"command": "node"with the script path in"args"instead of a shell string with escaped quotes. Claude Code 2.1.299 takes this form; the vendor hooks reference (code.claude.com/docs/en/hooks, read 2026-10-15) says path placeholders such as${CLAUDE_PLUGIN_ROOT}are substituted intocommandand into eachargselement as plain strings, with no shell, and that node plus a script path works on every platform. CoalWash ships the same shape in v1.12.2.scripts/verify.mjsnow checks it;platform-configs/hooks.jsonis the Antigravity template with its own schema and is unchanged.skills/coalface/SKILL.mdWallet and description,README.md): the swarm fits inside the estimated solo dollar cost only when worker tiers are cheaper than main (CoalTipple delegate-down, or a cheaper model the user sets); with the default main-equivalent workers it can exceed solo dollars, and no budget stop exists. The benchmark figures are unchanged.scripts/verify-release-shape.test.mjs,scripts/secret-gate.test.mjs,.coderabbit.yaml), with the git-spawn census pins re-pinned to the new blobs. Fixture git no longer waits on an editor, a prompt or a signer, and never signs with the operator's key (internal release tooling and tests; no shipped change)..github690c2de(scripts/release-notes.mjsincluded, superseding its first adoption above), and the hold onscripts/release-notes.test.mjsis lifted. Adopted at the canon blob,scripts/release-notes.test.mjs(7e779ef8, canon, later than690c2de),scripts/release-notes.mjs(f8d998d8),scripts/lib/release-shape.mjs(bfb29332),scripts/lib/release-shape.test.mjs(771a7e60) and.coderabbit.yaml(0d5a8860);scripts/verify-release-shape.test.mjsisfa8a730d. Neither release-notes file carries a census pin (internal release tooling and tests; no shipped change).scripts/lib/secret-scan.mjs(270a21a2, unchanged) andscripts/secret-scan.test.mjs(a0319dcd) from Bankfirebd328f2,scripts/secret-gate.mjs(856956a1) andscripts/secret-gate.test.mjs(2f066650) from the.githubcanon, and.githooks/pre-commitand.githooks/pre-pushwhole at1979bcaf. The gate and the hooks now state what the scan does not catch (a credential inside a URL or connection string, an HTTP authentication header whose token is not provider-shaped, a key split across lines), andSECURITY.mdsays the same (internal gate; no shipped change).scripts/lib/git-env-census.mjs13f8d95c, its test972d9ca8and its vectors file8147dd7a, from.github), and the room's own lexer census is removed.gitTestEnvis re-exported fromscripts/lib/git-env.mjsso the census trusts it by name; the room's one pin (scripts/secret-gate.mjs, which keepsGIT_INDEX_FILEon purpose) lives inscripts/lib/git-spawn-room.mjsand is measured byscripts/git-env-census-room.test.mjs(internal gate; no shipped change)..github/workflows/claude-ai-zips.yml, blob686f200a): while no stable Release exists, aworkflow_dispatchwith the newer pre-release tag andlaunch_form=truere-points the one launch-form Release (draft, empty its assets, move its tag); a tag push alone re-points nothing (internal release tooling; no shipped change).node --test --test-reporter=tapchild throughscripts/lib/wave-run.mjs(3119cb7d, with its testfd578cfdand thescripts/lib/stdout-sync.mjspreload27bd81af) and admits files by the live machine reading (scripts/lib/machine-reading.mjs,1c550b66, byte-equal to the skill's own copy), all adopted by blob id, under the heap cap, a clock per test, a clock per file and a whole-run deadline, and a file that exits 0 before its tests register is VACUOUS and the run is red.scripts/test-expect.jsonholds a count floor for every roster file but one and, forscripts/git-env-census-room.test.mjs, the expected test names, so a test that vanishes from a file that still exits 0 turns the run red (scripts/lib/suite-run.mjs; testing.md's TAP-names rule). The unreleased singlenode --testchild with--test-force-exitthat preceded it is removed (internal gate; no shipped change).Fixed
vX.Y.Z:pathcitation in the top entry is checked withgit cat-file -eagainst that tag (internal gate; no shipped change).vX.Y.Z:pathcitation in a clone without that tag is a named SKIP, not a FAIL (internal gate; no shipped change).Release page · CoalFace
All reactions