Skip to content

Proof: the corpus lane refuses a campaign it does not belong to (V5b2d-4m) - #564

Merged
lemone112 merged 5 commits into
mainfrom
v5b2d-4m-corpus-campaign-contract
Aug 7, 2026
Merged

lemone112 merged 5 commits into
mainfrom
v5b2d-4m-corpus-campaign-contract

Conversation

@lemone112

Copy link
Copy Markdown
Collaborator

Что это

Корпусный путь получает тот же контракт кампании, что PR #560 дал полосам верификации, и закрывает класс, который #560 намеренно оставил открытым.

  1. .github/workflows/full-domain-corpus.yml объявляет вход expect_lanes — required: true, без default. GitHub отвергает диспатч без такого входа до создания прогона, поэтому координатор, который об этой координате не знает, кампанию не начнёт вовсе.
  2. Первым шагом полосы, до actions/checkout и до любой дорогой работы, стоит арифметический гвард: домен 16777216 делится на window_points нацело, частное равно expect_lanes, window_start — каноническая десятичная запись внутри домена и на шве покрова этой ширины.
  3. dispatch_commands_v1 в proof/region/v1/corpus_dispatch.py добавляет -f expect_lanes=<len(plan)> в каждую команду.
  4. Новый файл 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}") FAILED (2) …refuses_a_campaign_that_contradicts_its_width: 0 != 64 : (65536, 255)
обезвредить делимость (правило удалено) FAILED (1) …refuses_a_width_that_cannot_tile_the_domain: 0 != 64 : (65535, 256). Наивные 1000 / 65537 мутанта не ловят — их снимает сравнение размера ниже; 65535 даёт ровно 256 при целочисленном делении, оставляя 256 точек домена непокрытыми
занизить домен (16777216 → 8388608) FAILED (10) в том числе …admits_every_seam_of_the_cover — корректная кампания начала бы отказывать себе
разрешить ведущие нули в window_start FAILED (1) …refuses_a_coordinate_that_is_not_a_canonical_decimal, строка 258 — случай 0200000. Все прочие написания в этом тесте ловятся другими правилами; 0200000 — восьмеричное 65536 для $(( )), десятичное 200000 для int(), ложится на шов и внутрь домена
разрешить ведущие нули в window_points FAILED (1) тот же тест, строка 262 — случай 0100000: восьмеричное 32768 замощает домен в 512 полос, а прогон реплеит 100000 точек
снять ограничение длины координаты FAILED (1) …refuses_a_start_off_the_seam_or_off_the_domain, строка 278 — 18446744073709551616: $(( )) переполняется в идеально выровненный ноль, [ -ge ] не разбирает значение и отвечает «не больше»
разрешить заявку о кампании без окна FAILED (1) …refuses_a_campaign_claim_without_a_window: 0 != 64 : 1
разрешить window_start без окна FAILED (1) …refuses_a_start_with_no_window_to_start
переставить гвард после checkout FAILED (1) …runs_before_anything_is_fetched_or_replayed: 2709 not less than 2326
снять -f перед координатой FAILED (1) …every_dispatched_command_carries_the_campaign_size

Семантика оболочки не предполагалась, а измерена в WSL: [ 010 -eq 8 ] ложно (test читает основание 10), $(( 0200000 )) = 65536 (восьмеричное), $(( 99999…9 % 65536 )) = 65535 без ошибки (тихое переполнение), [ 99999…9 -ge 16777216 ] возвращает 2 и читается как «ложь».

Что НЕ доказано

  • Живого диспатча не было. Отказ GitHub на диспатч без required-входа — документированное поведение API, но в этом PR оно не наблюдалось: workflow ещё не в main. Первый настоящий диспатч и есть проверка этого звена.
  • Гвард не исполнялся на раннере. Он исполнялся в bash под WSL и будет исполняться в CI (ci-worker.yml прогоняет discover -s proof/region/v1/tests, где живёт исполняющий тест). Поведение ubuntu-latest GitHub-раннера от локального 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.
  • Независимое review не выполнено — это открытый гейт данного PR.

Откат

git revert одного коммита e4dd210f возвращает всё: удаляет вход expect_lanes, шаг-гвард, координату в dispatch_commands_v1 и новый тестовый файл. Внешнего состояния изменение не создаёт — ни артефактов, ни прогонов, ни миграций.

Промежуточное состояние стоит знать до мержа: после мержа старый координатор (чекаут до этого коммита) больше не сможет диспатчить full-domain-corpus.yml — GitHub откажет из-за отсутствующего обязательного входа. Это и есть заявленный эффект, а не побочный. Обратный порядок — откат workflow при свежем координаторе — по контракту API должен отвергаться как неизвестный вход; здесь это не измерялось, и худший исход всё равно ограничен: лишняя координата workflow не читается ни одним шагом.

…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>
@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 17 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f1b4cd6f-f5ca-4a11-9cb6-34d64afe3dc3

📥 Commits

Reviewing files that changed from the base of the PR and between 35253fb and b8f3bb6.

📒 Files selected for processing (3)
  • .github/workflows/full-domain-corpus.yml
  • proof/region/v1/corpus_dispatch.py
  • proof/region/v1/tests/test_corpus_campaign_guard.py

Comment @coderabbitai help to get the list of available commands.

@lemone112
lemone112 merged commit 3c63177 into main Aug 7, 2026
10 checks passed
@lemone112
lemone112 deleted the v5b2d-4m-corpus-campaign-contract branch August 7, 2026 19:09
lemone112 added a commit that referenced this pull request Aug 10, 2026
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.
lemone112 added a commit that referenced this pull request Aug 10, 2026
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.
lemone112 added a commit that referenced this pull request Aug 10, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant