docs(readme): badges + clear 'how to update' guide (RU+EN) - #19
Merged
Conversation
- Both READMEs: 7 badges (version, license, platforms, Claude Code plugin, sponsors, stars, last commit) replacing the previous 4 — the version badge shows the latest release so users can see when they are behind. - New 'Обновление' / 'Updating ru-text' section: a primary method (npx skills add talkstream/ru-text) plus per-platform update commands (Claude Code marketplace+plugin update, Gemini extensions update, OpenClaw, Codex, manual copy), and a note that the community-marketplace pin advances with up to a day's lag. - Dogfooded: NBSP after single-letter words and before em dashes, guillemets. Context: the plugin was covered on Habr; new users install the community version, so clear update guidance was missing.
talkstream
added a commit
that referenced
this pull request
Jul 28, 2026
The «Домены» table quoted seven per-domain rule counts. They sum to 1035 — the retired «~1 044 rules» figure, split up. v1.10.1 recounted them by hand and corrected four; one release later three were wrong again (57 comma traps against a stated 56, 59 button labels against a stated 58) and four of the seven appear nowhere in the corpus at all. The table now names the reference file for each section, so a reader who wants a number opens the file and counts. Two sections that had no row — the sixteen tells and the scoring rubric — now have one. Two more claims were measured and found false: SKILL.md holds 583 words, not the 587 advertised since v1.9.0, and `references/` holds ten files, not nine. The note about the community marketplace was false in the direction that costs users the release. Since #19 both READMEs have said the pin «advances automatically with up to a day's lag». Measured today: the pin is at v1.8.0, three releases behind. The nightly sweep opens at most thirty PRs per run against 2283 entries and walks them roughly alphabetically; ru-text sits at index 1653 and has not been bumped once in the last 300 commits to that manifest. It is not on the freeze list and it passes `claude plugins validate` — this is starvation, not rejection. Both READMEs now describe the mechanism and point at `npx skills add` or a source install for anyone who needs the current version. `.claude/CLAUDE.md` carried the same false claim as a convention; corrected there with the measurement, so the next release does not repeat it. check-version.sh gains a fourth section so the size claim cannot drift again. It compares numbers rather than the sentence, because Russian inflects the noun with the numeral and a literal-string check would go red on a correct line the day the count crossed a declension boundary. A review of that section found seven defects, all of them now closed and each proven by the mutation that used to survive: - it read the first «SKILL.md:» line and ignored a second, so two lines both wrong passed. §1 of the same file has lived by «exactly once» since v1.10.1; §4 did not inherit it. - README.en.md was in the argv but pinned by nothing: dropping it left the selftest green. Same for the line count — only the word count was asserted. Three selftest cases now bind each hand separately. - the thousands-separator normalisation was a provable no-op, because the digit regex never matched a separator to begin with. It read «1 083 слова» as the pair (1, 083) and failed a correct README. Verified on a 1 103-word file. - an empty measurement reported ok. A python3 stub exiting 0 in silence now fails closed. - the comment claimed parity with `wc -w` while using python's split(), which treats U+00A0 as whitespace where byte-wise wc does not — on a file carrying the non-breaking spaces R16/R44 require, the two disagree. - the diagnostic joined findings with «; » and split on the same, tearing a quoted README line in half mid-sentence. The new prose was read by the ru-text check itself, against the corpus files rather than a summary of them: eleven findings, all applied. One was a Critical — a missing non-breaking space before an em dash that I had just written into the file. Every em dash in the Russian README is now verified by codepoint. Selftest 70 → 75 cases. Red-test: tools/selftest.sh — «a stale SKILL.md word count in the RU README is caught» and its three siblings fail with «check-version PASSED on corrupted input» until §4 of check-version.sh exists and binds each hand separately.
talkstream
added a commit
that referenced
this pull request
Jul 30, 2026
…n fail (#29) * test(golden): 13 curated texts with expected findings — AD-1…AD-9 covered whole Until now nothing measured whether the checker finds what it claims. Tests were green while behaviour could break silently — the classic failure the director's golden-set rule exists to prevent. Thirteen cases across every domain: info-style, канцелярит, typography, UX copy, business letter, punctuation, numerals, and four neuroslop texts. AD-1, AD-3 and AD-4 had no text at all before this, so the loss of their carve-outs during any corpus edit would have gone unnoticed. Two controls matter more than the eleven cases: - **12-clean-control** must return zero findings. A false positive costs more than a miss: the user stops trusting the tool and turns it off. - **13-carveouts-control** is built entirely from constructions the rules EXPLICITLY exempt — a character's direct speech, «честно говоря» in conversational register, a genuine step-by-step walkthrough, informative «важно», «итак» as a real summative connective. It catches overreach rather than omission, and no automated test can see that class. Case 09 records a known gap deliberately: «Скажу честно» may NOT be found before the neuroslop rules land, because «честно говоря» is an AD-7 trigger that AD-7.5 then exempts for conversational register — and the assistant's own service register fell through that carve-out. This file is where the difference will show. Case 07 keeps deliberately borderline numeral forms: the set measures not only "does it find" but "does it invent". Runs are done by the model through /ru-text:ru-check and /ru-text:ru-score, with transcripts in the PR. There is no shell harness and there will not be one — simulating a deterministic run of an LLM check would measure the simulation. Red-test: n/a (test fixtures only, no production-code paths touched; selftest 45/45 and the no-loss gate green before and after) * test(tools): gates.sh — CI's sequence as one command, plus the case that catches drift The three gates were three commands a person had to remember, written down in a handoff note and in the CI workflow, and nowhere a machine would read. That is also what kept the pre-push hook from ever running them: with no package.json and no pyproject, this repository looked to that hook like a project with no tests at all. tools/gates.sh runs what .github/workflows/gates.yml runs, in the same order — checker syntax, selftest, the paid-MCP contract, the pinned baseline and the no-loss gate. The sha256 tool is detected rather than assumed: macOS ships shasum and no sha256sum, and the Linux runner is the other way round. So is the shell that checks syntax — /bin/sh is bash 3.2 here and dash on the runner, so a bashism passed locally and failed in CI until this used dash -n where dash exists. Two copies of one sequence drift, so the selftest now fails when they do. It compares the checker scripts each file actually invokes (comments stripped, so naming one in prose does not count), the shape of each invocation — a checker whose failure is swallowed by `|| true` is not being run — and the baseline pin, file and hash, with comments stripped on BOTH sides, because stripping only one let a commented-out pin block in CI compare equal. Both files now walk tools/ with find rather than the tools/*.sh glob. A checker one directory down was invisible to the syntax gate and to the parity case at once. Also fixed pre-existing: fresh_copy cloned only references/ and SKILL.md, leaving out skills/ru-text/agents/*.yaml whose eight atoms the baseline counts — no case had noticed, because none had run the no-loss gate against a copy. And the NFC check spliced $ROOT into python source, so a checkout under a directory named with an apostrophe executed whatever followed it; ROOT now arrives through argv, as it already did in the folding check beside it. Red-test: tools/selftest.sh — «gates.sh passes on an untouched copy» падает без tools/gates.sh (нет файла); «gates.sh invokes exactly the checkers CI invokes» — там же * test(golden): six cases for the 2026 rules, and two controls that were never controlling The set measured nothing about the seven neuroslop rules, because it predates them. Six cases carry them: declared sincerity and forced triples (14), hollowed mechanism and phantom attribution (15), a chat transcript published as an article (16), a text addressed to a search engine (17), additive pseudo-pairs (18), and — the one that matters most — a second carve-out control (19) built entirely from constructions the seven rules explicitly exempt: a character saying «скажу честно», a named and dated source, a three-item list the subject actually has, a pair whose poles carry different numbers, a transcript published as evidence for the author's own finding, an identifier repeated because a pronoun would be ambiguous. The two existing controls asserted zero findings and had never been run. Both failed on the first run — seven findings and six, and every one of them a real typographic defect in the fixture: neither text contained a single non-breaking space, though both claim to be written by the rules of the corpus. Fixed, and the count is now written into 12's expected.md together with the command that verifies it, because a NBSP and an ordinary space are indistinguishable by eye and that is exactly how the fixture rotted unnoticed. The new fixtures are typeset correctly for the same reason: the defect under test should be the only defect in the text. Red-test: n/a (набор — не автотест: прогон делает модель через /ru-text:ru-check, см. tools/golden/README.md; уликами идут транскрипты «до/после» в теле PR) * feat(rules): seven tells of machine-written Russian, measured against the golden set AD-10 declared sincerity · AD-11 mandatory tricolon · AD-12 hollowed mechanism · AD-13 phantom attribution · AD-14 chat transcript as the artifact · AD-15 search-engine addressee · AD-16 additive pseudo-pair. Two of them — AD-14 and AD-15 — are charged to the document rather than to a fragment, which is new to this addenda set and is why they are graded High: the defect is the shape of the piece, and no local edit removes it. The rules were not collected by introspection. Four evidence channels were read blind to each other — what readers name themselves, what detectors flag, what platforms have already written into their rules, and what the linguistic literature measures — and nine further candidates were rejected on the record. Two of those rejections matter more than any acceptance: even sentence rhythm and vocabulary poverty are what detectors systematically mistake for machine text, and they are also what dry regulatory prose and non-native Russian look like. A rule catching them would punish a genre and an accent. AD-7 gains the trigger forms a model actually reaches for («скажу честно», «если честно», «не буду врать»), and AD-7.5 is narrowed: the register carve-out now protects a speaker INSIDE the text — dialogue, quotation, a character — and not an author writing about their own text in a conversational tone. The assistant register is a monologue written to sound like speech, and it fell straight through the old wording. The boundary is stated once, at AD-10.4, and governs both rules. Measured on 19 golden texts, before and after. Three control texts returned zero findings both times: seven new ways to fire on honest writing, and none of them fired. The run also caught three defects in these rules that reading did not. · A document-level charge replaced ten ordinary findings with three, and the text came out looking cleaner than before the rule existed. · Density replaced the per-instance findings with one line about density, costing the writer the list of lines to fix. · AD-16 absorbed a pleonasm that lived in Grammar, and the text scored 1.1 HIGHER than before the rule against it existed. All three are now rules of their own. The last is AD-16.8, and its principle is general: a new rule must never make its target score better. atom-map.tsv gains its first nine rows. Eight are the scoring.md lines whose scope this change extends. The ninth is AD-7.5, and its rationale says in plain words that the meaning was changed on purpose — NORMALISED is simply the only disposition the format has for a line rewritten in place, and a row describing a change of meaning as a change of wording is the failure that file exists to prevent. Red-test: n/a (правила — данные, не поведение кода; golden-set намеренно не харнес, см. tools/golden/README.md. Улики — транскрипты «до/после» и покейсовое сравнение в теле PR; tools/gates.sh зелёный до и после) * docs: quote the corpus size as a machine-counted floor, in atoms «~1 044 rules» was a hand-maintained figure nobody could reproduce. It had drifted — the corpus is 2089 atoms now — and correcting it meant editing eleven files at once, which is the reason it drifted in the first place. It is replaced everywhere by «over 2,000 linguistic atoms» / «более 2 000 лингвистических атомов»: the unit this repository's own no-loss gate counts, reproducible with `tools/extract-atoms.sh skills/ru-text | wc -l`. Two things were chosen deliberately. The UNIT: «rules» would have been false at this number. Counting rule-bearing lines — numbered rules, AD sub-rules, table rows, list items — gives 1597, so «2,000 rules» is not a claim this corpus can support. An atom is what the gate tracks, it is defined in extract-atoms.sh, and the README says in the same breath what it consists of. The FLOOR: «over 2,000», not a figure. A floor survives the corpus growing, so adding a rule no longer obliges anyone to re-stamp eleven files — and the convention now says to raise it only when the count clears the next thousand, and to raise it everywhere in one commit. The per-file counts in scoring.md were checked against the corpus while here and are accurate: typography.md declares 96 rules and carries R1…R96 with no gaps. The change was proofread by the plugin's own check, which found four defects in it. Three were introduced by the edit itself: two em dashes with an ordinary space before them (R16/R44) and a paragraph pushed from one em dash to three (AD-1.1). One rewrite closes all three — the apposition moves into parentheses, which is exactly the replacement AD-1.2 prescribes for an aside. Also fixed pre-existing: three missing non-breaking spaces after single-letter words in notion/README.md (R30), and a digit separator there that was an ordinary space where R32 requires a non-breaking one. Left alone, on the record: list items in both READMEs carry no closing punctuation (editorial-grammar §F.4). That is a decision about a whole list, not about the lines this commit touched, and fixing one line would make the list less consistent, not more. Red-test: n/a (правка чисел и формулировок в документации; поведение кода не меняется, tools/gates.sh зелёный до и после) * feat(tools): check-version.sh, and the six Russian phrases the description had lost Three numbers a person was keeping in step by hand, and getting wrong. The v1.10.1 gate found both READMEs advertising the previous release, then found .claude/CLAUDE.md doing the same; three days ago the corpus-size figure turned out to have drifted across eleven files at once. A number repeated in N places has N chances to be wrong and one script to be right. The checker holds three unlike things. The version is an EQUALITY across ten points — seven JSON fields in six manifests, plus three lines of prose a release has to remember — and it does not care what the version is, only that everything agrees. The description length is a BUDGET, and the file says out loud that 250 is ours and not a platform limit: the spec allows 1024. The trigger phrases are a PRESENCE test, and they are why this file matters. **The description had no Russian in it at all.** On hosts with no instruction file — the Claude apps, ChatGPT — that string is the entire trigger, so a user typing «вычитай» or «проверь текст» got nothing, and every gate stayed green while they did. It now leads with the six phrases people actually type, inside the first 100 characters so a truncating picker still shows them, and keeps «Also any Russian output», which carries the always-on semantics and is the easiest clause to lose in a rewrite. 210 characters against the 250 budget. The three atom-map rows record it as one deliberate change, not three. Six selftest cases prove the checker can fail, each for its stated reason: one manifest out of step, a version line missing from the RU README, a lost trigger phrase, phrases pushed past the head where a truncating picker stops showing them, and a description over budget. Two defects in the checker itself, both found by running it rather than reading it. Under `LC_ALL=C` — which the file sets, for the same reason every tool here does — `wc -m` counts BYTES, so a 210-character description measured 255 and failed its own budget. And the RU version line is written with a non-breaking space before the em dash, because this repository obeys its own R16/R44, so a pattern with an ordinary space reported the line as missing. Also fixed pre-existing: fresh_copy did not clone the manifests or the READMEs, so the new checker failed inside every gates.sh case for a reason those cases are not about. Red-test: tools/selftest.sh — все шесть случаев секции «selftest: check-version.sh» падают без tools/check-version.sh (нет файла); «a lost trigger phrase is caught» падал и на старом описании, в котором русских фраз не было вовсе * refactor(rules): stop claiming «written once» while writing it twice A `/simplify` pass over the finished module, behaviour-preserving, re-verified against nine golden cases. The largest finding was not redundancy but a false claim about redundancy. **«The same boundary is written once, at AD-10.4»** — while AD-7.5 restated that boundary in full, four-item list and identical example included. The fix is the claim, not the duplication: the year-long miss of «скажу честно» happened precisely because the boundary was NOT operational at AD-7's own site, and a rule read on its own has to decide on its own. AD-10.4 is now named the canonical statement, and AD-7.5 keeps its working copy, said out loud rather than denied. Three retellings of one motive folded into a reference. AD-11.3 carried the same metaphor as the governing section in a different suit — «a loss of coverage dressed as a summary» beside «wearing the clothes of a summary» — and AD-15.6 retold one incident with the same numbers the section already gives. Each keeps its local imperative, because an anchor jump lands inside a rule and not above it; only the second telling of the reasoning is gone. Five run dates left the normative text. `**Acknowledged:**` is where this corpus keeps provenance, AD-1…AD-9 keep theirs there, and a date is not an input to any trigger — it is read by a model that has to decide about a text, and it will read as debris in a year. The three dates that pin a paraphrased external document stay: without them a claim about someone else's rules is unverifiable. Also: the section titled «Two rules» had three bolded rules, the third being a qualifier of the first; the table of contents listed two sections after AD-16 that stand before AD-1; and two carve-outs restated their rule's own test rather than pointing at it. **Measured consequence, stated rather than buried.** Case 17 rose from 5.4 to 6.7 — and from 5.5 before these rules existed. The cause is a correction: AD-15.6 used to charge the repeated noun phrase as tautology in Grammar, and `editorial-grammar.md` §E defines tautology as ADJACENT cognates, so that charge was never one the corpus carried. Removing it returned Grammar to 9.5, which is what an impeccably grammatical SEO stub deserves by the rubric as written. The defect itself is charged, once, by AD-15 in Reader precision — where the score is already 3.0 and has nowhere further to fall. That is the arithmetic hole the Fable judge predicted, now with a live number against it. Not tuned here: moving a score by editing a rule until the number looks right is the failure the five orthogonal dimensions exist to prevent. It goes to the director as a decision, with the measurement attached. Re-verified: nine cases re-run against the edited corpus. Both carve-out controls stayed at zero findings. No rule-level finding was lost; the two fragments that moved are info-style judgement calls on cases whose scores did not change. Red-test: n/a (поведение-сохраняющий проход по формулировкам; корпус — данные, tools/gates.sh зелёный до и после, re-verify девяти случаев в теле сообщения) * feat(scoring): a floor under the label, because the arithmetic can be right and the word false A document charged with AD-14 or AD-15 is never labelled «Эталонный» or «Хороший», whatever the weighted sum returns. The number is reported as computed; only the word a reader carries away is constrained, with one line naming the rule that constrained it. This is not the non-compensatory cap that was deliberately declined, and the distinction is the point. A cap keyed to a soft dimension would put a hard ceiling on a score behind a judgement call a reader could dispute. A label floor overrides nothing in the five dimensions; it refuses to summarise a document as good when the whole genre is the defect. Measured, not supposed. A search-engine stub — grammatical, typographically clean, useless — scored 6.7 on Typography 9.5 and Grammar 9.5: the two hard dimensions carry 0.35 of the weight, and the entire harm sits in Reader precision, already at 3.0 with nowhere left to fall. A flawless chat transcript is the same shape and worse: with nothing wrong in any sentence it reaches 9.2 — «Эталонный» — for a genre platforms remove on sight. No rule about words can lower either one, and that was worth establishing before reaching for this. Driving Clarity on the stub from 7.0 all the way to 3.0 moves the total from 6.7 to 5.7: still «Средний», the label unchanged. On the transcript it does nothing at all, because a well-written transcript has no defect in its words. The hole is in the summary, so the repair belongs in the summary. Red-test: n/a (правило рубрики — данные, не поведение кода; tools/gates.sh зелёный до и после, арифметика обоих сценариев посчитана в теле сообщения) * docs: open the v3.0 formative direction, and cross-reference §H.2 instead of gutting it Two things the plan asked for, one of them measured before it was believed. **The v3.0 backlog.** Everything ru-text does today is a refusal — stop-words, канцелярит, anti-patterns, sixteen tells of machine prose — and it is good at it. What a living Russian sentence *does* is the other half, and it is not in the corpus. `docs/roadmap-v3-formative.md` opens that direction and, more usefully, records why it cannot be a patch to v2.0: a refusal is cheap to check and cheap to be wrong about, while a formative rule has no list to match, depends on what the sentence is doing, and tells a competent writer their good sentence is wrong when it misfires. The scoring model does not fit it either — five dimensions built to subtract have nowhere to put a well-chosen verb, and adding points for virtue invites exactly the optimisation those dimensions exist to prevent. **§H.2 keeps its thirty-six rules.** The plan said to deduplicate it into a pointer at the §B catalogue. Measured with the same parser check-frozen.sh uses: 42 entries here, 92 there, and exactly **6** in both. The step was written on the assumption that this section mostly repeats the catalogue. It does not, and following it literally would have deleted thirty-six rules that live nowhere else — which is precisely the silent loss the no-loss gate was built to catch, arriving through the front door as a planned refactor. So the six get what the corpus already does for overlapping rules: a cross-reference naming them, §B named as their canonical home, and one charge per fragment. Nothing is deleted. Red-test: n/a (документация и перекрёстная ссылка; поведение кода не меняется, tools/gates.sh зелёный до и после) * feat(tools): check-dogfood.sh — the numbers the product states about itself must be true The catalogue size lives in seven files. The last time it moved, four of them went stale and nobody noticed until a release gate looked. This checker measures the size and the category count from `info-style.md` with the same parser check-frozen.sh uses, and compares them with every place that states them. The first version scanned for claims with patterns like «(\d+) записей» and reported twenty-two false ones on its first run: `anti-patterns.md` counts its own sections in the same words. Deciding which number in a sentence is a claim about the catalogue is not a problem a shell script solves, and a checker that cries wolf is one people disable. So the consumer list is EXPLICIT, and a second check makes the list self-maintaining: the current value must not appear anywhere outside it. Move the catalogue to 93 and a stale «92» is still a «92» — the guard names the file and the list gets a row. A fixed list alone has exactly the failure mode that put four consumers out of date; a fixed list with a completeness guard does not. Two false-positive classes are excluded by hand, each for a stated reason. CHANGELOG.md and `.github/` record what the numbers WERE and must keep saying 97 where 97 was once wrong. And a letter before the digits means an identifier rather than a count — typography.md carries rule R92, and a guard that reads it as a stale claim is the crying wolf again. Three defects in the checker, all found by running it. `case "$f" in *.md|*.json) ;; esac` inside a command substitution does not parse under bash 3.2 — which is /bin/sh on macOS — and `sh -n` does not catch it; the error surfaces only when the line runs. `printf "$tmpl"` reads a template beginning with «- » as an option, and two claims are markdown list items. And `grep -qF "$want"` does the same with the same two. Also fixed pre-existing: fresh_copy produced a directory rather than a repository and left out notion/, so every gates.sh case failed inside the new checker for a reason none of them is about. Red-test: tools/selftest.sh — четыре случая секции «selftest: check-dogfood.sh» падают без tools/check-dogfood.sh (нет файла); «a consumer left behind is caught» падает и на предыдущей версии чекера, где списка потребителей не было * feat(rules): §I government, §J gerund phrases, §K homophones — the grammar the corpus lacked A coverage sweep asked where the corpus is thin and answered somewhere unexpected: not in the formative half, but in basic literacy. Government had **no rules at all** — §D covers agreement and nothing covered which case a preposition takes. Neither did a gerund phrase whose doer is not the sentence's, nor the homophone pairs a spellchecker cannot decide. The cost is not what it looks like, and the arbiter was right to reframe it. ru-text is executed by a language model, and a model flags «согласно приказа» with or without a rule. What was missing is the SUPPORT for the verdict: a finding with no rule ID, no golden anchor, no reproducible ground in the one dimension that calls itself objective. Narrow on purpose. Seven families passed the sweep; three ship. §I is a **closed list**, because the open form — checking every case after every preposition — is a detector of non-native Russian, and building one is forbidden here: it would punish an accent rather than an error. Participial commas, declension and aspect went to `docs/roadmap-v3-grammar.md` with the reason each was deferred; the wandering pronoun was rejected outright, because the channels split on it and that split is itself the evidence that the trigger is a judgement. The gate found fifteen defects in this package, and the five worst were in the norms themselves — the failure that would have had the tool confidently breaking correct text: · «Скучать по вам» was listed as the error and «по вас» as the fix. It is the other way round — and the pair is variable, so it does not belong in a closed list at all. Gone, with §I.1.3 now saying why a variable pair can never be here. · «Превосходство перед» is dated-but-attested, not wrong. Gone. · J.1.1 tested «the grammatical subject of the main clause». Rozental's criterion is the PRODUCER OF THE ACTION, and a one-member definite-personal sentence has no grammatical subject at all — so «Открыв файл, проверяем кодировку» was being called wrong. · «В течении» was said to be only a river. It is also the course of an illness, of time, and a movement in art or politics. · «В виду» was said to exist only inside «иметь в виду». It also means within sight — «эскадра шла в виду берега», where the "fix" would read as «because of the shore». Also added from the same gate: carve-outs for gerunds that became adverbs («молча», «не спеша»), for the inclusive «давайте» and the definite-personal, for a gerund sharing its doer with an infinitive, and — the one carried from AD-10.4 — for a quotation, where the error belongs to the speaker and charging the author for someone else's grammar is worse than missing it. Measured across three golden cases. §I: 8 of 8. §J and §K: all targets. The carve-out control returned **zero** twice — first on the constructions the rules illustrate, then on a harder text built from the four false positives the gate had found, none of which the first version of that control could catch. It failed once in between, and correctly: the carve-out examples were written with «следует», «нужно» and «можно», which are catalogued stop-words. A control that tests one rule has to be clean under all the others, or zero is unreachable and the criterion means nothing — the same lesson the non-breaking spaces taught in cases 12 and 13. Red-test: n/a (правила — данные, не поведение кода; golden-set намеренно не харнес. Улики — три прогона в теле сообщения: контроль карв-аутов 0 → 2 → 0, где двойка была настоящим дефектом фикстуры) * feat(tools): build-release.sh — two assets, built from tracked files and proven by unpacking Hosts disagree about what a skill is, so a release ships two archives of the same corpus: `ru-text-skills.zip` with ru-text/, ru-check/ and ru-score/ at the top, for hosts that install a directory of skills; `ru-text-skill.zip` with one folder, for hosts that take exactly one and would treat the other two as strays. Neither carries the tools, the golden set or the manifests — nobody installing a skill needs the machinery that verifies it. Three rules the script exists to enforce. It reads `git ls-files`, never the working tree, so an asset cannot ship a scratch file that is invisible once zipped. It refuses to build from a dirty checkout, because an artefact whose contents match no commit makes the version inside it a claim about code that does not exist. And it proves itself by unpacking: every build extracts into a clean directory and diffs the result against the source before the archive is allowed to exist, because a zip that lists the right names can still unpack wrong. `--check` builds, verifies and deletes. That mode runs in gates.sh and in CI, where it catches the failure with no symptom — a renamed or dropped reference file leaves the skill installing, activating, and answering from whatever corpus it still has. Two defects, both found by the selftest rather than by reading. The reference-completeness check compared `git ls-files` with a tree copied from `git ls-files`, so removing a file from the index moved both numbers together and the equality stayed true — a tautology wearing the clothes of a check. It now also asserts the floor the paid-MCP contract fixes at ten. And the case that was supposed to prove a dirty tree is refused had been running in `--check` mode all along, because `${4:---check}` substitutes its default for an empty fourth argument as well as a missing one; the mode is named now, so the mistake cannot repeat silently. Red-test: tools/selftest.sh — четыре случая секции «selftest: build-release.sh» падают без tools/build-release.sh (нет файла); «a reference file missing from the asset is caught» и «a dirty tree refuses a real build» падали и на первой версии скрипта — по тавтологичной проверке и по подстановке умолчания * test(golden): the v2.0 run — four controls out of four at zero All 22 texts, blind to the expected findings, against the corpus as it will ship. The table is in tools/golden/README.md; the transcripts are outside the repository. The number that matters: **every carve-out control returned zero**. Sixteen tells of machine prose and three grammar sections, and none of them fired on an honest fragment. Three of the four had to be repaired first, and every time the text was at fault rather than the rules. Cases 12 and 13 asserted zero findings while containing no non-breaking space at all. Case 22 wrote its carve-out examples with «следует», «нужно» and «можно», which are catalogued stop-words. And this run found the last one: «Переписка приведена целиком» in case 19 is passive voice with the agent named in the previous sentence — a real anti-patterns finding, in the control text, not in the carve-outs it was testing. The lesson is now written into the set's README, because it will recur: a text that tests one rule has to be clean under all the others, or zero is unreachable and «the control is at zero» means nothing. Red-test: n/a (фикстура и запись измерения; поведение кода не меняется, tools/gates.sh зелёный до и после. Улика — перепрогон случая 19: 1 находка → 0 после снятия пассива) * docs+test: the README stops advertising numbers nobody can reproduce The «Домены» table quoted seven per-domain rule counts. They sum to 1035 — the retired «~1 044 rules» figure, split up. v1.10.1 recounted them by hand and corrected four; one release later three were wrong again (57 comma traps against a stated 56, 59 button labels against a stated 58) and four of the seven appear nowhere in the corpus at all. The table now names the reference file for each section, so a reader who wants a number opens the file and counts. Two sections that had no row — the sixteen tells and the scoring rubric — now have one. Two more claims were measured and found false: SKILL.md holds 583 words, not the 587 advertised since v1.9.0, and `references/` holds ten files, not nine. The note about the community marketplace was false in the direction that costs users the release. Since #19 both READMEs have said the pin «advances automatically with up to a day's lag». Measured today: the pin is at v1.8.0, three releases behind. The nightly sweep opens at most thirty PRs per run against 2283 entries and walks them roughly alphabetically; ru-text sits at index 1653 and has not been bumped once in the last 300 commits to that manifest. It is not on the freeze list and it passes `claude plugins validate` — this is starvation, not rejection. Both READMEs now describe the mechanism and point at `npx skills add` or a source install for anyone who needs the current version. `.claude/CLAUDE.md` carried the same false claim as a convention; corrected there with the measurement, so the next release does not repeat it. check-version.sh gains a fourth section so the size claim cannot drift again. It compares numbers rather than the sentence, because Russian inflects the noun with the numeral and a literal-string check would go red on a correct line the day the count crossed a declension boundary. A review of that section found seven defects, all of them now closed and each proven by the mutation that used to survive: - it read the first «SKILL.md:» line and ignored a second, so two lines both wrong passed. §1 of the same file has lived by «exactly once» since v1.10.1; §4 did not inherit it. - README.en.md was in the argv but pinned by nothing: dropping it left the selftest green. Same for the line count — only the word count was asserted. Three selftest cases now bind each hand separately. - the thousands-separator normalisation was a provable no-op, because the digit regex never matched a separator to begin with. It read «1 083 слова» as the pair (1, 083) and failed a correct README. Verified on a 1 103-word file. - an empty measurement reported ok. A python3 stub exiting 0 in silence now fails closed. - the comment claimed parity with `wc -w` while using python's split(), which treats U+00A0 as whitespace where byte-wise wc does not — on a file carrying the non-breaking spaces R16/R44 require, the two disagree. - the diagnostic joined findings with «; » and split on the same, tearing a quoted README line in half mid-sentence. The new prose was read by the ru-text check itself, against the corpus files rather than a summary of them: eleven findings, all applied. One was a Critical — a missing non-breaking space before an em dash that I had just written into the file. Every em dash in the Russian README is now verified by codepoint. Selftest 70 → 75 cases. Red-test: tools/selftest.sh — «a stale SKILL.md word count in the RU README is caught» and its three siblings fail with «check-version PASSED on corrupted input» until §4 of check-version.sh exists and binds each hand separately. * docs: every install channel, checked against its vendor rather than against memory All 81 install-and-update claims in both READMEs were run against the vendors' live documentation and the live state of each registry. 31 were wrong. The instructions had been written once and never re-checked; the platforms moved underneath them. - **Claude Desktop never took the CLI's commands.** `/plugin` is terminal-only; in the app the path is the + button → Plugins → Add plugin. And «one install works in CLI, Desktop, VS Code, JetBrains and Web» was false on Web — a user-scope install does not reach a cloud session, which needs `enabledPlugins` in the repository's `.claude/settings.json`. WSL sessions have no plugins at all. - **Codex needs a marketplace configured before `/plugins` shows anything**, and a new session before the bundled skills load. Neither step was in the README. - **ru-text is not in the Cursor marketplace** the README told users to search. The catalogue lists 216 plugins and ru-text is not among them; `/marketplace/ru-text` is a 404. The manual copy, previously the fallback, is now the instruction. - **Both Antigravity paths moved.** Global is `~/.gemini/config/skills/`, read by all three Antigravity products; per-project is `.agents/skills/` — plural — with the old singular still accepted for compatibility. - **OpenClaw refs are owner-qualified**, `@talkstream/ru-text`, as ClawHub's own page for this skill instructs. - **`npx skills add` does less than the README implied.** It installs three skills, not one. Without `-y` it opens an interactive picker, so pasted into a script it installs nothing. It writes `.windsurf/skills`, `.junie/skills` and `.continue/skills` only when those directories already exist, so on a fresh project it leaves those three platforms unserved — their sections now lead with the manual copy. It is project-scoped, so a `-g` install has to be updated with `-g` or the update reports success over a stale copy. `.codex-plugin/plugin.json` had `logo` at the top level, which the Codex manifest schema does not define; it belongs inside `interface`. Moved. The Notion template inventory was missing the AI-text-tells section it grew in June, and quoted a word count that had drifted from 1 454 to 1 865. The section is now listed and the count is gone rather than re-stamped — the same reasoning that removed the domain table's per-domain figures. Two entries in the convention file were wrong in ways that would have cost the release: - it claimed the corpus floor is stated «in eleven files». Nine files state it, and `.codex-plugin/plugin.json` on main was still advertising «~1,044 rules» while the sentence claimed the sweep was complete. The hand-maintained count is replaced by the grep that reproduces it — the same defect the sentence itself warns about. - it claimed `clawhub skill publish` REQUIRES `--version` and fails without it. On clawhub 0.23.1 the guard fires only when the flag is present and malformed; omitted, it defaults to the registry's next patch. A dry run without it printed «Would publish ru-text@1.10.2» and exited 0, so publishing 2.0.0 without `--version 2.0.0` would have silently shipped a patch. Codex self-serve publishing, recorded as unavailable, now exists: the portal explicitly accepts a skills-only plugin, which is what this is. Noted for a directorial decision, not acted on. The new Russian prose was read by the ru-text check itself, against the corpus files rather than a summary: nineteen findings, all applied. Five were Critical typography — three literal tildes that leaked in from my own NBSP placeholder and two missing non-breaking spaces after a single-letter preposition. Both READMEs are now verified by codepoint: zero stray tildes, zero em dashes preceded by an ordinary space. Red-test: n/a (documentation and one manifest field; no behaviour path in the diff — the pre-patch selftest is green against the post-patch tree, 75 passed / 0 failed, and gates.sh passes end to end). * docs+test: hand the install to the agent, and gate the outcome instead of the prose The «Быстрый старт» section was thirteen platform-by-platform recipes — 195 of the README's 411 lines, and the half that had just been found 31 claims wrong. It is now one sentence to hand to an AI agent, because the agent knows where its own platform keeps skills better than an instruction written a year ago does. The call was tested rather than argued. Three fresh agents, sandboxed, denied the local checkout, each role-framed as a different platform's agent and given nothing but that sentence: two installed correctly, and one — Windsurf — found a global path this README never documented and refused a flag it could not verify. The third put Codex's copy in `~/.codex/skills` on the strength of a December-2025 blog post, while OpenAI's current documentation says user skills live in `$HOME/.agents/skills`. All three read this repository as their first source. That is why the per-platform material moved to INSTALL.md instead of being deleted: the prose's audience has changed from humans to agents, and an agent that finds nothing here takes its answer from a stale blog. INSTALL.md is organised around what the audit turned up rather than by platform: `~/.agents/skills/` is read by Codex, Cursor, Windsurf AND GitHub Copilot, so it is one shared path plus exceptions. It also keeps the four things the one-liner cannot carry — the Claude Desktop and Notion click-paths no agent can drive; the negative facts trial cannot discover; the per-platform directories; and the update story a one-shot install does not have. The gate moved with it. Reading instructions against vendor documentation gates the prose, not the outcome, costs 57 agents a pass, and — measured this session — has a half-life of about one release: Windsurf's docs are now on the Devin domain, Codex's on learn.chatgpt.com, and both Antigravity paths moved. `tools/probe-install.sh` gates the outcome instead: it builds a sandbox, prints the prompt, and afterwards judges the disk against `tools/install-paths.tsv`, which carries each path with the vendor URL and the date it was read. Four assertions, and the second is the one that earns its keep — a copy landing anywhere the platform does NOT read. An agent usually writes several copies, so a probe that only looked for a hit would have called the `~/.codex/skills` failure a pass. It does not run the agent: a shell cannot start another vendor's agent, and one that pretended to would be a gate testing itself. Both READMEs are now about half their former length, and every path they used to state lives in one machine-readable file instead of in twenty-six prose sentences across two languages. Selftest 75 → 81. Red-test: tools/selftest.sh — the five probe-install cases fail with «probe said PASS, wanted FAIL» (empty sandbox, undocumented path, stale bytes, truncated corpus) and «probe said FAIL, wanted PASS» (correct install) until probe-install.sh implements each assertion; verified by building each sandbox shape by hand before the script existed. * fix(tools): the probe was wrong about symlinks, and a clone is not an install Both defects came out of the first live run, which is the argument for running a gate for real rather than reasoning about it. **A symlinked install is the vendor's documented shape, not a suspicious one.** The script said, in a comment, that «a symlinked skill is a different thing from an installed one and must not read as a pass». OpenAI's page says the opposite in as many words: «Codex supports symlinked skill folders and follows the symlink target when scanning these locations» (learn.chatgpt.com/docs/build-skills.md). The probe agent linked deliberately, so that a pull on its clone updates the install — a better install than a copy, and the gate would have failed it. `find` now follows symlinks. **A clone is an intermediate, not a rogue install.** With symlinks followed, the source tree the agent cloned was reported as four copies landing where Codex does not look. A SKILL.md inside a git working tree is now excluded, by walking up to a `.git` and stopping at the sandbox root so a `.git` above the sandbox cannot excuse everything below it. **And the stray check compared directory names where it had to compare physical paths.** An agent that links `~/.agents/skills/ru-text` at a copy under `~/src` has ONE install reachable two ways; the name comparison called the target a second copy. Both sides now resolve through `pwd -P` before comparing, which collapses them into the one install they are. The selftest case that caught this used a non-git source directory on purpose — the live run's clone had a `.git` and so was excused by the previous fix, hiding the deeper defect underneath it. The byte-mismatch line now names the commit the agent actually fetched. Its commonest cause is not a fork but probing before the work reaches the default branch, and a diagnostic that does not say so sends the reader looking for a supply-chain problem. Two selftest cases, one per defect: a symlinked install must pass, and a source clone must not be reported. Selftest 81 → 83. Red-test: tools/selftest.sh — «a symlinked install at the documented path passes» fails with «probe said FAIL, wanted PASS» against the previous `find -type f`, and «the source clone is not reported as a rogue install» fails the same way once symlinks are followed but clones are not excluded. Both reproduced against the live sandbox before the fix. * fix(tools): the probe's clone exclusion could be switched off with mkdir A background security review reproduced it in one command. The exclusion that stops the source clone being reported as a rogue install accepted ANY git working tree above the file: mkdir ~/.codex/skills/../.git and an install at the stale-blog path — the exact failure this probe exists to catch — was excused, and the run printed PASS. A gate a directory disarms is worse than no gate, because it reports success. The second attempt was still wrong, and wrong without any decoy. It required the tree to hold `skills/ru-text/SKILL.md`, which `~/.codex/skills/ru-text` has by construction: every platform whose skills directory is literally named `skills` would have excused itself. A clone is now a `.git` WITH `.claude-plugin/plugin.json` beside it — the plugin manifest, which lives at this repository's root and has no reason to exist inside an installed skill. Everything under such a root is source, `tools/testdata/` included; an earlier `skills/`-only restriction reported this repository's own test fixture as a rogue install. Cloning into a stale path needs no special case: the repository has no root SKILL.md, so such a clone produces nothing loadable and check 1 fails for the plain reason. Three cases added, each pinning one of the three wrong answers: the decoy `.git` must not excuse anything, a fixture outside `skills/` must not make a genuine clone look rogue, and the clone fixture now carries the manifest that makes it a clone. Selftest 83 → 85. Red-test: tools/selftest.sh — «a decoy .git does not excuse an install at an undocumented path» reports «probe said PASS, wanted FAIL» against both earlier rules, reproduced by hand in the sandbox before the fix. * docs: Codex and ChatGPT share a plugin system, and we documented half of it The director asked whether the current Codex had been checked or an old picture copied. An old picture had been copied. Verified today against the live 0.144.0 binary and the current docs, which moved onto a ChatGPT host — developers.openai.com/codex/* now 308-redirects to learn.chatgpt.com, a signal that was in front of me twice and not followed through. - **Plugins are not Codex-only.** «Plugins are available with ChatGPT Work on the web and with ChatGPT Work or Codex in the ChatGPT desktop app. Codex CLI also has a plugin browser» (learn.chatgpt.com/docs/plugins). ChatGPT Work users install from the Work switcher → Plugins, an audience these docs never addressed. Both INSTALL files now name it, and the section is «Codex и ChatGPT» rather than «Codex CLI». - **There is a non-interactive install we never documented**: `codex plugin add <PLUGIN>@<MARKETPLACE>`, from `codex plugin add --help` on the live binary. The docs told users to open a browser and search, which cannot be scripted or copy-pasted. - **Codex ships `claude-plugins-official` as a default marketplace**, alongside openai-primary-runtime, openai-bundled and openai-curated — `codex plugin marketplace list` on a stock install. ru-text is not in it: we are in `claude-plugins-community`. So promotion to Anthropic's official tier would reach Codex users with no setup at all, which raises the value of that ask above the one channel it was filed under. - **The version note was stale by twenty-seven minors**: «pre-1.0 (v0.118.0)» against 0.144.0 installed and 0.145.0 on npm. Replaced with the measurement and the instruction to re-check rather than trust the line. Also removed the last hand-maintained corpus number to survive this release: «Плагин подгружает 217 UX-правил» / «loads 217 UX rules», in the use-case section, missed when the same class of figure was cleared out of the domain table. A sweep of both READMEs and both INSTALL files finds no other; what remains is publication years and external sources' own counts. The Cursor catalogue size lost its number too — «216 плагинов» is a third-party figure that drifts weekly, and the claim that matters is that ru-text is not in it. Red-test: n/a (documentation and one convention file; no behaviour path in the diff — the selftest is green before and after at 85 passed / 0 failed, and gates.sh passes end to end). * docs: fix three promises the shortened README could not keep An independent review read the cut-down README as a first-time user rather than as its author, and found three places where shortening had left a claim the product does not honour. - **The front door told the reader to do something that fails.** «Начните писать на русском — плагин подключится сам» sat directly under the install prompt, but skills load at session start: Codex says so in as many words («start a new session before using its bundled skills»), and the skill-reading platforms behave the same. The reader's very next action was the one action guaranteed not to work. Both READMEs now say to start a new session. - **Notion was listed among the platforms the one-line prompt covers.** It is not: Notion installs by copying a template page and clicking through Use with AI, on a Business or Enterprise plan, and there is no agent to hand a sentence to. Moved out of that list and pointed at INSTALL. - **«более 2 000 атомов … по 10 справочным файлам» against a table listing nine.** Both true — the tenth is `sources.md`, which is attribution rather than a rule section — but a reader who counts the table catches a contradiction. Now «в девяти справочниках и файле источников». The neuroslop scenario went from nine bullets to five. The review's diagnosis matches what the director smelled: bullets carrying a quotable specimen («Отличный вопрос!», «скажу честно») read as a scenario, and the three that carry only a term read as an index of rules. The five with specimens stay; the rest fold into the sentence after them, which already existed. «Обновление» loses the paragraph explaining the marketplace pin, which INSTALL.md states in full — the README keeps the fact and the link. Two Codex facts the same review turned up, both from the current docs: - a skill copied into `~/.agents/skills/` is read by THREE surfaces — the CLI, the ChatGPT desktop app in Codex mode, and the IDE extension. Plugins are not available in the IDE extension but standalone skills are, so the file copy reaches further than the plugin path. Stated in both INSTALL files, because it is the strongest argument for the shared directory. - `codex plugin marketplace upgrade` exists and was missing from the update block. The skills-CLI update line now repeats that it installs three skills: a reader arriving at «Обновление» through the README anchor skips the section where that was said. Red-test: n/a (documentation only; no behaviour path in the diff — selftest 85 passed / 0 failed before and after, gates.sh green, and every relative link and heading anchor across the four files resolves). * test(tools): check-typography — the claim about our own dashes, enforced README.md says, in its own words, that «каждое тире, кавычка и пробел в этом документе соответствуют правилам самого плагина». Nothing enforced it. It was checked by remembering to ask a model, and in one afternoon it failed twice: a literal `~` reached the file from a placeholder for a non-breaking space, and a missing NBSP before an em dash shipped inside prose written to explain non-breaking spaces. This checks the mechanical subset that needs no judgement — R16/R44, R30, R1/R2, the ellipsis, and a stray literal `~`, which is not a corpus rule but is the defect that actually shipped. Both are reproduced as fixtures and both are caught. Scope is an explicit two-file list, and the alternative was measured before being rejected: the same patterns over the corpus files and the Notion template report 53 «violations» that are all correct content — the wrong-hand column of a «плохо → хорошо» table, and stop-word entries like «в настоящее время» that are dictionary keys rather than sentences. In a file that teaches typography by showing it broken, breakage is the point. Every exclusion is named in the header with its reason. Inline code and link targets are blanked before matching, keeping offsets: `~/.agents/skills` is a home directory, not a mangled space. Also fixed, pre-existing: the selftest's `fresh_copy` did not carry INSTALL.md or INSTALL.en.md, so the new checker failed inside every gates.sh case for a reason no case was about. That list grows whenever a checker learns to read a new file, and the comment above it already said so. Red-test: tools/check-typography.sh — against a copy of README.md with the two defects reinstated (a `~` before an em dash at line 41, a plain space after «в» at line 75) it exits 1 and names both by rule and line; against the tree it exits 0. * fix(tools): check-typography was green over eight real defects The checker committed one commit ago as the systemic answer to «did you remember to run the check» did not run the check it claimed to. A model reading the same two files found eight R30 violations it had passed, and named the reason: both halves of the pattern were narrower than the rule. - `PREP` held lowercase letters only, so «В» and «У» — where a Russian sentence most often starts one — were never tested at all. Six of the eight. - The follower class demanded a Cyrillic letter or a digit next, so «в [README]», «и **`.agents/skills/`**» and «и /ru-score» escaped. A preposition is no less stranded for being followed by a bracket, an asterisk or a slash. Both widened; the eight defects fixed in README.md and INSTALL.md. Four selftest cases, and the shape of two of them is the point. The first pair written failed the requirement they exist for: «В WSL-сессиях» and «В [README]» each combine a capital preposition WITH a non-Cyrillic follower, so either mutation killed both and neither hand was guarded — the same fixture-to-the-scenario defect that produced the gap in the first place. Reshaped to isolate one half each, and verified by mutation: restoring the lowercase-only set now breaks exactly one case, restoring the narrow follower class exactly the other. Also fixed, found by the same review: README.md said «Плагин ловит 16 примет машинного текста. Девять видны прямо во фрагменте» above a list of five. The list was cut from nine to five in 6072e51 and only the second number was updated. And two numerals moved to words per §G.1 — «ещё семь платформ», «на семь тематических блоков». Selftest 85 → 90. Red-test: tools/selftest.sh — «a capital single-letter preposition is caught» and «a preposition before a non-letter is caught» both report «check-typography PASSED on corrupted input» against the narrower pattern; each survives the mutation aimed at the other half. * docs: rewrite both READMEs around the reader, and make one promise real Written from the ground up after a four-lens panel — a technology-adoption psychologist, a UX writer, a Russian editor in the information-style tradition and a DX technical writer — read the old page, and a fact-check found seven false claims in it. 206 lines → 128 1813 words → 1061 671 words before the reader's first possible action → 53 5 tables → 0 7 badges → 3 15 sections → 11 What the panel said, and what it changed: - **«Благодарности» stood before the page said what the tool does** — 70 words, naming nobody (verified: no personal name appears in that block), ending in «пожалуйста, купите их книги». A debt with no address. Moved down to «Источники и благодарности», where the names are, and the imperative is gone. - **The best thing the product has — one sentence that delegates the whole install to the agent — sat under two-thirds of a page.** It is now the first thing after the promise. - **There was no example.** In 206 lines the page never showed what the tool does to a sentence. «Как это выглядит» is a before/after pair taken from the golden set, with the three changes named. - **«Границы»**, the psychologist's central ask: what the skill will not do, and how to switch it off. A tool that edits a person's writing owes them the edges. Claims removed as unprovable: «гарантирует предсказуемо высокое качество от любого Claude-агента», «Проверено на [12 платформ]» (three agents were probed; one failed), «глубокое понимание», «полное покрытие», «канонических источников», and «7 тематических блоков» — nothing in the repository defines the seven. The one claim that mattered more than the others is now a mechanism rather than a hope. The draft said «Чужой текст не трогается. Цитаты, код — вне зоны», and a judge found nothing in the corpus that enforced it: the same class as the guarantee the panel had just killed. SKILL.md now carries the rule — «Someone else's words stay theirs: quoted material, code blocks and third-party text inside the user's document are reproduced as-is» — so the README describes behaviour instead of promising it. Two facts stopped having two sources. The prose version line is gone from both READMEs: the badge renders it live from the releases API, so `check-version` drops from ten points to eight and the class of drift it was catching there no longer exists. The size of SKILL.md is gone too — a manifest's word count answers «did the author follow the spec», which is not a question a reader has. §4 of check-version stays, self-activating: state the size again and it is checked; state it wrongly and the gate fails. Its four selftest cases now build the claim in the sandbox before corrupting it, since testing a checker against a claim the product no longer makes would be testing nothing. check-typography gains R32/R53, digit grouping — and it gains it because it was needed. The one number left with a group separator, «более 2 000 атомов», was set with an ordinary space and walked through the green gate; a judge found it by reading. Third time this checker has been narrower than the rule it names, and the third case is pinned like the others. Red-test: tools/selftest.sh — «an ordinary space between digit groups is caught» reports «check-typography PASSED on corrupted input» before R32/R53 exists; the four size cases report «check-version PASSED on corrupted input» if §4 is removed rather than made optional. * docs: round two — drop the last hand-counted number, and stop over-promising The judge verified the eight round-one fixes (all landed, one with a residue) and found two things worth another pass. **«У двенадцати примет из шестнадцати выписано, где приём законен» was wrong, and wrong in the way this release spent its whole day removing.** Counted by substance rather than by the phrase «carve-out», thirteen of the sixteen carry a legitimacy clause, not twelve — AD-2.3 («parcellation is a legitimate author's device and is not penalized») and AD-5.2 («Exception — normative technical terminology») say it in their own words. A reader could not have reconstructed the counting rule that produces twelve. The numeral is gone rather than corrected: the sentence now says where a device is legitimate and that the carve-out is read before the finding is raised, which is the part a reader can use, and there is no number left to drift. **«Чужой текст не трогается… вне зоны» promised more than the rule gives.** SKILL.md reserves the right to REPORT an issue in third-party text and forbids only rewriting it; «вне зоны» said it would not even be mentioned. That is the round-one defect one step along — a sentence wider than its mechanism — and the English file had it right while the Russian did not. Both now say the same thing: a remark, perhaps; an edit, never. Three more from the same review: - The page named **zero** supported platforms. A reader asking «does this work with Cursor?» had to leave for INSTALL.md. One line, twelve names, in both files. - `/ru-text:ru-check` and `/ru-text:ru-score` are Claude Code's slash syntax, and the README's primary install path — copying the skill directory — gives other platforms no such command. Scoring still works there by asking in words; now the page says so. - README.en.md had had no independent reading. Five calques fixed («where its own platform keeps skills is something the agent knows better than», «the passive named who acts», «a floor rather than a figure» — a floor IS a figure), and the Russian specimens it quotes now carry English glosses, including a translation of the after-example. A page whose examples are opaque to its reader is not a mirror of anything. Red-test: n/a (documentation only; no behaviour path in the diff — selftest 90 passed / 0 failed before and after, all four checkers green, every relative link and anchor resolves in both languages). * docs: the final ru-check, and the fourth rule the gate did not name The project's own check was run over the finished page against the v2.0 corpus, and blocked it on four findings. All four are fixed. - **R31 — initials were not bound to their surnames.** «А. Э. Мильчин», «Л. К. Чельцова», «М. Ильяхов», «Л. Сарычева», «Д. Э. Розенталя»: ten ordinary spaces where the rule asks for non-breaking ones, so a line could break between a person's initials and their name in the section that thanks them. - **AD-1.1 — four em dashes in the legal paragraph**, against the rule's own limit of one or two. The aside became parentheses, which is what AD-1.2 prescribes; the two dashes left are required by the punctuation reference and cannot go. - **§G.1 — «двенадцати», «шестнадцать», «десяти» spelled out**, where the rule puts ten and above in digits. Four places. «Ещё девять», «Ещё две» and «четыре вещи» stay as words: they are below ten, which is the same rule. - **The page credited `ux-writing.md` with a section it does not have.** «онбординг» / «onboarding» appears nowhere in that file — verified by grep, its sections run A to M with no onboarding among them. Replaced with «диалоги подтверждения» / «confirmation dialogs», which section I does cover. This is the class of self-description that `check-dogfood.sh` catches for numbers and nothing catches for words. check-typography gains R31, and the pattern in these misses is worth naming: every one has been a rule the corpus has and the checker did not — R30 too narrow, then digit grouping absent, now initials — never a rule it got wrong. The checker grows one rule per finding, and each is pinned by a case that fails without it. Selftest 90 → 91. One thing the judge raised and I am not deciding: §G.1 can be read as not meant to reach emblematic counters like «шестнадцать примет», in which case the corpus wants the clarifying sentence rather than the page wanting the edit. Today the law is the corpus as written and the page now obeys it; changing the rule instead is the director's call, not mine. Red-test: tools/selftest.sh — «an ordinary space after an initial is caught» reports «check-typography PASSED on corrupted input» until R31 is implemented. * docs: neuroslop gets its own section, and the lead says what the tool is for The director asked to raise the emphasis. It was the fourth bullet inside a list of four — the capability the product is most needed for, filed behind buttons and emails. Now it is a section of its own with its own…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds version/platform/stars badges and a dedicated Обновление / Updating ru-text section to both READMEs.
Why: ru-text was covered on Habr; new users install via the community marketplace and had no clear path to update. The version badge now shows the latest release, and the new section gives a primary method (
npx skills add talkstream/ru-text) plus per-platform update commands, including the community-marketplace pin-lag caveat.Quality: all commands fact-checked (
claude plugins …,gemini extensions update, clawhubupdateengine); adversarial review to zero (fixed NBSP-before-em-dash ×6 and platforms count 13→12); RU dogfooded (NBSP, «», em dashes); RU↔EN parity verified.