pr-smoke failed on all three platforms: the binary's install/uninstall render templates from the integration asset, and every place that stages the binary without the asset made those operations fail closed with "integration assets missing". The asset must travel with the binary in EVERY layout, not just the release archive. Five staging paths were missing it: - scripts/build.sh — stage cbm-integrations.json next to the freshly built binary, so `build/c/codebase-memory-mcp install` works straight out of a build tree (dev, and the base for the smoke fixture). - scripts/smoke-local.sh — include the asset in the fixture tarball and its required-sidecar check. Member set and ORDER now mirror package-release.sh exactly (binary, cbm-integrations.json, LICENSE, install.sh, notices); the fixture was smoking an archive layout we never actually ship. - install.sh / install.ps1 — after installing the binary, copy the asset beside it in the install dir. `install` already publishes a verified copy to ~/.cbm/assets/<version>/, but a later install/uninstall run from the install dir resolves the asset NEXT TO THE BINARY first, so without the adjacent copy that lookup misses and a re-install or uninstall fails on a machine that just installed successfully. Best-effort atomic rename, same shape as the existing install.sh/ps1 sidecar copy. install.ps1 stays pure ASCII. - scripts/smoke-test.sh Phase 14 — this phase hand-stages the binary into a fresh HOME without going through install, so nothing populates ~/.cbm/assets; stage the asset next to each staged copy so the uninstall it drives resolves. Verified: scripts/smoke-local.sh on the standard binary now runs clean through all 16 phases — zero "integration assets missing" / hook_script_uninstall / agent-cleanup-failed lines (was 5). windows-bundle, smoke-fixture, exec-bit and no-embedded-scripts contracts pass; install.ps1 has zero non-ASCII bytes. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
scripts/ — the canonical leg entries
The doctrine (enforced, not advisory): a venue may provision a machine;
only a canonical leg script may exercise the product. Local CI, PR CI, the
dry run and the release all call the SAME files below — venues differ only in
host specs, architecture and inputs, never in what a leg does. Platform
differences (arm64 sanitizer flags, the Windows launcher, the linux portable
binary) live INSIDE these scripts, once, never per-venue.
tests/test_venue_parity_contract.sh (run as Step 0j of every test leg) turns
any violation — inline harness logic in a workflow, a bypassed wrapper, a
missing --help — into a red build.
Every entry answers --help (authoritative, agent-oriented: modes, env, exit
codes) and rejects unknown flags with exit 2 + Please consult --help.
The legs
| leg | entry | what a run gives you |
|---|---|---|
| test | test.sh |
DEFAULT = the venue leg: static contracts (Step 0a–0j) + CLEAN ASan+UBSan build + all suites via the parallel harness + prod-binary guards. --suites a,b = iteration mode (incremental rebuild, subset, seconds). --tsan = the ThreadSanitizer leg. CLANGARM64 gets CI's trap-UBSan flags automatically. |
| build | build.sh |
CLEAN production build (+ launcher on Windows). ccache via env.sh makes repeats fast; CCACHE_COMPILERCHECK=content guarantees a hit is byte-identical to a cold compile — never stale. --with-ui, --version, STATIC=1, BUILD_DIR=. |
| lint | lint.sh |
clang-tidy + cppcheck + clang-format (+ no-skips policy). --ci = the CI gate set (no clang-tidy). Drives the same make targets as make lint/lint-ci. |
| smoke (unix) | smoke-local.sh |
Stages a full release fixture, serves it on a kernel-assigned port, runs smoke-test.sh (ALL phases incl. download/install/update E2E) inside a disposable HOME/XDG/TMP sandbox. ui variant makes a missing embedded UI a FAILURE. CBM_SMOKE_ARTIFACT_DIR = smoke an extracted release artifact verbatim (release mode). |
| smoke (windows) | ../test-infrastructure/vm/vm-smoke.sh |
Same contract for the launcher+payload pair, plus the user-PATH registry guard (prepare/verify/cleanup). |
| smoke-invariants | smoke-invariants.sh |
The "shipped binary does not fail" battery (MCP handshake, all tools invocable, malformed-input resilience) — no fixture server, no install E2E. smoke.yml runs it on the WIDEST build-from-source matrix (incl. older-glibc legs the release artifacts cannot cover). |
| soak | soak-legs.sh |
The release-gating soak SEQUENCE: quick then query-leak (the #581 detector — never reindexes, so RSS growth = query-path leak), each guarded by a completion-summary check. --legs quick for the ASan single-leg variant. Duration is per leg. |
Internal harnesses — never called directly by a venue (the contract forbids
it): smoke-test.sh (phases; wrappers provide fixture server + sandbox),
soak-test.sh (one soak run; soak-legs.sh provides the sequence + guards),
run-tests-parallel.sh (reached through test.sh).
Conventions
- Exit codes: 0 = pass · 2 = usage error · 90 = guard (a run died without its completion summary — never counts as green) · anything else = the leg's real failure.
- Iteration is a flag, not a side-tool: the fast paths (
--suites,--legs) are modes of the SAME entry the gates run, so a dev loop can never drift from the venue behaviour. - Env sandboxing: the smoke wrappers neutralize every agent-config destination override; a smoke can never scribble on your real config.
Recommended workflows
- Iterating on a change:
scripts/test.sh --suites <suite>(seconds, incremental, same ASan+UBSan flags as the gate). List suites:build/c/test-runner --list-suites. Debugging a Windows-on-ARM trap: re-run withSANITIZE=for a plain build, or use the emulatedwin.sh ubsan-*pair for full diagnostics. - Before any push (the 3-OS ladder):
scripts/test.sh(macOS, full) →./test-infrastructure/run.sh full(Linux + TSan + smoke) →test-infrastructure/vm/win.sh test-par+guards+smoke-install(+soakwhen the change touches memory/daemon paths). - Concurrency-touching change: add
scripts/test.sh --tsanearly — the same leg CI gates on. - Release-shaped verification:
CBM_SMOKE_ARTIFACT_DIR=<extracted artifact> scripts/smoke-local.sh <binary> [ui]smokes exactly what would ship. - A leg is red in CI but green locally: first suspect environment shape,
not code — the preflights (
win.shautomatic;scripts/ci/preflight-docker.sh) andtest-infrastructure/README.md's residuals list cover the knowable differences.
See scripts/ci/README.md for the CI plumbing and
test-infrastructure/README.md for the venue map.