fix(#56): exempt absolute-form .claude/ / docs/ paths in require-active-ticket.sh#65
Conversation
…ve-ticket.sh The hook's case statements matched only repo-relative forms. When FILE_PATH points outside REPO_ROOT (agent worktree whose git-toplevel differs from the outer apexstack tree), the strip on lines 29-31 is a no-op and REL_PATH stays absolute. The case match fails, the exemption is missed, the hook blocks legitimate session-marker / docs writes. Extends each path-prefix exemption with its absolute-form twin: .claude/*|.claude|*/.claude/*|*/.claude docs/*|docs|*/docs/*|*/docs projects/*/docs/*|*/projects/*/docs/* The existing `*.md` pattern already crosses `/`, so absolute-match via a `*/…` prefix is a known-good shape — this just extends the same trick to the remaining exemptions. Added 7-case smoke test (relative + absolute form of each exemption plus the non-exempt block/unblock controls). All pass. Scope note: #56 literally asked only about `.claude/`. I extended `docs/` and `projects/*/docs/*` too since they would fail the exact same way in the exact same conditions — filing follow-up bugs for each would be busywork. Documented the whole pattern in a comment block so future maintainers see the reasoning. Closes #56
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review: PR #65
Commit: dbb09090cd76620c47d6059f639f86c598094510
Summary
One-hook fix for #56. Extends the REL_PATH case statement in .claude/hooks/require-active-ticket.sh to match absolute-form paths (*/.claude/*, */docs/*, */projects/*/docs/*) in addition to the existing repo-relative forms. Fixes the agent-worktree fallthrough where REPO_ROOT strip is a no-op and REL_PATH stays absolute.
Checklist Results
- Architecture & Design: Pass — same shape as the existing
*.mdglob; consistent with how the hook already handles its only other cross-/pattern - Code Quality: Pass — 9-line comment block documents the reasoning; no dead code
- Testing: Pass — 7-case transcript in PR body covers relative, absolute, nested-worktree, non-exempt-with/without-ticket
- Security: Pass — exemption only broadens the "no ticket required" path; cannot bypass any other hook
- Performance: N/A (case-statement eval)
- PR Description & Glossary: Pass — 4 terms, all load-bearing (REPO_ROOT, absolute-form fallthrough, agent worktree, hook)
- Technical Decisions (AgDR): N/A — applying an existing pattern, no new approach
Logic trace against the 7 smoke cases
REPO_ROOT=/x,FILE_PATH=/x/.claude/session/current-ticket→REL_PATH=.claude/session/current-ticket→ matches.claude/*→ exit 0 ✓REPO_ROOT=""+FILE_PATH=/x/.claude/session/...→ strip is no-op →REL_PATH=/x/.claude/session/...→ matches*/.claude/*→ exit 0 ✓REPO_ROOT=/worktree,FILE_PATH=/outer/.claude/session/...→ strip mismatches →REL_PATHstays absolute → matches*/.claude/*→ exit 0 ✓FILE_PATH=/x/docs/foo.md→REL_PATH=docs/foo.md→ matchesdocs/*(or*.mdfallthrough) → exit 0 ✓- Absolute
/y/docs/foo.mdwith mismatched root → matches*/docs/*→ exit 0 ✓ - Non-exempt code, no ticket → falls through to marker check → exit 2 ✓
- Non-exempt code, with ticket marker → exit 0 ✓
All 7 pass.
Scope
Extending docs/ and projects/*/docs/* alongside .claude/ is justified — same root cause, same file, same patch hunk. Filing two follow-ups would be busywork and would leave the hook half-fixed between merges.
Potential false-positive
*/docs/* will match a legitimate source file at /x/src/myapp/docs/config.ts in a downstream project and exempt it from the ticket-first rule. In practice: apexstack hooks operate on the framework's own exemption list, downstream projects that vendor the hook tend to keep apexstack's layout (docs/ is docs, not source), and the prior docs/* pattern already had this property at the repo-relative level — only difference is it now crosses /. Not a blocker. Worth a follow-up only if a downstream project reports ghost-exempt source files.
Suggestions
None blocking.
Verdict
APPROVED
Reviewed by Rex (Code Reviewer Agent)
Reviewed commit: dbb09090cd76620c47d6059f639f86c598094510
The earlier `*/docs/*` pattern already matches `projects/<name>/docs/<anything>` (shell case `*` crosses `/`), so the explicit `projects/*/docs/*` arm is a dead branch. Shellcheck flags it as SC2221/SC2222 and the CI job fails. Remove the redundant arm; added an inline comment so the intent is preserved for future maintainers (per-project apexstack docs are still exempt, just via the generic `*/docs/*` pattern). Smoke test (all 7 cases) still passes.
atlas-apex
left a comment
There was a problem hiding this comment.
Re-review at HEAD e52928207c1ffe1b6a33c4721dae488e9c9c0a18: incremental diff is purely the shellcheck lint fix — drops the dead projects/*/docs/* arm (subsumed by */docs/*) and adds an inline comment explaining the subsumption for future maintainers. Remaining case arms still cover the intent: per-project apexstack docs exempted via */docs/*. CI green: shellcheck .claude/hooks passes, Verify Ticket ID passes. SC2221/SC2222 warnings resolved. LGTM.
…re-active-ticket.sh (me2resh#65) * fix(me2resh#56): exempt absolute-form .claude/ / docs/ paths in require-active-ticket.sh The hook's case statements matched only repo-relative forms. When FILE_PATH points outside REPO_ROOT (agent worktree whose git-toplevel differs from the outer apexstack tree), the strip on lines 29-31 is a no-op and REL_PATH stays absolute. The case match fails, the exemption is missed, the hook blocks legitimate session-marker / docs writes. Extends each path-prefix exemption with its absolute-form twin: .claude/*|.claude|*/.claude/*|*/.claude docs/*|docs|*/docs/*|*/docs projects/*/docs/*|*/projects/*/docs/* The existing `*.md` pattern already crosses `/`, so absolute-match via a `*/…` prefix is a known-good shape — this just extends the same trick to the remaining exemptions. Added 7-case smoke test (relative + absolute form of each exemption plus the non-exempt block/unblock controls). All pass. Scope note: me2resh#56 literally asked only about `.claude/`. I extended `docs/` and `projects/*/docs/*` too since they would fail the exact same way in the exact same conditions — filing follow-up bugs for each would be busywork. Documented the whole pattern in a comment block so future maintainers see the reasoning. Closes me2resh#56 * fix: drop redundant projects/*/docs/* arm (shellcheck SC2221/SC2222) The earlier `*/docs/*` pattern already matches `projects/<name>/docs/<anything>` (shell case `*` crosses `/`), so the explicit `projects/*/docs/*` arm is a dead branch. Shellcheck flags it as SC2221/SC2222 and the CI job fails. Remove the redundant arm; added an inline comment so the intent is preserved for future maintainers (per-project apexstack docs are still exempt, just via the generic `*/docs/*` pattern). Smoke test (all 7 cases) still passes. --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
…re-active-ticket.sh (me2resh#65) * fix(me2resh#56): exempt absolute-form .claude/ / docs/ paths in require-active-ticket.sh The hook's case statements matched only repo-relative forms. When FILE_PATH points outside REPO_ROOT (agent worktree whose git-toplevel differs from the outer apexstack tree), the strip on lines 29-31 is a no-op and REL_PATH stays absolute. The case match fails, the exemption is missed, the hook blocks legitimate session-marker / docs writes. Extends each path-prefix exemption with its absolute-form twin: .claude/*|.claude|*/.claude/*|*/.claude docs/*|docs|*/docs/*|*/docs projects/*/docs/*|*/projects/*/docs/* The existing `*.md` pattern already crosses `/`, so absolute-match via a `*/…` prefix is a known-good shape — this just extends the same trick to the remaining exemptions. Added 7-case smoke test (relative + absolute form of each exemption plus the non-exempt block/unblock controls). All pass. Scope note: me2resh#56 literally asked only about `.claude/`. I extended `docs/` and `projects/*/docs/*` too since they would fail the exact same way in the exact same conditions — filing follow-up bugs for each would be busywork. Documented the whole pattern in a comment block so future maintainers see the reasoning. Closes me2resh#56 * fix: drop redundant projects/*/docs/* arm (shellcheck SC2221/SC2222) The earlier `*/docs/*` pattern already matches `projects/<name>/docs/<anything>` (shell case `*` crosses `/`), so the explicit `projects/*/docs/*` arm is a dead branch. Shellcheck flags it as SC2221/SC2222 and the CI job fails. Remove the redundant arm; added an inline comment so the intent is preserved for future maintainers (per-project apexstack docs are still exempt, just via the generic `*/docs/*` pattern). Smoke test (all 7 cases) still passes. --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
Summary
One-hook fix for apexstack#56. When an agent worktree's
git-topleveldiffers from the outer apexstack tree,require-active-ticket.shleavesREL_PATHabsolute and the case-statement exemptions (relative-only) miss. Legitimate writes to.claude/session/current-ticketanddocs/**get blocked.Fix: extend each path-prefix exemption with its absolute-form twin (
*/.claude/*|*/.claude,*/docs/*|*/docs,*/projects/*/docs/*). The existing*.mdpattern already crosses/, so this is the same trick applied to the remaining exemptions.What changed
.claude/hooks/require-active-ticket.sh— three case arms extended + a comment block explaining the pattern for future maintainers/tmp/smoke-56.sh— not committed, stored locally); all passTesting
Scope note
The issue literally asked only about
.claude/. I extendeddocs/andprojects/*/docs/*too — they would fail the exact same way in the exact same conditions. Filing three follow-up bugs would be busywork. Documented the pattern in the comment block so future maintainers see the reasoning.Glossary
git rev-parse --show-toplevel. Used to normalise FILE_PATH to a repo-relative form.Related