Prospective native build receipts¶
scripts/record_native_build.py is an opt-in public observer for a fresh
out-of-source CMake/Ninja build and install. It does not reconstruct the history
of cached binaries, enable runtime-slot reuse, or qualify a library by itself.
Existing build commands remain unchanged unless the observer is selected.
For the already-supported unpatched FFTW recipe, select the executable observer and a fresh existing receipt directory outside the repository/build/install:
export VIBEQC_NATIVE_BUILD_COLLECTOR="$PWD/scripts/record_native_build.py"
export VIBEQC_NATIVE_RECEIPT_DIR=/absolute/external/empty-receipts
export VIBEQC_NATIVE_SOURCE_ARCHIVE=/absolute/fftw-3.3.10.tar.gz
bash scripts/build_fftw.sh
Use the source archive matching the recipe’s exact SHA-256 pin. A cache hit stays
a cache hit and produces no fresh-build receipt. VIBEQC_NATIVE_SEED_CONTEXT=1
remains a separate opt-in to the conservative Darwin/Apple-clang context resolver
and FFTW adapter. Its existing compiler, SDK, ABI, dependency, source and
final-prefix donor-read-denied probes still apply; this observer bypasses none.
No extra build is needed just to produce a receipt: select it when a fresh build
is already required.
Record contract¶
The observer accepts record --spec SPEC.json --output RECEIPT.json -- COMMAND….
The spec has sources (name to source directory), authenticated_sources (same
names, each with archive, sha256, and archive prefix), recipes (file paths),
cmake_builds (configured directories), install, artifact_manifest, cwd,
and explicit data_sources. Each data entry maps an install-relative destination
to { "source": "source-name", "path": "source-relative-file" }.
FFTW uses its authenticated api/fftw3.h as include/fftw3.h.
An empty data map explicitly observes no runtime data; it must not be interpreted
as qualification of a library’s data requirements.
The vibe.native-build-receipt/1 output retains pre-build observations and command,
producer identity, return code, and the complete post-install inventory. Only
status=recorded with integer returncode=0 denotes a successful observation.
Failed commands and changed inputs leave a failed receipt; no automatic retry or
unobserved fallback occurs. Source archives plus declared exact replacement programs must match source files
before and after the command. Undeclared patches, source-tree generated files, archive links,
and compiler wrappers requiring transitive provenance are not qualified by this
contract. Output files must match the install manifest exactly. Selected installed
data must match its authenticated source bytes and mode.
The receipt explicitly fingerprints six categories in inputs.semantic_inputs:
Category |
Observed input |
|---|---|
|
Authenticated archives, pinned replacement programs and complete observed inventories |
|
Explicit recipe file bytes |
|
Configured compiler executable paths and bytes |
|
CMake cache, compiler commands, Ninja/install graphs, selected build environment |
|
Observed host system, architecture, OS/libc and byte order |
|
Explicit authenticated source data mapped to installed destinations |
These hashes are observations, not universal compatibility keys. They retain absolute producing paths and are deliberately conservative. The candidate adapter must independently resolve its context, normalize only justified relocation roots, attest transitive toolchain/dependency inputs, compare semantics and run native/data probes in the final prefix with donor reads denied. Merely comparing compiler versions, six hashes or output hashes is insufficient.
The generic observer can record supplied library specs with the restricted replacement contract below; automatic recipe integration and runtime-slot admission are limited to the conservative Darwin FFTW and patched-libxc routes documented here. There is no supported libint/OpenBLAS/libecpint/spglib seed adapter yet. Those libraries’ recipe, patch, ABI, data and isolated native-probe contracts still need implementation. No live dependency reuse is established by protocol tests.
Receipts can contain local paths and environment observations. Keep them outside product sources, installers and distributable source archives; do not publish them automatically.
Focused protocol controls (no dependency build):
python3 scripts/tests/test_record_native_build.py.
Authenticated exact replacements¶
An authenticated_sources entry may additionally contain transformations, an
ordered list of { "path": "/absolute/program.json", "sha256": "<trusted pin>" }.
Each program uses schema vibe.native-source-replacements/1 and a nonempty
operations list. Every operation has exactly path, before and after:
pathis a canonical contained source-relative file path.beforeis the exact prior{ "sha256": "...", "mode": 420 }identity, or null for an addition. It must match the archive inventory or preceding operation.afteris null for deletion, or{ "sha256": "...", "mode": 420, "content_base64": "..." }for a complete regular-file replacement. Bytes must match the declared digest; special permission bits and aliases are refused.
This is an exact replacement language, not fuzzy patch application. The caller must supply reviewed transformation pins prospectively. The observer verifies the mathematical relationship between archive and transformed tree and binds the program bytes before and after execution; it does not claim to have witnessed a historical patch command. An undeclared edit remains a refusal. A changed program during execution leaves a failed receipt.
Receipts with any replacement program use source_authentication.status equal
to archive_transformed. Existing unpatched receipts retain archive_matched
and their semantic fingerprint shape. The current FFTW seed adapter deliberately
refuses transformed receipts; this contract does not qualify a new library,
transitive dependency, compiler wrapper or live runtime reuse. In particular,
FFTW source version and exported runtime version remain distinct observations.
Multistage inputs and declared dependency closure¶
A stage may declare dependencies, mapping names to exact predecessor
{ "receipt": "/absolute/receipt.json", "sha256": "<trusted receipt pin>", "install": "/absolute/preceding-install" } entries. Every predecessor must be
an authenticated successful prospective receipt. Its complete installed inventory
must still match, before and after the new command. All predecessors referenced
by those receipts must also be explicitly declared with matching identities;
missing transitive edges, duplicate identities, cycles and changed outputs refuse.
The new install and receipt cannot overlap protected predecessor installations.
For generated source, declare generated_sources in place of an archive entry:
{ "generated": { "dependency": "generator-stage", "subdir": "include" } }.
The matching sources.generated directory must be exactly that predecessor’s
output subtree, with its complete files and modes unchanged. There is no fallback
from an unmatched archive to an assumed generated input. Installed data mappings
and compiler translation units use these same authenticated source inventories.
Such receipts use status archive_with_dependencies in source authentication,
and include the declared predecessor graph, input semantics, producer identities
and installed output inventories. This authenticates the declared graph; it does
not discover undeclared dynamic libraries, arbitrary compiler-wrapper behavior or
system include dependencies. Unknown historical receipts remain unqualified.
The existing FFTW adapter continues to reject these new receipt classes until a
library-specific semantic resolver and isolated final-prefix probe qualify them.
Grouped recipe disposition¶
Library |
Remaining source/lifecycle contract |
|---|---|
FFTW |
Existing unpatched Darwin context, serial/threaded native and header-data probe; actual fresh-build then slot reuse still required. Exported3.3.9 from pinned3.3.10 remains legitimate. |
libxc |
Patched Darwin source/SDK/options resolver and donor-denied native/header probe implemented below; actual fresh-build then following-slot acceptance remains required. |
spglib |
Bind its configured single-stage recipe and candidate ABI/native probe; no automatic admission from a generic receipt. |
libecpint |
Bind generated/multiple-stage inputs and separate build/install commands, then its relocated ECP data operation. |
libint |
Bind generator/generated-source stages and configured integral feature options; preserved historical installs cannot supply a fresh receipt. |
OpenBLAS |
Its Make-based build/install is outside this CMake/Ninja observer; add an actual Make/toolchain/options resolver and candidate BLAS operation. |
These are explicit dispositions, not declarations that the recipes already emit or consume the multistage contract. No missing receipt authorizes a cold rebuild.
Patched libxc on Darwin (opt-in)¶
The library-specific scripts/native_libxc_seed.py route handles Libxc 7.0.0
with the pinned stable-spin-fraction patch on the existing conservative
Apple-clang/system-runtime context. It does not enable Linux qualification.
Its source is the exact reproducible Git archive of the recipe-pinned upstream
commit, not a reconstructed archive of an installed or patched source tree:
git -C /path/to/authenticated/libxc-repository archive --format=tar \
--prefix=libxc-7.0.0/ 7bd5bb41415968db94c499a2f093309c9a2dcf53 \
> /absolute/libxc-7.0.0.tar
# Required SHA256: 6cb75c9315de67310a2ceb35f5984c107f795e1235de724d37ea028885f9cc55
export VIBEQC_NATIVE_BUILD_COLLECTOR="$PWD/scripts/record_native_build.py"
export VIBEQC_NATIVE_RECEIPT_DIR=/absolute/external/fresh-receipts
export VIBEQC_NATIVE_SOURCE_ARCHIVE=/absolute/libxc-7.0.0.tar
export VIBEQC_NATIVE_SEED_CONTEXT=1
bash scripts/build_libxc.sh
Use this only when a fresh dependency build is already authorized and needed.
Existing installs still follow the normal cache path and never acquire a fresh
receipt. The existing builder retains its lifecycle lock and original CMake
options. In this opt-in route it stages the pinned archive directly, without
Git administrative files; an existing different source tree (including a Git
checkout) is preserved and refused, never deleted or retrospectively qualified. The collector checks the archive’s complete source inventory against
three exact replacement operations generated from the tracked, recipe-pinned
patch. A successful build must preserve source, observer, recipes, compiler,
SDK/toolchain, configured options and generated config.h/xc_version.h.
The installed patch marker, complete install manifest, authenticated xc.h and
xc_funcs.h, and generated version header are checked before the exclusive
.vq-native-libxc.json envelope is written. Failure is retained; no fallback,
retry or retrospective qualification occurs.
Libxc’s upstream README and ChangeLog aliases require explicit
allow_sibling_aliases: true in the authenticated-source spec. This permits
only a sibling regular member of the same pinned archive; missing targets,
chains, directories, escaping paths and hardlinks remain refused. The default
archive contract and FFTW extraction still reject all links.
The Queue adapter command is python3 scripts/native_libxc_seed.py; it accepts
the existing plan/verify JSON protocol on stdin. The pinned source archive must
be available in the adapter environment. Planning extracts and applies the
same authenticated transformation, runs only candidate configuration and
compares actual source/patch/options/compiler/SDK/ABI semantics. Verification
requires unchanged donor and candidate manifests and runs the tracked
probe_libxc_prefix.py in a separate process with donor reads denied. It binds
all called symbols and the patch marker to the candidate image, reads the two
candidate headers, and checks unpolarized LDA exchange energy and potential at
two densities against the analytic expression. The probe binds its actual
library/header hashes before and after execution and scrubs loader overrides.
Missing donor paths never count as isolation. This is a bounded native/header
operation, not general libxc functional or gradient scientific acceptance.
The source route does not establish live reuse: the authorized fresh build and following-slot donor-denied acceptance remain required. Other library routes and Linux compiler/sysroot/loader closure remain outside this implementation.