Repository navigation
Proof: the corpus lane refuses a campaign it does not belong to (V5b2d-4m) - #564
Conversation
…d-4m) Гвард в координаторе не защищает устаревший координатор: старый файл несёт старый контракт целиком. Сегодня это стоило двух массовых диспатчей — 133 прогона от забытого `--dry-run` и 69 от исполнения чекаута, где полярность флага была прежней. Оба раза правило существовало и оба раза не исполнялось той копией, которая отправляла диспатчи. Поэтому инвариант переносится туда, где код всегда свежий. `full-domain-corpus.yml` объявляет вход `expect_lanes` как required без default: GitHub отвергает диспатч без него ДО создания прогона, и координатор, который такого входа не знает, кампанию не начнёт вовсе. Первым шагом полосы, до checkout и до любой дорогой работы, стоит арифметика: 16777216 делится на `window_points` нацело, частное равно `expect_lanes`, а `window_start` — каноническая десятичная запись внутри домена и на шве покрова этой ширины. Сравнения — по сырым байтам через `case`: `[ -eq ]` и `int()` принимают окружающие пробельные символы, а `$(( ))` читает ведущий ноль как восьмеричную запись, из-за чего `0200000` был бы 65536 для гварда и 200000 для `corpus_lane.py` — один диспатч, два разных окна. Длина координаты ограничена восемью цифрами домена до арифметики: `$(( ))` молча переполняется на 2^64, где `18446744073709551616` выглядит идеально выровненным нулём. У этого workflow есть второй режим — ограниченный префиксный зонд без окна. Он не полоса кампании, и единственный истинный для него размер — ноль; диспатч, который называет кампанию и не несёт окна, запустил бы один и тот же зонд по разу на полосу и отчитался бы зелёным. `dispatch_commands_v1` добавляет `-f expect_lanes=<len(plan)>` в каждую команду. Тесты ИСПОЛНЯЮТ shell гварда, извлечённый из YAML: текстовая проверка на `-ne` ничего не говорит о том, что делает оболочка, и обезвреженное сравнение оставляло такие проверки зелёными. Co-authored-by: Claude Code <daniilerosov12@gmail.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 17 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Comment |
The lane guard admitted three hostile coordinate classes that #564's full-domain guard already refuses, leaving run titles the collector parser cannot bind: - octal/leading-zero window_points=0100000 read as 32768 by $(( )) while the lane runner's int() replays 100000 points; - window_start >= 2^64, where $(( )) wraps to a perfectly aligned zero and [ -ge ] answers "not greater" for what it cannot parse; - window_points > 2^64, the same wrap on the width. The campaign-size comparison is now byte-wise (canonical decimals by that point): [ -ne ] errors out on a size past the shell's own integer and the guard read that error as a match. Same law as merged #564, one SSOT per workflow: the guard stays in verification-lanes.yml and its tests in test_workflow_inputs.py, with no parser shared between the two workflows. Tests execute the guard's own shell; all three verifier probes were RED before this change and GREEN after.
Two CodeRabbit findings on test_workflow_inputs.py: - test_the_campaign_size_is_a_required_input sliced the declaration block at the first line containing "jobs:", which an input description mentioning the word would corrupt. The block now ends at the next input declaration at the same indentation, the same law merged #564's test_corpus_campaign_guard.py already uses. - _run_guard_v1 runs the guard without check=True, but said so implicitly: a nonzero status is the contract under test (exit 64), so check=False is now explicit with the reason.
…V5b2d-4k) (#560) * Proof: a lane refuses a campaign whose size contradicts its width The guard against a runaway campaign lived only in the coordinator, so a checkout older than the guard carried the older contract whole — including the inverted flag polarity. That has now happened twice: 133 runs from a forgotten `--dry-run` when the flag was the safety, and 69 more from reading the newer rules while executing a pre-merge file. No guard added to a client protects a client that is stale. So the same invariant moves to the one place that is always current. The lane declares `expect_lanes` required and without a default: GitHub refuses a dispatch that omits it before a run exists, which is exactly what an older coordinator sends. The first step then checks arithmetic — the window must tile the full domain into precisely the campaign claimed — before the checkout and before the artifact download, so an incoherent dispatch costs one second instead of an hour. The tests execute that shell rather than assert about its text: an earlier version asserted `-ne` was present and stayed green when the comparison was neutered. Seven mutations are killed, two of which first exposed weak tests — a coordinate asserted by membership rather than by its `-f` pairing, and a divisibility case that passed through the size comparison instead. The discriminating case is 65535: integer division answers 256 exactly while 256 points of the domain stay uncovered. Found along the way: the declared-input reader treated a comment as a dedent, so one comment silently hid every input below it — invisible, because a shorter set of names satisfies every assertion about the names it did find. Verified: 17 tests in this module, full local suite at the documented Windows baseline, and the Linux suite with both engine layers importable. * Proof: the lane also refuses a start its own name cannot render The campaign size was only half the coordinate. 254 MPFI lanes were dispatched today with a carriage return inside `window_start`: GitHub accepted the string, the run-name rendered a title carrying the control character, and the collector — which admits only the canonical decimal, so a foreign title cannot claim a plan window — could never have bound them. An hour of replay each, unclaimable, and visible only by counting the cover. Neither `[ -eq ]` nor `int()` would have objected; both accept surrounding whitespace. So the guard compares the raw bytes with `case`, and adds the two coordinates that make a start meaningful at all: inside the domain, and on a seam of this width's cover. Leading zeros are refused for a reason worth naming: `$(( ))` reads them as octal, so `0200000` silently becomes 65536 and passes both the seam and the domain check as an ordinary window — while rendering a title no plan window claims. That case is in the tests because without it the rule could be deleted and everything stayed green: every other bad spelling is also caught downstream. Verified: 20 tests, and all eight mutations of the guard's rules die, including the four added here. * fix(proof): verification lanes refuse coordinates past the shell integer The lane guard admitted three hostile coordinate classes that #564's full-domain guard already refuses, leaving run titles the collector parser cannot bind: - octal/leading-zero window_points=0100000 read as 32768 by $(( )) while the lane runner's int() replays 100000 points; - window_start >= 2^64, where $(( )) wraps to a perfectly aligned zero and [ -ge ] answers "not greater" for what it cannot parse; - window_points > 2^64, the same wrap on the width. The campaign-size comparison is now byte-wise (canonical decimals by that point): [ -ne ] errors out on a size past the shell's own integer and the guard read that error as a match. Same law as merged #564, one SSOT per workflow: the guard stays in verification-lanes.yml and its tests in test_workflow_inputs.py, with no parser shared between the two workflows. Tests execute the guard's own shell; all three verifier probes were RED before this change and GREEN after. * test(proof): harden guard contract test per review Two CodeRabbit findings on test_workflow_inputs.py: - test_the_campaign_size_is_a_required_input sliced the declaration block at the first line containing "jobs:", which an input description mentioning the word would corrupt. The block now ends at the next input declaration at the same indentation, the same law merged #564's test_corpus_campaign_guard.py already uses. - _run_guard_v1 runs the guard without check=True, but said so implicitly: a nonzero status is the contract under test (exit 64), so check=False is now explicit with the reason. --------- Co-authored-by: Claude Code <daniilerosov12@gmail.com>
Что это
Корпусный путь получает тот же контракт кампании, что PR #560 дал полосам верификации, и закрывает класс, который #560 намеренно оставил открытым.
.github/workflows/full-domain-corpus.ymlобъявляет входexpect_lanes—required: true, безdefault. GitHub отвергает диспатч без такого входа до создания прогона, поэтому координатор, который об этой координате не знает, кампанию не начнёт вовсе.actions/checkoutи до любой дорогой работы, стоит арифметический гвард: домен16777216делится наwindow_pointsнацело, частное равноexpect_lanes,window_start— каноническая десятичная запись внутри домена и на шве покрова этой ширины.dispatch_commands_v1вproof/region/v1/corpus_dispatch.pyдобавляет-f expect_lanes=<len(plan)>в каждую команду.proof/region/v1/tests/test_corpus_campaign_guard.pyисполняет shell гварда, извлечённый из YAML, а не утверждает о его тексте.Соседняя функция
verification_dispatch_commands_v1в том же файле — зона PR #560; здесь она не тронута. Конфликт при мерже будет механическим (соседние строки одного файла).Замеренный дефект
Сегодня дважды случился массовый ошибочный диспатч: 133 прогона от забытого
--dry-run, когда флаг был защитой, и 69 — от исполнения устаревшего чекаута, где полярность флага была прежней. Оба раза правило существовало в репозитории и оба раза не исполнялось той копией, которая отправляла диспатчи.Вывод, который здесь реализован: гвард в клиенте не защищает устаревший клиент, потому что старый файл несёт старый контракт целиком. Инвариант должен жить там, где код всегда свежий, — в самом workflow.
Что доказано
Проверки выполнены в WSL (на Windows слой
arb/mpfiне импортируется —fcntl).Полный набор,
python3 -m unittest discover -s proof/region/v1/tests -p "test_*.py":Ran 529 tests(было 515 наorigin/main, +14 — новые),FAILED (failures=3, skipped=1).Те же три падения — дословно те же имена — воспроизводятся на чистом
origin/main(1461bc2) до моей правки:test_build.ArbBuildIdentityCharacterizationTests.test_arb_runtime_binding_propagates_to_downstream_identities,test_build.SharedBuildTransportTargetTests.test_build_process_encoding_is_total_and_keeps_exact_golden,test_build.SharedBuildTransportTargetTests.test_post_popen_handler_gap_cannot_bypass_finalizer. Это голдены над локально исполняемой сборкой;test_build.py— зона PR #559, здесь не тронута.Под
PYTHONOPTIMIZE=2: тот же результат —Ran 529 tests, те же 3 предсуществующих падения.Оба гейта, обычным запуском и под
PYTHONOPTIMIZE=2:proof/region/v1/arb/tests/gate.py→OK (skipped=15),284 tests, inventory 3284dccf…301dbe;proof/region/v1/mpfi/tests/gate.py→OK (skipped=4).Пины инвентаря не пересчитывались и не должны были: срез не добавляет тестов в
arb/tests, оба гейта зелёные на неизменённых константах.Проверочное дерево не запрещает правку:
arb/tests/test_build_recipe.pyдержит формуarb.yml(WORKFLOW = ARB.parents[3] / ".github" / "workflows" / "arb.yml"), а не всех workflow; репозиторный grep даёт единственных потребителейfull-domain-corpus.yml—corpus_dispatch.pyи его тест.test_workflow_inputs.py(зона #560) остаётся зелёным: комментарии в блоке входов размещены с отступом 8 пробелов, поэтому текущий читатель деклараций их не принимает за дедент и видитexpect_lanesобъявленным.YAML разобран, не только прочитан:
yaml.safe_loadдаёт входы[points, shard_points, window_start, window_points, expect_lanes, lane_run_ids],expect_lanes: {description: …, required: True}безdefault, и первый шаг задания —refuse a dispatch that does not belong to a coherent campaign.Мутации: каждое утверждение убивает свою
Мутация вносилась в реальный артефакт, набор прогонялся, файл восстанавливался. Все десять убиты; для каждой ниже указан различающий случай — тот, что краснеет именно от своего правила, а не от соседнего.
"${lanes}" != "${lanes}")…refuses_a_campaign_that_contradicts_its_width:0 != 64 : (65536, 255)…refuses_a_width_that_cannot_tile_the_domain:0 != 64 : (65535, 256). Наивные 1000 / 65537 мутанта не ловят — их снимает сравнение размера ниже; 65535 даёт ровно 256 при целочисленном делении, оставляя 256 точек домена непокрытыми16777216→8388608)…admits_every_seam_of_the_cover— корректная кампания начала бы отказывать себеwindow_start…refuses_a_coordinate_that_is_not_a_canonical_decimal, строка 258 — случай0200000. Все прочие написания в этом тесте ловятся другими правилами;0200000— восьмеричное 65536 для$(( )), десятичное 200000 дляint(), ложится на шов и внутрь доменаwindow_points0100000: восьмеричное 32768 замощает домен в 512 полос, а прогон реплеит 100000 точек…refuses_a_start_off_the_seam_or_off_the_domain, строка 278 —18446744073709551616:$(( ))переполняется в идеально выровненный ноль,[ -ge ]не разбирает значение и отвечает «не больше»…refuses_a_campaign_claim_without_a_window:0 != 64 : 1window_startбез окна…refuses_a_start_with_no_window_to_start…runs_before_anything_is_fetched_or_replayed:2709 not less than 2326-fперед координатой…every_dispatched_command_carries_the_campaign_sizeСемантика оболочки не предполагалась, а измерена в WSL:
[ 010 -eq 8 ]ложно (testчитает основание 10),$(( 0200000 ))= 65536 (восьмеричное),$(( 99999…9 % 65536 ))= 65535 без ошибки (тихое переполнение),[ 99999…9 -ge 16777216 ]возвращает 2 и читается как «ложь».Что НЕ доказано
required-входа — документированное поведение API, но в этом PR оно не наблюдалось: workflow ещё не вmain. Первый настоящий диспатч и есть проверка этого звена.ci-worker.ymlпрогоняетdiscover -s proof/region/v1/tests, где живёт исполняющий тест). Поведениеubuntu-latestGitHub-раннера от локального bash не отличается по использованным конструкциям, но это вывод, а не наблюдение.assemble-lanesгвардом не покрыто. Оно не несёт оконных координат, поэтому арифметика к нему неприменима;expect_lanesдля такого диспатча обязан быть0— это проверяет полоса, но своей проверки передgh run downloadу сборки нет. Отдельный класс, отдельный срез.pointsиshard_pointsостаются невалидированными и подставляются в shell через'${{ github.event.inputs.… }}'. Это предсуществующая поверхность (не создана здесь и не расширена): диспатч требует прав записи, у задания толькоcontents: readи нет секретов.window_startиwindow_pointsпосле этой правки проверяются до использования.test_build.pyв этом окружении не расследованы: они предсуществуют наorigin/main, идентичны до и после, и файл принадлежит зоне PR Proof: bind what each comparator coordinate contains, not only its digest (V5b2d-4i) #559.Откат
git revertодного коммитаe4dd210fвозвращает всё: удаляет входexpect_lanes, шаг-гвард, координату вdispatch_commands_v1и новый тестовый файл. Внешнего состояния изменение не создаёт — ни артефактов, ни прогонов, ни миграций.Промежуточное состояние стоит знать до мержа: после мержа старый координатор (чекаут до этого коммита) больше не сможет диспатчить
full-domain-corpus.yml— GitHub откажет из-за отсутствующего обязательного входа. Это и есть заявленный эффект, а не побочный. Обратный порядок — откат workflow при свежем координаторе — по контракту API должен отвергаться как неизвестный вход; здесь это не измерялось, и худший исход всё равно ограничен: лишняя координата workflow не читается ни одним шагом.