diff --git a/editorial/production/README.md b/editorial/production/README.md index b6474fe..a2a836e 100644 --- a/editorial/production/README.md +++ b/editorial/production/README.md @@ -1,6 +1,6 @@ # Производство редакционных партий -На 31 июля 2026 года строгий аудит проходит 346 из 358 созданных материалов. Осталось 12 материалов, которые не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить. +На 31 июля 2026 года строгий аудит проходит 349 из 358 созданных материалов. Осталось 9 материалов, которые не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить. ## Одна партия diff --git a/editorial/reviews/2027-09-draft.md b/editorial/reviews/2027-09-draft.md new file mode 100644 index 0000000..a6078ce --- /dev/null +++ b/editorial/reviews/2027-09-draft.md @@ -0,0 +1,82 @@ +# P115 — September 2027: «Серия для инженера, который растёт» + +## Статус и граница + +Редакторская дата: **2026-07-31**. Период 2027-09 ещё не наступил; пакет является только **plan/scenario** с source cutoff **2026-07-31**. Он не сообщает о реальной учебной программе, репозитории, mentee, упражнении, review, feedback, прогрессе, owner, очереди или production effect. + +Модуль принимает только named fixed in-memory literals. Он не читает files, network, environment, clock, secrets, telemetry, system или data и не создаёт учебный процесс. Единственный accepted evaluator output — `synthetic-plan-hand-off`; в accepted и stop output всегда `productionEffect: not-attempted`. + +## Проход 1 — facts / temporal / voice + +| Статья | Body chars без sources | Угол | Временная граница | Источники и boundary | +| --- | ---: | --- | --- | --- | +| `editorial-2027-09-practice-mentor-series` | 9 227 | ситуация → synthetic prompt → критерий наблюдения | 2026-07-31 / 2027-09 / cutoff 2026-07-31 | RFC 2119 (March 1997) и RFC 8174 (May 2017), immutable IETF RFC; только нормативная лексика literal, не доказательство обучения | +| `editorial-2027-09-mechanism-mentor-series` | 9 169 | skill map, review loop, deliberate practice и falsifiability | та же | те же URL/version/date; не создают review, feedback, participant или model of learning | +| `editorial-2027-09-field-mentor-series` | 9 249 | hand-off самостоятельности и evidence без narrative | та же | те же URL/version/date; не назначают owner, процесс или персональную оценку | + +- Оба URL проверены `curl -I`: RFC 2119 и RFC 8174 вернули HTTP 200. Это первичные immutable RFC до cutoff. +- Первые два абзаца каждой статьи называют конкретную проблему и цену ошибки. У каждой статьи отдельные таблица, SVG, runnable safe example, упорядоченные действия, ограничения и следующий шаг. +- Голос 2025–2027: прагматичный техлидский разбор границ и стоимости. Нет общего мотивационного призыва, заявленного результата или фальшивого опыта. Deliberate practice используется только как ограничитель рассуждения, не как доказанная модель обучения. +- Фактологический verdict: **pass**. Temporal verdict: **pass**. Voice verdict: **pass**. + +## Проход 2 — literal safety / fail closed + +`mentor-series-plan-v1` принят только как `synthetic-plan-hand-off`. Factory делает JSON clone и recursive deep freeze; evaluator сравнивает input с known fixed literal. Неизвестный object не нормализуется. + +| Literal | Ожидаемый результат | Фактический результат | +| --- | --- | --- | +| `mentor-series-plan-v1` | `synthetic-plan-hand-off` | pass | +| `mentor-series-undated-v1` | `stop-temporal-boundary-required` | pass | +| `mentor-series-implicit-skill-v1` | `stop-unnamed-or-implicit-skill` | pass | +| `mentor-series-invented-review-v1` | `stop-invented-observation-review-feedback-or-progress` | pass | +| `mentor-series-invented-feedback-v1` | `stop-invented-observation-review-feedback-or-progress` | pass | +| `mentor-series-invented-outcome-v1` | `stop-invented-observation-review-feedback-or-progress` | pass | +| `mentor-series-invented-owner-v1` | `stop-invented-autonomy-owner-or-process` | pass | + +- Unnamed/implicit skill не допускается; `skillMap` и `exercise` обязаны быть exact named synthetic literals. +- Claimed observation, review, feedback, progress и outcome останавливаются. `autonomy: not-evaluated`, `recipient: not-assigned` и `process: not-created` не получают fallback. +- Fixture: **10/10** — 7/7 literal statuses и 3/3 article checks. `productionEffect: not-attempted` не является наблюдением о production. +- Safety/fail-closed verdict: **pass**. + +## Проход 3 — visual / mobile / a11y / safety + strict duplicate scan + +- Каждый SVG содержит русские `title` и `desc`; каждая статья содержит отдельные русские `alt` и `figcaption`. SVG поясняют контракт карты, матрицу review и петлю hand-off, а не выступают декоративной иллюстрацией. +- `xmllint --noout` прошёл для трёх assets. Safety scan на `script`, `foreignObject`, `javascript:`, `data:image` и event-handler attributes — empty/pass. +- Sharp создал 3 PNG `375x225`; они открыты вручную. На mobile читаемы: карта удерживает три состояния и stop, matrix — все три колонки и пять строк, hand-off — четыре gate и красный stop. Обрезаний или наложений не обнаружено. +- `npm run audit:draft -- scripts/upgrade-2027-09.mjs` — pass по трём exact slug и lengths 9 227 / 9 169 / 9 249. +- Строгий duplicate scan исключал section `Проверяемые источники`, но включал `

` и `

`; runnable code участвовал. Прочитаны P102–P114: 39 prior articles, 120 comparisons (117 current-to-prior + 3 внутрипакетные), `hits: []`; совпадений exact paragraphs длиной 160+ и common 12-word fragments нет.
+- Visual/mobile/a11y/safety verdict: **pass**. Duplicate scan verdict: **pass**.
+
+## Фактически выполненные команды
+
+```sh
+cd web
+node --check scripts/upgrade-2027-09.mjs
+node scripts/upgrade-2027-09.mjs --verify-fixture
+npm run audit:draft -- scripts/upgrade-2027-09.mjs
+xmllint --noout public/assets/editorial/2027/mentor-series-2027-skill-map-contract.svg public/assets/editorial/2027/mentor-series-2027-practice-review-matrix.svg public/assets/editorial/2027/mentor-series-2027-autonomy-handoff-loop.svg
+rg -n -i '<(script|foreignObject)\b|javascript:|data:image|(?:^|[[:space:]])on[a-z]+=' public/assets/editorial/2027/mentor-series-2027-skill-map-contract.svg public/assets/editorial/2027/mentor-series-2027-practice-review-matrix.svg public/assets/editorial/2027/mentor-series-2027-autonomy-handoff-loop.svg
+node --input-type=module -e 'import sharp from "sharp"; /* three SVG → 375px PNG */'
+curl -I https://www.rfc-editor.org/rfc/rfc2119.html
+curl -I https://www.rfc-editor.org/rfc/rfc8174.html
+```
+
+## Disposition
+
+Изменены только пять разрешённых файлов P115:
+
+- `web/scripts/upgrade-2027-09.mjs`
+- `editorial/reviews/2027-09-draft.md`
+- `web/public/assets/editorial/2027/mentor-series-2027-skill-map-contract.svg`
+- `web/public/assets/editorial/2027/mentor-series-2027-practice-review-matrix.svg`
+- `web/public/assets/editorial/2027/mentor-series-2027-autonomy-handoff-loop.svg`
+
+Registry, README, очередь, `articles.json`, app и чужие пакеты не изменялись этой работой. Git не использовался.
+
+## Независимое приёмочное ревью
+
+- Первичные источники повторно открыты 2026-07-31: RFC 2119 подтверждает статус BCP и дату March 1997, RFC 8174 — статус BCP, дату May 2017 и уточнение смысла заглавных ключевых слов. В статьях они применены только к точности требований к literal; они не используются как источник об обучении или оценке человека.
+- Повторно выполнены `node --check`, fixture (**10/10**), `npm run audit:draft` и три runnable-примера. Проверены их фактические outputs: они выводят только synthetic literals и `synthetic-plan-hand-off`; внешнего ввода и побочных действий нет.
+- Три SVG прошли XML/safety scan и открыты после рендера Sharp в ширине 375 px. Текст, стрелки, stop-ветки и подписи читаемы; декоративных или небезопасных элементов нет.
+- Строгий повторный duplicate scan P102–P115: **42 статьи**, **861 сравнение**, sources исключены, code включён, common 12-word fragments — `[]`.
+- Приёмочный verdict: **pass**. Пакет включён в registry как 347–349-й материал; production build и публикация выполняются после общей проверки интеграции.
diff --git a/web/data/editorial-revisions.mjs b/web/data/editorial-revisions.mjs
index 3da4bad..e24154b 100644
--- a/web/data/editorial-revisions.mjs
+++ b/web/data/editorial-revisions.mjs
@@ -111,6 +111,7 @@ import { revisions as may2027Revisions } from '../scripts/upgrade-2027-05.mjs';
 import { revisions as june2027Revisions } from '../scripts/upgrade-2027-06.mjs';
 import { revisions as july2027Revisions } from '../scripts/upgrade-2027-07.mjs';
 import { revisions as august2027Revisions } from '../scripts/upgrade-2027-08.mjs';
+import { revisions as september2027Revisions } from '../scripts/upgrade-2027-09.mjs';
 
 // This layer replaces archived source entries without losing their stable slug and date.
 export const editorialRevisions = [
@@ -227,4 +228,5 @@ export const editorialRevisions = [
   ...june2027Revisions,
   ...july2027Revisions,
   ...august2027Revisions,
+  ...september2027Revisions,
 ];
diff --git a/web/public/assets/editorial/2027/mentor-series-2027-autonomy-handoff-loop.svg b/web/public/assets/editorial/2027/mentor-series-2027-autonomy-handoff-loop.svg
new file mode 100644
index 0000000..adffd90
--- /dev/null
+++ b/web/public/assets/editorial/2027/mentor-series-2027-autonomy-handoff-loop.svg
@@ -0,0 +1,16 @@
+
+  Петля передачи самостоятельности
+  Схема показывает проверку дат, именованного literal и отсутствия evidence. Назначенный владелец или claimed feedback останавливают проверку; допустимый результат передаёт только неоценённую самостоятельность.
+  
+  Hand-off без назначения и выдуманного feedback
+  
+    Даты2026-07-31 / 2027-09
+    Literalnamed synthetic only
+    Evidencenot-collected
+    Hand-offnot-evaluated
+    
+    owner assigned или feedback claimed → stopprocess остаётся not-created, recipient — not-assigned
+    
+  
+  
+
diff --git a/web/public/assets/editorial/2027/mentor-series-2027-practice-review-matrix.svg b/web/public/assets/editorial/2027/mentor-series-2027-practice-review-matrix.svg
new file mode 100644
index 0000000..61d4dae
--- /dev/null
+++ b/web/public/assets/editorial/2027/mentor-series-2027-practice-review-matrix.svg
@@ -0,0 +1,13 @@
+
+  Матрица статусов practice и review
+  Таблица показывает, что prompt не запущен, а observation, review, feedback и progress не собраны или не заявлены. Любое claimed значение прекращает проверку.
+  
+  Practice / review: что известно literal, а что нет
+  
+    
+    ПолеСтатус P115Claimed значение
+    
+    Promptnot-runне доказывает выполнениеObservationnot-collectedstopReviewnot-collectedstopFeedbacknot-collectedstopProgressnot-claimedstop
+    Нет reviewer, mentee, feedback, outcome или учебного процесса
+  
+
diff --git a/web/public/assets/editorial/2027/mentor-series-2027-skill-map-contract.svg b/web/public/assets/editorial/2027/mentor-series-2027-skill-map-contract.svg
new file mode 100644
index 0000000..5a1fc20
--- /dev/null
+++ b/web/public/assets/editorial/2027/mentor-series-2027-skill-map-contract.svg
@@ -0,0 +1,31 @@
+
+  Контракт синтетической карты навыка
+  Три карточки показывают именованную карту, не запущенный prompt и отсутствие наблюдения. Красная ветка останавливает неявное умение.
+  
+  Карта навыка — контракт, не оценка человека
+  P115 · plan/scenario · 2027-09 · только fixed in-memory literal
+  
+    
+    Карта
+    synthetic-skill-map
+    named-synthetic-only
+    
+    Prompt
+    synthetic-practice
+    not-run
+    
+    Наблюдение
+    observation
+    not-collected
+    
+    
+    synthetic-plan-hand-off
+    productionEffect: not-attempted
+    
+    
+    implicit
+    skill → stop
+    
+  
+  
+
diff --git a/web/scripts/upgrade-2027-09.mjs b/web/scripts/upgrade-2027-09.mjs
new file mode 100644
index 0000000..0fc9dba
--- /dev/null
+++ b/web/scripts/upgrade-2027-09.mjs
@@ -0,0 +1,166 @@
+const escapeHtml = (value) => String(value).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
+const p = (text) => `

${text}

`; +const h2 = (text) => `

${text}

`; +const code = (text) => `
${escapeHtml(text)}
`; +const ol = (items) => `
    ${items.map((item) => `
  1. ${item}
  2. `).join('')}
`; +const figure = (src, alt, caption) => `
${alt}
${caption}
`; +const table = (caption, headers, rows) => `
${headers.map((cell) => ``).join('')}${rows.map((row) => `${row.map((cell) => ``).join('')}`).join('')}
${caption}
${cell}
${cell}
`; + +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>[\s\S]*$/, '')); } + +const REFERENCES = deepFreeze({ + rfc2119: { title: 'RFC 2119 — Key words for use in RFCs to Indicate Requirement Levels', url: 'https://www.rfc-editor.org/rfc/rfc2119.html', version: 'IETF, March 1997, RFC 2119, immutable RFC publication' }, + rfc8174: { title: 'RFC 8174 — Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words', url: 'https://www.rfc-editor.org/rfc/rfc8174.html', version: 'IETF, May 2017, RFC 8174, immutable RFC publication' }, +}); +function sources(entries) { return ``; } + +const FIXED_MENTOR_LITERALS = deepFreeze({ + 'mentor-series-plan-v1': { id: 'mentor-series-plan-v1', editorialDate: '2026-07-31', planningIssue: '2027-09', sourceCutoff: '2026-07-31', skillMap: { id: 'synthetic-skill-map-literal-v1', state: 'named-synthetic-only' }, exercise: { id: 'synthetic-practice-prompt-v1', state: 'not-run' }, evidence: { observation: 'not-collected', review: 'not-collected', feedback: 'not-collected', progress: 'not-claimed' }, handoff: { autonomy: 'not-evaluated', recipient: 'not-assigned', process: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off' }, + 'mentor-series-undated-v1': { id: 'mentor-series-undated-v1', editorialDate: '', planningIssue: '2027-09', sourceCutoff: '2026-07-31', skillMap: { id: 'synthetic-skill-map-literal-v1', state: 'named-synthetic-only' }, exercise: { id: 'synthetic-practice-prompt-v1', state: 'not-run' }, evidence: { observation: 'not-collected', review: 'not-collected', feedback: 'not-collected', progress: 'not-claimed' }, handoff: { autonomy: 'not-evaluated', recipient: 'not-assigned', process: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off' }, + 'mentor-series-implicit-skill-v1': { id: 'mentor-series-implicit-skill-v1', editorialDate: '2026-07-31', planningIssue: '2027-09', sourceCutoff: '2026-07-31', skillMap: { id: '', state: 'implicit' }, exercise: { id: 'synthetic-practice-prompt-v1', state: 'not-run' }, evidence: { observation: 'not-collected', review: 'not-collected', feedback: 'not-collected', progress: 'not-claimed' }, handoff: { autonomy: 'not-evaluated', recipient: 'not-assigned', process: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off' }, + 'mentor-series-invented-review-v1': { id: 'mentor-series-invented-review-v1', editorialDate: '2026-07-31', planningIssue: '2027-09', sourceCutoff: '2026-07-31', skillMap: { id: 'synthetic-skill-map-literal-v1', state: 'named-synthetic-only' }, exercise: { id: 'synthetic-practice-prompt-v1', state: 'not-run' }, evidence: { observation: 'not-collected', review: 'claimed', feedback: 'not-collected', progress: 'not-claimed' }, handoff: { autonomy: 'not-evaluated', recipient: 'not-assigned', process: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off' }, + 'mentor-series-invented-feedback-v1': { id: 'mentor-series-invented-feedback-v1', editorialDate: '2026-07-31', planningIssue: '2027-09', sourceCutoff: '2026-07-31', skillMap: { id: 'synthetic-skill-map-literal-v1', state: 'named-synthetic-only' }, exercise: { id: 'synthetic-practice-prompt-v1', state: 'not-run' }, evidence: { observation: 'not-collected', review: 'not-collected', feedback: 'claimed', progress: 'not-claimed' }, handoff: { autonomy: 'not-evaluated', recipient: 'not-assigned', process: 'not-created' }, requestedOutput: 'synthetic-plan-hand-off' }, + 'mentor-series-invented-outcome-v1': { id: 'mentor-series-invented-outcome-v1', editorialDate: '2026-07-31', planningIssue: '2027-09', sourceCutoff: '2026-07-31', skillMap: { id: 'synthetic-skill-map-literal-v1', state: 'named-synthetic-only' }, exercise: { id: 'synthetic-practice-prompt-v1', state: 'not-run' }, evidence: { observation: 'not-collected', review: 'not-collected', feedback: 'not-collected', progress: 'claimed' }, handoff: { autonomy: 'not-evaluated', recipient: 'not-assigned', process: 'not-created' }, requestedOutput: 'learning-improved' }, + 'mentor-series-invented-owner-v1': { id: 'mentor-series-invented-owner-v1', editorialDate: '2026-07-31', planningIssue: '2027-09', sourceCutoff: '2026-07-31', skillMap: { id: 'synthetic-skill-map-literal-v1', state: 'named-synthetic-only' }, exercise: { id: 'synthetic-practice-prompt-v1', state: 'not-run' }, evidence: { observation: 'not-collected', review: 'not-collected', feedback: 'not-collected', progress: 'not-claimed' }, handoff: { autonomy: 'not-evaluated', recipient: 'assigned', process: 'created' }, requestedOutput: 'synthetic-plan-hand-off' }, +}); + +export function createMentorSeriesLiteral(id = 'mentor-series-plan-v1') { const value = FIXED_MENTOR_LITERALS[id]; return value ? deepFreeze(cloneFixed(value)) : undefined; } +function stop(status, reason, nextAction) { return deepFreeze({ status, reason, nextAction, productionEffect: 'not-attempted' }); } +export function assessMentorSeriesPlan(input) { + const known = Object.values(FIXED_MENTOR_LITERALS).some((item) => JSON.stringify(item) === JSON.stringify(input)); + if (!known) return stop('stop-unknown-fixed-literal', 'input-is-not-a-known-named-fixed-literal', 'select-a-named-fixed-literal'); + if (input.editorialDate !== '2026-07-31' || input.planningIssue !== '2027-09' || input.sourceCutoff !== '2026-07-31') return stop('stop-temporal-boundary-required', 'editorial-date-planning-issue-and-source-cutoff-must-be-exact', 'restore-the-fixed-temporal-boundary'); + if (input.skillMap.id !== 'synthetic-skill-map-literal-v1' || input.skillMap.state !== 'named-synthetic-only' || input.exercise.id !== 'synthetic-practice-prompt-v1' || input.exercise.state !== 'not-run') return stop('stop-unnamed-or-implicit-skill', 'skill-map-and-exercise-must-be-named-fixed-synthetic-literals', 'restore-the-named-fixed-literal'); + if (input.evidence.observation !== 'not-collected' || input.evidence.review !== 'not-collected' || input.evidence.feedback !== 'not-collected' || input.evidence.progress !== 'not-claimed') return stop('stop-invented-observation-review-feedback-or-progress', 'learning-evidence-cannot-be-inferred-or-claimed', 'remove-the-invented-learning-claim'); + if (input.handoff.autonomy !== 'not-evaluated' || input.handoff.recipient !== 'not-assigned' || input.handoff.process !== 'not-created') return stop('stop-invented-autonomy-owner-or-process', 'autonomy-owner-and-training-process-cannot-be-created-by-a-plan', 'keep-handoff-unassigned-and-uncreated'); + if (input.requestedOutput !== 'synthetic-plan-hand-off') return stop('stop-disallowed-positive-result', 'future-plan-cannot-claim-learning-or-production-result', 'use-synthetic-plan-hand-off'); + return deepFreeze({ status: 'synthetic-plan-hand-off', literalId: input.id, planningIssue: input.planningIssue, skillMap: deepFreeze(cloneFixed(input.skillMap)), exercise: deepFreeze(cloneFixed(input.exercise)), evidence: deepFreeze(cloneFixed(input.evidence)), handoff: deepFreeze(cloneFixed(input.handoff)), productionEffect: 'not-attempted', nextAction: 'open-a-separate-authorized-scope-only-if-evidence-is-needed-for-a-decision' }); +} +export function inspectPracticeLiteral() { const input = createMentorSeriesLiteral(); const output = assessMentorSeriesPlan(input); return deepFreeze({ skillMap: input.skillMap.id, exercise: input.exercise.state, observation: input.evidence.observation, status: output.status, productionEffect: output.productionEffect }); } +export function inspectMechanismLiteral() { const input = createMentorSeriesLiteral(); return deepFreeze({ map: input.skillMap.state, review: input.evidence.review, feedback: input.evidence.feedback, status: assessMentorSeriesPlan(input).status }); } +export function inspectFieldLiteral() { const output = assessMentorSeriesPlan(createMentorSeriesLiteral()); return deepFreeze({ autonomy: output.handoff.autonomy, recipient: output.handoff.recipient, process: output.handoff.process, status: output.status }); } +export function runMentorSeriesFixture() { + const expected = [['mentor-series-plan-v1', 'synthetic-plan-hand-off'], ['mentor-series-undated-v1', 'stop-temporal-boundary-required'], ['mentor-series-implicit-skill-v1', 'stop-unnamed-or-implicit-skill'], ['mentor-series-invented-review-v1', 'stop-invented-observation-review-feedback-or-progress'], ['mentor-series-invented-feedback-v1', 'stop-invented-observation-review-feedback-or-progress'], ['mentor-series-invented-outcome-v1', 'stop-invented-observation-review-feedback-or-progress'], ['mentor-series-invented-owner-v1', 'stop-invented-autonomy-owner-or-process']]; + const checks = expected.map(([id, status]) => ({ id, expected: status, actual: assessMentorSeriesPlan(createMentorSeriesLiteral(id)).status })); + const sample = createMentorSeriesLiteral(); + return deepFreeze({ passed: checks.filter((item) => item.expected === item.actual).length, total: checks.length, accepted: checks.every((item) => item.expected === item.actual) && Object.isFrozen(sample) && Object.isFrozen(sample.skillMap) && Object.isFrozen(sample.evidence) && Object.isFrozen(sample.handoff), 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 refs = [ + { key: 'rfc2119', use: 'Задаёт фиксированный нормативный словарь для различения обязательного правила literal и необязательной будущей работы.', boundary: 'Не описывает обучение, компетенцию, review, feedback или результат человека.' }, + { key: 'rfc8174', use: 'Фиксирует, когда заглавные требования читаются нормативно; помогает не маскировать запрет как пожелание.', boundary: 'Не создаёт учебную программу, владельца, упражнение или evidence.' }, +]; + +const practice = revision({ slug: 'editorial-2027-09-practice-mentor-series', title: 'Серия для инженера, который растёт: упражнение как контракт наблюдения', categories: ['Наставничество', 'Развитие'], cover: '/assets/editorial/2027/mentor-series-2027-skill-map-contract.svg', excerpt: 'План на сентябрь 2027: как описать упражнение и наблюдаемый критерий без истории о человеке и без вымышленного результата.', readingMinutes: 24 }, [ + p('P115 — редакционный сценарий на сентябрь 2027, составленный 2026-07-31. В теме роста инженера дорогая ошибка начинается с невинной формулы: «дадим задачу, потом будет понятно». В такой фразе уже спрятаны навык, участник, выполнение и оценка. Если их не отделить, документ выглядит как учебная практика, хотя у него нет ни человека, ни запуска, ни наблюдения. Цена — следующий читатель принимает план за свидетельство того, что кто-то чему-то научился.'), + p('Вторая цена — заменить критерий готовности тёплым советом. Слова «разобрался», «стал самостоятельнее» и «получил обратную связь» звучат полезно, но в будущем сценарии это не факты. У P115 нет mentee, реального упражнения, review, feedback, навыкового прогресса, owner, репозитория или production effect. Разрешён один положительный evaluator output: synthetic-plan-hand-off с productionEffect: not-attempted. Всё остальное должно остаться неутверждённым.'), + h2('Упражнение не равно выполненной работе'), + p('Практический артефакт здесь — не задание человеку, а fixed literal в памяти. Он называет synthetic-practice-prompt-v1 и связывает его с synthetic-skill-map-literal-v1. Название намеренно синтетическое: оно не содержит технологии, домена, входа, времени выполнения или ожидаемого поведения. Такое ограничение убирает самый частый самообман: правдоподобный пример начинают читать как фрагмент настоящей программы.'), + p('Наблюдаемый критерий тоже не надо дорисовывать. В живой работе критерий отвечает на вопрос, что именно можно увидеть в сохранённом артефакте: правило, тест, объяснение границы, выбор между вариантами. В P115 нет артефакта и нет наблюдения, поэтому поле имеет значение not-collected. Оно не обозначает плохое выполнение; оно запрещает делать вывод о выполнении. Разница нужна, чтобы будущая проверка могла начаться с нуля, а не с чужого оптимистичного резюме.'), + table('Контракт планового упражнения', ['Часть', 'Значение P115', 'Вывод, который запрещён'], [['Карта', 'synthetic-skill-map-literal-v1', 'Список реальных навыков'], ['Prompt', 'synthetic-practice-prompt-v1', 'Упражнение было выдано или выполнено'], ['Наблюдение', 'not-collected', 'Есть критерий, результат или оценка'], ['Review и feedback', 'not-collected', 'Кто-то прочитал работу или ответил'], ['Эффект', 'not-attempted', 'Изменение production или компетенции']]), + h2('Ситуация, действие и наблюдаемая граница'), + p('Ситуация в статье должна быть узкой: известен только будущий редакционный выпуск, а не учебный контекст. Поэтому нельзя подменить её рассказом о новичке, очереди задач или известном затруднении. Действие также ограничено: модуль создаёт копию named literal, глубоко замораживает её и сравнивает с конечным набором разрешённых literals. Он не читает files, network, environment, clock, secrets, telemetry, system или data. Он не создаёт курс и не отправляет никому задачу.'), + p('Критерий наблюдаемости здесь механический. Запуск допустим, если exported function возвращает плановый hand-off; запуск не является наблюдением человека. Если передать literal с пустым skill id, evaluator останавливается. Если в evidence появится claimed, он тоже останавливается. Это полезнее, чем красивый checklist: контракт показывает, что нельзя получить положительный narrative из отсутствующего входа. Отрицательная ветка должна быть такой же видимой, как единственная accepted ветка.'), + figure('/assets/editorial/2027/mentor-series-2027-skill-map-contract.svg', 'Карта контракта: именованная синтетическая карта и не запущенный prompt ведут к отсутствию наблюдения; любое неявное умение останавливает evaluator.', 'Схема показывает правило формы для будущего планового материала. Она не описывает человека, учебный маршрут, выполненное упражнение или развитие навыка.'), + h2('Runnable пример проверяет форму, а не рост'), + p('Пример можно запустить в Node рядом с модулем. Он работает только с зашитым literal, не принимает ввод и не получает контекст процесса. В stdout попадут названия полей, а не оценка. Такой пример безопасен для статьи: читатель может увидеть контракт, но не получит ложного образца review или результата. Не добавляйте в него путь к проекту, имя роли или правдоподобный payload: каждая такая деталь превращает форму в вымышленную историю.'), + code("import { inspectPracticeLiteral } from './upgrade-2027-09.mjs';\n\nconst literal = inspectPracticeLiteral();\nconsole.log(literal.skillMap, literal.exercise, literal.status);\n// synthetic-skill-map-literal-v1 not-run synthetic-plan-hand-off"), + h2('Порядок действий для будущего scope'), + ol(['Зафиксировать три даты: editorial date 2026-07-31, плановый выпуск 2027-09 и source cutoff 2026-07-31.', 'Выбрать только named fixed in-memory literal; не добавлять неявное умение, технологию или человека.', 'Оставить prompt в not-run, а observation, review и feedback в not-collected.', 'Запустить fixture с accepted literal и отрицательными literals; stop должен быть результатом проверки, а не warning.', 'Если решение действительно требует упражнения, открыть отдельный authorized scope с собственным предметом, участниками и правилами evidence.', 'Хранить любой новый факт в новом артефакте; не переписывать им плановый P115.']), + h2('Почему намеренная практика не даёт права на историю'), + p('Выражение deliberate practice удобно, когда им называют повторяемое действие с заранее заданной границей проверки. Оно опасно, когда из него сразу выводят рост человека. Между действием и таким выводом лежат контекст, повтор, наблюдение, интерпретация и согласие участника. В P115 ни один слой не существует. Поэтому статья обсуждает структуру вопроса, а не модель обучения и не обещает, что строгий критерий сделает инженера сильнее.'), + p('Нормативные RFC ниже применяются ограниченно: они дают дисциплину слов «должен» и «не должен» в контракте evaluator. Они не становятся педагогической методикой. Требование not-collected относится к полю literal, а не к поведению реального человека. Это различение сохраняет текст техническим: мы объясняем, как не создать ложный факт, а не как управлять чужим развитием.'), + h2('Как читать критерий без подмены результата'), + p('Полезно разложить слово «критерий» на три разные вещи. Первая — форма будущего наблюдения: например, запись в отдельном артефакте могла бы показать ход рассуждения. Вторая — правило интерпретации: кто-то должен был бы решить, что эта запись относится к заявленному вопросу. Третья — последствие решения: оно могло бы повлиять на следующий scope. В P115 нет ни одной из трёх вещей. Есть только запрет считать их уже существующими. Поэтому evaluator не хранит score, шкалу и порог: они создали бы видимость измерения без предмета.'), + p('Это особенно важно для инженерных упражнений, где код кажется достаточным доказательством. Код может компилироваться и всё равно не объяснять границу, по которой был сделан выбор. Объяснение может быть аккуратным и всё равно не иметь отношения к реальной задаче. Пока scope не назвал предмет и способ проверки, нельзя выбрать даже вид артефакта. Синтетический prompt не является пробелом, который нужно заполнить примером; он удерживает отсутствие примера как факт формы.'), + p('Вместо слов «проверить понимание» лучше записывать, какую именно недоказанную связь надо не утверждать. Здесь связь между named skill map и человеческим действием отсутствует. Вторая отсутствующая связь — между действием и review. Третья — между review и progress. Если diagram или текст перескакивает через одну связь, он производит утверждение сильнее входа. Так возникает безопасный редакторский тест: каждое усиление должно иметь самостоятельный источник, а не соседнее поле literal.'), + p('Практичный компромисс не в том, чтобы добавить больше статусов. Длинная анкета быстро создаст видимость контроля. Лучше оставить несколько отрицательных значений и сделать их проверяемыми: не собранное наблюдение, не запущенный prompt, не заявленный progress. Они читаются хуже, чем история успеха, зато не требуют читателю угадывать, что произошло. Модуль сохраняет это свойство, потому что неизвестный object не нормализуется, а немедленно останавливается.'), + p('Есть полезная проверка формулировки: убрать имя hypothetical участника и спросить, остался ли у предложения наблюдаемый объект. Если после удаления остаётся только «стало лучше», это не критерий. Если остаётся literal, его status и правило stop, текст ещё можно проверить запуском. Такой тест не заменяет будущую работу с человеком; он отделяет редакционный контракт от неё. Для планового месяца это достаточный, но намеренно ограниченный результат.'), + p('Если будущий scope всё же определит упражнение, ему не нужно доказывать правоту P115. Он начнёт со своей постановки и может отказаться от этой терминологии. Это снижает стоимость hand-off: исходный план не привязывает людей к чужому сценарию. Важно сохранить именно такую обратимость. Редакционная серия о росте полезна только тогда, когда не превращает отсутствие контекста в долг пройти заранее написанный маршрут.'), + h2('Ограничения и следующий шаг'), + p('Этот материал не является учебной программой, rubric, назначением, review guide или оценкой. В нём нет критериев найма, времени, сложности, codebase, mentor и ожидаемого темпа. Он не говорит, что отсутствие наблюдения хорошо или плохо. Его предел проще: пока нет отдельного разрешённого контекста, у пакета есть только named synthetic literal и fail-closed evaluator.'), + p('Следующий шаг узкий: если конкретное решение потребует evidence, создать отдельный scope и явно описать, какие inputs разрешены, кто может участвовать, что считается отсутствием результата и как не переносить выводы в production. До этого P115 завершается только synthetic-plan-hand-off; productionEffect: not-attempted говорит о состоянии evaluator, а не о внешнем мире.'), +], refs); + +const mechanism = revision({ slug: 'editorial-2027-09-mechanism-mentor-series', title: 'Серия для инженера, который растёт: карта навыка без неподтверждённого вывода', categories: ['Наставничество', 'Развитие'], cover: '/assets/editorial/2027/mentor-series-2027-practice-review-matrix.svg', excerpt: 'План на сентябрь 2027: как различать skill map, review loop и фальсифицируемое утверждение без вымышленной обратной связи.', readingMinutes: 25 }, [ + p('P115 — сценарий на 2027-09 с редакторской датой 2026-07-31. Самая дорогая ошибка механизма роста — назвать карту навыков объяснением того, что человек умеет. Таблица с уровнями, review loop и аккуратными названиями быстро выглядит как доказательство: будто навык выбран, упражнение состоялось и вывод уже проверен. Цена — решение о следующем действии строится на схеме, а не на разрешённом evidence.'), + p('Вторая ошибка дороже потому, что скрыта в слове feedback. Оно часто соединяет действие, наблюдение и оценку одним жестом. В будущем plan нельзя утверждать review, feedback, outcome или progress, даже если они выглядят правдоподобно. У P115 есть только fixed literal и его статусы not-run, not-collected, not-claimed. Единственный positive output — synthetic-plan-hand-off; productionEffect остаётся not-attempted.'), + h2('Карта навыка — это контракт слов, не модель человека'), + p('Skill map полезна, когда делает явными элементы, которые нельзя подставить друг за друга. В этом выпуске map — строка synthetic-skill-map-literal-v1. Она не именует реальную компетенцию и не имеет уровней. Такое минимальное представление выглядит бедно, но оно проверяемо: evaluator знает ровно одно допустимое значение. Любая пустая строка, другое имя или implicit state завершается stop-unnamed-or-implicit-skill.'), + p('Фальсифицируемость здесь не означает, что мы тестируем личность. Это свойство утверждения о пакете: у него должен быть вход, который его опровергает. Для заявленного review таким входом служит отсутствие review в literal. Для заявленного прогресса — not-claimed. Если код позволил бы заменить эти статусы на удобные слова, план перестал бы быть ограниченным сценарием. Механизм ценен тем, что показывает stop, а не тем, что производит впечатление оценки.'), + table('Матрица утверждений и допустимых оснований', ['Утверждение', 'Состояние P115', 'Поведение evaluator'], [['Карта названа', 'named-synthetic-only', 'Принимает только точное literal-имя'], ['Prompt состоялся', 'not-run', 'Не выводит выполнение'], ['Есть review', 'not-collected', 'Останавливает claimed review'], ['Есть feedback', 'not-collected', 'Останавливает claimed feedback'], ['Есть прогресс', 'not-claimed', 'Останавливает положительный outcome']]), + h2('Review loop без придуманных участников'), + p('Обычно loop рисуют стрелками: задача, попытка, review, correction, новый цикл. Такая схема опасна в будущем выпуске: она визуально сообщает, что цикл уже существует. В P115 стрелки означают только логическое условие. Между not-run и not-collected нет передачи работы; между review и feedback нет роли; между feedback и progress нет причинной связи. Мы сохраняем названия полей, чтобы запретить их подмену, а не чтобы описать процесс.'), + p('Эта строгость не спорит с полезностью review в реальной инженерной работе. Она разделяет два уровня: будущий scope вправе когда-нибудь задать процесс, а текущий сценарий не имеет права заявить, что процесс уже создан. Поэтому process: not-created важнее, чем любая привлекательная диаграмма цикла. Значение не говорит «процесс плох»; оно говорит «этот модуль его не создаёт». Так контракт удерживает границу ответственности кода.'), + figure('/assets/editorial/2027/mentor-series-2027-practice-review-matrix.svg', 'Матрица review: карта и prompt имеют только синтетические статусы, а observation, review, feedback и progress остаются не собранными; claimed значение идёт в stop.', 'Матрица не показывает выполненный цикл, reviewer, feedback или изменение навыка. Она объясняет fail-closed правило будущего планового literal.'), + h2('Runnable проверка отрицательных веток'), + p('Следующий код возвращает только поля named literal. Он не читает репозиторий, filesystem, окружение, часы, сеть, секреты, телеметрию или системные данные. Он не получает пользователя и не создаёт очередь review. Запуск поэтому не подтверждает модель learning; он проверяет, что статусы не становятся положительными по умолчанию. Для реального evidence нужны другой scope, отдельная авторизация и собственные правила хранения.'), + code("import { inspectMechanismLiteral } from './upgrade-2027-09.mjs';\n\nconst state = inspectMechanismLiteral();\nconsole.log(state.map, state.review, state.feedback, state.status);\n// named-synthetic-only not-collected not-collected synthetic-plan-hand-off"), + h2('Порядок механической проверки'), + ol(['Проверить, что вход создан только factory и совпадает с одним named fixed literal.', 'Проверить даты; отсутствие одной даты не должно получать default.', 'Проверить skill map и prompt отдельно: имя и state должны быть точными, а prompt — not-run.', 'Передать literals с claimed review, feedback и progress и потребовать stop-status.', 'Проверить, что accepted output не содержит оценки, owner, process или production result.', 'Открывать новый scope только тогда, когда решение требует реальных evidence, а не для украшения карты.']), + h2('Где deliberate practice заканчивается'), + p('Термин deliberate practice можно использовать как имя намеренно ограниченного повторяемого действия. Но из одного действия нельзя вывести обучение, самостоятельность или качество решения. Даже в настоящем процессе понадобились бы предмет задачи, версия среды, правило review, сохранённый результат и интерпретация. P115 намеренно не выбирает ни один из этих параметров. Он не строит program и не утверждает, что его map измеряет что-либо вне собственной структуры.'), + p('Фальсифицируемость также имеет предел. Она проверяет, что наш evaluator отвергает known bad literals; она не доказывает, что любой будущий процесс будет хорошим. Замороженный объект защищает от изменения nested fields после factory, но не заменяет наблюдение. Поэтому не следует превращать pass fixture в feedback или «результат серии». Fixture доказывает только согласованность фиксированного правила.'), + h2('Источники задают строгость формулировки'), + p('RFC 2119 и RFC 8174 — первичные, датированные и неизменяемые публикации IETF. Здесь они применяются к языку evaluator: точное literal-значение требуется, а не предполагается. Публикации не являются исследованиями обучения и не подтверждают effectiveness намеренной практики. Такая оговорка не ослабляет текст; она не позволяет ссылке притвориться review, feedback или результатом.'), + h2('Граница между картой и измерением'), + p('Карта становится измерением только после выбора единицы, процедуры и интерпретации. Если карта содержит названия вроде «умение объяснять компромисс», сначала нужно определить, какой объект будет объяснён, какие альтернативы допустимы и где фиксируется аргумент. Затем нужен способ отличить воспроизведённый шаблон от самостоятельного решения. Наконец, нужен договор о том, что означает отрицательный результат. Ни один из этих элементов нельзя взять из строки с названием навыка. P115 поэтому удерживает map как synthetic identifier, а не как шкалу.'), + p('Review loop часто маскирует это различие. В нём есть движение, значит кажется, что появится измерение. Но цикл без входа и артефакта — только рисунок. Добавить в него reviewer означает назвать человека; добавить срок — создать обязательство; добавить expected correction — выдать outcome. Технически честная схема должна показывать разрыв: not-run не переходит в evidence, а claimed field идёт в stop. Такой разрыв не делает процесс невозможным, он не даёт считать его созданным.'), + p('Фальсифицируемый план не обещает, что его отрицательные cases исчерпывают мир. Factory знает конечный набор literals, и это намеренное ограничение. Любой похожий object, пришедший извне, получает stop-unknown-fixed-literal; evaluator не пытается распознать намерение по форме полей. Такой отказ менее удобен, чем permissive parser, но он не позволяет чужому payload стать учебной записью только потому, что у него похожие ключи.'), + p('Есть и редакторская выгода. Когда текст честно различает map, loop и measurement, читатель может спорить о конкретной границе, а не о настроении автора. Можно сказать: «нам нужен другой input» или «это правило не относится к нашему решению». Нельзя сказать, что статья уже описала чью-то компетенцию, потому что она этого не делает. Прагматичная техническая речь выигрывает от такой сухости: она оставляет проверяемый объект вместо лозунга.'), + p('Наконец, deliberate practice не должна становиться названием для любой повторяемой активности. В настоящем процессе ей потребовалось бы договориться о цели, безопасности участника, сохранении материалов и праве прекратить действие. Ни слова из этой серии не заменяет эти условия. Мы используем термин как ограничитель рассуждения: если нет наблюдаемой связи, нельзя выдать повтор за подтверждённое развитие. Эта оговорка защищает и будущего участника, и следующего редактора.'), + p('Поэтому у этой карты нет скрытого «следующего уровня». Следующий шаг определяется будущим решением, а не стрелкой на схеме или порядком полей. Пока evidence отсутствует, честный результат механизма — сохранить вопрос открытым, а не выбрать удобное объяснение роста.'), + h2('Ограничения и следующий шаг'), + p('Механизм не предлагает competency framework, rubric, рейтинг, карьерную лестницу, встречу или вмешательство в чью-либо работу. В нём нет скрытых баллов, времени, задачи, проекта, данных или участника. Положительный результат evaluator не равен «инженер вырос»: это только разрешённая форма ответа для plan/scenario на 2027-09.'), + p('Следующий шаг — отдельно решить, нужен ли evidence для конкретного решения. Если нужен, новый authorized scope должен назвать предмет, допустимый input, правила consent и privacy, метод, отрицательный результат и ответственного уже в своём контексте. P115 не получает эти факты задним числом. До того итог остаётся synthetic-plan-hand-off и productionEffect: not-attempted.'), +], refs); + +const field = revision({ slug: 'editorial-2027-09-field-mentor-series', title: 'Серия для инженера, который растёт: hand-off самостоятельности без легенды', categories: ['Наставничество', 'Развитие'], cover: '/assets/editorial/2027/mentor-series-2027-autonomy-handoff-loop.svg', excerpt: 'План на сентябрь 2027: как передать вопрос о самостоятельности без назначенного owner, выдуманного review и истории о результате.', readingMinutes: 24 }, [ + p('P115 — будущий plan/scenario на сентябрь 2027, датированный 2026-07-31. В hand-off о самостоятельности самая дорогая ошибка — выдать аккуратную передачу за факт: рядом появляются owner, «следующий уровень», завершённый review и обещанный результат. Получатель видит знакомую форму и естественно думает, что кто-то уже принял решение. Цена — неизвестность превращается в организационный долг, который никто не соглашался брать.'), + p('Вторая цена — придать evidence человеческое лицо. Даже без имени легко написать «инженер объяснил выбор», «наставник дал feedback», «после цикла стало лучше». Для P115 это выдуманная обратная связь. Нет mentee, reviewer, owner, учебного процесса, репозиторного примера, задания, результата или production effect. Field-часть передаёт только fixed literal; единственная positive ветка — synthetic-plan-hand-off, а productionEffect: not-attempted остаётся явным.'), + h2('Самостоятельность нельзя назначить строкой'), + p('Автономность часто пытаются передать как статус: «может действовать сам». У статуса есть скрытые условия — граница решения, право менять состояние, источник доказательств и ответственность за последствия. В P115 ни одно условие не задано. Поэтому handoff хранит autonomy: not-evaluated. Это не отрицательная оценка и не просьба оценить человека; это запрет выводить самостоятельность из слов о карте или упражнении.'), + p('То же относится к адресу передачи. Значение recipient: not-assigned не скрывает владельца. Оно сохраняет отсутствие назначения. Если бы evaluator принимал произвольную роль, модуль тихо создавал бы обязательство вне разрешённого scope. Вместо этого literal с assigned recipient или created process получает stop. Техническая дисциплина здесь проста: отсутствие организационного решения хранится как значение, а не как пустое место для догадки.'), + table('Что hand-off передаёт, а чего не создаёт', ['Поле', 'Значение P115', 'Не является'], [['Временная граница', '2026-07-31 / 2027-09 / cutoff', 'Историей учебного события'], ['Самостоятельность', 'not-evaluated', 'Оценкой инженера'], ['Адресат', 'not-assigned', 'Назначенным owner'], ['Процесс', 'not-created', 'Очередью, программой или review loop'], ['Evidence', 'not-collected', 'Feedback, результатом или прогрессом']]), + h2('Evidence без вымышленной обратной связи'), + p('Evidence имеет происхождение. Если в документе написано «есть feedback», читатель должен иметь возможность спросить: откуда он взялся, кто его дал, к чему относился и что из него следует. В плановом P115 на эти вопросы нет допустимых ответов, значит field-материал не использует даже нейтральный пересказ. not-collected означает именно отсутствие материала в пакете, а не то, что материал потерян, слабый или ожидает одобрения.'), + p('Такой hand-off сохраняет право будущего scope сказать «не продолжать». Возможно, конкретному решению не нужен evidence о learning. Возможно, предмет выйдет за границы privacy или consent. Возможно, правильным итогом будет отсутствие действия. Если в стартовом документе уже записаны owner и успех, это право исчезает: людям приходится спорить с легендой. Fail-closed evaluator делает отсутствие выдуманного narrative проверяемым свойством, а не стилевой рекомендацией.'), + figure('/assets/editorial/2027/mentor-series-2027-autonomy-handoff-loop.svg', 'Петля hand-off: плановый literal проходит временную и evidence-проверку, останавливается при owner или claimed feedback и передаёт только неоценённую самостоятельность.', 'Диаграмма не описывает реального инженера, наставника, передачу полномочий или учебный процесс. Она показывает границу значений в синтетическом модуле.'), + h2('Runnable hand-off не открывает процесс'), + p('Пример выводит автономность, recipient, process и итог evaluator. Он не открывает тикет, не читает конфигурацию, не вызывает сеть и не создаёт workflow. Нет обращения к filesystem, environment, clock, secret, telemetry, system или data. Его назначение — показать, что данные не получают fallback из внешнего мира. Поэтому строка not-assigned не становится адресом, а not-created не становится скрытым обещанием будущей программы.'), + code("import { inspectFieldLiteral } from './upgrade-2027-09.mjs';\n\nconst handoff = inspectFieldLiteral();\nconsole.log(handoff.autonomy, handoff.recipient, handoff.process, handoff.status);\n// not-evaluated not-assigned not-created synthetic-plan-hand-off"), + h2('Порядок передачи без назначения'), + ol(['Прочитать temporal boundary как часть контракта: план относится к 2027-09 и не сообщает прошлые факты.', 'Оставить skill map и prompt именованными synthetic literals; не приписывать им пользователя или систему.', 'Сохранить autonomy в not-evaluated, recipient в not-assigned, process в not-created.', 'Сохранить observation, review и feedback в not-collected; progress — в not-claimed.', 'Запустить fixture с invented owner, review, feedback и outcome; каждая такая ветка должна остановиться.', 'Открыть другой authorized scope лишь при доказуемой потребности решения и не переносить его материалы в P115.']), + h2('Почему поле не становится программой'), + p('Полевой язык любит конкретность: назначить человека, выбрать cadence, завести карточку, запросить отчет. Это разумные действия только после того, как предмет и полномочия существуют. В P115 они отсутствуют намеренно. Добавить их «для наглядности» означает создать учебный процесс текстом. Даже synthetic name не следует превращать в реалистичный кейс: правдоподобная деталь быстро становится ложным доказательством того, что контекст был известен.'), + p('Внешние источники не решают эту проблему. RFC задают различение требований, но не дают права на персональную оценку. Они не описывают consent, не назначают owner и не доказывают, что review произошёл. Поэтому source section у статьи содержит URL, версию, дату, применение и boundary, а основной текст не использует их как авторитетный ответ о развитии человека.'), + h2('Провенанс отрицательных статусов'), + p('Отрицательный статус тоже нуждается в точном чтении. not-evaluated не означает, что оценка была начата и не завершилась; она не начиналась внутри этого пакета. not-assigned не означает, что владелец потерялся; владелец не назначался. not-created не означает, что workflow сломан; workflow не создавался. Без этих различий пустые поля быстро получают историю задним числом. Field-форма сохраняет происхождение отсутствия, чтобы следующий scope не принимал его за дефект данных.'), + p('Такая точность важна не только для privacy. Она ограничивает технический вывод. Если recipient не назначен, нельзя утверждать, что hand-off доставлен. Если process не создан, нельзя говорить о cadence. Если feedback не собран, нельзя выбирать correction. Каждый пропуск останавливает соответствующий narrative до того, как он станет планом действий для реальных людей. Код делает это буквально: значение assigned не деградирует до warning, а ведёт к отдельному stop-status.'), + p('Соблазн добавить owner обычно оправдывают удобством: документу нужен адресат. Но адресат — это решение с последствиями, а не метаданные. Его нельзя подставить как пример без риска создать ложную обязанность. Поэтому даже обобщённая роль не подходит. В P115 допускается передать вопрос без recipient; будущий контекст сам определит, существует ли необходимость кому-то его адресовать. Эта неполнота не ошибка hand-off, а его безопасная форма.'), + p('Evidence работает сходно. Файл, комментарий или правдоподобный fragment code могли бы сделать статью живее, но они стали бы synthetic evidence с неясным происхождением. Читатель начинает сравнивать свой случай с образцом и незаметно получает критерий, который никто не авторизовал. Поэтому field-статья оставляет только literal и output evaluator. Они не сообщают о внешнем состоянии, зато у них есть точное происхождение: они созданы внутри одного модуля из constants.'), + p('Для передачи важно и направление ответственности. P115 не просит получателя подтвердить, опровергнуть или продолжить что-либо. Он лишь не позволяет принять один набор слов за другой: план — за evidence, отсутствие owner — за назначение, pass fixture — за эффект. Получатель нового scope вправе сузить вопрос или закрыть его без действия. Такая возможность теряется, когда hand-off заранее обещает полезный результат или предполагает, что отказ будет признаком недостаточной самостоятельности.'), + p('Такой hand-off легко проверить на деградацию. Добавьте claimed feedback, progress или owner в known bad literal — fixture должен остановиться. Передайте object с новым полем — он тоже не будет принят как «почти тот же» plan. Это не бюрократия вокруг текста. Это способ не дать будущей редакционной задаче превратиться в скрытую систему управления людьми без решения, полномочий и доказательств.'), + p('Небольшая цена такой строгости — документ не может успокоить читателя историей успеха. Зато он не создаёт ложный факт, с которым потом приходится согласовываться. Для изолированного scope это важнее полноты внешнего narrative.'), + h2('Ограничения и следующий шаг'), + p('P115 не является assessment, mentoring policy, кадровым решением, учебным планом, review, feedback record или evidence package. Он не говорит, что человек автономен или не автономен, не рекомендует передачу полномочий и не содержит production change. Code fixture проверяет только замкнутый набор literals; он не проверяет организацию, навыки или качество инженерного решения.'), + p('Следующий шаг возможен только в отдельном authorized scope, когда конкретное решение потребует evidence. Там должны появиться собственные границы, разрешённые inputs, защита личных данных, owner, метод и допустимый отрицательный результат. P115 сохраняет исходную неизвестность: его завершение — synthetic-plan-hand-off с productionEffect: not-attempted, без выдуманного feedback и без названного владельца.'), +], refs); + +export const revisions = deepFreeze([practice, mechanism, field]); +export function verifyRevisionsAgainstFixture() { + const fixture = runMentorSeriesFixture(); + const articleChecks = revisions.map((item) => { const text = bodyText(item.contentHtml); return text.length >= 9000 && text.length <= 12000 && /(цен[аы]|стоимост|дорог)/i.test(text.slice(0, 1400)) && //.test(item.contentHtml) && /
/.test(item.contentHtml) && /
/.test(item.contentHtml) && /
    /.test(item.contentHtml) && /2027-09/.test(text) && /2026-07-31/.test(text) && /productionEffect: not-attempted/.test(text); }); + return deepFreeze({ passed: fixture.passed + articleChecks.filter(Boolean).length, total: fixture.total + articleChecks.length, accepted: fixture.accepted && articleChecks.every(Boolean), fixture, articleChecks, characters: Object.fromEntries(revisions.map((item) => [item.slug, bodyText(item.contentHtml).length])) }); +} +if (process.argv.includes('--verify-fixture')) { const result = verifyRevisionsAgainstFixture(); process.stdout.write(JSON.stringify(result, null, 2) + '\n'); if (!result.accepted) process.exitCode = 1; } +if (process.argv.includes('--print-revisions')) process.stdout.write(JSON.stringify(revisions) + '\n');