myxce/.kiro/specs/xce-harness-component/brief.md
Rongsong Shen b3aa2af242
test(xce-harness-component): verify build isolation; narrow requirement 2.2
Validation task 4.3 found a real, deterministic conflict with the
original requirement 2.2 wording, not a flake: /xce-build controller
alone's default asan profile transitively rebuilds harness/xce_test,
because Meson's test-runner rebuilds every registered test's build-
order dependencies project-wide before filtering by --suite, and
harness_unit_test (task 2.1) depends on it. Confirmed via build-log
step-count analysis (explicit compile: 209 steps, clean; subsequent
meson test: 844 steps, resurrects it) and independently reproduced
twice, with an exact step-count match both times.

User decision (2026-09-14): accept as a documented Meson limitation
rather than auditing every component's test-target list (controller's
own suite already relies on this same mechanism for 4 of its own test
binaries) or weakening harness_unit_test's build-order guarantee
(verified load-bearing in task 4.2). Requirement 2.2 narrowed to what
the build system directly controls: its explicit compile-target list
never names xce_test. requirements.md/design.md/tasks.md updated to
match and cross-reference each other; logged as bug-1806 (accepted,
not fixed) for the record.

Also commits the xce-harness-component spec's remaining docs
(requirements.md, brief.md, research.md, spec.json) and the roadmap.md
promotion entry from discovery, none of which had been committed yet.

Task 4.3 of xce-harness-component.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLSNJhNoULvVcUhXEFafQC
2026-09-14 09:59:15 +00:00

10 KiB

Brief: xce-harness-component

Problem

xce_test — the REPL-driven wire-protocol test client used to drive/verify controller, scheduler, and worker (HA soak, resource-value verification, multi-host allocation proof, WAL/snapshot inspection) — is physically and organizationally welded to the controller component, even though it has no real dependency on it. Its 15 source files live in src/controller/testsuite/ and its build target is defined inside src/controller/meson.build, so it is invisible as a first-class thing in the project's own component vocabulary (CLAUDE.md's /xce-build component list: all, lib, controller, scheduler, worker, apiserver, xcecli, xceadmin has no entry for it) despite being load-bearing infrastructure for at least four other skills (/xce-test-ha, /xce-deploy-ha, /xce-test-multihost, /xce-test-resources).

Current State

  • Binary: xce_test, defined at src/controller/meson.build:58-85 (xce_test_src, xce_test_deps, xce_test = executable(...)).
  • Sources (15 files, all in src/controller/testsuite/): test.c (REPL/dispatch entry), waldump.c, walcompare.c, snapverify.c, snapdiff.c, configcompare.c, resval_typeresolve.c, joblist_display.c, join_worker_args.c, rcfile.c, flagspec.c, interruptcall.c, confirm.c, listfmt_json.c, listrow_json.c — plus their matching .h headers.
  • Verified finding (de-risks the move): none of these 15 files #include any controller-private header (ha.h, repl.h, config_repl.h, myconf.h, etc.). They depend only on libxce public headers (src/include/*.h, e.g. client.h, config.h, delay.h, idgen.h, persist.h, preason.h, utils.h, wal_types.h, xce/cluster.h, xce/types.h), the generated controller.capnp.h schema header, and xce_test's own component-local headers. xce_test_deps is libxce_dep, librtti_dep, struct2json_dep, libedit_dep, tinylog_dep, zlib_dep, c_capnproto_dep, ssl_dep, thread_dep — no controller_deps-only dependency. It is a pure network client, not a controller-internals harness.
  • Hidden coupling to untangle: src/controller/meson.build's controller_unit_test_src (lines ~160-466) currently recompiles ~14 of these same 15 production files a second time, paired with their own white-box unit tests, directly into the controller's own controller_unit_test binary: test_waldump.c+waldump.c, test_walcompare.c+walcompare.c, test_snapverify.c+snapverify.c, test_snapdiff.c+snapdiff.c, test_configcompare.c+configcompare.c, test_rcfile.c+rcfile.c, test_flagspec.c+flagspec.c, test_interruptcall.c+interruptcall.c (+test_xcetest_interrupt.c), test_confirm.c+confirm.c, test_listfmt_json.c+listfmt_json.c, test_resval_typeresolve.c+resval_typeresolve.c, test_joblist_display.c+joblist_display.c, test_join_worker_args.c+join_worker_args.c, test_listrow_json.c+listrow_json.c — plus test_xcetest_process_entry.c and test_test_cli.c, which white-box-test test.c's own REPL dispatch. This pairing is the real reason a naive "just move the 15 files" plan breaks: those ~16 test files have no production code left to compile against once their counterpart moves.
  • Not part of any nix/AppImage production package (src/flake.nix and src/meson.build have zero references to xce_test/testsuite) — it is dev/test-only tooling, so there is no release-artifact impact.
  • Existing behavior specs (xce-test-cli-ux — tasks generated, ready for implementation; xce-test-e2e-primitives — implemented; xce-test-rc-file — implementation-complete) all govern xce_test's behavior (CLI UX, REPL primitives, rc-file config) and reference these same files by their current src/controller/testsuite/ paths. None of them address where the code lives or how it's built.

Desired Outcome

xce_test (built at) becomes a genuine standalone component under src/harness/, following the project's existing C Daemon Layout Pattern (own meson.build, CLAUDE.md, include/, testsuite/) exactly like worker/ and scheduler/. It has its own explicit /xce-build harness entry, its own unit-test binary covering the ~16 white-box tests currently trapped inside controller_unit_test, and building controller no longer implicitly produces it. Every consumer that currently assumes "build controller → xce_test exists" is updated to build it explicitly.

