doc-triggers.py resolves the repo root by depth, so it climbs out of every project that adopts it #17

Closed
opened 2026-08-17 23:38:16 -05:00 by null · 0 comments
Owner

ROOT was pathlib.Path(__file__).resolve().parents[3] — correct only while the script sits at its template home, docs/architecture/scripts/.

The template's own adoption instructions tell a project to copy scripts into scripts/, and TOOLS.md documents exactly that ("they are taken from the template one at a time, having been read"). From <project>/scripts/doc-triggers.py, parents[3] resolves to the parent of the project directory — outside the repository.

What it costs

The failure is silent and reads as a pass. main() opens with:

if not DOCS.is_dir():
    print(f"doc-triggers: no docs/ directory at {DOCS}")
    return 0

So an adopting project gets exit 0 and a line naming a directory two levels above the project, and the check that enforces "update the triggered documents in the same commit as the code" has quietly stopped running. That is the failure mode GUARDS.md opens with — a guard that cannot fail is worse than no guard, because it is trusted — landing on the tool that polices the documents.

Reproduced against a scratch repo at <tmp>/thing/ with the script at scripts/, a docs/THING.md governing src/**, and src/a.py staged:

OLD: doc-triggers: no docs/ directory at <tmp>/docs
NEW: docs/THING.md
         src/a.py
       trigger: any change to the module

What to do

Find the root rather than assume its depth: walk up from __file__ for a directory holding both docs/ and .git, then either alone, then git rev-parse --show-toplevel, then give up to the script's own parent.

Traps

  • Ordering is load-bearing. docs/ and .git must be tried before docs/ alone, or a repo containing a vendored docs/ in a subdirectory anchors on the wrong one.
  • Do not make the missing-docs/ case non-zero. Exit status is always 0 by design here — this is a prompt, not a gate — so the fix has to be in root resolution, not in the exit code.
  • The in-place layout must keep working; the template runs this from docs/architecture/scripts/ itself.

Verify: with doc-triggers.py copied to scripts/ in a repo whose docs/ holds a document governing src/**, python3 scripts/doc-triggers.py --staged names that document instead of printing "no docs/ directory"; run in place from docs/architecture/scripts/ it still fires DOC_TRUST_MAP.md, TOOLS.md and architecture/README.md.

`ROOT` was `pathlib.Path(__file__).resolve().parents[3]` — correct only while the script sits at its template home, `docs/architecture/scripts/`. The template's own adoption instructions tell a project to copy scripts into `scripts/`, and `TOOLS.md` documents exactly that ("they are taken from the template one at a time, having been read"). From `<project>/scripts/doc-triggers.py`, `parents[3]` resolves to the **parent of the project directory** — outside the repository. ## What it costs The failure is silent and reads as a pass. `main()` opens with: ```python if not DOCS.is_dir(): print(f"doc-triggers: no docs/ directory at {DOCS}") return 0 ``` So an adopting project gets **exit 0** and a line naming a directory two levels above the project, and the check that enforces "update the triggered documents in the same commit as the code" has quietly stopped running. That is the failure mode `GUARDS.md` opens with — a guard that cannot fail is worse than no guard, because it is trusted — landing on the tool that polices the documents. Reproduced against a scratch repo at `<tmp>/thing/` with the script at `scripts/`, a `docs/THING.md` governing `src/**`, and `src/a.py` staged: ``` OLD: doc-triggers: no docs/ directory at <tmp>/docs NEW: docs/THING.md src/a.py trigger: any change to the module ``` ## What to do Find the root rather than assume its depth: walk up from `__file__` for a directory holding both `docs/` and `.git`, then either alone, then `git rev-parse --show-toplevel`, then give up to the script's own parent. ## Traps - Ordering is load-bearing. `docs/` **and** `.git` must be tried before `docs/` alone, or a repo containing a vendored `docs/` in a subdirectory anchors on the wrong one. - Do not make the missing-`docs/` case non-zero. Exit status is always 0 by design here — this is a prompt, not a gate — so the fix has to be in root resolution, not in the exit code. - The in-place layout must keep working; the template runs this from `docs/architecture/scripts/` itself. Verify: with `doc-triggers.py` copied to `scripts/` in a repo whose `docs/` holds a document governing `src/**`, `python3 scripts/doc-triggers.py --staged` names that document instead of printing "no docs/ directory"; run in place from `docs/architecture/scripts/` it still fires DOC_TRUST_MAP.md, TOOLS.md and architecture/README.md.
null added this to the Batch 02 — Findings from the first real runs milestone 2026-08-17 23:38:16 -05:00
null added the
P1
label 2026-08-17 23:38:16 -05:00
null closed this issue 2026-08-17 23:39:31 -05:00
Sign in to join this conversation.
No Label
P0
P1
P2
release-blocker
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: null/Project-Template#17
No description provided.