Files
progcode/editorial/agent-rewrites/076.json
T

8 lines
24 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"index": 76,
"slug": "editorial-2025-11-field-research-method",
"title": "Как проверять техническое утверждение по первоисточнику",
"excerpt": "Практический метод для случаев, когда ссылка выглядит убедительно, но не отвечает на вопросы о версии, контексте и границе применимости.",
"contentHtml": "<p>В проекте появляется рекомендация: «добавим условный GET — ETag не даст клиенту использовать устаревшее представление». Ссылка ведёт на официальную документацию, поэтому её хочется сразу перенести в код или runbook. Но такая фраза смешивает семантику HTTP, поведение конкретного сервера, работу библиотеки и бизнес-понятие «устаревший». Если хотя бы один слой не проверен, команда получает уверенный текст вместо доказательства.</p>\n<p>Цена ошибки видна не в момент копирования ссылки. Через несколько месяцев страница может измениться, SDK — перейти на другую версию, а источник ответа уже нельзя будет восстановить. Практическое решение — вести для каждого важного вывода короткую цепочку: утверждение, область действия, закреплённый источник, точный локатор, наблюдение и разрешённый вывод. Ни одно звено не следует достраивать по памяти.</p>\n<h2>Сначала разделите вопрос на уровни</h2>\n<p>Технический вопрос редко бывает одним утверждением. «Поддерживает ли система ETag?» может означать несколько разных проверок:</p>\n<table><caption>Что именно проверяет каждый слой</caption><thead><tr><th scope=\"col\">Слой</th><th scope=\"col\">Вопрос</th><th scope=\"col\">Доказательство</th><th scope=\"col\">Граница вывода</th></tr></thead><tbody><tr><td>Протокол</td><td>Какое поведение описывает HTTP?</td><td>Раздел RFC и его условие</td><td>Правило стандарта, а не гарантия продукта</td></tr><tr><td>Представление</td><td>Какую редакцию мы прочитали?</td><td>Версия, дата, commit или архивный URL</td><td>Можно повторно открыть тот же материал</td></tr><tr><td>Реализация</td><td>Что делает конкретный сервер или SDK?</td><td>Документация версии, тест или трасса запроса</td><td>Результат действует только для названной версии и среды</td></tr><tr><td>Данные</td><td>Что означает полученное значение?</td><td>Схема, владелец поля и проверка содержимого</td><td>Целостность ответа не доказывает его бизнес-актуальность</td></tr><tr><td>Решение</td><td>Что разрешено изменить в проекте?</td><td>ADR, тестовый результат и критерий отката</td><td>Вывод ограничен условиями эксперимента</td></tr></tbody></table>\n<p>Эта таблица нужна не для бюрократии. Она останавливает скачок от «в стандарте описан механизм» к «наш клиент будет вести себя нужным образом». В статье, тикете или ревью один абзац должен отвечать на один из этих вопросов.</p>\n<h2>Запишите карточку утверждения</h2>\n<p>Начните не с поиска, а с решения, которое может измениться. Формулировка «исследовать кеширование» слишком широкая. Формулировка «в нашем GET-клиенте можно использовать ответ 304 как сигнал оставить сохранённое представление, если сервер вернул тот же validator» уже содержит действие и условия.</p>\n<p>Минимальная карточка состоит из шести полей:</p>\n<ul><li><strong>statement</strong> — одно предложение, которое можно подтвердить или опровергнуть;</li><li><strong>scope</strong> — метод, ресурс, версия клиента и сервера, формат, авторизация и среда;</li><li><strong>source</strong> — первичный документ, официальный релиз, репозиторий или спецификация;</li><li><strong>locator</strong> — раздел, якорь, страница, путь к полю или строка файла;</li><li><strong>artifact</strong> — короткий фрагмент документа, заголовок ответа, commit или результат теста;</li><li><strong>decision</strong> — какое действие разрешено, а какое пока запрещено.</li></ul>\n<pre><code>const claim = {\n statement: 'GET-клиент может повторить условный запрос для того же представления',\n scope: 'HTTP; GET; один ресурс; конкретный клиент и сервер указаны отдельно',\n source: 'https://www.rfc-editor.org/rfc/rfc9110.html#section-13.1.2',\n locator: 'RFC 9110, section 13.1.2; section 15.4.5',\n artifact: 'ответ сервера: status, ETag, body length, request headers',\n decision: 'разрешить только после проверки сервера и клиента'\n};\n\nconst required = ['statement', 'scope', 'source', 'locator', 'artifact', 'decision'];\nconst ready = required.every((field) => claim[field].trim().length > 0);\nif (!ready) throw new Error('claim is incomplete');</code></pre>\n<p>Код выше проверяет только заполненность записи. Он не ходит в сеть и не доказывает совместимость. Это принципиальная граница: валидная карточка описывает путь проверки, но не заменяет саму проверку.</p>\n<h2>Закрепите источник, а не только адрес</h2>\n<p>Текущий URL — это указатель, но не всегда идентичная копия прочитанного материала. Для стандарта полезно сохранить номер документа и раздел. Для исходного кода — commit и путь. Для API — метод, URL, безопасные заголовки, дату наблюдения и версию схемы. Для PDF — дату публикации, название раздела и номер страницы. Ссылка на главную страницу проекта не является локатором.</p>\n<p>Если утверждение относится к файлу в Git, извлеките его из конкретного commit. Команда не меняет рабочее дерево и позволяет проверить ровно ту версию, на которую ссылается карточка:</p>\n<pre><code>commit=0123456789abcdef0123456789abcdef01234567\npath=docs/cache.md\n\ngit show \"$commit:$path\" | sed -n '1,160p'\ngit show --format=fuller --no-patch \"$commit\"\n</code></pre>\n<p>Идентификатор в примере учебный: перед запуском подставьте commit из своего репозитория и убедитесь, что он существует. Не называйте короткий хеш доказательством происхождения без проверки полного значения и remote. Если файл уже переехал, сохраните старый путь в карточке и отдельно запишите новый, а не заменяйте историю одним актуальным URL.</p>\n<figure><img src=\"/assets/editorial/2025/research-method-2025-research-log-loop.svg\" alt=\"Цикл проверки технического утверждения: вопрос, карточка, закреплённый источник, наблюдение, ограниченный вывод и возврат на уточнение\" loading=\"lazy\" /><figcaption>Надёжный вывод проходит через вопрос, scope, source pin и наблюдение. При пропаже версии или локатора цепочка возвращается на уточнение, а не превращается в положительный ответ.</figcaption></figure>\n<h2>Проверьте, что HTTP-термин не обещает лишнего</h2>\n<p>RFC 9110 описывает ETag как validator выбранного представления ресурса. Это не номер релиза, не подпись автора и не доказательство того, что данные соответствуют бизнес-правилу свежести. Условный запрос с If-None-Match сравнивает значение с текущим представлением на стороне, которая обрабатывает запрос. При подходящем условии GET или HEAD может закончиться ответом 304 Not Modified без нового тела.</p>\n<p>Из этого следуют два отдельных вывода. Первый относится к протоколу: 304 сообщает о результате условного запроса. Второй относится к продукту: конкретный клиент должен корректно сохранить предыдущий ответ, а сервер — выдавать validator для того варианта представления, который действительно сравнивается. RFC не проверяет код вашего SDK, прокси, CDN или правила обновления данных.</p>\n<p>Ниже — безопасная последовательность для тестового или принадлежащего команде GET-эндпоинта. Она не отправляет изменение данных, сохраняет только заголовки и тело локально и завершает работу, если сервер не выдал ETag:</p>\n<pre><code>: \"\\${URL:?укажите URL тестового GET-эндпоинта}\"\n\ncurl --fail --silent --show-error --location \\\n --dump-header /tmp/claim-first.headers \\\n --output /tmp/claim-first.body \\\n \"$URL\"\n\netag=$(sed -n 's/^[Ee][Tt][Aa][Gg]:[[:space:]]*//p' /tmp/claim-first.headers | head -n 1 | tr -d '\\r')\nif [ -z \"$etag\" ]; then\n echo 'ETag is absent; stop instead of claiming conditional-cache support' >&2\n exit 2\nfi\n\ncurl --fail --silent --show-error --location \\\n --dump-header /tmp/claim-second.headers \\\n --output /tmp/claim-second.body \\\n -H \"If-None-Match: $etag\" \\\n \"$URL\"\n\nawk 'toupper($1) ~ /^HTTP\\// { print }' /tmp/claim-second.headers\nwc -c /tmp/claim-first.body /tmp/claim-second.body</code></pre>\n<p>Второй ответ не обязан быть 304. Представление могло измениться, сервер может не поддерживать условные запросы, заголовок мог потеряться на прокси, а ответ мог зависеть от Authorization, Accept-Language или Vary. Запишите фактический status и заголовки. Не подменяйте отсутствие 304 словами «кэш сломан» — сначала уточните контракт сервера.</p>\n<h2>Сопоставьте источник с наблюдением</h2>\n<p>Полезно хранить рядом три строки: что утверждает документ, что наблюдает эксперимент и что разрешено сделать. Например: «RFC описывает validator представления» — источник; «первый GET вернул ETag, второй GET с тем же If-None-Match вернул 304» — наблюдение; «клиент может использовать сохранённое тело в этой тестовой конфигурации» — ограниченный вывод.</p>\n<p>Если второй запрос вернул 200 с новым телом, это не опровергает RFC. Это опровергает более узкую гипотезу о вашем endpoint в данных условиях. Если сервер вернул 304, это всё ещё не доказывает, что бизнес-данные свежи: сервер мог ошибиться при генерации validator, а клиент — сохранить ответ не для того варианта языка или кодировки.</p>\n<p>Для происхождения записи можно использовать модель PROV-DM: отделить сущность, действие и участника, который её создал или изменил. В прикладной карточке это выглядит так: сущность — скачанный документ или ответ; действие — запрос, сборка или преобразование; участник — сервер, клиент или владелец публикации. Такая модель делает происхождение явным, но сама по себе не присваивает данным истинность.</p>\n<h2>Умейте остановиться на отрицательном пути</h2>\n<p>Проверка становится полезной, когда может вернуть «недостаточно данных». Четыре частых случая:</p>\n<ul><li><strong>Нет версии.</strong> Страница официальная, но неизвестно, какую редакцию читали. Сохраните URL как ориентир и поставьте вывод на паузу до появления даты, release или commit.</li><li><strong>Нет локатора.</strong> Ссылка открывается, но читатель не может найти подтверждающий абзац. Не добавляйте ещё пять ссылок на ту же главную страницу; найдите раздел или поле.</li><li><strong>Разные контексты.</strong> Документ описывает публичный GET, а эксперимент использует авторизованный endpoint за CDN. Разделите protocol fact и compatibility claim.</li><li><strong>Наблюдение не отвечает на вопрос.</strong> Наличие ETag подтверждает наличие заголовка в одном ответе, но не доказывает корректный cache key, свежесть данных или поведение после обновления.</li></ul>\n<table><caption>Диагностика незавершённой проверки</caption><thead><tr><th scope=\"col\">Признак</th><th scope=\"col\">Что уже известно</th><th scope=\"col\">Чего не хватает</th><th scope=\"col\">Следующий безопасный шаг</th></tr></thead><tbody><tr><td>Официальная страница без даты</td><td>Известен владелец домена</td><td>Закреплённая редакция</td><td>Найти release, commit или версию документа</td></tr><tr><td>Есть цитата без условий</td><td>Найдена формулировка</td><td>Объект и исключения</td><td>Прочитать соседний раздел и сузить statement</td></tr><tr><td>Тест вернул 304</td><td>Условный GET сработал в тесте</td><td>Контракт SDK и варианты представления</td><td>Добавить тест клиента для Accept, Vary и авторизации</td></tr><tr><td>Хеш файла совпал</td><td>Получена та же локальная копия</td><td>Смысл и авторитет содержимого</td><td>Сослаться на официальную публикацию и владельца</td></tr></tbody></table>\n<h2>Порядок работы для ревью и runbook</h2>\n<ol><li><strong>Назовите решение.</strong> Запишите, какой код, настройка или рекомендация зависит от ответа.</li><li><strong>Сформулируйте один claim.</strong> Укажите субъект, действие, объект и условие. Разнесите протокол, реализацию и бизнес-эффект.</li><li><strong>Выберите первичный источник.</strong> Отдайте приоритет стандарту, официальной документации версии, release notes или репозиторию владельца.</li><li><strong>Закрепите публикацию.</strong> Сохраните дату, версию, полный commit или стабильный URL. Для изменяемой страницы добавьте дату чтения.</li><li><strong>Поставьте locator.</strong> Раздел, anchor, страница, путь к полю или путь в репозитории должны вести к конкретному месту.</li><li><strong>Снимите artifact.</strong> Сохраните короткий фрагмент, заголовки, status или тестовый результат. Секреты и персональные данные удалите.</li><li><strong>Повторите заявленный контекст.</strong> Проверьте тот же метод, формат, версию, авторизацию, прокси и вариант представления.</li><li><strong>Запишите отрицательную ветку.</strong> Укажите, что происходит при отсутствии версии, ETag, поля, права или ожидаемого status.</li><li><strong>Передайте ограниченный вывод.</strong> Отдельно напишите «доказано», «не проверено» и «что нужно проверить, чтобы расширить claim».</li></ol>\n<h2>Границы применимости</h2>\n<p>Карточка утверждения не делает источник истинным и не заменяет аудит безопасности, нагрузочное испытание, проверку лицензии или предметную экспертизу. HTTPS подтверждает защищённый канал до проверенного узла, но не гарантирует качество текста на странице. Хеш подтверждает совпадение байтов, но не смысл документа. Ответ 304 подтверждает результат конкретного условного запроса, но не семантическую свежесть бизнес-данных.</p>\n<p>Метод плохо подходит для вопроса «безопасна ли вся система». Такой вопрос нужно разделить на проверяемые claims: какая граница доверия, какая атака, какой контроль, какая версия и какой результат ожидается. Чем шире утверждение, тем больше самостоятельных наблюдений оно требует.</p>\n<p>Команды с <code>/tmp</code> рассчитаны на macOS и Linux с установленным curl, sed, awk и стандартной файловой системой. Они используют GET; не подставляйте в URL токены и не запускайте пример против чужого сервиса без разрешения. Если endpoint меняет данные по GET, это уже нарушение его контракта: остановитесь и используйте безопасный стенд. Для Windows сохраните те же шаги в PowerShell, но отдельно проверьте эквивалентность разбора заголовков.</p>\n<h2>Критерий готовности</h2>\n<p>Утверждение можно передавать в код, документацию или решение, если другой инженер без устного пояснения открывает тот же источник, находит locator, видит artifact и воспроизводит наблюдение в указанном scope. В тексте рядом стоят доказанное поведение и его ограничение. При изменении версии создаётся новая запись, а старая не исчезает.</p>\n<p>Финальные вопросы просты: какое наблюдение изменит решение? Что именно этот источник не доказывает? Какой безопасный тест отличит две оставшиеся гипотезы? Если ответов нет, проверка ещё не закончена. Лучше вернуть claim на уточнение, чем превратить правдоподобную ссылку в гарантию, которой документ не давал.</p>\n<h2>Проверяемые источники</h2><ul><li><a href=\"https://www.rfc-editor.org/rfc/rfc9110.html\" target=\"_blank\" rel=\"noopener noreferrer\">IETF RFC 9110: HTTP Semantics</a> — разделы 8.8 о validator fields, 13.1.2 об If-None-Match и 15.4.5 о 304 Not Modified. Спецификация описывает HTTP-семантику, но не совместимость конкретного SDK.</li><li><a href=\"https://www.w3.org/TR/prov-dm/\" target=\"_blank\" rel=\"noopener noreferrer\">W3C PROV-DM: The PROV Data Model</a> — официальная модель сущностей, действий и участников происхождения данных. Она помогает описать lineage, но не доказывает истинность значения.</li><li><a href=\"https://git-scm.com/docs/git-show\" target=\"_blank\" rel=\"noopener noreferrer\">Git documentation: git-show</a> — справка по просмотру объектов и файлов из указанного commit. Команда извлечения не заменяет проверку remote и авторства публикации.</li></ul>"
}