Skip to content

Make the sync commit bypass check-managed-files before adopting the hook in bundles/core #1462

Description

@tschm

Summary

rhiza-hooks has gained a check-managed-files hook (Jebel-Quant/rhiza-hooks#304,
shipped in Jebel-Quant/rhiza-hooks#309). It fails a commit that modifies a path listed in
.rhiza/template.lock's files: block, minus anything under exclude: in
.rhiza/template.yml.

It exists because the rule every managed repo's CLAUDE.md opens with — managed files
are overwritten on the next sync
— has had nothing enforcing it since make validate
was removed after v1.1.3. The failure it catches is silent and total: the edit works, is
reviewed, is merged, and disappears at the next sync.

This issue is not a request to adopt it. It is a request to make the sync path safe
first, because adopting it before that would break sync for every consumer.

Why the sync path breaks

A sync commit modifies template-owned files wholesale — that is its entire purpose — so
it is precisely the commit this hook is built to reject.

Concretely, in /rhiza:update (Jebel-Quant/rhiza-claude, commands/update.md step 7):

uv run --python 3.12 --no-project python "${CLAUDE_PLUGIN_ROOT}/scripts/stage_synced.py" .
# "It reads the lock's `files` list, stages exactly that plus template.yml/the lock"
...
git commit -m "chore: apply rhiza sync $TARGET"

stage_synced.py stages exactly the lock's files: list. check-managed-files reads
exactly the same list. So with the hook enabled and pre-commit installed, that commit
fails 100% of the time, in every consumer, on every sync.

What is already safe

Two cases need no change, so the fix is narrower than it might look:

  • The ref-bump commit (commands/update.md step 4) stages only
    .rhiza/template.yml. That file is project-owned, not template-owned, so the hook
    ignores it.
  • CI. The hook only reports paths that differ from HEAD, not merely paths that are
    managed and present. On a checked-out PR branch the tree is clean, so
    pre-commit run --all-files passes. (This narrowing was itself found by the hook
    firing on its own repo under make fmt, which passes every tracked file.)

The gap is the local sync commit, and only that.

Proposed fix

Set the documented bypass on the sync commit:

SKIP=check-managed-files git commit -m "chore: apply rhiza sync $TARGET"

SKIP is pre-commit's own mechanism, so this needs no cooperation from the hook, and it
is scoped to the one commit that legitimately rewrites managed files. check-managed-files
also accepts --allow PATH, but that is per-path and wrong for a wholesale restore.

The concrete edit is one line in Jebel-Quant/rhiza-claude (commands/update.md
step 7), and the same applies to any other sync path that commits on the user's behalf —
rhiza sync in rhiza-cli if it commits rather than only writing files. I have not
filed there; say the word and I will, or link this issue from a companion one.

The ask on this repo

Gate adoption on the above:

  1. Land the SKIP change in whatever performs the sync commit.
  2. Then add - id: check-managed-files to bundles/core/.pre-commit-config.yaml
    (alongside the existing rhiza-hooks block) and cut a release.

Adopting in the other order breaks /rhiza:update for all ~26 consumers at once, and the
failure is confusing rather than obvious — a hook telling you not to edit files that the
tool you just ran was supposed to edit.

Two side observations from the same investigation

Both are about this repo's shared hook list; happy to split them out if you would rather
track them separately.


Filed from a /rhiza:quality follow-up on rhiza-hooks. Evidence: stage_synced.py
behaviour as documented in commands/update.md; hook behaviour as implemented in
src/rhiza_hooks/check_managed_files.py and src/rhiza_hooks/_managed.py.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions