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
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 atsrc/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.hheaders. - Verified finding (de-risks the move): none of these 15 files
#includeany 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 generatedcontroller.capnp.hschema header, and xce_test's own component-local headers.xce_test_depsislibxce_dep, librtti_dep, struct2json_dep, libedit_dep, tinylog_dep, zlib_dep, c_capnproto_dep, ssl_dep, thread_dep— nocontroller_deps-only dependency. It is a pure network client, not a controller-internals harness. - Hidden coupling to untangle:
src/controller/meson.build'scontroller_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 owncontroller_unit_testbinary: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— plustest_xcetest_process_entry.candtest_test_cli.c, which white-box-testtest.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.nixandsrc/meson.buildhave zero references toxce_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 currentsrc/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:
- Move the 15 production files + their headers from
src/controller/testsuite/intosrc/harness/(layout to be finalized in design — e.g. flat undersrc/harness/mirroring controller's own flat-root exception, orsrc/harness/src/+src/harness/include/per the standard pattern;test.cstays the REPL entry point). - Split the unit-test binary: carve the ~16 paired white-box test files out of
controller_unit_test_srcinto a newharness_unit_testbinary defined insrc/harness/meson.build, registered as its ownmeson test()(new suite, e.g.harness, parallel to the existingsuite: 'controller').controller_unit_testkeeps every other file untouched — this is confirmed to betest_*.cdomain tests forha/persist/commit/repl/job/etc., which are genuinely controller-internal and stay exactly where they are. - Rewire the build: new
src/harness/meson.build,subdir('harness')added tosrc/meson.build, removexce_test_src/xce_test_deps/xce_testexecutable and the moved entries out ofcontroller_unit_test_srcinsrc/controller/meson.build. - Fully decouple (per user decision):
/xce-build controllerno longer transitively builds the harness. Addharnessas a new first-class/xce-buildcomponent (.claude/skills/xce-build/), update its component list and theKey Files/Componentsline in rootCLAUDE.md. - 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 harnessstep added (or a documented prerequisite) wherever it currently piggybacks on/xce-build controller. - Update steering:
build-deployment.md(line 24's "controlleralways buildsxce_test..." claim, the Meson Structure tree, the/xce-buildcommand table),structure.md(component table + C Daemon Layout Pattern exceptions list), and a newsrc/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 newharness_unit_testbinary; newsrc/harness/meson.build+src/harness/CLAUDE.md; addingharnessto/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-fileand future xce_test feature work — e.g. the still-openxce_test WAL/snapshot inspection toolingroadmap item); packaging xce_test into the nix/AppImage production artifacts (it is dev/test tooling today and stays that way); reorganizingcontroller's own domain unit tests (ha/persist/commit/repl/job/etc. — confirmed to stay insrc/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 insrc/harness/while their unit tests still reference the oldsrc/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_testbinary itself (staysxce_test; only the directory/component is namedharness). - 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-resourcesskills (must be updated to buildharnessexplicitly); the three existingxce-test-*behavior specs (their task/design docs reference file paths undersrc/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" (newsnapdump/walcomparework should target the post-movesrc/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-uxtest coverage rerun against the new binary location). - Meson/build hygiene: must respect the project's existing
--incrementalvs. full-wipe build-dir semantics (build-deployment.mdbug-1565 note) — a two-component build (controller+harness) in the same dir needs either/xce-build allor--incremental, same as any other two-component combo today. - User decisions locked in for this spec (2026-09-13,
/kiro-discovery): component directory name issrc/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.