_ _
| |_ ___| |_ _
| | . | | | |
|_|_|___|_|_ |
|___|
git mirror - github.com/owenewans/holy - branch master
file docs/roadmap.md
# 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.