[Homebrew/ABI] Prepare one verified ABI 42 package generation - #1079
Merged
62 commits merged intoJul 24, 2026
Merged
Conversation
Contributor
Phase B-1 matrix build status —
|
| Package | Arch | Status | Sha |
|---|---|---|---|
| icu | wasm32 | built | 48a3ee79 |
| libcurl | wasm32 | built | 8273da44 |
| libcxx | wasm32 | built | 53612e1c |
| libcxx | wasm64 | built | 986b4977 |
| libiconv | wasm32 | built | b494e26a |
| libpng | wasm32 | built | e31da77e |
| libxml2 | wasm32 | built | f8e7709d |
| libzip | wasm32 | built | 0e020e8d |
| openssl | wasm32 | built | bdef2279 |
| openssl | wasm64 | built | 11532ba6 |
| sqlite | wasm32 | built | a21f5097 |
| sqlite | wasm64 | built | 1f7a45fb |
| zlib | wasm32 | built | a826c5a1 |
| zlib | wasm64 | built | 09bd3336 |
| bc | wasm32 | built | 87d9afde |
| bzip2 | wasm32 | built | 09122fb0 |
| coreutils | wasm32 | built | 72765db8 |
| cpython | wasm32 | built | 314d4763 |
| curl | wasm32 | built | 63cca65e |
| dash | wasm32 | built | 0b2035e2 |
| diffutils | wasm32 | built | 5b829e0f |
| dinit | wasm32 | built | 28167e43 |
| erlang | wasm32 | built | fb022926 |
| fbdoom | wasm32 | built | ad115c1c |
| file | wasm32 | built | 41f1cbea |
| findutils | wasm32 | built | 9cf821c8 |
| gawk | wasm32 | built | f25ff8e1 |
| git | wasm32 | built | 956b61b3 |
| grep | wasm32 | built | 2b95ab13 |
| gzip | wasm32 | built | c5fea74e |
| homebrew-bootstrap | wasm32 | built | 3f44ee7f |
| kandelo-sdk | wasm32 | built | 5ec342f9 |
| kernel | wasm32 | built | d0e03c4b |
| less | wasm32 | built | 69fd5aea |
| lsof | wasm32 | built | 0cbea55d |
| m4 | wasm32 | built | 746a3cb4 |
| make | wasm32 | built | 8bbaab34 |
| mariadb | wasm32 | built | 89cb71f5 |
| mariadb | wasm64 | built | f6668fed |
| modeset | wasm32 | built | 8a5f567e |
| msmtpd | wasm32 | built | 94c0ffb6 |
| nano | wasm32 | built | 48c6e796 |
| ncurses | wasm32 | built | e95f6769 |
| netcat | wasm32 | built | 3d57ef27 |
| nginx | wasm32 | built | cc1c9c86 |
| php | wasm32 | built | 54c56075 |
| posix-utils-lite | wasm32 | built | 81206dd7 |
| ruby | wasm32 | built | b9554136 |
| sed | wasm32 | built | 6265486b |
| shell | wasm32 | failed | — |
| spidermonkey | wasm32 | built | 2c2b1f59 |
| tar | wasm32 | built | d842e794 |
| tcl | wasm32 | built | edae6679 |
| unzip | wasm32 | built | f4ee34b5 |
| userspace | wasm32 | built | 6538ad13 |
| vim | wasm32 | built | 39d28fe5 |
| wget | wasm32 | built | 222061a6 |
| xz | wasm32 | built | 71047565 |
| zip | wasm32 | built | a73d281e |
| zstd | wasm32 | built | 1e00e7d1 |
| bash | wasm32 | built | 830ea09a |
| lamp | wasm32 | failed | — |
| mariadb-test | wasm32 | built | 98b28ac6 |
| mariadb-vfs | wasm32 | built | 8ea599de |
| mariadb-vfs | wasm64 | built | ffd24483 |
| nethack | wasm32 | built | 35bd109a |
| nginx-php-vfs | wasm32 | failed | — |
| nginx-vfs | wasm32 | failed | — |
| node | wasm32 | built | 62a1b6d2 |
| redis-vfs | wasm32 | built | dfbdea8a |
| spidermonkey-node | wasm32 | built | 1fc4b5fe |
| vim-browser-bundle | wasm32 | failed | — |
| wordpress | wasm32 | failed | — |
| nethack-browser-bundle | wasm32 | failed | — |
| node-vfs | wasm32 | failed | — |
| rootfs | wasm32 | built | f37ef8a5 |
Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.
Require shell-derived images to match the reviewed capacity profile as well as its data and inode reserves. Keep a deliberate expected-capacity override for a future larger product profile. Make host-tree composition fail on every read, unsupported-entry, and VFS-write error; intentional omissions remain explicit excludes. Cover the complete copy-option surface, ENOSPC propagation, capacity drift, and larger-profile escape path.
Validate the serialized image capacity before compression or output writes, require intentional symlink handling, and propagate MariaDB test source failures. Add contract coverage for masked capacity, failed host reads, and shell profile constraints.
Bind the Homebrew main-shell serializer to its encoded capacity contract before output writes. Require every declared MariaDB test and fixture tree instead of preserving best-effort omissions, and remove the stale simple_select entry that the pinned source archive does not contain. Add executable failure-path, selection-parity, and package-input coverage.
Allow the static Formula planner to recognize three canonical native-tool Requirement classes without evaluating Formula source. Preserve the existing sealed homebrew/core identity plan, and reject unknown, dynamic, forged, unloaded, or test-only Requirement declarations.
Bind allowlisted Requirement classes, Formula identities, sentinel executables, and tags into a closed schema-4 host dependency plan. Validate that plan in every producer and consumer, reconstruct only matched build-only Homebrew dependencies for Superenv, and expose sealed test tools through the normal Formula test lifecycle. Cover malformed plans and evaluated-object drift, plus an actual install/test against the exact pinned Homebrew source.
Provision an isolated Bundler copy before the publisher boundary, then seal it and run the real pinned Homebrew install and test commands behind an OS-enforced network sandbox. Probe that boundary with a reachable control socket and fail if the gem tree changes or Bundler activity appears.
Carry the dev-shell PATH explicitly through the passwordless-sudo network namespace used by GitHub runners. This keeps sealed native Requirement sentinels visible after sudo applies secure_path, while retaining the OS-enforced offline boundary.
Document the closed schema-4 native Requirement contract, the offline pinned publisher lifecycle, and the remaining canonical-package activation gate. Keep the trusted publisher Homebrew revision distinct from the dedicated guest homebrew-bootstrap package so staging URLs are not mistaken for durable consumer inputs.
Generate the real pinned Homebrew lifecycle plan through the same static Formula parser and closed-schema validator used by publication before staging it for Build and test. Bound every host dependency list to the platform's 128-entry limit in both validation layers, and cover oversized plans so protected control data cannot grow beyond the reviewed graph contract.
Make product WordPress and LAMP builds resolve only their SHA-pinned source archives instead of invoking the unpacked local-demo setup path. Centralize the reviewed WordPress core copy policy, materialize the SQLite plugin from its separate pinned source, and keep every unrelated source symlink fail-closed. Cover the package entrypoint boundary, local-demo setup ownership, exact exclusions, plugin guest placement, unexpected symlinks, and refreshed package identities.
Derive one canonical typed-tree descriptor from an exact declared package ZIP output, then let image builds either preserve it as one first-use group or directly materialize that same descriptor and payload. Record source-tree versus runtime-tree distribution meaning so a tool source tree cannot be mistaken for a Homebrew bottle. Give Node the same relative lazy-asset URL resolution contract as the browser, preserve closed exact-byte acceptance, and teach Homebrew materialization evidence to distinguish its bottle groups from coexisting package trees without overlooking unexpected bottles. This changes no kernel or guest ABI.
Propagate real namespace lookup errors during package-tree preflight instead of treating every lstat failure as a missing path. Add focused package-tree coverage proving a digest-mismatched first fetch commits no member, remains retryable, and coalesces concurrent access into one fetch on both the failed attempt and the successful retry.
Pre-publication browser checks may read an artifact from a local or staging source while the VFS stores its final immutable HTTPS URL. Callers previously had to fetch and assemble that binding themselves, which made it too easy to associate incomplete or changed bytes with the trusted URL. Add a bounded loader that validates the complete source list before I/O, omits credentials, rejects redirects, streams exactly the declared length, verifies SHA-256, and only then returns canonical closed-asset bindings. Export the primitive and cover invalid identities, truncation, overflow, digest changes, aggregate limits, concurrency, and result ordering.
Abort peer fetches and wait for their response bodies to close when one verified source fails or the caller cancels. Validate and snapshot the full manifest before I/O, keep decoded bytes as the size authority, redact source queries from loader errors, and reject noncanonical URL fragments. Cover the contract with focused host tests and a real Chromium transport test for gzip decoding, omitted credentials, redirects, bounded streams, stream failure, and caller abort.
Bind each VFS Formula ordinary dependency closure to a fixed, URL-free manifest and rootfs payload inside its keg. Validate canonical payload ownership and preflight selected layers before the existing atomic runtime-layer consumer sees them. Deduplicate a shared dependency only when both layers resolve the exact same immutable bottle, link projection, and provenance. Record the remaining direct-bottle versus derived-rootfs transport choice without claiming publication or browser support.
Regenerate the authoritative program-package projection once after replaying the packaging, lazy package-tree, and bottle-owned VFS layer work onto the exact post-#1078 package-generation head. This keeps every consumer bound to the same complete source graph instead of preserving intermediate cache identities from the prior stacked branches.
Allocate every top-level process, fork child, spawn child, and pthread TID from one monotonic Rust ProcessTable sequence. Remove host-selected identity APIs, validate exact task/channel bindings, and make process/thread identity construction capability-based. Bump the incompatible host/kernel contract to ABI 42, update libc fork-child state, host adapters, package harnesses, generated ABI evidence, documentation, and Node/browser regression coverage.
Replace the fixed fork continuation capacity with ABI 42 linked, page-backed frame chunks shared across main-process, pthread, browser, Node, and dynamic-linker paths. Preserve truthful fatal cleanup on allocation failure for now and document recoverable ABORT_UNWINDING as the next POSIX-correct step.
Add ABI 42 ABORT_UNWINDING replay so a failed linked-frame allocation reconstructs committed inner frames, releases continuation ownership, and returns the original errno without terminating the process. Negative SYS_FORK results now use the complete parent rewind path as well. Main, pthread, and supported dynamic-side-module paths share the recovery contract; integrity and cleanup failures remain fatal. The P-10 stress fixture grows from 52,052 to 58,370 instrumented bytes (+6,318, +12.14%); runtime performance was not measured. The instrumenter suite, focused host/V8 suite, host build, and ABI consistency check pass. Browser validation was attempted but blocked by 35 missing package assets; the broader host suite also remains blocked by missing wasm64/sysroot and stale package artifacts.
Route main-process, pthread, and side-module begin exports through one pointer-width-aware boundary. V8 requires BigInt for wasm64 i64 arguments even when the address fits in a Number, so a shared helper prevents host paths from drifting. Exercise real i32 and i64 WebAssembly exports and make the abort-unwind fixture independent of the caller's working directory.
…ctory tests Update fork, spawn, procfs, and directory-cookie fixtures to obtain their process identities from ProcessTable and call the caller-validating APIs. This keeps the unit suite aligned with ABI 42 instead of reintroducing caller-selected PID shortcuts.
A new ABI needs matching bottles before the bottle-backed shell can validate, but normal publication from main creates a dependency cycle. Permit only an exact reviewed Kandelo SHA on the write path while keeping mutable branches forbidden. Document the merge-preservation and immediate pin-rotation contract, cover accepted and rejected ref shapes, and refresh the sealed publisher plan digest.
Preserve the exact 63-Formula wasm32 levels, seven-target wasm64 chain, one-Formula failure isolation, and Python VFS acceptance gate in the living migration plan. Include build and test edges so the operator does not dispatch a Formula before every target bottle it will pour is available.
Reject overlapping chunk ranges before an attached chain can own or release them. Require the replay tail to agree with stored frame bytes on child attachment, parent replay, and allocation-abort replay while keeping zero-frame aborts valid.
Share one width-aware JavaScript/WebAssembly pointer normalizer across worker imports and fork continuations. Preserve signed memory32 high-bit addresses, require exact BigInt memory64 values, and prove each replay predecessor is adjacent before exposing the current frame.
Refresh every affected composite-package cache key after the final host runtime and lazy-VFS inputs changed. This keeps the committed resolver projection source-current so final staging builds the exact reviewed ABI 42 tree instead of rejecting stale generated identities.
The canonical shell already embeds Homebrew Bash and registers the remaining 39 bottles as independent first-use trees. Remove stale candidate/later wording and document the current 36-root, 42-Formula composition without changing runtime inputs.
Keep the registry source recipe aligned with the Homebrew bottle recipe by compiling programmable-completion builtins. Stock brew restores and enumerates these builtins on every invocation, so a source-built fallback must expose the same shell contract as the published bottle.
The shared lazy-tree runtime is a declared input to VFS-producing package builds. Refresh the atomic projection so staging rebuilds those images and their reverse dependents instead of reusing identities from the pre-retry host runtime.
brandonpayton
force-pushed
the
emdash/homebrew-abi42-generation-qk044
branch
from
July 24, 2026 03:23
ff29a9f to
74ded46
Compare
brandonpayton
marked this pull request as ready for review
July 24, 2026 03:23
The standalone resolver is used by package and bottle workflows that do not execute the TypeScript source directly. Leaving it stale makes those consumers run older provenance and closure rules even though the reviewed source has changed. Regenerate the committed bundle with the canonical build script so direct TypeScript consumers and standalone packaging consumers enforce the same resolver contract.
brandonpayton
added a commit
that referenced
this pull request
Jul 24, 2026
…1080) ## Why Some packaging releases must keep one exact reviewed pull-request commit reachable after the pull request merges. For example, the ABI 42 Homebrew publisher and bottle catalog are pinned to one exact commit. A squash or rebase merge rewrites that identity, but the current merge-candidate activation protocol rejects merge commits. That would leave us with a bad choice: lose the pinned commit or merge successfully and then fail the canonical package activation. This adds one narrow, fail-closed merge mode for that situation. It does not change the default: ordinary pull requests still squash, and `batched-changes` pull requests still rebase. ## What changed - Add a `preserve-head-commit` history mode to Prepare merge. - Require its final merge commit to have exactly the prepared base and reviewed pull-request head as its ordered parents. - Continue requiring the merged tree to equal the tree that Prepare merge tested. - Reject a pull request that carries both `batched-changes` and `preserve-head-commit` before creating a candidate. - Document the bounded repository-settings window: merge commits may remain disabled except while an approved preserve-head merge is performed. ## Validation - `bash scripts/dev-shell.sh bash .github/scripts/test-verify-merge-candidate.sh` - `bash scripts/dev-shell.sh bash .github/scripts/test-init-merge-candidate.sh` - `bash scripts/dev-shell.sh bash .github/scripts/test-merge-candidate-workflows.sh` - `bash scripts/dev-shell.sh ruby -e 'require "yaml"; YAML.parse_file(".github/workflows/prepare-merge.yml")'` - `bash -n` for every changed shell script - `git diff --check` All listed checks passed. `actionlint` was not run because it is not declared in the repository dev shell; the repository's merge-candidate workflow contract suite and a YAML parse were run instead. ## Scope This changes CI/package-release history validation only. It does not change the kernel, ABI, runtime behavior, package bytes, or the frozen head of PR #1079.
This was referenced Jul 24, 2026
This was referenced Jul 28, 2026
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
The remaining Homebrew work changes both package artifacts and Kandelo's
process ABI. Publishing the package changes under ABI 41 would create bottles
that the ABI 42 kernel cannot use. Landing ABI 42 before its replacement
bottles exist would leave the shell without a complete package generation.
This PR therefore prepares one exact, verified ABI 42 source revision. The tap
will publish bottles from that frozen revision before the revision is merged,
and the merge will preserve it in
mainhistory.What changes
brewprogram through Kandelo's normal package resolver.This proves the guest bytes and makes them available for lazy activation; it
does not make
/usr/bin/breweager in the base shell.bottle recipe because stock
brewrestores and enumerates those builtins.can run offline after setup.
used by bottle workflows, rather than leaving those consumers on stale
generated code.
across Node.js and browsers.
while permanent HTTP, size, digest, decode, and inventory failures remain
fail-closed.
thread identifiers.
recoverable storage and validates its complete linked structure.
artifacts.
consumption all refer to one generation.
Why one PR
These edits form one release boundary. Splitting them would either publish
packages against an ABI that is about to disappear or leave the ABI 42 kernel
unable to consume its package generation. The commits remain purpose-scoped
even though the release unit is combined.
Publication and merge sequence
benchmarks, then freeze it.
dependency waves.
remains an ancestor of
main.mainform.This avoids both halves of the release cycle: ABI 42 code without bottles and
ABI 42 bottles whose source revision is absent from repository history.
Validation
Exact final evidence will replace this paragraph after the frozen candidate's
GitHub checks, full conformance suites, Node.js and Chromium shell proof, and
seven-suite Node.js/Chromium benchmark comparison complete.
What follows
Once the ABI 42 catalog is public, the immediate follow-up switches the main
shell to a mostly-lazy bottle-composed image: the always-needed shell remains
materialized, while optional programs and language runtimes activate from
their package-owned bottle layers on first use. A lazy in-guest
brewlifecycle and third-party tap workflow follow on the same foundation.