Requirements: 6 requirement areas covering single build path, unit/ backend/integration test migration, binary discovery, and doc consistency. Design: 6 rounds of independent adversarial review to convergence (2 real technical bugs caught -- unresolved Meson placeholder tokens in CGO flags, invalid unquoted dict-literal keys -- plus a long tail of stale Makefile references across docs/scripts/ source comments, closed by a scope-rule restructure rather than continued line-by-line patching). Tasks: 4 major / 12 sub-tasks, task-graph sanity review passed after one repair round. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XYdtrEWWZfKRRGED7raEYg
31 KiB
Design Document
Overview
Purpose: Delete src/frontend/Makefile and consolidate apiserver/xcecli build and test execution onto Meson, eliminating a real, already-realized duplicate version-fingerprint-computation risk.
Users: XCE developers building/testing apiserver and xcecli, and the project's own canonical build tooling (xce-build.sh, /xce-build) and dependent scripts (run-resource-verify.sh).
Impact: src/frontend/Makefile (194 lines, 5 targets) is removed entirely. Its build-cli/build-server targets are already dead from /xce-build's perspective (Meson already builds both binaries). Its test target's two live callers migrate to direct go test invocations. Its test-backend target's coverage moves into a genuine Meson test() registration. Its test-integration target's one line of logic (an env-var rename) is absorbed by direct invocation of the already-standalone tests/regression/run.sh.
Goals
- Exactly one build/test orchestration path for apiserver/xcecli exists after this lands.
- No CGO-backed backend test coverage is lost at any point during the migration.
- No script or document is left depending on a Makefile-specific fixed path or target.
Non-Goals
- Redesigning
apiserver/meson.build's existing CGO flag derivation (apiserver_cgo_deps) — reused as-is. - Changing
xce-build.sh's version-fingerprint computation — the single surviving source of truth is untouched. - Rewriting historical/frozen spec documents.
- Fixing
component-failover-adoption's unrelatedset -euo pipefailCGO-test-skip issue.
Boundary Commitments
This Spec Owns
- Deletion of
src/frontend/Makefile. - The two
xce-build.shcall sites that invokecd frontend && make test(apiserverandallcases). - A new Meson
test()registration for the CGO-backed backend suite inapiserver/meson.build, reusing the existingapiserver_cgo_depsderivation. run-resource-verify.sh's apiserver-binary discovery (currently the one script in the resource-verify skill still hardcoded to/tmp/apiserver; its siblingsBINARY/SCHED_BIN/XTalready resolve from the Meson build dir).- The documented invocation convention for
tests/regression/run.sh(unchanged script; only which binary path callers pointXCEat). deploy-ha.sh's threemake build-server//tmp/apiserver-referencing message strings (its binary-discovery logic itself is out of boundary — see below).- Live-documentation updates:
tech.md,build-deployment.md,testing.md,structure.md,frontend/CLAUDE.md,src/docs/deployment.md,xce-deploy-ha/SKILL.md,src/frontend/docs/status.md,src/docs/apiserver-backend-tasks.md,xce-test-resources/SKILL.md. tests/regression/run.sh's ownXCEbinary-not-found error message (currently reproduces the deletedbuild-clitarget's exact manual recipe).- Two C testsuite files' comments (
test_ha_bootstrap.c,test_ha_ctrlhello.c) pointing readers atmake test-integrationby name. - The root
CLAUDE.md's "Key Files" entry namingsrc/frontend/Makefileas "primary build/test orchestration" — the single most-visible live reference in the repo (loaded into every session). - Both Go modules'
cmd/main.goldflags-injection comments (apiserver/cmd/main.go,xcecli/cmd/main.go) naming the Makefile'sbuild-server/build-clitargets alongsidesrc/tools/go_buildas where GitCommit/BuildTime injection happens.
Out of Boundary
apiserver/meson.build's CGO flag values — only the existing derivation is reused, not redesigned.xce-build.sh's version-fingerprint computation (commit id / build time / dirty fingerprint) — unchanged, remains the single source of truthgo_buildalready reads via meson options.tools/go_builditself — unchanged, reused as-is.deploy-ha.sh's binary-discovery logic (the meson-first //tmp/apiserver-fallback branching itself) — already migrated in a prior session; not re-touched here. Its threemake build-server//tmp/apiserver-referencing message strings ARE in boundary — see File Structure Plan.- Historical/frozen spec documents (
tasks.md/research.md/design.mdof already-completed specs) referencing Makefile targets as acceptance criteria for shipped work. component-failover-adoption'sset -euo pipefailCGO-test-skip gap.- Test content — this is a pure execution-path migration; no test assertions change.
Allowed Dependencies
apiserver/meson.build's existingapiserver_cgo_depslist and the top-levelsrc/meson.buildprogram objects (go_compiler = find_program('go'),pkgconfig) — read/reused, not modified.xce-build.sh's existingcommit_id/build_time/dirty_fingerprintmeson options — read-only dependency, contract unchanged.run-resource-verify.sh's own established$BUILD_DIR/<component>/<binary>discovery convention (already used forBINARY/SCHED_BIN/XT) — the apiserver fix follows this existing in-file pattern, not a new one.
Invariant Cross-Check
This is a pure build-tooling migration — no async I/O, HA/consensus, persistence, or driver/simulation state-equivalence surface is touched. xce-audit-invariants' controller/scheduler dimension lists do not apply; no invariant checklist was skipped.
Revalidation Triggers
- If
apiserver_cgo_deps(the CGO dependency list inapiserver/meson.build) changes, both its consumers — the existingcustom_targetand the new backendtest()— must be updated together; they now share one derivation, so this should no longer be possible to miss, but any refactor of that block should verify both call sites still compile/run. - If
xce-build.sh's version-fingerprint env var contract (XCE_GIT_COMMIT/XCE_BUILD_TIME/XCE_DIRTY_FINGERPRINT) changes shape,go_buildand everycustom_targetdepending on it need re-verification — pre-existing contract, not introduced here, but worth flagging since Requirement 1 asserts it as the single source of truth. - Any future script needing to discover a built apiserver/xcecli binary should follow the Meson-build-dir-first pattern established here and in
deploy-ha.sh, not reintroduce a fixed legacy path.
Architecture
Existing Architecture Analysis
Two independent orchestration paths build the same two Go binaries today:
- Meson (
apiserver/meson.build,xcecli/meson.build) — viatools/go_build, already the path/xce-build apiserver//xce-build alluse for the actual binaries. src/frontend/Makefile— a second, independently-maintained path. Itsbuild-cli/build-servertargets duplicate the version-fingerprint computationxce-build.shalready owns; only itstesttarget has a live caller (xce-build.sh'sapiserver/allcases, 2 call sites,cd frontend && make test).test-backend/test-integrationhave no live caller today — they are developer-manual-only, andbuild-serveris independently confirmed broken (bug-1597).
The sibling xcecli case in xce-build.sh already bypasses Make entirely (cd frontend/xcecli && CGO_ENABLED=0 go test ./... -count=1) — this is the precedent the apiserver unit-test migration mirrors directly.
Architecture Pattern & Boundary Map
flowchart TB
subgraph Before[Before]
XB1[xce-build.sh apiserver/all] --> MT1[make test]
MT1 --> UT1[apiserver + xcecli unit tests]
Dev1[Developer, manual] --> MTB[make test-backend]
MTB --> DerivA[Makefile CGO flag derivation]
Dev2[Developer, manual] --> MTI[make test-integration]
MTI --> BC[build-cli]
MTI --> RunSh1[tests/regression/run.sh]
RVS1[run-resource-verify.sh] --> TmpPath[fixed path /tmp/apiserver]
end
subgraph After[After]
XB2[xce-build.sh apiserver/all] --> GT2[direct go test invocations]
GT2 --> UT2[apiserver + xcecli unit tests]
MesonTest[meson test] --> BackendTest[new backend test target]
BackendTest --> DerivB[apiserver_cgo_deps, shared]
Dev3[Developer, manual] --> RunSh2[tests/regression/run.sh]
RunSh2 --> XCEBin[XCE env pointed at meson build dir binary]
RVS2[run-resource-verify.sh] --> BuildDirPath[BUILD_DIR/frontend/apiserver/xce_apiserver]
CustomTarget[apiserver custom_target] --> DerivB
end
Architecture Integration:
- Selected pattern: Consolidation onto the existing Meson build graph; no new orchestration layer introduced.
- Domain/feature boundaries: build (Meson
custom_target, unchanged) stays separate from test execution (Mesontest()for the backend suite; direct shell/go testinvocation for unit and integration tests) — matching the existing project convention where C tests aremeson test()targets but the E2E regression suite (tests/regression/run.sh) is not. - Existing patterns preserved: the
xceclicase's direct-go test-invocation style (mirrored for apiserver's unit tests); the Mesontest()registration pattern already used for controller/scheduler (build-deployment.md's Test Registration example);run-resource-verify.sh's own$BUILD_DIR/<component>/<binary>discovery convention (mirrored for the one binary — apiserver — not yet following it). - New components rationale: exactly one new component — the backend-test
test()registration — since no Meson-testable equivalent exists today for CGO backend coverage. Everything else is migration of an existing call site, not new architecture. - Steering compliance:
build-deployment.md's "single hermetic build system" philosophy is the explicit target state this spec completes; no async-I/O, HA, or persistence invariants are touched (pure build-tooling change).
Technology Stack
| Layer | Choice / Version | Role in Feature | Notes |
|---|---|---|---|
| Build orchestration | Meson ≥ 1.5 (existing) | Sole build/test path for apiserver, xcecli, and the new backend test target | No version change; reuses go_compiler = find_program('go') already declared in src/meson.build |
| Backend test execution | go test invoked directly by Meson test() |
Runs ./backend/... under real CGO linkage |
No wrapper script — test() invokes the go_compiler program object directly with args/env/workdir |
| Shell tooling | Bash (existing) | xce-build.sh call-site migration, run-resource-verify.sh discovery fix |
No new script introduced |
File Structure Plan
Modified Files
-
src/tools/xce-build.sh— theapiservercase (~line 275) andallcase (~line 322) replacecd frontend && make testwith direct invocations:cd frontend/apiserver && CGO_ENABLED=0 go test ./store/... ./utils/... ./controllers/... ./backend/... -count=1 && cd ../xcecli && CGO_ENABLED=0 go test ./... -count=1— the exact same package set and flagsmake testruns today, just inlined, mirroring thexceclicase's own existing style at line 284. -
src/frontend/apiserver/meson.build— no refactor needed to compute the flags:cgo_cflags/cgo_ldflagsare already file-scope Meson variables from the existingapiserver_cgo_depsforeach loop (lines 20-38). They are not directly usable as-is, though: lines 42-43 append literal@CURRENT_SOURCE_DIR@/@BUILD_ROOT@placeholder text, which today is resolved only by the existingcustom_target's two-step path (meson substitutes those tokens in thecommand:argument list at lines 57-58 into realCURRENT_SOURCE_DIR/BUILD_ROOTenv vars, whichtools/go_build's ownfix_env/fix_input_envsshell functions then sed-substitute into$CGO_CFLAGS/$CGO_LDFLAGSat runtime). The new test bypassesgo_buildentirely (see Non-Goals —go_buildis hardcoded to a singlego buildinvocation, not reusable forgo test, and is out of boundary to modify), so it must resolve these tokens itself at Meson-configure time:resolved_cgo_cflags = cgo_cflags.replace('@CURRENT_SOURCE_DIR@', meson.current_source_dir()).replace('@BUILD_ROOT@', meson.project_build_root())(same pattern forcgo_ldflags) — Meson's own.replace()string method, evaluated once whenmeson.buildis processed, no shell/sed step needed. Add a newtest('apiserver backend', go_compiler, args: ['test', './backend/...', '-count=1'], workdir: meson.current_source_dir(), env: {'CGO_ENABLED': '1', 'CGO_CFLAGS': resolved_cgo_cflags, 'CGO_LDFLAGS': resolved_cgo_ldflags, 'GOFLAGS': '-mod=vendor', 'GOPROXY': 'off', 'GOCACHE': meson.current_build_dir() / 'go-cache', 'GOPATH': meson.current_build_dir() / 'go-path'}, suite: 'apiserver', depends: [libxce])— dict keys are quoted string literals (Meson dict-literal syntax requires this; an unquoted key parses as a variable reference and fails configure) —GOFLAGS/GOPROXYmirrortools/go_build's own offline/hermetic conventions (confirmedapiserver/vendor/is committed).GOCACHE/GOPATHare likewise set explicitly (pinned undermeson.current_build_dir(), not ambient$TMPDIR) since, same as the CGO flags, this test gets none ofgo_build's internal exports for free. -
.claude/skills/xce-test-resources/run-resource-verify.sh— line 203:APISERVER_BINchanges from"${XCE_RESVERIFY_APISERVER_BIN:-/tmp/apiserver}"to"${XCE_RESVERIFY_APISERVER_BIN:-$BUILD_DIR/frontend/apiserver/xce_apiserver}", matching the file's own existingBINARY/SCHED_BIN/XTconvention exactly (no dual-path fallback needed — none of its siblings have one, and/tmp/apiserveris never populated by anything once the Makefile is gone). Line 350's failure message updates from"cd src/frontend && make build-server, or the CGO-flags workaround"to"run /xce-build apiserver", matching the sibling messages' phrasing. Scope rule for every file below (this rule, not any individual line number, is the actual acceptance boundary — three successive review rounds each found a livemake/fixed-path reference the previous enumeration missed in an already-in-scope file, so the line numbers below are a verified starting inventory, not the boundary itself): update every live, current-fact reference to asrc/frontend/Makefiletarget (build-cli/build-server/test/test-backend/test-integration/test-all) or a Makefile-specific fixed path (/tmp/apiserver,/tmp/xce_static) in each named file — including ones in a different section, bullet, or comment block than the ones enumerated here. The Testing Strategy's "Live-reference sweep" is the authoritative completeness check; a task implementing one of these files is not done until that sweep, scoped to that one file, comes back clean. -
.kiro/steering/tech.md— the Build Systems table'sMakerow and itsmake build-server/make build-cli/make test/make test-integrationcode block; also lines 81-82 under "Testing Requirements" (`make test` must pass without a live server./`make test-integration` requires...), found only in review round 3 — same file, different section. -
.kiro/steering/build-deployment.md— the "Go Frontend Build" section'smakecommand block, replaced with the direct invocations this design introduces (unit tests viaxce-build.sh, backend tests viameson test --suite apiserver, integration tests via directtests/regression/run.shinvocation withXCE/URL). -
.kiro/steering/testing.md— the threemake test*bullet points under "Build targets"; the Philosophy line ("A change is not complete untilmake test... passes"); also line 95 under "What Not to Mock" (CGO bridge (`backend/`) is covered by `make test-backend`...), found only in review round 3. -
.kiro/steering/structure.md— the line referencingmake test/make test-all. -
src/frontend/CLAUDE.md— the "Build & Test" code block's fourmakecommands. -
src/docs/deployment.md— the "Build gotcha" section (lines 243-247), already steering developers away frommake build-server; reword now that the target no longer exists at all (from "avoid this, use X instead" to "this Makefile no longer exists, use X"). -
.claude/skills/xce-deploy-ha/SKILL.md— references at lines 40, 165, 453 tomake build-server//tmp/apiserveras a manual pre-step or troubleshooting hint; also the Step 4d intro (~line 294, "a pre-built apiserver binary exists at/tmp/apiserver"), found only in review round 3 — update all to/xce-build apiserverand the Meson build-dir path. -
src/tools/deploy-ha.sh— the twoechostrings in its/tmp/apiserverfallback branch (~162, 164) referencingmake build-server; also the preceding block comment (~lines 138-155, "The apiserver is buildable TWO ways... (2) the standalone Go workflow (cd src/frontend && make build-server)..."), found only in review round 3 — same defect, one file over. The meson-first//tmp/apiserver-fallback branching logic itself is unchanged (out of boundary — already correct); only text describing a now-deleted second build path changes. -
src/frontend/docs/status.md(line 67) — a status checklist line statingRoot Makefile: make test, make test-integration, make test-allas current infrastructure; update to reflect Meson-only tooling. -
src/docs/apiserver-backend-tasks.md(lines ~70, ~120) — twomake testreferences presented as current fact, not as a frozen spec record (this file lives outside.kiro/specs/, so Requirement 6.3's historical-spec exemption does not apply). -
.claude/skills/xce-test-resources/SKILL.md(line 108) — documents$XCE_RESVERIFY_APISERVER_BIN's default as/tmp/apiserver; update alongside the script's own default change (5.1's discovery fix and its documentation must not disagree). -
src/controller/testsuite/test_ha_bootstrap.c(comments at ~lines 290, 338, 388) andtest_ha_ctrlhello.c(comment at ~line 13) — each points a reader to "make test-integration" as where certain HA retry/tag/call-chain behavior is validated end-to-end. A 3-line rename to reference the regression suite directly (tests/regression/run.sh) rather than the deleted target; no test logic changes. -
Root
CLAUDE.md(line 42) — the "Key Files" entry`src/frontend/Makefile` — primary build/test orchestrationis deleted or replaced with the Meson-based equivalent (e.g.src/tools/xce-build.sh— already listed elsewhere in the same file's Build Commands). -
src/frontend/apiserver/cmd/main.go(~lines 25-27) andsrc/frontend/xcecli/cmd/main.go(~lines 39-41) — each has a comment reading "injected at link time via-ldflags... (seesrc/tools/go_buildandsrc/frontend/Makefile'sbuild-server/build-clitarget)"; drop the Makefile clause, keeping onlysrc/tools/go_build. -
src/frontend/tests/regression/run.sh(line 69) — theXCEbinary-not-found error currently says"Build with: cd xcecli && CGO_ENABLED=0 go build -o /tmp/xce_static ./cmd/main.go", reproducing the deletedbuild-clitarget's exact manual recipe (5.2's own literal example of what must not remain). Update to name/xce-build apiserver(which also buildsxcecli) instead. TheXCE="${XCE:-/tmp/xce_static}"default (line 12) is left as an inert placeholder — callers are still expected to passXCE=explicitly (testing.md already documents this as a required env var), so only the error-message content needs to stop pointing at a deleted target.
Deleted Files
src/frontend/Makefile— removed only after the above are landed and verified (see Migration Strategy).
Unchanged (verified, not modified)
src/frontend/tests/regression/run.sh's core logic (still a standalone, parameterized script driven byXCE/URLenv vars) — only its not-found error message changes, per above. The Makefile'stest-integrationtarget added no logic beyond renamingXCE_BIN→XCE/SRV_URL→URL; once removed, callers invokerun.shdirectly with those two env vars, pointed at a Meson-builtxceclibinary (<build_dir>/frontend/xcecli/xcecli) instead of the Makefile'sbuild-clioutput.src/tools/go_build,apiserver/meson.build's existingcustom_target,xcecli/meson.build— unchanged.
System Flows
The Before/After flow is fully captured in the Architecture diagram above; no additional sequence diagram is needed — this is a call-site substitution, not a new multi-party interaction.
Requirements Traceability
| Requirement | Summary | Components | Flows |
|---|---|---|---|
| 1.1, 1.2, 1.3 | Single build path; one fingerprint source; Makefile deleted once 2-4 covered | xce-build.sh (build already Meson-only), Makefile deletion |
Migration Strategy Phase 4 |
| 2.1, 2.2, 2.3 | Unit tests run without Makefile, same behavior, clear failure reporting | xce-build.sh direct go test call sites |
Migration Strategy Phase 2 |
| 3.1, 3.2, 3.3 | CGO backend suite runnable without Makefile, single CGO derivation, no coverage regression | apiserver/meson.build new test() |
Migration Strategy Phase 1 |
| 4.1, 4.2, 4.3 | Integration suite targets canonical-build binary, same scope/pass-fail criteria | tests/regression/run.sh invocation convention (unchanged script) |
Migration Strategy Phase 3 |
| 5.1, 5.2, 5.3 | Binary discovery from canonical build dir; clear error naming the surviving command; no sole dependency on fixed legacy path | run-resource-verify.sh APISERVER_BIN fix, deploy-ha.sh message strings |
Migration Strategy Phase 3 |
| 6.1, 6.2, 6.3 | Live docs reference only the surviving system; historical docs untouched | 11 doc files (plus 2 C testsuite and 2 Go source comment fixes) listed in File Structure Plan | Migration Strategy Phase 3 |
Components and Interfaces
| Component | Domain/Layer | Intent | Req Coverage | Key Dependencies (P0/P1) | Contracts |
|---|---|---|---|---|---|
xce-build.sh unit-test invocation |
Build tooling | Run apiserver/xcecli unit tests without Make | 2.1, 2.2, 2.3 | go toolchain (P0) |
Batch |
apiserver/meson.build backend test() |
Build tooling | Run CGO backend suite via Meson, reusing existing CGO derivation | 3.1, 3.2, 3.3, 1.2 | apiserver_cgo_deps (P0), go_compiler (P0), libxce (P0) |
Batch |
run-resource-verify.sh binary discovery |
Verification tooling | Locate the apiserver binary from the canonical build dir | 5.1, 5.2, 5.3 | Meson build dir layout (P0) | Batch |
tests/regression/run.sh invocation convention |
Verification tooling | Run the E2E regression suite against a canonical-build binary | 4.1, 4.2, 4.3 | Meson-built xcecli binary (P0), live apiserver (P0) |
Batch |
deploy-ha.sh message strings |
Verification tooling | Stop naming a deleted Makefile target in fallback/warning text | 5.2, 5.3, 6.2 | — | — |
| Documentation set (11 files) | Docs | Reference only the surviving build system | 6.1, 6.2, 6.3 | — | — |
Only the backend test() registration introduces a genuinely new boundary (a new Meson test target with its own env/dependency contract); the rest are call-site substitutions in already-existing scripts, so they are covered by the summary table plus the File Structure Plan detail above rather than full component blocks.
Build Tooling
apiserver backend test() target
| Field | Detail |
|---|---|
| Intent | Run the CGO-backed apiserver/backend/... test suite under Meson, with zero independent CGO-flag derivation |
| Requirements | 3.1, 3.2, 3.3, 1.2 |
Responsibilities & Constraints
- Owns: registering the test with Meson's test runner (
suite: 'apiserver') someson test -C <dir> --suite apiserver(and fullmeson test) picks it up. - Does not own: the CGO flag values themselves — reads
apiserver_cgo_deps's already-computedcgo_cflags/cgo_ldflags, the same values the existingcustom_target('apiserver', ...)in the same file already uses. - Must not add
-race— confirmed unusable in this project's ASAN-linked CGO environment (component-failover-adoption/tasks.md:197, hit 3 times independently).
Dependencies
- Inbound:
meson test//xce-build apiserver's test-running step (P0) - Outbound:
apiserver_cgo_depsderivation,libxcebuild target (P0 — must build before this test can link) - External:
gotoolchain viago_compilerprogram object (P0)
Contracts: Batch [x]
Batch / Job Contract
- Trigger:
meson test(any invocation covering theapiserversuite, including baremeson test -C <dir>) - Input / validation: requires
libxce.aand its generated headers already built in the same build dir (depends: [libxce]enforces build ordering) - Output / destination: standard Meson test log; non-zero exit on any
go testfailure - Idempotency & recovery:
go test -count=1(no test caching across runs, matching every other Go test invocation in this codebase)
Implementation Notes
- Integration: env additionally sets
GOFLAGS=-mod=vendor,GOPROXY=off, and writableGOCACHE/GOPATHunder the build dir's own tmp space — mirroringtools/go_build's existing hermetic/offline conventions, since this is the first placeapiserver/backend's real CGO path is exercised from inside the Meson/Nix sandbox rather than a developer's ambient shell. - Validation: confirm
meson test -C <dir> --suite apiserver(both standalone and as part of/xce-build apiserver's existing test step) reports this new test, and that it fails for the expected reason ifapiserver_cgo_depsis temporarily broken (proving it isn't silently skipped). - Risks: this is the one genuinely new capability in the migration — its correctness (does it actually build+run
backend/clib.go's real CGO path, not the!cgostub) is the primary thing Testing Strategy below must prove before Migration Strategy Phase 4 (Makefile deletion) is safe.
Testing Strategy
-
Unit-level (invocation correctness): after migrating
xce-build.sh's two call sites, confirm/xce-build apiserverand/xce-build allstill run exactly the same apiserver/xcecli test package set (./store/... ./utils/... ./controllers/... ./backend/...for apiserver,./...for xcecli) with the same pass/fail counts as the pre-migrationmake test-driven baseline. -
New capability verification: run
meson test -C <dir> --suite apiserver(and full/xce-build apiserver) and confirm the new backend test target appears, links against reallibxce(not the//go:build !cgostub), and passes with no compiler/linker error referencing a literal@CURRENT_SOURCE_DIR@/@BUILD_ROOT@string (the specific failure mode of an unresolved placeholder token reachinggo test); then deliberately breakapiserver_cgo_deps(e.g. comment outlibrtti_dep) and confirm the new test fails for the expected linker/undefined-symbol reason — proving it exercises the real CGO path, not a vacuous pass. -
Discovery-path regression: with
src/frontend/Makefiledeleted, runrun-resource-verify.shend-to-end and confirmAPISERVER_BINresolves to the Meson build dir and the apiserver layer is reachable; confirm the failure message (binary artificially removed) names/xce-build apiserver, not a deleted Makefile target. -
E2E regression parity: run
tests/regression/run.shdirectly (XCE=<meson-built xcecli path> URL=<live apiserver> bash tests/regression/run.sh) against a live apiserver and confirm the same PASS/FAIL/SKIP counts as the pre-migrationmake test-integrationbaseline. -
Live-reference sweep: run BEFORE Phase 4 (Makefile deletion), scoped to each file named in File Structure Plan, and again as a full-repository pass after — grep for
make (build-server|build-cli|test|test-backend|test-integration|test-all)AND/tmp/apiserver//tmp/xce_static. Running it per-file before deletion (not only repo-wide after) is what makes the File Structure Plan's "every live reference, not just the enumerated ones" scope rule actually enforceable, rather than relying on the enumeration being exhaustive. The full-repository pass will legitimately still hit files that are not violations — name these exclusion classes explicitly rather than leaving "zero hits" as an unachievable, ambiguous bar an implementer would otherwise have to rediscover by judgment call:.kiro/specs/**— historical spec documents (Requirement 6.3's own exemption), including this spec's ownbrief.md/research.md/requirements.md/design.md, which necessarily discuss the very targets being removed.**/vendor/**— third-party vendored dependency files (e.g.go.uber.org/zap's ownCONTRIBUTING.md) whosemake testrefers to that upstream project, not XCE's.- Dated historical records:
CHANGES.md,reports/*.md,docs/superpowers/plans/*.md,src/docs/archive/**— frozen snapshots of past state, not live guidance. .kiro/steering/roadmap.md's entry for this very spec (~line 82) — describes this spec's own backlog/discovery history, not a live instruction..wolf/memory.md,.wolf/cerebrum.md,.wolf/buglog.json— OpenWolf's own append-only session/bug logs, not authoritative project documentation.src/frontend/tests/regression/run.sh:12— theXCE="${XCE:-/tmp/xce_static}"default is a deliberately-retained inert placeholder (see File Structure Plan); only its error-message content (line 69) is required to change, not this default value itself.
Any hit NOT falling into one of the above classes is a real gap and must be fixed before Phase 4.
Migration Strategy
Phased, coverage-preserving order — the CGO backend test gap (Phase 1) must close before the Makefile can be safely removed (Phase 4), matching Requirement 3.3's explicit non-regression constraint.
flowchart LR
P1[Phase 1: add Meson backend test target] --> P3[Phase 3: fix run-resource-verify.sh discovery + update docs + document run.sh invocation]
P2[Phase 2: migrate xce-build.sh unit-test call sites] --> P3
P3 --> P4[Phase 4: delete src/frontend/Makefile]
- Phase 1 (Requirement 3) and Phase 2 (Requirement 2) have no dependency on each other — different files, no shared state — and may be implemented and landed in parallel. Phase 1 is net-new capability, zero risk to existing behavior. Phase 2 mirrors the already-proven
xceclipattern; low risk. - Phase 3 (Requirements 4, 5, 6): depends on both Phase 1 and Phase 2, since the documentation this phase writes describes the final Makefile-free state of both the build and the backend test target. Mechanical once Phases 1-2 land — the real reference list and exact line numbers are already enumerated in File Structure Plan.
- Phase 4 (Requirement 1): the only phase that is hard to reverse cheaply — gated on Phases 1-3 having landed and their own verification (Testing Strategy above) having passed.
- Rollback trigger: if Phase 1's backend test reveals
apiserver_cgo_depscannot be cleanly shared between thecustom_targetand the newtest()(e.g. a Meson version limitation on reusing computed variables across targets in the same file), stop before Phase 4 and re-evaluate Requirement 3.2 rather than forcing a second, duplicate CGO-flag derivation into existence — that would defeat this spec's own purpose. - Validation checkpoint: run the full Testing Strategy section after Phase 3, before executing Phase 4.