Перед merge лежит небольшой сгенерированный diff. Он решает видимый symptom, test рядом выглядит убедительно, а срок подталкивает нажать approve. В этот момент ошибка обычно не в том, что команда не умеет читать код. Ошибка в том, что проверка начинается с формы решения, а не с его границы. Цена такого порядка — принять лишний access change, потерять invalid-input contract или поверить тесту, который не видел изменённую ветку.
Ниже не разбор repository и не оценка модели, а три fixed synthetic case: scope mismatch, contract mismatch и test-evidence mismatch. Сначала ограничиваем задачу, затем сверяем diff с evidence. Если граница не доказана, proposal останавливают, а не усиливают фразой «похоже, всё хорошо».
Verification gate: решение до кнопки merge
Verification gate отделяет candidate diff от human decision. Он собирает scope, contract, reviewer и test evidence, но не запускает CI и не заменяет protected branch. Если условие не прошло, действие одно: stop, зафиксировать причину, не расширять diff и вернуть вопрос owner.
- Прочитать card. Task, scope, запреты, owner и expected evidence.
- Просмотреть diff. Каждый path и branch связаны с task.
- Сверить contract и test. Есть input, output и forbidden side effect для changed branch.
- Назвать unknown. После этого человек approve, request changes или открывает отдельный scope.
Case 1: полезная правка вышла за scope
В первом fixed case задача ограничена parser: привести synthetic invoice key к нижнему регистру. Но рядом меняется accessDecision: deny branch превращается в allow. Карточка не давала права менять authorization, поэтому reviewer останавливается на списке paths, до обсуждения style.
Список changed paths сверяют с allowed context и запретами. Неназванный path не добавляют задним числом: out-of-scope hunk удаляют и запрашивают отдельный bounded draft. Реальный ticket или threat analysis остаются за границей учебного примера.
Case 2: happy path скрыл изменение контракта
Во втором case formatter получает text, blank или invalid marker. Candidate форматирует text, но превращает invalid marker в empty string. Контракт различает их: blank означает absence, invalid — error result. Компактный код нарушает смысл, потому что rows не лежали рядом с changed branch.
Проверка требует трёх fixed rows: text, absent marker и invalid result. Это не проверка real API, а защита явного запрета. Если owner меняет invalid semantics, это уже отдельный contract change; без него gate останавливает proposal.
Case 3: тест есть, evidence нет
Третий case возвращает duplicate-key error, но candidate успевает вызвать write helper. Test проверяет unique key, поэтому есть файл и happy path, но нет evidence для changed branch. Для duplicate нужен error и zero calls write helper.
Статус test или lint не становится общим verdict. Lint может не видеть доменную границу, unique test не наблюдает duplicate. Для каждой changed branch записывают input, expected result и prohibited action.
| Case | Симптом | Контракт / запрет | Минимальная проверка | Решение gate |
|---|---|---|---|---|
| Scope mismatch | Parser hunk соседствует с access edit. | Только parser; authorization не меняется. | Сверить каждый changed path с prompt-card. | Stop и отдельное решение о scope. |
| Contract mismatch | Happy path верен, invalid marker стал empty. | Invalid и blank — разные results. | Проверить три fixed input-output rows. | Request changes до решения owner. |
| Test mismatch | Есть test unique path, но hidden write в duplicate. | Duplicate не вызывает write helper. | Assert duplicate error и zero calls. | Stop до focused negative test. |
Компактный synthetic workflow
Overlay script принимает только predetermined case id, возвращает canonical synthetic report и строит review draft. Extra key, sparse array, forged decision и cyclic JSON отклоняются до draft. Пример повторяется без codebase, а report нельзя незаметно расширить чужим полем.
import {
createFixedSyntheticAiCodingInput,
inspectSyntheticAiCodingAssistant,
planSyntheticAiCodingReview,
stopSyntheticAiCodingReview,
runAiCodingAssistantFixture,
} from './upgrade-2025-01.mjs';
const report = inspectSyntheticAiCodingAssistant(
createFixedSyntheticAiCodingInput('fixed-test-mismatch-v1'),
);
const draft = planSyntheticAiCodingReview(report);
const stopped = stopSyntheticAiCodingReview(draft);
if (!Object.values(runAiCodingAssistantFixture().assertions).every(Boolean)) {
throw new Error('fixed synthetic fixture failed');
}
console.log({ decision: report.decision.code, stopped: stopped.stopped });
// Fixed objects in memory only.
// No model call, real prompt, customer code, repository, secret, file, Git, network, CI, clock, production, metric or evaluation result is accessed.
// stopped records a teaching boundary; it is not a branch rollback or production action.
Три case не моделируют concurrency, database, authorization policy, CI, traffic, customer behavior, secrets или model evaluation. Fixture печатает decision и in-memory stop record, не merge. Stop не означает rollback: в модели нет branch, deployment или network.
Stop boundary и rollback: не одно и то же
Stop boundary действует до merge: path вне scope, value вне contract row или test не видит changed branch. Он запрещает принимать proposal, расширять diff и маскировать причину. Это не rollback.
Rollback возникает только после real change и требует отдельного owner, compatible action и verification. Помощник не знает production state, поэтому gate хранит stop-before-merge отдельно от rollback plan.
| Граница | Когда действует | Что можно честно обещать | Чего нельзя обещать |
|---|---|---|---|
| Stop boundary | До merge, когда evidence не прошло. | Proposal не принят; причина видна owner. | Что реальный branch или deployment уже восстановлен. |
| Review decision | После scope, contract и focused evidence. | Человек approve или request changes для ограниченного diff. | Что approval доказывает отсутствие любых дефектов. |
| Rollback plan | После реального change и только в его scope. | Есть отдельный owner, compatible action и verification. | Что synthetic stop record является rollback. |
Что фиксировать в pull request
Описание хранит task/scope, запреты, owner, contract rows, test evidence и unknown. Тогда comment точен: «accessDecision.js вне scope» или «duplicate test не проверяет zero calls».
GitHub review поддерживает comment, approve и request changes, но assistant comment остаётся candidate evidence. Последний владелец merge — инженер с контрактом и последствиями.
Ограничения и следующий проверяемый шаг
Пакет не запускает model, prompt, repository scan, file read, Git, CI, network, source search, production action, метрику или evaluation. Все ids, paths, contracts, labels, owners и test outcomes — fixed synthetic literals в памяти. Он не даёт рекомендацию применить конкретный assistant к customer code и не сообщает результаты реального теста. Документация GitHub и NIST здесь служит рамкой для ограничения риска, а не подтверждением работы конкретного инструмента или команды.
Следующий шаг: перед следующим AI-assisted merge выберите один changed branch и заполните таблицу из трёх строк: input, expected result, forbidden side effect. Затем проверьте paths against prompt-card. Если не удаётся назвать owner, boundary или test evidence, остановите proposal до merge. Ожидаемый результат — не больше бюрократии, а короткое объяснение, почему diff либо ограниченно готов к human decision, либо должен вернуться в доработку.
Историческая граница января 2025
Статья использует GitHub Docs commit 6a92295d от 31 января 2025 для responsible use и pull-request review, а также NIST SP 800-218 Version 1.1. Она не переносит в январь 2025 будущие agent workflows, model labels или результаты новых benchmark. Все три кейса, diagrams, outputs и checks являются учебными fixed synthetic in-memory values; они не раскрывают prompts, customer code, codebase, secrets или реальные данные.
Проверяемые источники
- GitHub Docs snapshot: Copilot Chat limitations (immutable GitHub Docs commit 6a92295d, 31 January 2025) — Документация ограничивает область помощника контекстом и прямо предупреждает: код может выглядеть валидным, но не соответствовать намерению разработчика; для чувствительного к безопасности кода нужны review и тестирование. Граница: Это описание ограничений конкретного продукта и интерфейса. Оно не измеряет качество любого помощника, не доказывает корректность конкретного diff и не задаёт процесс merge.
- GitHub Docs snapshot: improving Copilot Chat performance (immutable GitHub Docs commit 6a92295d, 31 January 2025) — Документация рекомендует держать запрос в рамке задачи, использовать помощник как инструмент, а не замену инженера, и проверять сгенерированный код через secure coding и code review. Граница: Рекомендация не означает, что хороший prompt, линтер или один тест дают гарантию correctness, security или совместимости с конкретным репозиторием.
- GitHub Docs snapshot: reviewing proposed pull-request changes (immutable GitHub Docs commit 6a92295d, 31 January 2025) — Pull request review рассматривает commits, files и diff, позволяет оставить комментарии, approve или request changes; diff удобно просматривать по файлам. Граница: Документация описывает механизм review в GitHub. Она не утверждает, что просмотренный diff или approval сам по себе доказывает отсутствие дефектов.
- NIST SP 800-218: Secure Software Development Framework Version 1.1 (final publication, 3 February 2022) — SSDF задаёт набор практик безопасной разработки, которые можно встраивать в конкретный SDLC, чтобы снижать число уязвимостей и влияние невыявленных проблем. Граница: SSDF — высокоуровневая рамка. Он не заменяет знания предметного контракта, тестовые данные, human review или решение владельца об acceptable risk.