Conversation
tools/install copies source over the installed tree with `rm -rf` followed by `cp -R`, so an edit made in the installed copy is destroyed on the next sync with no warning and no record. Comparing source against the install cannot tell the two cases apart, because both make them differ: the install was edited locally, or the source moved ahead. A guard that refuses on any difference breaks every routine update, which is a good way to get itself disabled. So each install now records a content hash of what it wrote, and a later run compares the install against that record. Matching means nothing local happened, and the copy proceeds no matter how far source has moved. Bundles with no record predate the manifest and fall back to comparing against source. That is conservative — it refuses a legitimate update once, until a manifest exists — on the grounds that a one-time re-run beats a silent delete. Also adds hooks/ to BUNDLE_DIRS and to the directories tools/install copies. It was in neither, so a skill shipping a hook had it installed by hand and tracked nowhere. That is how the evidence skill's wired PreToolUse gate — the one control that fires on every publish — came to have no source of record. The existing lint-skill-entry test asserts these two lists agree, and caught the omission when only one was updated. Controls, against a temp target and temp HOME: clean install exit 0 re-install, nothing touched exit 0 source moves ahead exit 0, change propagates local edit to the install exit 1, REFUSED, sha unchanged same with --force exit 0, edit discarded `node --test test/*.test.mjs` 61/61.
`description` was a plain scalar containing ": ", which YAML reads as a nested mapping, so the frontmatter did not parse. Any tool reading source frontmatter with a YAML parser fails on it; tools/install masked the defect by folding the value to a block scalar on the way out, so the installed copy parsed and the source did not. Folded to a block scalar at rest. The description text is unchanged.
`hooks/` was added here to `BUNDLE_DIRS` and to the installer's copy list, but `jongsun/add/pr-validate-falsifying-test` already does both in `edf65a3`, along with `tools/check-bundle-contract.sh` to assert the two lists agree. Two branches making the same change is how one of them ends up reverted by a merge resolution nobody reads. So this branch keeps only the part that is its own: refusing to overwrite an installed copy that has local changes. The guard iterates whatever `BUNDLE_DIRS` holds, so it covers `hooks/` for free once that branch lands. Dropping it also removes a defect this branch would otherwise carry into main. `check-bundle-contract.sh` reads the array with a single-line `sed`, and the multi-line form here made it fail to PARSE rather than fail a comparison — it exited 2 reporting that it could not read the declaration, which is a check that has stopped checking rather than one that found something. Controls re-run after narrowing, since the guard now iterates a different set: clean install 0, no-op re-install 0, source moves ahead 0 and propagates, local edit 1 with the sha unchanged, `--force` 0 and discards. 61/61.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
tools/installnow records a content hash of what it wrote to.mms-install-manifest; a later run refuses to overwrite an install that no longer matches that record.--forceoverrides. Carries an unrelateddomains/performancefrontmatter fix.Matching is against that record, not source, so an update installs however far source has moved; only a local edit refuses. An install predating the manifest compares against source instead, refusing one legitimate update until a manifest exists.
Motivation
tools/installcopies over the installed tree withrm -rfthencp -R, so an edit in the installed copy dies on the next sync, silently.Showcase
Against a temporary install target and
HOME:REFUSED--forceReplaces #111, which was closed when its fork was deleted. GitHub cannot reopen a pull request whose head repository is gone, so this is a new pull request from a branch in this repository carrying the same commits.