Record a launcher the hook can keep across upgrades - #694
Conversation
commitlore.bin held <data-root>/v0.8.2/dist/commitlore.mjs, so after upgrading to 1.0.1 the repository was still validating commits with the 0.8.2 build while the CLI reported 1.0.1. doctor noticed and said so; nothing fixed it, because install.sh cannot know which repositories have hooks. The wrapper is recorded instead when it demonstrably launches this build. It is an absolute path too, so it keeps the property the versioned path was chosen for -- independence from PATH and from any node_modules/.bin/commitlore above the repository -- and simply does not name a release. Only when it names this bundle. A wrapper belonging to a different installation is worse than a versioned path: it would send the hook to code this install never verified. Unreadable or unrelated falls back rather than guessing. Fourth instance of one pattern today. .mcp.json recorded the bare wrapper and followed every upgrade untouched; Hermes external_dirs, the plugin cache, and this each held a version or a copy, and each needed a fix. The configuration that pinned nothing is the one that survived. Existing hooks still need `commitlore hooks install` re-run -- doctor already prints exactly that as its fix. This only changes what new installs record. Verified by restoring the old resolution: the wrapper case fails. Limit: a hook records a launcher, never a release Blast: module Undo: easy Certainty: firm Provenance: authored Record-Id: r-693hook
CommitLore — record lintTrailers: clean — 1 commit in Trailer violations fail this check. Active constraints are informational — they are what the repository already decided, not a verdict on this PR. |
|
Closing: the approach is wrong, and CI caught why. Recording the wrapper worked. Executing it did not. The wrapper is a shell script that finds My PR body claimed the wrapper 'keeps the property the versioned path was chosen for'. That was wrong. Being an absolute path and being launchable by a recorded interpreter are different properties, and I asserted the second from the first. Three local reproductions passed — no wrapper, foreign wrapper, and the unit suite — because my What #693 needs insteadNot this. Either the stub grows a branch that executes a shell-script entry point directly (no recorded interpreter involved), or the launcher recorded is a version-free path to a The second is closer to what the other three instances of this pattern did, and it does not require the stub to learn a new execution mode. Reopening #693 with that. Nothing about the defect changed: |
…696) * Give the hook a path that outlives the release it was installed from commitlore.bin recorded <data-root>/v<version>/dist/commitlore.mjs, so an upgrade left every repository validating commits with the build it was installed from. Measured on the first machine to upgrade: three repositories pinned to 0.8.2 and 0.8.0 while the CLI was 1.0.1 -- this repository among them, through two releases. doctor said so on every run and stopped nothing. install.sh now maintains <data-root>/current beside the versioned checkouts, and hooks record that. It stays an absolute path to a .mjs, so the recorded interpreter launches it and the hook remains independent of PATH -- the two properties the versioned path was chosen for. The bin wrapper cannot serve here and that is not a guess: #694 recorded it and hooks failed under the restricted PATH a hook actually runs in, because a shell script cannot be launched with a recorded interpreter. Two things deliberately narrow. The link is only recorded when it resolves to the running bundle -- a current belonging to another install would send the hook to code this one never verified, which is worse than a version pin. And a host where the symlink cannot be made still installs: hooks there keep recording the versioned path, and `commitlore hooks install` after an upgrade remains the repair doctor already names. The path is derived from the layout rather than from the directory being called commitlore, after the first attempt matched on that name and failed anywhere the data root is named otherwise. Existing pins still need `commitlore hooks install` re-run. This changes what is recorded from now on. Limit: a hook records a path that does not name a release Blast: system Undo: easy Certainty: firm Provenance: authored Record-Id: r-693curr * Make the rejection case prove the rejection The test asserting a foreign current is refused passed for the wrong reason: the fixture pointed current at a path with no bundle, so realpathSync threw and the fallback happened because the link was broken. The identity comparison never ran, and removing it left the test green. The other installation is now a working one. Only the comparison can reject it. Two mutations, two different failures: removing the derivation -> the version-free case fails removing the identity check -> the foreign-current case fails Before this, one mutation covered both and the second layer was unpinned. Caught in review by asking which mutation each assertion answers -- a question the passing suite could not answer for itself. Limit: a rejection test names what does the rejecting Blast: local Undo: easy Certainty: firm Provenance: authored Record-Id: r-693mut2
Closes #693.
After upgrading to 1.0.1 the repository was still validating commits with the
0.8.2 build while the CLI reported 1.0.1.
doctornoticed and said so; nothingfixed it, because
install.shcannot know which repositories have hooks.What changed
The wrapper is recorded instead — when it demonstrably launches this build.
It is an absolute path too, so it keeps the property the versioned path was
chosen for (independence from
PATHand from anynode_modules/.bin/commitloreabove the repository) and simply does not name a release.
A wrapper belonging to a different installation is worse than a versioned path
— it would send the hook to code this install never verified — so an unreadable
or unrelated one falls back rather than guessing. Both directions are pinned.
Fourth instance of one pattern today
The configuration that pinned nothing is the one that survived.
Scope
This changes what new installs record. Existing hooks still need
commitlore hooks installre-run, whichdoctoralready prints as its fix line.Verified by restoring the old resolution: the wrapper case fails. 72 tests
passing across
hooksand the new file.Canonical artifact
036397f2.