[Homebrew/VFS] Verify the lazy shell before boot and activate Homebrew atomically - #1109
Merged
Merged
Conversation
This was referenced Jul 26, 2026
Contributor
Phase B-1 matrix build status —
|
| Package | Arch | Status | Sha |
|---|---|---|---|
| homebrew-bootstrap | wasm32 | built | 1ec4e97d |
| kandelo-sdk | wasm32 | built | 9155d009 |
| mariadb-test | wasm32 | built | e86311db |
| mariadb-vfs | wasm32 | built | 30eb94ab |
| mariadb-vfs | wasm64 | built | 64e1f49e |
| redis-vfs | wasm32 | built | a9f52855 |
| rootfs | wasm32 | built | 9bbf2712 |
Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.
Make deferred package trees one authenticated atomic unit before Homebrew composition, image export, fetch registration, or consumer callbacks. Carry the complete sealed-tree substrate, cross-host lifecycle contracts, and VFS image tooling onto the admitted-generation base so this first cutover commit is usable and testable on its own. Keep synchronous assertions synchronous and await authentication only at trust boundaries that can safely propagate failure. Preserve the audited base contract that source fallback, package fetch, Vite build, and sealed browser preview all receive one package-cache trust root. Keep VFS functional checks here, but leave fetched-catalog, eager-derivative, candidate-output, and browser-step assertions with the later lazy-shell workflow they describe. No ABI version, package archive, bottle, VFS release, or binary index is published by this commit.
Move the remaining shell, rootfs-overlay, mkrootfs, PHP, source-smoke, and Homebrew-base consumers behind imported atomic-seal verification before they inspect, copy, rebase, resolve, mutate, extract, or save derived state. Recheck browser boot ownership immediately after asynchronous verification so superseded work cannot resume against a stale machine. Cover forged member and cohort images without permitting partial output.
Return the exact filesystem verification promise and recheck ownership in the caller continuation, closing the seal-verification microtask race. Apply the same ownership rule after boot-time fetch, hash, composition, spawn, and closed-asset awaits, and register composed buffers for cleanup before rejecting superseded work. Exercise both supersession orderings and exact promise identity so a stale browser boot cannot regain authority after an await.
Treat imported lazy-tree seals as trust claims: Node and browser consumers must authenticate them before inspecting, mutating, composing, or booting the image. Make verified asynchronous restore the product boundary, reject sealed metadata on the synchronous registration path, serialize browser registrations, and tear down half-initialized workers on verification failure. Keep low-level parsing available only with an explicit verify-before-use contract. Cover shared host behavior, Node worker failure, browser boot rejection, and mkrootfs rejection, and document the same boundary for both hosts.
Register the exact Homebrew source package and its complete bottle-backed runtime support as one first-use transaction, then prove stock brew against first-party and independent third-party taps in shared Node and Chromium lifecycle contracts. Preserve source-rootfs as the required activation lane until production bottle admission and keep the replacement artifact lock pending, so this preparatory state cannot claim or publish stale local image bytes. Retain the audited one-cache assertions inherited from the base and adapt them only where this commit changes workflow step boundaries. Fetched-catalog, candidate-output, and browser-step assertions land here with the implementation they describe instead of making a sealed-VFS predecessor demand the future lazy-shell shape.
Preserve the canonical shell bottle provenance instead of resolving and copying Dinit again in every service image. Reject partial, lazy, or non-executable inherited sets, while retaining the legacy registry/source fallback until the shell owns neither binary.
Exercise complete inherited Dinit sets, rejection of partial, lazy, or non-executable sets, legacy registry fallback when the shell owns neither binary, and failure when neither source can provide a coherent service manager.
The lazy-shell projection was generated before the sealed VFS helper changes. Regenerate only the derived program index so each of the six VFS consumers binds the helper bytes it will actually build with. No source recipe, archive, release, bottle, or binary index is published here; this commit updates cache identity metadata for the combined source tree.
Reconstruct the reviewed live lifecycle harness on the combined atomic-activation product base. Preserve the pinned canary product lock while requiring independently supplied M, TF, and C authority, and bind the exact same candidate inputs across Node and Chromium. Source-Commit: 4b315aad68a7311f79fc0e06149e32e8d22f43ed Combined-Base: b0b8e11608b02a0e2ab77af9a4bf44d35a47853f
Bind Kandelo M, first-party tap TF, and independent-canary C to one exact anonymous public main record before any detached candidate work. Keep the reviewed product locks as independent corroboration, reject stale-but-reachable revisions in the closure contract, and document the provisional TF pin.
Keep the canonical shell package bottle-backed and fail-closed while the required PR/main lane stages a distinct, non-published source-rootfs bridge. Exercise the real browser-worker VFS restore boundary without importing unrelated default artifacts, and pin both explicit-byte and default-artifact BrowserKernel behavior with focused tests.
Run the temporary source product lanes for every relevant repository event so transitive package and shared tool inputs cannot evade validation through a stale path allowlist. Bind transient fetched-shell cleanup to the resolver canonical immutable generation target, and cover the actual target shape plus Pages trigger mutations.
brandonpayton
force-pushed
the
homebrew/sealed-lazy-lifecycle-qk044
branch
from
July 26, 2026 16:40
b7daa10 to
0104d21
Compare
Make publication readiness a shared dependency-closed authority. Pending packages and their reverse-dependent closures are omitted or rejected consistently before archive or release mutation. Drive staging, prepare-merge, force-rebuild, and test materialization from the Rust expected ledger. Recheck exact-main, package-source, and durable publication boundaries, with typed blocker evidence so operational failures cannot be mistaken for policy omissions. Enforce the same-version revision floor on success and failure writers, retain it across ABI pruning, and advance the shell recipe to revision 22 while its publication authority remains pending. Validated with the full xtask suite, durable package-generation suites, shell closure contract, workflow/scope contracts, package materialization tests, YAML parsing, Bash syntax checks, and the pinned cache-projection transition.
A durable generation preserves the producer snapshot source release tag while publishing identical verified content under a new content-addressed tag. Comparing those locator strings rejected every valid promotion. Bind the source locator explicitly, normalize only a cloned locator to the destination tag, and then require full snapshot equality. Thread the source tag through preparation, publication, and materialization; keep the one-shot validator transition pin current; and cover successful re-homing plus source-tag, snapshot, index, and archive tampering.
The hosted #1109 staging artifacts prove that the declared Kandelo SDK, MariaDB test, MariaDB VFS, and Redis VFS outputs changed after the shared VFS implementation updates. Advance their package revisions so the human-visible release lineage matches the new payload bytes, then regenerate the checked program-package projection and contextual cache keys. Rootfs remains at revision 9 because its declared rootfs.vfs payload is byte-identical even though its conservative input-derived cache key moved.
Carry the typed publication-blocker ledger into prepared browser workspaces and source-build each blocked root into an ephemeral local generation. Pin the separately identified source-rootfs shell through build-deps local-libs before rebuilding reverse-dependent VFS images, so exact PR browser validation cannot substitute stale canonical bytes or mutate release state.
Keep direct test compilation out of package-owned program mirrors, and verify the selected shell's existing link set as a preserved subset while allowing unrelated browser packages to add their own mirrors. This prevents unowned regular files from blocking package materialization without weakening generation identity checks.
Keep candidate kernel, userspace, and complete package closures bound to the immutable local generation that produced them while CI stages and resolves the workspace. Freeze the staging snapshot, reject stale identities and unsafe aliases, and fail closed instead of silently substituting released artifacts. Cover scalar and multi-member closure ownership, portable staging, concurrent mutation, stale-cache, symlink-ancestor, and identityless-root cases.
The first complete hosted run reached every major validation stage, but exposed four mismatches in the test harness: - Linux rejected an invalid package-generation link at a different valid check than Darwin. - A resolver test modeled kernel.wasm as anonymous bytes instead of a claimed immutable generation. - The temporary source shell installed fbDOOM and modeset but copied metadata from the lean bottled base. - The Node smoke passed a compatibility symlink to a boundary that intentionally accepts only direct regular files. Assert the stable rejection result across hosts, model the real kernel generation, and pass the validated immutable kernel member to Node without weakening the input boundary. Give the source shell an image-owned Doom and modeset profile overlay, bind its commands to installed executables, and run the modeset browser proof only for that image. Keep the bottled base honest by testing only software it owns. Update the source package revision, workflow contracts, focused tests, and authoritative documentation. ABI remains 42.
Contributor
|
prepare-merge: test-gate passed against the synthetic PR merge and sealed |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Kandelo's main shell is moving from one large virtual filesystem (VFS) image
to a smaller image whose optional programs are downloaded lazily from Homebrew
bottles.
That design is useful only if Kandelo can prove two things:
browser code reads, changes, combines, exports, or boots it.
see a partly installed
brewcommand or runtime.Continuous integration (CI) must also test the exact kernel, programs, and
images built from this pull request. It must not silently replace them with
older released files that happen to have the same names.
This PR establishes those guarantees. It also provides a temporary
source-built shell so pull requests and GitHub Pages can test current source
while the final bottles are rebuilt from merged
main.What changed
Safe lazy package activation
mutation, export, restore, or boot.
started workers.
verification is in progress, the older boot cannot become active afterward.
as one transaction on first use.
third-party tap lifecycle: tap, install, reinstall, export, reboot, verify
persisted state, perform a pinned no-op upgrade, uninstall, revoke trust, and
untap.
Exact CI inputs
A build output now keeps its immutable local-generation identity while CI
packages and stages a workspace.
This means CI:
package closures, unsafe symlink ancestors, and lookalike paths;
The candidate kernel's public path is intentionally a compatibility symlink.
The workflow now validates that link's namespace, cache identity, build
session, publication claim, and exact bytes, then passes the direct immutable
generation member to acceptance tests.
Honest image-owned demo metadata
The final bottled base shell does not include fbDOOM or modeset, so its
acceptance test does not claim or exercise those optional programs.
The temporary source-built shell does include them. It now composes a separate
profile overlay that:
A future optional bottle layer can carry those programs and their profiles
without making them part of the base shell.
Publication safety
The canonical shell recipe remains bottle-backed and fail-closed. This PR does
not publish a replacement shell, bottle, package archive, VFS release, or
binary index.
Packages can declare a project-owned
publication_state. One shared Rustpolicy excludes a pending package and everything that depends on it from
publication. Explicitly requesting a blocked package reports its dependency
chain; unrelated parse, graph, tool, and I/O failures remain real failures.
Durable generation validation also distinguishes an immutable source release
from its new content-addressed destination. Re-homing is allowed only when the
index, snapshot, archive inventory, digests, and producer provenance remain
identical.
Temporary source-shell bridge
Until final bottles are rebuilt from merged
main, the temporary shell:runner, workspace, run, temporary directory, cache, and index.
Failure or cancellation prevents later build, seal, freshness, and deployment
steps.
This broad source-build path is temporary. Final cutover will replace it with
narrower bottle-backed validation.
What the previous hosted run found
The complete run for head
b9ce9cdd04ceade23772aa297b5f49a1831fab6dfound four concrete harness andimage-ownership problems:
test-gate-validationexpected onlystaged local resolver link retains an external absolute target.GNU/Linux correctly rejected the same bad input later as
local program resolver link targets a noncanonical generation.The test now accepts either safe rejection outcome.
kernel.wasm, while thereal build exposes kernel bytes through a claimed, read-only immutable
generation. The fixture now models the real ownership contract.
WAITING FOR PAGE_FLIP. The executablebytes were correct, but the temporary source shell had copied metadata from
the lean bottled base and therefore never launched modeset. The source-only
profile overlay now owns that launch command.
local-binaries/kernel.wasmbecause that publiccompatibility path is intentionally a symlink. CI now passes the validated
direct generation member while retaining the strict non-symlink boundary.
The same run otherwise completed the package builds, candidate kernel,
source-rootfs shell build, direct browser-input preparation, fork-instrument
tests, libc tests, POSIX tests, and all Sortix groups. The separate browser
smoke run was green.
What the exact-head replay found
The complete replay for head
680c25bc0c90e198dde40ff3f9b3ae4454bf45c3established that the ownershipcorrections work end to end:
suite passed;
Its only direct failure was an obsolete migration assertion. The one-shot
#1097 cache-projection bridge expected historical
build_deps.rsbytes, butcurrent source has changed. A current-authority replay also proved that the
rootfs cache identity now differs because declared VFS and rootfs inputs
legitimately changed. Rotating the old pin would therefore misrepresent old
artifacts as current.
The final commit retires that bridge instead:
method;
merge.
Staging’s second red job was only the aggregate gate reflecting that same
validation result; it found no additional failure.
Validation
Local validation for the correction batch:
actionlint, with only the same two pre-existing informational findings asthe previous head;
git diff --check; andfail-closed dispatch, durable materialization, and merge-candidate lifecycle.
Final exact integration record:
5b13574395acf9a8e46c47c62dc2c38eda3bd3f8a0e0ce0cd65998483a779bc099a9a653bdac3465bc5f9c2975ec81a3917f94839bd0e3d858bf0cf0Fresh hosted validation for that exact head:
These runs are not claimed as passing until every required job reaches a
terminal green result. A quiet or incomplete log is not treated as a failure
and will not be cancelled merely for taking time.
No kernel ABI structure or semantics change in this PR; ABI remains 42.
Remaining cutover after merge
mainrootfs dependency closure in parallel.revision in Kandelo.
lifecycle.
Dinit is already resident in the shell and is not an additional publication
blocker.
Approval
Please do not merge until all hosted gates are green for exact head
a0e0ce0cd65998483a779bc099a9a653bdac3465and that head has receivedexplicit approval.