Skip to content

[Homebrew/ABI] Prepare one verified ABI 42 package generation - #1079

Merged
62 commits merged into
mainfrom
emdash/homebrew-abi42-generation-qk044
Jul 24, 2026
Merged

[Homebrew/ABI] Prepare one verified ABI 42 package generation#1079
62 commits merged into
mainfrom
emdash/homebrew-abi42-generation-qk044

Conversation

@brandonpayton

@brandonpayton brandonpayton commented Jul 23, 2026

Copy link
Copy Markdown
Member

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 main history.

What changes

  • Packages the guest brew program through Kandelo's normal package resolver.
    This proves the guest bytes and makes them available for lazy activation; it
    does not make /usr/bin/brew eager in the base shell.
  • Keeps source-built Bash's programmable-completion builtins aligned with the
    bottle recipe because stock brew restores and enumerates those builtins.
  • Models publisher-only tools as Homebrew Requirements and proves the publisher
    can run offline after setup.
  • Ships the same verified package-resolution rules in the standalone bundle
    used by bottle workflows, rather than leaving those consumers on stale
    generated code.
  • Refuses incomplete or unsafe VFS artifacts before publication.
  • Gives lazy and eager VFS images one verified package-tree implementation
    across Node.js and browsers.
  • Retries only temporary lazy-tree transport failures with bounded backoff,
    while permanent HTTP, size, digest, decode, and inventory failures remain
    fail-closed.
  • Defines a bounded, bottle-owned VFS layer contract for composable images.
  • Makes the kernel process table the only authority that allocates process and
    thread identifiers.
  • Replaces the fixed fork-continuation buffer with dynamically sized,
    recoverable storage and validates its complete linked structure.
  • Advances the ABI to 42 and rejects stale or structurally incomplete ABI 42
    artifacts.
  • Refreshes affected package identities together so staging, publication, and
    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

  1. Prove this exact PR head in staging, conformance, browser validation, and
    benchmarks, then freeze it.
  2. Pin the public tap's publisher and trust checks to that immutable SHA.
  3. Publish and anonymously verify the complete ABI 42 bottle graph in
    dependency waves.
  4. Validate the bottle-composed shell against those public artifacts.
  5. Merge this exact SHA with a merge commit so the published source revision
    remains an ancestor of main.
  6. Return tap workflow pins to their normal landed-main form.

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 brew
lifecycle and third-party tap workflow follow on the same foundation.

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Phase B-1 matrix build status — pr-1079-staging

ABI v42. 68 built, 8 failed, 76 total.

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
brandonpayton force-pushed the emdash/homebrew-abi42-generation-qk044 branch from ff29a9f to 74ded46 Compare July 24, 2026 03:23
@brandonpayton
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.
@brandonpayton brandonpayton closed this pull request by merging all changes into main in a57cc2a Jul 24, 2026
@brandonpayton
brandonpayton deleted the emdash/homebrew-abi42-generation-qk044 branch July 24, 2026 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant