---
name: ssot-maintenance
description: "Use when working on the SSOT docs (docs/NN_NN_*.md) — editing or creating a canon doc, hunting or fixing SSOT drift, adding or hardening a docs linter / CI gate, checking where a fact canonically lives, or publishing canon to the GitHub wiki. Operational playbook for docs:check_refs / docs:toc / tracker:check / wiki:sync, plus §Guard-craft — the craft of building a gate that actually catches: the recipe for adding a gate, its thesis, design rules, mutation-verify pitfalls, hardening checklist and the one-line index of the **blindness shapes** (a gate that under-implements its declared contract, a One-Home invariant with no gate behind it, a gate that constructs the defect it then reports, …) live in this skill's `guard-craft-index.md`, the shapes in full in `guard-craft.md`, both loading on demand — open the index when building, hardening or debugging a gate, and equally when writing a spec, mass-deleting, narrowing a rule or running a campaign. Defers the STANDARD itself to 00_06. Examples: \"edit 03_05\", \"is this value consistent across the docs?\", \"add a drift linter\", \"why is my guard green when it shouldn't be\", \"publish the docs to the wiki\", \"where does the Lorenz constant live?\""
---

# SSOT Maintenance

The *executable playbook* for keeping `docs/NN_NN_*.md` (and the firmware/backend they mirror) internally consistent. This skill is the **HOW**; it does **not** restate the standard or track state — those live elsewhere (see below). "SSOT drift slowly kills" — this skill is the antidote, and the engine for evolving better defenses.

## 📖 Read first — SSOT, do NOT restate here

These are the canonical homes. Read them before acting; never copy their content into this skill (that would itself be drift).

| Source | Owns |
|---|---|
| `docs/00_03_TRL_Matrix_HIL_and_Beyond.md` | **Readiness**: the NASA/ISO scale (1-9, never 10-12) and its `SRL`/`MRL` siblings (§1), TRL-Layered-Independence (§2), HIL + in-silico-as-HIL (§3), and the task-closure criterion + TRL Gate Events (§4). |
| `docs/00_06_SSOT_Documentation_Standard.md §0` | 🚦 **Validation Gate** — the admission criterion for a fact entering canon (an LLM proposes a *hypothesis*; it does NOT compute physics); roles vs instances → the `AI-vendor name One-Home` row, `00_06 §3.3`. |
| `docs/00_06_SSOT_Documentation_Standard.md §1` | **Canonical doc skeleton** (🎯 Мета / ✅ Статус / 🔗 Cross-references / 📑 auto-ToC / Content; blockers→00_07; no volatile counts). |
| `docs/00_06_SSOT_Documentation_Standard.md §2` | **Canonical-home registry** — *одна річ, один дім*. Seven tables of which fact lives where, partitioned by owning module (`§2.0`–`§2.6`; homes outside the module grid sit in `§2.0` under a **Поза модульною сіткою** label): TRL matrix→`00_03 §1`, AES modes→`03_05 §6`, Lorenz→`03_04 §1.2`, … |
| `docs/00_06_SSOT_Documentation_Standard.md §3` | **Drift-prevention tooling** — the CI-enforced guard registry, partitioned by SUBJECT (`§3.1`–`§3.6`); `§3.0` is its complement — what no gate sees. File a new guard under the matching subsection. ⛔ §3 is **never renumbered**: more inbound refs point at it than at the rest of the doc combined, so its number is an ADDRESS, and "tidying" it would break them all for cosmetics. |
| `docs/00_00_SSOT_Index.md` | SSOT index + reading order. |

> 🔑 **How to open `00_06` without reading all of it.** Its sections run `0 · 1 · 2 · 3 · 4` in file order, and the **first ~90 lines (≈28 kB) are everything that is NOT a registry** — the doc's own head, `§0` and `§1` in full, and all of `§2`'s prose, ending exactly at the first table (`### 2.0`). Do not read a list of what is in there from this line: the cut is defined by that BOUNDARY, and any enumeration here rots the moment a paragraph moves. That prefix is the default entry read; the two registries below it (`§2.0`–`§2.6`, `§3.1`–`§3.6`) are opened BY ADDRESS, never scanned. ⚠️ One exception, and it is the common one here: if the task TOUCHES A GATE, the prefix is not enough — `§3`'s own preamble — everything between its heading and `### 3.0` — must be read too; it carries the row-form contract, the registry's declared ceiling, and the operating rules for running the lane.

**Open work** lives in `00_07`; **campaign state** in memory, not here: `[[project_ssot_campaign_history]]` (Gen1 SSOT-standardization campaign, DORMANT) + `[[feedback_vilize_sweep_method]]` (the LIVE vilize method) + `[[project_vilize_00]]` / `[[project_doc_t33_t34_seed]]` (§00-tooling: markers, stan_audit), plus `[[feedback_no_volatile_counts]]`, `[[feedback_ssot_review_workflow]]`, `[[project_wiki_sync]]`.

## When to use

- Editing or creating any `docs/NN_NN_*.md` canon doc.
- "Is this value/fact consistent across the docs?" / suspect drift.
- Adding or tuning a docs linter / CI gate.
- "Where should fact X live?" (→ 00_06 §2 registry).
- Publishing canon to the GitHub wiki.

## Core principle

**Every fact has ONE canonical home (00_06 §2); everything else references it, never restates.** When a fact changes, edit it *only* at its home — references stay valid. A mirror must carry an explicit label saying it is one — the exact wording is `00_06 §2`'s to set, not this skill's. The linters below enforce *owner-only vocabulary*; the per-rule owner scoping lives in `00_06 §3.3` and is deliberately not restated here.

## Workflow — hunt → automate → fix

The loop that stabilises the SSOT (repeat per drift class):

```
1. HUNT     Find a fact restated inconsistently across docs/code
            (same value, two numbers; same string, two spellings).
            Identify its canonical OWNER (00_06 §2).
2. AUTOMATE Write a precise, low-false-positive linter (recipe → guard-craft-index.md)
            so the drift can never silently return.
3. FIX      Clean every off-home restatement → make it a reference.
            Re-run the gate until green; the gate now holds the line.
```

> Before editing any symbol the docs describe, honour the repo's blast-radius rule (CLAUDE.md §2): trace the symbol's callers first. Docs edits are low-risk, but value changes that mirror code are not.

### Module-restructure / extract-to-new-page

Moving a fact into its own canon page, merging two pages, dissolving one, or freeing/re-occupying a module number. **The method lives in `.claude/prompts/module_restructure.md`** (paste it, or «виконай …»); the norm — `00_06 §4`. ⚠️ Re-occupying a freed number is allowed (`00_05`), but it silently re-points every old ref at a different subject — a VERIFY event, not a renumber (its price → `00_06 §4`). Sibling loop, one item rather than one page → `item_cementation.md`.

### Cementing a 00_07 item (cement-trim or archive — code + SSOT + tracker together)

