fix(markdown-formatter): harden hook + simplify plumbing#11
Merged
Conversation
…list - Collapse the triplicated data_json envelope builder into one build_data_json helper (skipped / ok-clean / ok-findings paths). - Build FINDINGS_JSON in a single jq pass instead of re-spawning jq per matched line (was O(n) processes and O(n^2) re-serialization). - Drop a dead TOOL default that the line above always assigns. - Derive the ci-status RESULTS check from the needs graph (join(needs.*.result, ' ')) instead of a hand-maintained second list that had to be kept in sync by hand. Behavior-neutral; test suites unchanged and green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KPusuNL65RexZQQQ4SqL7t
Correctness fixes from an adversarially-verified review: - read_file_path: anchor the project-membership check on a path-segment boundary so a sibling directory that merely shares the prefix (e.g. repo-backup/ vs repo/) is no longer admitted as in-project. - normalize_path: case-fold the whole Windows path (not just the drive letter) so a case-only difference between file_path and CLAUDE_PROJECT_DIR doesn't skip a genuinely in-repo file. POSIX paths pass through unchanged (case-sensitive). - tests: exercise the jq-absence guard via an empty PATH — a shell-function shadow left command -v jq succeeding, so the guard was never hit; remove the dead readonly-unset/re-source. - tests: replace racy fixed sleeps with a bounded wait_for_sink poll so the fire-and-forget sink assertions stop racing process-spawn latency. - tests: use a circular hour distance for the UTC alignment check so it doesn't false-fail once per day at the 23->00 boundary. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KPusuNL65RexZQQQ4SqL7t
kyle-sexton
force-pushed
the
fix/markdown-formatter-hook-correctness
branch
from
June 27, 2026 18:59
06a63f3 to
f859176
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 06a63f369b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The unconditional ${rest,,} fold collapsed /c/Repo and /c/repo to the same
C:/repo on case-sensitive POSIX hosts, so hook::read_file_path could admit a
markdown file in a sibling directory outside CLAUDE_PROJECT_DIR. Gate the
drive-letter fold on OSTYPE (msys/cygwin/win32) so it applies only where the
filesystem is actually case-insensitive; POSIX paths pass through unchanged.
Correct the function comment, which wrongly claimed the drive regex never
matches on macOS/Linux. Add OSTYPE-aware unit tests covering both host classes
and the membership-guard regression.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HR4FCVWrioJ1dvfLJk1mcV
The /home/u/Pj test literal tripped the machine-specific-paths hygiene lane (flagged as a Linux user path). Swap it for /opt/App/Sub — still a mixed-case absolute POSIX path proving the no-fold pass-through, without a user-home shape. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HR4FCVWrioJ1dvfLJk1mcV
This was referenced Jul 17, 2026
kyle-sexton
added a commit
that referenced
this pull request
Jul 20, 2026
…ss when git clean failed (#395) (#590) ## Summary `git-tree-reset.sh --apply` printed `AppliedClean: git clean -fdx …` **unconditionally**, regardless of whether `git clean` actually succeeded — a false success signal that misleads any operator or automation keying off that line to conclude the tree reached a known-good state. Scope note: the sibling `AppliedReset` false-success and the unresolvable-`@{u}` gate that issue #395 references were already closed by #460 (reset-failure aborts clean, exit 5) and #542 (upstream-unresolved block, exit 6). This PR fixes the one remaining unguarded case — `AppliedClean` — so #395's acceptance criteria are fully met. ## Fix - Capture `git clean -fdx`'s exit status (`CLEAN_RC`), read on the line immediately after the capture so `$?` isn't clobbered (the script runs `set -uo pipefail`, no `-e`). - Gate the `AppliedClean` success line on the real outcome. A non-zero clean exit whose cause is **locked/in-use files** is the expected non-fatal case — `git clean` returns non-zero when it fails to remove any path, and that case is already reported honestly via `Unremovable:` — so it is **not** treated as failure (avoids regressing the deliberate locked-file handling on Windows). Only a non-zero exit with **no** `failed to remove` warnings is a genuine failure: it emits an explicit `FAILED:` line, `AppliedClean: failed`, and exits **7** instead of a success line. - Emit the `AppliedReset:` success line as soon as `reset --hard` genuinely succeeds — **before** `clean` — so a subsequent clean failure still surfaces the truthful reset outcome rather than swallowing it. - Run the reparse-point restore guard on the failure path too (data-loss guard: a clean that errored mid-run may still have deleted tracked files first; safe because `reset --hard` ran first). - Documented exit 7 in the script header, `usage()`, and the `clean` skill's `context/git-tree-reset.md` gates list. ## Verification New test case #11 (`git-tree-reset.test.sh`) forces a genuine clean failure via a `PATH` shim that intercepts only `git clean` (delegating every other subcommand — crucially `reset` — to the real git, so the reset genuinely succeeds). The full suite passes, including the 6 new assertions: ``` PASS: [38] clean failure exits 7 PASS: [39] clean failure reports failure PASS: [40] clean failure emits AppliedClean: failed PASS: [41] clean failure emits no clean success line PASS: [42] clean failure still reports the successful reset PASS: [43] clean failure leaves untracked intact (clean did not silently succeed) OK: git-tree-reset.sh tests passed ``` (All 43 tests pass; the pre-existing reset-failure suite #22–27 and upstream-unresolved suite #28–37 continue to pass — no regression. `shellcheck` is clean on both files.) Live `--apply` run against a repo where `git clean` fails after a successful reset — the report is now honest and exits non-zero: ``` AppliedReset: git reset --hard main FAILED: git clean -fdx exited 1 (non-locked-file cause) — untracked removal incomplete; reset --hard already applied. fatal: simulated git clean failure AppliedClean: failed RestoredTracked: 0 EXIT=7 scratch.txt still present (clean did NOT silently succeed): YES ``` Before this fix the same run printed `AppliedClean: git clean -fdx` and exited `0`. Closes #395 ## Related - #395 — this PR. - #396 — sibling issue on the same script (dry-run does not validate `@{u}` upstream). **Not addressed here** to avoid a merge collision on the same lines; a separate cycle picks it up. 🤖 Generated with a Claude Code implementation subagent (issue #395) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Jul 20, 2026
fix(disk-hygiene): reason about volume-root rejection instead of blanket-denying non-OS drives
#1026
Closed
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.
Improvements to the markdown-formatter hook from a
/simplifypass and a whole-repo/code-review(each finding adversarially verified before inclusion). Two commits, by concern.fix:correctness (verified bugs)hook-utils.shread_file_path!= "$proj"*is a prefix glob with no boundary — a sibling likerepo-backup/is admitted as in-project, so the hook would format.mdfiles outside the consumer reporoot/*, trailing slash stripped)hook-utils.shnormalize_pathfile_path/CLAUDE_PROJECT_DIRdiffer only in body casing → in-repo file silently skippedhook-utils.test.shjqwith a function —command -v jqstill succeeded, so the absence guard was never exercised (false coverage); dead readonly-unset/re-sourcePATH; remove the dead linessleep→ intermittent failures on Windowswait_for_sinkpoll (slow-sink timing test untouched)hook-utils.test.shrefactor:simplify (behavior-neutral)data_jsonbuilder into one helper.FINDINGS_JSONin a singlejqpass (was O(n) processes / O(n²) re-serialization).TOOLdefault.ci-statusRESULTSfrom theneedsgraph (join(needs.*.result, ' ')) instead of a hand-synced second list.Validation
hook-utils.test.sh27/0;markdown-format.test.sh40 pass (the 1 "fail" is a pre-existing slow-sink timing assertion that fails on Windows Git Bash before any of these changes). Shellcheck clean. Membership/normalize fixes verified against live temp-dir scenarios.🤖 Generated with Claude Code
https://claude.ai/code/session_01KPusuNL65RexZQQQ4SqL7t