8 lines
18 KiB
JSON
8 lines
18 KiB
JSON
{
|
||
"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) => ({\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) => 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>"
|
||
}
|