SSOT Maintenance
SkillDocs & knowledgeUse 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: its thesis, design rules, mutation-verify pitfalls and hardening checklist live here, while the **blindness shapes** (a gate that under-implements its declared contract, a One-Home invariant with no gate behind it, precision-in-the-anchor, …) are indexed here one line each and written in full in this skill's `guard-craft.md`, which loads on demand, open it 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?\"
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the SSOT Maintenance skill
What this skill tells your AI
The instructions your AI receives, as published by alexey-lukin/silken_net in .claude/skills/ssot-maintenance/SKILL.md and read by ahel’s review.
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) ; ⛔ the AI-vendor roster subsection was REMOVED 2026-09-07 — canon names roles only (frontier-LLM / coding-agent), never instances, and their definition lives in the §3 registry row for the AI-vendor name One-Home gate. Moved here 2026-08-10 when the method page dissolved (DOC-T.68 фаза 3); the golden rule no code/solder until the spec is approved survives as this gate, the rest of the old AI-pipeline prose did not. |
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; the handful of homes outside the module grid sit in §2.0 under a Поза модульною сіткою label — they are two, and no ref points at them): TRL matrix→00_03 §1, AES modes→03_05 §6, Lorenz→03_04 §1.2, … ⚖️ Ratified 2026-09-08 — a §3 gate over a VALUE obliges its home to be declared here. The exempt kinds (completeness · self-validating · absence) are named in that section's own intro, never restated here. |
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. ⚠️ A description cell over CELL_CEILING (3000 B, scripts/guard_registry_sync.rb) fails CI. |
docs/00_00_SSOT_Index.md | SSOT index + reading order. |
🔑 How to open
00_06without reading 238 kB. Its sections run0 · 1 · 2 · 3 · 4in file order, and the first ~90 lines (≈28 kB) are everything that is NOT a registry — the doc's own head,§0and§1in 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.
State (what's done / next) lives in memory, not here: [[project_ssot_campaign_history]] (Gen1 SSOT-standardization campaign, DORMANT) + [[feedback_vilize_sweep_method]] (the LIVE method — 00_07 tracker-hygiene + 7-family guard-craft) + [[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_*.mdcanon 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 — the example that used to stand in this sentence had already drifted.
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 below)
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 seven-step method lives in .claude/prompts/module_restructure.md (paste it, or «виконай …»); 00_06 §4 keeps only the NORM — three things now: the criterion for when a theme EARNS a page, its mirror (when a page is DISSOLVED — two conditions, and the act itself a founder judgment rather than a threshold), and the Ruthless Pruning boundary. ⚠️ Re-occupying a freed number is allowed and has been done (00_05), but §4 names its price: it silently re-points every old ref at a different subject and invalidates every exemption justified by "that address is dead forever" — so treat it as a VERIFY event, not a renumber. ⛔ The split is by TYPE, not by size: do not pull the steps back into canon, and do not push the norm into the playbook. Sibling loop, one item rather than one page → deep_archival.md.
Deep-archiving a 00_07 item (cement code + SSOT + tracker together)
A heavier, specialised loop for retiring a tracker item. 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 here — the one that stood in this line excluded 00_00 (10 tracker-ID mentions) and the then-top doc (14), turning a "wide audit" into a systematic false negative exactly where it promises to catch dangling refs. 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); fix any drift found along the thread; then cement-trim (open residual stays) or archive (fully done → §🗄️ table). Follow the breadcrumbs ([DOC.N]/[FW.N] tags, Cross-ref lines, 00_06 §2 home-registry). Commit each ID separately. 🔴 Founder disciplines (2026-06-09): ONE edit at a time (verify between — no batching, even non-glue); READ the FULL canon section — in EVERY doc the fact lives in — BEFORE collapsing/thinning (a grep hit is NOT confirmation; esp. a Присуд/verdict — never delete un-canonized analysis; an "all clean, nothing found" sweep is a signal to dig deeper, not to stop). This rule has no gate behind it (⚠️ not the ONLY one — this same page names further ungated axes below; the uniqueness half measured false 08-22) — the zero-loss set-diff is itself grep-based, so a fact that is present-by-token but gutted-in-substance passes green; orphan-ID sweep (comm -23 referenced-vs-00_07-homed → a resolved+cited fix with no ####/table row needs a §🗄️ row); re-audit already-cemented items to the deeper standard. 🔴 І свіп має ЗВОРОТНИЙ бік, який inbound-guard не покриває за побудовою: архівуючи ID, питай не «на кого чекаю Я», а «ХТО ЧЕКАВ НА МЕНЕ». Гейт стереже, щоб реф не став dangling, а реф на щойно заархівований ID резолвиться ідеально — «резолвиться» ≠ «ще актуальний» (§Guard-craft #50). Тож після архівації грепни ID по 00_07 і читай КОНТЕКСТ кожного хіта на слова блокування (⛔ · ЗАБЛОКОВАНО · до присуду · чекає на): кожен такий хіт протухлий за побудовою, доки не доведено інше. Виміряний інстанс — ARCH.88 тримав пʼять сайтів TEST.12 за мертвим ⛔ кілька днів; ⚠️ ціна асиметрична, бо хибне блокування ніхто не переміряє — воно виглядає як обережність. Повний рецепт → deep_archival.md Фаза 3. Full 18-step playbook + breadcrumbs + anti-patterns lives in .claude/prompts/deep_archival.md — this skill only points (One-Home).
Closing ANY item (not just a deep-archival) — the mirrors outlive the item
🔴 Канон переживає власну підставу рівно в мить, коли пункт ЗАКРИВАЮТЬ, і почервоніти цьому нічим [DOC-T.91, 2026-08-27]. Асиметрія робить клас передбачуваним: закриття оновлює ПУНКТ — той артефакт, який ти й редагував, — а дзеркала лишаються, бо вони інший артефакт і ти в них не заходив. Жоден гейт їх не бачить: файл існує, лінк резолвиться, а речення БУЛО правдивим у мить написання. Виміряно на закритті ARCH.111+OPS.34: сім домів лишились стверджувати старе при зелених усіх 20 осях tracker:check і зеленій смузі Docs — три казали «індексуються ЛИШЕ грошові події», чотири слали читача по ВІДКРИТИЙ присуд при ратифікованому й архівованому. Того ж проходу той самий клас знайшовся ще на трьох закриттях (токен-міграція UI · ціновий якір E.67 · вердикт глосарію lt) і на восьмому домі — у CLAUDE.md. ⚠️ Діапазон-скорочення (префікс, номер, дефіс, другий номер) тут писати НЕ можна — code_tracker_id_check читає його як ОДИН ідентифікатор, якого в реєстрі немає, і червоніє. Спіймано двічі на цьому ж абзаці: спершу на самому скороченні, тоді на застереженні, що його ЦИТУВАЛО. Перелічуй ID поодинці або описуй словами — гейт, що стереже форму, оподатковує кожен текст ПРО цю форму.
⛔ Найдорожчий підвид — ТАБЛИЦІ, а не проза, і різниця в ЦІНІ, не в обсязі: протухла проза бреше читачеві, протухла таблиця дає йому хибний ХІД, бо таблиця найчастіше і є меню, з якого хтось обирає (тут це був реєстр вибірки — той самий, з якого зовнішній читач дізнається, що ми показуємо аудиторові). Тому свіп починають із таблиць заходів, опцій і «що ще відкрито», і лише потім грепають прозу.
Рефлекс при кожному [x]/✅ — три греби, жоден не по ID пункту: (1) значення, яке щойно перестало бути правдою («індексуються лише X», «компілятора немає», «периметр = shared/»), корпус-широко — інфра-факт осідає в 3-12 домах (00_06 §2); (2) маршрути, що обіцяють ВІДКРИТЕ («відкритий присуд», «вирішує ⚖️ у», «дім роботи») і вказують на ID, який ти щойно закрив; (3) прозу власного пункту — **Стан:** пишуть один раз, а ноги закривають окремо, тож голова систематично стверджує дихотомію, яку її ж свіжа нога вже спростувала. ⚠️ Пункти (1)-(2) — це НЕ deep_archival (той важкий і про retire); вони коштують три греби й обовʼязкові навіть коли пункт лишається живим.
⊕ ЧЕТВЕРТИЙ греб, і він єдиний, у якого НЕМАЄ хибного токена: дзеркало, що протухло не від ПРАВКИ, а від РОСТУ цілі (2026-08-28, три інстанси за один sync-прохід). Три вище шукають те, що ти щойно змінив; цей шукає те, чого не змінював НІХТО — канон копіює артефакт, артефакт росте, копія лишається правдивою про свою дату й хибною про сьогодні. Виміряні форми: (а) часткова копія схеми — 05_01 перелічував ProtocolFinancials двома лічильниками з семи, тобто без тих трьох, що несуть усю доказову поставу; (б) абзац, що пережив ВЛАСНЕ закриття в тому ж доці — 05_03 казав «префікс емітується, але не СПОЖИВАЄТЬСЯ», тоді як мапінг споживає його від дня DOC-T.89, і спростування лежало трьома секціями нижче в тому самому файлі; (в) код-блок канону, що цитує рядок, який щойно став One-Home-константою — форма NAME = value пін-двигуна тут не рятує, бо цитата не є присвоєнням (§Guard-craft #97). 🔑 Дискримінатор, бо грепати нема чого: питай не «що я змінив», а «що канон КОПІЮЄ, і чи оригінал з тих пір не виріс» — і найдешевший лік для (а) не оновити копію, а ЗНЯТИ її на користь вказівника: копія протухне знову, вказівник — ні. 🔴 Четверта форма, знайдена 2026-09-01 і найпідступніша, бо несе ВЛАСНЕ СВІДЧЕННЯ про свіжість: копія, позначена словом «дослівно». S6.1 цитував рядок 06_01 про ізоляцію Redis із міткою «дослівна копія» — і мітка була правдива в день написання. Далі INF.22 переписав оригінал («окремі БАЗИ» → «окремий інстанс/кластер на КОЖНОГО споживача», бо нумерованих баз в Upstash немає), копія лишилась, а мітка перетворилась на сертифікат точності, якого ніхто не видавав. Ефект інверсний до звичайного дрейфу: звичайна копія викликає підозру й її перевіряють, а «дослівна» читається як УЖЕ звірена — тобто маркер фідельності купує копії довіру рівно тоді, коли вона її втратила. 🔑 Рефлекс: дослівно · verbatim · копія рядка · цитата з у каноні — це не запевнення, а ЦІЛЬ для греба; і лік той самий, що для (а), лише терміновіший — знімай на вказівник, бо мітку доведеться перевіряти щоразу, а вказівник не доведеться жодного.
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 since 2026-07-25, DOC-T.48 — the last advisory to flip) · standard-conformance (incl. H1 — DOC-T.49, checked before the skeleton exemptions) · and the rest. The roster is 00_06 §3.1 plus the owner-only rows of §3.3 — never enumerated here: it has grown twice while this cell stood still. Every category is now HARD — a hit fails the build, so "advisory while you clean the drift" (the recipe below) 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 (it has grown twice). 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. | .github/workflows/docs.yml |
🔴 СВІП «блокер проти ВЛАСНОГО присуду» — дешевий і дає найтихіший клас: пункт, чия робота ратифіковано звільнена, а STAGE лишився
🔗(2026-08-19). Хибне блокування ніхто не перемірює, бо воно виглядає як обережність, і жоден гейт його не бачить:🔗формально валідний, тригер названий, реф резолвиться. Прогін по всіх🔗-пунктах трекера дав ДВА з 29 — в одному[x]-присуд каже «наша машинна робота, НЕ gated партнерами» при STAGE🔗, у другому сам residual пише «не gated передумовами». Рецепт: візьми кожен🔗-пункт і грепни його ТІЛО на форми звільнення (НЕ gated·наша машинна робота·РОЗБЛОКОВАНО·блокування знято/протухло); хіт разом із живим🤖-residual = кандидат. ⚠️ Далі ЧИТАЙ: половина пунктів має дві половини під одним блокером (доменний контент партнера ⊥ операційний рядок застосунку), і лік там — РОЗДІЛИТИ residual, а не зняти STAGE. ⊕ Дзеркало вже записаного вdeep_archivalФаза 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); спіймано перечитуванням до коміту, гейт цього не бачить за побудовою — обидві ноги лишились формально валідними. Звільняючи ногу, прочитай її текст цілком на інші «чекає · після · ⊂ · доки» і питай про КОЖЕН гейт окремо; звільнення — твердження про всі.
🔴 ЛІНЗИ ЗАПУСКАЮТЬ, а не переказують — і прогалина тут вимірюється РОСТЕРОМ, не памʼяттю (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: обчислюваний реєстр уже ВІДХИЛЕНОГО (196 рядків у 75 файлах), який агент «з холоду» перелічити не може, а одна промашка коштує сесії; читати ПЕРЕД вибором роботи. ⚠️ Кожна лінза оголошує СТЕЛЮ, і її треба брати разом із числом:--stops— «підлога, повний READ дає ×3.2»;spec_claim_audit— «шортліст, не вердикт» (перевірено: на найгострішому кандидаті мутація дала ВІСІМ червоних, тобто покриття вчетверо щільніше за гіпотезу лінзи);stan_auditвісь 1 дає хибний хіт на приватний метод, коли канон-дім несе публічний, і тригериться власним поясненням у тілі пункту — форму пиши словами, не токеном.
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 22
- Forks
- 1
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
ssot-maintenance- Source
- github.com/alexey-lukin/silken_net