Skip to content

release: 1.2.17 — private-leak guard + 49 doc claims that no longer matched the code - #44

Merged
jojoprison merged 1 commit into
mainfrom
feat/private-leak-guard
Aug 21, 2026
Merged

jojoprison merged 1 commit into
mainfrom
feat/private-leak-guard

Conversation

@jojoprison

Copy link
Copy Markdown
Owner

Two [[wikilink]]s pointing at the maintainer's private Obsidian notes reached a public PR during the v1.2.14 review and were caught by hand. Nothing in the repo guarded that class. This adds the guard — and, since the question "does the rest of the documentation still tell the truth" was open, answers it: in 49 places it did not.

The guard

A blanket ban on [[wikilink]] is impossible: mnemo is a plugin about Obsidian and the docs carry 60+ legitimate examples. So scripts/lint-skills.py passes only shapes that cannot name a real note — placeholders ([[{hub_name}]], [[Session — …]]), single ASCII words ([[wikilinks]]), regex fragments — plus 32 invented names in the new scripts/wikilink-allowlist.txt. Everything else fails the lint with both ways out named in the message.

Two properties are deliberate, because both are how this class hides:

  1. The sweep reads whole files. The second link caught by hand was wrapped across two source lines; a line-by-line scan would have reported that file clean.
  2. A sweep that matches nothing fails instead of reporting clean — a wrong root, extension list, or regex is indistinguishable from a spotless repo.

It immediately caught its own documentation (the examples had been written as literals) and five machine-local paths that a hand-run grep had missed — that grep searched for one specific username and returned an honest, meaningless zero.

Mutant-kill: 6 mechanisms removed → 6 targeted failures. One survived at first: the test pinning "the guard is wired into main()" asserted that the guard's line appears in the output, and it appears just the same when the call is deleted. Rewritten to plant a real violation and require exit 1.

The 49 documentation defects

Found by an adversarial audit of every doc against the implementation, each finding confirmed by a separate verifier (of 50, exactly one was rejected).

The dominant failure was not the code moving ahead of the docs. It was a fact corrected in one file and left standing in its neighbour: the RU and ZH README sections still said "all fields are optional" eleven versions after the EN section was fixed in v1.2.5; CONTRIBUTING.md carried a stale copy of a gate whose canonical list lives in TESTING.md; docs/health.md showed a report format the skill no longer prints.

Worth calling out:

  • Six places across all three languages claimed nothing runs without your pick. review --full has been the documented exception since v1.2.8 — the flag itself is the consent.
  • CONTRIBUTING.md described a skill that fails the mandatory gate: no ## Portable paths, no invocation marker, and it implied an eighth skill is a drop-in addition when the canonical set is pinned in three places.
  • skills/session/SKILL.md contradicted itself about handoff.maxKB — 40 KB in one line, 56 KB fifty lines earlier. The code says 56; 40 turned out to be the legacy archive_handoff fallback when called without parameters, now recorded as such.
  • Seven CHANGELOG compare-links pointed at four tags that exist neither locally nor on origin — each a GitHub 404.
  • TESTING.md, the manual-gate document, described nothing from v1.2.16 and stamped itself v1.2.15 — the exact staleness v1.2.15 had fixed.

Dated CHANGELOG sections were not rewritten: an archive records what was true on the release date. Only the machine-readable part (links) was fixed, plus one dated note.

Gate

18 suites (one new, 351 → 373 tests), lint-skills.py PASSED, verify-release.py confirms v1.2.17, session-scan.py runs.

🤖 Generated with Claude Code

…й доки с кодом

Две ссылки на приватные заметки владельца доехали до публичного PR в ревью
1.2.14 и были пойманы руками — механической защиты от этого класса в репо не
было вовсе. Теперь есть, и заодно проверено, что остальная документация
говорит про код правду: не говорила в 49 местах.

## Гейт (scripts/lint-skills.py + scripts/wikilink-allowlist.txt)

Сплошной запрет `[[wikilink]]` невозможен — mnemo плагин ПРО Obsidian, в доках
60+ легитимных примеров. Проходят только формы, которые физически не могут
назвать чужую заметку: плейсхолдеры, одиночные ASCII-слова, куски регекспов,
плюс 32 придуманных имени в allowlist-файле. Всё прочее валит линт с
сообщением, называющим оба выхода.

Две особенности, и обе — про то, как этот класс прячется:

1. Скан читает файлы ЦЕЛИКОМ. Вторая пойманная руками ссылка была разорвана
   переносом строки (`[[Atom — Stop-хук Claude Code\nне получает токены…]]`) —
   построчный скан объявил бы файл чистым.
2. Свип, не нашедший НИ ОДНОЙ ссылки, падает, а не рапортует «чисто»: неверный
   корень, список расширений или регексп неотличимы от безупречного репозитория.

Гейт немедленно поймал собственную документацию (примеры нарушений были
записаны литералами) и пять машинно-локальных путей, которые ручной grep до
этого не увидел — тот grep искал одно конкретное имя пользователя и вернул
честный бессмысленный ноль.

Мутант-килл: 6 снятых механизмов → 6 адресных падений. Один сначала выжил —
тест «гейт подключён к main()» проверял наличие строки в выводе, а она
печатается и при удалённом вызове; переписан на подсадку живого нарушения.

## 49 расхождений доки с кодом

Найдены адверсариальным аудитом всех доков против реализации, каждое
подтверждено отдельным верификатором (из 50 находок отбита ровно одна).

Главный отказ — не «код ушёл вперёд», а «факт исправили в одном файле и
оставили в соседнем»: секции RU и ZH в README писали «все поля опциональны»
спустя одиннадцать версий после того, как EN-секцию починили в 1.2.5;
CONTRIBUTING нёс протухшую копию гейта, чей канон живёт в TESTING.md;
docs/health.md показывал формат отчёта, который скилл давно не печатает.

Отдельно стоит назвать:

- Шесть мест во всех трёх языках утверждали, что без твоего выбора ничего не
  запускается. `review --full` — задокументированное исключение с 1.2.8.
- CONTRIBUTING описывал скилл, который валит обязательный гейт: ни секции
  `## Portable paths`, ни строки-маркера, и обещал, что восьмой скилл
  добавляется просто, хотя набор пинится в трёх местах.
- `skills/session/SKILL.md` противоречил сам себе про `handoff.maxKB`: 40 KB в
  одной строке, 56 — пятьюдесятью строками выше. В коде 56; 40 оказалось
  fallback'ом легаси-пути `archive_handoff` при вызове без параметров.
- Семь compare-ссылок CHANGELOG вели на четыре тега, которых нет ни локально,
  ни на origin, — каждая давала 404.
- TESTING.md, документ ручного гейта, не описывал ничего из 1.2.16 и снова
  штамповал себя версией 1.2.15 — ровно тот стейл, который чинили в 1.2.15.

Датированные секции CHANGELOG не переписывались: архив — запись о том, что было
верно на дату релиза. Правлена только машинная часть (ссылки) плюс один
датированный маркер.

Гейт: 18 сюит (+1 новая, 351→373 теста), lint PASSED, verify-release для
v1.2.17 подтверждён, session-scan отрабатывает.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jojoprison
jojoprison merged commit 2def4e7 into main Aug 21, 2026
2 checks passed
@jojoprison
jojoprison deleted the feat/private-leak-guard branch August 21, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant