Skip to content

feat(colors): private declarative walking skeleton with atomic publish sink - #568

Merged
lemone112 merged 10 commits into
mainfrom
codex/private-declarative-walking-skeleton-current
Aug 11, 2026
Merged

feat(colors): private declarative walking skeleton with atomic publish sink#568
lemone112 merged 10 commits into
mainfrom
codex/private-declarative-walking-skeleton-current

Conversation

@lemone112

@lemone112 lemone112 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

What

Private, declarative walking-skeleton slice behind gate C7c. Adds the private program (Rust core + WASM build), the JS consumer, fixtures, and the full build -> publish -> verify lifecycle driven by build-private-program / prepare-npm-package, with an exact WASM size budget enforced by check-private-program-wasm-size-budget. The public surface stays unchanged until gate C7c is intentionally opened.

Why

Establish the end-to-end private publish path (build, bundle, publish, verify against the exact artifact) early, while keeping the public surface and existing release contract intact and reversible.

Invariants

  • Output bindings leave through exactly one atomic sink (scripts/atomic-write.mjs) with durability tests.
  • Released artifact is verified as the exact published artifact: tarball inspection, consumer contract, source snapshot, publish contract (verify-package-release, release-contract / release-provenance tests).
  • WASM size budget is enforced fail-closed; any size regression fails the gate.
  • Source attestations (receipt-v1.json + sha256; point-support reference-surplus proof + verifier) were regenerated and re-pinned to the changed source closure; the chain was re-verified end-to-end.
  • Private program, consumer, fixtures and mutation/publish contract tests ship only in this private slice; the public surface is unchanged until C7c.
  • Callers remain pinned: ci-worker and publish-worker carry caller pins and guard SHAs into the job.

Verification

Stage A local gates (architecture, appsec, executable) passed after canonical attestation regeneration. Classified local REDs are tracked out-of-band, not reproduced here.

Expected external gates (CI): checks triggered at this exact head must pass. Stage B - the Linux WASM size-budget run and caller re-pin confirmation - is a deliberate fail-closed gate and is NOT claimed or proven locally in this PR.

Rollback

Branch-only change; revert is a single commit revert. No schema or data migration. Reverting restores the previous public surface unchanged.

Summary by CodeRabbit

  • Новые возможности

    • Добавлена приватная WASM-программа с JavaScript-консьюмером, браузерной проверкой и управлением жизненным циклом.
    • Материализованный выбор связан с идентичностью релиза и проверяется при компиляции.
    • Добавлена строгая валидация состава и целостности публикуемого пакета.
  • Исправления

    • Усилена изоляция приватных артефактов от публичных сборок и экспортов.
    • Повышены гарантии воспроизводимости сборки, надёжной записи и контроля размера WASM.
  • Тесты

    • Расширены CI-, браузерные, mutation- и release-тесты, включая проверки повреждений и жизненного цикла ресурсов.

…h sink

Private surface (C7c-gated): the private program, WASM consumer, fixtures and mutation/publish contract tests ship only in this private slice; the public surface stays unchanged until gate C7c is intentionally opened.

Atomic sink and lifecycle: output bindings leave through one atomic sink (atomic-write.mjs + durability tests); the build -> publish -> verify lifecycle is driven by build-private-program / prepare-npm-package with an exact WASM size budget (check-private-program-wasm-size-budget).

Release proof: verify-package-release and the release-contract/provenance tests bind the exact published artifact (tarball inspection, consumer contract, source snapshot, publish contract).

Regenerated source attestations: receipt-v1.json + sha256 and the point-support reference-surplus proof + verifier were regenerated and re-pinned to the changed source closure; the chain was re-verified end-to-end.

Stage B / local evidence: ci-worker and publish-worker carry caller pins and guard SHAs into the job; generated WASM, build receipts, metadata and local evidence stay git-ignored and are not committed.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

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: 40 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: 5a5ac8e4-e0fd-46de-b176-182b9a328cb1

📥 Commits

Reviewing files that changed from the base of the PR and between 70973c9 and 9315c19.

📒 Files selected for processing (1)
  • scripts/test_mutation.py

Walkthrough

Добавлена закрытая private Program для WASM с фиксированным ABI, lifecycle и host handoff. Selection release материализуется и входит в ContentIdentity V8. Сборка, npm tarball, manifest, публикация, browser proof и mutation proof используют канонические проверки, digest и временные бюджеты.

Changes

Private Program и Core-контракты

Layer / File(s) Summary
Materialised selection и ContentIdentity V8
crates/labcolors-core/src/selection_release.rs, crates/labcolors-core/src/program*.rs, crates/labcolors-core/src/*boundary_tests.rs
Добавлены типизированная identity release и MaterialisedSelectionV1. Selection release передаётся в компиляцию, отчёты, сертификаты и ContentIdentity V8.
Writer и host handoff
crates/labcolors-core/src/program/attachment*
Attachment API переведён на writer-контракты. Добавлены externally managed attachment, typed host commands, stamp/revision checks и подтверждаемое освобождение.
Private fixture ABI и lifecycle
crates/labcolors-core/src/private_fixture.rs, crates/labcolors-core/Cargo.toml, crates/labcolors-core/src/lib.rs
Добавлены feature-gated native/WASM fixture, request/result buffers, host imports, lifecycle states, поколения, dispose tokens и reentry protection. Тесты проверяют wire format, certification, cleanup и hostile buffer mutation.

Сборка и публикация

Layer / File(s) Summary
Каноническая private Program сборка
scripts/build-private-program.mjs, scripts/ensure-private-program-artifact.mjs, scripts/check-private-program-wasm-size-budget.mjs
Сборка фиксирует исходники и toolchain, проверяет WASM surface, создаёт receipt и поддерживает повторную byte-identical сборку.
npm package и browser proof
scripts/prepare-npm-package.mjs, packages/colors/package.json, packages/colors/private-program/consumer.js, fixtures/private-program-browser/*, scripts/test-private-program-browser.mjs
В пакет добавлены private Program artifacts и consumer. Consumer выполняет ABI-проверки, host callbacks, run/dispose и cleanup. Browser proof устанавливает проверенный tarball и проверяет CSS, receipt и lifecycle.
Tarball и release manifest
scripts/inspect-npm-tarball.py, scripts/verify-package-release.mjs, .github/workflows/publish-worker.yml, scripts/atomic-write.mjs
Добавлены каноническая USTAR-инспекция, verified snapshot, fsync-запись и manifest schema v5. Validator связывает tarball, runtime/private WASM, metadata и source/build digests перед npm publish.

CI и контракты

Layer / File(s) Summary
CI gates и mutation proof
.github/workflows/ci-worker.yml, scripts/test-private-program-mutations.mjs
CI запускает private-fixture tests, private WASM budget, browser proof и mutation proof. Mutation flow проверяет baseline tarball, toolchain, filesystem boundaries, timeouts и ожидаемые browser failures.
Release и source-snapshot contracts
packages/colors/test/*contract.test.mjs, packages/colors/test/release-contract.test.mjs, packages/colors/test/release-provenance.test.mjs
Тесты фиксируют workflow order, pinned worker, manifest v5, tarball inventory, private artifacts, canonical environment, source inode binding, atomic writes и cross-platform execution.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant buildPrivateProgram
  participant verifyPackageRelease
  participant testPrivateProgramBrowser
  participant PrivateProgramConsumer
  participant WASM
  CI->>buildPrivateProgram: build optimized private Program
  buildPrivateProgram->>verifyPackageRelease: provide WASM, receipt and metadata
  verifyPackageRelease->>verifyPackageRelease: inspect tarball and create verified snapshot
  CI->>testPrivateProgramBrowser: run proof with tarball SHA-256
  testPrivateProgramBrowser->>PrivateProgramConsumer: install verified tarball
  PrivateProgramConsumer->>WASM: run ABI request
  WASM->>PrivateProgramConsumer: return certified result
  PrivateProgramConsumer->>testPrivateProgramBrowser: return CSS, receipt and dispose status
Loading

Possibly related PRs

  • Labpics-Team/lab-colors#531: Добавляет исходную реализацию selection_release, которую этот PR расширяет материализованными releases и propagation identity.
  • Labpics-Team/lab-colors#478: Затрагивает тот же transactional point-attachment код, который этот PR расширяет для handoff и externally managed lifecycle.
  • Labpics-Team/lab-colors#447: Затрагивает revision-bound point-support/session architecture, которую этот PR расширяет в Core и WASM pipeline.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок точно отражает основные изменения: приватную declarative Program и атомарный publish sink.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/private-declarative-walking-skeleton-current

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

…before tests

On Linux, replacing an admitted source file before the digest read reused the freed inode (probe: both generations reported dev=2096 ino=1514954, and size/mtime/ctime/birthtime collided within one timestamp tick), so the (dev, ino) check passed and the receipt silently bound the replacement bytes. Admission now captures identity and bytes from one open file description; the read re-verifies both, rejecting any generation whose bytes differ. A same-size replacement regression test locks the class.

CI runs npm test before release:verify, so the ignored private WASM did not exist and release-contract tests ENOENT'd. The package test script now runs scripts/ensure-private-program-artifact.mjs first: it reuses an artifact whose build receipt verifies against the current Core source, otherwise performs the canonical build, and fails loudly instead of skipping when the build fails.
The pinned caller worker's dtolnay/rust-toolchain action exports CARGO_INCREMENTAL=0, so the in-process canonical build in ensure-private-program-artifact.mjs correctly failed its strict validator before any test ran. The test prerequisite now spawns the canonical builder as a child process whose environment drops exactly the variables isCanonicalBuildEnvOverride classifies as executor/build overrides - one exported law shared with validateCanonicalBuildEnvironment, which is unchanged and still rejects the same variables when the builder is called directly. Required pins (BINARYEN_*, RUSTUP_HOME, CARGO_HOME, PATH) pass through untouched; the ambient CLI keeps its contact-build behavior and --require-optimizer is the hermetic entrypoint.

Tests lock the boundary: override classification, hermetic filtering, preservation of required pins, the filtered environment passing the strict validator unchanged, and direct rejection of CARGO_INCREMENTAL/RUSTFLAGS/NODE_OPTIONS/NODE_PATH. Full npm test passes on a clean Linux checkout with CARGO_INCREMENTAL=0 in the parent environment and the private WASM absent: the child performs the canonical build and all 437 tests pass.
@lemone112
lemone112 marked this pull request as ready for review August 10, 2026 19:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/labcolors-core/src/program/attachment.rs (1)

882-951: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Сократите дублирование между attach и attach_external.

Оба метода выполняют одинаковую последовательность: prepare_attachment_cold, упаковку contract failure в AttachmentCreateFailureV2::Contract и admit_prepared_state с одинаковым map_err. Различаются только границы трейтов и конструктор обёртки. Выделите общий приватный помощник, который принимает функцию-обёртку. Это уменьшит риск расхождения двух путей admission при будущих изменениях контракта.

♻️ Предлагаемая структура
impl OwnerV1 {
    fn attach_with<L, A>(
        &self,
        stream_id: u32,
        authored_emissions: &[AuthoredPointEmissionBindingV1<L::OutputId>],
        authored_presentations: &[AuthoredPointPresentationBindingV1],
        family_artifacts: FamilyArtifactBundleV2,
        sink: L,
        wrap: impl FnOnce(AttachedProgramStateV1<L::Writer>) -> A,
    ) -> Result<A, AttachmentCreateFailureV2<L>>
    where
        L: UnboundPointSinkWriterV1,
    {
        // одна общая cold-подготовка и один общий admission
    }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/labcolors-core/src/program/attachment.rs` around lines 882 - 951,
Сократите дублирование в методах attach и attach_external, выделив общий
приватный помощник attach_with, который выполняет prepare_attachment_cold,
преобразует ошибку подготовки в AttachmentCreateFailureV2::Contract и вызывает
admit_prepared_state с единым map_err для
AttachmentCreateFailureV2::SinkAdmission. Передавайте в помощник функцию wrap
для создания соответствующего результата; сохраните требования трейтов и текущие
типы обёрток каждого публичного метода.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci-worker.yml:
- Around line 831-855: Устраните дублирование таймаутов в job: объявите общий
минутный бюджет рядом с существующими WASM-бюджетами и используйте его в расчёте
remaining вместо литерала 70, а также выведите миллисекундный timeout mutation
из этого же источника для LAB_COLORS_PRIVATE_MUTATION_TIMEOUT_MS. Сохраните
литерал в timeout-minutes и добавьте комментарий, что он должен совпадать с
новым WASM_JOB_TIMEOUT_MINUTES.

In `@crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json`:
- Around line 72-118: Добавьте
crates/labcolors-core/src/program/attachment/handoff.rs в PRODUCT_ARTIFACT_PATHS
и соответствующую запись artifacts в receipt с актуальными размером, лицензией и
SHA-256; если файл не должен аттестоваться, вместо этого исключите его из
заявленной области аттестации и согласованно обновите receipt.

In `@crates/labcolors-core/src/private_fixture.rs`:
- Around line 681-687: Разделите пространства значений в
`begin_dispose_status_v1`: возвращайте успешный generation-token со смещением в
зарезервированный диапазон, сохраняя `0` и коды
`PrivateFixtureErrorV1::status()` для ошибок. Обновите `abort_dispose_v1` и
`commit_dispose_v1`, чтобы они снимали это смещение перед сравнением или
использованием внутреннего token; обычные error status должны продолжить
обрабатываться без изменений.

In `@crates/labcolors-core/src/program/attachment/handoff.rs`:
- Around line 446-454: Добавьте краткий комментарий рядом с
`next_handoff_point_sink_epoch_v1`, объясняющий использование
`Ordering::Relaxed`: epoch является лишь уникальным токеном, передаваемым
вызывающему коду по значению, поэтому синхронизация с другими данными не
требуется.
- Around line 125-129: Удалите вариант HandoffPointSinkHostErrorV1::Busy,
поскольку он нигде не создаётся и остаётся мёртвым кодом, либо реализуйте его
полноценное конструирование и обработку во всех соответствующих путях handoff.

In `@packages/colors/package.json`:
- Around line 68-72: Document the local build prerequisites for the scripts in
the package scripts block, including the required Binaryen version/configuration
and pinned rustup toolchain. Explain that these pins are needed for npm run
prepack and for npm test when a valid canonical artifact is unavailable, while
preserving the existing CI and publish workflows.

In `@packages/colors/test/private-program-test-prerequisite.test.mjs`:
- Around line 106-122: Make the parent environment in the test around
hermeticBuildEnvironment explicitly define all required canonical
pins—CARGO_HOME, RUSTUP_HOME, RUST_TOOLCHAIN, and LANG—in addition to the
existing BINARYEN_* and forbidden-variable values, matching the complete setup
used by the nearby positive validator test. Avoid relying on process.env so the
strict canonical-validator assertion is deterministic outside CI.

In `@packages/colors/test/release-contract.test.mjs`:
- Line 1164: Clone PRIVATE_PROGRAM_CANONICAL_BUILD with structuredClone at each
assignment on lines 1164, 1191, and 1250 before passing the values to
validators. Update the build, context.privateProgramBuild.build, and
metadata.build assignments so each receives an independent object, preserving
meaningful deep-equality validation and preventing cross-test mutation.
- Around line 3075-3085: Нормализуйте унаследованное окружение перед
переопределением PATH: в
packages/colors/test/release-contract.test.mjs#L3075-L3085 удалите существующий
ключ пути без учёта регистра, затем установите PATH с fakeBin и pythonBin;
аналогично в packages/colors/test/release-contract.test.mjs#L2510-L2513 удалите
регистронезависимый вариант перед установкой PATH с fakeBin для shell ancestry
guard.
- Around line 3094-3099: Исправьте разбор GITHUB_OUTPUT в построении
verifiedOutputs: замените split("\n") на split(/\r?\n/u) и разбирайте каждую
строку по первому символу "=" с сохранением всего оставшегося значения, включая
дополнительные "="; сохраните текущую структуру Map.
- Around line 1331-1357: Replace the raw byte-pattern scan in the test “the
private Program WASM rejects a shared-memory section mutant” with WASM section
parsing: start after the 8-byte header, decode each section’s LEB128 size, and
advance by its complete payload until locating section ID 5. Use that parsed
memory-section offset for the existing mutant construction, preserving the
current mutation bytes and assertion.
- Around line 3050-3072: Update the Windows setup in the release-contract test
to create a local python3.exe alias in fakeBin, pointing to the executable
returned by sys.executable, before validation runs. Keep fakeBin first in PATH
and retain the existing npm.exe setup; ensure the validator’s python3 lookup
resolves through the new alias instead of asserting python3.exe in the system
Python directory.
- Around line 714-718: Добавьте общий guard для сценариев с symlinkSync: заранее
определяйте поддержку символических ссылок пробным созданием и при EPERM
пропускайте только соответствующий symlink-тест, сохраняя обычный путь проверки
при доступных symlink. Примените guard к вызовам, связанным с linkedResult и
сценариям на строках 924 и 1130–1131; не заменяйте symlink обычным файлом.

In `@packages/colors/test/release-provenance.test.mjs`:
- Around line 28-51: Make the prepack fixture validate that
PREPACK_FIXTURE_SCRIPT_FILES contains every relative script dependency reachable
from prepare-npm-package.mjs and its imported modules. Add this completeness
check around copyPrepackFixture or the related provenance test, while preserving
the intentional atomic-write omission used by the negative guard test, so
missing fixture files fail distinctly from the guard regression.

In `@scripts/build-private-program.mjs`:
- Around line 1138-1149: Вынесите проверку согласованности BINARYEN_ROOT,
BINARYEN_RELEASE и BINARYEN_NODE_SHA256 из buildPrivateProgram и
configuredOptimizer в одну общую функцию с единым текстом ошибки. Вызывайте эту
функцию в обоих местах, сохранив отдельную проверку requireOptimizer для
обязательной настройки оптимизатора.
- Around line 1092-1105: Упростите проверку валидации внутри
validatePrivateProgramBuildReceipt: уберите недостижимое условие
requireOptimizer && toolchain.optimizer === null и проверяйте только наличие
toolchain. Сохраните последующее сравнение ожидаемого дескриптора для отклонения
receipt с неподходящим optimizer.
- Around line 65-70: Wrap the module-level runtime wasm budget loading around
sharedWasmToolchain in the existing fail-based error contract, so missing or
invalid RUNTIME_WASM_BUDGET data produces a typed failure prefixed with “private
Program build:”. Preserve the current parsing and toolchain extraction behavior
on valid input.

In `@scripts/ensure-private-program-artifact.mjs`:
- Around line 55-72: Update verifiedArtifactExists to use the shared
readPrivateProgramBuildReceipt helper instead of directly reading and
JSON-parsing receiptPath, while preserving the existing validation inputs and
failure behavior. This keeps artifact verification aligned with the canonical
receipt parsing used by the release path.

In `@scripts/prepare-npm-package.mjs`:
- Around line 46-57: Remove the local WASM_MAGIC, assertWebAssemblyBinary, and
artifactMetadata definitions from the package preparation flow. Export the
existing assertWasm and artifactMetadata helpers from build-private-program.mjs,
then import and reuse them in prepare-npm-package.mjs, preserving the existing
validation and metadata shape.

In `@scripts/test-private-program-mutations.mjs`:
- Around line 364-460: Extract the shared lexical and physical boundary
admission primitives from assertAdmittedTree and assertAdmittedRegularFile into
a reusable module, then update test-private-program-browser.mjs and
build-private-program.mjs to use it instead of assertStrictlyContained,
assertNoLinkPath, and pathIsWithin. Preserve the existing symlink,
filesystem-object, and boundary validation behavior at all call sites.

---

Outside diff comments:
In `@crates/labcolors-core/src/program/attachment.rs`:
- Around line 882-951: Сократите дублирование в методах attach и
attach_external, выделив общий приватный помощник attach_with, который выполняет
prepare_attachment_cold, преобразует ошибку подготовки в
AttachmentCreateFailureV2::Contract и вызывает admit_prepared_state с единым
map_err для AttachmentCreateFailureV2::SinkAdmission. Передавайте в помощник
функцию wrap для создания соответствующего результата; сохраните требования
трейтов и текущие типы обёрток каждого публичного метода.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 81d33f07-14eb-470b-801f-d8e564eb65d6

📥 Commits

Reviewing files that changed from the base of the PR and between 8ef36aa and 6ce4d6d.

📒 Files selected for processing (46)
  • .github/workflows/ci-worker.yml
  • .github/workflows/publish-worker.yml
  • crates/labcolors-core/Cargo.toml
  • crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json
  • crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.sha256
  • crates/labcolors-core/contracts/point-support-reference-surplus-q55-bps-proof-v1.json
  • crates/labcolors-core/src/generic_boundary_tests.rs
  • crates/labcolors-core/src/lib.rs
  • crates/labcolors-core/src/private_fixture.rs
  • crates/labcolors-core/src/program.rs
  • crates/labcolors-core/src/program/attachment.rs
  • crates/labcolors-core/src/program/attachment/handoff.rs
  • crates/labcolors-core/src/program/attachment/support.rs
  • crates/labcolors-core/src/program/attachment/tests.rs
  • crates/labcolors-core/src/program_boundary_tests.rs
  • crates/labcolors-core/src/program_clean_set_tests.rs
  • crates/labcolors-core/src/program_identity.rs
  • crates/labcolors-core/src/program_identity_tests.rs
  • crates/labcolors-core/src/program_relation_tests.rs
  • crates/labcolors-core/src/program_session.rs
  • crates/labcolors-core/src/selection_release.rs
  • crates/labcolors-core/src/selection_release_materialisation_tests.rs
  • fixtures/private-program-browser/index.html
  • fixtures/private-program-browser/proof.mjs
  • packages/colors/.gitignore
  • packages/colors/package.json
  • packages/colors/private-program/consumer.js
  • packages/colors/test/atomic-write-durability.test.mjs
  • packages/colors/test/private-program-ci-contract.test.mjs
  • packages/colors/test/private-program-consumer.test.mjs
  • packages/colors/test/private-program-mutation-contract.test.mjs
  • packages/colors/test/private-program-publish-contract.test.mjs
  • packages/colors/test/private-program-source-snapshot-contract.test.mjs
  • packages/colors/test/private-program-test-prerequisite.test.mjs
  • packages/colors/test/release-contract.test.mjs
  • packages/colors/test/release-provenance.test.mjs
  • scripts/atomic-write.mjs
  • scripts/build-private-program.mjs
  • scripts/check-private-program-wasm-size-budget.mjs
  • scripts/ensure-private-program-artifact.mjs
  • scripts/inspect-npm-tarball.py
  • scripts/prepare-npm-package.mjs
  • scripts/test-private-program-browser.mjs
  • scripts/test-private-program-mutations.mjs
  • scripts/verify-package-release.mjs
  • scripts/verify_point_support_surplus.py

Comment thread .github/workflows/ci-worker.yml
Comment thread crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json
Comment thread crates/labcolors-core/src/private_fixture.rs
Comment thread crates/labcolors-core/src/program/attachment/handoff.rs
Comment thread crates/labcolors-core/src/program/attachment/handoff.rs
Comment thread scripts/build-private-program.mjs
Comment thread scripts/build-private-program.mjs
Comment thread scripts/ensure-private-program-artifact.mjs
Comment thread scripts/prepare-npm-package.mjs Outdated
Comment thread scripts/test-private-program-mutations.mjs
…ts and release

Both the package test prerequisite and release:verify now produce the private
Program artifact through one child-boundary primitive
(run-canonical-private-program-build.mjs): spawn, env filtering, and timeout
live in a single module, the child environment drops exactly the
isCanonicalBuildEnvOverride overrides, required toolchain pins pass through
untouched, the strict direct validator is unchanged, and child failure
propagates loudly. This closes the release path under the pinned caller
worker's ambient CARGO_INCREMENTAL=0, which previously failed the in-process
build in verify-package-release.mjs.

test_mutation.py: the publish-worker registry test now parses the multi-line
run block scalar semantically and proves fail-closed behavior against eight
hostile mutants (second npm publish, missing --ignore-scripts, wrong or
alternate registry, unquoted or foreign tarball, missing pre-publish sha256
recheck, injected NPM_REGISTRY), while still asserting exactly one publish,
the exact quoted tarball, and the adjacent recheck.

Latent release blocker surfaced by the required release:verify proof:
expectedPackedFiles rejected npm's declared "./index.d.ts" types spelling
under the stricter pack-path normaliser; the types field is now normalised
exactly like an export target.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/colors/test/private-program-test-prerequisite.test.mjs`:
- Around line 154-165: Усилить тест вокруг runCanonicalPrivateProgramBuild:
проверить не только импорт и наличие экспортов, но и фактическое использование
общего примитива обоими consumer-модулями ensurePrivateProgramArtifact и
verifyPackageRelease. Добавьте наблюдаемую проверку через контролируемую
dependency injection либо отдельный контракт consumer-модулей, чтобы локальная
копия build-логики не проходила тест.

In `@scripts/test_mutation.py`:
- Around line 2110-2130: Усилить validator в _assert_publish_script_fail_closed,
связав SHA-256-проверку с точным путём "$TARBALL_PATH": проверять наличие
команды actual_sha256="$(sha256sum --binary -- "$TARBALL_PATH")", а не
независимых фрагментов. В словаре mutants добавить отдельную мутацию, заменяющую
аргумент этой команды на "$FOREIGN_PATH", и убедиться, что она отклоняется.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0d2bd57d-6434-459e-be24-a3d353bc4203

📥 Commits

Reviewing files that changed from the base of the PR and between 6ce4d6d and 929ac08.

📒 Files selected for processing (6)
  • packages/colors/test/private-program-test-prerequisite.test.mjs
  • packages/colors/test/release-contract.test.mjs
  • scripts/ensure-private-program-artifact.mjs
  • scripts/run-canonical-private-program-build.mjs
  • scripts/test_mutation.py
  • scripts/verify-package-release.mjs

Comment thread packages/colors/test/private-program-test-prerequisite.test.mjs
Comment thread scripts/test_mutation.py
begin_dispose_v1 returned raw generation tokens from the same small-integer
range as PrivateFixtureErrorV1 status codes, so after twelve run/dispose
cycles a live token 12 was indistinguishable from InternalInvariant and a
consumer could leave the attachment Disposing forever. Live tokens now live
in [0x10000000, 0x1fffffff], disjoint from every status code and both
sentinels; abort/commit decode the wire token and fail closed with
InvalidDisposeToken outside the live range. Remove the never-constructed
HandoffPointSinkHostErrorV1::Busy variant and document why Relaxed ordering
suffices for the handoff epoch counter.
… budgets

- derive the wasm-job deadline ledger and the mutation ms timeout from one
  WASM_JOB_TIMEOUT_MINUTES budget source instead of duplicated literals
  (timeout-minutes keeps its match-required comment)
- export assertWasm/artifactMetadata from build-private-program.mjs and reuse
  them in prepare-npm-package.mjs; drop the duplicated local helpers
- wrap the runtime WASM toolchain pin read in the typed fail contract and
  simplify the unreachable optimizer-null branch; share one
  assertOptimizerConfigurationComplete law between configuredOptimizer and
  buildPrivateProgram
- make the hermetic child environment test deterministic outside CI by
  spelling out every canonical pin instead of inheriting process.env
- guard symlink scenarios with a real symlink-support probe (EPERM on Windows
  without Developer Mode skips only the symlink scenario), create a fakeBin
  python3.exe alias instead of asserting a system python3.exe, normalize the
  inherited PATH key case-insensitively before substitution, and parse
  GITHUB_OUTPUT on the first '=' with CRLF-tolerant splitting
- locate the WASM memory section by parsing section headers instead of
  scanning for the byte pattern; add a decoy regression test
- make the prepack fixture closure-check its relative import graph so an
  incomplete fixture fails distinctly from the guard regression
- document the local Binaryen/rustup pins required by npm test and prepack
The shared-helper refactor removed the local sha256 arrow function while
prepareNpmPackage still calls it when building build-metadata.json, which the
release gate exercised as ReferenceError: sha256 is not defined. Restore the
helper and lock the definition in the prepack source contract test so the
removal fails there instead of inside the release verifier.
@lemone112

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Close two CodeRabbit Major threads (test-strength only, no production
defect).

F1: the prerequisite test no longer checks only export existence — it now
asserts the consumer-module contract for both consumers: each must import
and call runCanonicalPrivateProgramBuild from the canonical module and must
not embed its own build boundary (spawnSync, hermeticBuildEnvironment,
isCanonicalBuildEnvOverride, CHILD_BUILD_TIMEOUT_MS, --require-optimizer).
A local copy of the build logic inside a consumer is rejected by the mutant
loop, and a scratch regression with a local-copy consumer fails the
strengthened test while the real consumers pass 6/6.

F2: the publish-worker registry validator binds the exact pre-publish
commands instead of independent fragments — the sha256 command must be
exactly actual_sha256="$(sha256sum --binary -- "$TARBALL_PATH")" and the
digest comparison must be the exact guarded if-line. A new foreign-sha256sum
mutant is rejected; a scratch demonstration shows the fragment-only
validator lets a foreign-path hash with a spurious "$TARBALL_PATH" mention
slip through while the exact-command validator rejects it.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/test_mutation.py (1)

2191-2216: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Запретите переназначение TARBALL_PATH перед публикацией.

Текущая проверка принимает мутацию TARBALL_PATH="/tmp/foreign.tgz" перед sha256sum. В этом случае перепроверка и npm publish используют другой файл. Добавьте проверку запрета присваиваний в publish-шаге и мутацию для этого случая. Проверьте также записи TARBALL_PATH через GITHUB_ENV в предыдущих шагах job.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/test_mutation.py` around lines 2191 - 2216, Extend the publish-step
validation around publish_index/pre_publish to reject any reassignment of
TARBALL_PATH before npm publish, including shell assignments and writes through
GITHUB_ENV in earlier job steps. Add a mutation case that changes TARBALL_PATH
to a foreign tarball before the sha256sum check, and assert the generated
workflow detects and rejects it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/colors/test/private-program-test-prerequisite.test.mjs`:
- Around line 184-206: Update assertDelegatesToSharedPrimitive in the test to
validate the shared import and runCanonicalPrivateProgramBuild invocation
without depending on quote style, whitespace, or whether an options object is
passed. Use AST inspection or equivalent formatting-tolerant matching, while
preserving the existing rejection of embedded build-boundary symbols.

In `@packages/colors/test/release-provenance.test.mjs`:
- Around line 53-63: Расширьте проверку в assertPrepackFixtureScriptClosure,
чтобы она находила относительные импорты и реэкспорты с одинарными или двойными
кавычками, включая пути ./ и ../, а также динамические вызовы import().
Извлекайте имя .mjs-файла из всех поддерживаемых форм и проверяйте каждый
найденный файл через scriptFiles.includes, сохранив существующее сообщение об
отсутствующей зависимости.

In `@scripts/build-private-program.mjs`:
- Around line 1114-1120: Update the failure handling after toolchain selection
in the surrounding build flow to distinguish requireOptimizer === true from
requireOptimizer === false. Preserve the existing optimized-artifact message for
the canonical path, but use a receipt/build.toolchain-specific message when
requireOptimizer is false and receipt?.build?.toolchain is missing.

---

Outside diff comments:
In `@scripts/test_mutation.py`:
- Around line 2191-2216: Extend the publish-step validation around
publish_index/pre_publish to reject any reassignment of TARBALL_PATH before npm
publish, including shell assignments and writes through GITHUB_ENV in earlier
job steps. Add a mutation case that changes TARBALL_PATH to a foreign tarball
before the sha256sum check, and assert the generated workflow detects and
rejects it.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 824eca31-6444-4103-bf87-babd3e018fe1

📥 Commits

Reviewing files that changed from the base of the PR and between 929ac08 and 70973c9.

📒 Files selected for processing (14)
  • .github/workflows/ci-worker.yml
  • crates/labcolors-core/src/private_fixture.rs
  • crates/labcolors-core/src/program/attachment/handoff.rs
  • packages/colors/README.md
  • packages/colors/private-program/consumer.js
  • packages/colors/test/private-program-ci-contract.test.mjs
  • packages/colors/test/private-program-consumer.test.mjs
  • packages/colors/test/private-program-mutation-contract.test.mjs
  • packages/colors/test/private-program-test-prerequisite.test.mjs
  • packages/colors/test/release-contract.test.mjs
  • packages/colors/test/release-provenance.test.mjs
  • scripts/build-private-program.mjs
  • scripts/prepare-npm-package.mjs
  • scripts/test_mutation.py

Comment thread packages/colors/test/private-program-test-prerequisite.test.mjs
Comment thread packages/colors/test/release-provenance.test.mjs
Comment thread scripts/build-private-program.mjs
@lemone112

Copy link
Copy Markdown
Collaborator Author

@coderabbitai resolve

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
✅ Action performed

Comments resolved and changes approved.

…n publish

Close the final verifier class: a mutant that reassigns
TARBALL_PATH="/tmp/foreign.tgz" immediately before the exact
sha256 recheck command vacuously satisfies every exact-command binding while
both the recheck and npm publish operate on the foreign path.

The validator now rejects ANY assignment to TARBALL_PATH or TARBALL_SHA256
inside the publish script (bare, export/readonly/local, env-prefixed, or +=)
- the identities are bound exactly once by the workflow env block and must
never be rebound in the script. Three mutants lock the class: a bare
TARBALL_PATH rebind, an export-form rebind, and a TARBALL_SHA256 rebind,
each placed before the recheck. RED first: all three slipped through the
previous validator; sabotage check: removing the rule lets all three slip
again. Full scripts/test_mutation.py: 56/56; the real publish-worker.yml
script passes the strengthened validator unchanged.
… write blacklist

The isolated verifier proved that no blacklist of shell write mechanisms can
close the rebinding class: printf -v TARBALL_PATH, read -r TARBALL_PATH,
eval 'TARBALL_PATH=...', indirect printf -v via a name variable, and
positional indirection all survive assignment-pattern checks while still
rebinding the verified tarball identity before the recheck.

The token-bearing publish step now has a canonical golden contract: the
validator requires the run block to be byte-for-byte the reviewed canonical
form, so every deviation - a rebind by any mechanism, a reorder, an added
indirection, even a comment - is rejected, and any legitimate workflow change
is an explicit reviewed golden update. Five mutants lock the verifier's
exact forms; RED first showed all five slipping through the blacklist,
GREEN rejects all seventeen mutants, and the sabotage check (golden removed)
lets exactly those five slip again. The real publish-worker.yml script
passes the golden unchanged. Full scripts/test_mutation.py: 56/56.
@lemone112
lemone112 merged commit beecd25 into main Aug 11, 2026
10 checks passed
@lemone112
lemone112 deleted the codex/private-declarative-walking-skeleton-current branch August 11, 2026 05:19
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