Approach

Pure structural relocation + build-graph split — no behavioral/logic changes to xce_test itself:

  1. Move the 15 production files + their headers from src/controller/testsuite/ into src/harness/ (layout to be finalized in design — e.g. flat under src/harness/ mirroring controller's own flat-root exception, or src/harness/src/ + src/harness/include/ per the standard pattern; test.c stays the REPL entry point).
  2. Split the unit-test binary: carve the ~16 paired white-box test files out of controller_unit_test_src into a new harness_unit_test binary defined in src/harness/meson.build, registered as its own meson test() (new suite, e.g. harness, parallel to the existing suite: 'controller'). controller_unit_test keeps every other file untouched — this is confirmed to be test_*.c domain tests for ha/persist/commit/repl/job/etc., which are genuinely controller-internal and stay exactly where they are.
  3. Rewire the build: new src/harness/meson.build, subdir('harness') added to src/meson.build, remove xce_test_src/xce_test_deps/xce_test executable and the moved entries out of controller_unit_test_src in src/controller/meson.build.
  4. Fully decouple (per user decision): /xce-build controller no longer transitively builds the harness. Add harness as a new first-class /xce-build component (.claude/skills/xce-build/), update its component list and the Key Files/Components line in root CLAUDE.md.
  5. Fix every consumer that currently assumes xce_test exists right after building controller: /xce-test-ha, /xce-deploy-ha, /xce-test-multihost (.claude/skills/xce-test-multihost/run-multihost-verify.sh), /xce-test-resources — each needs an explicit /xce-build harness step added (or a documented prerequisite) wherever it currently piggybacks on /xce-build controller.
  6. Update steering: build-deployment.md (line 24's "controller always builds xce_test..." claim, the Meson Structure tree, the /xce-build command table), structure.md (component table + C Daemon Layout Pattern exceptions list), and a new src/harness/CLAUDE.md.

Scope

  • In: relocating xce_test's 15 source files + headers into src/harness/; splitting the paired ~16 white-box tests into a new harness_unit_test binary; new src/harness/meson.build + src/harness/CLAUDE.md; adding harness to /xce-build; decoupling it from /xce-build controller; updating every downstream skill/script and steering doc that assumes the old coupling.
  • Out: any behavioral change to xce_test itself (owned by xce-test-cli-ux/xce-test-e2e-primitives/xce-test-rc-file and future xce_test feature work — e.g. the still-open xce_test WAL/snapshot inspection tooling roadmap item); packaging xce_test into the nix/AppImage production artifacts (it is dev/test tooling today and stays that way); reorganizing controller's own domain unit tests (ha/persist/commit/repl/job/etc. — confirmed to stay in src/controller/testsuite/).

Boundary Candidates

  • The production-binary move (files + meson target) is independent of the unit-test-binary split, but both must land together — an intermediate state where xce_test.c's sources live in src/harness/ while their unit tests still reference the old src/controller/testsuite/ paths would not build.
  • The build/skill decoupling (item 4-5 above) is separable follow-up work from the pure file move (items 1-3) and could in principle be its own task group within the same spec, but is NOT a separate spec — it's required for the "standalone component" outcome to actually hold (a component whose build is still silently triggered by another component's build isn't standalone).

Out of Boundary

  • Renaming the xce_test binary itself (stays xce_test; only the directory/component is named harness).
  • Any new xce_test functionality (commands, REPL features, output formats).
  • Touching xceadmin, xcecli, or any Go frontend build wiring.
  • Re-litigating which controller unit tests belong where beyond the ~16 files whose production counterpart is physically moving.

Upstream / Downstream

  • Upstream: none — this is a pure internal restructuring with no external dependency.
  • Downstream: /xce-test-ha, /xce-deploy-ha, /xce-test-multihost, /xce-test-resources skills (must be updated to build harness explicitly); the three existing xce-test-* behavior specs (their task/design docs reference file paths under src/controller/testsuite/ that will need a path-only update, not a re-review of their approved requirements/design); the still-open roadmap backlog item "xce_test WAL/snapshot inspection tooling" (new snapdump/walcompare work should target the post-move src/harness/ location).

Existing Spec Touchpoints

  • Extends: none directly — this is a new boundary, not an extension of an approved spec.
  • Adjacent: xce-test-cli-ux, xce-test-e2e-primitives, xce-test-rc-file — same binary, disjoint concern (behavior vs. location/build). File-path references in their design/tasks docs will go stale after this spec lands; worth a quick path-only sync pass once implemented, not a re-open of their approved content.

Constraints

  • No behavioral regression in xce_test — every existing command/REPL feature must work identically post-move (verify via the existing xce-test-e2e-primitives/xce-test-cli-ux test coverage rerun against the new binary location).
  • Meson/build hygiene: must respect the project's existing --incremental vs. full-wipe build-dir semantics (build-deployment.md bug-1565 note) — a two-component build (controller + harness) in the same dir needs either /xce-build all or --incremental, same as any other two-component combo today.
  • User decisions locked in for this spec (2026-09-13, /kiro-discovery): component directory name is src/harness/ (binary name unchanged, xce_test); build coupling is fully decoupled (not transitional-compatible) — downstream skills must be fixed as part of this spec, not left broken.