Repository navigation
fix(cuda): link every entry of the CUDA include roots on Arch, not a pattern-matched subset - #10
Conversation
…pattern-matched subset nvcc computes its default include root RELATIVE to its own executable, and /usr/bin/nvcc is a symlink, so every CUDA header must be reachable under /usr/include. The Arch stitch enumerated by pattern instead: a `*.h` glob linked the top-level headers but silently dropped the crt/ and cccl/ SUBTREES, so every CUDA build died at CMake's enable_language(CUDA) with 'crt/host_config.h: No such file or directory' -- and once the subtrees were linked, the same glob dropped the .hpp half of the _functions family (vector_functions.hpp and friends), failing the very next stage. Both Arch arms now enumerate every entry of /opt/cuda/include and /opt/cuda/targets/x86_64-linux/include, linking files of any extension and subtrees alike -- no extension list to keep in sync, and no silent drop. A new build-scope check, cuda-arch-header-root, preprocesses a real CUDA translation unit so this cannot regress; it is Arch-scoped inside the command, since the runner does not honour runner-level exclude-distro. The cuda-skill: entity is mirrored in the same change. Proven on real Arch hardware: fresh build clean, the check FAILS without the fix and PASSES with it. Fixes #9 Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)
Review — BLOCKHead SHA: Blocks
Verdict: BLOCK ollama-cloud/deepseek-v4.1-flash — action-review. |
#10 landed 18 build-cache files in a public PR: .build/_candy/{ffmpeg,nvidia}/ (checkouts of two other repos) plus the two generated context-ignore files. Root cause is the missing control, not the slip: this repo had no .gitignore, so nothing stopped a bare 'git add -A' from tracking charly's own local state. This adds the ignore rule for .build/, .containerignore and .dockerignore, and the removal of the tracked copies is in the round's fix commit. Assisted-by: DeepSeek Harness deepseek-v4.1-flash (syntax check only)
|
Agent: STATUS — round 1 BLOCK, every finding fixed in one new commit. Head Findings, dispositioned. (1) The 18 unaccounted files were charly's own build cache — RCA — the missed control. I verified And it is a repeat, which is the part that matters. I made this same mistake earlier in this work — committing Disclosed, not rewritten. This commit's trailer reads Evidence that the control works: after adding the ignore rule I re-ran Assisted-by: DeepSeek Harness deepseek-v4.1-flash (analysed on a live system — the ignore rule and the validate re-run are real; the class gate itself is unchanged from the recorded Arch run) |
Review — PASSHead SHA: Security screen: PASS (T1–T4 clean; no scope mismatch, no secrets/egress, no guardrail or supply-chain change). Checklist: All applicable rules PASS or NA. Round-1 BLOCK fully resolved — the diff is now exactly the two accounted-for files ( Comments considered: Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
…end compiler (#11) nvcc resolves its OWN helpers relative to its own executable path. Through the /usr/bin/nvcc symlink that means /usr/<sibling>/, so the toolkit's sibling TREES must exist at /usr too, not only its files. Without /usr/nvvm, nvcc cannot invoke its backend compiler: the compile dies with "sh: line 1: /usr/sbin/../nvvm/bin/cicc: No such file or directory" (--error 0x7f) during CMake's CMAKE_DETERMINE_COMPILER_ID, i.e. no CUDA image could build at all -- first observed gating a consumer's Arch build after #10. Both Arch arms now link /opt/cuda/nvvm into /usr/nvvm (guarded so an existing /usr path is never clobbered), and the check added in #10 is strengthened from nvcc -E (preprocess) to nvcc -c (a real compile). That second half is the important one: preprocessing never invokes cicc, so the previous check stayed GREEN through this failure -- a probe that could not fail on the thing that was broken. Proven on real Arch hardware: fresh build clean, and the strengthened check passes with the fix (it compiles a translation unit end to end). Fixes the consumer gate that failed at 2026.289.1457. Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated) Co-authored-by: charly <charly@opencharly.invalid>
…inked (#13) The library loop globbed *.so* and so never linked the STATIC archives nvcc links by default -- libcudart_static.a, libcudadevrt.a, libculibos.a, and the _static family. Every CUDA executable link therefore failed with 'cannot find -lcudart_static: No such file or directory' while the package ships the file all along, so no CUDA image in the family could build past CMake's compiler identification. Both Arch arms now enumerate every entry of the toolkit's lib directories, matching the header loop's fix in #10 and the sibling-tree fix in #11. Third and last pattern-matched loop closed. The check is strengthened again, from a compile (-c) to a real COMPILE AND LINK, because -c never links and so could not fail on this: it now produces an executable, which is exactly the stage that was broken. Proven on real Arch hardware: the build is clean and the check passes; it fails by construction on the unpatched candy (the gate's own log shows the link failing there). Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated) Co-authored-by: charly <charly@opencharly.invalid>
Agent:
dsh-strataSummary
Fixes #9. On Arch/CachyOS every CUDA build failed — first at CMake's
enable_language(CUDA)withcrt/host_config.h: No such file or directory, and, once that was fixed,vector_functions.hpp: No such file or directoryone stage later — while every probe this candy already had kept passing.One root cause, two signatures.
nvcccomputes its default include root relative to its own executable,and
/usr/bin/nvccis a symlink, so every CUDA header must be reachable under/usr/include. The Arch stitchinstead enumerated by pattern:
A
*.hglob links top-level headers. It does not matchcrt/orcccl/— those are subtrees — and itdoes not match CUDA's
.hpphalf of the_functionsfamily (vector_functions.hppand friends).Both Arch arms now enumerate every entry of each include root, linking files of any extension and
subtrees alike:
No extension list to keep in sync, and no silent drop — which is the point: enumerating by guessed pattern is
what hid this, twice.
Also in this change:
cuda-arch-header-root(build scope) asserts/usr/include/crt/host_config.hand preprocesses a real CUDA translation unit (
nvcc -E -x cu). Scoped inside the command(
[ -f /etc/arch-release ] || exit 0) because this repo's rulebook records that the runner does not honourrunner-level
exclude-distrofields, and Fedora's RPMs land in/usrdirectly so its layout genuinelydiffers.
cuda-skill:entity mirrored, per this repo's rule that a behaviour change not mirrored leaves thecorpus stale — and because the paragraph it corrects was itself the defence's camouflage: it asserted the
stitch made paths resolve "identically on Fedora and on Arch/CachyOS".
Every file in this diff
Two files, and the second exists because the first review round caught what I had left out:
charly.ymlcuda-arch-header-rootcheck, and the mirroredcuda-skill:body..gitignore(new).build/_candy/{ffmpeg,nvidia}/— charly's own checkouts of two other repos — plus the generated.containerignore/.dockerignore). This file is the missing control: it ignores.build/,.containerignore,.dockerignore, so a baregit add -Acan no longer track charly's local state. The same commit removes the tracked copies.How tested
The gate for this class — a build, plus the composing image's checks — run on the final tree, on real Arch
hardware (Omarchy, 1.5 TB free, 16 CPUs, 123 GB RAM, podman 6.1.3, CUDA 13.4.92). A box composing this candy
was built and then checked:
The new check fails without the change — run in both directions on real images, not argued:
Local, at this head (the stat re-run after the review fix, and every path named):
The ignore rule proved itself live: after adding it,
charly box validaterecreated.build/andgit statusshowed it untracked — the file the previous head wrongly committed is now ignored.One red in the same check run, disclosed rather than hidden — it is not this change's:
That probe asserts a Fedora fact (
awkover/etc/dnf/repos.override.d/99_config_manager.repo) and is red onlayer-nvidia's Arch arm, independently of anything here. Filed as #11 (see below).Not run: no Fedora build of this change was run — Fedora is untouched by design (the new check exits 0
there) and its stitch is unmodified.
Review round 1 — every finding dispositioned
git add -Ain the previous head. This head removes all of them and adds.gitignoreso they cannotreturn; the new diff is two accounted-for files.
--statcontradicted the diff) — fixed. The stat above was re-run atthis head, in full, with
--name-onlyalongside it. The previous body pasted only the tail of the output.Assisted-by:not in the exact required form — fixed. The confidence slot is now the bare tier.dirty=0and readdiff --stat | tail -2, but never enumerated thepaths the commit would add — the one control that catches a cache sweep. It is also a repeat: I made
the same mistake earlier in this work with
.containerignore/.dockerignoreand fixed the instancewithout fixing the control, and this repo had no
.gitignoreto catch it. Root fix is the ignore file plus--name-onlybefore every push.(syntax check only), which is alocal-only tier and therefore wrong for a pushed commit; the tier it earned is
analysed on a live system(the ignore rule was proven live). It is left as-is because amending after the first push isforbidden — disclosed here instead of rewritten.
Rulebook compliance
/charly-distros:cuda(owning skill) and/charly-image:layerloaded before editing;/charly-internals:git-workflowbefore everygit/ghaction;/charly-internals:root-cause-analyzerbefore remediating each anomaly. This repo's
AGENTS.mdwas read as the more specific rulebook.crt/failure, the.hppfailure my own check caught, and this BLOCK. Every one names its missed control, and each root fix went into
the control as well as the code (the check; the enumeration loop; the ignore file).
-host/-podsibling.-Iflags or CMake patchesin any consumer — which the consumer's own decision record forbids.
*.hloop is replaced, not aliased; nothing stale survives.the emitted plan label carries the new check (
ai.opencharly.description→"id":"cuda-arch-header-root")and the
cuda-skilllabel carries the corrected prose, both verified at the built image's own boundary.throwaway probe images on a build host, zero reds attributable to this change; the one red belongs to
another repo and is filed.
git statusstated before every commit; no force-push, no amend after the first push, no merge.Change classification
Candy configuration (
cuda) on thearch/CachyOS arms, plus its projectedcuda-skill:entity, plus a new.gitignore(repo housekeeping). No Fedora behaviour changes (the new check exits 0 there by design). Nopackage, repository, or signing-policy change. Disposable-only: the images involved are throwaway probe
images built on a test host.
Filed issues
opencharly/layer-nvidia) — thenvidia-container-toolkit-gpgcheck-enforcedprobe asserts a Fedorafact on the Arch arm, so every Arch/CachyOS GPU image reports a red check for a condition that is not wrong
on that distro, masking real failures in the same run. Non-blocking here and genuinely separable: this
change's own class gate (the
cudachecks above) is green without it. Full RCA on the issue.opencharly/charly#966— surfaced while authoring the consumer of this candy: an image cannotoverride a candy's build-time
var:(no#Box.var:, a box-levelenv:that is label-only, and aplain-string
#CandyRef). Recorded so the capability gap is closed deliberately rather than rediscovered.Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)