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
84 lines
15 KiB
Markdown
84 lines
15 KiB
Markdown
## Summary
|
|
- **Feature**: `eliminate-frontend-makefile`
|
|
- **Discovery Scope**: Extension (existing build system, light discovery — brief.md's own Path C investigation already covered most of the ground; this pass verified currency and filled architecture-level gaps)
|
|
- **Key Findings**:
|
|
- Only one live automated caller of `src/frontend/Makefile` exists today: `xce-build.sh`'s two `cd frontend && make test` call sites (`apiserver` and `all` cases). `build-cli`/`build-server`/`test-backend`/`test-integration` have no live automated caller — they are developer-manual-only.
|
|
- `apiserver/meson.build` already computes the exact CGO flags (`apiserver_cgo_deps`: librtti, c-capnproto, openssl, tinylog, math, rt) the Makefile's `test-backend` independently re-derives via pkg-config. A shared derivation is directly reusable for a new `test()` target — no new mechanism needed.
|
|
- `xcecli`'s case in `xce-build.sh` already bypasses Make entirely (direct `go test` invocation) — this is a live, working precedent for the apiserver unit-test migration, not a hypothetical pattern.
|
|
- `run-resource-verify.sh` already has an established `$BUILD_DIR/<component>/<binary>` discovery convention for its other three binaries (`BINARY`, `SCHED_BIN`, `XT`); only `APISERVER_BIN` is the odd one out still hardcoded to `/tmp/apiserver`.
|
|
- `tests/regression/run.sh` is already a standalone, fully-parameterized script (`XCE`/`URL` env vars). The Makefile's `test-integration` target added zero logic beyond an env-var rename (`XCE_BIN`→`XCE`, `SRV_URL`→`URL`) plus a `build-cli` prerequisite. No new script is needed for Requirement 4 — only documentation of the direct invocation.
|
|
|
|
## Research Log
|
|
|
|
### Live automation dependency surface
|
|
- **Context**: requirements.md's Boundary Context needed to state precisely what currently depends on the Makefile, to scope the coverage-preservation requirements accurately.
|
|
- **Sources Consulted**: `grep -rn --include="*.sh" -E '\bmake\b' src/tools/ .claude/skills/`, direct read of `xce-build.sh` lines 255-328.
|
|
- **Findings**: Exactly 2 live `make` invocations exist in the whole repo's live automation (`xce-build.sh:275`, `:322`, both `cd frontend && make test`). `deploy-ha.sh` and `run-resource-verify.sh` reference the Makefile only in human-facing strings (error/log messages) or by checking for its *output path*, never by executing `make`.
|
|
- **Implications**: The coverage-preservation requirements (2, 3, 4) protect manual developer workflows and documentation accuracy, not any existing automated pipeline — this made scope smaller and safer than it might first appear, and confirmed as a direct answer to a user clarifying question during the requirements phase.
|
|
|
|
### CGO backend test flag derivation reuse
|
|
- **Context**: requirements.md 3.2 requires the new backend test path to derive CGO flags from "the same single source" as Meson's existing apiserver build, not a second independent derivation (the exact failure mode this whole spec exists to eliminate).
|
|
- **Sources Consulted**: `apiserver/meson.build` (full read), `src/meson.build` (`go_compiler = find_program('go')`, `pkgconfig = find_program('pkg-config')`), `src/frontend/Makefile`'s own `test-backend` recipe (`FRONTEND_CGO_PKGS := librtti c-capnproto openssl tinylog`, `-lm -lrt`).
|
|
- **Findings**: `apiserver/meson.build`'s `apiserver_cgo_deps` loop already produces `cgo_cflags`/`cgo_ldflags` covering the identical dependency set the Makefile independently re-derives via pkg-config. `go_compiler` (the raw `go` program object) is already available at top-level scope — no new `find_program()` call needed.
|
|
- **Implications**: A new `test()` in the same file can read the same `cgo_cflags`/`cgo_ldflags` variables the existing `custom_target` already computes — genuinely one derivation, not two, satisfying 3.2 directly rather than by convention/discipline.
|
|
|
|
### `run-resource-verify.sh`'s own established discovery pattern
|
|
- **Context**: requirements.md 5.1-5.3 needed a concrete replacement for `run-resource-verify.sh`'s `/tmp/apiserver` default.
|
|
- **Sources Consulted**: full grep of `_BIN=`/`BUILD_DIR` in `run-resource-verify.sh`.
|
|
- **Findings**: `BINARY`, `SCHED_BIN`, `XT` already resolve as `"${ENV_VAR_OVERRIDE:-$BUILD_DIR/<component>/<binary>}"`, each independently overridable, with `$BUILD_DIR` defaulting to `$REPO/src/xce.build`. Only `APISERVER_BIN` deviates, hardcoded to `/tmp/apiserver` with no `$BUILD_DIR`-relative default at all.
|
|
- **Implications**: the correct fix is not "mirror `deploy-ha.sh`'s dual-path pattern" as brief.md's Downstream section literally suggested, but "match this script's own sibling convention exactly" — see Design Decision below.
|
|
|
|
## Architecture Pattern Evaluation
|
|
|
|
| Option | Description | Strengths | Risks / Limitations | Notes |
|
|
|--------|-------------|-----------|----------------------|-------|
|
|
| Meson `test()` reusing `apiserver_cgo_deps` | New backend test target shares the existing `custom_target`'s CGO derivation | Single source of truth (satisfies 3.2 directly); no wrapper script | Requires the derivation to be readable by both a `custom_target` and a `test()` in the same `meson.build` — confirmed straightforward, both are just Meson variables in scope | **Selected** |
|
|
| Standalone shell script re-deriving CGO flags via pkg-config | Keep a Makefile-free script mirroring the Makefile's own `test-backend` pkg-config derivation | Avoids touching `apiserver/meson.build` | Reintroduces exactly the duplicate-derivation risk this spec exists to eliminate | Rejected (brief.md's own "not recommended" option 2) |
|
|
|
|
## Design Decisions
|
|
|
|
### Decision: `run-resource-verify.sh`'s `APISERVER_BIN` follows its own sibling convention, not `deploy-ha.sh`'s dual-path fallback
|
|
- **Context**: brief.md's Downstream section suggested mirroring `deploy-ha.sh`'s meson-first / `/tmp/apiserver`-fallback pattern.
|
|
- **Alternatives Considered**:
|
|
1. Mirror `deploy-ha.sh`'s dual-path pattern (meson path first, `/tmp/apiserver` fallback).
|
|
2. Match `run-resource-verify.sh`'s own existing `BINARY`/`SCHED_BIN`/`XT` convention (single `$BUILD_DIR`-relative default, no fallback).
|
|
- **Selected Approach**: Option 2.
|
|
- **Rationale**: once `src/frontend/Makefile` is deleted, nothing in the project's own tooling will ever populate `/tmp/apiserver` again — a fallback to it is a fallback to a path only a developer's own hand-run `go build` could produce, which is not a real safety net worth the inconsistency of being the only binary in this script with different default-resolution logic than its three siblings.
|
|
- **Trade-offs**: slightly diverges from the brief's literal suggestion, but produces a more internally consistent script and satisfies requirements.md 5.3 ("shall not require... as its only means") without needing a fallback at all, since the primary path is now proven reliable (Meson always builds apiserver via `/xce-build apiserver`/`all`).
|
|
- **Follow-up**: `deploy-ha.sh`'s own `/tmp/apiserver` fallback becomes similarly vestigial once the Makefile is gone — out of boundary for this spec (already migrated in a prior session per brief.md), but worth flagging as a small future cleanup, not a blocker here.
|
|
|
|
### Decision: No wrapper script for the new backend test target
|
|
- **Context**: Meson `test()` needs an executable; `go test` with CGO env and a specific working directory could be wrapped in a small shell script for clarity.
|
|
- **Alternatives Considered**:
|
|
1. A thin wrapper shell script invoking `go test` with the right env, registered as the `test()`'s executable.
|
|
2. `test()` invokes the `go_compiler` program object directly, with `args`, `env`, and `workdir` kwargs.
|
|
- **Selected Approach**: Option 2.
|
|
- **Rationale**: Meson's `test()` natively supports `workdir` and `env`; no wrapper is needed, and one fewer file avoids exactly the kind of incidental indirection this spec exists to remove elsewhere.
|
|
- **Trade-offs**: revised after an independent adversarial review round (2026-09-03) caught a real one: `cgo_cflags`/`cgo_ldflags` contain literal `@CURRENT_SOURCE_DIR@`/`@BUILD_ROOT@` placeholder text that is normally resolved by `tools/go_build`'s own `fix_env` sed machinery — bypassing `go_build` means bypassing that resolution too. Fixed by resolving both tokens directly with Meson's own `.replace()` string method at configure time (`cgo_cflags.replace('@CURRENT_SOURCE_DIR@', meson.current_source_dir()).replace('@BUILD_ROOT@', meson.project_build_root())`) rather than reintroducing a wrapper script — still net simpler than Option 1, but not the zero-cost choice the first design pass assumed.
|
|
|
|
### Decision: `deploy-ha.sh`'s dead-target message strings are in boundary even though its discovery logic is not
|
|
- **Context**: the first design draft excluded `deploy-ha.sh` entirely as "already migrated in a prior session," reasoning from the binary-discovery *logic* (genuinely already meson-first). An independent adversarial review round caught that its three `make build-server`/`/tmp/apiserver`-referencing `echo` strings (lines ~157-164) were not part of that prior migration and would still tell a developer to run a target that no longer exists, once `src/frontend/Makefile` is deleted.
|
|
- **Selected Approach**: split the file's two concerns — discovery logic (out of boundary, unchanged) vs. message text (in boundary, added to File Structure Plan) — rather than treating "already touched once" as "fully out of scope."
|
|
- **Follow-up**: none needed beyond the File Structure Plan entry; this is a 2-string text edit, not a logic change.
|
|
|
|
### Decision: `status.md` and `apiserver-backend-tasks.md` are live documentation, not historical spec records
|
|
- **Context**: requirements.md 6.3 exempts historical, already-completed *spec* documents from doc updates. An independent adversarial review round found two files outside `.kiro/specs/` (`src/frontend/docs/status.md:67`, `src/docs/apiserver-backend-tasks.md:70,120`) stating `make test`/`make test-integration` as current fact — missed by the original brief's doc inventory, which only enumerated files already known to be live-authoritative.
|
|
- **Selected Approach**: treat both as live documentation in scope for update, since 6.3's exemption is worded specifically around ".kiro/specs" historical records, not arbitrary status/changelog files elsewhere in the repo.
|
|
- **Follow-up**: added both to File Structure Plan.
|
|
|
|
### Decision: doc-file File Structure Plan entries state a scope rule, not a closed line-number list
|
|
- **Context**: three successive independent adversarial review rounds each found at least one live `make`-target/fixed-path reference in a file the design already had in scope, in a section/line the enumeration hadn't named (round 1: two new doc files entirely; round 2: `xce-test-resources/SKILL.md`, `run.sh`'s error message; round 3: `tech.md`:81-82, `testing.md`:95, `deploy-ha.sh`:138-155's comment block, `xce-deploy-ha/SKILL.md`:294 — all in files already listed). A closed line-number enumeration kept being treated as if it were the completeness boundary, when it was really just a snapshot of what one investigation pass happened to find.
|
|
- **Selected Approach**: reworded every doc/script File Structure Plan entry around a stated scope rule ("every live reference in this file," not just the enumerated lines) and moved the Testing Strategy's live-reference sweep to run per-file BEFORE Phase 4, not only repo-wide after — so a task implementing one file is verifiably complete against that file's own grep, independent of whether this design's own enumeration was exhaustive.
|
|
- **Rationale**: the recurring pattern strongly suggested the enumeration approach itself, not any individual miss, was the actual defect — fixing instances one at a time without changing the underlying acceptance criterion risked a fourth, fifth round finding the same class of gap indefinitely.
|
|
- **Follow-up**: a fourth review round found the sweep's own "zero hits" bar was itself unachievable as worded (several legitimate, deliberately-excluded classes — vendored files, dated historical records, an inert placeholder default, OpenWolf's own logs — all match the same grep). Named each exclusion class explicitly in the Testing Strategy rather than leaving "zero hits" ambiguous; also found two C testsuite files (`test_ha_bootstrap.c`, `test_ha_ctrlhello.c`) with comments naming `make test-integration` by name, outside any doc/script file category considered so far — added to File Structure Plan (a 3-line rename, not a logic change). A fifth review round, specifically scanning `.go` source-file comments (a category rounds 1-4 never checked), found two more: the ROOT `CLAUDE.md`'s "Key Files" entry (line 42, the single most-visible live reference in the repo — loaded into every session, distinct from the already-covered `src/frontend/CLAUDE.md`) and both Go modules' `cmd/main.go` ldflags-injection comments naming the Makefile's `build-server`/`build-cli` targets. Both added to File Structure Plan. The recurring lesson across rounds 1, 4, and 5: each round's "fresh eyes, no assumptions" instruction and switch to an unchecked file *category* (docs → scripts → C test comments → Go source comments) is what surfaces genuinely new gaps — re-reading the same already-covered files more carefully stopped finding anything past round 2.
|
|
|
|
## Risks & Mitigations
|
|
- **Risk**: the new backend `test()` silently links against `backend/stub.go` (the `//go:build !cgo` fallback) instead of the real CGO path, producing a vacuous pass. **Mitigation**: Testing Strategy's "New capability verification" step deliberately breaks `apiserver_cgo_deps` and confirms the test fails for the expected linker reason before trusting a green run.
|
|
- **Risk**: deleting the Makefile before all manual-developer-only targets (`test-backend`, `test-integration`) have a proven equivalent silently drops coverage nobody notices until someone needs it. **Mitigation**: Migration Strategy's explicit Phase ordering (1-3 must land and be verified before Phase 4).
|
|
- **Risk**: `run-resource-verify.sh`'s new discovery default assumes `$BUILD_DIR` (`$REPO/src/xce.build`, the `asan` profile dir) always contains a built apiserver — true only after `/xce-build apiserver`/`all` has actually been run. **Mitigation**: this matches the existing behavior/risk profile of the script's other three binaries (`BINARY`/`SCHED_BIN`/`XT`), which already assume the same; no new risk class introduced.
|
|
|
|
## References
|
|
- `.kiro/specs/eliminate-frontend-makefile/brief.md` — original Path C discovery investigation (2026-08-27), the primary source for scope/seam decomposition.
|
|
- `src/tools/xce-build.sh` (lines 255-328) — live call-site evidence.
|
|
- `src/frontend/apiserver/meson.build`, `src/meson.build` — CGO derivation and program-object reuse evidence.
|
|
- `.claude/skills/xce-test-resources/run-resource-verify.sh` (lines 200-207, 348-351) — existing sibling discovery convention.
|