A heavier, specialised loop for *cementing* a tracker item — thinning a live one to a pointer (cement-trim) or retiring a done one (archive). Walk **every** code/doc site of the ID — forward **and** inbound refs, **semantic terms** (service names, constants, opcodes), not just the ID, across the WHOLE canon + code + spec + `.github`. ⛔ **Never write a NUMERIC RANGE of docs here** — take the list from the tree: `ls docs/[0-9][0-9]_[0-9][0-9]_*.md`; the canon-file set grows, a range rots silently. Verify each `✅` against real code + `git log` (don't trust prose-claims-done). Canonize what lives only in 00_07 prose **before** trimming (migrate-first); then **cement-trim** (open residual stays) or **archive** (fully done → §🗄️ table). Commit each ID separately. Founder disciplines (one edit at a time · READ the full canon section in every doc before thinning · orphan-ID sweep · re-audit cemented items) → `item_cementation.md` §Принципи + Шпаргалка + Фаза 2. ⚠️ No gate stands behind them: the zero-loss set-diff is grep-based, so a fact present-by-token but gutted-in-substance passes green. ⊕ Reverse sweep («хто чекав на МЕНЕ»; «резолвиться» ≠ «актуальний», §Guard-craft #50) → `item_cementation.md` Шпаргалка + Фаза 3. The full playbook (phases, breadcrumbs, anti-patterns) lives in **`.claude/prompts/item_cementation.md`** — its generated index blocks carry one rule per line, and each such line's body (mechanism · instance · bounds) sits under the same number in the companions `item_cementation_rules.md` and `item_cementation_adversary.md`, opened when a line stops you; Principles 1–8 are numbered separately and keep their bodies in the playbook. This skill only points (One-Home).

### Closing ANY item (not just a cementation) — the mirrors outlive the item

🔴 **Канон переживає власну підставу рівно в мить, коли пункт ЗАКРИВАЮТЬ, і почервоніти цьому нічим** [DOC-T.91, 2026-08-27]. Асиметрія робить клас передбачуваним: закриття оновлює **ПУНКТ** — той артефакт, який ти й редагував, — а дзеркала лишаються, бо вони інший артефакт і ти в них не заходив. Жоден гейт їх не бачить: файл існує, лінк резолвиться, а речення **БУЛО правдивим** у мить написання. Виміряно на закритті `ARCH.111`+`OPS.34`: **сім** домів лишились стверджувати старе при зелених усіх осях `tracker:check` і зеленій смузі `Docs` — три казали «індексуються ЛИШЕ грошові події», чотири слали читача по **ВІДКРИТИЙ присуд** при ратифікованому й архівованому. Того ж проходу той самий клас знайшовся ще на трьох закриттях (токен-міграція UI · ціновий якір `E.67` · вердикт глосарію `lt`) і **на восьмому домі — у `CLAUDE.md`**. ⚠️ **Діапазон-скорочення (префікс, номер, дефіс, другий номер) тут писати НЕ можна** — `code_tracker_id_check` читає його як ОДИН ідентифікатор, якого в реєстрі немає, і червоніє. Перелічуй ID поодинці або описуй словами — гейт, що стереже форму, оподатковує кожен текст ПРО цю форму.

⛔ Порядок свіпу після ратифікації (виконувані артефакти → таблиці → проза) і чому таблиця дорожча за прозу → `00_05 §4` п. 2.

**Рефлекс при кожному `[x]`/✅ — три греби, жоден не по ID пункту:** (1) **значення**, яке щойно перестало бути правдою («індексуються лише X», «компілятора немає», «периметр = `shared/`»), корпус-широко — інфра-факт осідає в 3-12 домах (`00_06 §2`); ⊕ **форму ЗАПЕРЕЧЕННЯ** (`не існує` · `немає` · `нуль` · `no … gate` · `until … exists`) грепай окремо, у домах, суміжних зі збудованим: таке твердження не ділить токена з роботою, що його спростувала (2026-09-10: три з чотирьох знахідок закриваючого свіпу — «канал не реалізовний», «there is no `--check` gate here», «нуль згадок у `docs/`»); (2) **маршрути**, що обіцяють ВІДКРИТЕ («відкритий присуд», «вирішує ⚖️ у», «дім роботи») і вказують на ID, який ти щойно закрив — ⊕ **і на ID, чию ⚖️ ти щойно РАТИФІКУВАВ, хоч сам пункт лишився живим:** події закриття там немає, тож цей греб — єдине, що клас підхоплює. Виміряно 2026-09-20 на `SLASH-1`: рядок Кат-A у `05_05 §2` (грошовий канон) **24 дні** казав «Відкритий присуд, звужений виміром до пари опцій», тоді як присуд ухвалили 08-27 і він був ТРЕТЬОЮ опцією; реф резолвився, форма була бездоганна, пункт справді відкритий — просто вже не ТИМ питанням. **Питай не «чи резолвиться», а «чи ціль ще про ТЕ питання».** ⊕ **І третій тригер того самого греба, ширший за обидва: ти не закрив і не ратифікував, а просто ПЕРЕПИСАВ предикат чужої ноги.** Виміряно 2026-10-01 (HW.33): застосування кореня переписало ногу HW.8.4 з «CAD ✅» на «CAD — після коміра», і свіп чесно оновив САМЕ ЦЮ ногу — а чотири носії, що цитували її як АЛЬТЕРНАТИВНУ дорогу («модельна під паузою, бенчева — ні»), лишились стояти, хоч дорога замкнулась у коло. 🔑 Наявне правило легенди `00_07` («перечитай НОГИ пункту») йде ВИХІДНИМИ рефами — усередині свого пункту; цей клас іде ВХІДНИМИ: хто спирається на ногу, яку ти щойно переписав, і спирається саме як на вихід. **Рефлекс: переписавши предикат ноги, грепни її ID і спитай не «чи реф живий», а «чи те, що на неї ПОКЛАДАЮТЬСЯ, вона ще дає».**; (3) **прозу власного пункту** — `**Стан:**` пишуть один раз, а ноги закривають окремо, тож голова систематично стверджує дихотомію, яку її ж свіжа нога вже спростувала. 🔑 **І причина, чому саме дихотомія протухає непомітно: вона ВИГЛЯДАЄ ВИЧЕРПНОЮ** (виміряно на `SEC.18`, 2026-08-27 — голова ділила роботу на «чекає строків ⊥ відвантажено», а та сама доба народила ногу, що не належить ЖОДНІЙ половині). Читач бачить дві половини, які разом дають ціле, і не питає про третю; тож перечитуючи `Стан` після закриття ноги, питай не «чи він ще правдивий», а **«чи нова нога лягає в котрусь із названих половин»**. ⚠️ Пункти (1)-(2) — це НЕ `item_cementation` (той важкий — цементує пункт цілком); вони коштують три греби й обовʼязкові навіть коли пункт лишається живим.

⊕ **ЧЕТВЕРТИЙ греб, і він єдиний, у якого НЕМАЄ хибного токена: дзеркало, що протухло не від ПРАВКИ, а від РОСТУ цілі** (2026-08-28, три інстанси за один sync-прохід). Норма — `00_05 §4` п. 4 («ціль ЗБАГАТІЛА»). Виміряні форми: (а) **часткова копія схеми** (два поля з семи — без тих, що несуть доказову поставу); (б) **абзац, що пережив ВЛАСНЕ закриття в тому ж доці**, коли спростування лежить кількома секціями нижче; (в) **код-блок канону, що цитує рядок, який став One-Home-константою** — цитата не є присвоєнням, тож пін-двигун не рятує (§Guard-craft #97). 🔑 **Дискримінатор, бо грепати нема чого:** питай не «що я змінив», а **«що канон КОПІЮЄ, і чи оригінал з тих пір не виріс»** — і найдешевший лік для (а) не оновити копію, а ЗНЯТИ її на користь вказівника: копія протухне знову, вказівник — ні. 🔴 **Четверта форма, знайдена 2026-09-01 і найпідступніша, бо несе ВЛАСНЕ СВІДЧЕННЯ про свіжість: копія, позначена словом «дослівно».** `S6.1` цитував рядок `06_01` про ізоляцію Redis із міткою «дослівна копія» — і мітка була правдива в день написання. Далі `INF.22` переписав оригінал («окремі БАЗИ» → «окремий інстанс/кластер на КОЖНОГО споживача», бо нумерованих баз в Upstash немає), копія лишилась, а мітка перетворилась на сертифікат точності, якого ніхто не видавав. **Ефект інверсний до звичайного дрейфу: звичайна копія викликає підозру й її перевіряють, а «дослівна» читається як УЖЕ звірена — тобто маркер фідельності купує копії довіру рівно тоді, коли вона її втратила.** 🔑 Рефлекс: `дослівно` · `verbatim` · `копія рядка` · `цитата з` у каноні — це не запевнення, а ЦІЛЬ для греба; і лік той самий, що для (а), лише терміновіший — знімай на вказівник, бо мітку доведеться перевіряти щоразу, а вказівник не доведеться жодного.

> 🔴 **СВІП «блокер проти ВЛАСНОГО присуду» — дешевий і дає найтихіший клас: пункт, чия робота ратифіковано звільнена, а STAGE лишився `🔗`** (2026-08-19). Хибне блокування ніхто не перемірює, бо воно **виглядає як обережність**, і жоден гейт його не бачить: `🔗` формально валідний, тригер названий, реф резолвиться. Прогін по всіх `🔗`-пунктах трекера дав ДВА з 29 — в одному `[x]`-присуд каже «наша машинна робота, НЕ gated партнерами» при STAGE `🔗`, у другому сам residual пише «не gated передумовами». **Рецепт:** візьми кожен `🔗`-пункт і грепни його ТІЛО на форми звільнення (`НЕ gated` · `наша машинна робота` · `РОЗБЛОКОВАНО` · `блокування знято/протухло`); хіт разом із живим `🤖`-residual = кандидат. ⚠️ Далі ЧИТАЙ: половина пунктів має дві половини під одним блокером (доменний контент партнера ⊥ операційний рядок застосунку), і лік там — РОЗДІЛИТИ residual, а не зняти STAGE. ⊕ Дзеркало вже записаного в `item_cementation` Фаза 3 («архівуючи ID, питай не на кого чекаю Я, а хто чекав на МЕНЕ»): там блокер тухне ззовні, тут — від власного присуду пункту.
>
> 🔴 **Рецепт вище ключується на СЛОВНИКУ звільнення — і саме тому пропускає найтихіший підвид, де жодного такого слова немає: суперечність між `**Стан:**` і ЧЕКБОКСОМ** (E.33, 2026-08-21). Там `Стан` уже записував «ЖИВІ канали — SMTP і Telegram; межа ~30 msg/s є ПЕРШИМ реальним предметом цього пункту», а чекбокс поруч і далі вимагав, щоб «адаптери існували». Ані `НЕ gated`, ані `РОЗБЛОКОВАНО` в тілі не було — пункт спростував себе ЗМІСТОМ, не словником. **Другий прохід рецепта: для кожного `🔗`-пункту прочитай `Стан` і чекбокс ПОРУЧ і спитай, чи перший не описує світ, у якому передумова другого вже виконана.** ⚠️ Той самий прохід дав і третю форму — **дублікат residual'а з РІЗНИМИ заявами про гейтування** (ARCH.75: те саме питання `duration`⟷`relevance` стояло пунктом (в) `🔗`-пакета І окремим «вільним» `⚖️`); там лік — злити в гейтований, бо ратифікований присуд каже, що до події воно не задається. 📊 База ставки, виміряна за один прохід: **три пункти з девʼяти** ділились на дві половини, де `🔗` ховав вільну (ARCH.31 · E.33 · ARCH.75-дубль) — тобто це не курйоз, а нормальний улов цементаційної кампанії.
>
> 🔴 **Дзеркало обох рецептів — НАДМІРНЕ звільнення, і воно тихіше, бо виглядає як виконаний присуд** (HW.33, 2026-09-14). Ратифікація звільняє ноги, що чекали САМЕ на неї, але нога буває гейтована ДВІЧІ, і свіп, що ключується на імені присуду, знімає обидва гейти одним рухом. Свіп присуду «вхід» (стелю передано в HW.9 входом) звільнив разом із приливом і ногу коміра, чию СТІНКУ не задає жоден артефакт, і креслення радома, що чекає корони (⚖️ HW.30); спіймано перечитуванням до коміту, гейт цього не бачить за побудовою — обидві ноги лишились формально валідними. **Звільняючи ногу, прочитай її текст цілком на інші «чекає · після · ⊂ · доки» і питай про КОЖЕН гейт окремо; звільнення — твердження про всі.**

## Commands

All via binstubs — **`bin/rails` / `bin/rspec`**, never `bundle exec` (`[[feedback_local_verify]]`).

| Command | Does | Engine |
|---|---|---|
| `bin/rails docs:check_refs` | The omnibus gate **within its own step** (one of the `docs_check` job's many — the lane is `docs_band.rb`): dangling `NN_NN` links (HARD) · §-label drift (HARD, DOC-T.48) · standard-conformance (**incl. H1** — DOC-T.49, checked before the skeleton exemptions) · and the rest. **The roster is `docs.rake`'s `failed <<` labels, mapped to `00_06 §3` rows by `DOCS_RAKE_LABELS` in `scripts/guard_registry_sync.rb` — never enumerated here.** **Every category is now HARD** — a hit fails the build, so "advisory while you triage" (the recipe in `guard-craft-index.md`) is a *transient* state, not a resting one. | `lib/docs_linter.rb`, `lib/docs_toc.rb` |
| `bin/rails docs:toc` | Regenerate the `📑 Зміст` auto-ToC between `<!-- TOC:AUTO:START/END -->` from current `## ` headings (curated `— descriptions` preserved). Run after changing headings. | `lib/docs_toc.rb` |
| `bin/rails tracker:check` | 00_07 DRY — full axis list in `00_06 §3.2`, not here. The one worth carrying in the head is **item visibility** (DOC-T.49): every `#### ` item must sit INSIDE a registry section (`## §NN`), because `parse` cannot see one that doesn't, and then every other check here iterates a set that silently lacks it. | `lib/tracker/dashboard.rb` |
| `ruby scripts/code_doc_section_refs.rb` | **HARD gate** (docs.yml, DOC-T.48): every `NN_NN §X` cited in a code comment, in the `.claude` routing layer or in the `.github` CI layer still resolves — **the exact perimeter lives in the script, not here**. Closes the structural blind spot that `docs:check_refs` scans `docs/**` and never reads code. The priciest step in `docs_check` (tens of seconds over the whole tree), so run it deliberately, not in a tight loop. | `scripts/code_doc_section_refs.rb` |
| `bin/rails docs:graph` | _(on-demand audit, NOT a CI gate)_ ref-graph view: orphan / dead-end pages, in/out-degree skew, one-way sibling links, comprehensive `#anchor` + linked-`§X` resolution. The graph lens the per-line gates can't give (they check refs flat, not the `NN_NN` link graph). | `lib/docs_graph.rb` |
| `bin/rails wiki:sync` | **Dry-run** (default): clone wiki, transform links + carry images, show `--stat` diff + unresolved links. Publishes nothing. | `lib/wiki_link_normalizer.rb` |
| `bin/rails wiki:sync PUSH=1` | Commit + push the canon `NN_NN` pages to the GitHub wiki (SSH to `*.wiki.git`). | ↑ |
| `COVERAGE=0 bin/rspec spec/lib/docs_linter_spec.rb spec/lib/docs_toc_spec.rb spec/lib/docs_graph_spec.rb` | Unit-test the linter / ToC / ref-graph engines (pure functions — `spec_helper`, **no Rails/DB**; `COVERAGE=0` skips the whole-suite coverage gate on a subset run). | — |
| `ruby scripts/docs_check.rb [refs\|tracker]` | **Fast local** alias — runs `docs:check_refs` + `tracker:check` with **no Rails boot** (~0.3s vs ~1.2s; no `bundle`/DB — only `ruby`+`rake`). Reuses the exact rake bodies → those two steps cannot drift from CI. ⚠️ **Two steps of the `docs_check` job (ask `docs_band.rb --list` how many there are — the count grows) — NOT the lane**; reading its green as a verdict about the Docs lane reddened `main` three times (OPS.25). Read-only (ToC regen stays `bin/rails docs:toc`). | reuses `lib/tasks/docs.rake` + `tracker.rake` |
| `ruby scripts/docs_band.rb` | **The WHOLE `CI · Docs` lane** (~1.5 min, on-demand): step list read from `docs.yml` itself, so a hand-written roster cannot rot beside it. NOT-RUN is classified BEFORE launching (interpreter resolve · `ruby -c` · `bundle check`) and reds alongside FAIL — an empty finding-set is "clean" only if every check EXECUTED. ⚠️ `git add` first: `spdx_headers` enumerates via `git ls-files` — except a WARM background-compute output (in-silico §When Modifying #21 forbids staging it): then run the band in a clean worktree; the band's own refusal prints the recipe. | `.github/workflows/docs.yml` |
| `ruby scripts/stan_audit.rb` | _(advisory, on-demand — ганяти на цемент/vilize-сесіях, НЕ CI-gate)_ три осі по registry-айтемах 00_07 — третя = **[x]-staleness** (чекнутий бокс із датою `✅ YYYY-MM-DD` старший ~14 днів → цементуй у Стан/канон і зрізай; бездатні = лічильник). Дві осі по `**Стан:**`-рядках: **canon-claim** (код-символ ∉ заявлені канон-доми айтема — ловить «Механіка — `NN_NN §X`» без змісту; FP-класи вбиті historical sweep'ом DOC-T.37 — повний exempt-перелік у шапці скрипта) + **volatile-numbers** (число+лічильне слово, класи A/B/C/D очима). Кожен хіт розібрати очима: FP / wrong-дім → Стан-реф-дожим / діра → канонізувати-migrate; новий повторюваний FP-клас → вбити В СКРИПТ. Метод/історія → `00_06 §3` | `scripts/stan_audit.rb` (standalone; реюзить `Tracker::Dashboard`-парсинг) |
| `ruby scripts/tracker_report.rb --takeable` · `--critical-path` | _(advisory, on-demand — ПРИСУД, не борг)_ режими над `00_07`; ростер — `case` у скрипті. 🔴 Кожен друкує ВЛАСНУ сліпоту ПЕРЕД таблицею — читай преамбулу, не таблицю (інакше це палантір: числа правдиві над курованою множиною). Одиниця — НОГА, не пункт. Чому advisory і стелі → `00_06 §3.2` + шапка скрипта | `scripts/tracker_report.rb` (standalone; реюзить `Tracker::Dashboard`-парсинг) |
| `ruby scripts/tracker_volatile_counter_check.rb --strict` | **HARD** у `docs.yml` [DOC-T.99, ⚖️ founder 2026-09-05] — число рухомої множини в `- **Стан:**` чи `📊 WATCH`. Лік автора — **назвати членів замість лічити** або лишити число з КОМАНДОЮ, що його відтворює. Словник (`NOUN`), винятки й оголошена стеля — шапка скрипта; чому — `00_06 §3.2` | `scripts/tracker_volatile_counter_check.rb` |
| `ruby scripts/component_doc_sync.rb` | **component registry gate** (HARD, CI `docs.yml`, UI.12): `04_04` ⟷ `app/views/` — domain files ⟷ §6.4 rows (1:1) · `shared/{ui,iot,web3}` ⟷ §6.1–6.3 (1:1) · namespace dirs ⟷ the §1 hierarchy tree. Sibling of `model_doc_sync` and `workflow_doc_sync`. The load-bearing part is the PARSER: row forms (a FOURTH must be taught explicitly) + ceilings → script header. | `ruby scripts/component_doc_sync.rb` (CI `docs.yml`) |
| `ruby scripts/model_doc_sync.rb` | **code↔doc registry gate** (HARD, CI `docs.yml`): `04_01` ⟷ `app/models/` (model files ⟷ `### Model` headings §2..§7 1:1 · concerns ⟷ §1 · `PARTITIONED_TABLES` ⟷ §0/§11) **+ `04_02` ⟷ `app/services/**`+`app/workers/**`** (every class mentioned). Run it (or rely on CI) after adding a model/service/worker. Pure Ruby, no Rails. Method/why → `00_06 §3`. | `scripts/model_doc_sync.rb` (standalone) |
| `COVERAGE=0 bin/rspec spec/quality/no_future_dated_claims_spec.rb` | **HARD gate** (docs.yml cross-tree step, DOC-T.77): a record about something DONE must not carry a date that has not happened. The date is an ORDERING ANCHOR — a forward-shifted entry makes an older verdict look newer than the one disproving it; anchor = HEAD commit date (§Guard-craft #67); why and discriminator → spec header. ⚠️ **Writing about this gate taxes you:** quoting a future date as an *illustration* on a line that also carries a completion marker reds it — paraphrase, do not exemplify (same class as writing about tracker form). | `spec/quality/no_future_dated_claims_spec.rb` |

> 🔴 **ЛІНЗИ ЗАПУСКАЮТЬ, а не переказують — і прогалина тут вимірюється РОСТЕРОМ, не памʼяттю** (2026-08-19). Вимірено на собі: із режимів `memory_gate.sh` роками ганялись ДВА (`--audit`, `--selftest`); `--weight`/`--oneway`/`--routes`/`--stops`/`--genre` — жодного разу, попри те що скіл `memory-maintenance` прямо велить «run the SEPARATE modes». **Вказівник на ростер (на відміну від пойменованого списку) про себе не нагадує**, тож практика тихо вироджується в один звичний виклик. Ростер бери з ДЖЕРЕЛА: `grep -oE '^\s+--[a-z-]+\)' .claude/hooks/memory_gate.sh`. ⊕ Найцінніший із них для ЦЬОГО скіла — `--stops`: обчислюваний **реєстр уже ВІДХИЛЕНОГО**, який агент «з холоду» перелічити не може, а одна промашка коштує сесії; читати ПЕРЕД вибором роботи. ⚠️ Кожна лінза оголошує СТЕЛЮ, і її треба брати разом із числом: `--stops` — «підлога, повний READ дає ×3.2»; `spec_claim_audit` — «шортліст, не вердикт» (перевірено: на найгострішому кандидаті мутація дала ВІСІМ червоних, тобто покриття вчетверо щільніше за гіпотезу лінзи); `stan_audit` вісь 1 дає хибний хіт на приватний метод, коли канон-дім несе публічний, **і тригериться власним поясненням у тілі пункту** — форму пиши словами, не токеном.

CI: `docs.yml` is the home of the doc-gate RAKE PAIR. ⚠️ Not of every doc gate: the spec-shaped ones it runs (`spec/quality/*`, `spec/deploy/*`) are ALSO swept by `ci.yml`'s full-tree rspec, so those have two CI homes and double-run on a mixed PR. Its `changes` filter covers `docs/**` + `**.md` + **every source tree** — deliberately wide, because several gates scan them tree-wide (perimeters live in the scripts) and the pin/model-sync gates read specific files inside them; a gate whose input sits outside it never runs on its own PR (recipe step 6, `guard-craft-index.md`). `ci.yml` has no `paths-ignore`: its `changes` job skips code jobs on a docs-only diff and `ci-ok` still reports. Branch protection (`docs-ok`) → `06_07 §2`.

## 🛡️ Guard-craft — a gate that actually catches

**Lives in [`guard-craft-index.md`](guard-craft-index.md) — open it the moment the task is an EVENT rather than docs work** (building, hardening or debugging a gate · asking whether a spec can fail at all · mass-deleting · narrowing a rule · running a campaign · shipping anything a human executes by hand). It carries the recipe «Add a new drift guard», the craft's thesis, its design rules and the generated one-line index of the blindness shapes; their bodies are in [`guard-craft.md`](guard-craft.md), opened by number — cite `§Guard-craft #N`. Why it left this body, and the price → the head of that file.

## Checklists

**Before merge** (any docs change):

```
- [ ] ruby scripts/docs_check.rb   → green — but it is TWO steps of the `docs_check` job, never the band
- [ ] ruby scripts/docs_band.rb    → green — the WHOLE `CI · Docs` lane, step list read from `docs.yml`
      itself. ⛔ A roster of gates rots by construction — never re-add one here.
- [ ] the band is NOT every lane that reads docs: `grep -l '<edited doc>' .github/workflows/*.yml`
      — a hit outside `docs.yml` is your lane too (2026-09-23: a 02_02 prose edit, band green,
      reddened `Smoke · In-silico L2` → local `pytest tools/in_silico/tests/test_doc_cache_sync.py`).
- [ ] bin/rails docs:toc           → run if headings changed, then re-check green (regen, not in the band)
- [ ] fact edited ONLY at its home (`00_06 §2`); mirrors labelled
- [ ] no volatile counts · no blocker section in canon · Cross-references at top
```

**Wiki publish — ZERO-TOUCH** (since 2026-06-24): `.github/workflows/wiki.yml` publishes on every push to `main` touching `docs/**` (off-switch: repo var `DISABLE_WIKI_AUTOSYNC=true`). Do **NOT** run `wiki:sync PUSH=1` by hand after a normal canon-push — it RACES the CI run (non-fast-forward reject). A manual `bin/rails wiki:sync` (dry-run) stays a useful link-check before a big restructure. Detail → `[[project_wiki_sync]]`.

## Gotchas (hard-won)

- **Subset `bin/rspec` runs trip the SimpleCov coverage gate** (a per-group `minimum_coverage` failure). That's an **artifact** of a partial resultset, not a real failure. The linter/ToC specs are pure units (`spec_helper`, no Rails/DB) — run them gate-free with `COVERAGE=0 bin/rspec spec/lib/docs_*_spec.rb`; for app-coverage truth run the full `bin/rspec` (`[[feedback_local_verify]]`).
- **`db/structure.sql`**: never stage drive-by Postgres-version line diffs — restore from HEAD (`[[feedback_structure_sql]]`).
- **`wiki:sync` needs SSH access** to the `*.wiki.git` repo; **always dry-run first**; read its "unresolved links" — they're often stale source links worth fixing. **Run it PLAIN** — never prepend `/usr/bin` to PATH (shadows the rvm ruby shim → system Ruby 2.6 → bundler crash); a `Gem::Resolver…GemParser` trace can also be a SentinelOne-eaten shim (`[[project_rvm_env_repair]]`).
- **A missing closing ` ``` ` fence silently desyncs EVERY fence-aware guard** (the `in_fence` toggle runs in every fence-aware `DocsLinter` method) + truncates the ToC — one unclosed fence disables them all at once. **Now HARD-gated**: `DocsLinter.unbalanced_code_fences` (DOC-T.45, 2026-07-18) counts fences by the SAME `line.start_with?` predicate the guards use, so `docs:check_refs` aborts on an odd count (reporting the opening line) — a mirror gate, self-consistent with what it protects.
- **An ILLUSTRATIVE path is indistinguishable from a live claim — in EVERY file a gate scans, and there are at least three such gates.** `guard_registry_sync` resolves each path a `00_06 §3` row cites; `spec/quality/claude_prose_path_refs_spec.rb` resolves each backticked file path in `.claude/**/*.md`; `path_check` does it for the memory corpus. A plausible example path fails all of them exactly like a dead real one. **Describe the form in words; never spell an example path, however obviously fictional it looks.**
- **Homoglyph / mixed-script drift** (a Cyrillic letter inside a Latin word) — HARD-gated by `ruby scripts/homoglyph_check.rb` (perimeter = its `GLOBS`); scan by hand only files outside it.
- **Stray COMBINING MARK inside a same-script word** — the homoglyph's sibling, and the cost is sharper: a word carrying `U+0301` is invisible to `grep` for that word, so it silently drops out of every sweep aimed at it (measured with a positive control — `grep` scored 0 on the affected line and 1 on a clean control). Same script, so no mixed-script scan sees it. Detector: `perl -CSD -ne 'while (/(\p{L}{0,6}\x{0301}\p{L}{0,6})/g) { print "$ARGV:$.: $1\n" }' $(git ls-files 'docs/*.md' '.claude/**/*.md' '.github/**')`. ⚠️ It stays a RECIPE, not a gate, and the reason is linguistic: Ukrainian legitimately marks stress to split homographs (the castle/lock pair is the schoolbook one), so artefact-vs-deliberate is a judgement no regex owns — read each hit. ⚠️ Describe that pair in words, never spell it: an accented example inside this file is itself a hit, and a detector whose first two findings are its own documentation is one a reader learns to skim (#10a, one surface over). Precision on the corpus at the time of writing was total (every hit an artefact, none a homograph), which is what made a hand sweep cheaper than any gate. ⛔ Do not "fix" these with a blind strip in a file you have not read: two of them were a mistyped word, not a mis-accented one, and stripping the mark alone would have cemented the typo.
- **Encoding trap in the detector ITSELF:** a `perl -CSD` one-liner decodes input to characters, but a Cyrillic literal in the SCRIPT stays bytes without `use utf8` — so the match silently fails and reports a clean tree. This bit the very sweep that found the class. **Verify any non-ASCII matcher with a positive control before believing its zero.**
- **`.c` firmware comments stay Ukrainian + the file's poetic house style** (`[[feedback_comment_style]]`).
- **zsh**: `status` is read-only; quote globs (`[[feedback_zsh_bash_gotchas]]`).

## Keep this skill bounded

This file is the **method**. It must not accumulate: the *standard* → `00_06`; *open work* → `00_07`; *campaign state* → memory; a *new guard* → its engine (`lib/docs_linter.rb` or `scripts/*.rb`) + its `00_06 §3` row; a *new blindness shape* → `guard-craft.md` (index regenerated). If you're tempted to add a fact here, it belongs in one of those homes — that discipline is the very thing this skill enforces.
