myxce/.kiro/specs/xce-harness-component/tasks.md
Rongsong Shen 2f7b64b468
docs(xce-harness-component): refresh harness CLAUDE.md post-implementation
Feature-level validation (/kiro-validate-impl) found src/harness/CLAUDE.md
(written by task 1.3, before tasks 2.1/2.2/3.1 landed) still claimed no
/xce-build harness entry point and no unit-test binaries existed -- both
false by the time all 16 tasks completed. Updated to describe the real,
final state: /xce-build harness as the build command, and all 5 test
binaries (harness_unit_test + 4 standalone) under the harness suite.

Also logs one more out-of-boundary stale-path finding
(src/tools/test-commit-durability.sh:97) for a future owner.

This closes out feature-level validation for xce-harness-component --
mechanical (173+1213 tests, 0 failures), design/boundary alignment
(zero controller-private dependency, both sanctioned exceptions exact
match), and requirements coverage (22/22 mapped) all passed cleanly.

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

20 KiB

Implementation Plan: xce-harness-component

  • 1. Foundation: relocate xce_test itself and establish the component

  • 1.1 Relocate xce_test's production sources, wire its standalone build, and strip every controller-side reference to the moved files

    • Move all 15 xce_test source files (test.c, 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) and their headers out of src/controller/testsuite/ into src/harness/, content unchanged
    • Create src/harness/meson.build defining only the xce_test executable so far (same sources/dependencies as today, paths updated); add subdir('harness') to src/meson.build
    • In the same task, from src/controller/meson.build remove: the xce_test_src/xce_test_deps/xce_test executable block; every controller_unit_test_src entry that references one of the 15 moved files, which is 10 production+test pairs (waldump, walcompare, snapverify, snapdiff, configcompare, rcfile, flagspec, interruptcall, confirm, listfmt_json, each with its test_*.c) plus test_xcetest_interrupt.c (extra interruptcall.c coverage) — 11 test files total; and the four entire standalone executable()/test() blocks (resval_typeresolve_unit_test, joblist_display_unit_test, join_worker_args_unit_test, listrow_json_unit_test), since each references one of the 15 moved production files directly
    • Also remove those same 11 test files' extern/RUN_TEST entries from controller_test.c. Leave test_test_cli.c's and test_xcetest_process_entry.c's entries in place — neither links any of the 15 moved files (they spawn the built xce_test binary as a subprocess instead), so they stay valid in controller_unit_test until task 2.1 relocates them
    • The 11 removed test files' .c sources are left on disk at their current src/controller/testsuite/ path for now (referenced by no build target) — task 2.1 physically relocates them together with test_test_cli.c/test_xcetest_process_entry.c
    • Observable: a harness-scoped build produces an xce_test binary; a controller-scoped build run immediately after this single task (no later tasks applied) still succeeds, controller_unit_test's reported test count has dropped by exactly the 11 removed entries, and none of the four standalone binaries are defined anymore
    • Requirements: 1.1, 1.2, 1.3, 2.1, 2.2, 2.4
  • 1.2 Promote the shared ctrlstatus_fmt.h header and repoint its current consumers

    • Move ctrlstatus_fmt.h to src/include/xce/; update the include path in harness's test.c and joblist_display.c (already relocated in 1.1) and in controller's test_ctrlstatus.c
    • joblist_display.c's own test file, test_joblist_display.c, still lives in src/controller/testsuite/ at this point and is intentionally left untouched here — its include-path fix happens in task 2.2, when that file relocates
    • Observable: a repo-wide search finds no remaining relative #include "ctrlstatus_fmt.h"; all three current consumers include it from xce/ctrlstatus_fmt.h
    • Requirements: 1.4
  • 1.3 Write the harness component guide

    • New src/harness/CLAUDE.md describing the component's purpose, build command, and structure, matching the style of existing component guides (e.g. src/controller/CLAUDE.md)
    • Observable: src/harness/CLAUDE.md exists and documents the build command and file layout
    • Requirements: 6.1
  • 2. Core: migrate the five harness test binaries

  • 2.1 Consolidate the controller-embedded harness tests into a new binary and finish clearing them from the controller's own test binary

    • Physically relocate the 13 test files for this group into src/harness/testsuite/: the 11 whose controller_unit_test_src/controller_test.c references were already removed in task 1.1 (test_waldump.c through test_xcetest_interrupt.c, left on disk at their old path until now), plus test_test_cli.c and test_xcetest_process_entry.c (still validly part of controller_unit_test until this task)
    • Write a new Unity runner harness_test.c (modeled on controller_test.c) carrying all 13 extern/RUN_TEST entries; register the new harness_unit_test executable and its meson test() under suite harness in src/harness/meson.build; declare its build-order dependency on the xce_test executable target (two of its tests spawn that binary over a pty)
    • In the same task, remove test_test_cli.c's and test_xcetest_process_entry.c's entries from controller_unit_test_src and their extern/RUN_TEST lines from controller_test.c — the only two of the 13 not already removed in task 1.1 (test_ctrlstatus's entry stays — it tests controller's own ctrlstatus.c)
    • Observable: meson test --suite harness runs harness_unit_test with the same pass count these 13 files reported before the move; meson test --suite controller run immediately after this same task still runs controller_unit_test successfully, with its test count reduced by exactly these final 2 entries (11 were already reflected in task 1.1's count drop)
    • Requirements: 3.1, 3.2, 3.3, 3.4
  • 2.2 Relocate the four already-standalone harness test binaries

    • Physically relocate the test_resval_typeresolve.c, test_joblist_display.c, test_join_worker_args.c, and test_listrow_json.c files into src/harness/testsuite/ (left on disk at their old path since task 1.1 removed their controller-side executable()/test() blocks); re-create each of the four executable()/test() blocks, unchanged in shape, in src/harness/meson.build under suite harness, referencing their production files already relocated to src/harness/ in task 1.1
    • Update test_joblist_display.c's ctrlstatus_fmt.h include path to xce/ctrlstatus_fmt.h as part of this same move
    • Observable: meson test --suite harness lists all four binaries alongside harness_unit_test, each reporting the same pass count as before the move
    • Requirements: 1.4, 3.1, 3.2, 3.4
  • 3. Integration: decouple build orchestration, downstream workflows, and documentation

  • 3.1 Add the harness build entry and decouple it from the controller build

    • In src/tools/xce-build.sh, drop controller/xce_test from the controller) case's compile target list; add a new harness) case following the identical three-part setup_build / meson compile / conditional meson test --suite harness template already used by scheduler)/worker)
    • Observable: /xce-build harness on a fresh build dir (no prior controller build) produces the xce_test binary and runs the harness suite; /xce-build controller alone does not produce xce_test
    • Requirements: 2.1, 2.2, 2.3, 2.4
  • 3.2 (P) Update the HA soak workflow's harness prerequisite

    • Update .claude/skills/xce-test-ha/run-ha-soak.sh and SKILL.md so the soak ensures the harness is built (or fails with a clear message) instead of assuming a controller build produced it
    • Observable: running the workflow from a build dir where only controller was built either builds the harness itself or reports a clear, actionable message instead of a raw spawn/connect failure
    • Requirements: 5.1, 5.4
    • Boundary: xce-test-ha skill
    • Depends: 3.1
  • 3.3 (P) Extend the local HA deploy workflow's soft-skip handling to the harness

    • Update .claude/skills/xce-deploy-ha/SKILL.md to cover the harness binary under its existing worker/scheduler/xceadmin soft-skip pattern
    • Observable: deploying from a build dir without the harness built reports the same clear soft-skip style already used for a missing worker/scheduler/xceadmin binary
    • Requirements: 5.2, 5.4
    • Boundary: xce-deploy-ha skill
    • Depends: 3.1
  • 3.4 (P) Update the multi-host verification workflow's harness prerequisite

    • Update .claude/skills/xce-test-multihost/run-multihost-verify.sh and SKILL.md
    • Observable: running the workflow from a build dir where only controller was built either builds the harness itself or reports a clear, actionable message
    • Requirements: 5.3, 5.4
    • Boundary: xce-test-multihost skill
    • Depends: 3.1
  • 3.5 (P) Update the resource-value verification workflow's harness prerequisite

    • Update .claude/skills/xce-test-resources/run-resource-verify.sh and SKILL.md
    • Observable: running the workflow from a build dir where only controller was built either builds the harness itself or reports a clear, actionable message
    • Requirements: 5.3, 5.4
    • Boundary: xce-test-resources skill
    • Depends: 3.1
  • 3.6 (P) Update root guide and build/deployment steering for the harness component

    • Add harness to root CLAUDE.md's /xce-build component list and Subdirectory Guidelines; remove build-deployment.md's "controller always builds xce_test" claim and add harness to its /xce-build command table and Meson Structure tree
    • Observable: CLAUDE.md lists harness among buildable components; build-deployment.md no longer claims the controller build produces xce_test
    • Requirements: 6.1, 6.2
    • Boundary: CLAUDE.md, build-deployment.md
    • Depends: 3.1
  • 3.7 (P) Update structure steering to list the harness component

    • Add harness to structure.md's component table and to its flat-root Exceptions list alongside controller
    • Observable: structure.md's component tree and Exceptions section both mention harness
    • Requirements: 6.3
    • Boundary: structure.md
    • Depends: 1.1
  • 4. Validation: prove behavioral parity and end-to-end correctness

  • 4.1 Verify xce_test's behavioral parity after relocation

    • Rerun the existing xce-test-cli-ux / xce-test-e2e-primitives / xce-test-rc-file test coverage against the harness-built xce_test binary and diff its command/flag/output behavior against a pre-move capture
    • Observable: no behavioral difference is found; every previously-passing scenario in that coverage still passes unchanged
    • Requirements: 4.1, 4.2, 4.3
    • Depends: 3.1
  • 4.2 Verify the harness_unit_test build-order dependency actually holds

    • Deliberately remove the built xce_test binary, run harness_unit_test, and confirm test_test_cli.c/test_xcetest_process_entry.c fail loudly rather than silently pass; rebuild normally and confirm the suite passes
    • Observable: the deliberate-removal run reports a clear failure from the two pty-spawning tests; the normal run reports the full suite green
    • Requirements: 3.1, 3.2
    • Depends: 2.1, 3.1
  • 4.3 Verify independent and combined build behavior

    • Run /xce-build harness alone on a clean build dir and confirm xce_test is produced; run /xce-build controller alone and confirm its explicit compile step never targets xce_test (a full default-profile test run may still transitively rebuild it via harness_unit_test's dependency -- a documented, accepted Meson limitation, not a defect; see requirements.md's "Known limitation" boundary note); run /xce-build all and confirm both exist
    • Observable: each of the three build invocations produces exactly the binaries described above, and the controller-only build's explicit meson compile step is confirmed (via build-log inspection) to never name xce_test
    • Requirements: 2.1, 2.2, 2.4
    • Depends: 3.1
  • 4.4 Verify every downstream workflow from a clean build state

    • Run the HA soak, local HA deploy, multi-host verification, and resource-value verification workflows starting from a build directory where the harness has never been built
    • Observable: none of the four workflows fails with a raw/unrelated error; each either succeeds after building the harness itself or reports the expected clear, actionable message
    • Requirements: 5.1, 5.2, 5.3, 5.4
    • Depends: 3.2, 3.3, 3.4, 3.5

Implementation Notes

  • Task 1.1: discovered a real gap in the discovery/design audit — test_config_repl.c, test_ha_core_safety.c, test_upgrade_snapshot_apply.c, test_bug857_regression.c (controller's own domain tests, out of this spec's boundary) call functions directly from waldump.c/walcompare.c/snapverify.c/snapdiff.c. Fixed by having controller_unit_test_src recompile those four files a second time from ../harness/. This is a permanent, sanctioned controller→harness dependency, not a migration artifact — recorded in design.md's Allowed Dependencies. Later tasks: do not assume harness has zero inbound dependency from controller; only assume harness has zero outbound dependency on controller (Requirement 1.4).
  • Task 1.1: test_test_cli.c/test_xcetest_process_entry.c locate xce_test as a build-dir sibling via resolve_xce_test_path(). Since they still live in src/controller/testsuite/ until task 2.1, a temporary xce_test_controller_link custom_target symlink bridge was added to src/controller/meson.build (documented in-code as removable once task 2.1 relocates both files). Task 2.1 must remove this custom_target and the test()'s depends: on it as part of that relocation.
  • Task 1.1 gotcha: a meson custom_target command's @INPUT0@/@OUTPUT0@ tokens expand to build-root-relative paths, but a symlink's target string is resolved relative to the symlink's own directory at dereference time, not the invocation cwd or the string's own reference frame — using @INPUT0@ directly as an ln -sf target from a different subdirectory produces a broken link. Use an explicit ../-relative (or absolute) path instead.
  • Build dir note: this repo's default build dir resolves to src/xce.build/ (relative to src/tools/xce-build.sh's own cwd), not a bare xce.build/ at the repo root.
  • Task 4.1: Confirmed behavioral parity conclusively — found a genuine pre-relocation binary (src/build.dbg/controller/xce_test, predates commit cf55d691 by 3 days) and byte-diffed its --help/--usage/piped-REPL output against the harness-built binary: identical (only --version's embedded build-hash/timestamp differs, as expected). Real, non-blocking follow-up found (out of this spec's boundary, pre-scoped by requirements.md's Adjacent Expectations for the xce-test-rc-file-owned one): src/controller/testsuite/test_rcfile_integration.sh and clean_failover_preservation.sh (the latter actually belongs to ha-term-safety task 5.2, not one of the three named xce-test-* specs) both hardcode a stale default binary path (src/xce.build/controller/xce_test) and the latter's failure message still says "run /xce-build controller" — should be repointed to src/xce.build/harness/xce_test by whoever owns each script next.
  • Feature-level validation (/kiro-validate-impl, post-4.4): three parallel independent checks (mechanical+smoke, design/boundary alignment, requirements+cross-task) all passed cleanly (173+1213 tests 0 failures; harness has zero controller-private dependency; both sanctioned exceptions exact-match; 22/22 requirements mapped; zero stale controller/xce_test references within this spec's own files). Two dimensions independently found the same gap: src/harness/CLAUDE.md (written by task 1.3, genuinely in-boundary per design.md's File Structure Plan) was never revisited after tasks 2.1/2.2/3.1 landed, so it still claimed "no /xce-build harness entry point yet" and "no unit-test binaries yet" -- both false. Fixed directly post-validation (doc-only correction, not a new task). Lesson for future specs: a component-guide task written early (task 1.3) should either land LAST, or tasks.md should explicitly assign a later task to circle back and refresh it once the facts it describes stabilize. Also found one more out-of-boundary stale-path script beyond the two already known: src/tools/test-commit-durability.sh:97 hardcodes the old controller/xce_test path -- noted for whoever owns that script next, not fixed here.
  • Task 4.4 (final task): verified all four downstream workflows against a genuinely harness-absent, otherwise-fully-built dir, including a real 3-node HA cluster deployment for xce-deploy-ha. All pass. Extended task 4.3's finding: worker) and scheduler)'s xce-build.sh cases also run meson test, so they too transitively resurrect harness/xce_test via the same mechanism (apiserver) does not, since it only runs go test) -- same accepted-limitation status as task 4.3, no new decision needed. Found one more pre-existing, out-of-boundary stale doc claim worth a quick follow-up sometime: .claude/skills/xce-build/SKILL.md:37 still says "controller always builds xce_test too... in every profile" (false since task 3.1).
  • Task 4.3: found a real, deterministic Requirement 2.2 conflict, not a flake — under the default asan profile, /xce-build controller's meson test --suite controller step transitively rebuilds harness/xce_test on disk, 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 xce_test. Traced precisely via build-log line analysis (explicit meson compile step: 209 steps, clean; subsequent meson test step: 844 steps, resurrects it) -- this is why task 3.1's own validation missed it: it checked the old controller/xce_test path (correctly absent), not harness/xce_test (the path that actually gets touched). User decision 2026-09-14: accept as a documented Meson limitation and narrow Requirement 2.2's wording to what the build system directly controls (its own explicit compile-target list), rather than auditing every component's test-target list (non-trivial -- controller's own suite already has 4 small test binaries not in its own explicit compile list, relying on this exact same auto-rebuild) or weakening harness_unit_test's build-order dependency (task 4.2 verified load-bearing). requirements.md/design.md updated accordingly; logged as bug (not-fixed, accepted) for the record.
  • Task 3.7: Major Task 3 (Integration) is now fully complete. Task 3.6's review round caught a real doc-consistency miss (a partial fix left a contradicting stale claim elsewhere in the same file); the lesson (full end-to-end file re-read, not just the two named spots) was applied successfully in 3.7 and independently confirmed by review. Non-blocking follow-up noted for a future pass: structure.md line 92's generic "test.c provides the test runner harness" line is doubly stale (controller's runner is controller_test.c, harness's is harness_test.c) and also coincidentally collides with src/harness/test.c, which is real production code (xce_test's REPL entry point), not a test runner — worth a one-line correction sometime, out of this spec's boundary.
  • Task 2.2: Major Task 2 (Core) is now fully complete — all 5 harness test binaries exist under suite: 'harness' (4/20/5/12/132 tests, all green), controller's suite is fully clean at 1199 tests. Minor non-blocking cleanup found for a future pass: src/controller/meson.build:211's struct2json_dep comment still cites test_listfmt_json.c (relocated to harness in task 2.1) as a consumer, and its own dependency may now be unused in controller_unit_test_deps — worth checking whether it can be dropped entirely once someone audits it.
  • Task 2.1: confirmed resolve_xce_test_path() (/proc/self/exe dirname + sibling lookup) needed zero code change once both xce_test and harness_unit_test build under the same src/harness/meson.build — they land in the same build-dir subdir automatically. Test counts cross-checked and consistent end to end: 1331 (pre-move) → 1228 (after task 1.1's 11-entry removal) → 1199 controller + 132 harness = 1331 (after task 2.1). Minor non-blocking nit for a future pass: test_xcetest_process_entry.c's header comment still describes the old controller-embedded build layout — stale prose only, not a functional issue.