NextBSD: executing the releng/15.1 bump & drm-kmod 6.12
The per-repo runbook for issues #336 (base 15.0→15.1) and #337 (graphics kexts 6.6→6.12 + firmware) — from a six-agent scope of the whole build chain, June 2026.
1. The four headline findings (verified during scoping)
2. The build chain & dispatch topology
Six repos, wired by repository_dispatch. The bump must propagate in dependency order; each arrow is an automatic cross-repo dispatch (on a real upstream change, not PRs). Your manual checkpoint sits right after the sync.
freebsd-src (fork) sync-fork.yml ──upstream-updated──▶ toolchain
releng/15.1 │
▲ ├──toolchain-updated──▶ nextbsd-kernel
[YOU VERIFY HERE] └──toolchain-updated──▶ nextbsd-freebsd-compat
│ │
nextbsd-kernel ──kernel-updated──▶ nextbsd-kernel-modules │ │
│ publishes kernel-obj + nextbsd-kernel to ◀── continuous ──┐ │ │
▼ │ ▼ ▼
(continuous: kernel-obj-*.tar.gz, nextbsd-kernel-*.tar.gz) (continuous: graphics-kexts.tar.gz) (continuous: nextbsd-base-*.tar.gz)
└──────────────────────────────┬───────────────────────────────────────────┬───────────────────────┘
▼ base-updated / latest-continuous pull
nextbsd (ISO assembler) ── boot-test ──▶ image
Note the toolchain fans out to both nextbsd-kernel and nextbsd-freebsd-compat in parallel. The ISO repo pulls all three upstream artifacts (kernel, modules, compat) from their rolling continuous tags — no pins — so 15.1 artifacts flow in automatically once published.
3. Per-repo scope
Pills mark which ticket each edit serves: #336 base bump, #337 drm 6.12. “Decoy” = a FREEBSD_BRANCH env that looks like the pin but is never dereferenced (the real source version arrives baked in the toolchain image).
3.1 nextbsd-redux/freebsd-src — the sync fork #336
Pure upstream mirror, no NextBSD-local commits on the releng branches (confirmed: fork releng/15.0 is byte-identical to upstream; this upholds the “never touch freebsd-src” rule). releng/15.1 already exists in the fork but is stale — sitting at 15.1-RC2, ~18 commits behind upstream releng/15.1 HEAD (96841ea0, 2026-06-12). The sync is fast-forward-only (GitHub merge-upstream API), so it cannot lose work or force-push.
| File:line | Now | Edit |
|---|---|---|
sync-fork.yml:20 | ref: releng/15.0 | → 15.1 |
sync-fork.yml:28 | gh repo sync --branch releng/15.0 | → 15.1 |
sync-fork.yml:35 | git fetch origin releng/15.0 | → 15.1 |
sync-fork.yml:36 | git rev-parse origin/releng/15.0 | → 15.1 |
sync-fork.yml:50 | client_payload[branch]=releng/15.0 | → 15.1 (dispatch to toolchain) |
sync-fork.yml:9 | comment “operates exclusively on releng/15.0” | → 15.1 (cosmetic) |
A global releng/15.0→releng/15.1 replace in this one file is correct (0 other refs anywhere in the repo). Decision for you: replace 15.0 entirely (clean bump, the issue’s intent) vs. sync both branches through a transition window.
3.2 nextbsd-redux/nextbsd-kernel-toolchain — the container #336
Clones the fork at ${FREEBSD_BRANCH} into /usr/src and bakes a kernel-toolchain stage; the GHCR image is the source artifact downstream builds inside. This is the first repo to actually change after the fork. Clang/LLVM stays 19 for 15.1 (both cut from stable/15) — do not bump it. __FreeBSD_version is not baked here; it rides in the cloned tree.
| File:line | Edit |
|---|---|
build-toolchain.yml:19 | FREEBSD_BRANCH: releng/15.0 → 15.1 (the value CI uses; flows to build-args at :88) |
Dockerfile.amd64:5 | ARG FREEBSD_BRANCH=releng/15.0 → 15.1 |
Dockerfile.arm64:5 | ARG FREEBSD_BRANCH=releng/15.0 → 15.1 |
README.md:7 / Dockerfile.*:12 | doc/comment “15.0”/“Clang 19” wording (cosmetic) |
3.3 nextbsd-redux/nextbsd-kernel — patches + config + overlay #336 #337
The small patch repo (not a source fork). Corrected headline (§1.1, §7.5): 5 of 7 patches are clean on 15.1; 0001 and 0004 needed a mechanical rebase. The FREEBSD_BRANCH env here is a decoy (never read — the branch lives in the toolchain Dockerfiles).
| Patch | Target(s) | 15.1 risk |
|---|---|---|
0001 widen lkmnosys band | syscalls.master | DRIFTED — 15.1 added base syscalls 599–602; band shifted 599–646 → 603–650 (PR #47); make sysent regenerates companions |
0002 newbus quiesce hook | subr_bus.c, eventhandler.h | Very low — both identical |
0003 reserve EVFILT_MACHPORT | sys/event.h | None — 15.1 still SYSCOUNT 15; clean |
0004 firmware_path raw search | subr_firmware.c | DRIFTED — 15.1 fixed the inverted warn bool at :284; removed-line context updated to (flags & FIRMWARE_GET_NOWARN) == 0 (PR #47); 91-line refactor hunk already clean |
0005 coredumps off | kern_ucoredump.c | None — one-liner |
0006 unionfs rename dir target | union_vnops.c | Low — hand-authored zero-index hunk; identical tree |
0007 unionfs tagged fileid | union_vnops.c, union.h | Low — large; disjoint hunks from 0006; order matters (0006→0007) |
Edits: build.yml:15 FREEBSD_BRANCH→15.1 (decoy, cosmetic) and build.yml:323 vmactions release: '15.0'→'15.1' (real — the smoke-test VM that md-mounts/injects the kernel; keep aligned for KBI hygiene). The build also appends mach_knote_enqueue to stock kern_event.c at build.yml:135 — depends on knote_enqueue staying static-callable (kqueue unchanged on 15.1, low risk). Verify config(8) accepts every config/NEXTBSD device name (em, ig4, ietp, iichid, the h* HID leaves) against 15.1’s GENERIC on the first build.
If 6.12 had needed a new baked dep (it does not — §1.2): config-level deps go next to the graphics block at config/NEXTBSD:41-42; an option-less helper module mirrors files.linuxkpi_video (new src-overlay/conf/files.<mod> + a cat >> conf/files wire-in step). Kept here for the record.
3.4 nextbsd-redux/nextbsd-kernel-modules — where both tickets land #336 #337
The repo that builds the graphics kexts. The DRM version lives in exactly one literal; the 15.1-ness arrives via the ingested kernel-obj, not a local pin.
| File:line | Edit | Ticket |
|---|---|---|
build.yml:28 | FREEBSD_BRANCH: releng/15.0 → 15.1 — the load-bearing pin; drives the release-notes string | #336 |
build.yml:225 | --branch 6.6-lts → 6.12-lts — the single DRM literal (no submodule/var) | #337 |
build.yml:454, 621, 674 | FW_TAG=20260519 → newer linux-firmware tag — three un-shared copies, edit all (boot-test sample / iwlwifi kext / graphics kexts) or they desync | #337 |
build.yml:223, 186-187 | step name + comments “6.6-lts … drm-66-kmod … releng/15.0” (cosmetic) | both |
build.yml:530 | vmactions release: '15.0' (host VM for UFS inject) → '15.1' optional/availability only | #336 |
tools/gen-i915-personalities.sh:47 | REWRITE the ID regex — see below | #337 |
Firmware size: bundling is whole-vendor cp -RL (build.yml:687), no per-GPU subsetting; amdgpu alone is “hundreds of MB” (the workflow says so at :663) and a newer FW_TAG only grows it, inflating graphics-kexts.tar.gz and the ISO. Subsetting to matched ASICs, or splitting firmware into a non-ISO asset, is a design change — out of scope for the one-line flip but flagged.
3.5 nextbsd-redux/nextbsd-freebsd-compat — the curated base #336
The FREEBSD_BRANCH: releng/15.0 at build.yml:18 is vestigial (never dereferenced; /usr/src comes baked in the toolchain image). So there is no load-bearing pin here — but this repo carries the migration’s sharpest runtime-not-CI risks:
- Lever B is the #1 silent failure. The
-DSTANDARD_LIBRARY_PATHappend (build.yml:101-104, scoped via.if ${.CURDIR:M*/libexec/rtld-elf}) is what puts/System/Library/Libraries+/usr/local/libon rtld’s compiled-in path. If 15.1 renames the macro or moves the rtld dir, it compiles clean and silently produces a stock rtld — the whole GNUstep desktop stops resolving libs. Verify post-build:strings .../ld-elf.so.1 | grep -F '/System/Library/Libraries'. (There is no ldconfig boot job to fall back on, by design.) - krb5 closure is the most fragile compile. The build leans on 15.0 specifics:
MK_KERBEROS=no/MK_MITKRB5defaults, thecompile_etheader-staging dance (build.yml:128-164), and thelibkrb5.so.122soname. A 15.1 MIT-krb5 bump orMK_*flip needsKRBFLAGS/staging rework, and downstreamcurl/git/pkglinkage re-pointed. - C++ trio vs ports clang.
libc++/libcxxrt/libcompiler_rtassume “matches ports clang 19” (srclist.txt:50-55). If 15.1 ships libc++ 20, revisit that invariant. - libc / libthr / rtld must move as a unit — shared private
__libc_interposing[]table; never mix 15.1 rtld/libthr with 15.0 libc. - No-clobber-Apple-libs. A new transitive
DT_NEEDEDin any 15.1 component could stage a FreeBSD lib that shadows an Apple-provided one. Diff the 15.1/stagelib set vs the Apple inventory onroot@1/root@2before shipping. Reconcile the setuid re-apply guard (build.yml:209) against srclist setuid entries.
Edits: build.yml:18 → 15.1 (documentary) + comment refresh (build.yml:130,223, srclist.txt:53,185,240,242). The substance is the post-build verification list above, gated before the continuous cascade to the ISO.
3.6 nextbsd-redux/nextbsd — the ISO assembler #336
Net: near-zero substantive change. Pure “latest continuous” pass-through — base, kernel, and kexts are pulled by version-agnostic patterns, so 15.1 artifacts flow in the moment upstream publishes them. PKG_ABI is FreeBSD:${MAJOR}:${ARCH} (build.sh:31) → FreeBSD:15:amd64 for all 15.x — must not be hardcoded to a minor. The image’s displayed identity is a build timestamp, not a FreeBSD version. IGNORE_OSVERSION=yes everywhere means a 15.0 build host can run a 15.1 assembly — but see the correction in §7.1: the build VM also gap-fills the rootfs with its own binaries, so its release does end up in the shipped image. The matrix bump below is required, not optional.
| File:line | Verdict |
|---|---|
build.sh:31 PKG_ABI=FreeBSD:15:amd64 | KEEP — ABI-stable, derived by stripping minor |
build.sh:652 grep 'releng/15.0' (non-fatal diagnostic) | Bump to 15.1 or generalise to releng/15 — cosmetic, else the print goes silent |
build.yml:100-102,280-281,398-399 matrix freebsd:'15.0' + variant:'15.0-RELEASE' | REQUIRED (not optional — correction, §7.1) — the VM gap-fills the rootfs, so it must be 15.1. 15.1-RELEASE is on vmactions/the mirror. Bump both; also drop the version from the job name: labels (PR #341) |
tests/boot-test.sh | Recommend ADD a sysctl kern.osreldate ≥ 1500509 assertion — the acceptance floor is gated nowhere today |
3.7 Deep dive: the i915 6.12 personality generator fix #337
An empty match table is a non-shipper, so this gets its own fully-scoped fix. The breakage, the trap, and the implementation:
What broke. tools/gen-i915-personalities.sh:48-52 extracts IDs with
grep -oE 'INTEL_VGA_DEVICE\(0x[0-9A-Fa-f]+' over i915_pciids.h. On 6.12 that header has zero such literal rows — IDs moved into MACRO__(0x….) entries inside per-platform INTEL_<PLAT>_IDS(MACRO__, …) macros — so IDS is empty and the script trips its own [ -n "$IDS" ] guard. The output contract it must preserve: an IOKitPersonalities dict whose IOPCIPrimaryMatch is space-separated 0x<device><vendor> words (e.g. 0x59168086), vendor hardcoded 8086, IOProbeScore=10000. Consumed verbatim by ko2kext.sh -p into the kext Info.plist.
The fix — let the C preprocessor expand the driver’s own list. Redefine the INTEL_VGA_DEVICE callback to emit a tagged id, replay i915_pci.c’s INTEL_<PLAT>_IDS(INTEL_VGA_DEVICE, …) rows, and scrape. This resolves all nesting (MTL→ARL) for free, auto-excludes anything not in pciidlist, and tracks future drm-kmod bumps. The generator takes a new i915_pci.c arg; only the extraction block changes, output stays byte-identical:
REFS=$(grep -E 'INTEL_[A-Z0-9_]+_IDS[[:space:]]*\(INTEL_VGA_DEVICE' "$PCI_C" | sed -E 's@/\*.*@@')
IDS=$(
{
printf '#include "%s"\n' "$SRC"
printf '#undef INTEL_VGA_DEVICE\n'
printf '#define INTEL_VGA_DEVICE(id, info) @@id@@\n'
printf 'int nbkm_i915_ids[] = {\n%s\n};\n' "$REFS"
} | "${CC:-cc}" -E -P -xc - 2>/dev/null \
| grep -oE '@@0x[0-9A-Fa-f]+@@' | grep -oE '0x[0-9A-Fa-f]+' \
| tr 'A-F' 'a-f' | sort -u
)
[ -n "$IDS" ] || { echo "i915 pciidlist expansion produced no ids" >&2; exit 1; }
The host runner (drm-kmod job, build.yml:271) has cc/clang; the header is self-contained (no -I needed). The build step gains a locator and passes it — and tighten the find to the moved path:
I915H=$(find /tmp/drm-kmod -path '*drm/intel/i915_pciids.h' | head -1) I915C=$(find /tmp/drm-kmod -path '*gpu/drm/i915/i915_pci.c' | head -1) "$T/gen-i915-personalities.sh" "$I915H" "$I915C" org.nextbsd.kext.intelgraphics IntelGraphics > pers/IntelGraphics.iokitpersonalities
CI gate — close the hole that hid this. The current selftest (tests/personalities-selftest.sh) feeds the generator a synthetic old-form INTEL_VGA_DEVICE(0x….) fixture, so it would have stayed green against the real 6.12 break. Three layers:
- Update the fixture to 6.12 shape (a
MACRO__(0x…)header + a tinyi915_pci.cstub), asserting MTL→ARL expansion lands and anxe-only id does not. - Real-source count band after generation:
N=$(grep -oE '0x[0-9a-f]{8}' pers/IntelGraphics.iokitpersonalities | sort -u | wc -l); [ "$N" -ge 300 ] && [ "$N" -le 450 ](~364 expected). This alone would have caught the empty table. - Driver cross-check in the FreeBSD VM (
build.yml:528+):kldxref/pnpinfothe builti915kms.ko(itsLKPI_PNP_INFOtable), normalise to0x<dev>8086, and assert set-equality with the generated match words — ground-truth parity that fails loudly on any future header drift.
Fallback if a compiler is ever absent: a pure-shell recursive macro-expansion seeded from the pciidlist macro names (must replicate the preprocessor’s fixpoint nesting — more fragile, kept only as a backstop). When NextBSD later adds an xe kext, LNL/BMG/standalone-ARL get their own generator off xe’s pciidlist — not this one.
4. Ordered runbook
Follow the dependency chain. Each step has a gate — do not cascade until it’s green.
Step 0 — Sync the fork to 15.1 #336
Edit sync-fork.yml (§3.1, five literals), merge to main, run via workflow_dispatch. First run fast-forwards releng/15.1 from RC2 to upstream HEAD and will cascade a full rebuild — expected.
Step 1 — [YOUR MANUAL CHECKPOINT] Verify the 15.1 source is current
gh api "repos/nextbsd-redux/freebsd-src/compare/freebsd:releng%2F15.1...nextbsd-redux:releng%2F15.1" \
--jq '{status, ahead_by, behind_by}' # expect {"status":"identical","ahead_by":0,"behind_by":0}
gh api repos/nextbsd-redux/freebsd-src/contents/sys/sys/param.h?ref=releng/15.1 \
--jq '.content' | base64 -d | grep __FreeBSD_version # expect 1501000 (≥ 1500509)
You asked to do this yourself — this is the gate before anything downstream builds on 15.1.
Step 2 — Rebuild the toolchain image #336
Edit the 4 FREEBSD_BRANCH pins (§3.2), merge. Gate: a PR build first (PRs never publish) to smoke-test the 15.1 clone + kernel-toolchain stage before it pushes :latest and dispatches downstream. Confirm clang stays 19.
Step 3 — Rebuild the kernel on 15.1 #336
Edit build.yml:15 (decoy) + :323 (smoke-test VM). Gate: git apply of all 7 patches succeeds (expected clean per §1.1); config(8) accepts every NEXTBSD device; buildkernel green; boot-smoke-test passes. The kernel publishes kernel-obj-* + nextbsd-kernel-* to continuous and dispatches modules.
Step 4 — Rebuild the curated base on 15.1 #336
(Runs in parallel with Step 3 — toolchain dispatches both.) After build: verify Lever B (strings ld-elf.so.1 | grep /System/Library/Libraries), confirm krb5 soname/flags, diff /stage libs vs Apple inventory for clobbers, reconcile the setuid guard. Do not let continuous cascade to the ISO until these pass.
Step 5 — Bump graphics kexts to 6.12 + firmware #337
Now on a 15.1 kernel-obj: flip build.yml:225 to 6.12-lts, bump all three FW_TAG copies, and rewrite gen-i915-personalities.sh per the implementation-ready diff in §3.7 (preprocessor-driven, 364 IDs). Gates: required .ko set still produced (i915kms/amdgpu/radeonkms); i915 ID count is non-zero and matches kldxref; OSBundleLibraries chain still valid (no new drm.ko dep, per §1.2). Watch graphics-kexts.tar.gz size.
Step 6 — Assemble & boot-test the ISO #336 #337
15.1 artifacts flow in automatically. Optional: bump build.sh:652 diagnostic; add the kern.osreldate assertion to boot-test.sh. Final acceptance: boot the image, sysctl kern.osreldate ≥ 1500509 (expect 1501000), launchd/kexts/networking up, a supported GPU brings up KMS against the 6.12 drm.ko, pkg install still works (FreeBSD:15:amd64).
5. Risk register (ranked)
| # | Risk | Where | Surfaces | Mitigation |
|---|---|---|---|---|
| 1 | i915 generator extracts 0 IDs on 6.12 (old regex form gone) | modules gen-i915-*.sh:48-52 | Build — generate step exit 1s on the empty set (blocks #337; selftest stays green on its synthetic fixture) | §3.7: preprocessor rewrite off pciidlist (364 IDs); count-band + kldxref parity gate |
| 2 | Lever B silently drops /System/Library/Libraries | compat build.yml:101-104 | Runtime (desktop can’t load libs) | strings ld-elf.so.1 | grep post-build |
| 3 | New 6.12 MODULE_DEPEND not baked | kernel config / modules | Kext load on real HW | Resolved — 6.12 drm.ko adds no new dep (§1.2) |
| 4 | krb5 closure fails to compile on 15.1 | compat build.yml:128-164 | Build | Re-check soname/MK_*; adjust KRBFLAGS |
| 5 | Toolchain tag skew (no 15.x marker) | toolchain GHCR tags | Silent 15.0 carry-over | Confirm downstream reads dispatch payload, not literal tags |
| 6 | Firmware bloat inflates ISO | modules build.yml:687 | ISO size | Per-ASIC subset or split FW asset (design change) |
| 7 | Graphics kexts not load-tested in CI | modules smoke-test | Boot only | Add graphics-kext load test |
| 8 | No osreldate floor gate in CI | nextbsd boot-test.sh | — | Add sysctl kern.osreldate assertion |
| 9 | Build VM gap-fill ships stale 15.0 userland binaries (init, uname, freebsd-version) onto a 15.1 kernel | nextbsd build.sh:~202 + matrix freebsd:'15.0' | Runtime — CI green, but booted image shows uname -U 15.0 vs uname -K 15.1 | Bump matrix VM to 15.1 (§7.1, PR #341); verify uname -U == uname -K == 1501000 on a booted image |
6. Acceptance — mapped to the tickets
- #336 Full chain (toolchain→kernel→modules→compat→ISO) builds green on
releng/15.1; booted image reportskern.osreldate ≥ 1500509; launchd boot, kexts (incl. graphics 6.6 pre-#337), networking still work;pkg installworks (FreeBSD:15:amd64). - #337 On the 15.1 image,
IOGraphics/IntelGraphics/AMDGraphics/RadeonGraphicsload against the 6.12drm.ko, firmware is found, and a supported GPU brings up KMS. (Reminder from the decision plan: 6.12 still has no Intelxe— Lunar Lake / Battlemage stay unsupported.)
7. Execution addendum — corrections & extra steps from the live bump (20 June 2026)
The bump was executed end-to-end on 20 June 2026 (kernel PR #47, compat PR #27, ISO-matrix PR #341). Four findings corrected or extended the scoping above — including a wrong “zero patch drift” prediction (§7.5) — recorded here so the next minor bump (15.1→15.2) is mechanical.
7.1 The build VM is a load-bearing source — the matrix bump is REQUIRED, not optional
§3.6 originally rated the matrix.freebsd:'15.0' pin “optional, build-host only.” That was wrong. build.sh (~line 202) gap-fills the rootfs from the VM’s /bin /sbin /usr/bin with cp -RpPn (no-clobber) for everything the curated from-source base omits — which includes init, uname, and freebsd-version (the last removed from the base in #300). So a 15.0 VM bakes 15.0 userland binaries into a 15.1 image.
Fix: bump matrix.freebsd 15.0→15.1 and variant 15.0-RELEASE→15.1-RELEASE in all three matrix blocks (PR #341). The plan’s “only if vmactions offers a 15.1 image” conditional is resolved: 15.1-RELEASE is present on the mirror (.../releases/amd64/15.1-RELEASE/base.txz → HTTP 200) and accepted by vmactions/freebsd-vm. The job name: labels were also made version-agnostic (build (${{ matrix.arch }})) so they stop drifting each bump — variant still drives the distfiles cache key + FREEBSD_VARIANT.
7.2 workflow_dispatch builds but never publishes/cascades — use repository_dispatch
Every repo gates its publish-to-continuous and downstream cascade on github.event_name == 'push' || 'repository_dispatch' — never workflow_dispatch. So a manual run (or a PR merge in a repo with no push trigger) builds and validates but leaves continuous stale. This bit the bump three times before it was understood.
| Repo | Publishes on | To actually publish/cascade after a manual change |
|---|---|---|
nextbsd-kernel | push to main publishes continuous; module cascade only on repository_dispatch | merge cascades publish; for the full chain, dispatch the toolchain |
nextbsd-freebsd-compat | publish gates only on ref==main (so workflow_dispatch on main does publish); no push trigger; ISO cascade only on repository_dispatch | workflow_dispatch on main to publish; then base-updated for the ISO |
nextbsd (ISO) | release job excludes workflow_dispatch; no push trigger on the build | gh api repos/nextbsd-redux/nextbsd/dispatches -f event_type=base-updated |
Rule of thumb: a manual dispatch is for validation; a repository_dispatch (or the toolchain re-cascade) is for shipping.
7.3 Cache purge — optional hygiene, not a fix
No cache caused any version skew. ccache is content-addressed (a 15.1 source compile yields 15.1 objects every time — it cannot emit a stale-version binary); the distfiles cache is keyed on variant (build.yml:121), so it auto-invalidates when variant flips to 15.1-RELEASE. The stale binaries came from the VM image, which we don’t cache. For a clean-slate rebuild guarantee only:
for r in nextbsd-kernel-toolchain nextbsd-kernel nextbsd-kernel-modules nextbsd-freebsd-compat nextbsd; do gh cache delete --all -R nextbsd-redux/$r done # then re-cascade the whole chain from the top: gh workflow run "Build Toolchain Containers" -R nextbsd-redux/nextbsd-kernel-toolchain --ref main
7.4 Verification on a booted image
uname -K==uname -U==1501000(kernel and userland both 15.1) — the single sharpest check; a split here is the §7.1 gap.sysctl kern.osreldate==1501000(the #336 acceptance floor ≥1500509).freebsd-versionis gone (preferred, per #300) or reports 15.1;nextbsd-versionreports the build timestamp.- Not
ldd— it lists a binary’s shared-lib deps, it cannot report kernel version. Useuname -K/kern.osreldate.
7.5 The patch stack did drift — headline §1.1 was wrong
The scoping’s biggest claimed de-risk — “all 7 patch targets byte-identical, zero rebase” — did not hold. It was caught by the live Apply patches CI step failing, then confirmed against a clean releng/15.1 tree. Two of seven patches drifted (PR #47); the other five applied unchanged.
| Patch | What changed in 15.1 | Rebase |
|---|---|---|
0001 lkmnosys band | 15.1 added base syscalls 599 kexec_load, 600 pdrfork, 601 pdwait, 602 renameat2, colliding with the band’s old 599–646 range | Shifted the 48-slot band to 603–650 (first free slot after 602). Safe — mach_syscall_wire.c auto-allocates via NO_SYSCALL; nothing hardcodes the base. make sysent regenerates companions. |
0004 firmware_path | 15.1 fixed an inverted warn bool at subr_firmware.c:284 — the same bug 0004 already corrects (semantic convergence) | Updated the removed-line context to 15.1’s (flags & FIRMWARE_GET_NOWARN) == 0; the 91-line refactor hunk was already clean. |
Lesson: “same last-touch SHA on 15.0” does not imply identical on 15.1 — a releng minor can touch any file. The reliable gate is the Apply patches CI step itself (strict + cumulative, in order), not a pre-scan of file SHAs. Both edits were mechanical (no new logic), so the “minimal patch authoring” spirit held even though “zero” did not.
Sources & method
Scope produced by six parallel read-only agents over the NextBSD build chain (June 2026), each reporting file:line edits, rebase risk, and runtime-vs-CI failure surfaces. Cross-repo facts verified directly against GitHub:
- Patch-stack parity: last-touch commit SHAs of all 7 target files identical on
nextbsd-redux/freebsd-srcreleng/15.0vsreleng/15.1;__FreeBSD_version1500068vs1501000fromsys/sys/param.h. - drm.ko deps:
MODULE_DEPEND(drmn, …)infreebsd/drm-kmod6.12-ltsdrivers/gpu/drm/drm_os_freebsd.c(01682db0, 2026-06-14). - i915 restructure:
include/drm/intel/i915_pciids.hon6.12-lts—MACRO__(0x….)form,INTEL_<PLAT>_IDS()macros, 0INTEL_VGA_DEVICE(0x….)literals; amdgpuamdgpu_drv.c(308 rows), radeondrm_pciids.h(699 rows). - Decision context: nextbsd-drm612-upgrade-plan.html; tickets #336, #337.