Skip to content

feat(setup): stamp installed version into .cmm-stack-version (v1.11.1)#79

Open
halindrome wants to merge 4 commits into
developfrom
feat/stamp-install-version
Open

feat(setup): stamp installed version into .cmm-stack-version (v1.11.1)#79
halindrome wants to merge 4 commits into
developfrom
feat/stamp-install-version

Conversation

@halindrome

Copy link
Copy Markdown
Owner

Summary

setup.sh now stamps the stack version into the install target so a user can tell which version of the hooks they're running with a single cat — no more grepping hook internals.

This gap surfaced while diagnosing a reported cmm-grep-nudge.sh false-positive (a git commit whose message contained "larger" + a cwd containing "claudeapps/"). Root cause turned out to be a stale global install (the old unanchored substring matcher), not a source bug — the current source already anchors nav verbs to command position. There was no way for the affected user to tell what version they had installed; this fixes that.

What changed

  • install_global and install_project write <target>/.cmm-stack-version:
    1.11.1
    commit=<short-sha>
    installed=<iso-utc>
    
    Line 1 is the bare version (from VERSION); extra lines aid diagnosing dev/unreleased installs. Honors --dry-run.
  • Bumped VERSION / version.txt1.11.1 (1.11.0 already shipped).
  • CHECKSUMS.sha256 regenerated for setup.sh.

User-facing check

cat "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/.cmm-stack-version"   # global
cat .claude/.cmm-stack-version                                 # project

Testing

Isolated end-to-end install into a temp dir:

  • .cmm-stack-version written with 1.11.1 on line 1 ✓
  • freshly-installed cmm-grep-nudge.sh is the anchored (v2) hook ✓
  • --dry-run reports the stamp without writing ✓
  • bash -n setup.sh clean ✓

Scope / QA

Touches setup.sh → does not qualify for the docs-only QA skip. Standard 2–4 QA rounds apply (/pr-qa).

🤖 Generated with Claude Code

shanemccarron-maker and others added 2 commits June 17, 2026 18:43
Both install_global and install_project now write a .cmm-stack-version
marker into the install target (config dir / .claude). Line 1 is the bare
version (from VERSION); extra lines carry the source commit + install date.
Users can identify which stack version they're running with a single
`cat "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/.cmm-stack-version"` instead of
grepping hook internals — the gap surfaced while diagnosing a stale-install
false-positive in cmm-grep-nudge.sh. Honors --dry-run. CHECKSUMS regenerated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ships the .cmm-stack-version install stamp. 1.11.0 already shipped, so the
stamp reports a fresh patch version.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@halindrome

Copy link
Copy Markdown
Owner Author

QA Round 1

Result: clean for blocking purposes — 0 critical, 0 major, 0 minor blocking findings. 1 minor non-blocking observation (test gap).

Contract Verification (source: synthesized)

Criterion Verdict Evidence
install_global writes <config_dir>/.cmm-stack-version ✅ pass setup.sh write_version_stamp "${config_dir}"; config_dir from detect_config_dir.
install_project writes .claude/.cmm-stack-version ✅ pass write_version_stamp ".claude"; relative .claude consistent with sibling install paths.
Line 1 bare version from VERSION; later lines commit SHA + timestamp ✅ pass Simulation → 1.11.1 / commit=… / installed=…; trailing newline stripped by $(cat …).
Honors --dry-run (reports, no file) ✅ pass DRY_RUN=true path prints "Would write …", creates no dir/file (verified).
Version readable via single cat ✅ pass Line 1 is the bare version.
VERSION / version.txt bumped to 1.11.1, consistent ✅ pass Both contain 1.11.1.
CHECKSUMS.sha256 regenerated, setup.sh digest matches ✅ pass Recorded digest == shasum -a 256 setup.sh.
No regression; additive + fail-safe ✅ pass Stamp is final action before echo "" in both functions; all external reads use || echo fallbacks → set -euo pipefail cannot abort the install (verified rc=0 with VERSION absent and no git). bash -n clean.

Findings

Contract: none. Regression: none.

Pre-existing issues discovered

  • [claude] F-01 (minor, observation, test-gap): No automated test asserts the marker is written. The repo has a tests/test-phase-NN-*.sh convention that verifies install artifacts, but nothing references cmm-stack-version / write_version_stamp. Non-blocking; the PR's manual end-to-end test covered the happy path. Future install-flow refactors could silently drop/break the stamp with no test to catch it.

Schema Change

None. Changed files: setup.sh, VERSION, version.txt, CHECKSUMS.sha256.


SAST review skipped

Code scanning is not enabled on this repository (GitHub API: "no analysis found"). No SAST delta this round.


QA performed by Claude Code (claude-opus-4-8)

Closes round-1 finding F-01 (no test asserted the marker is written).
tests/test-version-stamp.sh extracts write_version_stamp from setup.sh and
unit-tests it standalone: marker write (line 1 = bare VERSION), DRY_RUN
writes nothing, fail-safe fallback (no VERSION / no git -> unknown/nogit,
rc=0 under set -euo pipefail), plus static guards that install_global and
install_project both invoke the stamp. 5/5 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@halindrome

Copy link
Copy Markdown
Owner Author

QA Round 2

Result: clean for blocking — 0 critical, 0 major, 0 minor blocking. 3 minor non-blocking observations. Fresh reviewer independently re-reviewed the full diff including the round-1 test.

Contract Verification (source: synthesized)

All 8 original criteria pass; the round-2 addition (tests/test-version-stamp.sh provides real coverage and passes) passes — reviewer ran it (5/5). One criterion marked partial on wording only: "fail-safe" — see F-02 (nil realistic exposure).

Reviewer confirmed the test is genuine (not a tautology): awk extraction captures the whole function (inner } is indented; column-0 /^}/ stops at the real brace), subshell DRY_RUN/SCRIPT_DIR overrides take effect, T1/T2/T3 exercise distinct branches and would fail on regression, temp dirs cleaned up, date -u format portable across BSD/GNU.

Findings (all minor, non-blocking)

  • [claude] F-01 (minor, test-robustness, confirmed mechanism / hypothetical trigger): tests/test-version-stamp.sh T3 asserts commit=nogit using an empty mktemp -d as a "no git repo" dir, but git rev-parse walks parents — if $TMPDIR lives inside a git checkout (some CI setups), T3 inherits a real SHA and spuriously FAILs. Test conflates "no VERSION + no git" with "no ancestor .git".
  • [claude] F-02 (minor, robustness, confirmed): write_version_stamp's mkdir -p and {…} > file are unguarded, so an uncreatable/unwritable target aborts the installer under set -euo pipefail — unlike the cat/git/date reads which use || echo. Realistic exposure ~nil (both call sites pass dirs the installer already created), but the helper is marketed "fail-safe".
  • [claude] F-03 (minor, observation, out-of-scope): No Makefile/CI workflow runs any test; all tests/*.sh are ad-hoc. Pre-existing repo-wide, not introduced here.

Schema Change

None.


SAST review skipped

Code scanning is not enabled on this repository. No SAST delta this round.


QA performed by Claude Code (claude-opus-4-8)

F-02: guard mkdir/redirect in write_version_stamp so an uncreatable or
unwritable target warns and returns 0 instead of aborting the installer
under set -euo pipefail (matches the |\| echo guards on the value reads).
F-01: make test T3 hermetic — point SCRIPT_DIR at a guaranteed-absent path
so git -C -> nogit deterministically, independent of $TMPDIR placement.
Add T6 asserting the fail-safe write returns 0 and writes no marker on an
uncreatable target. 6/6 pass. CHECKSUMS regenerated. F-03 (no CI runner)
left out of scope — pre-existing repo-wide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@halindrome

Copy link
Copy Markdown
Owner Author

QA Round 3 — clean ✅

Result: 0 findings (0 contract, 0 regression, 0 observation). Fresh reviewer verified the round-2 fixes and did a full holistic pass.

Round-2 fix verification

  • F-02 (fail-safe) — correct & complete. Differentially proven under real bash + set -euo pipefail: guarded body (current) → rc 0 on an uncreatable target (no abort); guard reverted → rc 1 (aborts). The if { …; } > file; then … else … correctly catches a redirect-open failure. Happy path intact — real setup.sh --project install wrote the marker with 1.11.1 on line 1.
  • F-01 (test hermeticity) — correct. T3 now uses a guaranteed-absent SCRIPT_DIR, so git -Cnogit deterministically regardless of $TMPDIR.
  • T6 confirmed a genuine regression test (passes guarded, fails unguarded), with cleanup.
  • F-03 (no CI runner) remains intentionally out-of-scope (pre-existing repo-wide).

Contract Verification

All 8 criteria satisfied with evidence (real end-to-end install + 6/6 test run + bash -n clean + CHECKSUMS matches setup.sh + VERSION/version.txt = 1.11.1).

Schema Change

None.


SAST review skipped

Code scanning is not enabled on this repository. No SAST delta.


QA performed by Claude Code (claude-opus-4-8)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants