Files
progcode/editorial/agent-rewrites/055.json
T
huncode 2d914b543f
Build and deploy / deploy (push) Failing after 15s
Publish rewritten technical article archive
2026-08-02 22:19:34 +03:00

8 lines
18 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"index": 55,
"slug": "editorial-2026-06-field-multi-runtime",
"title": "Когда PHP, JavaScript и D говорят разное: как закрыть границу контракта",
"excerpt": "Разные runtime не становятся одной системой от похожего JSON. Разберём наблюдаемый симптом, явный контракт, отрицательный путь и критерий, который отделяет проверяемую модель от заявления об интеграции.",
"contentHtml": "<p>Запрос проходит через PHP, затем попадает в JavaScript и заканчивается обработкой на D. Пользователь видит ошибку без понятной причины, а оператор не может связать запись D с исходным запросом. Иногда все три части возвращают похожий JSON, но одна сторона считает ошибку исключением, другая — обычным значением, а третья записывает время в другой шкале. Внешне система работает. Внутри она уже потеряла общий смысл.</p>\n<p>Цена такой ошибки выше, чем один неудачный запрос. Команда может повторить несовместимый ответ, принять его за временный сбой и включить повторную попытку там, где операция уже выполнена. Можно получить двойное списание, зависшую задачу или неверный отчёт. Похожая форма данных не защищает от разных правил обработки.</p>\n<h2>Тезис: общий смысл живёт на границе</h2>\n<p>Три runtime можно соединить только через узкий, именованный контракт. Он должен назвать операцию, форму успешного значения, форму ошибки и основание времени. Каждый адаптер обязан сохранить эти поля без скрытого приведения. Если поле нельзя сопоставить, система должна остановиться и назвать причину. Молчаливое «примерно подходит» опаснее явного отказа.</p>\n<p>В этом материале проверяется модель границы. Учебный пример хранит запись в памяти JavaScript и читает её обычной функцией. Он не запускает PHP, JavaScript как отдельный процесс или D. Он не обращается к сети, диску, часам, телеметрии и сервисам. Поэтому его результат говорит только о внутренней сопоставимости записи. Это ограничение входит в смысл примера.</p>\n<h2>Механизм: четыре поля, которые нельзя угадывать</h2>\n<p>Сначала назовите операцию. Строка <code>fixed-order-decision</code> лучше, чем общий «обработчик заказа»: у неё есть конкретная граница. Затем задайте value tag. В примере это <code>order-ready</code>. Число <code>4200</code> получает единицу и валюту. Без tag и единицы потребитель может принять копейки за рубли или число лимита за сумму.</p>\n<p>Ошибка получает named envelope. В нём явно присутствуют <code>semantics</code>, <code>code</code> и <code>retry</code>. Значение <code>code: null</code> означает отсутствие кода внутри известного envelope. Отсутствующий сам envelope означает другую проблему. Эти два случая нельзя сливать в одну пустую строку.</p>\n<p>Время в изолированной модели задаётся ordered fixed logical ticks. Пара <code>100..108</code> показывает порядок и интервал из восьми условных шагов. Это не миллисекунды, не latency и не SLA. Если нужен production-замер, он требует отдельного источника времени, политики измерения и проверки среды.</p>\n<pre><code>const contract = {\n schemaVersion: 'fixed-boundary-1',\n operation: 'fixed-order-decision',\n value: { tag: 'order-ready', amountMinor: 4200, currency: 'RUB' },\n error: { semantics: 'named-envelope', code: null, retry: 'not-requested' },\n time: { basis: 'fixed-logical-ticks', opened: 100, closed: 108 }\n};\n\nconst adapters = ['php', 'javascript', 'd'].map((model) =&gt; ({\n model,\n contractVersion: 'fixed-boundary-1',\n valueTag: 'order-ready',\n errorSemantics: 'named-envelope',\n timeBasis: 'fixed-logical-ticks',\n mapping: 'exact'\n}));\n\nfunction check(record) {\n if (record.schemaVersion !== 'fixed-boundary-1') {\n return { status: 'stop-incomplete-contract', reason: 'schema-version-missing' };\n }\n if (record.adapters.some((item) =&gt; item.mapping !== 'exact')) {\n return { status: 'stop-incomparable-adapter', reason: 'mapping-is-not-exact' };\n }\n return { status: 'synthetic-review-hand-off', observedEffect: 'none-observed' };\n}\n\nconsole.log(check({ ...contract, adapters }));</code></pre>\n<p>Пример учебный. Он показывает форму проверки, а не совместимость библиотек. В нём имена <code>php</code>, <code>javascript</code> и <code>d</code> — значения поля <code>model</code>. Они не доказывают, что три языка обменялись данными. Положительный результат означает лишь: запись содержит названные поля, версии совпадают, а mapping не скрывает преобразование.</p>\n<h2>Как распознать ложное совпадение</h2>\n<p>Одинаковый текст ошибки не задаёт одинаковое действие. PHP может вернуть envelope, JavaScript — выбросить значение, а D — записать код в отдельное поле. Потребитель, который проверяет только сообщение, потеряет режим завершения. Сравнивайте не текст, а семантику: кто владеет ошибкой, можно ли повторить операцию и какие данные сохраняются.</p>\n<p>Одинаковое число времени тоже ничего не гарантирует. Один адаптер может передать логические шаги, другой — epoch seconds. Числа совпадут случайно, а вывод окажется ложным. Поэтому basis должна быть полем контракта и каждого адаптера. Пропущенный <code>closed</code> должен закрывать проверку, а не заменяться текущим временем.</p>\n<div class=\"table-scroll\"><table><caption>Симптомы на границе и проверяемое действие</caption><thead><tr><th scope=\"col\">Симптом</th><th scope=\"col\">Причина</th><th scope=\"col\">Проверка</th><th scope=\"col\">Действие</th></tr></thead><tbody><tr><td>Ответы похожи, но retry ведёт себя по-разному</td><td>Envelope смешан с thrown value</td><td>Сравнить error semantics и наличие code/retry</td><td>Выровнять envelope или вернуть stop</td></tr><tr><td>Время совпадает только на одном стенде</td><td>Разные time basis</td><td>Проверить basis и обе границы интервала</td><td>Назвать одну шкалу или прекратить сравнение</td></tr><tr><td>Сумма проходит проверку, но меняет порядок величины</td><td>Tag, unit или currency угадываются по имени</td><td>Проверить value tag, amountMinor и currency</td><td>Добавить явное поле и запретить inference</td></tr><tr><td>Адаптер «почти» совпадает с contract</td><td>Скрытая coercion при mapping</td><td>Потребовать mapping: exact</td><td>Описать преобразование явно либо остановить hand-off</td></tr><tr><td>Нельзя связать запись D с запросом PHP</td><td>Нет общего correlation field</td><td>Проверить, входит ли идентификатор в contract</td><td>Добавить поле в новый контракт; не восстанавливать связь по времени</td></tr></tbody></table></div>\n<figure><img src=\"/assets/editorial/2026/multi-runtime-2026-integration-evidence-loop.svg\" alt=\"Цикл проверки общего контракта: фиксированная запись проходит проверки границы и получает именованный отказ или передачу на synthetic review\" loading=\"lazy\" /><figcaption>Схема показывает чтение одной записи в памяти. Стрелки не означают сетевое соединение, запуск runtime или измерение production.</figcaption></figure>\n<h2>Отрицательный путь важнее happy path</h2>\n<p>Проверка должна отказываться от удобного вывода. Возьмём запись, где у одного адаптера <code>errorSemantics: 'thrown-value'</code>, а у контракта остаётся <code>named-envelope</code>. Такой набор нельзя объявить совместимым. Функция возвращает <code>stop-incomparable-adapter</code> и оставляет владельцу конкретное действие: выровнять семантику.</p>\n<p>Другой случай: <code>time.basis</code> равен <code>wall-clock</code>, а <code>closed</code> отсутствует. Здесь нельзя написать «обработка заняла неизвестное время» и нельзя вычислить значение из текущих часов. Проверка должна вернуть <code>stop-undetermined-time-boundary</code>. Она не спорит о точности. Она фиксирует отсутствие основания для сравнения.</p>\n<p>Третий случай — coercion. Если адаптер превратил строку в число, округлил сумму или заменил пустое значение значением по умолчанию, результат уже не exact mapping. Приведение может быть правильным в конкретной программе, но оно требует правила, единицы и теста. До этого момента оно скрывает смысл и закрывает hand-off.</p>\n<h2>Порядок действий</h2>\n<ol><li>Назовите одну операцию и версию схемы. Не начинайте с описания всех сервисов.</li><li>Опишите value через tag и явные единицы: например, <code>amountMinor</code> и <code>currency</code>.</li><li>Опишите error envelope целиком. Зафиксируйте code, retry и допустимое отсутствие кода.</li><li>Выберите одну time basis и запишите ordered opened и closed. Не называйте ticks миллисекундами без источника.</li><li>Добавьте по одной записи для PHP, JavaScript и D. Сверяйте каждый адаптер с contract.</li><li>Запретите скрытое приведение. Для каждого преобразования добавьте именованное правило или верните stop.</li><li>Прогоните положительный и отрицательные случаи через одну проверку. Сохраните status и nextAction без редакторской интерпретации.</li><li>Передайте запись на следующий review только как synthetic hand-off. Реальную интеграцию проверяйте отдельным набором доказательств.</li></ol>\n<h2>Что можно утверждать после проверки</h2>\n<p>Допустимая формулировка узкая: «фиксированная запись соответствует названным правилам и может перейти на synthetic review». Нельзя писать «PHP, JavaScript и D совместимы», «адаптер работает», «интеграция подтверждена» или «latency равна восьми». У модели нет runtime, транспорта, хоста, зависимостей, прав, пользовательских данных и production-метрик.</p>\n<p>Это не бюрократическая оговорка. Явная граница защищает решение от расширения смысла при копировании. Читатель видит, какой факт проверен, а какой ещё требует отдельного эксперимента. Если понадобится связать PHP-запрос и запись D, добавьте correlation id и проверьте его на реальном пути. Не выводите связь из одинакового времени, порядка строк или похожего JSON.</p>\n<h2>Ограничения</h2>\n<p>Модель не описывает ABI, сериализацию, nullable policy, иерархию классов, stack unwinding, сборку мусора, планировщик, retry конкретного клиента или схему регистрации сервисов. Эти свойства нельзя спрятать в поле <code>details</code>. Если свойство влияет на решение, назовите его отдельным полем и задайте проверку. Если назвать его нельзя, остановите границу.</p>\n<p>Модель также не заменяет контракт домена. Tag <code>order-ready</code> говорит о форме значения, но не доказывает, что бизнес действительно разрешает выдавать заказ. Доменный смысл проверяет владелец операции. Техническая проверка должна передать ему точное значение и не присваивать себе его решение.</p>\n<h2>Проверяемый критерий готовности</h2>\n<p>Граница готова к synthetic hand-off, если выполнены все условия: есть schema version и operation; value имеет tag и единицы; error содержит named semantics, code и retry; time имеет одну basis и целые ordered ticks; присутствуют все три model labels; каждый адаптер сохраняет version, tag, error semantics, time basis и exact mapping; отрицательные случаи возвращают именованные stop; результат содержит <code>observedEffect: none-observed</code>.</p>\n<p>Проверяемый результат можно повторить на той же записи и получить тот же status. Если status меняется от текущих часов, сети, окружения или неявной нормализации, это уже не изолированная проверка. Если положительный status требует доверия к словам о запущенном сервисе, он выходит за границу примера. В обоих случаях работу нужно остановить и уточнить новый scope.</p>\n<h2>Проверяемые источники</h2>\n<ul><li><a href=\"https://www.php.net/manual/en/language.exceptions.php\" target=\"_blank\" rel=\"noopener noreferrer\">PHP Manual: Exceptions</a> — официальное описание исключений PHP; используется только для различия механизма исключения и явно возвращаемого значения.</li><li><a href=\"https://262.ecma-international.org/16.0/\" target=\"_blank\" rel=\"noopener noreferrer\">ECMA-262, ECMAScript 2025 Language Specification</a> — официальная спецификация семантики JavaScript; не подтверждает работу конкретного адаптера.</li><li><a href=\"https://dlang.org/spec/exception-safe.html\" target=\"_blank\" rel=\"noopener noreferrer\">D Language Specification: Exception Safety</a> — официальное описание исключительной безопасности D; не заменяет интеграционный тест приложения.</li></ul>"
}