Repository navigation
v0.14.3 - a planted link can no longer redirect the project config
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.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
- The conductor is wired in exec form (CWK2-027):
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. - The wallet's dollar invariant is stated as conditional (
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. - 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.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). - The secret scanner, the gate and both hooks are re-synced byte for byte:
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). - The git-spawn census is the flock's shared one, adopted by blob id (
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). - The claude.ai ZIP workflow is re-copied from the canon (
.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). - 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=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
- The pointer gate reads code fences with one shared scanner (tilde fences and indented fences included), and a
vX.Y.Z:pathcitation in the top entry is checked withgit cat-file -eagainst that tag (internal gate; no shipped change). - A
vX.Y.Z:pathcitation in a clone without that tag is a named SKIP, not a FAIL (internal gate; no shipped change).