diff --git a/.claude/skills/new-module/SKILL.md b/.claude/skills/new-module/SKILL.md index 5473176..71dff26 100644 --- a/.claude/skills/new-module/SKILL.md +++ b/.claude/skills/new-module/SKILL.md @@ -102,6 +102,10 @@ There is **no `--dry-run` and no `--check-mode`** — to sanity-check config/pat `du -sh /opt/psi/MX//` from a second shell; don't kill a healthy build. - modbuild runs hooks with `pipefail` + `nounset`: `yes | cmd` fails (SIGPIPE) — use `printf 'y\ny\n' | cmd`. +- **Never `cp -a` / `cp -p` into `$PREFIX`**: chown is refused on `/opt/psi`, so every + file logs `failed to preserve ownership ... Permission denied` and cp exits non-zero + (olex2 2026-10: 12k-line log, die-guard aborted a healthy copy). Use + `cp -r --preserve=mode,timestamps,links src/. "$PREFIX"/` (or tar pipe / `install`). - modbuild has **no errexit in hooks**: a failed command scrolls by and the build still prints "done", installing the modulefile over a broken PREFIX. Guard every critical hook step with `|| std::die 42 ""` and end `install` with an diff --git a/olex2/build b/olex2/build index 193b429..b55ec68 100755 --- a/olex2/build +++ b/olex2/build @@ -38,7 +38,11 @@ pbuild::install() { local -r src="${SRC_DIR}/olex2" # 1. vendor tree, flat into $PREFIX (= BaseDir). Slow on /opt/psi: 12k files. - cp -a "${src}/." "${PREFIX}/" || std::die 42 "olex2: copying the vendor tree into ${PREFIX} failed" + # NOT `cp -a`: on /opt/psi chown is refused, so -a ends with thousands of + # "failed to preserve ownership ... Permission denied" and a non-zero exit + # (that killed the first build). Keep mode/timestamps/links only. + cp -r --preserve=mode,timestamps,links "${src}/." "${PREFIX}/" || \ + std::die 42 "olex2: copying the vendor tree into ${PREFIX} failed" # 2. zip loses nothing, but make sure the ELF binaries are executable and # everything is world-readable on the shared install