Skip to content

ci: skip unchanged workspace builds by a complete input stamp instead of rebuilding in every runtime hook #2319

Closed as not planned

Description

@schlessera

Decision (maintainer, 2026-10-22): design accepted; Gate 0 authorized after #2458

Ruling on §1b of the stronger-boundary design:

  1. Design accepted as the stronger-boundary deliverable, with its findings: §1 items 1–4, the §1a dispositions, and R1–R4 as the irreducible residual for TypeScript (T) outputs.
  2. Gate 0 authorized (design §8.1), to start once fix(ci): build runtime packages once per test invocation #2458 merges. Limits: at most 3 engineer-hours, artifacts of at most 6 existing CI runs, no dispatch, no build-qualification execution. Rerun Gate 0 if fix(ci): build runtime packages once per test invocation #2458 is abandoned or changes its invocation model.
  3. Second receipt shape for fix(ci): build runtime packages once per test invocation #2458 hooks: acceptable in principle. An isolated receipt bound to a committed generation and the key may later be accepted alongside real tsc receipts, so same-root reuse is not ruled out by construction. Its concrete shape still needs its own ruling and is only considered if Gate 0 reports value.

Gate 0 brief (the only authorized work)

Compute the §8.1 net saving per job from existing artifacts at the merged #2458 head: the tmp/*-probe.json workspace-build receipts (including tmp/unit-worker-N-build-*-probe.json), #2458's build-start, build-attested and build-unattested events, runtime-hook events and the pack log. Count eligible same-root repeats per package, including build-unattested fallbacks to per-file hook builds; equal repeat.before.sha256 values are candidates only, and unavailable key identity counts as unknown.

Deliverable: one issue comment reporting exactly one of value, no net value (confirmed net saving ≤ 0) or insufficient evidence (missing or ambiguous data), with the per-job table, the runs and SHAs used, and hours spent. Gate 0 stops there.

Not authorized: Gates 1–3, any implementation of the stronger boundary, any hosted or offline qualification run, activation, or changes to the dormant operation. Ordinary rebuilding stays active. After Gate 0 reports, return the issue to needs: decision for §1b item 3 (on no net value or insufficient evidence) or item 4 (on value). The original acceptance criteria stay open; nothing here withdraws them.

2026-10-22 correction: folded the maintainer's §1b ruling into the brief; needs: decision replaced by blocked on #2458 with agent-ready for the bounded Gate 0 desk work only.

2026-10-22 Gate 0 reported: #2458 merged as 736a3445e, which removes blocked. Gate 0 found insufficient evidence (result). Every job has 0 confirmed same-root repeats except captures: its capture:verify second pass rebuilds all 19 packages in the same root, with unknown key identity. agent-ready is replaced by needs: decision for the in-scope question on that repeat, then §1b item 3. Gates 1–3 stay unauthorized.

Dormant slice merged and main proof verified — 2026-10-20

PR #2449 merged as e9bd4621486fa07ced9c2c576e03603fd7f0eba1, with independently verified parent 510c2909b666b37880999fc50e5759c11591db33 and tree 14ec0d2d77cb10abfcbdaf18f33c733b961934d2; the squash is present on remote main. This delivers the dormant operation, actual producer-context binding and malformed-policy ordinary-fallback correction under Refs. The maintainer's activation deferral remains binding: production is unqualified, CI intent is off, and ordinary builds remain active without Docker.

Confirmation run 39377232609, attempt 1, passed all 17 selected jobs. Every actual checkout log names 79b3af810f16d39792e7e35c724871379e69412b, whose parents are the recorded base and head 1eafd54e6256400134a4071958ebea9b4eb8ea99 and whose tree matches the squash. The aggregate's candidate and selected-proof receipts agree: all nine categories freshly pass, no retained categories, unit shards 1–4. The controller performed the guarded merge and released reservation 42e30bb3c750dae8e362a59f1808863e; independent readback finds no active reservation.

Measured confirmation: 2 s from event to first job, 1,284 s elapsed (21m24s), 9,814 summed job seconds (163m34s), zero cancellations. Unit (3) was longest at 1,192 s. These are execution costs, not host CPU or a matched optimization gain. Required current-head preflight remains 969 fast tests / 6,435 assertions plus 70 affected tests / 759 assertions, costing 79.53 s wall / 134.98 s host CPU. Prior focused, mutation and native/runtime controls retain their original source attribution.

Automatic main-push CI 39379334227, attempt 1, completed SUCCESS. All 17 actual job checkout logs independently name squash e9bd4621486fa07ced9c2c576e03603fd7f0eba1; its verified tree remains 14ec0d2d77cb10abfcbdaf18f33c733b961934d2. The integrated aggregate confirms all nine selected categories passed freshly, with no retained proof and unit shards 1–4. No retry or additional dispatch was used. Main cost: 3 s event-to-first-job, 1,229 s elapsed (20m29s), 10,450 summed job seconds (174m10s), zero cancellations; unit (3) was longest at 1,157 s. These measurements do not establish a matched optimization saving.

The merge-window reservation was released by the successful confirmation controller. Fresh canonical readback at coordination commit 228c8781f9bb7323767d329ae2c3fd9c00ba74dc has active: null and records release of reservation 42e30bb3c750dae8e362a59f1808863e. No lock is retained for post-merge CI. PR and issue retain milestone 0.44.0.

#2319 remains OPEN for its unchanged original optimization, ambient/provenance and comparable hosted-cost criteria. Activation is explicitly deferred; a stronger deterministic runtime/native-build boundary requires a separate specification and ruling. The completed dormant slice does not authorize that work or satisfy those criteria. agent-ready is removed to avoid unattended activation work. Parent claim e1849-2319-parent-confirm-r5 is released for this handoff; automatic main-proof reconciliation is now complete. Source, indexed evidence and historical failures are preserved.

R5 review checkpoint before parent refresh — 2026-10-20

Draft #2449 now has prepared candidate dfa31b3e72bd9e970c08a7161f725b22bcfd09f7, tree c5c029d1ca291df1ec340fb68a81271b2a76e389, tested base 9203e85966b409bfb4d645d48cc37344186d68e3. The maintainer ruling explicitly defers activation and retains this dormant operation/context slice under Refs #2319. Production remains unqualified, CI intent remains off, and ordinary rebuilding stays active without Docker. Original optimization, ambient/provenance and comparable hosted-cost criteria remain OPEN after any dormant delivery; they are neither waived nor moved out of this issue.

Independent review covered all 28 changed files. One concrete correction: parseable qualification policies with null producer/configuration maps threw outside the fallback guard and aborted the real ordinary build. The completeness check now shares the existing policy-read exception boundary. Both cases fail at ORDINARY_BUILD_COMPLETES_WITHOUT_QUALIFIED_POLICY before the fix and when it is reverted; byte-identical restoration passes. Three actual build-entrypoint cases / 39 assertions verify real compiler/Node consumption, force/subset/jobs behavior and zero Docker attempts for malformed maps, dormant/invalid intent and aliased policy. The same-class audit covers both map reads and the other policy call sites.

Proof at the recorded r5 head: focused 107 tests / 848 assertions; bun run check:pr --base origin/main passes 969 fast tests / 6,401 assertions plus 70 affected-import tests / 759 assertions; strict types pass. Initial preflight correctly refused bubblewrap 0.9.0's 411.6 ms setup under the unchanged 250 ms gate. A separately built, checksum-verified private bubblewrap 0.13.1 passes three setup probes and 66 real launcher/filesystem-filter/sandbox tests / 265 assertions; command-scoped PATH then passes preflight. The system tool, images and deadlines are unchanged. Initial refusal and an intermediate tooling-link failure remain retained.

