fix(pre-commit): keep key order in pretty-format-json so apm-owned JSON survives
pretty-format-json sorts object keys by default, but apm emits insertion order and `apm audit --ci` diffs its output byte-for-byte. A file in the formatter's scope therefore drifts on every commit with an empty git diff. Pass --no-sort-keys so `.claude/settings.json` and `.claude/apm-hooks.json` round-trip untouched and drop them from the exclude. marketplace.json stays excluded: it carries literal em dashes the formatter re-escapes to —. tests/test-pretty-json-tool-owned.sh runs the repo's real autofix hooks over copies of the four tracked apm-owned files and fails if any is rewritten, so losing the flag fails a test instead of surfacing as drift. Refs: #102 Co-Authored-By: Claude Code <[email protected]> Claude-Session: https://claude.ai/code/session_01KkT7RSDwDbmrM9T34b6sTi
This commit is contained in:
1 parent
3ff0741857
commit
c2c56ff948
4 files changed
+156
-50
No files matched your search
+19
-15
@@ -1279,24 +1279,28 @@ point only). Machine-specific settings go in the gitignored `.claude/settings.lo
|
||||
does not deploy and the replay does not compare; shared enforcement belongs in
|
||||
`.pre-commit-config.yaml`.
|
||||
|
||||
### Why it is excluded from `pretty-format-json`
|
||||
|
||||
It is in the **second and last alternation** in that hook's `exclude:` pattern, and that alternation
|
||||
is the only one there for a reason other than "generated manifest". Mind which number you are
|
||||
quoting: the pattern is `^(\.claude-plugin/marketplace\.json|\.claude/(settings|apm-hooks)\.json)$`
|
||||
— **two top-level alternations, expanding to three real tracked files**:
|
||||
`.claude-plugin/marketplace.json`, this one, and its committed `.claude/apm-hooks.json` sidecar,
|
||||
which is apm output under the same byte-for-byte replay and is excluded for the same reason.
|
||||
### Why `pretty-format-json` runs with `--no-sort-keys`
|
||||
|
||||
`pretty-format-json --autofix` sorts object keys unless `--no-sort-keys` is passed, while apm's hook
|
||||
integrator emits insertion order (`matcher` before `hooks`, `type` before `command`). Leaving the
|
||||
file in that hook's scope therefore rewrites apm's output into a form apm would never produce on the
|
||||
way into **every** commit, and `apm-audit-ci` then reports permanent drift on a file with an empty
|
||||
`git diff` — exactly what happened when the `SessionStart` hook first landed in `2e395a4`. Re-running
|
||||
`apm install` fixes the file; leaving it in scope would re-break it on the very commit carrying the
|
||||
fix.
|
||||
integrator emits insertion order (`matcher` before `hooks`, `type` before `command`). In scope with
|
||||
the default, the formatter rewrites apm's output into a form apm would never produce on the way into
|
||||
**every** commit, and `apm-audit-ci` then reports permanent drift on a file with an empty `git diff`
|
||||
— exactly what happened when the `SessionStart` hook first landed in `2e395a4` (#102).
|
||||
|
||||
**Load-bearing. Do not tidy it out of that list** (see `LESSONS.md`, 2026-08-14).
|
||||
The hook now passes `--no-sort-keys`, so this file and its committed `.claude/apm-hooks.json` sidecar
|
||||
(apm output under the same byte-for-byte replay) need **no exclude**: the formatter's default 2-space
|
||||
indent already matches apm's, and with insertion order kept they round-trip untouched.
|
||||
`tests/test-pretty-json-tool-owned.sh` runs the repo's real `pretty-format-json`, `end-of-file-fixer`
|
||||
and `trailing-whitespace` over copies of the four tracked apm-owned files (these two,
|
||||
`.claude-plugin/marketplace.json` and `apm.lock.yaml`) and fails if any is rewritten, so dropping
|
||||
`--no-sort-keys` — or an apm change that makes another autofixer touch its output — fails a test
|
||||
instead of surfacing as drift on an unchanged file.
|
||||
|
||||
**Load-bearing. Do not remove `--no-sort-keys`.** `.claude-plugin/marketplace.json` is the one path
|
||||
still in that hook's `exclude:`: it carries literal em dashes that the formatter re-escapes to
|
||||
`\u2014`, which `--no-ensure-ascii` would stop but for every JSON file. This closes the JSON case
|
||||
only; a new tool-owned file in the scope of another autofixer is still caught only by that test,
|
||||
not by a derived gate.
|
||||
|
||||
## Pushing without a network
|
||||
|
||||
|
||||
Reference in new issue
Block a user