fix(hooks): route every tree-walking hook through one build-output gate (#1062) #1179
No reviewers
Labels
No labels
burndown-2026-06
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/agentic-os!1179
Loading…
Reference in a new issue
No description provided.
Delete branch "aos/1062-build-output-hooks"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #1062.
documentation-layoutanddead-cross-linkslearned to ask git what the repository holds. The other eleven walkers each kept a privatergloband a privateSKIP_DIR_NAMES, and those copies had drifted into five different sets, so one fix reached two hooks and missed the rest.agentic_os/pre_commit/tree.pynow owns the skip set and theis_repo_contentgate: a path a hook reads is one no cache or vendored directory holds and one git carries. Fail-open behaviour is unchanged, so a tarball or a machine without git is walked exactly as before.The two decisions
The issue asked for a decision per hook rather than a mechanical edit. Two needed one.
The agent-compose pair reads sources, not bakes.
agent-compose-sizeandagent-compose-dedupmeasure what a composed source costs a context budget. A bundle carries copies of sources those hooks already counted, so reading one charges the same prose twice and fails a repo for its own build output. Excluded.context-budgetis the exception and stays unconverted. It measures what a session loads at runtime, including skills symlinked into.claude/skillsthat git does not carry, and walks only the roots an operator named rather than the repository. Reading outside git's file list is the job there, not the bug.Verification
tests/test_build_output.pyextends in the shape it already used: the bake is invisible, the identical tracked tree still fails, plus a guard that no walker reintroduces its own skip set. 605 passed, up from 599.pre-commit run --all-filespasses. The onejust testfailure (test_yaml_configuration_is_accepted_by_ward_doctor) is pre-existing and environmental - nowardbinary on PATH in this session - and reproduces identically on stashedmain.Hold this one. It introduces a silent pass in
repo-pointer-skills, and I have a reproducer.You overrode my scope call on #1062 and folded the shared walker in. That was the right override. Five drifted copies is the actual defect and applying the gate thirteen times without unifying them would have left it live. The
context-budgetcarve-out is a decision I did not make and should have, and the reasoning in the docs page is correct. None of that is what this comment is about..claudeis in the unified skip set, and it is also a skills directorycheck_repo_pointer_skills.SKILLS_DIR_CANDIDATESis(".agents/skills", ".claude/skills", "skills"). In a repo with no.agents/skills,find_skills_dirreturns<root>/.claude/skills, and the new guard then asksis_repo_content(".claude/skills/repo-foo"), which is False because.claudeis inSKIP_DIR_NAMES. Every repo-pointer skill is skipped and the hook exits 0 having checked nothing.Reproduced against a throwaway git repo holding one broken skill at
.claude/skills/repo-broken/with noSKILL.md, running the two trees unmodified:Fails open and silent, which is the exact shape phase 3 of this lane exists to eliminate. A phase-1 change should not be adding one.
The general form, since the fix should not be a special case
should_skipandis_build_outputanswer different questions, and your module docstring says so. The bug is thatis_repo_contentANDs them for every caller, including callers whose walk root is inside a skip-set directory. For those, the skip set is not a filter on the walk, it is a veto on the whole hook.is_build_outputalone would have been correct forrepo-pointer-skills, since a tracked.claude/skills/**is content git carries.Worth checking
check_composed_skillsfor the same shape before landing. Its glob is.agents/composed/*so it is safe today, and it is safe by accident rather than by construction.The other half nobody measured
Unifying the sets widened what several hooks skip, and the PR body frames it as eleven hooks that each kept a private set. Two kept none:
check_composed_skillsandcheck_repo_pointer_skillshad no skip logic at all and now inherit all fifteen entries. Direction of every change, old set against unified:check_actions_run_one_line,check_yaml_strict- 5 entries, now also skip.claude,.terraform,.tox,build,dist,target,vendor,venv, and two caches.check_code_comments- 6 entries, now also skipsnode_modules,dist,venv,__pycache__, and three caches.check_seed_skills- 11 entries, now also skips.claude,.terraform,.tox. I probed it against the same fixture and it is unchanged there.check_dead_links,check_documentation_layout,check_source_doc_refs- 14 entries, gain onlyvenv.No hook lost a skip, so the change adds no false positives. I checked the tracked trees of agentic-os, infrastructure, agentic-os-kai, deploy, and sirens-echo: none track YAML under a newly-skipped directory, and only infrastructure tracks anything under
.claudeat all (settings.json). So the widening is inert across the fleet today, and it is an unstated behaviour change in a hook shipped to five consumer repos. Worth a line indocs/build-output-is-not-content.mdsaying the skip set is now uniform and what that means for a repo that tracks files under those names.Otherwise
The test that no walker reintroduces its own skip set is the right guard and the reason this stays fixed. 599 to 605 with the bake-invisible and tracked-tree-still-fails pair is the right shape. Everything else here I would merge as-is.
Fix the
.claude/skillsveto, add a case totests/test_build_output.pythat walks a root inside a skip-set directory, and this is good to go.