revise November 2027 advice revision plan articles
Build and deploy / deploy (push) Successful in 16s

This commit is contained in:
2026-07-31 21:00:07 +03:00
parent 0ae1c4612c
commit 6eb359ef5f
7 changed files with 316 additions and 1 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
# Производство редакционных партий # Производство редакционных партий
На 31 июля 2026 года строгий аудит проходит 352 из 358 созданных материалов. Осталось 6 материалов, которые не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить. На 31 июля 2026 года строгий аудит проходит 355 из 358 созданных материалов. Осталось 3 материала, которые не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
## Одна партия ## Одна партия
+54
View File
@@ -0,0 +1,54 @@
# P117 — ноябрь 2027: «Пересмотр старых советов»
## Scope и временная граница
P117 — future-only редакционный сценарий: `editorDate: 2026-07-31`, `planDate: 2027-11`, `sourceCutoff: 2026-07-31`. Он не утверждает существование исторической статьи, snapshot, старого совета, документационного изменения, свежего repro, тестового прогона, коррекции, публикации, owner-а или production-результата. Любые такие предметы представлены только именованными полями будущих вопросов. Единственный положительный evaluator output — `synthetic-plan-hand-off`; во всех ветках `productionEffect: not-attempted`.
Изменены ровно пять разрешённых файлов:
- `web/scripts/upgrade-2027-11.mjs`
- `editorial/reviews/2027-11-draft.md`
- `web/public/assets/editorial/2027/mistakes-revisions-2027-advice-timeline.svg`
- `web/public/assets/editorial/2027/mistakes-revisions-2027-condition-correction-matrix.svg`
- `web/public/assets/editorial/2027/mistakes-revisions-2027-evidence-handoff-loop.svg`
Git не использовался. Registry, README, очередь, `articles.json`, app и чужие пакеты не менялись.
## Источники и их границы
1. [W3C PROV-DM: The PROV Data Model](https://www.w3.org/TR/2013/REC-prov-dm-20130430/) — W3C Recommendation, 30 April 2013, датированная неизменяемая публикация. HTTP `200` проверен перед написанием. Применение: терминологически отделить сущность, деятельность и происхождение записи от пересказа о якобы известном совете. Граница: не доказывает, что существовала статья, автор, совет, условие, противоречие или коррекция P117.
2. [NIST SP 800-128: Guide for Security-Focused Configuration Management of Information Systems](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-128.pdf) — NIST SP 800-128, August 2011, dated PDF; HTTP `200` проверен 2026-07-31. Применение: язык фиксированной конфигурационной основы и контролируемого изменения, ограничивающий будущий вопрос о версии/условии. Граница: не устанавливает фактическую конфигурацию, ревизию, тест, решение, владельца или результат.
3. [RFC 3339: Date and Time on the Internet: Timestamps](https://www.rfc-editor.org/rfc/rfc3339.html) — IETF RFC 3339, July 2002, immutable RFC. Применение: дисциплина точных фиксированных дат editor date, plan date и source cutoff. Граница: не подтверждает время события, публикацию, наблюдение либо hand-off.
Все источники опубликованы не позднее cutoff и используются как vocabulary/boundary, не как результат пересмотра. В HTML каждой revision у ссылки указаны exact URL, версия/дата, применение и граница.
## Проход 1 — факты, структура и безопасность модели
- Три независимые M10 статьи начинаются с конкретной цены: обрезанный совет и лишний повторный поиск предпосылок; ложное опровержение из смены версии; фиктивная коррекция и ложная очередь.
- Practice отвечает, как сохранить claim вместе с assumption envelope; mechanism — как разделить version, condition, contradiction и repro boundary; field — как передать вопрос о возможной коррекции без verdict-а, owner-а или статуса завершения.
- Каждая статья содержит собственную таблицу, SVG с русскими `alt`/caption, исполнимый Node-пример с отдельным named fixed in-memory literal и нумерованный маршрут. Основной body без sources: **9 619 / 9 491 / 9 023** знака.
- `assessAdviceRevisionPlan` принимает только exact known fixed literals, ничего не читает и не пишет. Отсутствующая дата, unnamed claim, unnamed condition, mutable/unpinned evidence, injected repro result, declared correction/outcome закрываются explicit stop statuses. Fixture проверяет 9 веток, включая три допустимых плановых literals.
## Проход 2 — редактура, голос и независимость
- Голос 2025–2027: короткая прагматичная техническая речь, явная стоимость решения, comparison matrix и воспроизводимый способ остановиться. Нет универсального роста, вымышленного опыта и обещания результата.
- Future-only граница повторена смыслово, но не как общий ввод: practice работает с envelope утверждения; mechanism — с различающим вопросом и falsifiability; field — с передачей без назначения работы.
- Строгий scan исключил `Проверяемые источники`, но включил `<p>` и `<pre><code>`; он проверил exact normalised fragments длиной от 160 символов и 12-word n-grams. Сканированы **45** предыдущих статей P102–P116 и три P117-пары: **138** сравнений, `collisions: []`.
## Проход 3 — визуал, запуск и выпусковой preflight
- `node --check scripts/upgrade-2027-11.mjs` — PASS.
- `node scripts/upgrade-2027-11.mjs --verify-fixture` — **PASS fixture: 9/9 assertions**.
- `npm run audit:draft -- scripts/upgrade-2027-11.mjs` из `web/` — PASS для exact three slugs: **9 619 / 9 491 / 9 023** body chars. npm вывел существующие warnings о неизвестных user config `store-dir`, `cache-dir`, `public-hoist-pattern`; audit завершился успешно, warnings не относятся к P117.
- `xmllint --noout` для трёх SVG — PASS. SVG safety scan на `script`, event handlers, `javascript:`, `foreignObject`, `<image>` и external `href` — пустой/PASS.
- Sharp создал три PNG шириной **375 px**; ручной осмотр подтвердил читаемые заголовки, таблицу, подписи и отсутствие обрезания после переноса нижней красной строки timeline на две строки.
P117 заканчивается plan-only hand-off. Любая работа с реальным советом, источником, версией, contradiction, repro, correction, owner-ом или публикацией требует отдельного authorisation scope и не может быть задним числом добавлена в этот пакет.
## Независимое приёмочное ревью
- Повторно проверены первичные источники. PROV-DM подтверждает датированную W3C Recommendation 30 April 2013 и различение entity, activity и provenance; NIST SP 800-128 подтверждает название и публикацию August 2011; RFC 3339 подтверждает статус Standards Track, дату July 2002 и назначение формата timestamp. В P117 они служат только vocabulary и границей метода, а не доказательством существования старого совета или его исправления.
- Повторно выполнены `node --check`, fixture (**9/9**), `npm run audit:draft` и три runnable-примера. Они возвращают только fixed future-question literals и `synthetic-plan-hand-off`; реальный совет, текущая страница, воспроизведение или correction не создаются.
- Три SVG повторно прошли XML/safety scan и рендер Sharp на 375 px. На мобильной ширине читаемы дата/границы, матрица и независимый hand-off; красные stop-ветки не обрезаны и не накладываются на данные.
- Строгий duplicate scan P102–P117: **48 статей**, **1 128 парных сравнений**, sources исключены, code включён, common 12-word fragments — `[]`.
- Приёмочный verdict: **pass**. Пакет включён в registry как 353–355-й материал; production build и публикация выполняются после общей проверки интеграции.
+2
View File
@@ -113,6 +113,7 @@ import { revisions as july2027Revisions } from '../scripts/upgrade-2027-07.mjs';
import { revisions as august2027Revisions } from '../scripts/upgrade-2027-08.mjs'; import { revisions as august2027Revisions } from '../scripts/upgrade-2027-08.mjs';
import { revisions as september2027Revisions } from '../scripts/upgrade-2027-09.mjs'; import { revisions as september2027Revisions } from '../scripts/upgrade-2027-09.mjs';
import { revisions as october2027Revisions } from '../scripts/upgrade-2027-10.mjs'; import { revisions as october2027Revisions } from '../scripts/upgrade-2027-10.mjs';
import { revisions as november2027Revisions } from '../scripts/upgrade-2027-11.mjs';
// This layer replaces archived source entries without losing their stable slug and date. // This layer replaces archived source entries without losing their stable slug and date.
export const editorialRevisions = [ export const editorialRevisions = [
@@ -231,4 +232,5 @@ export const editorialRevisions = [
...august2027Revisions, ...august2027Revisions,
...september2027Revisions, ...september2027Revisions,
...october2027Revisions, ...october2027Revisions,
...november2027Revisions,
]; ];
@@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="720" viewBox="0 0 1200 720" role="img" aria-labelledby="title desc">
<title id="title">Временная граница пересмотра совета</title>
<desc id="desc">Схема показывает editor date 31 июля 2026 года, source cutoff той же даты и будущую plan date ноября 2027 года. Между ними расположены вопросы о claim, condition и immutable evidence; заявленного прошлого совета и результата нет.</desc>
<rect width="1200" height="720" fill="#101827"/>
<text x="64" y="78" fill="#f8fafc" font-family="Arial, sans-serif" font-size="40" font-weight="700">Сначала рамка, затем вопрос о совете</text>
<text x="64" y="118" fill="#b8c6dc" font-family="Arial, sans-serif" font-size="22">P117 · future-only сценарий · нет цитаты, статьи, теста или коррекции</text>
<line x1="110" y1="270" x2="1090" y2="270" stroke="#5d7394" stroke-width="8" stroke-linecap="round"/>
<circle cx="190" cy="270" r="28" fill="#7dd3fc"/><circle cx="520" cy="270" r="28" fill="#a7f3d0"/><circle cx="1010" cy="270" r="28" fill="#fbbf24"/>
<text x="120" y="330" fill="#e0f2fe" font-family="Arial, sans-serif" font-size="24" font-weight="700">editor date</text><text x="104" y="362" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="22">2026-07-31</text>
<text x="437" y="330" fill="#d1fae5" font-family="Arial, sans-serif" font-size="24" font-weight="700">source cutoff</text><text x="434" y="362" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="22">2026-07-31</text>
<text x="928" y="330" fill="#fef3c7" font-family="Arial, sans-serif" font-size="24" font-weight="700">plan date</text><text x="932" y="362" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="22">2027-11</text>
<rect x="92" y="454" width="300" height="136" rx="18" fill="#172a46" stroke="#7dd3fc" stroke-width="2"/><text x="122" y="500" fill="#e0f2fe" font-family="Arial, sans-serif" font-size="25" font-weight="700">Claim question</text><text x="122" y="539" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="20">named · not-collected</text>
<rect x="450" y="454" width="300" height="136" rx="18" fill="#173b38" stroke="#a7f3d0" stroke-width="2"/><text x="480" y="500" fill="#d1fae5" font-family="Arial, sans-serif" font-size="25" font-weight="700">Condition question</text><text x="480" y="539" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="20">version / applicability unknown</text>
<rect x="808" y="454" width="300" height="136" rx="18" fill="#44371b" stroke="#fbbf24" stroke-width="2"/><text x="838" y="500" fill="#fef3c7" font-family="Arial, sans-serif" font-size="25" font-weight="700">Evidence question</text><text x="838" y="539" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="20">immutable pin required</text>
<text x="64" y="650" fill="#fda4af" font-family="Arial, sans-serif" font-size="20" font-weight="700"><tspan x="64" dy="0">Запрещённый вывод: существовал старый совет, найдено основание,</tspan><tspan x="64" dy="28">выполнен repro или сделана коррекция.</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="720" viewBox="0 0 1200 720" role="img" aria-labelledby="title desc">
<title id="title">Матрица условия и коррекции для планового пересмотра</title>
<desc id="desc">Матрица разделяет claim, condition, evidence, contradiction, repro и correction. Допустимы только named questions и плановая передача; mutable evidence, injected repro и declared correction останавливаются.</desc>
<rect width="1200" height="720" fill="#131522"/>
<text x="54" y="70" fill="#f8fafc" font-family="Arial, sans-serif" font-size="38" font-weight="700">Сравнение начинается до verdict-а</text>
<text x="54" y="110" fill="#b8c6dc" font-family="Arial, sans-serif" font-size="22">P117 · condition и contradiction не заменяют друг друга</text>
<rect x="54" y="158" width="1092" height="64" rx="12" fill="#28364f"/><text x="82" y="199" fill="#e2e8f0" font-family="Arial, sans-serif" font-size="23" font-weight="700">Слой</text><text x="365" y="199" fill="#e2e8f0" font-family="Arial, sans-serif" font-size="23" font-weight="700">Допустимая форма</text><text x="750" y="199" fill="#e2e8f0" font-family="Arial, sans-serif" font-size="23" font-weight="700">Fail-closed граница</text>
<g font-family="Arial, sans-serif" font-size="21"><rect x="54" y="232" width="1092" height="62" fill="#1c2940"/><text x="82" y="271" fill="#dbeafe">Claim</text><text x="365" y="271" fill="#bbf7d0">named question-only</text><text x="750" y="271" fill="#fecaca">unnamed или declared claim</text><rect x="54" y="296" width="1092" height="62" fill="#202d44"/><text x="82" y="335" fill="#dbeafe">Condition</text><text x="365" y="335" fill="#bbf7d0">version / applicability not-collected</text><text x="750" y="335" fill="#fecaca">версия из памяти</text><rect x="54" y="360" width="1092" height="62" fill="#1c2940"/><text x="82" y="399" fill="#dbeafe">Evidence</text><text x="365" y="399" fill="#bbf7d0">immutable version or dated snapshot</text><text x="750" y="399" fill="#fecaca">mutable current document</text><rect x="54" y="424" width="1092" height="62" fill="#202d44"/><text x="82" y="463" fill="#dbeafe">Contradiction / repro</text><text x="365" y="463" fill="#bbf7d0">not-collected / not-run</text><text x="750" y="463" fill="#fecaca">injected repro result</text><rect x="54" y="488" width="1092" height="62" fill="#1c2940"/><text x="82" y="527" fill="#dbeafe">Correction / outcome</text><text x="365" y="527" fill="#bbf7d0">not-declared</text><text x="750" y="527" fill="#fecaca">declared correct or complete</text></g>
<path d="M600 590 L600 642" stroke="#86efac" stroke-width="5"/><path d="M588 628 L600 644 L612 628" fill="none" stroke="#86efac" stroke-width="5"/>
<text x="426" y="689" fill="#bbf7d0" font-family="Arial, sans-serif" font-size="26" font-weight="700">Только synthetic-plan-hand-off · effect not-attempted</text>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="720" viewBox="0 0 1200 720" role="img" aria-labelledby="title desc">
<title id="title">Петля передачи вопроса о коррекции</title>
<desc id="desc">Схема показывает, как именованные вопросы о claim, condition, evidence и repro передаются в отдельный будущий авторизованный scope. Correction, recipient и outcome остаются не объявленными, поэтому схема не заявляет исправление или завершённый тест.</desc>
<rect width="1200" height="720" fill="#10231f"/>
<text x="62" y="78" fill="#f0fdf4" font-family="Arial, sans-serif" font-size="39" font-weight="700">Передача вопроса без фиктивного финала</text>
<text x="62" y="118" fill="#b9d9cb" font-family="Arial, sans-serif" font-size="22">P117 · corrective hand-off не назначает владельца и не публикует correction</text>
<g font-family="Arial, sans-serif"><rect x="82" y="220" width="246" height="126" rx="18" fill="#173e36" stroke="#86efac" stroke-width="2"/><text x="116" y="267" fill="#dcfce7" font-size="26" font-weight="700">Question envelope</text><text x="116" y="307" fill="#cbd5e1" font-size="19">claim · condition</text><rect x="480" y="220" width="246" height="126" rx="18" fill="#173e36" stroke="#86efac" stroke-width="2"/><text x="518" y="267" fill="#dcfce7" font-size="26" font-weight="700">Evidence boundary</text><text x="518" y="307" fill="#cbd5e1" font-size="19">immutable pin required</text><rect x="878" y="220" width="246" height="126" rx="18" fill="#173e36" stroke="#86efac" stroke-width="2"/><text x="928" y="267" fill="#dcfce7" font-size="26" font-weight="700">Repro question</text><text x="928" y="307" fill="#cbd5e1" font-size="19">not-run only</text></g>
<path d="M328 283 H462" stroke="#86efac" stroke-width="5"/><path d="M726 283 H860" stroke="#86efac" stroke-width="5"/><path d="M1124 346 C1124 500 836 570 610 570 C384 570 82 500 82 346" fill="none" stroke="#7dd3fc" stroke-width="5" stroke-dasharray="12 10"/>
<rect x="384" y="496" width="432" height="116" rx="18" fill="#16324a" stroke="#7dd3fc" stroke-width="2"/><text x="444" y="542" fill="#e0f2fe" font-family="Arial, sans-serif" font-size="27" font-weight="700">Separate future scope</text><text x="446" y="578" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="19">authorization and method not created here</text>
<text x="78" y="676" fill="#fecaca" font-family="Arial, sans-serif" font-size="21" font-weight="700">Correction: not-declared · recipient: not-assigned · outcome: not-declared · productionEffect: not-attempted</text>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+221
View File
@@ -0,0 +1,221 @@
const escapeHtml = (value) => String(value).replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#039;');
const p = (text) => `<p>${text}</p>`;
const h2 = (text) => `<h2>${text}</h2>`;
const code = (text) => `<pre><code>${escapeHtml(text)}</code></pre>`;
const ol = (items) => `<ol>${items.map((item) => `<li>${item}</li>`).join('')}</ol>`;
const figure = (src, alt, caption) => `<figure><img src="${src}" alt="${alt}" loading="lazy" /><figcaption>${caption}</figcaption></figure>`;
const table = (caption, headers, rows) => `<div class="table-scroll"><table><caption>${caption}</caption><thead><tr>${headers.map((cell) => `<th scope="col">${cell}</th>`).join('')}</tr></thead><tbody>${rows.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join('')}</tr>`).join('')}</tbody></table></div>`;
function cloneFixed(value) { return JSON.parse(JSON.stringify(value)); }
function deepFreeze(value) { if (value && typeof value === 'object' && !Object.isFrozen(value)) { Object.values(value).forEach(deepFreeze); Object.freeze(value); } return value; }
function plainText(html) { return html.replace(/<[^>]+>/g, ' ').replace(/&(?:quot|amp|lt|gt|#039);/g, ' ').replace(/\s+/g, ' ').trim(); }
function bodyText(html) { return plainText(html.replace(/<h2>Проверяемые источники<\/h2>[\s\S]*$/, '')); }
const REFERENCES = deepFreeze({
provDm: {
title: 'PROV-DM: The PROV Data Model',
url: 'https://www.w3.org/TR/2013/REC-prov-dm-20130430/',
version: 'W3C Recommendation, 30 April 2013, dated immutable publication',
},
nist128: {
title: 'NIST SP 800-128: Guide for Security-Focused Configuration Management of Information Systems',
url: 'https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-128.pdf',
version: 'NIST Special Publication 800-128, August 2011, dated PDF',
},
rfc3339: {
title: 'RFC 3339: Date and Time on the Internet: Timestamps',
url: 'https://www.rfc-editor.org/rfc/rfc3339.html',
version: 'IETF RFC 3339, July 2002, immutable RFC publication',
},
});
function sources(entries) {
return `<ul>${entries.map(({ key, use, boundary }) => {
const ref = REFERENCES[key];
return `<li><a href="${ref.url}" target="_blank" rel="noopener noreferrer">${escapeHtml(ref.title)}</a> — ${escapeHtml(ref.version)}. Применение: ${escapeHtml(use)}. Граница: ${escapeHtml(boundary)}.</li>`;
}).join('')}</ul>`;
}
const FIXED_ADVICE_CASES = deepFreeze({
'advice-preservation-plan-v1': {
id: 'advice-preservation-plan-v1', editorDate: '2026-07-31', planDate: '2027-11', sourceCutoff: '2026-07-31',
claim: { id: 'future-advice-claim-question-v1', state: 'question-only', wording: 'not-collected' },
condition: { id: 'future-advice-condition-question-v1', version: 'not-collected', applicability: 'not-collected' },
evidence: { id: 'future-advice-evidence-reference-v1', pin: 'immutable-version-or-dated-snapshot', state: 'not-collected' },
contradiction: { id: 'future-advice-contradiction-question-v1', state: 'not-collected' },
repro: { id: 'future-advice-repro-question-v1', state: 'not-run', result: 'not-injected' },
correction: { id: 'future-advice-correction-question-v1', state: 'not-declared', outcome: 'not-declared' },
handoff: { id: 'future-advice-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
'advice-boundary-plan-v1': {
id: 'advice-boundary-plan-v1', editorDate: '2026-07-31', planDate: '2027-11', sourceCutoff: '2026-07-31',
claim: { id: 'future-versioned-claim-question-v1', state: 'question-only', wording: 'not-collected' },
condition: { id: 'future-version-condition-question-v1', version: 'not-collected', applicability: 'not-collected' },
evidence: { id: 'future-version-evidence-reference-v1', pin: 'immutable-version-or-dated-snapshot', state: 'not-collected' },
contradiction: { id: 'future-contradiction-question-v1', state: 'not-collected' },
repro: { id: 'future-falsification-repro-question-v1', state: 'not-run', result: 'not-injected' },
correction: { id: 'future-boundary-correction-question-v1', state: 'not-declared', outcome: 'not-declared' },
handoff: { id: 'future-boundary-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
'advice-handoff-plan-v1': {
id: 'advice-handoff-plan-v1', editorDate: '2026-07-31', planDate: '2027-11', sourceCutoff: '2026-07-31',
claim: { id: 'future-handoff-claim-question-v1', state: 'question-only', wording: 'not-collected' },
condition: { id: 'future-handoff-condition-question-v1', version: 'not-collected', applicability: 'not-collected' },
evidence: { id: 'future-handoff-evidence-reference-v1', pin: 'immutable-version-or-dated-snapshot', state: 'not-collected' },
contradiction: { id: 'future-handoff-contradiction-question-v1', state: 'not-collected' },
repro: { id: 'future-handoff-repro-question-v1', state: 'not-run', result: 'not-injected' },
correction: { id: 'future-handoff-correction-question-v1', state: 'not-declared', outcome: 'not-declared' },
handoff: { id: 'future-corrective-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
'advice-missing-date-v1': {
id: 'advice-missing-date-v1', editorDate: '', planDate: '2027-11', sourceCutoff: '2026-07-31', claim: { id: 'future-date-claim-question-v1', state: 'question-only', wording: 'not-collected' }, condition: { id: 'future-date-condition-question-v1', version: 'not-collected', applicability: 'not-collected' }, evidence: { id: 'future-date-evidence-reference-v1', pin: 'immutable-version-or-dated-snapshot', state: 'not-collected' }, contradiction: { id: 'future-date-contradiction-question-v1', state: 'not-collected' }, repro: { id: 'future-date-repro-question-v1', state: 'not-run', result: 'not-injected' }, correction: { id: 'future-date-correction-question-v1', state: 'not-declared', outcome: 'not-declared' }, handoff: { id: 'future-date-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
'advice-unnamed-claim-v1': {
id: 'advice-unnamed-claim-v1', editorDate: '2026-07-31', planDate: '2027-11', sourceCutoff: '2026-07-31', claim: { id: '', state: 'question-only', wording: 'not-collected' }, condition: { id: 'future-claim-condition-question-v1', version: 'not-collected', applicability: 'not-collected' }, evidence: { id: 'future-claim-evidence-reference-v1', pin: 'immutable-version-or-dated-snapshot', state: 'not-collected' }, contradiction: { id: 'future-claim-contradiction-question-v1', state: 'not-collected' }, repro: { id: 'future-claim-repro-question-v1', state: 'not-run', result: 'not-injected' }, correction: { id: 'future-claim-correction-question-v1', state: 'not-declared', outcome: 'not-declared' }, handoff: { id: 'future-claim-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
'advice-unnamed-condition-v1': {
id: 'advice-unnamed-condition-v1', editorDate: '2026-07-31', planDate: '2027-11', sourceCutoff: '2026-07-31', claim: { id: 'future-condition-claim-question-v1', state: 'question-only', wording: 'not-collected' }, condition: { id: '', version: 'not-collected', applicability: 'not-collected' }, evidence: { id: 'future-condition-evidence-reference-v1', pin: 'immutable-version-or-dated-snapshot', state: 'not-collected' }, contradiction: { id: 'future-condition-contradiction-question-v1', state: 'not-collected' }, repro: { id: 'future-condition-repro-question-v1', state: 'not-run', result: 'not-injected' }, correction: { id: 'future-condition-correction-question-v1', state: 'not-declared', outcome: 'not-declared' }, handoff: { id: 'future-condition-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
'advice-mutable-evidence-v1': {
id: 'advice-mutable-evidence-v1', editorDate: '2026-07-31', planDate: '2027-11', sourceCutoff: '2026-07-31', claim: { id: 'future-evidence-claim-question-v1', state: 'question-only', wording: 'not-collected' }, condition: { id: 'future-evidence-condition-question-v1', version: 'not-collected', applicability: 'not-collected' }, evidence: { id: 'future-evidence-reference-v1', pin: 'mutable-current-document', state: 'not-collected' }, contradiction: { id: 'future-evidence-contradiction-question-v1', state: 'not-collected' }, repro: { id: 'future-evidence-repro-question-v1', state: 'not-run', result: 'not-injected' }, correction: { id: 'future-evidence-correction-question-v1', state: 'not-declared', outcome: 'not-declared' }, handoff: { id: 'future-evidence-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
'advice-injected-repro-v1': {
id: 'advice-injected-repro-v1', editorDate: '2026-07-31', planDate: '2027-11', sourceCutoff: '2026-07-31', claim: { id: 'future-repro-claim-question-v1', state: 'question-only', wording: 'not-collected' }, condition: { id: 'future-repro-condition-question-v1', version: 'not-collected', applicability: 'not-collected' }, evidence: { id: 'future-repro-evidence-reference-v1', pin: 'immutable-version-or-dated-snapshot', state: 'not-collected' }, contradiction: { id: 'future-repro-contradiction-question-v1', state: 'not-collected' }, repro: { id: 'future-repro-question-v1', state: 'not-run', result: 'claimed-reproduced' }, correction: { id: 'future-repro-correction-question-v1', state: 'not-declared', outcome: 'not-declared' }, handoff: { id: 'future-repro-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
'advice-declared-correction-v1': {
id: 'advice-declared-correction-v1', editorDate: '2026-07-31', planDate: '2027-11', sourceCutoff: '2026-07-31', claim: { id: 'future-correction-claim-question-v1', state: 'question-only', wording: 'not-collected' }, condition: { id: 'future-correction-condition-question-v1', version: 'not-collected', applicability: 'not-collected' }, evidence: { id: 'future-correction-evidence-reference-v1', pin: 'immutable-version-or-dated-snapshot', state: 'not-collected' }, contradiction: { id: 'future-correction-contradiction-question-v1', state: 'not-collected' }, repro: { id: 'future-correction-repro-question-v1', state: 'not-run', result: 'not-injected' }, correction: { id: 'future-correction-question-v1', state: 'declared-correct', outcome: 'declared-complete' }, handoff: { id: 'future-correction-handoff-question-v1', recipient: 'not-assigned', state: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off',
},
});
export function createFixedAdviceRevisionCase(id = 'advice-preservation-plan-v1') { const fixed = FIXED_ADVICE_CASES[id]; return fixed ? deepFreeze(cloneFixed(fixed)) : undefined; }
function stop(status, reason, nextAction) { return deepFreeze({ status, reason, nextAction, productionEffect: 'not-attempted' }); }
export function assessAdviceRevisionPlan(input) {
const known = Object.values(FIXED_ADVICE_CASES).some((item) => JSON.stringify(item) === JSON.stringify(input));
if (!known) return stop('stop-unknown-fixed-literal', 'input-is-not-a-known-named-fixed-in-memory-literal', 'select-a-named-fixed-literal');
if (input.editorDate !== '2026-07-31' || input.planDate !== '2027-11' || input.sourceCutoff !== '2026-07-31') return stop('stop-missing-or-invalid-temporal-boundary', 'editor-date-plan-date-and-source-cutoff-must-be-exact', 'restore-all-three-fixed-dates');
if (!input.claim.id || input.claim.state !== 'question-only' || input.claim.wording !== 'not-collected') return stop('stop-unnamed-or-declared-claim', 'claim-must-be-named-and-remain-a-future-question', 'name-the-claim-without-declaring-it');
if (!input.condition.id || input.condition.version !== 'not-collected' || input.condition.applicability !== 'not-collected') return stop('stop-unnamed-or-declared-condition', 'condition-must-be-named-without-version-or-applicability-claim', 'name-the-condition-without-inventing-its-values');
if (!input.evidence.id || input.evidence.pin !== 'immutable-version-or-dated-snapshot' || input.evidence.state !== 'not-collected') return stop('stop-mutable-or-unpinned-evidence', 'evidence-must-be-a-named-immutable-reference-question', 'require-an-immutable-version-or-dated-snapshot');
if (!input.contradiction.id || input.contradiction.state !== 'not-collected') return stop('stop-unnamed-or-injected-contradiction', 'contradiction-must-remain-a-named-future-question', 'remove-the-declared-contradiction');
if (!input.repro.id || input.repro.state !== 'not-run' || input.repro.result !== 'not-injected') return stop('stop-injected-repro-result', 'repro-result-cannot-be-created-by-a-plan', 'keep-repro-not-run-and-result-not-injected');
if (!input.correction.id || input.correction.state !== 'not-declared' || input.correction.outcome !== 'not-declared') return stop('stop-declared-correction-or-outcome', 'correction-and-outcome-cannot-be-declared-by-a-plan', 'keep-correction-and-outcome-undeclared');
if (!input.handoff.id || input.handoff.recipient !== 'not-assigned' || input.handoff.state !== 'not-created') return stop('stop-created-handoff-or-owner', 'plan-cannot-create-a-recipient-or-handoff', 'keep-recipient-unassigned-and-handoff-uncreated');
if (input.requestedOutput !== 'synthetic-plan-hand-off') return stop('stop-disallowed-positive-result', 'only-synthetic-plan-hand-off-is-permitted', 'use-synthetic-plan-hand-off');
return deepFreeze({ status: 'synthetic-plan-hand-off', literalId: input.id, claim: deepFreeze(cloneFixed(input.claim)), condition: deepFreeze(cloneFixed(input.condition)), evidence: deepFreeze(cloneFixed(input.evidence)), contradiction: deepFreeze(cloneFixed(input.contradiction)), repro: deepFreeze(cloneFixed(input.repro)), correction: deepFreeze(cloneFixed(input.correction)), handoff: deepFreeze(cloneFixed(input.handoff)), productionEffect: 'not-attempted', nextAction: 'open-a-separate-authorized-scope-only-to-collect-and-assess-the-named-questions' });
}
export function inspectAdvicePreservationLiteral() { const result = assessAdviceRevisionPlan(createFixedAdviceRevisionCase('advice-preservation-plan-v1')); return deepFreeze({ literal: result.literalId, claim: result.claim.id, condition: result.condition.id, status: result.status, productionEffect: result.productionEffect }); }
export function inspectAdviceBoundaryLiteral() { const result = assessAdviceRevisionPlan(createFixedAdviceRevisionCase('advice-boundary-plan-v1')); return deepFreeze({ literal: result.literalId, evidencePin: result.evidence.pin, repro: result.repro.state, status: result.status, productionEffect: result.productionEffect }); }
export function inspectAdviceHandoffLiteral() { const result = assessAdviceRevisionPlan(createFixedAdviceRevisionCase('advice-handoff-plan-v1')); return deepFreeze({ literal: result.literalId, correction: result.correction.state, recipient: result.handoff.recipient, status: result.status, productionEffect: result.productionEffect }); }
export function runAdviceRevisionFixture() {
const expected = [['advice-preservation-plan-v1', 'synthetic-plan-hand-off'], ['advice-boundary-plan-v1', 'synthetic-plan-hand-off'], ['advice-handoff-plan-v1', 'synthetic-plan-hand-off'], ['advice-missing-date-v1', 'stop-missing-or-invalid-temporal-boundary'], ['advice-unnamed-claim-v1', 'stop-unnamed-or-declared-claim'], ['advice-unnamed-condition-v1', 'stop-unnamed-or-declared-condition'], ['advice-mutable-evidence-v1', 'stop-mutable-or-unpinned-evidence'], ['advice-injected-repro-v1', 'stop-injected-repro-result'], ['advice-declared-correction-v1', 'stop-declared-correction-or-outcome']];
const checks = expected.map(([id, status]) => ({ id, expected: status, actual: assessAdviceRevisionPlan(createFixedAdviceRevisionCase(id)).status }));
const accepted = createFixedAdviceRevisionCase('advice-preservation-plan-v1');
return deepFreeze({ passed: checks.filter((item) => item.expected === item.actual).length, total: checks.length, accepted: checks.every((item) => item.expected === item.actual) && Object.isFrozen(accepted) && Object.isFrozen(accepted.claim) && Object.isFrozen(accepted.condition) && Object.isFrozen(accepted.evidence), checks: deepFreeze(checks) });
}
function revision(meta, parts, referenceEntries) {
const contentHtml = parts.join('') + h2('Проверяемые источники') + sources(referenceEntries);
const proseLength = bodyText(contentHtml).length;
if (proseLength < 9000 || proseLength > 12000) throw new Error(`${meta.slug}: body length ${proseLength}`);
return deepFreeze({ ...meta, contentHtml, proseLength });
}
const commonRefs = [
{ key: 'provDm', use: 'Даёт строгие термины для различения сущности, деятельности и происхождения записи; здесь это помогает не выдавать вопрос о совете за уже установленную историю.', boundary: 'Не подтверждает существование старой статьи, её автора, совет, условие, противоречие или исправление.' },
{ key: 'nist128', use: 'Поддерживает дисциплину фиксированной конфигурационной основы и контролируемого изменения; здесь она ограничивает форму будущего вопроса о версии и условии.', boundary: 'Не устанавливает конфигурацию, ревизию, проверку, решение, владельца или результат какого-либо проекта.' },
{ key: 'rfc3339', use: 'Задаёт неизменяемую норму записи даты, поэтому фиксированные editor date, plan date и cutoff не смешиваются с текущими часами.', boundary: 'Не доказывает время события, публикацию, наблюдение или завершённый hand-off.' },
];
const practice = revision({ slug: 'editorial-2027-11-practice-mistakes-revisions', title: 'Пересмотр старых советов: как сохранить утверждение вместе с его допущениями', categories: ['Практика', 'Техническое письмо'], cover: '/assets/editorial/2027/mistakes-revisions-2027-advice-timeline.svg', excerpt: 'План P117 на ноябрь 2027: как не превратить короткий совет в бесконтекстное правило и как передать вопрос о его основаниях без вымышленной истории.', readingMinutes: 24 }, [
p('P117 — будущий редакционный сценарий на ноябрь 2027, записанный 2026-07-31. У старого совета есть неприятная цена: его часто переносят в новый контекст как одну короткую фразу, а условие, версия и граница остаются за кадром. Следующий инженер получает не утверждение, которое можно проверить, а удобный лозунг. Цена ошибки конкретна: действие выбирают по обрезанному правилу, затем тратят время на обратный поиск предпосылок и спорят не о фактах, а о том, что будто бы имелось в виду.'),
p('Вторая цена — назвать потерянный контекст «ошибкой старой статьи» до того, как существует сам объект проверки. В этом выпуске нет исторической публикации, снимка, цитаты, документации, автора, реального условия, свежего воспроизведения, тестового прогона или исправления. Поэтому здесь нельзя объявлять совет верным, неверным, устаревшим или исправленным. Есть только named future question fields. Единственный положительный ответ evaluator-а — <code>synthetic-plan-hand-off</code>; <code>productionEffect</code> всегда <code>not-attempted</code>.'),
h2('Не сохраняйте фразу отдельно от рамки'),
p('Полезно думать о совете не как о цитате, а как о карточке из нескольких независимых частей. Первая часть — claim: вопрос о том, что именно когда-нибудь потребуется сформулировать. Вторая — condition: вопрос о версии и применимости. Третья — evidence: вопрос о допустимой привязке к immutable version или dated snapshot. Пока значения не собраны в отдельном авторизованном scope, все три остаются <code>not-collected</code>. Такой дизайн кажется строгим, зато он не даёт прошлому ярлыку стать сегодняшней командой.'),
p('Слова «сохранить совет» иногда ошибочно понимают как сохранить всю формулировку. Это опасный вид архива: строка может выглядеть точной, но не указывать ни объект, ни исключение, ни границу. В плановом материале даже правдоподобную строку нельзя сочинять: она станет фиктивной старой цитатой. Вместо неё фиксируется идентификатор вопроса <code>future-advice-claim-question-v1</code>. Идентификатор не рассказывает историю и не закрывает спор; он позволяет различить поле claim от condition и не подставить одно вместо другого.'),
table('Карточка сохранения будущего вопроса о совете', ['Поле', 'Фиксированное значение P117', 'Что это разрешает', 'Какой вывод закрыт'], [['Claim', '<code>future-advice-claim-question-v1</code> + <code>not-collected</code>', 'Назвать предмет будущего разбора', 'Существовал старый тезис или его точная формулировка'], ['Condition', '<code>future-advice-condition-question-v1</code>', 'Отдельно потребовать версию и применимость', 'Совет подходит конкретной версии или среде'], ['Evidence', '<code>immutable-version-or-dated-snapshot</code>', 'Запросить устойчивую ссылку', 'Документ уже найден или не менялся'], ['Repro', '<code>not-run / not-injected</code>', 'Оставить место для будущей проверки', 'Поведение воспроизведено'], ['Correction', '<code>not-declared</code>', 'Не терять вопрос о возможной правке', 'Что-либо исправлено или стало лучше']]),
h2('Допущение — часть смысла, а не примечание'),
p('У любого практического совета есть область, за пределами которой он может стать вредным. Это не делает совет плохим. Условие может зависеть от версии интерфейса, режима запуска, формата входа, политики доступа или внешнего контракта. Но P117 не называет ни одну такую реальную версию: назвать её означало бы притвориться, что старый объект уже известен. Поле condition хранит только вопрос и запрет на значение. Будущий исследователь должен будет собрать версию и применимость как evidence, а не вытащить их из уверенной интонации текста.'),
p('Отдельный риск — подменить условие рекомендацией. Фраза «проверяйте документацию» не говорит, какую именно документацию можно считать основанием. Здесь boundary жёстче: current page сама по себе не годится, если она может измениться. Нужна версия, неизменяемый commit или датированный снимок. Это не требование собрать ссылку прямо сейчас. Это правило, по которому будущий scope будет отличать источник вопроса от изменяемого объяснения. Пока pin не назван, evaluator возвращает stop и не подставляет разумный default.'),
figure('/assets/editorial/2027/mistakes-revisions-2027-advice-timeline.svg', 'Временная шкала P117: editor date 2026-07-31, будущая plan date 2027-11 и source cutoff 2026-07-31 окружают три вопроса claim, condition и evidence; между ними нет заявленного прошлого совета или результата.', 'Схема показывает temporal boundary и порядок вопросов для будущего разбора. Она не является снимком статьи, журналом изменений, документацией или подтверждением того, что совет когда-либо существовал.'),
h2('Исполнимый пример оставляет содержание неизвестным'),
p('Ниже запущенный фрагмент работает исключительно с named fixed in-memory literal. Он не принимает URL, текст статьи, переменные окружения, файл, часы, сеть, Git, журнал, тестовый стенд или пользовательский ввод. Возвращаемый status описывает только форму плана. В частности, печать <code>not-collected</code> не означает, что материал потерян; она означает, что P117 не получил права назвать его собранным. Это небольшая, но важная защита от случайного превращения редакционного черновика в источник истории.'),
code("import { inspectAdvicePreservationLiteral } from './upgrade-2027-11.mjs';\n\nconst fixedAdviceQuestion = inspectAdvicePreservationLiteral();\nconsole.log({\n literal: fixedAdviceQuestion.literal,\n claim: fixedAdviceQuestion.claim,\n condition: fixedAdviceQuestion.condition,\n result: fixedAdviceQuestion.status,\n effect: fixedAdviceQuestion.productionEffect,\n});"),
p('Пример намеренно не печатает якобы старую формулировку. Если добавить её в literal, она станет synthetic текстом, но читатель легко примет её за найденный архив. Тот же запрет действует для номера версии, времени публикации, имени автора и причины изменения: реалистичность не превращает выдуманную деталь в evidence. Безопасный учебный результат — лишь hand-off с названиями вопросов, которые другой scope сможет принять, отклонить или уточнить.'),
h2('Как удержать границу при подготовке'),
p('Первый практический вопрос звучит не «надо ли переписать совет?», а «какое утверждение требуется сохранить вместе с условиями?». Это меняет стоимость обсуждения. Команда не должна согласовать литературную трактовку, пока не знает минимальный доказательный пакет. Сначала разделяются claim, condition и evidence; затем решается, достаточно ли будущему читателю одной версии документа или нужна отдельная проверка поведения. Такая последовательность не обещает, что проверка будет выполнена. Она только предотвращает необратимый вывод до появления входных данных.'),
ol(['Поставить на карточке все три фиксированные даты: <code>editorDate: 2026-07-31</code>, <code>planDate: 2027-11</code> и <code>sourceCutoff: 2026-07-31</code>.', 'Назвать claim идентификатором вопроса, не создавать цитату, заголовок старого материала или вывод о его истинности.', 'Назвать condition отдельным идентификатором и оставить version/applicability как <code>not-collected</code>; не переносить условие из памяти.', 'Разрешить evidence только как future reference с immutable version или dated snapshot; mutable current page вернуть на stop.', 'Сохранить repro как <code>not-run</code> и <code>not-injected</code>; не писать, что тест или ручная проверка уже дали результат.', 'Передать только synthetic plan hand-off в отдельный authorisation scope, где будут заново определены доступ, метод и ответственный вопрос.']),
h2('Контрпример: память не становится provenance'),
p('Иногда самый быстрый путь — сказать: «все знают, почему это правило появилось». Именно здесь контекст теряется окончательно. Коллективная память может подсказать направление поиска, но не заменяет pinned evidence и не позволяет утверждать историю. Она особенно ненадёжна, когда один и тот же короткий совет кочует между версиями или командами. В P117 память не запрещена как будущий вход, но ей не выдана роль доказательства. До отдельной оценки она остаётся неназванным источником и должна закрывать принятие, а не открывать его.'),
p('Другой контрпример — заменить условие широкой оговоркой «зависит от контекста». Такая фраза выглядит осторожно, но ничего не защищает: читатель не знает, какой контекст нужно зафиксировать и как обнаружить несовместимость. Named condition question строже и полезнее. Она требует будущую версию и применимость, однако не делает вид, что они уже известны. В результате карточка сохраняет неопределённость в явном поле, а не прячет её в конце абзаца.'),
h2('Минимальная карточка дешевле последующего пересказа'),
p('У такой карточки есть ещё одно практическое свойство: она не заставляет будущего читателя доверять редактору. Достаточно увидеть, что claim, condition и evidence названы раздельно, а значения не подменены. Если одна часть окажется нерелевантной, новый scope сможет удалить или заменить именно её, не переписывая вокруг вымышленную историю. Это уменьшает blast radius редакторского решения: меняется вопросная карточка, а не вывод о людях, системах или уже опубликованных результатах.'),
p('Не надо добавлять в карточку поле «уверенность». До появления evidence оно будет измерять только риторику автора. Не надо добавлять и поле «приоритет»: без предмета и владельца оно станет скрытой очередью. Нужны лишь идентификаторы будущих вопросов и стоп-границы. Такая аскетичность не делает будущий разбор беднее; она оставляет ему возможность выбрать метод по реальному объекту, а не по предзаполненной оценке.'),
h2('Ограничения и следующий шаг'),
p('Эта модель не проверяет архив, репозиторий, release notes, документацию, конфигурацию, реальный совет, авторство, ссылку, тест или production. Она также не решает, нужна ли коррекция и кому её выполнять. Deep freeze защищает только учебный объект в памяти, а не информацию за его пределами. Официальные источники ниже задают язык происхождения, конфигурационной основы и дат, но не являются ревизией чьего-либо текста. Они не превращают synthetic names в historical facts.'),
p('Следующий шаг не «обновить старую статью», потому что здесь нет такой статьи. Нужен отдельный scope с явно разрешённым объектом исследования. В нём можно будет выбрать один claim question, определить допустимую immutable привязку, собрать condition и сформулировать критерий опровержения. До этого P117 заканчивается ровно там, где должен: записанной формой вопроса и <code>synthetic-plan-hand-off</code>, без декларации коррекции или эффекта.'),
], commonRefs);
const mechanism = revision({ slug: 'editorial-2027-11-mechanism-mistakes-revisions', title: 'Пересмотр старых советов: версия, условие и граница опровержения', categories: ['Архитектура', 'Надёжность'], cover: '/assets/editorial/2027/mistakes-revisions-2027-condition-correction-matrix.svg', excerpt: 'План P117 на ноябрь 2027: как отделить противоречие и будущий repro от версии и условия, чтобы непроверенный пересмотр не стал вердиктом.', readingMinutes: 25 }, [
p('Пересмотр старого совета ломается не только из-за отсутствующей цитаты. Дорогая ошибка появляется, когда несовпадение версии или условия сразу называют опровержением. Один человек видит новый вариант интерфейса, другой помнит другую предпосылку, и разговор быстро превращается в «совет больше не работает». Цена — ложная отмена полезного правила либо, наоборот, сохранение правила там, где его предпосылка уже не названа. Оба исхода заставляют команду делать лишний круг диагностики.'),
p('P117 не содержит старого совета, версии, документа, противоречащего наблюдения, окружения, воспроизведения, тестового лога или результата повтора. Это будущий сценарий на <code>planDate: 2027-11</code> при editor date и source cutoff 2026-07-31. Поэтому слово «опровергнут» здесь не может стать итогом. Положительный evaluator output один: <code>synthetic-plan-hand-off</code> с <code>productionEffect: not-attempted</code>. Любая попытка добавить подтверждённый repro, текущую mutable страницу или заявленную коррекцию должна закрываться.'),
h2('Версия не равна противоречию'),
p('Версия описывает, к какому состоянию предмета относится будущий вопрос. Противоречие описывает другой вопрос: какой факт мог бы сделать claim несостоятельным при сопоставимых условиях. Эти сущности нельзя склеивать. Если в документе найдена новая версия, это ещё не говорит, что прежнее утверждение неверно: возможно, изменился предмет, область применимости или словарь. И наоборот, даже зафиксированная старая версия не гарантирует, что совет работал в каждом режиме. Для честной ревизии нужны два разных поля и два разных основания.'),
p('В literal P117 поле <code>condition</code> имеет named id, но <code>version</code> и <code>applicability</code> остаются <code>not-collected</code>. Поле <code>contradiction</code> тоже названо, однако его state — <code>not-collected</code>. Это не бедность модели, а барьер против преждевременной логики. Пока сторона сравнения не определена, нельзя объявить противоречие и нельзя выбирать «исправление». Хорошая модель оставляет неизвестное неизвестным, а не заполняет его наиболее правдоподобным текстом.'),
table('Матрица механизма пересмотра', ['Слой', 'Вопрос будущего scope', 'Допустимое состояние P117', 'Недопустимая подмена'], [['Claim', 'Что потребуется проверить?', '<code>question-only</code>', 'Придуманная старая цитата'], ['Version / condition', 'К какой версии и области применим вопрос?', '<code>not-collected</code>', 'Версия из памяти или current page'], ['Contradiction', 'Что именно могло бы опровергнуть claim?', '<code>not-collected</code>', 'Новая формулировка как готовый вердикт'], ['Repro boundary', 'Какое наблюдение потребуется отдельно?', '<code>not-run / not-injected</code>', '«Тест уже подтвердил»'], ['Correction', 'Какой ответ будет допустим после оценки?', '<code>not-declared</code>', 'Статус исправлено или завершено']]),
h2('Опровержимость начинается с различающего вопроса'),
p('Фальсифицируемость в этом материале не означает выполнить тест ради красной ветки. Она означает заранее назвать различие между «условие неизвестно» и «есть наблюдение, которое в тех же условиях не согласуется с claim». Без этого различия будущий repro становится театром: любой результат можно объяснить сменой версии, а любая версия — объявить новым доказательством. P117 не строит метод прогона. Он сохраняет границу вопроса <code>future-falsification-repro-question-v1</code>, чтобы будущий scope не выдал первый удобный запуск за ответ.'),
p('На практике это означает четыре независимые проверки: имеется ли named claim; имеется ли named condition; pinned ли evidence; не впрыснут ли результат repro. Последняя особенно важна. Реалистичный объект с полем <code>claimed-reproduced</code> выглядит информативнее пустого объекта, но именно поэтому опасен. В плановом редакционном выпуске ему неоткуда взяться. Evaluator не пытается оценить правдоподобие результата и не выбирает частичное принятие: он останавливает весь hand-off. Такой fail-closed путь сохраняет возможность честного будущего исследования.'),
figure('/assets/editorial/2027/mistakes-revisions-2027-condition-correction-matrix.svg', 'Матрица P117 разделяет claim, condition, immutable evidence, contradiction, repro и correction; зелёный путь заканчивается только плановой передачей, а красные клетки показывают состояния, которые evaluator обязан остановить.', 'Матрица описывает синтетическую логику проверки формы. Она не сравнивает реальные версии, не воспроизводит поведение и не устанавливает противоречие старому совету.'),
h2('Runnable пример показывает только границу'),
p('Этот пример читает named fixed in-memory literal, встроенный в модуль. Он не получает параметры процесса, не парсит документацию и не сохраняет результат. Важно не подменять его тем, чем он не является: вызов <code>inspectAdviceBoundaryLiteral</code> не подтверждает, что какая-либо версия определена, а значение <code>not-run</code> не равно неудачному тесту. Это маркировка отсутствия запуска. Без этой маркировки читатель легко сделает противоположные, но одинаково необоснованные выводы: «всё доказано» или «всё уже опровергнуто».'),
code("import { inspectAdviceBoundaryLiteral } from './upgrade-2027-11.mjs';\n\nconst fixedBoundaryQuestion = inspectAdviceBoundaryLiteral();\nconsole.log({\n literal: fixedBoundaryQuestion.literal,\n evidencePin: fixedBoundaryQuestion.evidencePin,\n repro: fixedBoundaryQuestion.repro,\n result: fixedBoundaryQuestion.status,\n effect: fixedBoundaryQuestion.productionEffect,\n});"),
p('Названный literal не является шаблоном, который надо наполнить от руки в запущенном процессе. Evaluator принимает только exact known fixed records после JSON-сравнения. Любой объект с дополнительным полем, другой датой или «полезным» результатом выглядит неизвестным и получает <code>stop-unknown-fixed-literal</code> либо более узкий stop. Это намеренно консервативно: способность угадать дефолт — плохая замена provenance. Сначала появляется разрешённый источник и метод, затем новый scope создаёт отдельный артефакт.'),
h2('Почему mutable документ недостаточен'),
p('Текущая страница документации может быть полезна как ориентир, но не как надёжное доказательство пересмотра. Она способна поменяться после cutoff, переписать термин, скрыть прежнюю оговорку или вести на другую версию. В этой модели допустим только label <code>immutable-version-or-dated-snapshot</code>. Сам label не доказывает, что ссылка найдена; он лишь запрещает принять <code>mutable-current-document</code>. Разница кажется формальной до тех пор, пока поздний читатель не пытается восстановить, на чём держался вывод.'),
p('Не стоит противопоставлять pinned evidence и живую документацию как хорошее и плохое. У них разные роли. Живая страница помогает будущему исследованию понять текущий словарь; pinned материал позволяет сказать, что именно было доступно на обозначенной границе. P117 не собирает ни то ни другое и не устанавливает, что они расходятся. Он только требует не смешивать их в одной ячейке. Если future scope увидит несоответствие, это будет повод сформулировать новый вопрос, а не разрешение задним числом объявить исходный совет неверным.'),
h2('Порядок, который не производит ложный verdict'),
p('Механизм полезен, когда он делает отказ информативным. Stop по пустому condition не говорит «совет плохой»; он говорит «нельзя даже начать сравнение». Stop по mutable evidence не говорит «документация бесполезна»; он говорит «её изменяемость не даёт закрепить основание». Stop по injected repro не говорит «результат невозможен»; он говорит «этот план не имеет права его создавать». Благодаря таким различиям следующий scope получает точную причину, а не общий красный статус.'),
ol(['Зафиксировать temporal boundary P117 и не использовать текущие часы как замену editor date, plan date или cutoff.', 'Выделить one named claim question; не восстанавливать текст утверждения по памяти или из чужого пересказа.', 'Выделить one named condition question и оставить version/applicability неизвестными до отдельного сбора.', 'Потребовать evidence pin уровня immutable version или dated snapshot; mutable reference вернуть в stop без эвристики.', 'Записать contradiction как вопрос о различающем наблюдении, но не выполнять и не описывать repro внутри планового выпуска.', 'Оставить correction/outcome undeclared и передать статус hand-off только в новый разрешённый scope.']),
h2('Граница сравнения важнее количества деталей'),
p('Можно сделать карточку длиннее, добавив предполагаемые команды, поля ответа и пороги. До появления объекта это создаст не метод, а фиктивный протокол. Falsifiability требует не много пунктов, а одного различающего правила: какие условия должны быть сопоставимы, прежде чем наблюдение вообще имеет отношение к claim. P117 не определяет эти условия, поскольку не знает предмета; зато не разрешает спрятать их отсутствие за якобы уже выполненным repro.'),
p('Поэтому stop — не ошибка интерфейса evaluator-а. Он сохраняет точку, в которой требуется новая информация или новая авторизация. Система не заменяет missing condition строкой «default», не берёт актуальную веб-страницу вместо pinned reference и не превращает произвольный input в допустимый case. В будущем это может показаться неудобным, однако именно предсказуемый отказ делает версию, условие и противоречие независимыми объектами проверки.'),
h2('Ограничения механизма'),
p('Эта проверка не выполняет версионное сравнение, diff, HTTP-запрос, чтение файла, browser run, sandbox, тест, reproduction, поиск по архиву или доступ к внешней документации. Она не измеряет совместимость, не выбирает метод доказательства и не назначает владельца. Синтетический status не является quality gate реального продукта. Он подтверждает лишь то, что ограниченный fixed object не содержит заявленной версии, результата или коррекции. Именно поэтому его нельзя использовать как доказательство того, что будущая работа будет завершена.'),
p('Следующий шаг — открыть отдельный scope, только если нужен ответ на один из named вопросов. В нём следует выбрать версию или датированный снимок, описать сравнимые условия, назвать наблюдение, которое действительно могло бы опровергнуть claim, и отделить результат от решения о коррекции. До этого шага P117 не имеет factual verdict. Он сохраняет механизм, который не путает смену контекста с противоречием и не подделывает repro ради завершённости.'),
], commonRefs);
const field = revision({ slug: 'editorial-2027-11-field-mistakes-revisions', title: 'Пересмотр старых советов: корректирующая передача без ложного завершения', categories: ['Процессы', 'Практика'], cover: '/assets/editorial/2027/mistakes-revisions-2027-evidence-handoff-loop.svg', excerpt: 'План P117 на ноябрь 2027: как передать вопрос о возможной коррекции, не объявляя прошлый материал неправильным и не выдавая повторный тест за выполненный.', readingMinutes: 24 }, [
p('В поле самая дорогая ошибка пересмотра звучит убедительно: «старый материал надо признать неправильным и поправить». Такая формула сразу назначает виновника, действие и финал, хотя часто известен только вопрос о применимости. Цена — ложная коррекция попадает в очередь, читатель видит статус как доказательство, а будущая проверка уже вынуждена подгоняться под объявленный исход. Вместо короткого hand-off команда получает обязательство, которого никто не мог обосновать.'),
p('В P117 нет старой статьи, редакционной карточки, автора, владельца, репозитория, теста, прогона, review, публикации, исправления или production result. Все такие предметы существуют только как запрещённые для декларации future question fields. Нельзя сообщать, что old advice ошибочен, correction сделана или rerun завершён. Разрешён положительный результат только <code>synthetic-plan-hand-off</code> и только с <code>productionEffect: not-attempted</code>. Это не отказ от корректности; это отказ выдавать намерение за завершённую работу.'),
h2('Передаётся вопрос, а не приговор'),
p('Корректирующий hand-off начинается с минимальной карточки: есть named claim question, named condition question, named evidence question, named contradiction question и named repro question. Поля correction и handoff тоже названы, но имеют значения <code>not-declared</code>, <code>not-assigned</code> и <code>not-created</code>. Такая карточка не обещает, что кто-то возьмёт её в работу. Она позволяет честно сказать ровно одно: для будущего scope сформулирована граница вопроса, а предмет, доступ и решение ещё отсутствуют.'),
p('Это отличается от очереди. Очередь обычно подразумевает объект, приоритет, исполнителя и готовое действие. Здесь ни один из них не известен. Если заполнить recipient вымышленной ролью, hand-off станет видом назначения. Если назвать correction, он станет видом решения. Если указать outcome, он станет видом отчёта. Evaluator специально закрывает эти случаи, хотя они делают запись удобнее для чтения. Без такого запрета документ незаметно превратится из плана исследования в распоряжение о пересмотре.'),
table('Пакет корректирующей передачи', ['Часть пакета', 'Состояние в P117', 'Зачем оставлено так', 'Что не следует утверждать'], [['Question envelope', 'Named ids, <code>question-only</code>', 'Не смешивать предметы будущей оценки', 'Известна старая ошибка'], ['Evidence boundary', 'Pinned source требуется, state <code>not-collected</code>', 'Не опереться на меняющийся текст', 'Основание уже собрано'], ['Repro boundary', '<code>not-run / not-injected</code>', 'Не превратить план в результат прогона', 'Тест повторён и подтвердил вывод'], ['Correction', '<code>not-declared</code>', 'Оставить решение после оценки', 'Материал исправлен'], ['Recipient / handoff', '<code>not-assigned / not-created</code>', 'Не назначать человека или процесс', 'Есть владелец и работа передана']]),
h2('Разделите исправление, публикацию и эффект'),
p('Даже в настоящем проекте эти три слова не синонимы. Возможная коррекция — решение изменить формулировку или артефакт. Публикация — отдельное действие над определённым каналом. Effect — наблюдение после действия по заранее оговорённому критерию. P117 не имеет ни одного из этих входов, поэтому хранит correction и outcome как undeclared. Эта детализация нужна не ради бюрократии: если назвать effect в момент передачи, получатель уже не сможет отличить гипотезу пользы от полученного результата.'),
p('Особенно вредна фраза «повторный тест закончен». Она склеивает метод, среду, вход, наблюдение и интерпретацию в два слова. В plan/scenario нет права добавлять такой факт, даже как иллюстрацию. Поле <code>future-handoff-repro-question-v1</code> лишь резервирует тему будущей проверки. Его state <code>not-run</code> не указывает на сбой, задержку или отказ от работы; он фиксирует отсутствие запуска в этом пакете. Любой injected result — положительный или отрицательный — закрывает evaluator, потому что модель не читает внешние данные.'),
figure('/assets/editorial/2027/mistakes-revisions-2027-evidence-handoff-loop.svg', 'Петля передачи P117: named questions о claim, condition, evidence и repro идут к отдельному будущему scope; correction, recipient и outcome остаются undeclared, поэтому петля не заканчивается публикацией или production эффектом.', 'Диаграмма показывает границу корректирующей передачи. Она не отображает реального владельца, статью, тест, исправление, публикацию, проверку или достигнутый результат.'),
h2('Runnable пример не создаёт работу'),
p('Модуль ниже полностью self-contained. Named literal уже лежит в памяти и глубоко заморожен; функция возвращает компактное описание его статуса. Она не создаёт задачу, issue, комментарий, файл, письмо, уведомление, pull request или запись в очереди. Отсутствие I/O важно здесь больше, чем красивый workflow: учебная функция не должна иметь скрытого канала, через который «передача» станет настоящим организационным событием. Запуск показывает контракт отказа от ложного завершения, а не прогресс процесса.'),
code("import { inspectAdviceHandoffLiteral } from './upgrade-2027-11.mjs';\n\nconst fixedHandoffQuestion = inspectAdviceHandoffLiteral();\nconsole.log({\n literal: fixedHandoffQuestion.literal,\n correction: fixedHandoffQuestion.correction,\n recipient: fixedHandoffQuestion.recipient,\n result: fixedHandoffQuestion.status,\n effect: fixedHandoffQuestion.productionEffect,\n});"),
p('Здесь нет функции <code>assignOwner</code>, потому что её появление противоречило бы предмету статьи. Нельзя заменить отсутствующее полномочие красивым названием роли вроде «editor» или «maintainer»: имя само по себе уже объявляет адресата. Аналогично нельзя добавить <code>publish: false</code> и считать это безопасным моделированием публикации. Лучше вообще не создавать действие, чем создавать его тень и потом спорить, была ли она частью факта. P117 формирует только вопросную структуру и следующую границу авторизации.'),
h2('Коррекция может быть одним из будущих исходов, но не текущим статусом'),
p('Сохранение вопроса о коррекции не делает исход предрешённым. Future scope может обнаружить, что condition был неверно понят, evidence недостаточно, repro нерепрезентативен или claim вообще нельзя восстановить. В каждом случае правильным результатом может быть отсутствие коррекции. Эта возможность теряется, если initial hand-off уже говорит «исправить». Поэтому evaluator не принимает <code>declared-correct</code> и <code>declared-complete</code>: они превращают открытый вопрос в смоделированную победу без источника.'),
p('Обратная ошибка — считать отказ от verdict-а бездействием. Нет: hand-off содержит практический следующий шаг и точные stop reasons. Будущий исследователь узнаёт, чего не хватает: даты, имени claim, имени condition, immutable pin, чистого repro или undeclared correction. Такая точность сокращает повторную трактовку, не обещая результата. В отличие от общего «нужно разобраться», она задаёт минимальный вход для следующего решения и не делает вид, что этот вход уже получен.'),
h2('Что должен получить следующий scope'),
p('Получатель не обязан соглашаться с framing карточки. Он может вернуть её, если claim слишком широк, condition не даёт отделить режимы, источник нельзя закрепить или planned repro не различает альтернативы. Такой возврат не равен отказу от коррекции: он не позволяет потратить доверие читателя на преждевременный verdict. Для P117 это единственный полезный критерий hand-off — вопрос стал достаточно явным, чтобы его можно было отклонить по конкретной причине, а не по настроению.'),
p('В карточке сознательно нет поля «срочно». Срочность принадлежит отдельной ситуации с доступным объектом, риском и полномочием на решение. В future-only плане она лишь подталкивает автора назвать correction раньше evidence. Если впоследствии появится причина ускорить работу, она должна быть записана в новом артефакте с собственной датой и границей. Ноябрьский сценарий не может получить эту причину задним числом.'),
h2('Порядок корректирующей передачи'),
ol(['Зафиксировать, что P117 является future-only сценарием: editor date 2026-07-31, plan date 2027-11, source cutoff 2026-07-31.', 'Описать scope именованными question fields и не добавлять название, цитату или оценку несуществующего старого материала.', 'Проверить, что claim и condition имеют ids, а их содержание, версия и применимость остаются <code>not-collected</code>.', 'Оставить evidence неполученным и допустить только immutable version либо dated snapshot как будущую форму привязки.', 'Оставить repro в <code>not-run / not-injected</code>, correction/outcome — <code>not-declared</code>, recipient/handoff — <code>not-assigned / not-created</code>.', 'Передать <code>synthetic-plan-hand-off</code> как запрос на новый authorised scope, не как задачу, приказ, публикацию или подтверждённый результат.']),
h2('Ограничения и следующий шаг'),
p('P117 не проверяет факты о прошлых публикациях и не защищает читателя от всех неверных советов. Он не открывает архив, registry, README, articles.json, очередь, app, package, сеть, документацию, журнал тестов или production. Он не назначает owner, не ставит срок и не выбирает платформу для дальнейшей работы. Источники ниже нужны лишь для словаря происхождения, изменения конфигурации и точной записи даты. Они не утверждают, что в данном выпуске был совет, спор, коррекция или hand-off.'),
p('Следующий шаг должен быть маленьким и отдельно разрешённым: принять один named question field как предмет исследования, определить доступный immutable source, описать возможный repro без результата и только затем решить, нужна ли коррекция. Если полномочия, объект или evidence не появляются, корректный ответ — оставить hand-off не созданным. Это не незавершённость текста; это честная граница между планом и действием. P117 не объявляет старый материал ошибочным и не обещает, что повторный тест когда-либо будет завершён.'),
], commonRefs);
export const revisions = deepFreeze([practice, mechanism, field]);
if (process.argv.includes('--verify-fixture')) {
const result = runAdviceRevisionFixture();
if (!result.accepted) process.exitCode = 1;
process.stdout.write(`PASS fixture: ${result.passed}/${result.total} assertions\n`);
} else if (process.argv.includes('--print-revisions')) {
process.stdout.write(JSON.stringify(revisions, null, 2) + '\n');
}