Main integration is isolated in 889deebd469d9f1bcfdf00bdac8c52ea965cb8db; correction/docs are in dfa31b3e72bd9e970c08a7161f725b22bcfd09f7. Tested base includes the new sandbox prerequisite, earlier candidate admission, stable Docker fixtures and artifact retention. Subsequent live main 510c2909b666b37880999fc50e5759c11591db33 changes only the local preflight CLI test fixture (#2451); that delta was inspected, not merged or relabeled as tested. Parent must reconcile live base and merge-checkout identity for confirmation.

Historical runtime evidence remains separately attributed below. This round reverified 29 indexed raw receipts/controllers/captured helpers plus eight context receipts, confirming distinct actual context containers, real affinity change, compiler/probe mismatch, intended omitted-guard failures and restoration. It did not replay the all-package/native/browser controls. In particular, newly integrated main includes a ui-server source correction, so older packed-package results are not current combined-tree package proof. Generated producer qualification remains conservative; no pins were refreshed merely to grant admission.

Timed work in this round totals 193.67 s summed wall / 282.98 s host CPU, including failed setup/link preparation, installation, mutation controls and validation. Parallel commands overlap; these sums are not session elapsed. Untimed acquisition/extraction/review and historical runs are excluded. No Docker product controller or hosted confirmation ran here; no matched saving is claimed. Earlier capture/lookup costs keep their original attribution below.

Claim e1849-2319-20261020-r5-dormant returns the prepared candidate to parent coordination and releases only its own assignment. Required parent review and exact-candidate selected hosted proof remain pending. This worker does not reserve the canonical slot, mark ready, merge or close #2319. PR and issue retain release 0.44.0.

Prior r4 candidate and source-bound proof — 2026-10-20

Draft PR #2449 preserves the implementation under Refs #2319. Head 3e5be8f234ca7c9ee69f555f6040be5d72997902, tree 9cab2d0c2fd3d1e5b8293cfa22195bc6c919648c, branch feat/2319-isolated-ci-build-r4; tested base 1f88a7a3018fc669f0dd8d97bd36572d8b315b03. The live PR base subsequently advanced to 8ac0fc6cfd7f4142f961deac260e6a1b98f6c415; only the independently owned worker temporary-environment test changed, and this candidate was not automatically refreshed. Exact earlier identities remain intact.

Decision (maintainer, 2026-10-20): defer activation and retain the dormant operation/context fix. Production qualification stays unqualified and ordinary rebuilding remains the active behavior. The dormant slice in #2449 can continue through scoped review and required proof as a Refs delivery. This does not satisfy, waive or close the original unchanged-output reuse, ambient/provenance or comparable hosted-cost criteria. A stronger deterministic runtime/native-build boundary is not authorized by this decision and would need a separate specification and ruling before activation work resumes. Release 0.44.0 remains assigned to the independently reviewable dormant slice.

Implemented and freshly checked:

  • Each eligible lookup owns a new bounded fixed-image context reader. Actual daemon identity, boot/kernel/version, CPU affinity and Node bytes enter the lookup identity; the real compiler independently checks context before publication. Real affinity drift with the identity guard omitted yields zero-child stale reuse and the intended PRODUCER_CONTEXT_DRIFT_MUST_REFUSE_REUSE red. Restored guards refuse mismatched publication; restoring original context restores repeat reuse. Real SIGTERM during the context reader fails the guarded operation; omitting that guard reaches CONTEXT_INTERRUPT_MUST_NOT_RETURN_SUCCESSFUL_REUSE, and the restored normal path passes.
  • Main reconciliation is separately committed (2b0c9ecd0, then chore(ci): coordinate exact candidate integration with expiring leases #2197 integration bb4f6bfcb). The repeat-observation import is retained in the producer/copy closure. Current generated-input qualification continues to refuse changed producers; three stale pins were not simply replaced to obtain admission. Observation identity never grants cache eligibility.
  • Fresh all-nineteen cold/repeat/packed-consumer/trace execution passes the original package inventories, default exports, types/bin/import probes and React 18 checks. Four offline installers verify 2,047 payload records against 584 archived third-party packages. Fresh Chromium 153.0.8010.12 / pinned Node 24.20.0 renders public BrainMarkdown, with no first-party source imports and all 6,526 first-party files unchanged across the consumer. The prior native/browser causal controls below retain their own source attribution.
  • Fresh output tampering rebuilds one/reuses eighteen; derived CSS subset recovery rebuilds one/reuses five; forced jobs=2 compiles six selected packages and the next repeat omits six. All nineteen output identities restore. Existing lease/ordinary-fallback tests retain their assertions. Thirty-three associated context/producer/native/browser container IDs are independently absent.
  • Current-head bun run check:pr --base origin/main passes 959 fast tests / 6,361 assertions and 67 affected-import tests / 720 assertions, with lint/leakage clean. Strict types pass; additional focused guards pass 47 tests / 511 assertions. No selected hosted confirmation has been requested. The parent coordinates any later confirmation separately from activation.

The runtime controls retain exact captured input identity 475e003b8c6d9c3a90fceb3ce8ed7060ed59467205ea973124b61959b516e491. They precede the separately assessed #2197 procedure merge, two additional receipt-failure test cases and unused-import cleanup. The executed producer/package behavior is unchanged by those final differences; these are source-bound receipts, not a fabricated current-combined-tree run or eligibility grant. Retained failures include a rejected proc mount, incorrect browser-harness props and the first preflight's unused import/concurrent scratch scan. Successful corrections do not erase those receipts. All 64 retained r3 files were independently length/SHA256 verified; the purged historical eighteen-arm archive was not recovered.

Finite ambient/provenance findings:

  • The selected all-nineteen syscall observation completes. Both operands of 93 rename/renameat calls resolve to fresh private state; 43 normalized kernel/device operand classes remain explicit. That finite operand review does not prove output independence or observe all reads.
  • Diagnostic entropy interception reaches the actual nested LightningCSS 1.32.0 and Oxide 4.3.3 binaries. Altered returned entropy, diagnostic clock settings and narrowed affinity preserve the tested ui-kit CSS; this bounded equality is not general qualification. Direct vDSO execution bypasses the intercepted clock with an observed 86,400-second delta. Static Bun/direct syscalls, vDSO and hardware paths remain unclosed.
  • Oxide's Sigstore provenance now verifies the consumed archive subject and release workflow identity; a tampered payload fails verification. The consumed LightningCSS binary matches its signed registry archive, but no source/build attestation was available in registry metadata or the checked upstream binary/tarball endpoints. Its GNU release uses floating Rust and image inputs. Registry integrity does not establish source-to-binary provenance.

The scope choice is resolved in favor of deferral. The fixed-container flags, hashes and finite equal-output samples remain insufficient for activation; no unknown input or missing provenance is reclassified as qualified. Remove the resolved needs: decision label and resume only review, necessary corrections and proof for the dormant slice. #2319 stays open after any Refs merge for its deferred optimization criteria. No access or archive-loss blocker is inferred.

Before original optimization completion: establish the selected ambient/provenance boundary, qualify the final reviewed producer/input identity, obtain necessary exact-candidate selected hosted proof, and measure comparable hosted setup/runtime-hook/critical-path costs including capture/lookup/publication overhead. Historical 606.090 executed builder seconds remain opportunity, not saved elapsed time.

Measured fresh local operation costs are cold 85.963 s, repeat 20.741 s, packed consumers 121.560 s, and observed trace 119.011 s. Cold capture/lookup costs 20.310/1.272 s; repeat capture/lookup costs 18.327/2.413 s. The four-arm controller costs 395.86 s wall / 143.00 s host CPU; force/subset/output controls 172.20 s / 120.40 s; context-reader interruption control 276.66 s / 115.56 s, including workspace lease waiting. Docker CPU is excluded. No valid hosted saving is established.

Claim e1849-2319-20261020-r4 owns this implementation handoff. Its assignment was released and verified absent after live ownership readback; the draft/branch and indexed private receipts are retained. The earlier sections below are historical checkpoints and do not override this current status or the original acceptance criteria.

Prior r3 qualification checkpoint — 2026-10-20

Continuation claim e1849-2319-20261019-r3 has completed two fresh narrow causal controls on preserved source 8e11437fb053277cd8793157eda1b8289d998341 (tree 803ddc8985ecb45a1cf8abf71f91c0f2bda720cb), branch feat/2319-isolated-ci-build-r3. No committed source change, main integration, PR, activation, hosted dispatch or completion is claimed. Production policy remains unqualified; unsupported inputs retain ordinary rebuilding without requiring Docker.

Fresh bounded readback verifies the original fixed Docker endpoint (29.8.2) and installed policy image sha256:eff16c30e6f3f4af0a03fa4b706120d5e9b0891c344a27d64559aff5900a4a27. No daemon restart, endpoint substitution or image pull was used. Docker access is not the current blocker.

Evidence recovery: the maintainer confirms old worktrees were purged. The former qualification worktree and named temporary evidence locations are absent, with no replacement location supplied. This does not establish that every external archive was deleted. Historical eighteen-arm, nineteen-package and cleanup reports below are historical summaries; their raw archives/runtime receipts were not recovered or reverified. The corrected private controller code was recovered from recorded source/patches and matches SHA256 60b22882e15df47fcc91820f9fa796195b1f45444f196ef1f5f66d73ea5da0ba. Code recovery is not runtime evidence recovery. All results below are new executions with retained raw receipts.

Fresh evidence:

  • Focused guards: 25 tests / 171 assertions; consumer/qualification tests: 13 / 38. Actual output-identity mutation fails CI_BUILD_OUTPUT_DRIFT_REFUSES_REUSE on its intended assertion; byte-identical restoration passes. Five bounded process-group controls pass, including the intended PRIVATE_NATIVE_ORDINARY_GROUP_ABSENCE_REQUIRED mutation failure. These do not replace complete runtime proof.
  • Actual native producer: resolution identifies Tailwind's nested LightningCSS 1.32.0, rather than root 1.33.0 targeted by the recovered controller. Its consumed binary matches the lock-integrity-verified official archive. New setup on pinned Node 24.20.0 proves original transform delegation plus an exact CSS sentinel. The new native controller targets that consumed binary.
  • Native causal result: cold five-package ui-kit closure runs real compilers. Changed native input is refused by the original guard. Omitting installation/full-input identities yields actual zero-child stale reuse and the intended NATIVE_PRODUCER_DRIFT_REACHES_PUBLISHED_STYLESHEET assertion fails. Restored guard falls back to the real ordinary build; changed CSS reaches the actual packed stylesheet byte-for-byte (NATIVE_TARBALL_CONSUMES_EXACT_CHANGED_STYLESHEET, NATIVE_PRODUCER_DRIFT_REACHES_PACKED_STYLESHEET). Restoring the original native bytes recompiles only ui-kit, reuses four unaffected outputs, and restores original output identities. Actual ordinary fallback uses Bun 1.4.2 and Node 18.19.1, separately attributed from pinned-image Node 24.20.0. Both owned producer containers were drained, removed and independently confirmed absent.
  • Packed real browser causal result: six-package ui-react closure, four arms, 24 real package tarballs. Public BrainMarkdown renders from packed default exports in Chromium 153.0.8010.12 / pinned Node 24.20.0. The bundle has 5,082 inputs, includes the public dist entry and no first-party source imports. Source-input omission gives zero compiler children, correct baseline text with no page errors, then the intended BROWSER_ISOLATED_UI_REACT_SOURCE_MARKER failure. Restored guard rebuilds and the marker reaches the DOM. Original source restoration restores all six output identities and the unmarked browser render. Output identities are checked before/after each consumer so a hidden rebuild cannot mask stale dist. All three producer and four browser containers were independently confirmed absent. This is a standalone default-export/source-marker control, not the full chat-focus functional suite.

Proof boundaries used ordinary UID, route-free networking, dropped capabilities, no-new-privileges, read-only producer inputs/root, private HOME/tmp/output, and bounded owned process/container lifetimes. Package acquisition and native-header preparation occurred separately before offline proof. No test guarantee was reduced.

Measured costs: native successful control 151.54 s, browser four-arm control 223.50 s; all timed commands 477.29 s wall-sum and 388.59 s host CPU, including 36.39 s private frozen installation and a retained 62.81 s preparation failure caused by a symlinked policy copy before producer start. That preparation was corrected to a physical policy copy. Docker child CPU, untimed preparation/tracker work and session elapsed are not represented by these totals. Input capture alone costs roughly 22.6–26.8 s per measured operation. Unsafe zero-child arms are counterfactuals, not valid savings. No comparable hosted saving is established.

Still required, within this issue:

  1. Actual producer boot/kernel/context binding at a later reuse lookup. workspaceScope currently observes host context; equality during one container lifetime does not bind a future lookup.
  2. Finite source-specific closure and causal evidence for clock/entropy (including native/vDSO paths), CPU affinity/concurrency/hardware, active ambient filesystem/syscall operands, and source-to-binary provenance. Container flags, hashes and repeated equal output alone cannot establish these classes. General complete closure is not established by the present bounded design.
  3. Integration with main assessed at cea53611ddea4916ac323060bfef42ec18118fea, merge-base 8f9d2ceaa6df72e46a6feccec3f3a96292f18648: reconcile the new build-repeat-observation.ts import and relevant build/pack/workflow changes. Literal first-party import audit covers 17 files; diagnostic ci-pack.ts is outside the explicit producer-pin list. Three generated-input pins are stale (ci-build-evidence.ts, ci-build-consumers.ts, ci-build-operation.ts) and currently refuse the candidate; do not update them merely to turn admission green. Observation identity is not cache eligibility.
  4. Required package/browser/compatibility proof on the final reviewed source, plus comparable hosted setup/runtime-hook/critical-path timings including identity overhead. Historical summaries cannot substitute for missing raw receipts or combined-tree proof.

Next step: preserve these source-bound fresh receipts, resolve the concrete producer-context and ambient-closure gaps before any activation, then reconcile current imports/pins on a separately attributed integration candidate. Where inputs cannot be qualified, keep safe ordinary rebuilding. The parent coordinator will review the handoff and choose later hosted confirmation. No human-access blocker or new decision waiver is inferred from the archive purge. This continuation releases only its own claim; the issue stays open.

2026-10-20 correction: replaced stale in-progress qualification prose with newly executed red/green/restored results, precise evidence-loss limits, integration gaps and measured costs. Earlier sections below remain dated historical reports, not current raw proof.

Earlier successful setup receipts (2026-10-18)

The authenticated development-service prerequisite is resolved. The original fixed Docker socket now accepts daemon calls, and the already installed immutable producer image was read back at the exact pinned digest. The prior failed noninteractive startup attempts are retained as history: the installed service had been inactive, noninteractive sudo required a password, and direct systemd startup required interactive authentication. No image pull, daemon configuration, socket substitution or producer-boundary change was used.

Both reviewed setup controls passed in separate owned, offline fixed-image containers, each with a thirty-second internal deadline. Actual inspection verified read-only root and input binds, network none, all capabilities dropped, no-new-privileges, UID/GID 1000, two-CPU quota, four-GiB memory and PID limit 256. Both exited zero, drained and were removed by their verified immutable IDs.

  • Native delegation: actual pinned-image Node 24.20.0 with its verified binary hash loaded the real LightningCSS public JavaScript entry and native transform. The original emitted .odysseus-cargo{color:red;width:2px}. The valid private native proxy emitted exactly those bytes plus the fixed CSS sentinel. ABI/loading/export-property setup therefore passed. This is a setup receipt, not yet native-drift admission/refusal or published-stylesheet counterfactual proof.
  • Producer context: the actual owned producer's boot and kernel hashes matched separately read host hashes for that one lifetime. It observed a two-CPU cgroup quota, affinity spanning thirty-two CPUs, four-GiB memory maximum and unlimited memory.high. This does not bind a later reuse lookup or establish ambient independence.

The eighteen-arm private checkpoint and nineteen-package packed-consumer receipts below remain attributed to 8e11437; they were not repeated. Independent source audits account for the 117 retained kernel/device trace labels as forty normalized classes and map candidate Bun/WebKit/Rayon/Rust and Node/libuv/V8 dependencies on memory, concurrency, kernel backend selection, timing and entropy. Some labels contain strace device annotations rather than literal pathnames. Exact instruction attribution, binary/source provenance and emitted-output independence remain unclosed; decoded provenance declarations are not verified signatures.

Context

Original report at historical source cb7dbe5ab362496278fe14593796ef51af4ada89 (the source anchors and full-build hook counts in this paragraph belong to that checkout): scripts/build.ts deletes every publishable package's dist/ and runs a fresh, non-incremental bunx tsc -p for each one in sequence, plus Tailwind for ui-kit and ui-react (the loop at scripts/build.ts:41-110; rmSync(distDir…) at line 44). Twenty-two test files spawn this full build from their setup hooks (16 in packages/ui-react/tests, 5 in tests/, 1 in tests/helpers/). The hooks rebuild deliberately: per chat-focus-runtime.test.ts, a source marker mutation must not be hidden by a stale dist.

Measured cost:

  • Locally: 74 s on a 32-core host at cb7dbe5ab for 19 packages. The largest are ui-react (12.9 s), module-diagrams (10.1 s), ui-backend-pi (6.7 s) and core (5.7 s).
  • CI, N=2 worker prebuild: 121 to 168 s in run 39022827712.
  • Effect on runtime hooks: in that run, ui-react runtime beforeAll hooks finish within about 3 s of their 180 s deadline serially, and exceed it with two workers (ci: attribute repeated hosted runtime setup hook timeouts #2279). Each hook's identical rebuild repeats work the checkout has already done. In the N=2 path, each worker has just built every package privately before the tests start.

#1837 is the attribution spike for this cost. This issue is the selected implementation of its main recommendation.

Part of #1849.

Current safety correction (2026-10-17)

The bounded safety slice is now delivered by PR #2352, actual squash 2a0b77f675da2f01c32adba3f4920650a5ee09fa, parent 8f9d2ceaa6df72e46a6feccec3f3a96292f18648, tree d99462fe0bdbf0fe04ea6f7a880f9b7cc801a111. Its ready-candidate CI39054832489 completed with all sixteen jobs SUCCESS; the separate cancelled cheap run is not included. PR #2353 is closed as superseded, not merged. No current execution context has complete effective-input qualification. The delivered safety fallback removes persistent stamp admission, so all selected packages follow ordinary leased compilation, stylesheet/copy/bin processing. Default serial builds, opt-in two-job builds, subset selection and --force remain. Old stamp files are inert; unsupported inputs cannot authorize skipping.

Actual build-consumer controls reproduce both gaps before correction: a changed effective config alias leaves stale lowered JavaScript, and a private installed compiler mutation leaves the real Node consumer returning 1 instead of 2. The corrected path compiles and passes both named oracles, then exact config/compiler restoration restores original bytes and consumer value. Focused recovery/scheduling/producer checks pass 28 tests / 250 assertions and strict types pass. The single required local PR preflight completed with exit 0: 950 fast tests / 6,314 assertions and 503 affected feedback tests / 7,486 assertions. PR #2353 is now closed as superseded by published PR #2352 at head 1977a75ea82e23d5a9d03b40c058341e8df3e3a1; its original source used actual synthetic checkout c98288c98abdbf189e7849d0ef1faeffcf3da58a, parents actual main8f9/head4b773 and the same tree 03baadb15f10cc430fae73408ca025d0e86abe32. Natural CI39050339589, workflow .github/workflows/ci.yml, pull_request attempt 1, completed with the known selected callout failure; the final outcome and coordinator handoff are recorded below.

This uses Refs #2319: the issue remains OPEN. Its original unchanged-repeat skipping, safe complete-input qualification and optimization/timing criteria below are explicitly UNDELIVERED. The safety fallback is not represented as completion of those criteria, and no larger code hash is treated as proof of all active filesystem/runtime inputs. A future optimization must qualify effective aliases, complete first-party imports, installed transitive compiler/native/stylesheet inputs and actual runtime context, or continue rebuilding. The completed #1837 attribution and original source/browser freshness receipts retain their exact scopes.

Approved isolated CI build operation (2026-10-17)

Decision (maintainer, 2026-10-17): implement and qualify an isolated CI build operation for unchanged-output reuse. This selects development and qualification, not activation based on the old stamp or a larger hash. The original safe reuse and comparable-cost criteria remain required; they are not deferred or represented as delivered by ordinary rebuilding.

Develop one fixed first-party CI operation for TypeScript and the two stylesheet producers. This is a concrete operation, not an extension/plugin interface. Ordinary local builds remain available without a mandatory container dependency; unsupported or unqualified contexts rebuild. Existing diagram-export engineering patterns may be reused, but its qualification grants no compiler/build authority.

Before enabling positive reuse, prove captured source/configuration, complete installed toolchain/native inputs and runtime bytes are the bytes actually consumed, with a constrained filesystem and environment, no network acquisition, fresh private writable HOME/tmp/output, and checked output ownership. Preserve lease, force/subset/jobs behavior, failed/interrupted-build refusal, output tampering/recovery and source-marker/default-export freshness. Actual config-target, installed compiler and transitive stylesheet/native drift must invalidate or refuse eligibility. A supported unchanged invocation must demonstrably skip compiler/stylesheet children while preserving output bytes and modes.

Run offline boundary counterfactuals, all nineteen packed consumer inventories and comparable hosted setup/critical-path measurements including identity overhead. The 606.090 seconds of repeated executed builder work measured in #1837 remains conditional opportunity, not saved elapsed time or cache eligibility. Keep the reviewed safe ordinary-rebuild fallback until this operation is qualified. Record the durable CI decision with its implementation before activation.

Dormant operation qualification (2026-10-17)

The unpublished candidate is frozen at 8e11437fb053277cd8793157eda1b8289d998341, tree 803ddc8985ecb45a1cf8abf71f91c0f2bda720cb, parent 991e43ba9a19e3579b99ddd88774ed2898a6cb2b. Its six correction files are byte-identical to the completed private qualification's captured inputs. The fixed offline controller exits 0 with 18 labeled arms and 14 actual producer containers, all confirmed drained and removed before successful publication or evidence compaction. This is private qualification, not a qualified production context: CI intent remains off, production activation remains unqualified, and installation/runtime/ambient/compatibility/hosted-cost activation fields remain unset. No PR, required full preflight, hosted dispatch or activation is claimed by this checkpoint.

The real cold operation compiles all nineteen packages. Its unchanged repeat omits every TypeScript/stylesheet child, reuses all nineteen outputs and preserves their bytes and modes. Delete/edit/extra/mode damage each rebuilds only the affected package; stylesheet recovery rebuilds ui-react while retaining valid checked derived dependencies. Force with two jobs and a source change rebuild all nineteen. Effective config aliasing, an altered installed TypeScript emitter and changed nested stylesheet content each refuse isolated eligibility and run the ordinary private builder. Actual consumers observe lowered target output, changed emitter value 2 and changed CSS; restoration recovers value 1 and the original output identities. The installed-compiler receipt does not substitute for the still-required native stylesheet producer counterfactual.

The unchanged authoritative ciPack assertions pass for all nineteen tarballs: workspace pins, inventories, executable targets, Bun/Node imports, package/bin probes, consumer checks, published types and React 18 Bun/Node compatibility. All four known native offline installers exit 0, with scripts disabled and installed bytes checked against verified archives before imports; there are 2,047 payload-verification records across these installations, not that many distinct packages. The actual pinned image consumes Node 24.20.0 and the captured Bun 1.4.2 binary. Cache preparation remains outside proof, with 584 exact third-party artifacts and separately reviewed SRI; no registry acquisition is permitted inside the disconnected outer namespace or network-none producer.

Two consumer transport corrections preserve the existing assertions and dependency graph. Bun's pack/pin probes temporarily write manifests, so they run against a physical consumer-only writable repository copy while captured /repo stays read-only and installed consumers remain outside its ancestry. The pinned Bun otherwise redirects esbuild's bin alias into a platform package without its own bin declaration. A fixed installer-only native-linker-disable flag preserves the declared wrapper, graph and all payload bytes; an actual offline two-arm control executes both entrypoints successfully. The strict verified/declaration-based alias guard remains unchanged. No dependency/override additions, manifest/install-spec changes or graph flattening are used.

The final diagnostic all-nineteen trace completes within the original bounds and produces exactly the unobserved output identities. Its selected observation is complete, but ambient qualification remains false: 117 kernel/device path identities, four ambient-call classes, additional rename operands, vDSO/hardware and source/output-dependency questions remain explicit. Trace completeness and output equality do not establish that those inputs are irrelevant. Source investigation verifies the installed oxide and LightningCSS GNU binaries against official SRI-checked archives and records upstream source/provenance metadata; signature verification and the finite active-source/ambient audit are not represented as complete. Host workspaceScope boot/kernel hashes alone do not establish the actual Docker producer's boot/kernel context.

Independent actual common-producer interruption reaches a verified live owned container and real TypeScript launcher, then signals the exact owned operation. The operation exits 1 after child 143; its immutable container drains, is removed and is independently confirmed absent, with no producer success receipt. The shared execute body and six active capture/lifetime/entry/build/lease helpers are byte-identical to the frozen candidate. The earlier full-tree identity remains separately attributed: this is shared-engine lifetime evidence, not activation or an actual production-publication receipt.

Exact current-source focused verification is bun run test ./tests/ci-build-consumers.test.ts ./tests/ci-build-qualification.test.ts: 13 tests / 38 assertions across two root files, exit 0. Strict types, targeted lint and whitespace checks pass. Three resumed bare-path discovery runs also executed preserved copies under temporary captures; their totals 65/156/208 are duplicate-discovery history, not distinct current-root guard counts. Earlier pre-resume exact ./ receipts retain their own attribution. The private-fallback source-call control fails its named current-lease assertion before explicit environment forwarding, then passes after correction; the complete actual config/compiler fallback arms pass in the frozen run.

All earlier failures remain preserved: missing fixed-cache prerequisite before any producer; the implicit Bun startup environment causing an owned private-lease wait, stopped after diagnosis with nine completed arms retained; the read-only manifest-write failure after seventeen completed arms; and strict refusal of the native esbuild alias before consumer imports. Their corrected successors do not erase or relabel those failures. Failed captures remain preserved; only successful drained-and-removed owned states are compacted.

Local operation observations are cold 99.168 s (capture 20.518, lookup 0.522, producer 75.927, publication 1.905), unchanged repeat 26.014 s (capture 24.327, lookup 1.686), packed consumers 144.117 s, and diagnostic trace 143.260 s. Host load was uncontrolled. These phase observations are not a comparable hosted benchmark, complete qualification-preparation measurement or claim of saved CI elapsed time; #1837's executed builder work remains conditional opportunity.

Before positive reuse or completion of the original optimization criteria, the following remain required:

  • A finite source-specific ambient-read/output-dependency audit and causal controls, including actual Docker producer boot/kernel context versus host context, clocks/randomness/hardware and unresolved paths/operands.
  • An actual transitive stylesheet/native producer drift refusal or invalidation counterfactual with restoration; the existing compiler and CSS-source controls do not stand in for it.
  • Real browser marker/default-export freshness against isolated outputs, with a stale-output mutation that reaches the oracle and is not masked by another ordinary rebuild.
  • Comparable hosted setup, runtime-hook and critical-path measurements at comparable sources, including identity/publication overhead and the existing runtime-hook events.
  • Coordinator-owned observer integration and complete imported-producer/pin reconciliation, then the required PR preflight and exact-candidate selected hosted proof before readiness/merge.

2026-10-17 qualification fold: records the frozen completed offline controller, exact root-focused receipt, independently attributed interruption, consumer corrections, all preserved failures and the finite remaining gates. No production eligibility, hosted performance improvement or issue completion is inferred.

Historical development receipts

At the earlier source-only checkpoint, the controller candidate was a692495084cbb5863f755e3106f27ac4ad516588 (tree 5c95e9808b565e9f30a74306f8e8640aad102628, parent dc827002a0834dd1666fe35b647ec405b0265120) and was under source review. The earlier real cold-operation receipts below remain bound to exact dc827; they are not relabeled as execution of the controller. It is unpublished and unqualified: CI intent is off, positive reuse is disabled, and native/ambient, compatibility and hosted-cost qualification evidence remains unset. Ordinary local and unqualified contexts retain the delivered rebuild fallback. The durable CI decision accompanies the source; existing diagram-export qualification grants no build authority.

Source controls cover captured-byte/mode identity, output drift, checked derived-output capture, actual final-file alias/FIFO and ancestor swaps, and refusal when owned-container removal is not confirmed. Local daemon controls are bounded and mutating commands use a verified immutable container ID plus session ownership; a name-replacement control leaves the foreign container untouched. These lifecycle tests replace only the lowest process-call boundary and do not constitute actual Docker interruption or isolation proof. Actual compiler fixture controls preserve source/config/installed-compiler freshness, scheduling and peer drain. An intent-set run exposed two startup fault-owner failures because its old generic receipt filename injector hit the optional operation observation first; the narrow correction targets the actual workspace receipt and all four real storage-failure/exit/drain controls now pass (32 assertions). That earlier run remains 46 PASS / 2 FAIL.

The first real common-only isolated smoke at 40e53bad96f140618e8f06a446724598a98aadf0 failed before compilation because entry initialization tried to create an already existing HOME directory. Its original failed evidence is preserved; it is not compiler or boundary qualification. The changed successor creates private HOME/cache before Bun/lease initialization, then checks the actual fresh tmpfs, ownership, nonalias directories, permissions and expected non-root UID/GID. Exact-source focused controls pass 38 tests / 228 assertions, with strict types and lint passing.

One changed-source common-only isolated smoke at dc827002a0834dd1666fe35b647ec405b0265120 succeeds on the existing immutable pinned image, with networking disabled and no acquisition. The real TypeScript child exits 0; 20 output files are retained privately. Actual read-only mounts, fixed executable ownership/runtime bytes, private writable topology and absence of the original checkout/canary are checked. The session-owned immutable container ID drains, is removed, and an independent ID-scoped absence query succeeds. No workspace common/dist or reuse stamp is published; qualification remains off and its activation evidence remains unset. This is a single-package compatibility smoke, not complete ambient-read or reuse qualification. Observed total 20.575 seconds includes 16.649 seconds of capture, 0.049 seconds lookup and 3.606 seconds producer time; these are not a before/after speedup or comparable hosted measurements.

One subsequent cold all-nineteen-package qualification at the same frozen dc827002a0834dd1666fe35b647ec405b0265120 succeeds: 19 real TypeScript and two Tailwind children all exit 0, producing 4,857 privately retained files. The three theme/token copies and four core hook files match captured source bytes (hooks also match modes); all four declared bins are executable. Actual container drain/removal and an independent full-ID absence check succeed. The operation completes within its fixed 300-second producer bound: total 87.566 seconds, including 17.969 seconds capture, 0.047 seconds lookup, 67.979 seconds producer and 1.304 seconds output validation. No workspace outputs or stamps are published. These are local cold-operation observations, not a cache benefit, packed-consumer qualification or comparable hosted timings.

The controller source shares actual capture/key/receipt/output/cleanup/publication validators with production while keeping its fresh private workspace, operation purpose and receipt domain separate. Its fixed arms cover repeat omission, per-package output recovery, force/subset/jobs, real marker/config-alias/installed-compiler/nested-CSS consumers, a diagnostic-only trace arm and the existing all-nineteen ciPack assertions. Production rejects copied proof receipts. The trace classifier preserves incomplete, kernel/device/time/random and unresolved inputs as unknown; it never grants ambient qualification. Packed installers receive native offline flags, no install scripts and a private cache, with installed payloads checked against verified tarballs before imports. Registry/cache preparation remains separate from the offline operation and requires a fixed reviewed manifest of exact package/transitive tarball integrity; missing prerequisites refuse rather than acquiring inside proof. Controller-owned successful captures are compacted only after drained/removal receipts, retaining runtime, exact input/invocation/cleanup manifests and deduplicated necessary output/tarball bytes. Failed and foreign states are preserved.

Source-only controls pass: 11 tests / 41 assertions for the new shared/purpose/trace/offline/compaction guards; 30 tests / 129 assertions for changed guards and exact producer bindings; strict types and targeted lint pass. Five causal source mutations fail their intended assertions (proof-purpose admission, external references, native offline flags, kernel ownership and incomplete-state deletion), then exact source is restored. The final intent-set ordinary real-consumer freshness file passes all three tests / 111 assertions. These are source and ordinary fixture checks, not actual controller/trace/packed/browser execution. No new hosted run, workflow activation or positive production eligibility has been requested.

At that earlier source-only checkpoint, all nineteen packed consumers, browser marker/default-export freshness, real interruption/lifetime controls, complete ambient-read/output-dependency qualification, unchanged compiler-child omission and comparable hosted costs remained required. The current qualification section above records the subsequently completed evidence and the gates still open. The measured repeated work from #1837 is not saved elapsed time.

Scope

  • Make scripts/build.ts skip a package when the inputs that produce its output are unchanged and the existing output is exactly what that build produced. Add --force to always rebuild.

  • The stamp is per package and lives outside every shipped path, for example under root node_modules/.cache/brain-build/. Every package's files includes dist, so the stamp must not live in dist/.

  • Original minimum invalidation checklist (insufficient for eligibility by itself): one build-input hash shared by every package. Cross-package imports resolve to each sibling's src/ through the root customConditions: ["bun"] (header comment, scripts/build.ts:6-13), and build order is not a dependency boundary. The hash therefore covers:

    • every tracked and untracked-not-ignored file under every packages/*/ except dist/ and node_modules/;
    • the root tsconfig*.json, package.json and bun.lock, plus scripts/build.ts and its imports;
    • Bun.version.

    Any input change rebuilds every package, which matches today's behaviour. Only unchanged repeats skip.

  • Stamp output: a hash of every file under the package's dist/ (path, mode and content). A skip requires both the input hash and the current output hash to match the stamp. A deleted, edited or extra dist file therefore forces a rebuild.

  • Keep the workspace write lease, the bin-mode marking and all copy steps, unchanged for rebuilt packages.

  • Print one line per skipped package, for example Up to date packages/<dir>, so logs still account for every package.

Out of scope

Acceptance criteria

  • Unit tests in a temporary fixture repository show:
    • (a) a second build with no changes skips every package and leaves every dist byte-identical;
    • (b) editing any package's source file, including one only another package imports, rebuilds every package;
    • (c) deleting, editing or adding a file in dist/ rebuilds that package;
    • (d) changing the root tsconfig.json, bun.lock or Bun.version rebuilds everything;
    • (e) --force rebuilds everything;
    • (f) a stamp copied into another checkout with no dist/ does not skip.
  • Mutation receipt: removing the output-hash comparison makes (c) fail on its named assertion; restore it.
  • Real-runtime receipt: the existing source-marker guarantee holds. Edit a ui-react source marker, run a runtime test that rebuilds, and see the marker in the browser-consumed dist. Record the command and result.
  • No stamp file appears in any bun run check:pack tarball listing. The packed-file inventories are unchanged.
  • A hosted unit run records the ui-react runtime files' setup-phase durations before and after at comparable SHAs, using the test(ui-react): retain setup phase and child completion receipts #2306 runtime-hook events.

Verification

bun run test on the new build-stamp tests, bun run check:pack, the real-runtime receipt above, a hosted run comparison, and bun run check:pr --base origin/main.

Contract impact

None. Repository build tooling only; package contents are unchanged.

2026-10-17 confirmed complete-input guard gap

Independent qualification of PR #2328 at 1f343ad13fadbd4cf1e964d44ade19a97a92d77f confirmed that changing the effective contents of a symlinked root compiler config can leave the stock input hash unchanged and the build decision up-to-date, while actual installed TypeScript emits different JavaScript. The cached decision was captured before forcing compilation, so the unchanged old output hash does not prevent the first incorrect skip. fileEntry (scripts/build-stamp.ts:22-29) records only the symlink target string; this affects the complete-input eligibility requirement above.

Warm and restored-target actual compiler controls pass; SYMLINKED_ROOT_TSCONFIG_TARGET_CHANGE_MUST_INVALIDATE fails on expected build, received up-to-date, with identical symlink identity and stock helper. Full causal receipt and source-class audit: #2319 (comment) . Qualify effective target changes or refuse reuse for unsupported symlink inputs before claiming the complete-input criterion. This is part of this issue, not a separate optimization. The regular-source real-browser freshness control is independently complete at #2319 (comment) ; it does not establish every input class. The implementation owner/branch remains unchanged.

2026-10-17 installed compiler input qualification

An independent owned offline control, also delivered to the active PR, confirms another gap under the existing complete-input criterion at exact head 79a34735276f21dbd993a69049b42ca076b7ed7d. Changing only an owned installed TypeScript 6.0.3 compiler entry preserves the package-version file, lock, project source and stock input hash. The stock decision remains up-to-date before fresh compilation, but the ordinary unchanged compiler command then emits different JavaScript that a real built consumer executes. The named invalidation assertion is RED (exit 1); restoring the owned entry restores the original output/key and a passing supported up-to-date decision (exit 0). Shared/worktree dependencies and this issue's owner branch remain unchanged.

The safe outcomes remain accounting for effective installed toolchain inputs or refusing reuse for unsupported/unqualified installations. Package-version equality alone does not establish compiler source identity. This single entry mutation proves that membership gap; hashing only that entry would not qualify all transitive compiler/runtime/native/stylesheet inputs. It complements the existing config-alias and producer-helper findings without changing implementation ownership, the settled subset/concurrency directions or the acceptance criteria.

2026-10-17 delivered partial and open eligibility criteria

PR #2328 delivered 8f9d2ceaa6df72e46a6feccec3f3a96292f18648, but the actual delivered stamp helper remains byte-identical to both failing controls above (SHA256 5c7c7b72d0d7ba383600dbc16c0d6d1cc544104b480823b90955be6d8566d220). Effective config-target and installed compiler changes can still preserve the input key; the imported build-receipt producer is still absent from the explicit inventory. The ordinary-source/browser proof remains scoped partial delivery. This issue is reopened for its existing complete-input criterion, with milestone 0.44.0 retained. Correct the delivered behavior on a new post-merge branch; preserve the existing mutation and real-consumer evidence and refuse unsupported reuse rather than infer eligibility from package versions or link strings.

Coordinator handoff (2026-10-17)

Automatic CI39050339589 completed FAILURE on exact checkout c98288c98abdbf189e7849d0ef1faeffcf3da58a / tree 03baadb15f10cc430fae73408ca025d0e86abe32: all sixteen jobs drained, fourteen SUCCESS and browser (1) plus aggregate FAILURE. The aggregate accepts the requested immutable candidate identity and rejects only the selected browser failure. Browser (1) reproduces the two known #2351 WebKit literal/grouped callout deadlines (15,179 / 15,090 ms); its other 230 modules pass, with 4,808 passing cases and four existing explicit skips. No stamp safety consumer assertion fails.

All four unit jobs succeed. API-digest-verified ZIPs, exact worker checkouts, immutable discovery/partition membership and final XML/timings reconcile all 1,071 files exactly once: 14,501 passing cases, 28 existing explicit skips (24 live image cases and four unavailable-vector indexer cases), zero failures. All three actual build freshness/config-alias/installed-compiler controls execute and pass in unit (3). Pack, verify, both layout shards, browser (2), captures, runtime/runtime_host and endurance also succeed. These category successes are source-specific evidence, not whole-workflow green or a retention baseline.

The coordinator accepts ownership of claim complete-input-2319-20261017, with the shared assignment retained. PR #2353 becomes draft only after every selected job and the aggregate finish, so no active proof is cancelled. Its frozen safety slice is being composed with the separate #2351 and #2146 repairs into the concrete successor #2352. PR #2353 was subsequently closed as superseded after exact safety commit 4b7733264686ba6154333b141df209f0597c4acd was retained in published PR #2352 head 1977a75ea82e23d5a9d03b40c058341e8df3e3a1; it was not merged or represented as green. That successor subsequently merged as 2a0b77f675da2f01c32adba3f4920650a5ee09fa with all sixteen ready-candidate jobs successful, as recorded in the current safety correction above. This historical failed safety-only run remains failed. No unchanged retry, main refresh or extra workflow dispatch is requested. #2319 remains OPEN at 0.44.0 for its original optimization/skip criteria, explicitly undelivered; #1837 remains CLOSED with its separate attribution result.

Verification access restored — 2026-10-19

The original coordinator resumes under claim isolated-ci-build-2319-20261019-r2, retaining branch feat/2319-isolated-ci-build at 8e11437fb053277cd8793157eda1b8289d998341. Fresh readback found no assignment or active implementation PR. The existing fixed Docker endpoint responds with version 29.8.2, and the already installed pinned Playwright 1.63.0 image resolves to digest sha256:eff16c30e6f3f4af0a03fa4b706120d5e9b0891c344a27d64559aff5900a4a27. Disk reports 36,170,506,240 available bytes. No endpoint substitution, daemon restart or image download was used.

This satisfies the recorded access prerequisite only. First recover and verify retained source/evidence after environment restart; temporary-path receipts may be unavailable and must not be silently reconstructed or attributed to a fresh run. The earlier successful eighteen-arm controller remains historical; no unchanged replay is requested. Production eligibility remains unqualified pending the existing native stylesheet/browser/ambient/hosted criteria and required final proof.

2026-10-19 stop/handoff: immediately after access reconciliation and the replacement claim, the maintainer instructed not to start new work and to hand off the thread. The recovery worker was interrupted. No new qualification, source implementation, PR or completion is claimed. The replacement coordinating assignment is released; access restoration remains a factual prerequisite receipt. A successor must establish fresh custody and inspect source/evidence before continuing the still-open criteria.

2026-10-20 maintainer correction: explicitly selected activation deferral with dormant work retained; the former pending recommendation is now a ruling. Resumed scope is limited to the dormant slice, with original optimization acceptance preserved as open.

2026-10-20 review correction: recorded the dormant fallback repair, current local proof and separate source/base attribution; refreshed the build header citation without changing original acceptance criteria.

Decision (maintainer, 2026-10-22): resume qualification planning

Option B selected: resume with a concrete qualification plan. Define the supported build boundary, refusal controls and net CI-cost comparison for maintainer review before qualification begins. This authorizes bounded planning, not activation, a qualification experiment or an assumption that the dormant operation is already safe for reuse. Ordinary rebuilding remains active and the delivered dormant operation remains disabled.

Authorized next scope

Prepare one reviewable plan covering:

  • The exact admitted source/configuration and installed toolchain inputs, including effective configuration targets, transitive compiler/native/stylesheet dependencies and the actual runtime bytes consumed.
  • Filesystem/environment isolation, permitted ambient reads and provenance guarantees, supported native producers, private writable HOME/tmp/output and output ownership. Unsupported, changed or unqualified inputs must refuse reuse and rebuild.
  • Causal refusal controls for configuration-target, compiler, transitive stylesheet/native and ambient/runtime drift; interruption, output tampering/recovery and source-marker freshness; unchanged lease, force/subset/jobs semantics.
  • A bounded offline qualification matrix, named meaningful failing-first/restored controls, packed-consumer checks and explicit success/refusal criteria. Existing finite equal-output samples are insufficient proof of the complete input boundary.
  • Comparable hosted setup and critical-path measurements that include isolation, input identity and qualification overhead; report total execution cost as well as any net saving. State the proposed experiment's scope and resource bounds before execution.
  • The smallest implementation/qualification sequence, any remaining choices, and the exact boundary and bounded experiment the maintainer must approve next.

Planning acceptance and review gate

The plan is complete when it specifies every item above with checkable verification and explicit limitations, maps the original optimization criteria to its proposed evidence, and is presented for maintainer review. Planned work/status stays in this issue; any durable approved CI ruling belongs in the relevant decision record during delivery. Do not implement a stronger build boundary or begin qualification based on this planning authorization alone.

Keep needs: decision and no agent-ready on this original optimization issue until the concrete boundary and bounded qualification effort are approved and folded into its implementation/verification brief. The decision to prepare that plan is settled; the remaining decision is approval of the actual proposed boundary and experiment. Preserve original open optimization/ambient/provenance/cost criteria, dormant delivery receipts, priority and release attribution. No new activation or release commitment is selected.

Stronger-boundary design selected — 2026-10-22

Decision (maintainer): Option B — design a stronger deterministic native/runtime boundary first. This selects B from the concrete proposal, distinct from the earlier planning Option B. The existing-operation staged experiment and its offline/hosted runs and budgets are not approved.

The next deliverable is a reviewable design specifying:

  • Controls for direct/vDSO clocks, entropy, CPU/hardware and kernel/device inputs; explain what is enforced or normalized, what is proven output-independent, and what must refuse reuse.
  • The exact source/configuration, runtime and transitive compiler/native/stylesheet input boundary, including effective aliases and actual consumed bytes.
  • Native source-to-binary provenance requirements and available evidence; distinguish provenance guarantees from isolation guarantees and retain unsupported gaps explicitly.
  • Filesystem/environment isolation, private writable state, output ownership, publication and interruption handling, preserving workspace lease and force/subset/jobs semantics.
  • Feasibility, necessary implementation changes, compatibility consequences and expected costs, without implementing the stronger boundary as part of design.
  • Meaningful causal failing-first/restored controls, packed/default-export/browser freshness proof, and a bounded offline/hosted qualification and net-cost experiment for subsequent approval, mapped to the original acceptance criteria.

Design acceptance: another reviewer can identify the exact supported/refused inputs, enforcement mechanisms, remaining assumptions, provenance limitations, implementation scope and experiment resource limits. A documented finding that no feasible stronger boundary satisfies the original requirements is an acceptable design outcome for maintainer review; it does not waive those requirements.

Present the concrete design for a separate ruling before implementation or qualification. Activation remains deferred and ordinary rebuilding remains active. No experiment or hosted run is authorized by this choice. The scope choice is resolved; retain needs: decision solely for approval of the resulting stronger-boundary design and qualification scope, with no agent-ready. Original acceptance criteria, priority and dormant delivery/release attribution remain unchanged.

2026-10-22 correction: folded the maintainer's selection of proposal Option B into the current brief; replaced the pending A/B/C choice with the stronger-boundary design deliverable and its review gate.

Stronger-boundary design delivered — 2026-10-22

The design is posted for maintainer review, after six adversarial review rounds (gpt-6-astra and opus-5.5) and a scratch prototype. It is a design only: no implementation, qualification run or hosted run happened. Its findings:

  • No feasible boundary exists for the native stylesheet builds as consumed. Original criteria (a) and (c) therefore cannot be met as written for the two styles.css files.
  • A fresh-realm host for TypeScript reduces the remaining ambient inputs to four stated runtime assumptions (R1–R4). A local prototype emits bytes identical to the tsc CLI. The boundary is unqualified.
  • After fix(ci): build runtime packages once per test invocation #2458, the expected same-root saving is about zero, pending Gate 0 artifact confirmation.
  • Provenance stays open for the Node runtime, the TypeScript bundle and Bun as the verifier.

Decisions requested are in the comment's §1b; items 1–2 cost nothing. The original criteria stay open: any withdrawal is a separate, explicit request (§1b item 3). needs: decision remains for approval of this design and its qualification scope, with no agent-ready. Activation stays deferred and ordinary rebuilding stays active.

Activity

  1. added this to the 0.44.0 milestone on Oct 17, 2026
  2. added
    type: choreTooling, CI, release plumbing, dependencies.
    area: ui-reactReact chat/files/voice components, stores, WebSocket transport.
    area: ciCI workflows, the gates they run, release scripts, packaging.
    priority: p0Drop everything: a security hole, data loss, or a broken release.
    agent-readyContext and acceptance criteria are complete enough for an agent to take this unattended.
    on Oct 17, 2026
  3. self-assigned this
    on Oct 17, 2026
  4. schlessera commented on Oct 17, 2026

    @schlessera
    OwnerAuthor

    Claim p02319-stamp-20261017: implementing on branch chore/2319-build-input-stamp from current main 9d5cd00b7.

  5. schlessera commented on Oct 17, 2026

    @schlessera
    OwnerAuthor

    Coordination with the separately owned build work: #2325 is now merged as 3d1b208cc921e6143a590a98cd9647d74ae312ca, following the Node-import repair #2327 at f333. The subset implementation changes build argument parsing and loop selection plus the exact build/helper producer pins; it preserves the default nineteen-package build. No refresh of your branch is requested solely for main advancement, but those are relevant inputs when reconciling the two implementations.

    For the #1837 attribution criteria, the currently documented marker export/compiled-output check and subsequent marker-reverted browser run are distinct evidence. They do not yet demonstrate a changed marker reaching the actual browser or the required stale-output guard mutation. That criterion remains visible in #1837; the attribution worker is retaining it without duplicating your build-stamp implementation.

  6. schlessera commented on Oct 17, 2026

    @schlessera
    OwnerAuthor

    Coordination from #1837: claim attrib1837-hook2279-20261017 will independently qualify only the remaining real-browser source-marker criterion on a separate fresh copy of PR #2328 head 1f343ad13fadbd4cf1e964d44ade19a97a92d77f. Your implementation branch, claim and hosted run remain yours; no changes or dispatches there.

    The current PR receipt proves a source export reaches emitted dist, followed by a separate runtime run after restoration. The independent control will freeze one named browser DOM oracle before warming, mutate actually rendered ui-react source, require the new marker in the real browser, make stale output fail that assertion when input invalidation is disabled, restore and pass, then restore original source/probe bytes. This supplements the emitted-output/key tests rather than inferring browser freshness from them. The bounded attribution report is on #1837; I will post exact source, mutant/restoration and offline-environment receipts here when complete.

    Source audit selected the existing chat-focus form-submit case, whose fresh browser bundle uses the package default export. The answer-delivery fixture explicitly sets Bun.build conditions to ["bun"] (beforeAll, packages/ui-react/tests/answer-delivery-runtime.test.ts:92-99 at the exact PR head), so that separate 24-case run consumes source and cannot by itself qualify dist freshness. The frozen temporary chat-focus probe retains all original assertions, adds the rendered marker oracle and numeric build-outcome receipts, and wraps its existing cleanup in a value-preserving measured phase.

  7. schlessera commented on Oct 17, 2026

    @schlessera
    OwnerAuthor

    Coordination with #2319 / PR #2328: #2321 now has a complete same-source hosted comparison (run 39029776835; full receipts on #2321). Its approved implementation is a fresh main-based chore/2321-bounded-ci-build branch adding opt-in --jobs=2 only for the hosted pack build and the hosted browser/layout/endurance workspace build commands. Default, local, release, capture, native and private N=2 builds stay serial. Incremental output was declined after an actual missing-output recovery failure.

    This will touch scripts/build.ts and its exact audited producer binding after source review, so it overlaps this stamp work. I will preserve the stamp authority/skip criteria and coordinate the final combined build source rather than blindly replace producer hashes. Hard/optional dependency levels and full --for closure semantics stay intact. Please retain this overlap when integrating #2328; neither measurement workflow nor helper is a production change.

  8. schlessera commented on Oct 17, 2026

    @schlessera
    OwnerAuthor

    Independent real-browser freshness criterion completed for #1837 / #2319 (2026-10-17).

    Exact implementation head: 1f343ad13fadbd4cf1e964d44ade19a97a92d77f (PR #2328), copied into a separate owned checkout/install. No owner branch/tree was changed. This qualifies the ordinary full-build path at that source, not a later combined tree or whole-suite result.

    The selected existing case was chat-focus's “form submit moves focus to the answer's status, which reads Answered once the backend has it.” Its fresh resolver bundles the public package default export. The answer fixture instead explicitly sets Bun.build conditions: ["bun"] (beforeAll, packages/ui-react/tests/answer-delivery-runtime.test.ts:78-111 at this head), so its separate 24-case pass cannot establish dist freshness. That source-backed distinction determined the control.

    Before warming, the frozen temporary probe retained every original assertion, added one DOM attribute oracle plus numeric built/skipped receipts, and wrapped the existing afterAll cleanup in a value-preserving observed phase. Probe SHA256 b42554a20346231be614c3acf49d63303990994c2124f6bea31a73bf0633447d. Original chat-focus SHA256 4c97f8d10c4f4523f30201373546081c2ebc1113add7578b776b83652e1c05c7.

    1. Cold build: 19 packages built, exit 0. Immediate unchanged repeat: 19 up to date, zero built, exit 0; every dist path/mode/content remained identical. Warm stamp/input/output snapshots were saved.
    2. Add data-odysseus-source-marker="ithaca-1837" to the actually rendered AnswerDeliveryStatus source. Disable ONLY the stamp.input !== input guard, retaining output validation. The same frozen runtime probe records 19 skipped / zero rebuilt packages; its 0.097739s build join exits 0 with both EOFs. Complete output manifests remain byte-identical to warm. The real browser reaches the original ANSWERED/focus assertion, then reads the marker as null. The intended ODYSSEUS_RENDERED_SOURCE_MARKER_REBUILT assertion fails: expected ithaca-1837, received null. One executed case fails (three assertions reached), six other cases are deliberately filtered. This is a runtime guard failure, not a module-load failure or key-only predicate.
    3. Restore the exact helper bytes, leaving the changed rendered source and frozen probe untouched. The build records 19 rebuilt / zero skipped packages, exit 0 plus both EOFs, 56.984912s. The real browser reads ithaca-1837; the same case passes all five assertions, including all original assertions. Emitted output contains the attribute and differs from warm.
    4. Restore the exact original component and test bytes. The original unmodified case passes all four assertions, with a 57.714995s successful rebuild. The marker is absent again. A final unchanged build skips all 19 packages and preserves every output byte. Final tracked status is clean and the source/helper identities match the exact PR head.

    The input guard's stock SHA256 is 5c7c7b72d0d7ba383600dbc16c0d6d1cc544104b480823b90955be6d8566d220; its one-condition bypass is 8a8a39289a886fae8d26e862f6fa60e000f2af88ef06954838373f93b9f3d086. The rendered component changes from aaeafa3b3771f57290d76e7871a9aeea74b219848c3f806fdad81c2d0595892b to fbbfe60d5d5b706d4ecfde50ba552e1442b494e0826d62c60c8ee0491e2ecaf7 and back. Probe identity is constant across the RED/restored guard pair. All input/output manifests, stamps, source snapshots, XML, raw child/EOF logs and process samples are retained.

    This narrow native control also independently observes existing cleanup: 97.593ms after RED and 133.046ms after the restored guard PASS. These supplemental local measurements do not replace uninstrumented hosted cleanup with invented timings. Runtime was pinned offline Playwright v1.63.0-noble / Chromium 153.0.8010.12, Bun 1.4.2, Node 24.20.0, 4-CPU quota and 16 GiB, private HOME and ledger namespace, no external network or host Docker socket. Existing test deadlines/assertions and offline guards remained. The owned container is stopped/removed; original source bytes are restored.

    This satisfies the narrow actual rendered-source invalidation criterion for the tested guard/path. It does not complete hosted before/after timing, other full #2319 criteria, or #1837's remaining total-invocation/critical-shard attribution limits. No whole-suite green, universal performance saving or post-merge combined-tree proof is claimed.

  9. schlessera commented on Oct 17, 2026

    @schlessera
    OwnerAuthor

    Confirmed remaining complete-input criterion failure in PR #2328 head 1f343ad13fadbd4cf1e964d44ade19a97a92d77f: a symlinked root tsconfig can change actual compiler output without changing the stock input hash. This is independent of the completed browser-marker guard qualification above.

    Source: fileEntry (scripts/build-stamp.ts:22-29) represents a symlink using only its link-target string at line 26. buildInputs consumes that representation for root build inputs/configs and package files at line 51. buildDecision (scripts/build-stamp.ts:76-81) then accepts the unchanged input and current output hash; the actual builder skips compilation at scripts/build.ts:53-55.

    The bounded offline control used an owned minimal Git fixture with fixture/tsconfig.json -> ../outside/compiler.json, a package tsconfig extending that root path, and fictional source:

    export const harbour = (value?: { name?: string }) => value?.name ?? "Ithaca";

    The implementation helper was exact stock SHA256 5c7c7b72d0d7ba383600dbc16c0d6d1cc544104b480823b90955be6d8566d220, read-only from the exact head; actual installed TypeScript 6.0.3 ran under Node 24.20.0 / Bun 1.4.2. No implementation or owner branch was modified.

    1. Compile using the linked config's target ES2019, exit 0, and record the stock build stamp. Input hash 14649c87e92c815c0e54fc3f395abeddcdcc1e452ca8a8201fa40b80f28fe324; output hash ffc00d744f946ddaf58a39d42670da268c0289d6af06cb818f760482c846c3ce. An unchanged repeat is correctly eligible to skip.
    2. Change ONLY the symlink target's configuration bytes to target ES2022. Symlink dev/inode/mode/link string remain identical; fixture source and stock helper remain identical. The stock input hash is still exactly the hash above, and the cached dist still exactly matches its stamp. Before invoking the compiler, stock buildDecision returns up-to-date, so the builder would skip.
    3. Run the actual installed tsc anyway. It exits 0 and emits different JavaScript: ES2019's lowered null checks become the original optional chaining/nullish coalescing. Actual output hash becomes 0c1f8bb6f7b4726ac5fe4930b110567eb9148a79472e3cbcd82004f3d35f2385. The named assertion SYMLINKED_ROOT_TSCONFIG_TARGET_CHANGE_MUST_INVALIDATE fails RED, expected build, received up-to-date. This is an actual compiler/guard contradiction, not just a hash-predicate test or module-load failure. Output integrity cannot catch the first incorrect skip because cached output A was still intact when the decision was made.
    4. Restore the original target bytes, preserving the same symlink identity. Actual tsc exits 0 and restores the exact original output/hash; stock up-to-date eligibility is again correct. The restoration assertion passes. Target bytes and owned fixture state are restored; container is removed.

    The target config SHA256 changes f2d23ece6fe0eec7355413fecb89356d04c8f21d32ac885734825d71ab380fb5 → c8465464c08aaf414636d7d63be7869e8fd22ba38c45bb08bffc1eeb977fc7a0 → original, while the stock input hash never changes. Commands were actual node <installed-typescript>/bin/tsc -p packages/odysseus/tsconfig.build.json --pretty false, plus stock buildInputs / recordBuild / buildDecision, inside the offline pinned image with 4-CPU / 16-GiB limits. Warm exits 0, named regression exits 1 for the expected assertion, restoration exits 0. Complete source, identities, raw compiler output and snapshots are retained.

    Same-class source audit: the link-only representation also feeds package/script input entries and output symlinks through distHash at scripts/build-stamp.ts:64. Those callsites need the same eligibility policy; this runtime control specifically reproduces the root-config case. A bounded fix can refuse stamp eligibility for unresolved symlinks, or account for their effective target inputs safely. Do not silently accept link-string identity as complete compiler input identity. Please add the causal regression and qualify the correction before treating #2319's complete-input criterion as satisfied. This is within the existing issue, not a new optimization or new implementation claim.

  10. schlessera commented on Oct 17, 2026

    @schlessera
    OwnerAuthor

    Coordination from #1837: its frozen attribution slice at 1de2b7205dc00eb7b00fc87a78dd2c58fc95bb46 adds the local import scripts/build-receipt.ts to scripts/build.ts. When these slices are combined, that helper must join the stamp's complete-input inventory. The current explicit ROOT_BUILD_INPUTS list at PR #2328 head 4f52c27df4e852cf25a0745a36f12b3df7361530 does not yet name it. The attribution slice includes it in its audited CSS producer map and fixture copies.

    This is a future combination requirement under #2319's existing complete-input criterion, not a failure of the present uncombined head or a takeover of your branch. The independently confirmed symlink-target gap and its actual compiler receipt remain in this issue's body. The ownership and implementation claim remain yours; no rebase is requested merely for unrelated main advancement.

  11. 63 remaining items

  12. schlessera commented on Oct 22, 2026

    @schlessera
    OwnerAuthor

    Claim 46429e4e-2319-boundary-design: preparing the stronger deterministic native/runtime boundary design selected on 2026-10-22, for separate maintainer review. Design only — no implementation, qualification execution or hosted run. Delivered as an issue comment; no branch is planned. needs: decision stays.

  13. schlessera commented on Oct 22, 2026

    @schlessera
    OwnerAuthor

    Stronger deterministic native/runtime boundary — design for review (v5, 2026-10-22)

    Prepared under the 2026-10-22 Option B ruling. This is a design only: no implementation, qualification execution or hosted run is authorized or performed. Activation stays deferred, ordinary rebuilding stays active, and the original acceptance criteria, dormant delivery and release attribution are unchanged. Nothing here waives a criterion; §1b item 3 is a separate, explicit request.

    Inspected: main b17e349b7c8ff0f69c4cade3a953c86008d3ede8; #2458 head b751f30becd03af1b506e34f4f62f0cb155b83d3 (open draft); installed TypeScript 6.0.3; local Node 24.21.0. The pinned image's Node 24.20.0 has not been probed; every claim about it is pending under F1.

    1. Outcome

    1. No feasible boundary for the native builds as consumed. That covers Tailwind's @tailwindcss/oxide and lightningcss, and Bun as a producer. vDSO clocks, rdtsc/cpuid, direct syscalls and missing source-to-binary provenance cannot be closed by tracing, interposition or equal-output samples. A WASM build would be a different producer, rejected for cost (§11). Because of this, original criteria (a) "an unchanged repeat skips every package" and (c) "a damaged dist file rebuilds that package" cannot be met as written for ui-kit and ui-react stylesheets. This is the documented finding the brief allows. It does not waive anything.
    2. For TypeScript, a fresh-realm boundary reduces ambient inputs to four stated assumptions, R1–R4 (§4.4). They concern the V8/Node runtime and ICU data. They cannot be proved to the original criteria's standard, so accepting them needs a ruling. The boundary is proposed and unqualified.
      • A scratch prototype on Node 24.21.0 shows four things:
        • It loads TypeScript 6.0.3 in the realm with the module-level sys undefined.
        • It closes the clock and entropy escapes found by review.
        • It marshals all host data as realm-local objects.
        • It emits bytes identical to the real tsc CLI. Two fixtures were checked: 16 of 16 output files matched, covering JS, .d.ts, .js.map and .d.ts.map, with paths, customConditions: ["bun"] and a real OS symlink. Both runs exit 0.
      • That is evidence of feasibility, not qualification.
    3. After fix(ci): build runtime packages once per test invocation #2458, the expected same-root saving is about zero (§8.1). The current key binds the workspace root, and fix(ci): build runtime packages once per test invocation #2458 builds once per invocation in fresh roots. What remains is about a dozen identical-input builds per CI run in different roots and jobs. Reusing those needs cross-root or cross-run trust, which is out of scope (§2).
    4. Provenance remains open for the Node runtime, the TypeScript bundle and Bun as the verifier (§6). Determinism plus exact-byte identity would make reuse equivalent to a fresh run of the same producer. It would not make that producer trusted.

    Recommendation: decide items 1–2 of §1b now; they cost nothing. If Gate 0 confirms no net same-root value once #2458 merges, the maintainer may take item 3 of §1b: an explicit, criterion-by-criterion withdrawal request. Without that ruling, the criteria stay open and this document stays the reference boundary.

    1a. The named items: one disposition per cell

    Labels:

    • Pending: a mechanism is specified and prototype-demonstrated where noted; its guard control is not yet built.
    • Assumed: a residual with observational support only.
    • Excluded: the producer's output is never reused.
    • Open: not satisfied.
    Named item T: TypeScript C/M/D: copies, modes, dirs S: stylesheets Mechanism (T)
    Direct and vDSO clocks Pending Pending (postcondition) Excluded No performance, process or timers in the realm. Every ECMA-262/402 current-time operation is replaced or refuses (§4.3). Prototype-demonstrated. Node-internal native clock use cannot reach realm values except via R1.
    Entropy Pending Pending (postcondition) Excluded Math.random refuses; no crypto in the realm; hashing is a bridge call
    CPU and hardware Assumed (R1) Pending (postcondition) Excluded No os, process or navigator. JIT, CPU features and GC behaviour fall under R1.
    Kernel and device Pending (F1, R3) Pending (postcondition) Excluded No filesystem object in the realm, and --permission read access is limited to the loader and the manifest
    Locale, timezone, Unicode Assumed (R4) n/a Excluded Fixed LANG, LC_ALL and TZ, asserted in the realm. ICU and Unicode data come from the image.
    Effective compiler dependency Pending n/a Excluded Exact captured typescript.js bytes, evaluated from the manifest
    Runtime (Node, V8, ICU) Assumed (R1–R4) n/a n/a Exact bytes and image digest bound
    Native and stylesheet dependencies n/a (none on the T path) n/a Excluded Installed bytes are still part of the input key
    Effective aliases Pending Pending Excluded Manifest link resolution under the capture rules (§3.3). Prototype-demonstrated with an OS symlink.
    Source-to-binary provenance Open Open (Bun verifier) Open (lightningcss) §6

    1b. Decisions requested, in order

    1. Accept this document as the stronger-boundary design deliverable, with its findings: §1 items 1–4, the §1a dispositions, and R1–R4 as the irreducible residual for T.
    2. Economics and fix(ci): build runtime packages once per test invocation #2458: authorize Gate 0 (≤ 3 h, no runs) once fix(ci): build runtime packages once per test invocation #2458 merges. Separately: would a second receipt shape for fix(ci): build runtime packages once per test invocation #2458 hooks ever be acceptable? If not, same-root reuse can save nothing, and Gates 1–3 need not be considered.
    3. Only if Gate 0 reports no net value or insufficient evidence: an optional, explicit waiver request. Withdraw criteria (a)–(f), the mutation and real-runtime receipts, the ambient and provenance criteria, and the hosted comparison, each named, on the ground that fix(ci): build runtime packages once per test invocation #2458 removes the motivating cost. Alternatively, keep ci: skip unchanged workspace builds by a complete input stamp instead of rebuilding in every runtime hook #2319 deferred with the criteria open.
    4. Only if Gate 0 reports value:
      1. the provenance policy for the Node runtime, the TypeScript bundle and Bun: either exact bytes plus available evidence, or source-to-binary provenance, which blocks all three today;
      2. Gate 1;
      3. then R1–R4 acceptance given F1 and F3, the class contract and S treatment, the receipt shape, and Gate 2;
      4. then Gate 3.

    2. Threat model, equivalence target, reuse scope

    • Target: reused outputs equal, in bytes and modes, what the same isolated operation would produce now on the current captured inputs.
    • In scope: accidental dependence of a trusted producer on ambient state. A malicious compiler is out of scope, and a V8 realm is not a security boundary against hostile code. Section 4 removes accidental channels and states which outer operations remain reachable. Provenance (§6) addresses trust.
    • Reuse scope: the existing key, which binds checkout path, device and inode, UID/GID, socket, producer context and jobs (ci-build-operation.ts:47-53, 189-190). It binds no job or run identity. Reuse is limited to the same root because the key binds that root; the current workflow's fresh runners and worktrees make every root new. Reuse across roots, jobs, runs or branches, for example through actions/cache, is out of scope. It would need attested receipts and a cache-poisoning threat model.

    3. Output contract

    3.1 Ownership. Every regular file under packages/<p>/dist is owned by exactly one of T, C or S. An unowned file, a doubly-owned file, a symlink or any other type refuses reuse and publication. Capture already rejects non-file, non-directory entries (ci-build-boundary.ts:103-104, 124-127).

    Owner Members Reuse
    T Files the host receives through writeFile during executeCommandLine for p Reusable
    C ui-kit/dist/{theme,tokens}.css, ui-react/dist/theme.css, core/dist/hooks and all its descendants (copied from core/src/hooks) Reusable by postcondition: bytes equal the captured source
    S ui-kit/dist/styles.css, ui-react/dist/styles.css Never reused; regenerated by every operation that selects the package

    Today's hooks are extensionless shell files. If a future .ts file under core/src/hooks produced a T file inside a C tree, it would be doubly owned and would refuse. It would not be silently resolved.

    3.2 Modes.

    • T files are 0644.
    • Bin targets (M) are T files given mode | 0o111 (scripts/bin-modes.ts:18-22), which yields exactly 0755.
    • C files and C directories, including core/dist/hooks itself, keep their captured source modes.
    • The dist root and every other directory are 0755.
    • S files are 0644.

    3.3 Links. Input aliases follow the capture rules: relative targets only, and anything external, cyclic or unresolved refuses. The existing exception for declared bin-output targets is kept (ci-build-boundary.ts:66-86). Output links always refuse.

    3.4 Cross-package inputs. T resolves siblings to src through customConditions: ["bun"] (scripts/build.ts:6-13). S reads ui-kit's C file: ui-react/src/styles.css imports ./theme.css, whose line 18 imports @schlessera/brain-ui-kit/tokens.css. Selecting ui-react also selects ui-kit (packages/ui-react/package.json:54). S therefore runs for both, after both packages' T and C outputs are staged.

    4. Class T boundary: fresh-realm compiler host

    4.1 Process and loader (pinned; digests in policy)

    /usr/bin/node --permission \
      --allow-fs-read=/tool/tsc-host.cjs --allow-fs-read=/operation/manifest.bin \
      --disallow-code-generation-from-strings /tool/tsc-host.cjs <package>
    
    • One process runs per pending package, inside the existing container.
    • The process has no write, addon, child, worker, WASI or inspector permission.
    • Each path gets its own repeated flag. Node 24.21.0 ignores a comma-joined --allow-fs-* list and prints a deprecation warning.

    The outer host (tsc-host.cjs, our code, about 300 lines) is guarded by review and digest only. It runs in the outer realm with Node APIs; for example, process.getBuiltinModule stays callable there.

    Load sequence:

    1. Create the realm: vm.createContext(vm.constants.DONT_CONTEXTIFY, { codeGeneration: { strings: false, wasm: false } }). This gives an ordinary realm global whose constructor is the realm's own Object. Without the codeGeneration options, eval and Function still work in a new context despite the process flag (shown in review).
    2. Run realm preparation (§4.3).
    3. Create every object the compiler receives inside the realm: module, exports, the host, the argument array and the callback.
    4. Compile the captured typescript.js bytes with vm.compileFunction(source, ["module", "exports"], { parsingContext }) and call it with this undefined.

    With no process or require in the realm, isNodeLikeSystem() is false (typescript.js:3772-3774). So the module-level sys stays undefined: getNodeSystem, its case probe and its environment reads never run (8269-8278, 8670-8678), and perf_hooks is not required (5086-5130). Consequences, all F2 assertions:

    • diagnostics and tracing require system === sys and are unreachable (138057-138061);
    • inline source maps use TypeScript's own base64 encoder (121654-121658);
    • plugin loading (host.require, 187998) is language-service only;
    • the library directory comes from host.getExecutingFilePath() (126834-126842).

    Compilation runs through ts.executeCommandLine(host, cb, ["-p", "/repo/packages/<p>/tsconfig.build.json"]), the CLI's own entry point (_tsc.js ends with executeCommandLine(sys, noop, sys.args)).

    4.2 The bridge and host contract

    • Bridge: one outer function, bridge(name, json) → json. Strings go in, and a string comes out that the realm parses with its own JSON. Arrays and objects the compiler sees are therefore realm objects, and no outer object, Symbol or Error crosses. The bridge never throws into the realm: an outer fault becomes {ok:false}, sets the latch, and the realm wrapper throws a realm-local error.
    • Host: the realm-created host is wrapped in a recording Proxy. Every property read must be in a reviewed set; an unknown read records CI_BUILD_HOST_UNREVIEWED_MEMBER.
    • Reads observed across the two fixtures (13 members): readFile, fileExists, directoryExists, readDirectory, realpath, writeFile, createHash, exit, writeOutputIsTTY, getEnvironmentVariable, getExecutingFilePath, getCurrentDirectory and useCaseSensitiveFileNames.
    • Defined but unread by these fixtures: write, getDirectories, newLine and args.
    • The reviewed (allowed) set is kept separate from the observed set. F2 settles the final observed set across all 19 packages.
    Member Answer
    readFile, fileExists, directoryExists, getDirectories From the manifest only. Anything outside /repo or absent from the manifest is absent.
    readDirectory ts.matchFiles over the manifest's sorted listing. This is the listing that root discovery uses (typescript.js:43926-43943).
    realpath Manifest link resolution (§3.3)
    writeFile, createDirectory Staged; only /repo/packages/<p>/dist/**
    useCaseSensitiveFileNames, newLine, args, getCurrentDirectory, getExecutingFilePath true, "\n", fixed, /repo/packages/<p>, /repo/node_modules/typescript/lib/tsc.js
    getEnvironmentVariable ""
    write, writeOutputIsTTY Captured log; false
    exit, createHash Recorded; SHA-256
    • Lifecycle: completion is the synchronous return of executeCommandLine for -p, with the exit code recorded. After completion the bridge refuses every call, and a later call sets the latch. That includes queued Promise callbacks. The pass condition is therefore evaluated only on a later macrotask turn (setImmediate), after the shared microtask queue has drained, never synchronously on return. Prototype results:
      • A clean run passes.
      • A synchronous late writeFile is refused and latched; the run fails.
      • A queued, caught late writeFile is refused and latched before the predicate is computed; the run fails. An earlier synchronous predicate reported a stale success here, which review caught. The Proxy records every non-reviewed key read, including symbol keys.
    • Pass condition: a completion record with exit 0, latch clear and no unreviewed member. Anything else fails the operation, even if TypeScript catches the realm error.

    4.3 Realm preparation: systematically derived channels

    The channels are the intrinsics whose results ECMA-262, ECMA-402 or V8 leave host-dependent. F1 asserts the realm's global list exactly; it has 67 entries on 24.21.0, and Temporal is absent.

    Source of host dependence Treatment Prototype result
    ECMA-262 current time: Date(), new Date(), Date.now A fixed-epoch replacement Date, implemented as a standalone function that does not inherit from the original. Only UTC and parse are copied onto it. Date.prototype.constructor is rebound to the replacement. Date.now, Date.prototype.constructor.now(), new Date().constructor.now() and new (new Date(0).constructor)() all return 0. Object.getPrototypeOf(Date) has no now; an earlier draft that inherited the original leaked the clock through that path.
    ECMA-402 current time: Intl.DateTimeFormat format() and formatToParts() with no date Refuses when the date is undefined Throws CI_BUILD_CLOCK_REFUSED
    Math.random Refuses Throws
    Default locale and time zone (ECMA-402 DefaultLocale/DefaultTimeZone, LocalTZA) Fixed LANG/LC_ALL=C.UTF-8 and TZ=UTC. The realm asserts and records the resolved locale and zone. en-US/UTC. Review showed sv-SE and an offset of −60 under other settings, which is why the values are fixed.
    Unicode data (normalize, \p{} property escapes, case mapping) Bound to the image's ICU build (R4) —
    GC-observable WeakRef, FinalizationRegistry; Atomics, SharedArrayBuffer, WebAssembly; V8 console Deleted. 6.0.3 uses Atomics and SharedArrayBuffer only as type-checker names (typescript.js:16762-16784, 73988). Absent
    eval, Function from strings Context codeGeneration.strings: false Throws EvalError
    V8 stack extensions: Error.stackTraceLimit, prepareStackTrace, captureStackTrace, CallSite Each is defined on the realm Error as non-writable and non-configurable: limit 0, prepareStackTrace undefined, captureStackTrace a no-op. No formatter can be installed, so no CallSite is produced. TypeScript's exported setStackTraceLimit (typescript.js:7314) then fails with TypeError, closing the build. It has no call site inside typescript.js. No outer prepareStackTrace is installed. new Error("x").stack === "Error: x". ts.setStackTraceLimit(), an assignment and a defineProperty restore all throw TypeError, and the limit stays 0. Review showed a writable limit could be raised to 100, after which a structured formatter exposed outer frames.
    Symbol.for registry (shared across realms) No symbol crosses the bridge —
    Promise and microtask ordering Spec-defined; completion rule as in §4.2 —

    What still needs a reachability argument is the catch clauses, not the whole bundle. F3 audits every catch reachable from executeCommandLine, checker included (about 43 } catch sites), for one that could turn exhaustion into successful output (R2).

    4.4 Residual assumptions

    • R1: for identical Node bytes, V8 evaluates realm code identically regardless of CPU, JIT tier and GC.
    • R2: stack or heap exhaustion fails the build (F3).
    • R3: Node 24.20.0's permission and vm behaviour matches the 24.21.0 behaviour shown here (F1).
    • R4: ICU, Unicode and time-zone data are fixed by the image digest. F1 records process.versions.icu, unicode and tz, plus the icu_* keys in process.config.

    O1 (§8.3) supports R1 and R2 observationally only.

    5. Operation flow and publication

    Evidence versus admission.

    • T evidence is immutable, per session: the T manifest (paths, bytes and modes), the C postconditions, D modes, the loader, realm and host digests, completion records and the key.
    • Admission is the per-package stamp that points at evidence.
    • A lookup hits when the admission stamp matches the key and the current dist equals T ∪ C ∪ D, plus at most the S file.

    Generation state. tmp/ci-build-cache/generation.json is written by atomic file-rename and holds {id, state: "publishing" | "committed", selected}.

    Publication sequence, under the existing write lease:

    1. Stage complete new trees: T and C (staged or derived) plus fresh S. They go under tmp/ci-build-gen/<id>/new/<p>, on the same filesystem as packages/.
    2. Validate the union: §3 ownership and modes, T and C unchanged after S, C postconditions.
    3. Drain and remove the container, confirming absence.
    4. Write generation.json as publishing.
    5. Delete admission stamps for all selected packages.
    6. For each package: rename dist to …/old/<p>, then rename …/new/<p> to dist.
    7. Write the operation receipt, bound to id.
    8. Write admission stamps.
    9. Write generation.json as committed, then delete …/old.

    Recovery and authority.

    • Any operation that finds publishing treats every package in its selected as a miss. It restores or rebuilds, and never reuses.
    • Consumer and hook authority from the isolated path, meaning the fix(ci): build runtime packages once per test invocation #2458 handoff, ci-pack and visual entry points, requires a committed generation whose id matches the receipt. Each enumerated entry point checks this after acquiring the lease.
    • This is no weaker than the ordinary build, which also replaces dist non-atomically under the lease (build-execution.ts:29). Lease semantics are unchanged.
    • Readers that do not check a generation get the same guarantee as today.

    Transitions.

    Case Flow
    Cold or miss T and C for pending packages; S for selected UI packages; steps 1–9
    Full hit, no UI package Early return, as today (ci-build-operation.ts:210-215). Zero compiler children; the context-reader container still runs. Authority comes from the existing committed generation.
    Full hit with a UI package Container runs S only, with -o /stage/<p>/styles.css (a private writable mount) and reused T and C mounted read-only (ci-build-boundary.ts:163-166). Steps 1–9. T evidence is reused; admission is rewritten.
    Partial hit Reused packages are derived inputs; steps 1–9
    S failure, or interruption before step 4 Nothing changes on disk; previous admission stays
    Interruption during steps 4–8, or in step 9 before the atomic state write publishing remains, so there is no authority; the next run recovers
    Interruption during step 9's cleanup, after committed is written Authority holds; the leftover …/old trees are cleanup debt that the next operation removes
    Force Everything is built
    Subset Dependency closure retained

    #2458 handoff (needs its own ruling). #2458's completedBuild accepts only jobs === 1 receipts whose packages show real tsc (and css) children with exit code 0 (scripts/test-invocation.ts:34-45 at b751f30b). A hit has no tsc child. Reuse therefore requires a second accepted receipt shape: an isolated receipt bound to a committed generation and the key. Without it, every hit is followed by an ordinary rebuild in the hooks, and reuse saves nothing by construction.

    6. Provenance, separate from isolation

    Conditional argument. Exact ownership (§3), committed publication (§5) and the realm boundary (§4, under R1–R4) imply equivalence to a fresh run of identical producer bytes. They do not establish trust.

    Artifact Identity Provenance evidence (checked 2026-10-22) Status
    typescript.js 6.0.3 Exact captured bytes bun.lock integrity. npm view [email protected] dist.attestations is empty. The file is a 9.1 MB bundle; source-to-bundle equality is unverified. Open
    Image Node Bytes, image digest, process.versions Whether it matches the GPG-signed release is pending F4. Policy node.sha256 is null today. Open
    Bun 1.4.2 Produces no reused byte, but is the verifier: it computes capture hashes, the key, output identities, receipt matching and postconditions Release checksum Open, and relevant. Option: a Node co-verifier in the context-reader container, which already runs on every lookup, with read-only mounts. This adds a second implementation, not trust. Cost is charged in §8.
    oxide 4.3.3 Excluded @tailwindcss/[email protected] has an SLSA v1 attestation n/a
    lightningcss 1.32.0 Excluded No attestation Open, as in every ordinary build

    7. Implementation scope (only if Gates 0–2 justify it)

    Part Size or note
    scripts/ci-build-tsc-host.cjs: loader, realm preparation, bridge, Proxy, latch, framing About 300 lines
    §3 ownership and mode checks About 400 lines across these rows
    §5 generation publication; S-only path with -o Touches build-execution.ts:29, 54-58, ci-build-operation.ts:210-215, 222, 274-293, ci-build-state.ts:22-31
    Stamp and evidence split; optional co-verifier —
    Generation check in the enumerated consumer entry points —
    The #2458 second receipt shape Only after its ruling
    Controls (§8.3) —
    Decision-record update for isolated-ci-build.md —

    There is no package-content or CLI/MCP contract change. Ordinary and local builds are unchanged and Docker-free.

    8. Gates and limits

    Each gate is approved separately and stops with a written finding. Outcomes are reported as value, no net value or insufficient evidence; these are distinct, and ambiguity is never reported as "no value".

    8.1 Gate 0: economics (desk work plus existing artifacts; no runs)

    Net saving per job:

    r × (ordinary repeat − isolated hit) − c × (isolated cold − ordinary cold) − image availability − co-verifier
    

    Here r is the number of eligible same-root repeats and c the number of isolated cold builds. The same expression is used in Gate 3.

    Expected answer from code, at #2458 head:

    Job Same-root repeats Evidence
    pack 0 One build --jobs=2 (ci.yml:145) on a fresh runner
    browser, layout, endurance 0 One build each (scripts/ci-proof.ts:49-72)
    unit 0 Each worker gets a fresh git worktree root per invocation and builds once (scripts/unit-workers.ts:122, 177-203; scripts/test.ts:186-194)
    runtime 0 One invocation build. Measurement isolation selects none.
    runtime_host 0 Native proof cells are outside runtimeBuildSelection (scripts/prove-native-host.ts:44-85)
    captures 0 Builds inside its own image

    This is the expected value on successful paths. When prepareInvocation reports build-unattested (test-invocation.ts:180-183), hooks fall back to ordinary per-file builds (packages/ui-react/tests/fixtures/runtime-package-build.ts:9-21). Those fallbacks would be real repeats, and Gate 0 counts them.

    Remaining duplicates outside scope. About a dozen identical-input builds per run happen in different roots: two concurrent unit-worker roots per shard across three shards, plus pack, browser, layout and endurance. They stay out of scope under the root-bound key for three reasons: unit workers build concurrently, they run under unshare --user --mount with capabilities dropped (unit-workers.ts:200), so Docker reachability is doubtful, and cross-root trust is excluded by §2.

    Confirming from artifacts. Sources:

    • the tmp/*-probe.json workspace-build receipts (scripts/build-receipt.ts:51-85), uploaded by every proof job (ci.yml:201, 256, 324, 381, 438, 490, 543), including tmp/unit-worker-N-build-*-probe.json;
    • fix(ci): build runtime packages once per test invocation #2458's build-start, build-attested and build-unattested events;
    • runtime-hook events;
    • the pack log.

    Equal repeat.before.sha256 values identify candidate repeats only. The observation inventory is narrower than capture (build-repeat-observation.ts:76 onward), so eligibility stays unknown until key identity is established. Repeats are evaluated per package, because stamps are per package and the key excludes selected. Unavailable identity counts as unknown.

    Limits: 3 engineer-hours; artifacts of at most 6 existing runs; no dispatch. Rerun Gate 0 if #2458 is abandoned or changes its invocation model.

    Stop: a net saving of 0 or less on confirmed counts means no net value. Missing or ambiguous data means insufficient evidence.

    8.2 Gate 1: feasibility

    Item Work Limits
    Desk F2: the §4.1 consequences and the final host read set. F3: the catch-clause audit (R2). ≤ 4 engineer-hours
    Scratch Align the prototype with §4 exactly: manifest blob, --permission with only the two reads, all 19 package configurations as fixtures ≤ 4 engineer-hours
    Image F1: Node 24.20.0's permission denials, repeated-flag syntax, DONT_CONTEXTIFY and codeGeneration, the exact realm global list, and the R4 data versions ≤ 10 docker run --network=none invocations against the pinned digest, ≤ 10 min, no pulls
    Acquisition F4: the official Node binary, checksum and signature for the image's version ≤ 2 downloads, ≤ 200 MB

    8.3 Gate 2: offline qualification

    Every control's mutant is restored, and the restore is shown green.

    Control Setup Mutant Red assertion
    H1 Host read set over 19 packages equals the reviewed set Drop one reviewed member CI_BUILD_HOST_UNREVIEWED_MEMBER
    H2 Fixture with an included, unreferenced module; fault injected into the readDirectory listing Latch disabled (the emit silently lacks the module) CI_BUILD_HOST_FAULT_MUST_NOT_PUBLISH
    H3 Realm closure, checked two ways. Assertions: every §4.3 row, the exact global list and stack text. Reachability walk: start from the realm global, module, exports, the host, the argument array and the callback. Follow every own property descriptor, including accessor get/set functions (which are followed but not invoked), and every [[Prototype]]. Separately, check the values and errors returned from every exercised host call. Lexical closure captures, such as the bridge, cannot be walked and rest on source review. Assert that no forbidden object is reachable: the original Date constructor, the original Math.random, any deleted global, the bridge function, and any outer-realm object. Skip any one preparation step, or let the replacement Date inherit from the original CI_BUILD_REALM_CLOSED
    H4 Host T output equals real node tsc -p for 19 packages in the image Inject newLine: crlf into the parsed options, host only CI_BUILD_HOST_EMIT_EQUALS_CLI
    H6 An outer object crossing the bridge Bridge returns a raw outer array CI_BUILD_BRIDGE_REALM_LOCAL
    H7 Lifecycle and stack: a late host call after completion, and a queued-microtask host call whose error the realm catches, are both refused and latched, and no success record is issued. ts.setStackTraceLimit(), plus assignment and defineProperty on the stack properties, all fail. Bridge not closed at completion; success predicate computed before the microtask queue drains; stack properties left writable CI_BUILD_HOST_CLOSED_AFTER_COMPLETION, CI_BUILD_STACK_LOCKED
    P1 Outer host process attempts /proc/self/status, process.binding, dlopen, Worker and child_process No --permission CI_BUILD_COMPILER_CAPABILITY_DENIED
    X1 S writes index.js — CI_BUILD_OWNERSHIP_EXCLUSIVE
    X2 Wrong source copied to theme.css and stamped C postcondition removed CI_BUILD_COPY_POSTCONDITION
    X3 A T file at 0600; a bin at 0644 — CI_BUILD_OUTPUT_MODES
    S1 Unchanged source, ui-react/dist/styles.css deleted. Expect zero tsc, two S children, and restored CSS in the tarball and browser DOM. Skip S on a hit CI_BUILD_STYLESHEET_ALWAYS_REGENERATED
    I1–I4 Kill during S, and inside steps 5, 6 (between the two renames of one package, and between packages) and 8. Then a named consumer (the #2458 handoff, ci-pack) must reject the mixed generation. Write committed before the replacements finish, or let the consumer skip its generation check CI_BUILD_COMMIT_POINT
    H5 Hit, then a runtime hook with zero hook tsc (only if the §5 ruling is granted) Receipt not generation-bound CI_BUILD_HIT_SATISFIES_INVOCATION_RECEIPT
    V1 Bun identity mutant ignores one path (only if the co-verifier is adopted) — CI_BUILD_VERIFIERS_AGREE
    O1 Observational only: default vs --jitless, --cpus 1 vs 2, two affinities, doubled --stack-size. All T identities equal. — —

    Retained from the existing operation: config alias, installed-compiler mutation, packed default-export source-marker freshness in a real browser, tamper/delete/add recovery, force/subset/jobs, and the 19 packed-consumer inventories.

    Limits:

    • One fresh checkout and install.
    • At most 10 full 19-package arms; at most 30 fixture or single-package executions.
    • At most 5 hours wall-clock and at most 2 concurrent containers, each under the existing 330 s client deadline.
    • At most 25 GB scratch, deleted after receipts are archived.
    • One retry, for an infrastructure failure only. Stop on the first unexplained divergence.

    8.4 Gate 3: hosted net cost (only if Gate 0 finds r > 0)

    • Job: a temporary workflow_dispatch build-only job, added in its own PR.
    • Arms per dispatch, in randomized order:
      • an ordinary cold build in a fresh root;
      • an isolated cold build in a second fresh root;
      • three isolated hits in that root, interleaved with ordinary rebuilds in a third root.
    • Metric and sample: the per-dispatch mean of the §8.1 formula using Gate 0's r. Sample size is fixed at exactly 10 valid dispatches. The estimate is a t-interval over dispatch means.
    • Decision rule:
      • value when the lower 95% bound exceeds 30 s per job;
      • no net value when the upper bound is at most 0;
      • insufficient evidence otherwise.
    • Secondary: two matched full confirmations recording test(ui-react): retain setup phase and child completion receipts #2306 runtime-hook setup, critical path and summed seconds. This also covers the original hosted before/after criterion, which fix(ci): build runtime packages once per test invocation #2458's own measurement can satisfy.
    • Total cap: 12 hosted runs and 30 runner-hours, retries and cancellations included, with each dispatch capped at 25 minutes including image pull. At most one rerun, and only for a lost runner or a failed checkout.

    9. Original acceptance criteria

    Criterion Status
    (a) unchanged repeat skips every package; dist byte-identical Not achievable as written for the two styles.css files (§1 item 1). T, C, M and D would skip. S is never claimed byte-identical.
    (c) damaged dist file rebuilds that package T, C, M and D: yes. styles.css is regenerated on every selecting run. Not as written for S.
    (b), (d), (e), (f) Mechanisms unchanged. The key gains loader, realm and host digests.
    Mutation receipt H1–H4, H6, X2 and I-series, plus the existing output-hash mutation
    Source marker; tarball inventories Retained browser and inventory controls; S1
    Hosted before/after Gate 3 secondary, or #2458's measurement
    Ambient §1a; R1–R4 unproven
    Provenance Open (§6)

    11. Alternatives rejected

    • Make native producers deterministic in place: needs PR_SET_TSC/ARCH_SET_CPUID faulting and vDSO removal (record-and-replay tooling). Hosted support is uncertain, and provenance would still be missing.
    • WASM stylesheet producers (lightningcss-wasm, @tailwindcss/oxide-wasm32-wasi): a realm-style boundary for S would become possible. Rejected because it needs dependency overrides (a lockfile and release change), oxide's WASI build uses workers and shared memory, and shipped CSS would come from a different producer than local builds use.
    • Reproducible from-source native builds: they give provenance without determinism, at disproportionate cost.

    Earlier revisions (a frozen Node API around the stock CLI, then a shallow AST audit) were refuted in review. The round summaries below record why.

    Review record

    Three adversarial rounds, each by gpt-6-astra and opus-5.5 independently:

    • Round 1 (v1): invalid permission flag syntax; tsc's swallowed filesystem errors; incomplete Node API freeze; controls that could not turn red; criteria silently changed; economics after fix(ci): build runtime packages once per test invocation #2458.

    • Round 2 (v2): TypeScript builds Node's sys at load; shallow AST audit unsound; fix(ci): build runtime packages once per test invocation #2458 rejects tsc-less receipts; publication not interruption-safe; cold-build penalty missing.

    • Round 3 (v3): clock reachable via Date.prototype.constructor and Intl format(); outer prototypes and stack APIs leak across the realm; generation-state and consumer admission missing; "superseded" wording was a waiver in disguise; cross-root duplicates unstated.

    • Round 4 (v4, astra): one blocker: the stack properties were writable, so ts.setStackTraceLimit() plus a formatter re-exposed outer frames. Also: the replacement Date inherited from the original constructor (found in an interrupted run); late host calls were not refused; the interruption mutant did not test the real invariant; the read list and the cleanup row were inaccurate. Fixed above; the stack, Date, lifecycle and read-list fixes are demonstrated in the prototype.

    • Round 5 (v5, astra): one blocker. The success predicate was computed before queued microtasks ran, so a stale success could be reported. Fixed by evaluating the predicate after the queue drains. Prototype: a clean run passes; queued and synchronous late calls both fail.

    v4 resolves each with the bridge, constructor and Intl closure, stack neutralization, the generation protocol, waiver separation and the census. The prototype demonstrates the realm fixes and CLI-identical emit on two fixtures. Scratch work ran only under /tmp on local Node 24.21.0; no repository build, Docker run or hosted run occurred.

  14. schlessera commented on Oct 22, 2026

    @schlessera
    OwnerAuthor

    Claim 46429e4e-2319-boundary-design released. The design deliverable is posted and linked from the body. No code, branch or PR was created. The next action is the maintainer's: §1b items 1–2. needs: decision is unchanged.

  15. removed their assignment
    on Oct 22, 2026
  16. added
    blockedWaiting on another issue or an upstream dependency. Say which in the body.
    agent-readyContext and acceptance criteria are complete enough for an agent to take this unattended.
    and removed
    needs: decisionBlocked on a maintainer or designer ruling, not on code.
    on Oct 22, 2026
  17. schlessera commented on Oct 22, 2026

    @schlessera
    OwnerAuthor

    Decision (maintainer, 2026-10-22), on design §1b: (1) the stronger-boundary design is accepted, with R1–R4 as the residual for TypeScript outputs; (2) Gate 0 (§8.1: ≤ 3 engineer-hours, artifacts of ≤ 6 existing runs, no dispatch) is authorized once #2458 merges; (3) a second, isolated receipt shape for #2458 hooks is acceptable in principle, with its concrete shape left to a later ruling if Gate 0 reports value. Gates 1–3, implementation, qualification runs and activation remain unauthorized; the original criteria stay open. The brief is updated; the issue is now blocked on #2458 with agent-ready for the bounded Gate 0 desk work only.

  18. schlessera commented on Oct 22, 2026

    @schlessera
    OwnerAuthor

    Gate 0 result (design §8.1), 2026-10-22: insufficient evidence

    Every proof job has 0 confirmed same-root repeats, with one exception: captures. captures does one full-workspace rebuild per run in the same root, and its key identity cannot be observed. Without captures, the confirmed counts give no net value. With it, the stop rule ("missing or ambiguous data means insufficient evidence") applies, so the result is insufficient evidence. The ruling below would settle it either way without new runs.

    Scope kept to the brief. Desk work only, over the artifacts and job logs of 3 existing, completed automatic main-push runs. No dispatch, no build or qualification execution, no code change, and no change to the dormant operation. Ordinary rebuilding stays active and the original criteria stay open.

    Runs and SHAs used (3 of the 6 allowed)

    Run Head Relation to #2458 State
    A: 39766119331 736a3445e82aee509e10f3c8d00b95fc77749202 the #2458 squash itself Cancelled at 11:14Z by a newer main push. 15 of 16 proof jobs had finished (unit (4) failed on offline-launcher and fixture-admission tests; #2623 fixes this, and run B's unit (4) passes). runtime_host was cancelled mid-job. All 14 artifacts were uploaded.
    B: 39766877611 3125574b8 descends from 736a3445e. The only changes are scripts/browser-shard-costs.json and tests/offline-test-launcher.test.ts. The invocation, build, receipt, unit-worker, capture and ci.yml files are byte-identical. Complete, all green, including runtime_host.
    C: 39766742446 18675b8d9870278c5721f82132fb4660acf9f420 descends from 736a3445e (one test file changed). The invocation, build, receipt, unit-worker, capture and ci.yml files are byte-identical. Complete, all green. Together with B, the first green main runs with #2458's once-per-invocation build.

    PR #2458's own CI at head 217c33370 skipped every proof job (draft gates only), so it has no artifacts to analyse.

    Per-job table (A / B / C)

    The repeat count is per package within one root. "Candidate" means a second build in the same root whose key identity is unknown.

    Job Builds per root Confirmed same-root repeats Candidates, identity unknown Ordinary build, s (A / B) Evidence
    pack 1 (--jobs=2, 19 packages) 0 0 92 / 95 / 81 job log: 19 Building packages/… lines; no probe upload
    unit, 4 shards × 2 worker roots 1 full build per worker root (jobs=1) 0 0 120–189 / 128–198 / 146–189 8 unit-worker-N-build-*-probe.json per run, one per root. 8/8 build-attested per run. 17/17 real runtime hooks attested, 0 real built fallbacks, 0 real build-unattested
    runtime 1 subset build (11 packages) 0 0 84.1 / 86.2 / 82.4 1 build-attested; 2/2 hooks attested
    runtime_host 0 0 0 n/a B, C: no probe and no build progress (A was cancelled)
    browser × 3 1 each 0 0 78–112 / 108–109 / 103–107 1 probe per artifact
    layout × 2 1 each 0 0 71–102 / 65–83 / 103–104 1 probe per artifact
    endurance 1 0 0 106.7 / 63.3 / 108.5 1 probe
    captures 2 full builds, same root unknown 1 × 19 packages 86.0 + 86.4 / 72.9 + 70.6 / 113.9 + 114.3 2 probes, both repeat.state: "unknown" (before unobservable inside the capture image)

    Other observations:

    • Equal repeat.before.sha256: none. In each run, all 15 known receipts have distinct values: different roots, different dependency inodes. Every full build's output identity is the same (374cd6a976c9…) across roots. That is the cross-root duplicate that §2 excludes.
    • Fixture-root events, excluded from the counts. These belong to the wrapper self-tests, which run in temporary Odysseus fixture roots. None of them is a workspace build, and none produced a copied probe.
      • Unit shard 1: 2 invocations of ithaca,troy (attested) from tests/test-invocation-workers.test.ts, plus 2 sibling-rejection-N hooks with disposition built.
      • Unit shard 4: 14 invocations of raft from the tests/helpers/unit-worker-fixture.ts tests: 12 build-unattested and 2 preparation-failed (code 7).
      • I matched each by nonce to its fixture build-start.
    • Dormant operation: no ci-build-operation-*-probe.json in any artifact, which is correct: BRAIN_CI_BUILD_OPERATION is unset.

    Net saving, §8.1 formula

    r × (ordinary repeat − isolated hit) − c × (isolated cold − ordinary cold) − image availability − co-verifier

    • pack, unit, runtime, runtime_host, browser, layout, endurance: r = 0 on all three runs, which matches §8.1's code expectation. The net saving is ≤ 0 for any non-negative isolation overhead. No net value on confirmed counts.
    • captures: this corrects §8.1's code table, which listed captures as 0.
      • Where the repeat comes from: capture:verify runs scripts/capture.ts twice (scripts/captures/verify.ts:51-52). Each pass runs bun run build inside the pinned image with the checkout bind-mounted read-write (scripts/capture.ts:96-99). The second pass rebuilds all 19 packages about 2.4 min after the first, on the same checkout, with no source change in between. Each pass also refuses source that changes while it builds.
      • Upper bound on r: 1 per captures run. Upper bound on the gross term: ≤ 114 s (observed range 71–114 s) minus the isolated hit, before subtracting c = 1 cold overhead, image availability and co-verifier.
      • Eligibility cannot be established from artifacts:
        1. The receipt's input observation is unknown in the image, so key identity is unavailable. The brief says that counts as unknown.
        2. The build runs inside a container without /var/run/docker.sock, which the current operation's scope requires (scripts/ci-build-operation.ts:47-50).
        3. The second build is the independent arm that the reproducibility comparison exists to prove.

    Time

    About 1 engineer-hour (10:45–11:45Z), including the wait for run A and the run C addendum. The 3-hour limit is not reached.

    Ruling needed (issue returns to needs: decision)

    Is captures' capture:verify second-pass rebuild in the reuse scope for #2319?
    (a) Out of scope. It is the deliberately independent second build of a reproducibility check, and it runs inside the capture image, where the isolated operation cannot run. Gate 0 then stands as no net value on confirmed counts, and §1b item 3 applies: the explicit, named criterion-withdrawal request, or keep #2319 deferred with the criteria open.
    (b) In scope. Gate 0 cannot conclude without establishing that repeat's key identity, which needs separately authorized work. At most it is worth one job's rebuild, ≤ 114 s gross per captures run. Gates 1–3 stay unauthorized either way.

    Recommendation: (a). Reusing the first pass would weaken what capture:verify proves. And even in the best case the saving is bounded to one conditionally selected job, less the isolation costs.

  19. added
    needs: decisionBlocked on a maintainer or designer ruling, not on code.
    and removed
    agent-readyContext and acceptance criteria are complete enough for an agent to take this unattended.
    blockedWaiting on another issue or an upstream dependency. Say which in the body.
    needs: decisionBlocked on a maintainer or designer ruling, not on code.
    on Oct 22, 2026
  20. schlessera commented on Oct 22, 2026

    @schlessera
    OwnerAuthor

    Maintainer ruling 2026-10-22: the captures capture:verify second-pass rebuild is out of #2319's reuse scope. It is the deliberately independent second build of a reproducibility check. Gate 0 therefore stands as no net value: in the first main runs with #2458 (39766119331, 39766877611, 39766742446), every job builds once per root, and every runtime hook uses the shared invocation build (Gate 0 result). The remaining criteria are withdrawn. The build-once goal is delivered by #2458, and Gates 1-3 are not pursued. Closing as superseded by #2458.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ciCI workflows, the gates they run, release scripts, packaging.area: ui-reactReact chat/files/voice components, stores, WebSocket transport.priority: p0Drop everything: a security hole, data loss, or a broken release.type: choreTooling, CI, release plumbing, dependencies.

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions