Stale wiki/ path literals survive the kb/ rename across tools/, types/ and one kb/ page #102

Closed
opened 2026-09-13 08:57:28 +00:00 by torben · 2 comments
Owner

Done, shipped in 6.1.0-beta.7 (commit 24cd221), with a prose correction in 6.1.0-beta.8 (9a1be6a).

The reported symptom was real. The reported scope was not: it was one instance of a class.

The wiki/ → kb/ rename (2026-08-21, recorded in kb/concepts/architectures/Three-Layer Architecture.md) moved the directory but left the string wiki/ standing in 33 places across the tree. Nothing caught it for four weeks, because no check reads a path literal in source.

The scan itself was never wrong — run_lint(kb_dir) walks kb/ and page_count = len(pages) counts what it found. Only the labels lied.

What was fixed

User-facing output (13 of the 33):

  • lint_core.py:529 — the report header, Scanned N pages under `wiki/` (the originally reported line). Verified after the fix: Scanned 182 pages under kb/``.
  • Error messages: xref, cite (×2), touch, raw accept, move, rm, rename, log status
  • --help text: cite sync --all, provenance rebuild-index --dry-run, move --reconcile, and log's own Typer app help

Agent-facing: the four description: fields in types/type-spec.schema.yaml, which reach an agent through types describe and through every schema-validation message. base_dir's now reads "relative to the KB root (kb/)".

Control-plane prose: types/type-spec.md:181.

Comments and docstrings: frontmatter_io.py, type_resolver.py (×4), _util.py, log_append.py, tools/wikitool. Two were doubly wrong — git_publish.py and run_budget.py cited wiki/concepts/Mass-Update Gate.md, while the page lives at kb/concepts/workflows/Mass-Update Gate.md; the collection level was stale too.

Tests: test_log_append.py's assertion moved with the string; comments in test_type_resolver.py and test_touch.py.

Corpus: kb/entities/projects/Chemenu.md's "Architektur" line, pulled through with wikitool touch and logged to kb/log.md.

Deliberately not touched

  • raw/ — immutable by contract, whatever it says.
  • CHANGES.md's older entries — records of what was true at the time, not wayfinders. Same evidence/wayfinder split this repo applies to the tracker.
  • kb/concepts/architectures/Three-Layer Architecture.md — it documents the rename and is correct as written.
  • test_dist_cmd.py:456 — https://example/torben/wiki/releases/... is a fixture URL where wiki is a repository name.
  • "Dreilagig" on the Chemenu page stayed. An earlier revision of this body called it stale on the grounds that the pipeline has four stages. That was wrong: the corpus's own Three-Layer Architecture page carries reports/ as a fourth phase beside the three layers, so the wording is consistent and only the path was defective.

The guard

A pure string sweep would have left the identical trap for the next rename, so the fix carries one: tools/chemenu/tests/test_source_hygiene.py scans every .py file under tools/chemenu/ plus tools/wikitool against a table of retired stage paths. A future rename adds one row in the same change that does the renaming, and every forgotten site becomes a test failure instead of a string nobody reads for a year.

A docs verify sibling to check_no_issue_references() was considered and rejected: it reads shipped_prose(), which is markdown only, and the bulk of the defect sat in .py strings. A pytest guard covers exactly the surface the defect lives on.

Two exceptions are an explicit list with a reason rather than a cleverer regex — the fixture URL above, and the guard file itself, which necessarily declares the retired paths.

Acceptance criteria

  • grep -rn "wiki/" tools/ types/ returns nothing outside the out-of-scope list — verified after publish; the only remaining hits are the fixture URL and the guard's own declaration.
  • Every path a wikitool error message or --help string names resolves in a fresh checkout.
  • git_publish.py and run_budget.py cite kb/concepts/workflows/Mass-Update Gate.md, the path wikitool search "Mass-Update Gate" returns.
  • A test fails if any wiki/ literal is reintroduced under tools/chemenu/ — proved with a canary line in lint_core.py, which the guard reported as lint_core.py:842 names the retired path 'wiki/' (now 'kb/') before being reverted.
  • kb/entities/projects/Chemenu.md updated through wikitool touch, logged via log append --op update.
  • pytest (1314 passed, +2 from the new file), docs verify (56 commands, 73 shipped documents, 58 reference files) and instructions verify (23 instructions, 7 skills) all green before each publish.
  • VERSION at 6.1.0-beta.8, both bumps --patch --impact low, changelog prose written for each.

Doc pull-through

Nothing in docs/, in any CONTRACT.md, or in the README-shaped human docs went stale: no command behaviour, flag or reasoning moved, and none of those documents named wiki/. Checked rather than assumed.

One judgment made and worth recording: instructions/dev/issue-tracking.md § "Renames and other decay in the tracker" was considered as a home for a pointer to the new guard and deliberately left alone. That section is scoped to the tracker; the guard is scoped to source, and it is self-documenting at the point of failure — a failing run names the retired path and its replacement.

Two process notes

  • The published 6.1.0-beta.7 changelog entry first claimed "27 places" and "about half of them user-facing". Both were wrong — 27 came from a wc -l counting only tools/**/*.py. Corrected to 33 and thirteen in 6.1.0-beta.8, in the changelog and in the guard's docstring. The correction needed its own --patch bump because the docstring lives under tools/, and CI's version gate is scoped by path, not by intent.
  • During the guard's negative test, git checkout tools/chemenu/lint_core.py was used to revert a canary line and took the unstaged fix in the same file with it. Caught, restored, re-verified by grep and a full suite run before publishing.
**Done, shipped in 6.1.0-beta.7 (commit `24cd221`), with a prose correction in 6.1.0-beta.8 (`9a1be6a`).** The reported symptom was real. The reported scope was not: it was one instance of a class. The `wiki/` → `kb/` rename (2026-08-21, recorded in `kb/concepts/architectures/Three-Layer Architecture.md`) moved the directory but left the string `wiki/` standing in **33 places** across the tree. Nothing caught it for four weeks, because no check reads a path literal in source. The scan itself was never wrong — `run_lint(kb_dir)` walks `kb/` and `page_count = len(pages)` counts what it found. Only the labels lied. ## What was fixed **User-facing output (13 of the 33):** - `lint_core.py:529` — the report header, ``Scanned N pages under `wiki/` `` (the originally reported line). Verified after the fix: `Scanned 182 pages under `kb/``. - Error messages: `xref`, `cite` (×2), `touch`, `raw accept`, `move`, `rm`, `rename`, `log status` - `--help` text: `cite sync --all`, `provenance rebuild-index --dry-run`, `move --reconcile`, and `log`'s own Typer app help **Agent-facing:** the four `description:` fields in `types/type-spec.schema.yaml`, which reach an agent through `types describe` and through every schema-validation message. `base_dir`'s now reads "relative to the KB root (kb/)". **Control-plane prose:** `types/type-spec.md:181`. **Comments and docstrings:** `frontmatter_io.py`, `type_resolver.py` (×4), `_util.py`, `log_append.py`, `tools/wikitool`. Two were *doubly* wrong — `git_publish.py` and `run_budget.py` cited `wiki/concepts/Mass-Update Gate.md`, while the page lives at `kb/concepts/workflows/Mass-Update Gate.md`; the collection level was stale too. **Tests:** `test_log_append.py`'s assertion moved with the string; comments in `test_type_resolver.py` and `test_touch.py`. **Corpus:** `kb/entities/projects/Chemenu.md`'s "Architektur" line, pulled through with `wikitool touch` and logged to `kb/log.md`. ## Deliberately not touched - `raw/` — immutable by contract, whatever it says. - `CHANGES.md`'s older entries — records of what was true at the time, not wayfinders. Same evidence/wayfinder split this repo applies to the tracker. - `kb/concepts/architectures/Three-Layer Architecture.md` — it documents the rename and is correct as written. - `test_dist_cmd.py:456` — `https://example/torben/wiki/releases/...` is a fixture URL where `wiki` is a repository name. - **"Dreilagig" on the `Chemenu` page stayed.** An earlier revision of this body called it stale on the grounds that the pipeline has four stages. That was wrong: the corpus's own `Three-Layer Architecture` page carries `reports/` as a fourth *phase* beside the three layers, so the wording is consistent and only the path was defective. ## The guard A pure string sweep would have left the identical trap for the next rename, so the fix carries one: `tools/chemenu/tests/test_source_hygiene.py` scans every `.py` file under `tools/chemenu/` plus `tools/wikitool` against a table of retired stage paths. A future rename adds one row in the same change that does the renaming, and every forgotten site becomes a test failure instead of a string nobody reads for a year. A `docs verify` sibling to `check_no_issue_references()` was considered and **rejected**: it reads `shipped_prose()`, which is markdown only, and the bulk of the defect sat in `.py` strings. A pytest guard covers exactly the surface the defect lives on. Two exceptions are an explicit list with a reason rather than a cleverer regex — the fixture URL above, and the guard file itself, which necessarily declares the retired paths. ## Acceptance criteria - [x] `grep -rn "wiki/" tools/ types/` returns nothing outside the out-of-scope list — verified after publish; the only remaining hits are the fixture URL and the guard's own declaration. - [x] Every path a `wikitool` error message or `--help` string names resolves in a fresh checkout. - [x] `git_publish.py` and `run_budget.py` cite `kb/concepts/workflows/Mass-Update Gate.md`, the path `wikitool search "Mass-Update Gate"` returns. - [x] A test fails if any `wiki/` literal is reintroduced under `tools/chemenu/` — proved with a canary line in `lint_core.py`, which the guard reported as `lint_core.py:842 names the retired path 'wiki/' (now 'kb/')` before being reverted. - [x] `kb/entities/projects/Chemenu.md` updated through `wikitool touch`, logged via `log append --op update`. - [x] `pytest` (1314 passed, +2 from the new file), `docs verify` (56 commands, 73 shipped documents, 58 reference files) and `instructions verify` (23 instructions, 7 skills) all green before each publish. - [x] `VERSION` at `6.1.0-beta.8`, both bumps `--patch --impact low`, changelog prose written for each. ## Doc pull-through Nothing in `docs/`, in any `CONTRACT.md`, or in the README-shaped human docs went stale: no command behaviour, flag or reasoning moved, and none of those documents named `wiki/`. Checked rather than assumed. One judgment made and worth recording: `instructions/dev/issue-tracking.md` § "Renames and other decay in the tracker" was considered as a home for a pointer to the new guard and deliberately left alone. That section is scoped to the *tracker*; the guard is scoped to *source*, and it is self-documenting at the point of failure — a failing run names the retired path and its replacement. ## Two process notes - The published 6.1.0-beta.7 changelog entry first claimed "27 places" and "about half of them user-facing". Both were wrong — 27 came from a `wc -l` counting only `tools/**/*.py`. Corrected to 33 and thirteen in 6.1.0-beta.8, in the changelog and in the guard's docstring. The correction needed its own `--patch` bump because the docstring lives under `tools/`, and CI's version gate is scoped by path, not by intent. - During the guard's negative test, `git checkout tools/chemenu/lint_core.py` was used to revert a canary line and took the unstaged fix in the same file with it. Caught, restored, re-verified by grep and a full suite run before publishing.
torben added the status/unconfirmed label 2026-09-13 08:57:28 +00:00
torben changed title from lint report mislabels its scan root as wiki/ instead of kb/ to Stale `wiki/` path literals survive the kb/ rename across tools/, types/ and one kb/ page 2026-09-17 06:51:47 +00:00
torben added prio/plannedsize/Marea/kbkind/defect and removed status/unconfirmed labels 2026-09-17 06:51:52 +00:00
Author
Owner

Changelog: Triaged against the tree, status/unconfirmed removed — the symptom is confirmed, but the original body's "cosmetic one-liner, fix the literal" diagnosis was wrong about scope: 27 stale wiki/ literals across tools/, types/ and one kb/ page, of which ~13 are user-facing error messages and --help text. Body rewritten from the one-line diagnosis to the full inventory, an explicit out-of-scope list (raw/, CHANGES.md, the page documenting the rename), the guard decision, and checkable acceptance criteria. Labelled area/kb / kind/defect / prio/planned / size/M.

Original stub, for the record:

Root cause found: tools/chemenu/lint_core.py:529 hardcodes f"Scanned {report['page_count']} pages under \wiki/. ...". It's a cosmetic string bug, not a functional one — the scan itself correctly walks kb/(32 pages matched exactly), only the printed label is wrong. Fix: change the literal to ``kb/ ``.

Two notes on that text: the page count it cites (32) no longer matches the corpus, and the docs verify route was considered and rejected — shipped_prose() does not read .py, where most of the defect sits.

**Changelog:** Triaged against the tree, `status/unconfirmed` removed — the symptom is confirmed, but the original body's "cosmetic one-liner, fix the literal" diagnosis was wrong about scope: 27 stale `wiki/` literals across `tools/`, `types/` and one `kb/` page, of which ~13 are user-facing error messages and `--help` text. Body rewritten from the one-line diagnosis to the full inventory, an explicit out-of-scope list (`raw/`, `CHANGES.md`, the page documenting the rename), the guard decision, and checkable acceptance criteria. Labelled `area/kb` / `kind/defect` / `prio/planned` / `size/M`. Original stub, for the record: > Root cause found: tools/chemenu/lint_core.py:529 hardcodes f"Scanned {report['page_count']} pages under \wiki/`. ...". It's a cosmetic string bug, not a functional one — the scan itself correctly walks kb/(32 pages matched exactly), only the printed label is wrong. Fix: change the literal to ``kb/` ``. Two notes on that text: the page count it cites (32) no longer matches the corpus, and the `docs verify` route was considered and rejected — `shipped_prose()` does not read `.py`, where most of the defect sits.
Author
Owner

Changelog: Closed. Body moved from spec to record — criteria ticked with what verified them, the count corrected from 27 to 33 (the earlier figure counted only tools/**/*.py), and the "Dreilagig is stale" claim withdrawn as wrong. Added the doc-pull-through result (nothing went stale, checked not assumed), the rejected-docs verify reasoning, and two process notes: the published changelog prose needed a follow-up bump to fix the same count, and a git checkout during the guard's negative test briefly reverted an unstaged fix.

Shipped as 24cd221 (6.1.0-beta.7) and 9a1be6a (6.1.0-beta.8).

**Changelog:** Closed. Body moved from spec to record — criteria ticked with what verified them, the count corrected from 27 to 33 (the earlier figure counted only `tools/**/*.py`), and the "Dreilagig is stale" claim withdrawn as wrong. Added the doc-pull-through result (nothing went stale, checked not assumed), the rejected-`docs verify` reasoning, and two process notes: the published changelog prose needed a follow-up bump to fix the same count, and a `git checkout` during the guard's negative test briefly reverted an unstaged fix. Shipped as `24cd221` (6.1.0-beta.7) and `9a1be6a` (6.1.0-beta.8).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#102