diff --git a/.claude/skills/xce-build/SKILL.md b/.claude/skills/xce-build/SKILL.md index 65305556..f14c0ae3 100644 --- a/.claude/skills/xce-build/SKILL.md +++ b/.claude/skills/xce-build/SKILL.md @@ -1,6 +1,6 @@ --- name: xce-build -description: "Build XCE components with tests. Usage: /xce-build [component] [profile] [build_dir] [--incremental]. Components: all (default), lib, controller, scheduler, worker, apiserver, xcecli, xceadmin. Profiles: asan (default), debug (non-ASAN -O0 -g3 for gdb/cores), release. Automatically caps build/test parallelism (--jobs) to the CPU/memory/load available at invocation time." +description: "Build XCE components with tests. Usage: /xce-build [component] [profile] [build_dir] [--incremental]. Components: all (default), lib, controller, harness, scheduler, worker, apiserver, xcecli, xceadmin. Profiles: asan (default), debug (non-ASAN -O0 -g3 for gdb/cores), release. Automatically caps build/test parallelism (--jobs) to the CPU/memory/load available at invocation time." disable-model-invocation: false allowed-tools: Bash(*) --- @@ -31,10 +31,10 @@ Args: `[component] [profile|build_dir] [build_dir] [--incremental]` — passed a This is a judgment call, not a rigid formula — if you notice other heavy build processes already running (`ps aux | grep -E 'cc1plus|ninja|go build'`) or the available-memory read looks unusually low, bias further down. - **No `context: fork`, intentionally.** It was tried (twice) and reproducibly breaks this skill: whenever ARGUMENTS is non-empty (e.g. `controller`), the forked subagent receives no usable task — it responds as if handed only ambient project context, never runs the build, and reports nothing back. Bare `/xce-build` (no args) happens to still "succeed" under `context: fork` only because the empty-arg case is indistinguishable from no task at all failing open into some default — not because forking works. Do not re-add `context: fork` here without first confirming the harness actually threads a non-empty ARGUMENTS payload into the forked subagent's prompt. -- **component** (1st word, default `all`) — `all`, `lib`, `controller`, `scheduler`, `worker`, `apiserver`, `xcecli`, `xceadmin` +- **component** (1st word, default `all`) — `all`, `lib`, `controller`, `harness`, `scheduler`, `worker`, `apiserver`, `xcecli`, `xceadmin` - **profile** (2nd word, default `asan`) — `asan` (debug + AddressSanitizer → `xce.build`), `debug` (non-ASAN `-O0 -g3 -fno-inline -fno-omit-frame-pointer` → `build.dbg`), `release` (`-O3`, no sanitizer → `build.release`). Each profile uses its own default build dir so the variants never clobber each other. If the 2nd word isn't one of these three keywords, treat it as a legacy explicit build_dir instead (3rd word, if present, always overrides the build dir). - Use the **`debug`** profile to root-cause heisenbug crashes that ASAN perturbs away and that gdb-on-release turns into a hang/timeout — the non-ASAN `-O0 -g3` build reproduces them and gives a fully symbolized backtrace under gdb (how bug-1282/bug-1286 were cracked). -- **`controller` always builds `xce_test` too** (`meson compile … xce_controller controller_unit_test controller/xce_test`), in every profile — not just `asan`. `xce_test` is the driver `/xce-test-ha` needs; you never have to build it as a separate step after `/xce-build controller`, and the two binaries in a build dir are always the same commit/profile in lockstep. +- **`xce_test` lives under its own `harness` component, not `controller`** (`xce-harness-component` spec, 2026-09-14) — `/xce-build controller`'s explicit compile step only builds `xce_controller controller_unit_test`; it no longer produces `xce_test` as a declared target. `xce_test` is the driver `/xce-test-ha`/`/xce-test-multihost`/`/xce-test-resources` need, so build it explicitly with `/xce-build harness` (which also builds its own 5 test binaries under the `harness` meson suite) before those workflows, or use `/xce-build all`. Known accepted quirk: because `harness_unit_test` declares a build-order dependency on `xce_test` (two of its own tests spawn it), a **default `asan`-profile** build of *any other* component that runs `meson test` (controller, worker, scheduler) can still transitively resurrect `harness/xce_test` on disk as a side effect of Meson's test-runner rebuilding all registered tests' dependencies before filtering by suite — this is a documented Meson platform behavior (not a bug, see `.wolf/buglog.json` bug-1806), not something `/xce-build ` does on purpose, and not something to rely on as a way to get `xce_test` built. - **`xceadmin` is Python, meson-driven (`src/xceadmin/meson.build`'s `custom_target` wraps `meson-build.sh`), and ignores the ASAN/debug/release sanitizer semantics entirely** — `xce-build.sh`'s `xceadmin` case just runs `meson compile -C "$BUILD_DIR" xceadmin`, the same target `nix build .#xcecore` and every other component use; the `profile` arg is accepted but has no effect on it (every invocation does the identical pinned, non-editable, out-of-tree install + test, regardless of `asan`/`debug`/`release` — unlike the old editable-install-by-default behavior, this always exercises real packaged schema resolution, not just a `release` run). For fast iterative dev without a full meson reconfigure, `xceadmin` can still be built standalone: `cd src/xceadmin && pip install -e .` (see `meson-build.sh` for the exact out-of-tree steps the meson target itself runs). Every invocation syncs the bundled `controller.capnp`/`c.capnp` and the 7 JSON validation schemas from `src/schema/` and `src/configs/schema/` into `xcecommon`'s packaged `schema_files/`, installs pinned into a fresh build-dir venv, runs `pytest` against that install, and — only after tests pass — builds an installable wheel from that same schema-synced tree into `$BUILD_DIR/xceadmin/dist/xceadmin--py3-none-any.whl` (`pip wheel … --no-deps`, so it's xceadmin's own wheel only, not a vendored bundle of `click`/`pycapnp`/etc). `xce-build.sh` prints the wheel's path and a ready-to-run `pip install ""` line after the build. Requires the nix dev shell (`pycapnp`, `pyyaml`, `jsonschema`, `click`, `pytest`, `ruff` — all provided by `src/nixSupport/xce.nix`). - **`--incremental` (bug-1565 escape hatch, opt-in, NOT the default)**: every invocation normally does `rm -rf "$BUILD_DIR"` + a full fresh `meson setup`, unconditionally — correct in isolation, but since the actual compile step afterward only rebuilds the ONE requested component, a plain single-component build silently deletes any OTHER already-built binary sharing that dir (e.g. `/xce-build xceadmin` after `/xce-build controller` wipes `xce_controller`). Pass `--incremental` to reconfigure the existing dir in place instead (`meson setup --reconfigure`), preserving whatever else was already built there — use it specifically when you want a sibling component alongside an already-built one, e.g. `/xce-build controller` then `/xce-build xceadmin --incremental` to end up with both in the same dir at once (needed for `/xce-deploy-ha`, which wants `xce_controller` + `xcecd_virtual` + `xce_scheduler` + the xceadmin wheel all together). Deliberately not the default: this project's capnp-generation `custom_target` has documented, unfixed missing-dependency-edge races (buglog.json — normally papered over as a loud, retry-fixable failure on a clean build; skipping the wipe could instead let the same gap cause silent staleness). If anything looks wrong after an incremental build, rebuild without the flag. diff --git a/src/controller/testsuite/clean_failover_preservation.sh b/src/controller/testsuite/clean_failover_preservation.sh index 4e780c72..ea0cb527 100755 --- a/src/controller/testsuite/clean_failover_preservation.sh +++ b/src/controller/testsuite/clean_failover_preservation.sh @@ -75,7 +75,7 @@ set -u HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$HERE/../../.." && pwd)" BINARY="${XCE_CONTROLLER_BIN:-$REPO_ROOT/src/xce.build/controller/xce_controller}" -XCE_TEST="${XCE_TEST_BIN:-$REPO_ROOT/src/xce.build/controller/xce_test}" +XCE_TEST="${XCE_TEST_BIN:-$REPO_ROOT/src/xce.build/harness/xce_test}" DATADIR="${XCE_HA_DATADIR:-$REPO_ROOT/ha/data}" DEPLOY_SH="${XCE_DEPLOY_SH:-$REPO_ROOT/src/tools/deploy-ha.sh}" @@ -137,7 +137,7 @@ xtest() { # ── Preconditions ──────────────────────────────────────────────────────────── [ -x "$BINARY" ] || fail "controller binary not found/executable: $BINARY (run /xce-build controller)" -[ -x "$XCE_TEST" ] || fail "xce_test not found/executable: $XCE_TEST (run /xce-build controller)" +[ -x "$XCE_TEST" ] || fail "xce_test not found/executable: $XCE_TEST (run /xce-build harness)" [ -r "$DATADIR/cluster.bin" ] || fail "cluster.bin missing under $DATADIR (deploy prerequisite)" [ -r "$DATADIR/xce.crt" ] && [ -r "$DATADIR/xce.key" ] || fail "TLS certs missing under $DATADIR" [ -x "$DEPLOY_SH" ] || fail "deploy script missing: $DEPLOY_SH" diff --git a/src/controller/testsuite/test_rcfile_integration.sh b/src/controller/testsuite/test_rcfile_integration.sh index 61c97444..866f8645 100755 --- a/src/controller/testsuite/test_rcfile_integration.sh +++ b/src/controller/testsuite/test_rcfile_integration.sh @@ -28,7 +28,7 @@ set -u # ── Config ─────────────────────────────────────────────────────────────────── HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$HERE/../../.." && pwd)" -XCE_TEST="${XCE_TEST_BIN:-$REPO_ROOT/src/xce.build/controller/xce_test}" +XCE_TEST="${XCE_TEST_BIN:-$REPO_ROOT/src/xce.build/harness/xce_test}" # xce_test's `masters` setting defaults to "localhost:9990" (test.c's # settings[] table) and prints as "" until something actually @@ -351,7 +351,7 @@ test_rcfile_failure_continues_interactive() { main() { [ -x "$XCE_TEST" ] \ - || { log "FAIL: xce_test not found/executable: $XCE_TEST (run /xce-build controller)"; exit 1; } + || { log "FAIL: xce_test not found/executable: $XCE_TEST (run /xce-build harness)"; exit 1; } test_rcfile_takes_effect_piped test_rcfile_takes_effect_interactive diff --git a/src/tools/test-commit-durability.sh b/src/tools/test-commit-durability.sh index 6a4988ce..32f82f92 100755 --- a/src/tools/test-commit-durability.sh +++ b/src/tools/test-commit-durability.sh @@ -80,7 +80,7 @@ # reports RED (no primary fdatasync precedes the ack). After the fix it must # go GREEN. See run_deterministic() below. # -# Requires a current build: run /xce-build controller first. +# Requires a current build: run /xce-build controller and /xce-build harness first. set -u # ── mode selection ──────────────────────────────────────────────────────────── @@ -94,7 +94,7 @@ fi WORKTREE=$(cd "$(dirname "$0")/../.." && pwd) BINARY="$WORKTREE/src/xce.build/controller/xce_controller" -XCE_TEST="$WORKTREE/src/xce.build/controller/xce_test" +XCE_TEST="$WORKTREE/src/xce.build/harness/xce_test" DEPLOY_DIR="${1:-/tmp/xce-ha-deploy}" ROUNDS="${2:-8}" PEERS="localhost:9991,localhost:9992,localhost:9993"