Follow-on to DOCFIX-139/140 (the mechanical ipv4->dc-dc rename sweep). This repo has now been renamed/forked twice in its short life (per D-110); rather than sweep by hand again next time, this delivery removes the remaining hardcoded self-references and adds a lint rule so a NEW hardcode can't land silently. Executed under blanket approval; no live cloud mutation -- repo content only. Validation: repo-lint 0 fail / 1 documented WARN; tests/repo-lint harness 34/34 (was 29/29; 5 L9 cases added); full repo-wide grep for the current repo name across scripts/runbooks/skill confirms only the two deliberately-exempted environment.md fact lines remain.
FILE: scripts/repo_lint.py
WHAT: a new check that FAILS when a script/RUN-block/skill file hardcodes the CURRENT repo's own directory name (R.name) as a literal path/URL token. Scope: whole-file for scripts/**/*.{sh,py} and .claude/hooks/*.{sh,py}; fenced-code-block-only for runbooks/*.md (prose naming a repo -- including a sibling repo by name -- is harmless; only an executed literal is the hazard); whole-file for .claude/skills/**/*.md (agent-operational instructions, not incidental prose). Opt-out marker repo-lint: allow-selfref for a genuine, reviewed exception (mirrors the existing L2 allow-stale-tokens convention).
WHY: this repo was seeded from openstack-caracal-ipv4 this same week (D-110) and DOCFIX-139 was a manual, one-time grep-and-fix sweep for the resulting stale references. Nothing stopped a NEW hardcode from being written today, or stopped this same class of bug from recurring on the next fork/rename. A lint rule converts "remember to grep for this" into an enforced gate.
SIDE FIX: all_text()'s .claude exclusion was narrowed from "skip all of .claude/" to "skip only .claude/worktrees/" (matching .gitattributes' own scoping of the worktree gitignore rule). The blanket exclusion meant .claude/skills/ and .claude/hooks/ -- both real, checked-in repo content, not session-local worktree copies -- were invisible to L1 (and now L9) lint entirely. Verified no new L1 findings from widening scope (checked non-ASCII/ CR byte counts in all 6 newly-in-scope files before narrowing: all clean).
HARNESS: tests/repo-lint/run-tests.sh T29-T33 (script hardcode FAILS, opt-out marker suppresses it, runbook prose outside a code block does NOT fire, runbook code-block hardcode FAILS, skill file hardcode FAILS). 34/34 green.
KNOWN LIMITATION (logged, not actioned -- pre-existing, not introduced here): L9's runbook check inherits L3/L4/L6's in_code detection, which only recognizes triple-backtick fences. runbooks/d011-batch3-window-DRAFT.md (4-space-indented pseudo-code) and runbooks/tenant-onboarding-v2-DRAFT.md (--- BEGIN block ... --- END block --- comment delimiters) use different conventions and are NOT reached by L3/L4/L6/L9 at all -- confirmed by manually grepping both for the DOCFIX-139 hardcodes, which lint did not flag. This is a real, separate lint-coverage gap (affects the existing L3/L4/L6 checks too, not just the new L9), logged here rather than fixed, since generalizing in-code detection to arbitrary block conventions is its own scoped piece of work. DOCFIX candidate: either teach the checks to recognize indented/BEGIN-END blocks, or standardize all runbooks onto triple-backtick fences.
REVERT: git checkout HEAD~ -- scripts/repo_lint.py tests/repo-lint/run-tests.sh (re-arms both the self-reference blind spot and the .claude/skills / .claude/hooks lint-invisibility; not recommended).
FILES:
.claude/skills/openstack-cloud-ops/SKILL.md -- frontmatter description, Step 0 identity/discovery text (now: confirm identity via git remote -v rather than guess a clone path; ask the operator for the clone URL rather than hardcode one), session-bootstrap line (now references $REPO)..claude/skills/openstack-cloud-ops/references/environment.md -- the repo URL is KEPT (this file's stated purpose is documenting anchor facts, exactly like its VIP/version/hostname entries -- re-verify before command-use, same discipline as everything else here) but tagged repo-lint: allow-selfref with an explicit rationale; added a $REPO convention pointer bullet.runbooks/README.md -- new Conventions bullet establishing $REPO: set once per session (export REPO=$(git rev-parse --show-toplevel) if already cd'd into the clone, else export REPO=~/<wherever you cloned it>); every RUN block that needs the repo path references $REPO, never a literal.runbooks/ops-update-procedure.md, runbooks/d011-batch3-window-DRAFT.md, runbooks/phase-01-bundle-deploy.md, runbooks/tenant-onboarding-v2-DRAFT.md -- the same 8 hardcoded paths fixed mechanically in DOCFIX-139 (rename) are now converted to $REPO (required, fails loud if unset -- no hardcoded fallback guess, consistent with hard rule 2 "never use an inferred value").clientdocs/sweep-receipt.txt (L7 re-record; reviewed for drift from the tenant-onboarding-v2-DRAFT.md edit -- no client-facing mirror, hash-only).WHY: converts "the clone dir must be named exactly X" from an assumption baked into 8 command sites into one explicit, operator-stated session input -- exactly the "measured or carried from confirmed as-built" standard hard rule 2 already requires for every other value in this repo.
REVERT: git checkout HEAD~ -- <file> per file above.