Skip to content

Marker-location mismatch: code-reviewer agent writes to ops-repo path, merge-gate hook reads from project-repo path #229

@Abdelrahman-Shahda

Description

@Abdelrahman-Shahda

Problem

For a managed project (in workspace/<name>/), the code-reviewer agent and the block-unreviewed-merge.sh hook disagree about where approval markers live.

Observed during a real merge (ApexYard ops fork → managed project apessolutions/dfn PR #96):

  1. Code-reviewer agent (.claude/agents/code-reviewer.md) wrote its approval marker to the ops-repo path:

    <ops_root>/.claude/session/reviews/96-rex.approved
    

    This is what the agent's spec / its prior verdict explicitly stated as Files touched.

  2. The merge-gate hook (.claude/hooks/block-unreviewed-merge.sh) looked for the marker in the project-repo path (via git rev-parse --show-toplevel from inside workspace/<name>/):

    <ops_root>/workspace/<name>/.claude/session/reviews/96-rex.approved
    
  3. Merge was blocked with: BLOCKED: PR #96 has no recorded code-reviewer (Rex) approval. even though Rex had just approved.

  4. Worked around manually by copying markers to the project-repo path.

Same skill, contradicting spec

Inside .claude/skills/approve-merge/SKILL.md step 5, the spec uses:

REPO_ROOT=$(git rev-parse --show-toplevel)
mkdir -p "$REPO_ROOT/.claude/session/reviews"

— which puts the CEO marker in the project repo, agreeing with the hook. So /approve-merge and the merge-gate hook are aligned. But the code-reviewer agent writes to a different place.

Suggested fix

Pick one of:

  • (a) Both Rex and /approve-merge write to the ops-repo .claude/session/reviews/ (alongside the ticket markers under .claude/session/tickets/<project>). Update block-unreviewed-merge.sh to walk up to the ops root the same way require-active-ticket.sh already does (looks for onboarding.yaml + apexyard.projects.yaml).
  • (b) Both write to the project repo .claude/session/reviews/. Update the code-reviewer agent's spec + /approve-merge's spec to use git -C workspace/<name> rev-parse --show-toplevel. Also requires every managed project's .gitignore to include .claude/session/ — see apexyard's own .gitignore for the precedent.

(a) seems more coherent with the apexyard#41 layout that already moved ticket markers under the ops root. It also avoids spreading approval state across many gitignore configurations.

Reproduction (against an ApexYard fork)

  1. Adopt a project via /handover, clone it into workspace/<name>/
  2. /start-ticket for an issue in that project's repo
  3. Open a PR, invoke the code-reviewer agent → it writes to <ops_root>/.claude/session/reviews/
  4. gh pr merge → blocked, hook reports the missing marker at workspace/<name>/.claude/session/reviews/

Workaround in the meantime

Manually copy / write markers under workspace/<name>/.claude/session/reviews/ before retrying the merge. Mind the project's .gitignore (most projects don't gitignore .claude/ — accidentally committing markers is the risk).

Severity

P1 — every audit / framework-flow PR hits this. Friction multiplies linearly with PR count.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions