Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import type { Block } from '../types'

export const body: Block[] = [
{
"kind": "p",
"text": "A tool that measures whether your safety checks work reported one of them as having no failure path at all. The gate has four. Every one of them is a ternary, and the tool only knew how to recognise the other kind."
},
{
"kind": "code",
"text": "pack_index_consistency_gate.py 0 no failure path to break"
},
{
"kind": "p",
"text": "That line reads like an oddity worth a shrug. It is the worst possible output: a path the scanner cannot see is a path it scores as covered."
},
{
"kind": "h",
"text": "What it was missing"
},
{
"kind": "p",
"text": "The tool works by mutation. It finds every line where the program returns a failing status, rewrites that line to return success, and demands that the program's own negative control notice. A line it cannot find is a line it never breaks, and a line never broken is scored the same as a line whose control caught the break."
},
{
"kind": "p",
"text": "The scanner matched a bare `return 1` through `return 4`. It did not match any of these:"
},
{
"kind": "code",
"text": "return 0 if not fails else 1\nreturn 1 if bad else 0\nraise SystemExit(3)"
},
{
"kind": "p",
"text": "Across the twelve gate scripts in this repository: **thirty-four failure paths seen, eight missed** — seven ternaries and one `SystemExit`. The denominator was short by a fifth of what the tool claimed to measure, and the shortfall was invisible because the report only ever counts what it found."
},
{
"kind": "h",
"text": "The number moved the wrong way, which is the honest direction"
},
{
"kind": "p",
"text": "Fixing the scanner made the results worse. Sites scanned went from thirty-four to forty-two; surviving mutants — the ones nothing catches — went from thirteen to twenty; gates with at least one survivor went from eight to nine."
},
{
"kind": "p",
"text": "This is the second time in this campaign that repairing an instrument has raised a count that reads like a defect count. The first was an elaboration ratchet where removing four syntax errors *increased* the reported error total, because a syntax error truncates the file and hides everything behind it. Both times, the instinct is to distrust the repair. Both times, the higher number is the true one, and the comfort of the lower number was the whole problem."
},
{
"kind": "p",
"text": "Worth writing next to the number itself, not just in the change that produced it: the next person to read the file is not the person who read the pull request."
},
{
"kind": "h",
"text": "Two ways to get the fix wrong"
},
{
"kind": "p",
"text": "**Mutate the ternary's arm rather than the whole line.** `return 1 if bad else 0` has a failing arm and a passing one, and it is tempting to rewrite just the `1`. But either arm may be the failing one — `return 0 if killed else 1` is in the same repository — and a mutant that changes nothing and then \"survives\" is a gap the tool invented. The whole return is replaced."
},
{
"kind": "p",
"text": "**Read any digit as a verdict.** `return t27c_failures` and `return code2` both contain a matching character. `raise SystemExit(main())` is a dispatch, not a verdict. Treating those as sites would manufacture survivors in code that is fine."
},
{
"kind": "p",
"text": "That asymmetry is worth being explicit about: a missed site stays an open question, and an invented one gets published as a defect in somebody's work. This tool had already invented one finding — a survivor that existed only because the tool ran the first of a gate's two controls instead of both — and it went out in an issue and a blog post before anyone checked it. So the digit test is deliberately conservative, and it has its own negative tests."
},
{
"kind": "h",
"text": "Three defects, one shape"
},
{
"kind": "p",
"text": "This is the third defect in this tool in two days. Laid side by side they are the same mistake:"
},
{
"kind": "ul",
"items": [
"It took the **first** control flag a gate declares, not the set — so a gate with two controls was measured by one of them.",
"Its control map was **one-to-one**, so a single control covering six gates could not be expressed, and those gates kept reporting as uncovered while the control sat in the tree.",
"It matched **one syntactic form** of a failing return, and scored the others as covered."
]
},
{
"kind": "p",
"text": "Each is scope decided by what was convenient to write rather than by what the rule is for. That is a named class in the taxonomy this same audit produced — and all three instances of it are in the auditor, not in the code being audited."
},
{
"kind": "p",
"text": "There is no clever remedy in that. A tool that measures coverage is itself a thing whose coverage nobody measures, and the only defence found so far is boring: when a report says something surprising about a file, open the file. \"No failure path to break\" was surprising, and the file was four lines of `git grep` away."
}
]

export const ruBody: Block[] = [
{
"kind": "p",
"text": "Инструмент, который меряет, работают ли ваши проверки безопасности, сообщил про одну из них: путей отказа нет вовсе. У этого гейта их четыре. Все четыре — тернарники, а инструмент умел узнавать только другую форму."
},
{
"kind": "code",
"text": "pack_index_consistency_gate.py 0 no failure path to break"
},
{
"kind": "p",
"text": "Строка выглядит как курьёз, достойный пожатия плечами. На деле это худший из возможных выводов: путь, которого сканер не видит, он засчитывает покрытым."
},
{
"kind": "h",
"text": "Чего он не видел"
},
{
"kind": "p",
"text": "Инструмент работает мутациями. Он находит каждую строку, где программа возвращает падающий статус, переписывает её на успешный и требует, чтобы негативный контроль этой программы это заметил. Строка, которую он не нашёл, — это строка, которую он никогда не ломал, а неломаная строка засчитывается так же, как та, чей контроль поломку поймал."
},
{
"kind": "p",
"text": "Сканер матчил голое `return 1`…`return 4`. Ни одну из этих форм он не видел:"
},
{
"kind": "code",
"text": "return 0 if not fails else 1\nreturn 1 if bad else 0\nraise SystemExit(3)"
},
{
"kind": "p",
"text": "По двенадцати гейт-скриптам репозитория: **тридцать четыре пути отказа увидено, восемь пропущено** — семь тернарников и один `SystemExit`. Знаменатель был занижен на пятую часть того, что инструмент брался мерить, и недостача была невидима, потому что отчёт считает только найденное."
},
{
"kind": "h",
"text": "Число поехало в «плохую» сторону — и это честная сторона"
},
{
"kind": "p",
"text": "Починка сканера сделала результаты хуже. Просканированных сайтов стало сорок два вместо тридцати четырёх; выживших мутантов — тех, кого никто не ловит, — двадцать вместо тринадцати; гейтов хотя бы с одним выжившим — девять вместо восьми."
},
{
"kind": "p",
"text": "Это второй раз за кампанию, когда починка прибора **поднимает** счёт, читающийся как счёт дефектов. Первый был с храповиком элаборации: снятие четырёх синтаксических ошибок *увеличило* общее число ошибок, потому что синтаксическая ошибка обрывает файл и прячет всё, что за ней. Оба раза инстинкт — не доверять починке. Оба раза верно именно большее число, а утешительность меньшего и была всей проблемой."
},
{
"kind": "p",
"text": "И это стоит писать рядом с самим числом, а не только в правке, которая его произвела: следующий, кто откроет файл, — не тот, кто читал пул-реквест."
},
{
"kind": "h",
"text": "Два способа починить это неправильно"
},
{
"kind": "p",
"text": "**Мутировать ветку тернарника, а не строку целиком.** У `return 1 if bad else 0` есть падающая ветка и проходящая, и соблазн — переписать только `1`. Но падающей может оказаться любая: `return 0 if killed else 1` лежит в том же репозитории. А мутант, который ничего не меняет и потом «выживает», — это выдуманный инструментом пробел. Поэтому заменяется весь return."
},
{
"kind": "p",
"text": "**Читать любую цифру как вердикт.** В `return t27c_failures` и `return code2` подходящий символ есть. `raise SystemExit(main())` — это диспетчеризация, а не вердикт. Засчитать их сайтами — значит изготовить выживших в коде, с которым всё в порядке."
},
{
"kind": "p",
"text": "Асимметрию тут стоит назвать вслух: пропущенный сайт остаётся открытым вопросом, а выдуманный публикуется как дефект в чужой работе. Этот инструмент одну находку уже выдумал — выживший существовал только потому, что инструмент запускал первый из двух контролей гейта вместо обоих, — и она уехала в issue и в пост до того, как её проверили. Поэтому проверка цифры намеренно консервативна и имеет собственные негативные тесты."
},
{
"kind": "h",
"text": "Три дефекта, одна форма"
},
{
"kind": "p",
"text": "Это третий дефект в этом инструменте за двое суток. Положенные рядом, они — одна и та же ошибка:"
},
{
"kind": "ul",
"items": [
"Он брал **первый** объявленный гейтом флаг контроля, а не набор — и гейт с двумя контролями мерился одним.",
"Карта контролей была **один к одному**, поэтому единый контроль на шесть гейтов нельзя было выразить, и те гейты числились непокрытыми, пока покрывающий их файл лежал в дереве.",
"Он матчил **одну синтаксическую форму** падающего возврата, а остальные засчитывал покрытыми."
]
},
{
"kind": "p",
"text": "Каждый раз охват определён тем, что было удобно написать, а не тем, ради чего правило существует. Это именованный класс в таксономии, которую произвёл этот же аудит, — и все три его экземпляра сидят в аудиторе, а не в аудируемом коде."
},
{
"kind": "p",
"text": "Хитрого лекарства тут нет. Инструмент, меряющий покрытие, сам является вещью, чьё покрытие никто не мерит, и единственная найденная защита скучна: если отчёт говорит о файле что-то удивительное — откройте файл. «Путей отказа нет» было удивительным, а файл лежал в четырёх строках `git grep` отсюда."
}
]
29 changes: 29 additions & 0 deletions apps/website/src/data/blog/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@ import type { PostMeta } from './types'

/** Индекс блога: список и метаданные без тяжёлых тел публикаций. */
export const postsIndex: PostMeta[] = [
{
slug: 'the-scanner-scored-what-it-could-not-see',
title: 'The scanner scored what it could not see',
summary: 'A mutation tool reported a gate as having no failure path. The gate has four -- all of them ternaries, a form the scanner did not recognise, so it scored them as covered.',
date: '2026-08-23',
readingMinutes: 7,
tags: ['CI', 'Mutation testing', 'Measurement', 'Self-critique'],
receipts: [
{ label: 'gHashTag/t27 #2470 -- the scanner fix, and the four unit tests including two negative directions', href: 'https://github.com/gHashTag/t27/pull/2470' },
{ label: 'gHashTag/t27 #2468 -- the survivor the tool invented, and the corrected numbers', href: 'https://github.com/gHashTag/t27/issues/2468' },
],
openQuestions: [
'Whether other syntactic forms of a failing exit are still invisible is not established: the scanner now knows three, and nothing enumerates the set.',
'The twenty surviving mutants are not shown to be defects. A survivor means nothing proves the gate will stay right, not that it is wrong today.',
'The mutation operator is a single one -- a verdict forced to zero. Inverting a condition is a different class this run does not cover.',
'A survivor can mean an unreachable site rather than an uncovered one, and the tool still does not separate the two.',
],
published: true,
ru: {
title: 'Сканер засчитал то, чего не видел',
summary: 'Мутационный инструмент сообщил, что у гейта нет путей отказа. Их четыре — все тернарники, форма, которой сканер не знал, и потому засчитал их покрытыми.',
openQuestions: [
'Остались ли невидимыми другие синтаксические формы падающего выхода — не установлено: сканер знает три, и множество никем не перечислено.',
'Двадцать выживших мутантов не показаны дефектами. Выживший значит «ничто не доказывает, что гейт останется верным», а не «он неверен сейчас».',
'Мутационный оператор один — вердикт, принудительно обнулённый. Инвертирование условия это другой класс, и он здесь не покрыт.',
'Выживший может означать недостижимый сайт, а не непокрытый, и инструмент их по-прежнему не разделяет.',
],
},
},
{
slug: 'the-control-that-could-not-fail',
title: 'The control that could not fail',
Expand Down
3 changes: 3 additions & 0 deletions apps/website/src/data/blog/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ import { body as body_ternary_won_the_wire_not_the_gate, ruBody as ruBody_ternar

import { body as body_the_control_that_could_not_fail, ruBody as ruBody_the_control_that_could_not_fail } from './bodies/the-control-that-could-not-fail'

import { body as body_the_scanner_scored_what_it_could_not_see, ruBody as ruBody_the_scanner_scored_what_it_could_not_see } from './bodies/the-scanner-scored-what-it-could-not-see'

const bodies: Record<string, PostBody> = {
'the-scanner-scored-what-it-could-not-see': { body: body_the_scanner_scored_what_it_could_not_see, ruBody: ruBody_the_scanner_scored_what_it_could_not_see },
'the-control-that-could-not-fail': { body: body_the_control_that_could_not_fail, ruBody: ruBody_the_control_that_could_not_fail },
'ternary-won-the-wire-not-the-gate': { body: body_ternary_won_the_wire_not_the_gate, ruBody: ruBody_ternary_won_the_wire_not_the_gate },
'the-required-check-was-an-echo': { body: body_the_required_check_was_an_echo, ruBody: ruBody_the_required_check_was_an_echo },
Expand Down
Loading