# Holy roadmap ## Current state - [x] Run C99 `holygetiso` from an explicit config through a real x86_64 dual-libc ext4 build. Its ISO passed two QEMU boots with libc removal and cache recovery. A second build selected a noarch package from a pinned, sealed native mirror, installed it with its source ID, embedded the mirror, and passed the same two-boot contract. Both `--export-inputs` bundles passed SHA-256 verification. Portable host-tool export remains open. - [x] Stage an exact package when its native catalog cannot close a dependency, then resolve it with an explicitly added package from another pinned source in holyinstall's frozen set plan. A fixture rejects the root alone, installs both artifacts with their separate source IDs, and checks the installed DB. A full x86_64 ext4 image with two sealed source mirrors passed two QEMU boots; its exported input bundle passed SHA-256 verification. - [x] Prepare additional image packages with the native `holypkg add` resolver in a separate root bound to all pinned mirrors. The image builder copies its selected artifacts with their source IDs, including a unique exact provider from another source. A two-source fixture installs the result with `holyinstall`; no package is installed in the resolver root. A real x86_64 ext4 ISO with only `add fixture:cross-root` selected `other:helper`, passed two QEMU/TCG boots with both libc runtimes removed and restored, and its exported inputs passed SHA-256 verification. Pinned resolver answers now select a source by consumer hash and requirement ID when two catalogs offer the same provider. A three-source fixture rejects the unanswered choice; a second full ISO with the pinned answer passed two QEMU/TCG boots and its exported inputs passed SHA-256 verification. - [x] Fetch pinned bootstrap inputs over HTTPS into an explicit directory, verify SHA-256 before publication, and reject altered cached files. On x86_64, local builds produced musl 1.2.5, static BusyBox 1.37.0, static dinit 0.22.1 and static mdevd 0.1.8.2 packages. BusyBox, dinit and mdevd passed their libc-free chroot fixtures. The complete static-deps source set built musl-static holypkg, holyinstall, holygetiso and holy-init. Static core, foreign archive import, and local recovery after removal of both dynamic libc passed their chroot fixtures. A 7.2.7 x86_64 static-core ISO booted under QEMU/TCG and passed its PID 1, shell, package and installer probes. A second x86_64 ISO with glibc 2.42 and musl 1.2.5 passed QEMU boot and in-guest libc-recovery probes after both runtimes were removed. A persistent ext4 variant passed two QEMU boots, including removal of both libc packages and recovery across reboot. These local artifacts remain under out/; i686 boot and a published image remain separate gates. - [x] Build i686 musl, glibc, BusyBox, dinit, mdevd and the musl-static Holy binaries. The i686 static client passed the pentium2 QEMU user-mode target test and the libc-free static-core chroot fixture. BusyBox, dinit and mdevd passed their package fixtures. A single x86_64 root ran glibc32, musl32, glibc64 and musl64 probes with threads, pipes and local recovery. i686 kernel boot is still untested in this local build. - [x] Boot the x86_64 live ISO, prepare a blank GPT guest disk in holyinstall, install the target root, then boot the installed disk through BIOS and UEFI under QEMU/TCG. The installed guest checks dinit, holypkg, package repair and local password login; a wrong password is rejected. A separate i686 BIOS install-to-disk gate is recorded below. - [x] Install a static OpenDoas package in the same artifact-approved holyinstall set transaction as the base system. BIOS and UEFI boots authenticate the local account and then run the scoped BusyBox UID command through doas; the PTY probe supplies its password and checks UID 0. The fixture uses a local shadow account and does not cover PAM/NSS or an account menu. ## Package manager - [x] Add a direct `holypkg run SOURCE:PACKAGE -- COMMAND` launcher for an installed executable, with source-slot selection, manifest verification, argv/exit preservation, and manifest-derived private-bin PATH priority. The fixture installs a static executable in a disposable root. An explicit `--view PUBLIC=PRIVATE` bind mounts a package-owned private file or directory over an existing public path of the same type in a private user/mount namespace, then enters the target root. The fixture checks absolute helper lookup, argv, exit status and host path isolation. Automatic private conflict placement, missing public mountpoints and privileged fallback remain open. - [x] Publish a native index generation with an optional Ed25519 signature before switching `current`; verify the exact index bytes and package artifacts against a supplied public key. Signed HTTPS mirrors check the signature before package downloads. Freeze source keys outside the source ID, enforce them during sync and bound catalog reads, and carry them through holygetiso's effective config. Wrong keys and changed signatures fail local fixtures. The signed HTTPS fixture still needs a network-enabled run. - [x] Bind explicit non-native architecture placement decisions to individual selected artifact hashes, the plan and the recovery journal. Preserve host and target in installed state and check output, retain decisions for reused providers, and reject inheritance by new update artifacts. Cached replacements now accept a fresh artifact-scoped decision, including simultaneous setuid approval; recovery checks both journal decisions. Automatic runtime capability detection remains open. - [x] Install direct hardlinks after their regular payload, validate inode groups, restore missing anchors from surviving members, and recover interrupted link creation/removal. Scan ELF facts at every hardlink path and retain hardlinked manual names in documentation bundles. Native pack and manifest generation detect shared inodes, select deterministic anchors and preserve direct links, including forward archive references. External aliases stay outside packages. - [x] Update cached hardlink groups with shared staging inodes, preserve retained anchors, and support content/mode changes, membership changes, anchor moves and splits/merges. Retain group staging links through database publication and validate topology during recovery and cleanup. Reject undeclared inode sharing within installed manifests. - [x] Resolve pacman package version constraints before passing exact candidate identities to libsolv. Preserve the comparator family, apply arch/libc scopes, reject cross-family constraint satisfaction, and validate updates against installed consumer constraints. Run 92 upstream comparison cases and solver / transaction fixtures. The separate Debian comparator covers epoch, tilde and revision. An explicit Holy native comparator covers numeric versions and prereleases. APK and XBPS comparators now also select prepared updates in their own source slots; remaining foreign comparators remain open. - [x] Resolve declared package aliases using their own versions and artifact ABI scopes. Preserve claims and their hash in holy-instance-4, discover installed aliases, and reject updates dropping required capabilities. Read legacy state through verified cached artifacts when alias metadata is needed. Build claims still need dependency resolution support. - [x] Resolve unversioned literal file requirements from verified nondirectory payload paths, including links. Preserve the chosen owner in installed graphs; reject removal that breaks a consumer. Declared file claims alone do not satisfy a requirement. Versioned file requirements and cross-source lookup remain open. - [x] Resolve unversioned bare command requirements from executable payloads in standard bin directories, including links to an executable in the same artifact. Reject claim-only and nonexecutable candidates; retain command edges through installation and removal checks. Custom PATH, shell builtins, versioned command requirements and private launcher mappings remain open. - [x] Build gzip, LZ4, Zstandard, XZ and bzip2 codecs into the static musl client. Verify foreign import and native install/check/remove in a chroot without dynamic libc or external decoders; reject truncated compressed inputs. - [x] Import local pacman binary archives through libarchive into verified native outputs, preserve original artifacts and metadata, classify/split known ELF ABIs, and bind outputs with a conversion receipt. Fixtures cover an actual gzip PKGINFO, links, malformed archives, inactive hooks and data installation. Repository sync, publisher verification, config files, recipe import and full foreign relation/hook/transform installation remain open. - [x] Import local Debian .deb binary archives into native outputs with original ar bytes, control fields and scripts retained. Check ar order, 2.x version headers, optional post-data members, codec suffixes, payload paths, architecture claims and install/check/remove for a data package. Resolve Depends entries including OR alternatives and exact/unversioned Provides claims with Debian version ordering within the deb family. Automatic cross-source discovery probes each branch of a missing OR group; the solver checks branch versions after staging candidates. Pre-Depends and other unsupported relationships stay foreign requirements; conffiles require a decision. Verify listed `control/md5sums` files against the payload before conversion; the original MD5 list is not source authentication. A pinned local or HTTPS APT Packages index with an explicit pin now supports name search, exact package metadata, HTTPS fetch with artifact hash/size checks, and optional .deb import. A Release.gpg path now verifies a user-selected OpenPGP keyring, suite, Valid-Until when present, and signed index hash/size; catalogs keep evidence for rechecking. Registered APT sources now pin an OpenPGP keyring hash; sync-source and source-aware query/fetch check the source-id, URL and key. sync-source binds its catalog under the target database; source queries find that binding by suite, component and index architecture. Explicit --inrelease verifies clearsigned metadata through gpgv and rechecks it on query/fetch. Optional --files fetches a signed Contents index and supports exact path lookup, including source-bound catalogs. Coverage is marked partial; an absent match stays unknown. It remains a hint until the selected payload confirms the file. apt fetch --import --require-file checks the Contents hint and the converted .holy payload before recording a file provider in its fetch receipt. Common sync/search/info/fetch now use the registered APT binding with explicit suite, component and index architecture. An inverted index, automatic candidate fetch, solver integration and full hook integration remain open. - [x] Import local Slackware .txz/.tgz/.tbz/.tlz packages into native outputs. Preserve original bytes, filename identity/build tag, install/ metadata and review-required doinst.sh. Classify mixed x86/x86_64 ELF payloads, reject unsafe archive paths and unknown architecture, and install/check/remove a converted data package. Offline fixtures cover codecs and links; manual imports of Slackware 15.0 aaa_base and which archives passed. Repository discovery, publisher signatures and dependency metadata beyond the archive remain open. - [x] Import local APK v2 binary packages with bounded gzip member parsing. Preserve control files and unverified signatures, check .PKGINFO datahash against the compressed data member, split observed ELF ABIs and keep simple package/SONAME/command dependencies as exact requirements and unsupported expressions as attributed foreign requirements. Offline fixtures cover two/three members, script review, data install, truncated/extra streams and unsafe paths. Manual imports of Alpine v3.22 alpine-baselayout-data 3.7.0-r0 and scdoc 1.11.3-r0 passed. Supported APK v2 version constraints use a family-specific comparator, checked against 841 pairs from apk-tools 2.14.12; unrecognized forms remain foreign requirements. A rootless APKINDEX.tar.gz parser now retains the original signed or unsigned index, publishes a hash-bound local catalog and answers search/info without installation. An Alpine v3.22 main/x86_64 index with 5647 packages passed manual import and lookup. `apk fetch` now retrieves a selected package over HTTPS, checks index size and Q1 control checksum, .PKGINFO identity and datahash, and retains the original with a selection receipt. Local HTTPS fixtures and Alpine scdoc 1.11.3-r0 passed. Registered `type apk` sources now select a named repository for HTTPS index sync. A reviewed digest or explicit acceptance pins the index; fetch can recheck the active source-id and URL. Alpine v3.22 main/x86_64 with 5647 entries and scdoc fetch passed the registered-source path. Sync now binds the catalog to the source/repo in the target database; search, info and fetch can find it by source/repo. The binding detects catalog tampering and survives relocation of a target root. APKINDEX RSA signatures now verify against the registered public-key fingerprint. A `trust require` Alpine v3.22 main index with 5647 packages passed using the key extracted from `alpine-keys` 2.5-r0. That extraction tests signature mechanics; it does not establish the key's out-of-band authenticity. Keyed fetch now verifies the APK package signature over the compressed control member and records its result separately from the index. A signed Alpine scdoc 1.11.3-r0 fetch passed; local HTTPS fixtures reject missing keys, wrong keys and altered package signatures. Local APK import accepts an explicit RSA public key, verifies the package signature, and records algorithm and key fingerprint in each output origin. `apk fetch --import` now converts the verified download into `.holy`, rechecks the package hash and signature, and records the selected index hash and artifact URL in output origin. Optional exact SONAME and file requirements check converted payload claims before the fetch receipt becomes complete. The signed HTTPS fixture installs, checks and removes an associated output in a disposable root. `apk providers soname:NAME` searches a digest-bound inverted index of so: claims as hints; the checked import still decides whether a package really provides the SONAME. `apk fetch-provider` now chooses a unique candidate by SONAME and architecture, verifies its payload, and returns decision-required when the index lists multiple candidates. The general resolver does not invoke this path yet. A native `add SOURCE:PACKAGE` can take `--candidate-local ALIAS=FILE.holy` for an explicitly associated imported output. The shared set resolver and installed graph check it alongside native packages; automatic foreign candidate discovery remains open. Native automatic provider search now skips active foreign source families instead of counting their absent native mirror as unavailable. The common search/info CLI reads bound APK repositories by source alias and optional repo name; APK file coverage still reports unavailable. The common fetch CLI now selects a bound APK artifact by source, version, architecture and repository, with package verification and optional import. The common sync CLI accepts APK sources and a named repository, using the registered signing key and the APK index verifier. Feeding foreign candidates into the general resolver and full relation semantics remain open. - [x] Parse `holy.conf` syntax and reject malformed includes and records. - [x] Plan and atomically apply a source identity registry under the database writer lock. Preserve IDs across alias changes and retain inactive origin history; reject stale, wrong-root and history-dropping plans. Apply consumes the reviewed plan without rereading user includes. Automatic trust enforcement remains open. - [x] Bind explicitly associated local artifacts to active registered source IDs in set plans and installed state. Retain the alias at installation, preserve origin through source deactivation and provider reuse, and validate associations during interrupted-set recovery. Signature evidence, automatic retrieval-origin binding and automatic update selection remain open. - [x] Verify local LZ4-frame `.holy` archives, file manifests, hashes and basic ELF facts. - [x] Read dynamic symbols, binding/visibility and per-symbol GNU versions through libelf, including ELF32/ELF64 without section headers when the hash tables give a symbol count. Preserve weak imports and compatibility/default versions. Symbol lookup order and dependency-provider validation remain open. - [x] Classify static ET_EXEC without dynamic linkage as nolibc; reject unclassified ELF in native package scan rather than trusting a libc label. - [x] Pack a prepared regular-file/dir/symlink/hardlink tree into a verified native `.holy`; reject unlisted inputs and unsupported file types before publication. - [x] Generate a prepared DATA tree's regular-file/dir/symlink/hardlink HOLY/files manifest with numeric ownership and SHA-256; reject unsupported objects. - [x] Stage verified objects in a target-root cache; preview collisions. - [x] Fetch a pinned native `.holy` over HTTPS with certificate checks and a local CA fixture; reject credential-bearing redirect targets before making redirected requests. Signed generation discovery remains open. - [x] Build and seal a local repository catalog; search and fetch its verified objects. - [x] Resolve a restricted local/catalog graph with libsolv; reject unsupported semantics. - [x] Validate every artifact in a proposed complete set, including consumers outside the selected update's dependency graph. Preserve disconnected packages and cycles, reject missing requirements and keep ambiguous provider edges decision-required. Update planning must still supply the proposed installed set and bind it to database generation, source and ownership decisions. - [x] Add observed ELF interpreter, SONAME and strong symbol edges to that graph; reject candidate class/ABI/version/symbol mismatches and expose stable IDs for root provider choices. Unresolved launch scopes report unknown. Literal absolute provider paths now support dynamic set transactions; complete loader contexts remain open. - [x] Export canonical selected artifact/edge records from the resolver; bind the supported install subset to its graph in the plan hash and installed state. Graph integrity checks preserve legacy state compatibility. - [x] Journal installation, check and removal of `linux/nolibc` data and native static ELF artifacts into existing or explicitly declared safe directories. Recovery covers empty aborted installs, completed installs and interrupted removals under documented conditions. - [x] Install relative symlinks with recorded targets and ownership; check, remove and recover them without following the links. Absolute links remain outside the transaction subset. - [x] Query exact installed data-file ownership; report duplicate regular-file claims as conflicts while permitting shared directory entries. - [x] Check one or all installed data manifests against the target root without downloads or repair; report each changed artifact in the all-packages pass. Emit machine-readable pass/fail summaries and per-path findings for this restricted check. - [x] Check direct executable shebang interpreters for local `.holy` payloads inside the target root. Report unresolved `env`, malformed shebangs and interpreter chains as unknown; nested runtime dependencies remain open. - [x] Reject existing directory mode/owner drift before data-only install; report installed directory drift in check without removing shared directories. - [x] Compare installed slots by source-id, name, os, arch and libc. Permit distinct slots with compatible ownership and reject a second active version of one slot. Same-name glibc/musl executables run in the dual-libc chroot fixture. Multiple installed instances of the same artifact remain open. - [x] Expose installed-slot check, manifest files and confirmed removal by SOURCE:PACKAGE. Resolve the recorded source ID through renamed or inactive aliases, require arch/libc selection for ambiguous slots, and keep files available when the live payload drifts. Source-instance fixtures cover the CLI and removal journal path. - [x] Install a resolved cached static/data set with one writer lock, plan hash and generation change; persist reasons/edges, reject referenced-provider removal, and recover completed sets or resume untouched remaining packages after failure. The bootstrap image installs its base through this set engine. - [x] Expose local .holy installation as holypkg add with explicit candidate archives, a displayed set plan, terminal approval or scoped --yes, and decision-required behavior without a terminal. Explicit root-artifact association resolves an active source alias to its immutable ID. Exact-hash CLI decisions permit non-native architecture placement and setuid payloads; the engine retains both in its plan and journal. Remote source lookup and hooks remain outside this local entry point. - [x] Install glibc/musl dynamic sets with explicit interpreter and DT_NEEDED payload paths; execute real fixtures in a disposable x86_64 root. Report broken selected provider files through installed check. Ordinary SONAME search and automatic path conversion still require implementation. - [x] Plan and journal missing-only repair from the verified artifact cache. Preserve changed/partial files, reject stale plans and resume recorded repair after injected write failure. Resolve installed `SOURCE:PACKAGE` for plan and apply; expose exact path ownership through `owner`. General reinstall and config merge remain open. - [x] List native cache objects and require an explicit `cache clean SHA256 --yes` before deleting an unreferenced object. Hold database/cache locks, protect installed instances and hashes retained in transaction records, and reject incomplete transactions. `--accept-unavailable` permits reviewed removal of a referenced object, records its unavailable hash, and later staging clears the marker. Listing reports unavailable objects. Recovery of arbitrary external rollback references remains open. - [x] Discover installed providers through package names and literal ELF paths; scan cached archives of the resulting candidate closure. Reuse intact version-2/3 instances without changing their state, reason, graph or payload. Bind reused state into plans and validate it during interrupted-set recovery. Named loader search, automatic preference ranking and cache-independent discovery remain open. - [x] Report orphan dependency instances by traversing saved edges from explicit roots. Ignore stale edges belonging to removed consumers; detect unreachable cycles and preserve shared providers. The read-only command works without cache artifacts and refuses incomplete, missing-provider or unknown-graph snapshots. - [x] Show one shortest installed dependency path from an explicit root with `why SOURCE:PACKAGE`. Report an unreachable dependency as orphan and reject incomplete or malformed graphs. The source-instance and orphan fixtures cover graph traversal after package removal. - [ ] Complete source-aware installed slots and version families; extend transactions to replacements, complete dynamic-library contexts and grouped removal. The explicit --accept-broken removal path now retains consumers and reports their broken edges; durable completed-transaction decisions remain unfinished. - [ ] Install executable and shared-library payloads with ABI-aware linking, private providers, interpreter handling and explicit conflict decisions. - [x] Accept nonempty HOLY/transform as an immutable provenance record in local solve, single-package planning, set installation and removal. The installer verifies the already transformed payload and does not execute the record. A pacman fixture splits one foreign archive into noarch, x86 and x86_64 outputs, installs all three in one set, checks them and runs both static ELF programs. Cached update with a transform record also passes. Executable hooks and unresolved foreign semantics remain decision gates. - [x] Install, run, check and remove a native static syscall-only ELF fixture; foreign-architecture approval remains open. - [x] Resolve exact unversioned HOLY/deps SONAME records from scanned ET_DYN payloads, reject a forged typed claim, save the selected provider in the installed graph and prevent its removal. A selected foreign dependency now returns decision-required; an unused candidate can carry one without blocking a separate operation. A later set can find and reuse the installed SONAME provider from its cached archive, and a mismatched arch scope cannot reuse it. An unrelated ABI package needs no cache object for this lookup. A later set also discovers installed providers for ELF DT_NEEDED SONAME edges. Indexed installed SONAME lookup remains open. - [x] Install a bare DT_NEEDED SONAME when the consumer has an ordered list of absolute or $ORIGIN-relative RUNPATH/RPATH directories and the chosen provider owns the first existing DIRECTORY/SONAME with matching ABI and required symbol versions. A provider-owned symlink chain to a versioned library is accepted. Cached replacements revalidate every selected SONAME edge. Installed check reads verified target-root ELF files and reports provider, alias or earlier-path shadowing drift. Other loader tokens and default search, cross-package aliases and plugins remain open. - [x] Resolve direct absolute shebangs in native package sets against exact executable ELF paths. Save the selected provider edge, reject unresolved env/malformed scripts, block removal of a needed interpreter, and report installed interpreter drift. Resolve relative symlink chains in the supplied candidate set and protect each selected alias provider. Discover installed alias owners for a later script installation using root-confined lookup, including chains split between installed and new packages. - [ ] Handle hooks, service consent, overrides, general rollback and recovery of each interrupted mutation phase. - [x] Carry config/mutable flags through verified manifests and installed checks; import Debian conffiles as config files, reject invalid declarations, and report changed-config. - [x] Preserve edited config files during a cached update. Bind the observed hash to the reviewed plan, publish incoming bytes as an owned .holy-new, store the raw and local manifests separately, and carry local state through later updates. The fixture checks stale plans, repeat updates, ownership, recovery after interruption, reverse cached update and package removal. Missing-only repair restores PATH.holy-new from the verified archive and rejects a missing preserved public config, whose local bytes are absent from the archive. Explicit config replacement remains open. - [x] Accept an artifact-scoped skip decision for nonempty HOLY/hooks in local set installation. Print hook records before the decision, bind the skip to plan and journal, retain hooks/transform in installed state, report skipped-hook as installed-unconfigured, and cover add/check/remove fixtures. Native postinstall execution is covered below. Editing hooks and handling foreign phases or unknown external effects without explicit retry remain open. - [x] Review and run native postinstall scripts from installed packages in the target root with an interpreter named by the hook record. A separate plan binds root, generation, artifact and script bytes; a persisted journal records running/ready stages. An unknown result needs an explicit retry, and a user-namespace fixture covers failure, recovery and success. Foreign scripts, preinstall and automatic execution during add remain open. - [x] Prepare regular-file and relative-symlink replacements beside their target, verify bytes and metadata before publication, and retry individual add/replace/ remove transitions after interruption. Reject drift and preserve complete old or new files across injected rename failure and process termination. These primitives now support the journaled cached-update command below. - [x] Compare verified old/new archive manifests into a canonical file plan with stable change IDs and both artifact hashes. Check the entire payload delta without writing files, accepting exact before/after states during recovery. Preserve unsupported entries in the record and reject their application. The cached update preview binds source, graph and ownership checks; directory creation is implemented below; directory metadata replacement remains open. - [x] Preview one cached slot replacement with `db plan-update`. Bind the generation, root/database identities, every installed state, source registry, file delta and proposed complete dependency graph. Reject changed payloads, conflicting owners, disabled origins and unavailable old archives. Preserve source identity across alias changes. The single-slot catalog path below fetches candidates; new dependency selection and grouped replacements remain open. - [x] Apply the reviewed cached replacement with one writer lock and generation change. Stage changed payload, journal individual transitions, publish the next installed database and retain the old records. Rewrite consumer edges while preserving reasons/source identity. Recover interrupted publication after injected SIGKILL and ENOSPC; preserve partial staging for explicit inspection. Test file addition/removal, regular/symlink transitions and a compatible ELF provider update. Hooks and content merging remain open. - [x] Preview and apply a reverse cached replacement from a committed update transaction with `holypkg rollback`. Verify the original journal, committed marker and plan digest; reuse the dependency solver, whole-file plan hash, writer lock and update recovery. External hook effects and arbitrary transaction types remain outside this command. - [x] Prepare one source-aware slot update from a bound native catalog. Select the highest newer pacman/deb version or require an exact choice when version ordering is unknown, save the catalog digest and complete update plan, then apply only after whole-file hash approval and source/DB revalidation. A fixture covers upgrade, explicit downgrade and stale/tampered plans. Apply now checks the selected digest against the pinned index and installed slot before changing rootfs; a forged but internally consistent plan for an unlisted cached artifact fails. Grouped updates and trial execution remain open. - [x] Apply a single-slot `up SOURCE:PACKAGE` in one invocation through the same hashed plan and checked apply path. Print the full plan, require a terminal decision or scoped --yes, and retain it for noninteractive review. The direct path tests both approval and decision-required behavior; updating all installed slots together remains open. - [x] Read the pinned catalog index for an installed source slot and stage only matching name/os/arch/libc versions during update preparation. Verify those archives against the index before planning; keep the full catalog validation path for explicit source binding. Exact search, info and fetch now also verify only matching archives against the pinned index. A corrupt unrelated archive no longer blocks these operations. Older native indexes still require a full candidate scan during add. - [x] Select the add candidate pool from v5/v6 native indexes by walking declared package/file/command/SONAME requirements and scanned interpreter, DT_NEEDED, shebang and symlink paths. Verify and stage only reachable archives; a corrupt unrelated object no longer blocks add, while a corrupt selected provider does. An in-memory inverted map resolves exact requirement names to indexed candidates without rereading every archive or rescanning every index entry. The pinned index and selected hashes remain bound to the reviewed plan. Cross-source discovery, indexed symbol versions and runtime dlopen probes remain open. - [x] Require a fresh artifact-hash approval when a cached replacement contains a setuid executable. The plan, journal, installed state and recovery retain the decision; a previous package's approval is not inherited. Fixtures cover refusal, mode 4755 publication, injected ENOSPC recovery and removal of setuid on the next replacement. Privileged hardlinks remain unsupported. - [x] Create missing manifest directories before payload installation, update or repair. Validate every absent parent, preserve existing modes/owners and publish prepared directories without replacement. Handle arbitrary archive entry order; recover exact staged/published directories in interrupted sets and updates. Reject symlinked parents, changed metadata and partially initialized staging. Retain directories and untracked contents on removal. Full directory metadata changes, privileged ownership and general single-install resume remain open. - [ ] Implement native HTTPS/Git source synchronization, signed generations and cache retention with provenance. - [x] Sync a registered holy-git source at an explicit full commit and native index digest. Verify all referenced artifacts and an optional registered Ed25519 signature, bind the sealed clone to its source-id, and reject a changed commit on later queries. A local Git fixture covers signed and unsigned sync, search, fetch, wrong pins and changed checkout metadata. Remote Git transport and multi-source resolution still need integration testing. - [x] Accept a pinned holy-git commit in holygetiso source sections. Preserve the commit in the effective config and build record, pass it to source sync, and verify an imported clone before source binding. A local signed Git fixture covers image source staging and config validation. - [x] Mirror an explicitly pinned HTTPS native catalog into a new sealed local snapshot through the common transport. Verify all artifact hashes, identity, payload and claims before publishing current; retain unsigned URL/digest provenance. Fixture TLS covers search/solve/fetch, escaped filenames, empty, duplicate/truncated indexes, false claims, bad hashes, missing URLs and limits. Signed generations use a separate Ed25519 sidecar; the signed HTTPS fixture still needs a network-enabled run. - [x] Resolve an active registered holy-http alias to its immutable source-id and HTTPS URL, then mirror a pinned index into a new local catalog. An unsigned remote current pointer can propose a digest; a separate exact-hash confirmation rereads it before mirroring. Store source-id and selection in mirror-origin before sealing. Local TLS fixtures cover alias changes, unrelated backends, wrong digest, missing CA, changed/malformed pointers and credential-bearing redirects. Multi-source dependency resolution remain open. - [x] Fetch one SOURCE:PACKAGE from an explicit sealed synced mirror without installing it. Check active source ID and URL against mirror provenance, verify the pinned index and selected archives, reject ambiguous names, and support extraction into a new directory. - [x] Install SOURCE:PACKAGE from an explicit sealed holy-http mirror. Stage candidate artifacts, resolve dependencies in one set, bind newly selected packages to the registered source-id, and bind index digest to the reviewed plan and recovery journal. Reject changed catalogs before apply. A faulted generation update recovers from the version-5 journal without network access. Explicit `--candidate SOURCE:PACKAGE` combines bound catalogs in one reviewed set. `--candidate-provider SOURCE:KIND:NAME` stages exact indexed package, file, command or SONAME providers and their local closure. Both recheck each source before apply and preserve selected source IDs. The add loop now queries exact missing package, file, command and SONAME edges across active bound native catalogs before staging artifacts. It stages a unique matching source and its local closure. Multiple sources or unavailable coverage require a named alias in the terminal; noninteractive calls return decision-required. An explicit `--candidate-provider` selects the source. A three-source fixture checks both the noninteractive decision and terminal selection, then verifies installed files. `--answers FILE` now selects a source by consumer hash and requirement-id for noninteractive add; duplicate and stale answers fail before rootfs changes. It probes installed providers first, including inactive origins. Same-source registered-parent and source-family preference now choose among exact native offers by source-id and policy; source priority breaks ties within a rank. Explicit answers override them. Source plan now reports changes to trust, key, parent, family and priority; source show displays the applied policy. Complete coverage diagnostics and plugin discovery remain open. A three-catalog ELF fixture verifies SONAME discovery after installed libc and interpreter paths, selected source identity, and installed check. The source probe rejects a same-SONAME candidate without the consumer's version-attributed imported symbol. - [x] Query an active holy-http source through an explicit synced mirror with `search QUERY --source ALIAS` and `info ALIAS:PACKAGE`. Verify source identity, pinned index and matching artifacts before returning exact names; report missing and ambiguous info queries without mutating the target. Native repositories also index verified nondirectory payload paths and support exact `search --file` with complete/unavailable coverage. File queries verify indexed candidates without reopening unrelated archives. Explicit `--fuzzy` returns ranked, capped hints for package names and file basenames, without treating them as exact providers. Search without --source visits active aliases in stable order, labels each result with its source ID and reports unavailable catalogs as incomplete coverage. Multi-source resolver integration remains open. - [x] Add complete HOLY/deps records to native index generation 4. Verify the records against each selected archive, and expose `repo requirements` for a digest-pinned metadata query without opening the payload. The solver still scans archives for ELF-derived requirements; indexed candidate closure remains open. - [x] Add scanned DT_SONAME facts to index generation 5. Exact provider lookup uses actual ET_DYN payload facts, then verifies selected archives; a forged HOLY/provides SONAME claim cannot become a candidate. Generation 6 adds per-library defined version names and checks strong ELF version needs before staging SONAME candidates. A targeted payload scan now rejects a matching SONAME/version candidate missing a strong imported symbol before staging. Cross-source offers apply the same consumer ELF probe. Generation 7 indexes exported dynamic symbols by library path, version and ELF attributes. Provider search rejects missing exports without opening candidate archives; selected artifacts are checked against the index and then by the resolver. Generation 8 records and verifies the version comparator family. Update preparation selects from index records and stages only the chosen artifact; the fixture corrupts an unselected same-slot archive without changing the chosen update. Large-catalog index scaling remains open. - [x] Bind a verified synced mirror and index digest to a registered source-id under the target database lock. Resolve add, fetch, search and info without repeating --catalog; reject corrupt bindings and changed mirrors. Keep the binding across alias renames. Sync without --output now publishes a verified generation in the target cache and binds it for source queries. A registered Ed25519 key now rejects unsigned or changed bound catalogs. A rootless system-cache workflow remains open. - [ ] Implement remaining foreign binary adapters and file indexes with real fixtures: RPM, eopkg, homebrew and guix, all of which now have one. APT has a pinned local index and HTTPS fetch/import path; APK has a separate index/fetch path. XBPS local binary import parses plist metadata, checks payload hashes and resolves simple versioned dependencies with a bounded Dewey comparator. It resolves relative archive symlink targets against absolute files.plist targets before comparing them, while retaining both original records. A pinned repodata catalog supports HTTPS sync, search, info and archive fetch. An explicit RSA public key can match index metadata and verify package .sig2. A registered XBPS source can now pin the RSA key, URL and source-id during sync-source, then bind the catalog conversion digest in the target database. Source-aware search/info/fetch resolve that binding by index architecture and reject changed catalog data or source definitions. Root-relative bindings survive moving a target root with its cache. Common sync/search/info/fetch now use the same registered-source checks for XBPS, with explicit index architecture and version where required. A separate digest-checked shlib-provides index now gives exact SONAME candidate hints from Void metadata, including source-bound queries. Foreign binary import now derives SONAME provides from classified ELF payloads, so a selected archive can supply separate file-level evidence. Complex patterns remain review-required. Key enrollment, automatic provider selection remain open. `holypkg index` now answers the two questions the planner answers internally: it names the installed artifacts that own a path and the artifacts that declare a capability, and it prints the whole index when given no selector. A name with several providers is a candidate list and the status is 1, since choosing one of them is a decision a report does not make, and a name nothing declares is status 6 because an absent answer is not a proof. A fixture installs an application, the library it chose and a second provider of the same soname that places its file elsewhere, then checks one owner, two candidates, the agreement with the conflict report and every refusal. The planner still reads the manifests themselves, so an index narrows nothing yet. A Homebrew formula converter now reads a formula as Ruby text and never evaluates it. The class name, description, homepage, license, url, sha256 and revision are carried, a formula that states no version records the version its source url carries, a depends_on becomes a runtime requirement and a :build dependency a build requirement, and a recommended or optional dependency is reported. A resource or a patch block with a pinned url and digest becomes a fetched source. A system call inside def install or on_linux becomes a build step that runs the same command in the source root, with #{prefix}, HOMEBREW_PREFIX, #{libexec}, #{etc}, #{var} and #{buildpath} rewritten onto the build root; an interpolation the reader does not model keeps its text and is named. Every other statement of an install body stays Ruby, so the formula is copied beside the recipe as homebrew-install.rb, the build declares a ruby build requirement, and the report names the file and line of each statement. A fixture converts a mechanical formula, builds the recipe it produced into a real package, installs it beside a provider that closes the requirement the depends_on created, and converts a formula full of Ruby, platform blocks, a bottle and a test block, checking every named refusal. The build also keeps the mode a declared directory had, since a package built here used to claim /usr with the mode of the manager's own staging tree and could not be installed beside any other package that claims it. A Solus eopkg importer now reads the ZIP artifact, carries the metadata as text and walks the install tar with libarchive. The metadata is read in its own context, so a packager identity is not a package name and a build dependency is not a runtime requirement; a description, a history entry, a conflict, a replacement and a declared capability are counted and named rather than imported. Each runtime dependency becomes one exact package requirement whose original field is the releaseFrom value the metadata states. The install tar travels whole under a private path, since a Solus layout is recorded rather than claimed, and an install script, a COMAR object, a delta and a signature are dropped rather than run or trusted. A Guix package definition converter now reads the definition as Scheme text and never evaluates it. The name, version, synopsis, homepage, license and build system are carried, an origin becomes one pinned source with the base32 digest decoded into the hex a Holy source records, and an origin that is not a url-fetch is reported. Each name in inputs becomes a runtime requirement and each name in native-inputs a build requirement, where a versioned entry contributes only its name. The build system becomes the tools it runs: gnu-build-system becomes autoreconf, configure with the payload prefix, make and make install, and cmake and meson become their three commands, while a system this reader does not replace is reported. An argument whose entries are literal strings becomes the flags of the phase that takes them, and an argument that computes a value keeps its text and is reported. A fixture converts a mechanical definition, builds the recipe it produced into a real package, and converts a definition with a git origin, a trivial build system, a versioned input, a phase list, a computed flag and a modulo expression, checking every named refusal. - [ ] Implement AUR, Aports, xbps-src, SlackBuilds, RPM spec, Debian source, Gentoo, Pacstall, Homebrew and Guix recipe conversion with helper environments and split outputs. Every named family now has a converter. The native side of that work now exists: `holypkg build` parses a holy-recipe(5) manifest, fetches pinned sources, unpacks them, runs reviewed phase steps with absolute HOLY_* paths, and packs one .holy per declared output. Outputs are grouped by the ABI facts of the payload, so a single build yields a noarch/nolibc document output and separate ABI libraries. Requirements come from declared depend records and payload DT_NEEDED entries; provides come from payload SONAMEs; config flags and runtime hooks are recorded with the produced digests. `split-step` gives one output its own staging tree, so a payload requirement and a hook script are written only into the output that carries their file. The PKGBUILD family converts: identity, dependencies with their comparison relations, source entries with their sha256sums, backup paths and install fragments are carried; the phase bodies keep their Bash with the makepkg variables mapped onto the exported paths; each package_NAME function becomes a split output; and a conversion report lists every carried, preserved, helper, unknown and changed item with its PKGBUILD line range. A fixture converts a real PKGBUILD, builds the produced recipe through the normal engine and installs its split outputs. The converter also reads lists the way a shell does, so a comma inside an element belongs to its name, and a brace inside a parameter expansion does not end a function body. The Void template family converts as well: `holypkg convert template` and `holypkg import --format void` read the xbps-src template, carry its identity, dependency lists with their comparators, distfiles with their checksums and conf_files/mutable_files, and keep every pre/do/post phase body in Bash behind a prologue that maps $wrksrc, $masterdir, $DESTDIR and $PKGDESTDIR onto the exported HOLY_* paths. The v* helpers a body calls are carried into that prologue, and vman, vsv, vsed, vcompletion and vsrccopy are reported as unresolved. A NAME_package function becomes an output whose split step carries its pkg_install body. A patches or files directory is archived beside the recipe, an INSTALL or REMOVE file becomes one hook, build_options are fixed to build_options_default so no vopt_ call survives, and a phase the template leaves out is reported as supplied by the build style the converter does not run. A fixture converts a template with three outputs, builds it through the normal engine and checks the resulting ABI groups; 700 upstream templates from void-packages convert and every produced recipe passes the manager's own validation. The Aports family converts as well: `holypkg convert APKBUILD` and `holypkg import --format aports` read the APKBUILD, carry its identity, map arch onto the Holy machine names, and read depends as depend and makedepends/makedepends_build/makedepends_host/checkdepends as build-depend, so a !NAME conflict becomes x-conflicts and a so: or cmd: requirement is reported. The abuild phase bodies keep their original shell behind a prologue that maps $srcdir, $startdir, $pkgdir, $subpkgdir, $JOBS and the other abuild.conf parallel settings onto the exported HOLY_* paths, and the step changes into $builddir because abuild runs a phase there, with a declared builddir rebased on the source tree and an absent one reported as the abuild default of $srcdir/$pkgname-$pkgver. Each subpackages entry becomes an output whose split step carries its split function, taken from the entry or from the last dash-separated suffix of the name, and an entry with no written function is reported as needing the default_dev, default_doc, default_static, default_openrc or default_libs helper, so no output is claimed for it. A post-install or pre-deinstall script becomes one hook, and the other four install actions are reported as having no Holy hook stage. Since aports pins sha512sums, which a Holy source cannot use, a remote source with no sha256sums entry is reported rather than fetched, while a local source beside the APKBUILD is copied next to the recipe and hashed as SHA-256. The shell text the Void and Aports converters share now also lives in one parser, so a conditional block, a case block, an appended value and an unreadable top level statement are handled the same way in both. A fixture converts an APKBUILD with four declared subpackages, builds the produced recipe through the normal engine and checks the resulting split payloads and hook; all 1668 upstream APKBUILDs from aports convert and every produced recipe passes the manager's own validation. The SlackBuilds family converts as well, and needs a different shape because a SlackBuild script is one linear shell program rather than a set of phase functions. `holypkg convert NAME.SlackBuild` and `holypkg import --format slackbuild` read the script, carry PRGNAM, VERSION, BUILD, TAG and PKGTYPE in either the plain or the ${NAME:-value} form, and put the whole body into a single build step whose prologue maps $ARCH onto $HOLY_ARCH, $CWD and $TMP onto $HOLY_SRC, $PKG onto $HOLY_DEST and $OUTPUT onto $HOLY_OUT. The cd $PKG and the /sbin/makepkg call are left out because the engine packs the payload, and so is a tar line reading $CWD, because the engine has already unpacked the recorded archive. slack-desc beside the script carries the summary, homepage, requires and conflicts, and the info file carries the upstream URL and its MD5 sum, which is reported as unusable; a local archive is copied next to the recipe and hashed as SHA-256 instead, and every other file the script reads through $CWD travels beside it as a source. A doinst.sh becomes one hook, the $PKG/install tree is reported as packaging metadata, and the strip pass, the ownership rewrite, the user and group creation and the loader and desktop cache helpers are reported as unresolved. A fixture converts a script with a local archive, a patch and an install hook, builds the produced recipe through the normal engine and checks both the ELF group and the noarch group; all 2211 upstream scripts from the development and libraries trees convert and every produced recipe passes the manager's own validation. The RPM spec family converts as well, and needs a parser of its own because a spec is neither shell nor a list of phase functions. `holypkg convert NAME.spec` and `holypkg import --format rpmspec` read the spec, carry Name, Version, Release, Summary, License and URL, collect the %global and %define records and expand the macros that resolve, so a body keeps its own words with _sourcedir, _builddir, _topdir and buildroot rewritten onto the exported paths. A Version or Release written with a macro in it keeps only its literal part and reports the macro, so the value stays what the spec says. BuildRequires becomes build-depend and Requires becomes depend, read one record per line because an rpm requirement carries its comparison with it; Provides, Conflicts, Obsoletes and Recommends become x- records, since none of them is a requirement, and a rich dependency, an rpmlib capability and a requirement naming a file are reported. The prep, build, install and check sections become the matching phases, %setup, %autosetup and %autopatch become a cd into the unpacked tree and a patch pass over the declared patches, the %make_install family and the __ prefixed helpers become the shell line they stand for, and every other rpm section command is reported and left in the body so the build fails visibly rather than losing a step. A %package block becomes an output whose split step copies the paths its own %files list named out of the main tree, because an rpm subpackage is a file list and not a body; the main %files list is reported as a check the install already made. A local Source or Patch file beside the spec is copied and hashed as SHA-256, and one that is absent is reported, since a spec normally pins no digest. A fixture converts a spec with a subpackage, a patch, a file requirement and a rich dependency, builds the produced recipe through the normal engine and checks the three payloads it produced; 387 of the 388 source RPM specs sampled from the Fedora archive convert, the one refusal being a spec with no Name at all, and every produced recipe passes the manager's own validation. The Debian source family converts as well, and needs a parser of its own because a source package is a set of files rather than one program text. `holypkg convert debian` and `holypkg import --format debian` read debian/control, which is RFC822 with continuation lines, and take the version from the first record of debian/changelog, since that is the distribution version and not the upstream one. It is split at the last dash: an all-numeric tail is the Debian revision and becomes the Holy release, a version with no such tail is native and gets release one, and either outcome is reported, as is an epoch, which names a packaging revision order and is dropped. A relationship field is a comma separated list of groups and a group may offer alternatives with a pipe, so the first alternative of each group is carried and the rest are reported; Build-Depends and Build-Depends-Indep become build-depend, Depends and Pre-Depends become depend, a strict comparison becomes lt or gt, and Provides, Breaks, Conflicts, Replaces, Recommends, Suggests and Enhances become x- records, since none of them is a requirement. A dpkg substitution variable such as ${misc:Depends} is reported rather than guessed, and an entry with an architecture qualifier is reported instead of being turned into a record. Each binary stanza becomes an output, and a binary that names a .install, .docs, .manpages or .links file list becomes a subpackage whose split step copies the paths that list named out of the main tree, because a debian subpackage is a file list and not a body; a list line is a source and a destination, and a line with no destination names the source itself, while a list that names no path at all is reported rather than written as a split step that would fill no tree. The binary that names no file list owns the whole tree, and more than one such binary is reported since the converter cannot tell which one is the main tree. debian/rules becomes the build step behind a prologue that sets DEB_HOST_MULTIARCH and DEB_BUILD_OPTIONS; dh is a macro framework rather than a script, so every debhelper call, every debhelper override and dpkg-buildpackage are reported and left in the body so the build fails visibly. The maintainer scripts, debian/copyright, debian/watch and debian/source/format are copied next to the recipe and reported, and a lintian-overrides file is reported as suppressing a report rather than building anything. A fixture converts a package with a subpackage file list, a maintainer script, an alternative and a build profile, and checks the split payloads, the version split and the malformed and empty cases; all 398 source packages sampled from the Debian trixie archive convert and every produced recipe passes the manager's own validation. The Gentoo ebuild family converts as well, and needs the shared shell parser rather than a parser of its own, because an ebuild is bash with a metadata header. `holypkg convert NAME.ebuild` and `holypkg import --format gentoo` read it, take the identity from the file name, which is PN-PV-rPR.ebuild, so a trailing -rN becomes the Holy release, a file name with no revision gets release one and an epoch is preserved and dropped. EAPI, LICENSE and SLOT are carried, and KEYWORDS names the machines an ebuild is tested on rather than the machine that builds it, so arch is any. A mirror:// entry names no single address and a remote archive has no digest, since a Gentoo Manifest pins a BLAKE2B and a SHA-512 rather than the SHA-256 a Holy source needs, so both are reported, while a PATCHES entry and any other file named beside the ebuild is copied next to the recipe and hashed as SHA-256. A dependency atom keeps its package name and its comparison, a blocker becomes x-conflicts, and a USE conditional, an any-of group, a slot, a use dependency and a virtual are reported, since a Holy recipe has no USE flags and cannot choose between the members of a group; the atoms inside one are carried anyway so the build still holds them. Each standard phase function becomes the matching phase behind a prologue that rebuilds the variables Portage exports onto the Holy paths, a phase the ebuild leaves out is the one the inherited eclasses supply, and every eclass and every ebuild.sh helper a body calls is reported rather than run, so the build fails visibly. A fixture converts an ebuild with two local patches, a blocker, an any-of group, a slot, a use dependency, a virtual and a maintainer script, and checks the patches, the split identity and the malformed cases; the parser work this needed fixes four gaps that a Void template and an APKBUILD could not reach, namely a trailing comment that holds an apostrophe, a line continuation that reads as an unterminated value, a heredoc whose body holds a brace, and a parenthesized list written one element per line, so 12191 of the 12192 ebuilds in the gentoo tree sampled convert, the one refusal being the package skeleton, which carries no version in its file name, and every produced recipe passes the manager's own validation. The Pacstall family converts as well, and needs the shared shell parser plus its own reading of a metadata header that is written as assignments. `holypkg convert NAME.pacscript` and `holypkg import --format pacstall` read the pacscript, carry pkgname, pkgver, pkgrel, pkgdesc, url, license, maintainer, repology, arch and gives, and expand $pkgname, ${pkgname}, $pkgver, $pkgrel, $gives, $pkgbase and $epoch as well as a variable the same pacscript states in an assignment of its own, so a name or a version written from a private value of that file is carried; a value that needs the shell to choose a substring is a computed identity and returns 2. An epoch is preserved and dropped. amd64 and x86_64 become x86_64, i386 and i686 become i686, any and all become any, and a machine Holy does not carry is written as it stands and reported. A source entry is NAME::URL, ?NAME::URL or a plain URL, a sha256sums entry in the same order becomes source-sha256, and a file named beside the pacscript is copied next to the recipe and hashed; a git address, a remote source with no digest and a plain http address are reported rather than carried, since a Holy source is fetched over https. The engine fetches and unpacks the recorded sources, so the extracted tree takes the place of srcdir, which is reported. depends, makedepends and checkdepends become depend and build-depend with the comparator names the other converters use, a group of alternatives written with a pipe is reported with the first of them carried, and pacdeps become depend with the fact that they name packages of the same pacstall repository reported, because a Holy resolver has to find them in a source that has them. provides, conflicts, breaks, replaces, enhances, recommends and suggests name no requirement, so they become x- records, an optdepends entry becomes x-optdepend with its description, a backup entry becomes config and an r: prefix becomes config mutable with a report. A list written per machine or per distribution under a suffixed name is reported, and so is every setting that steers a Pacstall run and every digest list other than sha256sums. prepare, build, check and package keep their own shell behind a prologue that rebuilds pkgdir, pacdir, srcdir, startdir, builddir, TARCH, NCPU, pkgname, pkgbase, pkgver, pkgrel, pacname, gives and epoch from the exported Holy paths, and every helper a body calls and every variable of the Pacstall environment a body reads is reported rather than invented. A list of names with a pkgbase is a split pkgbase: every name becomes an output and its package_NAME function becomes the split step that fills it. pre_install, pre_upgrade, post_install and post_upgrade become one install hook and pre_remove and post_remove one remove hook, each written beside the recipe, declared as a source and installed into the payload, and a Holy hook runs with ACTION unset, so the pre and post bodies arrive in the order Pacstall calls them. A conditional block and an assignment inside one are reported, since the converter evaluates neither. A fixture converts a pacscript that builds through the normal engine, one that is a split pkgbase, one with both hook groups, and one that carries every reported case; 910 of the 919 upstream pacscripts from pacstall-programs convert and every produced recipe passes the manager's own validation, the nine refusals being seven versions that carry a tilde, which a recipe records as a label, and two names that need a shell substring expansion. The parser work this family needed fixes four gaps the Void, Aports, RPM, Debian and Gentoo families could not reach: a list written on one line was recorded as one value with its parens left in it, a list written on many lines had its elements and its closing paren read again as statements of their own, the line count drifted by one for every list, and a heredoc word written apart from its << was not recognized, so an apostrophe inside such a body ended the function early. An x- record of a recipe also undercounted its buffer, so a value with a byte outside printable ASCII overflowed it while the build read the recipe. The makepkg build environment and the vm build environment remain open. The build runner no longer loses its private build root, keeps a root the caller named, and reaches both the default and the named-root path in the fixture. The same run also restores three interrupted-mutation fixtures whose LD_PRELOAD shims hooked the wrong symbol names under _FILE_OFFSET_BITS=64, and restores the plan-set check that a source binding names an artifact inside the resolved set. - [ ] Implement Nix closure, Flatpak, Snap, AppImage, Scoop and WinGet imports without silently discarding runtime requirements. AppImage type 2 inspect/extract now snapshots the original, checks ELF and SquashFS structure, extracts with unsquashfs without running the image, and records an unclassified AppDir plus per-file ELF, loader, script and link facts. `import --format appimage` now also emits one native package beside the review bundle: the AppDir travels whole under a private path, the entry point becomes a link under a private bin directory, /usr/bin/NAME is a launcher that starts it in the package run context, the desktop entry is rewritten onto the launcher, and the classification and conversion reports travel with the package. Dependencies are the payload's own: a DT_NEEDED the payload carries through its SONAME is satisfied privately, every other name becomes a soname requirement, and a link whose absolute or escaping target cannot travel in a payload becomes a recorded file requirement. The arch, libc and version come from the payload itself, a mixed-ABI payload is refused, and every entry is attributed to the installing user with each parent directory declared by the same manifest. The import returns decision-required and the package report names the changed launch conditions, the dropped image-level sandbox, the runtime probes static inspection cannot close, the path views a link needs and the version decision. `snap inspect` and `snap extract` now read the eight-byte header that states the SquashFS offset and size, extract with unsquashfs without running the image, and record the manifest beside per-file ELF, loader, script and link facts. `import --format snap` emits one native package: the snap root travels whole under a private path, the image itself is the entry point, /usr/bin/NAME is a launcher that starts it in the package run context, and the classification and conversion reports travel with the package. The name and version come from the manifest, the arch and libc from the payload's own ELF files, a mixed-ABI payload is refused, and the base the manifest names becomes a package requirement, since the runtime snapd would mount has to come from a source here; plugs, confinement, hooks, environment names and command-chain entries are recorded and counted rather than emulated. The import returns decision-required and the report names the base requirement and everything the conversion drops. The Flatpak manifest converter reads a JSON manifest, carries the id, version, summary, url, command, branch and machine, turns the sdk into a build requirement and the runtime into a runtime requirement because they are two different ids, and gives each module one step in module order. The make, autotools, autogen, cmake and meson templates are replaced by the shell that runs the same tools, a patch applies with -p1 before its module builds, an inline source becomes a file beside the recipe, a local archive is copied next to it and a remote one keeps its declared sha256, a /app path becomes $DESTDIR and a module prefix becomes /usr. finish-args permissions, cleanup steps and build extensions are dropped and counted, and a buildsystem with no Holy phase is a helper the report names. The Scoop importer reads a manifest as JSON, verifies the artifact beside it against the digest the manifest pins, and carries it whole under a private path, with the declared extract_dir replacing the first component of every archive member and the declared program looked up inside the payload. A bucket dependency becomes a package requirement, while the PowerShell installer, the Windows integration keys and the bucket update keys are dropped and counted. Nothing runs the artifact and no Wine requirement is invented, so the import returns decision-required. The closure fixture now proves the shape a Nix closure needs: one shared object package with two application packages that name it by exact path, one owner and several dependents. Removing an application leaves the object and the other application intact, removing the object is refused while an application still needs it, accepting the broken dependents removes it and the check report names the provider that is gone, and restoring the object makes the surviving application whole again. The WinGet importer reads a winget-pkgs manifest as YAML, takes its PackageIdentifier, PackageVersion, InstallerUrl and InstallerSha256, verifies an upper-case digest against the artifact beside the manifest, and carries it through the same writer the Scoop package uses. A PackageDependencies block becomes package requirements, every nested block that is not one is skipped and counted, and the installer, Windows and catalog keys are dropped with a count. Nothing runs the artifact, so the import returns decision-required. The Nix closure importer reads a capture that names its store paths, the output root, the entry points and the references between them, and emits one package per store path. Every store path has to sit beside the capture, since nothing builds a store, and each travels whole under /usr/lib/holy/private/NAME/store/STORE_PATH/. A reference to a carried store path becomes a package requirement, so one object two applications name has one owner and two dependents, and a reference to a store path the capture does not carry becomes a requirement whose original field is the store hash. One pass over a store path's own bytes confirms each reference the capture declares, and the report counts the ones the payload does not carry. Nix states no version, so every package records 0 and the store hash is its identity. A fixture installs the closure, removes one application and sees the object survive, and the removal of the object is refused while the other application still needs it. Nothing is executed, so the import returns decision-required and names the store view a Nix program with absolute paths would need. `holypkg split TREE --output NEW_FILE` now proposes the split outputs of a prepared tree before anyone writes them: every non-directory path receives one output, a path line records the reason, an explicit rule outranks the heuristic, and four cases stay decisions instead of assignments. A header, an include directory and pkg-config metadata are proposed for -devel, a versioned shared object and a license stay in the runtime output, and a man page or reference document is proposed for -doc. An unversioned object is a decision because the payload may dlopen it, a static archive is a decision because only the project knows, a link that leaves the tree or is absolute is a decision because a payload carries neither, and two rules naming different outputs for one path is a decision by definition. A fixture builds a real payload with a program, a versioned object, a plugin, an archive, headers, pkg-config, documentation and a license, and checks the proposal, the rules that settle it, the contradictions and the refusals. `holypkg split --debug` now adds a NAME-debug output whose files are cut from the runtime ELFs with objcopy, and the ELF reader reports the GNU build-id note so a stripped artifact and its debug file are matched by an identity instead of a name. Each debug record names the runtime path and that note, an ELF without a note is a decision because nothing would tie the pair together, and the proposal names the tool rather than inventing a per-file command. `elf FILE --build-id` reads the note section, so a separate debug file, which keeps the note and loses the loadable segments, is still checked. A fixture cuts a real pair with objcopy, keeps the note in both files, confirms the stripped file lost its debug sections and names its debug file, and drives GDB to the recorded source line and stack trace through the pair; the same artifact without its debug file resolves no line, which is what makes the debug output load-bearing. `make check-cc` now compiles the core with tcc, gcc and clang in turn, packs a package with each result and verifies it, and returns 6 when a toolchain is absent, so the three named host compilers are checked rather than assumed. The Solus eopkg importer reads a ZIP artifact holding metadata.xml, files.xml and an install tar, and emits one native package. The metadata is read as XML text in its own element context, so a Name under Source is a packager identity rather than the package name and a BuildDependencies entry is not a runtime requirement. Each RuntimeDependencies entry becomes one exact package requirement whose original field is the releaseFrom value, since a distribution release is a property of the repository and not of the dependency. Solus states no release, so the native one is 1, and an architecture this manager does not place is a decision rather than a guess. The install tar travels whole under /usr/lib/holy/private/NAME/eopkg/, a leading ./ is dropped, a member naming .. is refused, and a link that leaves the private tree becomes a recorded file requirement. An install script, a COMAR object, a delta, a signature and a declared file list are named in the report and dropped: nothing runs and no signature is trusted. A fixture converts a real artifact, installs the package beside a provider that closes the requirement, checks the private layout is what landed, and refuses a missing metadata, a missing install tar, a malformed document, an unplaceable path and an unknown architecture. - [ ] Implement `holypkg run`, context-specific provider paths, grouped `up --prepare`, isolated root/VM trials and full `check` reports. The existing run launcher now derives private PATH directories from the selected installed manifest, so a public executable can invoke its own private helper by name. Explicit directory views bind package-owned private trees over existing /usr/lib or /app mountpoints in the child namespace. An explicit --auto-view now binds package-owned private regular files over existing matching public paths in the child namespace and refuses ambiguous mappings. The command after -- may now name a manifest-owned private file under /usr/lib/holy/private/ARTIFACT-ID/ with a bin directory and a plain file name after it, which is how a package whose payload is private starts its own entry point. `holypkg conflict` now reads the installed set and reports every capability two artifacts both offer: a package name two providers claim, a SONAME two providers claim, a file path two artifacts declare and a program name two private trees place in a bin directory, which the run PATH resolves by sort order. Two providers of one SONAME with different arch or libc records are an abi mismatch rather than a duplicate. A fixture installs a shared object and its consumer, adds a second provider of the same SONAME, a second artifact claiming one package name, two artifacts declaring one file path and two private programs of one name, and checks each finding, its reason and its provider list, alongside the refusals for a root with no database and a pending transaction. Automatic conflict detection inside the installation transaction itself remains open. ## Base system and images - [x] Build musl-static dependencies, holypkg and holy-init for i686 and x86_64 with explicit compiler and linker targets. Check ELF class/machine and pointer width, and run a static C package through pack/install/check/execute/remove under QEMU user mode (pentium2 or qemu64). The i686 client also passes codec import and DNS/HTTPS fixtures without dynamic libc on a compatible x86_64 kernel. i686 BIOS boot and dinit's static C++ runtime are covered by separate gates below; compiler SDK packaging remains unfinished. - [x] Generate an attributed installed-man source bundle with `holypkg docs`: verify source hashes, decode supported compressed pages, preserve aliases and same-name providers, report missing/omitted pages, and refuse changed inputs or pending transactions. Static gzip decoding passes a libc-free chroot fixture. The image builder generates its own bundle from installed sources and binds its hash to the image plan. BIOS/UEFI guests verify and regenerate it before libc recovery and after reboot. Altered bundle/source disk fixtures fail the documentation boot stage. Text remains roff source. - [x] Build pinned i686 and x86_64 musl-static BusyBox as native packages and test their installed shell in a chroot without dynamic libc directories. Build logs, source/config/artifact hashes and upstream license files are retained. This bootstrap profile does not supply static holypkg or network recovery. - [x] Link the prototype holypkg with musl-static dependencies; verify native archive, ELF, repository, solver and HTTPS fixtures. Run local package cache/install/check/remove and BusyBox shell probes inside a libc-free chroot. The separate dual-libc chroot gate now restores actual runtime payloads; i686 BIOS recovery is covered by the dual-libc image gate below. - [x] Test the static client's DNS and HTTPS path in a private-network libc-free chroot, including wrong CA/digest refusals and a hashed JSON report. Pinned static BusyBox packages for i686 and x86_64 now include ip, udhcpc and nslookup; the fixture raises loopback with that packaged ip applet inside the libc-free chroot. Guest DNS is covered by the QEMU fixture below; public CA packaging remains a separate gate. - [x] Package statically linked BusyBox, dinit, mdevd and the local recovery chain, plus both dynamic libc runtimes for i686 and x86_64. The isolated QEMU HTTPS recovery fixture is listed below; ordinary network configuration and public CA packaging remain unfinished. - [x] Build pinned i686 and x86_64 musl as native runtime packages with source hashes, license and a natively linked loader SONAME. Run pthread/allocation probes alongside glibc. - [x] Run musl32 and musl64 pthread/clock probes and bidirectional pipes in a shared disposable x86_64 root. A static i686 client installs both architecture slots with artifact-scoped decisions and restores either or both removed runtimes from its cache. The i686 BIOS boot gate is listed below. - [x] Build pinned i686 and x86_64 glibc 2.42 loader/libc payloads from source as a native bootstrap package with licenses and recorded private-path patches. Complete SDK, auxiliary libraries, locale/NSS packaging and upstream-suite acceptance remain open. - [x] Install and run glibc32, glibc64, musl32 and musl64 together on an x86_64 kernel, including pthread/clock and pipes between ABI variants. Restore all four runtime packages through the static i686 client and cached artifacts. Glibc compilation uses the host multilib SDK; the packaged SDK is unfinished. - [x] Run static holypkg inside an x86_64 root after deleting both glibc and musl runtime payloads; restore from cached LZ4 .holy files and run both dynamic probes. Repeat each libc separately, including loader symlink restoration. This gate covers missing payload repair, not forced package removal, boot or network recovery. - [x] Build pinned i686 and x86_64 musl-static dinit with upstream tests; exercise service start/status/shutdown and stop-command effects with dinitctl in a libc-free chroot as an ordinary user. Install/check/remove the complete package, including command and man-page symlinks, through the transaction engine. The static-core image also exercises dinit as PID 1. - [x] Build pinned i686 and x86_64 musl-static mdevd/skalibs with licenses and upstream HTML docs. Install, check and remove the package; parse valid symbolic-owner configuration and reject invalid regex inside a libc-free chroot with a private network namespace. The static-core image exercises readiness, coldplug and dinit integration; client libudev compatibility remains separate. - [x] Build an x86_64 static-core ISO through native package transactions, a private dracut sysroot and Limine. Audit initramfs payloads against the installed root and reject dynamic ELF. Boot with dinit as PID 1, BusyBox, mdevd/coldplug and a local package install/check/remove in QEMU. - [x] Select BusyBox, dinit, mdevd, glibc and musl from a pinned native source during image construction. Record each original hash and source ID, normalize the selected core packages, and preserve the source binding when the guest reinstalls libc from cache. The source-stage fixture and x86_64 two-boot ext4 QEMU contract pass. These inputs came from a disposable local catalog; a public Holy repository and i686 source-backed image remain open. - [x] Convert the five existing user-owned bootstrap archives into a sealed, unsigned source-ready catalog with root-owned manifests in a user namespace. Keep the original and converted hashes, source ID, index digest and an includable image config. Fresh namespace resolvers accepted all five x86_64 and i686 packages for read-only install plans. The image source stage records each i686 placement decision and fetched all five i686 core artifacts. Publication, signatures and i686 boot testing remain open. - [x] Accept a pinned native linux package as the image kernel input. Check its version, target architecture and extracted x86 boot header, install the original .holy with its source ID, and use its boot/vmlinuz for the ISO. An x86_64 ext4 image with five core packages from one source and linux from a second source passed the two-boot libc-removal/recovery QEMU contract. That first fixture kernel package contained the image without a module set. - [x] Package a matching 7.2.7 x86_64 dummy.ko and modules.dep with a pinned native linux artifact. The ELF scanner accepts its ET_REL payload only at a kernel module path with matching .modinfo vermagic; a mismatched release fails the fixture. A full x86_64 ext4 image passed two QEMU/TCG boots. On each boot, the guest checked the module hash, loaded it with finit_module and found dummy in /proc/modules; the second boot followed removal and recovery of both dynamic libc packages. General module dependency handling, i686 kernel modules and hardware drivers remain open. - [x] Add `make bootstrap-kernel` for an existing x86 kernel image and optional modules staging tree. It checks the boot header, modules.dep coverage, package manifest and ELF module facts, then records input and artifact hashes. Wrong architecture and missing modules.dep targets fail before publication. The generated linux.holy entered a pinned source catalog and passed the same x86_64 ext4 two-boot QEMU contract, including dummy load on both boots and libc removal/recovery. A kernel source recipe remains open. - [x] Extend that RAM profile with both dynamic libc packages and separate C probes. Boot present, glibc-missing, musl-missing and both-missing images under BIOS/TCG and UEFI/TCG. Restore absent payloads and loader links from cached .holy files inside the guest, verify broken-provider diagnostics, run allocation/thread/clock probes and pipe data between the two ABIs. The image audit rejects unexpected ldconfig aliases and undeclared dynamic ELF. Interactive on-disk installation remains open. - [x] Mount an ext4 root through static holy-init/BusyBox switch_root. Boot present, glibc-missing, musl-missing and both-missing disk fixtures with BIOS/TCG and UEFI/TCG. Restore libc, sync, reboot and repeat the full boot, dynamic/IPC and package contracts on the same qcow2 overlay. Separate boot marker sets prevent first-boot evidence from satisfying the second boot. Verify the read-only raw base remains unchanged; a missing disk fails with a device timeout instead of falling back to RAM. This is an ISO booting a prepared ext4 image, not an installed disk with its own Limine/ESP. - [x] Build a standalone GPT disk with a BIOS Boot partition, FAT32 ESP and ext4 root. Boot through Limine without a CD-ROM in BIOS/TCG and UEFI/TCG: present and both-libcs-missing cases each pass two complete boots, including cache repair, dynamic/IPC and package probes. The raw base remains unchanged. Kernel-update integration and holyinstall remain open. - [x] Mount the GPT ESP at /boot before starting dinit. BIOS/UEFI recovery runs each pass two boots with both libc payloads initially missing; the guest checks the mounted kernel manifest and a FAT write across reboot. - [ ] Resolve the glibc 2.42 upstream-check failures on the current host. The completed run has 6995 PASS, 4 FAIL, 89 UNSUPPORTED, 13 XFAIL and 7 XPASS. Failures concern mount-header redefinition, two invalid-I/O-flag tests and rseq registration-length assumptions. Boot recovery proofs do not establish a passing upstream suite. - [ ] Package Limine, dracut, kernel, firmware, SDK/sysroots and the default ConnMan+iwd network profile. Static local recovery and a private HTTPS recovery fixture have acceptance tests; production network recovery remains. - [ ] Complete C99 `holyinstall` plans for accounts, network, encryption and filesystem choices. The implemented blank-disk GPT/ext4/FAT path uses reviewed plans and `holypkg --root`; account login has a VM fixture. Config and text menu now bind selected artifacts to registered source IDs through frozen plan format 4 and retain that provenance at install. The live install fixture now carries its source config and artifact bindings into the target root, copies embedded pinned mirrors, and checks installed source records. A disposable-root fixture verifies source preservation and fetch after root relocation. A source-attributed full installed-disk VM run remains. - [ ] Implement `holygetiso` with explicit inputs, installed man bundle and a boot-validated ISO for each target architecture. The first in-tree C99 frontend now parses a single explicit local-input config, records its hash in the boot plan and drives the existing bootstrap/QEMU path. Additional relative includes now contribute to one frozen effective config; include cycles and duplicate scalar values fail before the build. Local .holy packages join its set plan and input record. Pinned holy-http sources now solve and fetch same-catalog dependency closures, register their source IDs in the image root and bind each fetched artifact in the set plan. An explicit sealed mirror supplies the same pinned generation offline. The builder includes a full verified catalog in the image root only with embed-mirror yes. That binding uses a root-relative path, so moving the built root preserves source lookups without forcing every ISO to carry an entire repository. `--export-inputs` now checks the build's input lock, then copies and verifies package inputs, mirrors and plans separately. The builder records direct host tool paths and hashes, but does not archive their dependency closure. The explicit build-only path records untested and exits 6. The local-input and sealed-mirror builds above pass full QEMU gates. Explicit cross-source choices and unique native provider discovery now work for additional image packages. Relocatable installation remains open. ## Acceptance gates - [x] Validate the x86_64 ext4 recovery matrix across present/glibc/musl/both initial states and BIOS/UEFI under TCG: eight cases, sixteen boots. The retained-evidence gate checks per-boot identity, restoration and package/IPC probes, hashes input snapshots and rejects incomplete or duplicate cases. This matrix uses an ISO kernel and persistent disposable root overlays. - [x] Run current prototype fixtures under GCC, TCC and Clang ASan/UBSan. - [x] Boot the i686 static core with kernel 7.2.7, BusyBox, dinit, mdevd and static holypkg from a BIOS optical ISO under QEMU/TCG. The guest checks PID 1, man bundle, device permissions and a local package transaction. The dual-libc disk boot gate is listed below. - [x] Boot an i686 BIOS dual-libc RAM ISO under QEMU/TCG with glibc and musl payloads absent at startup. The guest checks broken providers, restores both packages from cached native artifacts and runs C probes plus bidirectional pipes. The same fixture also checks a local package transaction. Separate present, glibc-only and musl-only initial-state runs are recorded in the build reports. - [x] Boot an i686 BIOS ISO with a persistent ext4 root under QEMU/TCG. With both libc payloads absent, the guest restores them from cached artifacts, reboots and verifies the restored libraries, package state and IPC probes. The present/glibc-only/musl-only ext4 cases use the same two-boot contract. - [x] Boot an i686 BIOS GPT disk independently under QEMU/TCG. The guest mounts its FAT boot partition, restores both libc packages, writes a boot-partition witness and verifies that witness plus package state after reboot. i686 UEFI and the interactive installer remain separate acceptance gates. - [x] Install the i686 static core from a BIOS live ISO onto a disposable GPT disk under QEMU/TCG. The guest formats FAT32 and ext4, applies the reviewed package set, creates a login account and boots the installed disk separately. The second guest checks dinit, holypkg, authenticated login and doas. The account menu, PAM/NSS, network and i686 UEFI remain untested by this gate. - [x] Boot a dual-libc RAM image with both libc archives absent from its cache and fetch their native artifacts over HTTPS from a QEMU fixture in a private network namespace. The guest uses static BusyBox ip and holypkg, verifies the fixture CA and artifact hashes, repairs both runtimes and runs dynamic/IPC probes. Guest DNS resolution and hostname-verified HTTPS are covered for both architectures; public CA and external network coverage remain open. - [x] On persistent ext4 QEMU roots, remove both dynamic libc packages through holypkg with an explicit broken-dependency decision, reboot into the static core, then reinstall both native artifacts from cache. Check broken-provider diagnostics, package state and dynamic/IPC probes after the second boot on x86_64 and i686. The i686 BIOS GPT case also boots independently from its FAT ESP and passes the same two-boot contract. - [x] Run `make check-root` against disposable target-root install, check, remove and recovery fixtures; this gate does not boot a system. - [x] Add a BIOS/UEFI `make check-qemu ARCH=... ISO=... BOOT_PLAN=...` runner with serial markers, ISO hash, QEMU argv, exit status, elapsed time and logs. Missing images return a requirement error; blank ISO fails both architecture fixtures via `make check-qemu-gate`. Cancellation reaps the guest and records failure. The x86_64 static-core ISO passes BIOS/TCG and UEFI/TCG boot contracts. - [x] Run `make check-install` against plan/apply/disk fixtures and a separate installed-disk VM gate in BIOS and UEFI. The VM gate covers disk preparation, installation, boot and account login. - [x] Add `make check-hardware` for a physical NVIDIA GPU bound to Nouveau: identify Mesa NVK, present Vulkan frames and measure accelerated OpenGL frames. Save commands, output and timings in a JSON report. A host-only diagnostic pass is labeled as such; the default Holy gate returns 6 without an installed Holy database. The present host probe passed on Slackware; no Holy hardware result is claimed. - [ ] Extend the QEMU runner to qcow2 trial overlays and per-probe timeouts/result channels. The runner now accepts self-contained raw and qcow2 input disks, copies either to a read-only base and boots a separate qcow2 overlay. Guest stage markers get independent configurable deadlines and per-stage reports with boot numbers; repeated markers in one boot do not renew a deadline. The default removes copied boot inputs and writable overlays after reporting; QEMU_KEEP=1 retains them for inspection. Live input copy consistency remains unverified; full `holypkg test PLAN` integration and the Holy hardware gate remain open. - [ ] Boot both target architectures in QEMU and prove PID 1, shell, package install/removal and recovery after removing either or both dynamic libc runtimes. - [ ] Run compiler/SDK, language, GUI, graphics, gaming, workstation and foreign source cases with pinned artifacts, logs, elapsed time and explicit coverage.