Build, test and qualify
Run these commands from the sima-neat/kernels repository root. CMake 3.21+, a C++20
compiler, Python 3, file, and a Linux environment are required. The A65 profile
also requires an AArch64 SDK/toolchain; executing its tests requires a connected
DevKit. EV74 licensed
compilation is separate; see EV74 (EV74/README.md).
Production presets require GCC 16.2 or later in the GCC 16 series and matching
libstdc++ 16 headers and libraries. Native builds select gcc-16 and g++-16;
A65 and EV74 host builds select aarch64-linux-gnu-gcc-16 and
aarch64-linux-gnu-g++-16. Set both CMAKE_C_COMPILER and
CMAKE_CXX_COMPILER to absolute paths for a differently named GCC 16 installation.
Set SIMA_GCC16_ROOT to a private GCC 16 installation prefix to use its native
or cross drivers without changing system compiler alternatives. GCC supplies its
C++ headers and runtime; the A65 sysroot supplies target C headers and platform
libraries. Older SDK C++ headers and libraries must not override GCC 16 providers.
Rebuild C++ consumers with a compatible SDK/runtime cohort; C++20 alone does not
provide cross-compiler ABI compatibility. EV74 device code still uses MetaWare.
Portable documentation/source checks may use a direct CMake configuration with
another C++20 compiler; they do not qualify the production GCC 16 toolchain.
Local and CI production presets share the same GCC pre-check. If no compiler or
prefix is explicitly selected and GCC 16 is missing, configuration downloads the
SHA-512-pinned GCC 16.2.0 release and builds it in a private cache. It verifies the
upstream prerequisite checksums, serializes installation and publishes the prefix
only after a C++20 compile/link check. The first build can take tens of minutes;
later builds reuse it. Set SIMA_GCC16_CACHE to a persistent cache directory or
preinstall the compiler in your SDK image. Set SIMA_GCC16_AUTO_INSTALL=OFF for
offline builds. Explicit compiler selections are never silently replaced.
The existing target C SDK, bootstrap GCC/G++, Make, binutils, zlib development
headers and wget/curl remain prerequisites; no sudo, system alternatives or device
runtime installation is performed. MetaWare is never downloaded by this helper.
Build and package the installed SDK
From the repository root in the development container:
cmake --preset a65 -DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=lib/aarch64-linux-gnu -DBUILD_TESTING=OFF
cmake --build --preset a65 --parallel 4
DESTDIR="$PWD/dist/sdk" cmake --install build/a65
python3 dist/sdk/usr/share/SimaKernels/tools/package_metadata.py verify \
--prefix dist/sdk/usr
python3 dist/sdk/usr/share/SimaKernels/tools/package_metadata.py deb \
--prefix dist/sdk/usr --output dist/simaai-kernels-dev.deb
Use a fresh staging directory and DEB destination. The A65 preset needs its SDK
sysroot and cross compiler; set SIMA_A65_SYSROOT when the default does not apply.
These commands build the default target and stage an installed SDK without
executing tests, compiling licensed EV device code,
installing into a system sysroot or deploying to a board. BUILD_TESTING=ON
also compiles registered tests; qualification remains a separate step.
One Kernels-owned producer records usr/share/SimaKernels/buildinfo.json at the
end of CMake installation. It verifies configuration/build completion, dirty and
untracked source contents, compiler/toolchain identity, installed public headers
and the complete installed payload, including file modes and relocatable links.
The installed tool projects that exact SDK into a DEB without recompilation.
Source/configuration changes require reconfiguration and a completed default
build before installation; hashing stale objects is not a replacement.
This is build identity, not a clean-build or numerical/device qualification
receipt. External sysroot/cache inputs remain trusted and immutable; their full
contents are not a hermetic attestation. The C++ ABI is not cross-version stable.
Runner and Core consume this installed tree through SimaKernels_DIR; they must
not include this checkout's private sources. Their top-level build can invoke
the same CMake build/install producer and compose deployment once afterward.
An implementation-only change can reuse a contract-compatible Runner package,
but static consumers must relink to use the new numerical implementation.
An optional ownership/staging wrapper delegates to this same producer; it does
not require build.sh or create a competing receipt. For example:
python3 tools/build_local.py --profile host --all --package-dir dist/host-package
It supports --build-dir, --package-dir, --toolchain, --jobs and --clean;
cleaning/replacement requires its ownership markers. A failed build returns
failure and preserves the previous package, which is not the failed build's
result. Build/staging outputs cannot overlap protected source inputs. The host
profile excludes A65-specific operations and cannot satisfy an AArch64 Runner
dependency. Use the qualification commands below for test execution.
Choose the execution profile
| Profile | Scope | Execution |
|---|---|---|
host | All registered portable operation suites; excludes A65-specific BoxDecode | Development host; not A65 qualification |
a65 | All registered A65 operations | AArch64 target; cross builds automatically use dk |
ev74 | Public EV74 contracts/codecs only; no A65 libraries or tests | AArch64 SDK packaging profile; not device qualification |
host-sanitize | All registered portable correctness suites with ASan/UBSan | Development host; no latency timing |
cmake --preset a65
cmake --build --preset a65 --parallel
ctest --preset a65
The A65 toolchain defaults to /opt/toolchain/aarch64/modalix. Override
SIMA_A65_SYSROOT at configure time for another matching SDK installation.
Presets clear inherited compiler flags so an SDK shell does not accidentally
turn a host build into an ARM build.
cmake --preset host
cmake --build --preset host --parallel
ctest --preset host
cmake --preset host-sanitize
cmake --build --preset host-sanitize --parallel
ctest --preset host-sanitize
The host presets explicitly empty inherited SDK compiler selections, toolchain
paths and compiler/linker flags. Use a
fresh build directory when switching environments: CMake retains flags already
stored in its cache. Explicit -D compiler flags still apply, and the sanitizer
preset retains its instrumentation. Target presets keep their SDK toolchain.
The selected profile and host architecture determine local or DevKit execution;
an incompatible executable is rejected by the operating-system loader. Cross
execution sources ~/.devkit-sync.rc, uses dk and SCP to stage an isolated
temporary directory, collects reports, and removes that directory. It never
replaces installed device software. Matching sanitizer libraries are staged when needed; use
SIMA_KERNELS_TARGET_RUNTIME_DIRS if the compiler cannot locate them.
All launches share a device-side lock. CTest also runs latency tests serially. Do not run applications or unrelated benchmarks concurrently on that device. The lock coordinates this test launcher, not every possible device process.
Default test coverage
Every A65 operation has one generic correctness executable and one latency executable
under A65/<operation>/tests/. Correctness covers many shapes, dtype/layout
combinations, invalid requests and buffer safety, with independent references.
Latency is built and registered by default—no environment opt-in is required.
CTest fixtures require correctness to pass before timing that operation.
Local default timing uses the full catalogue, 100 samples, 20 warmups, and CPU affinity. Reports distinguish preparation, first execution and steady-state percentiles. For BoxDecode, context preparation is reported separately. Reports and artifact hash sidecars are written in the build directory; they are not source assets.
# Only correctness; this is not full latency qualification.
ctest --test-dir build/a65 -L kernel-execution --output-on-failure -j1
# One operation: its correctness fixture runs before latency.
ctest --test-dir build/a65 -R '^a65_quant_latency$' --output-on-failure -j1
Useful CMake settings are SIMA_KERNELS_LATENCY_SAMPLES,
SIMA_KERNELS_LATENCY_WARMUP, SIMA_KERNELS_LATENCY_CPU and
SIMA_KERNELS_LATENCY_SUITE. A smoke suite is only a development subset.
Latency timing requires Release or RelWithDebInfo; use the correctness label
for an ordinary Debug build. Sanitizer builds deliberately do not register
latency timing tests.
Representative CI and full qualification
The existing backend build workflow selects representative on pushes. Manual
test_suite: full and weekly validation use the same builders, artifacts and
hardware lanes. Both profiles retain the latency sample policy and median
allowances. A representative result is not full release qualification.
| Layer | Every push (representative) | Weekly/manual (full) |
|---|---|---|
| A65 native correctness | Complete independent numerical and safety suite | Same complete suite |
| A65 native latency | Deterministic implementation/storage boundaries; BoxDecode retains its complete catalogue | Complete catalogue |
| EV CPU contracts and source models | Bounded contract, binding, dispatch, layout-golden and instrumented source-safety witnesses | Complete CPU numerical domains and Cartesian catalogues |
| Real EV correctness | Complete native catalogue, including camera-format, ROI, conversion-boundary and tail panels | Same complete catalogue |
| Real EV latency | Existing default, supplemental and extended catalogues | Same catalogues |
The CPU gate answers a small set of engineering questions: does admission reject bad requests before writes, does binding preserve addresses and capacities, do wire dispatch and worker partitions agree, and do source-model DMA dependencies, tails, holes and retained buffers stay safe? Each operation selects small witnesses for its mechanisms, not every combination of numerical values and large shapes. Instrumented source models remain necessary: device output comparisons alone do not prove absence of out-of-span reads or premature scratch reuse.
Real EV tests own broad device numerical correctness. Full CPU mode retains the exhaustive independent references, input-bit domains and scheduling cross-products for weekly validation and focused debugging. Neither mode changes production math, numerical tolerances, worker dispatch or latency baselines.
Run an existing executable from the repository root on the development host:
# Host-profile build only; not A65 target qualification.
python3 tools/run-kernel.py --profile host \
--binary build/host/tests/a65_quant_benchmark -- \
--suite representative --list-cases
# CPU source model, not real EV execution. Omit --suite for the full default.
python3 tools/run-kernel.py --profile host \
--binary build/host/tests/ev74_quant_contract -- --suite representative
Use the architecture-safe launcher for AArch64 builds; never execute them locally on x86. Unknown suite arguments fail. Standalone expression probes also receive the explicit CI profile where they have broad numerical loops.
EV CPU logs emit timed MODEL_STAGE records and one MODEL_COMPLETE summary
with completed sections and actual source-model execution counts. CI rejects
missing sections, incomplete stages, the wrong suite or zero source-model work;
metadata-only local builds cannot satisfy this gate. Reports retain these records
and aggregate CPU-phase elapsed time separately from native execution. This is fixture-owned
coverage evidence, not an independent per-shape or EV-ISA attestation.
CPU checks run under exclusive ownership before candidate firmware is loaded. Native tests start only after all CPU checks pass, with the same validated artifacts and ownership scope. Firmware is restored and hash-checked after every activated trial. CPU failures report firmware not loaded, not successful restoration. The existing suite deadline remains unchanged; excessive test cost is not fixed by increasing the timeout.
The weekly scheduler must be installed on main, the default branch. It dispatches
build.yml on develop with test_suite: full, an empty compare_base (both
backends) and validation_only: true. That option retains run artifacts but skips
branch publication and promotion. The scheduler records the dispatched run and
its source commit; follow that run for acceptance. A scheduler pass is not a test
pass. Manual full validation uses the same inputs. Release qualification still
requires full coverage and reviewed baseline evidence.
Check shape families with reproducible randomness
The family generator varies real fixtures, not kernel dispatch or numerical code. A65 unary latency executables and the EV74 Cast, Quant, QuantTess and Preproc device fixtures expose family mode. Original default catalogues and regression gates remain unchanged.
Choose one seed for a complete list/measurement pair; use different recorded seeds in later trials to avoid optimizing only a fixed set of shapes:
SEED=$(python3 -c 'import secrets; print(secrets.randbits(64))')
mkdir -p build/family
python3 tools/run-kernel.py --profile a65 \
--binary build/a65/tests/a65_dequant_benchmark -- \
--suite family --family-seed "$SEED" --family-count 2 --list-cases \
> build/family/cases.log
python3 tools/run-kernel.py --profile a65 \
--binary build/a65/tests/a65_dequant_benchmark -- \
--suite family --family-seed "$SEED" --family-count 2 \
--samples 100 --warmup 20 --cpu 0 \
--output build/family/summary.csv --raw-samples build/family/raw.csv \
> build/family/run.log
python3 tools/family_generator.py --operation dequant \
--catalogue build/family/cases.log --log build/family/run.log \
--report build/family/summary.csv --raw build/family/raw.csv
For EV74, use the existing exclusive firmware-qualification procedure to run the
matching device fixture with --list-family-cases and --family-latency-only,
using the same --family-seed and --family-count. Feed the saved catalogue and
full measurement log to the same checker, with --operation and without
--report/--raw. Cold listing does not connect to EV or allocate device buffers.
Each anchor retains its dtype, arithmetic parameters and storage policy. Spatial
axes receive joint doubling/adjacent probes, independent-axis doubling/adjacent
probes when multiple axes are selected, and seeded random siblings, usually
between half and twice their original extents. Tile-residue and camera bounds can
constrain that interval; tiny axes use a wider bounded interval to produce
distinct siblings. Unselected channels, rank and batch axes stay unchanged.
Preproc reconstructs source/ROI/destination geometry and required YUV parity;
real device-bound rejections are recorded separately, never counted as passes.
--family-count means random siblings per anchor, in addition to fixed probes.
An exhausted random range fails explicitly rather than silently reducing coverage.
The default seed is fixed; the command above selects a fresh reproducible trial.
A65 family mode additionally crosses physical layouts with unit, ordinary and subnormal coefficients, applicable zero-point extremes and both Dequant output dtypes. Its pointwise permutation anchors also include different input/output physical orders: only compatible orders may be flattened. These extra anchors do not change the default latency catalogue or its baselines. An anchor's siblings retain its parameters; independent parameter profiles are distinct anchors, not a claim that one arithmetic leaf handles every parameter.
The checker compares each sibling with its original anchor measured in the same
invocation. For growth, the reference is anchor_median × new_work / anchor_work;
for shrinkage, it remains the anchor median because fixed invocation cost does not
shrink with tensor size. It then applies the existing 5% relative allowance and
applicable A65 absolute floor once, without altering raw medians or existing
baselines. Work units are declared: A65 logical elements, EV tensor accessible
input/output spans, or Preproc output pixels. Accessible spans include declared
holes/padding and are not measured DMA traffic. Pixel scaling is a workload
budget, not a guarantee that source reads, interpolation or memory traffic scale
linearly. A failure calls for investigation, not a new special case or waiver.
Cold identities/descriptors, seed, completion counts and all chronological samples must agree. Missing anchors, truncated runs, filtered evidence and incorrect statistics fail closed. Family checks do not replace operation-specific absolute latency limits or matched-baseline qualification. Large siblings can legitimately need a larger proportional budget; that alone does not prove a physical limit. Operation-specific extra callbacks are still covered by the original tests, not automatically shape-varied by the shared A65 visitor.
Investigate repeatability without changing the gate
Use tools/paired_latency.py when an unchanged or improved kernel produces
inconsistent p50/p95 results. It collects the full catalogue in predetermined
ABBA and BAAB order; A is the frozen baseline and B is the candidate. Both
executables must use the same benchmark harness and support --raw-samples.
Reserve the DevKit for the complete experiment: the launcher lock covers each
invocation, not unrelated applications or the entire sequence.
python3 tools/paired_latency.py collect --operation cast \
--baseline-binary /absolute/path/to/baseline/a65_cast_benchmark \
--candidate-binary /absolute/path/to/candidate/a65_cast_benchmark \
--output-dir /absolute/path/to/new-empty-experiment \
--rounds 2 --samples 100 --warmup 20 --cpu 0
The tool keeps every run and raw sample, verifies exact catalogue and workload
identity, checks executable and explicitly staged dependency hashes, and checks
that raw observations reproduce the reported percentiles. Use
--baseline-runtime-dir or --candidate-runtime-dir for explicitly supplied
target shared libraries.
This does not certify the complete system-library dependency set.
A successful diagnostic deliberately returns INCONCLUSIVE (exit 3), not a qualification pass. Its repeated-increase/decrease labels describe observed block directions, not statistical confidence bounds or proof of causation. Missing or incompatible evidence returns exit 2. No cases, unfavorable samples, or gate failures are silently removed. The strict acceptance rule below is unchanged; noisy equality cannot establish zero-margin equivalence.
CPU placement is part of the measurement contract
Record the complete allowed CPU mask and physical-core/SMT topology, not only a
logical CPU number. For example, logical CPUs 2,3 can be siblings on one
physical core rather than two independent cores. Verify the target topology;
CPU numbering is not a portable placement rule.
For Runtime-to-EV74 measurements, submission and completion also involve host threads. Allowing the caller and service worker to move between SMT siblings can change wakeup, cache and resource-sharing behavior without changing kernel math. A fixed single-CPU mask is a useful diagnostic control, not a universal latency or throughput recommendation. Test the intended deployment's concurrency too.
Compare baseline and candidate with the same complete mask, thread-placement policy, frequency policy and workload. Keep a changed-mask experiment as a separate cohort with its own control and candidate runs. Do not selectively replace slow rows, relax the default median gate or relabel a new mask as a kernel optimization. Report host process CPU time separately from wall latency; affinity alone does not measure CPU utilization.
Measurement versus qualification
Without a baseline, a passing CTest run establishes correctness and successful
measurement, not absence of latency regressions. The qualify target refuses
to succeed without all required current-native baseline reports.
Supply a reviewed baseline directory containing a65-<operation>-latency.csv
for every operation. Capture baseline and candidate using the same benchmark
harness, full case catalogue, compiler/build configuration, device, CPU,
frequency policy, warmup count and sample count. The baseline is the current
optimized native implementation—not an old plugin implementation.
cmake --preset a65 -DSIMA_KERNELS_BASELINE_DIR=/absolute/path/to/native-baseline
python tools/qualification_provenance.py build --build-dir build/a65 --parallel 2
cmake --build build/a65 --target qualify
Run the provenance build command standalone, never from a target in the
same active CMake build. It reconfigures the existing build directory, performs a
clean build of all registered contract/benchmark pairs, and writes
qualification-build.json only after success. This avoids stale objects after
restoring source files with preserved modification times. Ordinary development
builds remain incremental; only qualification requires this clean-build receipt.
The qualifier checks current source content, configuration, compiler identity and
every registered correctness/latency executable hash against the receipt before tests and again before
reporting success. CTest commands must select those exact executable paths.
Missing or changed evidence fails closed; the qualify target never recursively
cleans or automatically blesses existing binaries. To inspect provenance without
running tests, use python tools/qualification_provenance.py verify --build-dir build/a65.
Use an isolated source/build workspace with no concurrent editors or builds. The receipt tool serializes its own operations, not unrelated build commands. Keep external compiler components, the sysroot and compiler-cache configuration immutable and trusted, or disable the compiler cache for qualification. The receipt hashes project production/public headers, test/harness sources, CMake inputs and tools, plus the configured compiler executable and toolchain file; it is not a hermetic dependency-closure attestation or protection against forged receipts. Source symlinks are rejected rather than silently omitted. A failed or interrupted clean build cannot reuse an older receipt. Rebuild the receipt after changing any covered input or artifact; do not regenerate it by merely hashing existing outputs.
Qualification runs all registered correctness and latency suites. The median budget
uses the recorded baseline unchanged, with a checked-in 1.05 reference-budget
multiplier applied once before the existing allowances. A case passes when
candidate_p50_us <= reference_p50_us + allowance_us, including equality.
Every case retains its 5% median allowance. Dequant also retains its absolute
0.10 µs (100 ns) floor; the seven cases below retain 0.05 µs (50 ns) floors.
reference_p50_us = 1.05 * measured_baseline_p50_us
allowance_us = max(0.05 * reference_p50_us,
operation_absolute_floor_us,
case_absolute_floor_us)
limit_p50_us = reference_p50_us + allowance_us
The allowances are combined with max, not added. The fixed absolute floors
are not scaled. Unlisted floors are zero. A 100 µs baseline has a 105 µs reference
and 110.25 µs limit. Dequant at 0.12 µs passes up to 0.226 µs
(0.126 + 0.10); at 10 µs it passes up to 11.025 µs, not 11.125 µs.
The multiplier is the normal default policy, not an environment opt-in. It does
not rewrite reports, inflate raw samples, or accumulate across repeated comparisons.
| Operation | Exact case ID | Allowance |
|---|---|---|
| Argmax | s0/t2/layout2/axis0/p0 | 0.05 µs |
| Argmax | s4/t1/layout3/axis5/p1 | 0.05 µs |
| Argmax | short/n16/t2/layout0/axis1/p1 | 0.05 µs |
| Argmax | short/n22/t1/layout0/axis1/p1 | 0.05 µs |
| Argmax | short/n6/t3/layout0/axis1/p2 | 0.05 µs |
| BoxDecode | yolo26/scan-HW3-C255-tile16/int8/layout2/rank6/K16/sparse/h0/a0 | 0.05 µs |
| BoxDecode | yolo26/scan-HW3-C255-tile32/int8/layout2/rank6/K16/sparse/h0/a0 | 0.05 µs |
These are explicit acceptance tolerances, not measured timer resolution or proof
that an increase is noise. They do not change kernel arithmetic, numerical
correctness tolerances or baseline measurements. Passing within tolerance does
not prove an observed increase is noise or that the kernel became faster.
tools/compare_native_latency.py owns the policy and prints each applicable
allowance. CTest passes --operation to select the operation's policy; manual
comparisons that omit it still apply the 1.05 reference multiplier and common
5% relative allowance, without operation/case absolute floors.
Only p50 is a latency regression blocker. Preparation, context preparation, first execution, mean, minimum, p95, p99 and maximum remain in reports for diagnosis; increases in these statistics do not fail the regression tests. CTest explicitly selects p50 and the matching operation, and the qualifier rejects registrations that change this policy. Missing/extra cases, malformed data, incompatible workload/device metadata and insufficient samples still fail closed, as do correctness failures. Source and executable hashes identify the artifacts but are not equality keys: candidate artifacts are expected to change.
Timing noise is not an automatic exemption. Investigate failed cases on an idle, thermally stable device; retain complete repeated runs outside the source tree. Do not selectively replace slow rows or call a partial catalogue a full qualification. Threshold changes require a reviewed, checked-in policy update and matching documentation; they are not performance improvements.
Consume the installed library
cmake --install build/a65 --prefix /absolute/path/to/sima-kernels-install
In your CMake project:
find_package(SimaKernels CONFIG REQUIRED)
target_link_libraries(my_application PRIVATE SimaKernels::a65_quanttess)
Configure a native application with CMAKE_PREFIX_PATH pointing at that
installation. For an external A65 install, pass the matching toolchain and the
exact package directory: the SDK deliberately restricts implicit package searches
to its target sysroot.
cmake -S /path/to/application -B /path/to/application-build \
-DCMAKE_TOOLCHAIN_FILE="$PWD/cmake/toolchains/a65-linux.cmake" \
-DSimaKernels_DIR=/absolute/path/to/sima-kernels-install/lib/cmake/SimaKernels
Use your configured install library directory instead of lib if customized.
Fused operation dependencies are transitive.
A65 BoxDecode is exported only by an A65 build. The package_consumer CTest
installs, relocates and builds an external shared-library consumer to verify
exported headers, transitive dependencies and position-independent archives for
all installed A65 operations and all fourteen EV74 host codecs. Linux GNU/Clang
shared links also reject unresolved references. This checks host codecs, not EV74
device archives; it is a build/link check, not an execution qualification.
The public API is experimental; package version 0.1.0 is not a stable ABI promise.
Versioned find_package requests therefore require an exact package version.
See calling kernels, the support matrix
and each operation's README for contracts, C++ call snippets and links to real tests.
EV74 feature and tracking acceptance
The ordinary host build includes typed admission, descriptor and mock-dispatch
checks for Histogram, FAST and FAST+BRIEF. Unsanitized, non-cross-compiling host
builds with Clang add actual OpenCL expression models with checked host DMA and
independent oracles. The entire ev74_tracker_contract suite requires that same
configuration; a passing build without it is not Tracker contract acceptance.
Neither these models nor a successful private MetaWare build establishes target
correctness.
Each family has a standalone EV74/<operation>/tests/e2e/ project consuming
installed Runtime/Kernels packages. Its default device invocation checks
correctness and measures latency; it is not an automatic host CTest run.
Firmware capability verification, device ownership and per-in-flight workspace
are explicit prerequisites. Use the private EV74 workflow and
operation pages for the accepted case catalogue and numerical rules. Keep
correctness, compiler checks, latency measurement and baseline qualification
separate in reports. No fresh target qualification is implied by host CI.
The protected qualification workflow routes A65 and EV74 independently. An
EV74-only change builds no A65 qualification package: its device artifact contains
native packages and matching firmware, while an AArch64 ev74 profile supplies
only public EV74 host contracts/codecs plus a separately packaged AArch64 test harness. The
device receipt is accepted only when all 14 operation families represented under
EV74/<operation>/tests/ have individual passing report files whose hashes are recomputed.
Qualification completes before sima-cli packaging and publication. The harness
is not an installation component. When both backends are selected, both lanes run
and the published sima-cli package definition has
scope: combined; a single-backend package names the included and omitted
component explicitly.
Native archives include their kernel-owned registration sources and native
headers. Firmware composition uses those verified package contributions, not a
second operation catalog from Runtime. The pinned Runtime/platform source asset
must support SimaKernels_FIRMWARE_DIR, SimaKernels_NATIVE_INCLUDE_DIR and
SIMA_RUNTIME_BUILD_DEVICE_TESTS. The EV-only harness enables the guarded device
targets without the mixed A65/EV host suite; all 14 EV numerical families remain
required. Optional A65 shared-buffer cross-checks are reported as not built for
this package, not as EV passes. Older
assets fail before platform compilation. Updating local source does not update
that private artifact: publish the reviewed matching source bundle and update
deps/ev74-device.json with its asset identity and checksum before enabling this
candidate in remote qualification. Never fall back to an older operation table.