Both sub-tasks 2.1 and 2.2 were already done and committed; the container checkbox itself was missed during the task loop. All 21 checkboxes (16 leaf tasks + 5 container headers) are now marked complete. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
21 KiB
Implementation Plan
-
1. Foundation: dirty_fingerprint meson option and C-wide define
dirty_fingerprintmeson option (string, default'') added insrc/meson.options, byte-for-byte matchingcommit_id/build_time's style/type/yield;add_project_arguments()extended with-DVERSION_DIRTY_FINGERPRINT=- Observable confirmed live (independently re-verified by review, fresh scratch build): a bare
meson setupwith zero-Doptions configures cleanly (73 targets); all 542 C compile commands contain the new define (empty string), matching the existing two defines' counts exactly; no consumption code touched yet - Requirements: 1.1, 5.1
-
2. Foundation: compute real fingerprint values at both build entry points
-
2.1 (P) xce-build.sh computes the dev-loop fingerprint, independently of commit_id
dirty_fingerprintcomputed viagit diff HEAD+git ls-files -z --others --exclude-standard | LC_ALL=C sort -zcontent,sha256sumtruncated to 8 hex chars; empty on a clean tree or on computation failure (3 independently-verified graceful-degradation paths: mktemp failure, sha256sum failure, git diff failure -- none abort the script despiteset -euo pipefail); zero working-tree/index mutation (read-only git invocations only);commit_id's own computation left byte-for-byte untouched- Observable confirmed live (independently re-verified by review, real builds with HEAD pinned to control for concurrent background commits): editing a tracked file and rebuilding produces a fingerprint; different content produces a different fingerprint; reverting to the first edit's exact bytes reproduces the first fingerprint exactly; a
.gitignore-matched*.bakfile leaves the fingerprint unchanged;commit_id's-dirtysuffix stayed intact across every build; every profile (asan/debug/release) carries the option; the original feature's unmodifiedtest-build-version-regression.shpasses twice in full (asan+debug) - Requirements: 1.1, 1.2, 1.3, 1.4, 5.1
- Boundary: xce-build.sh
-
2.2 (P) Nix flake computes the fingerprint via self.narHash at eval time, independently of myCommitId
myDirtyFingerprintcomputed asbuiltins.hashString "sha256" self.narHashtruncated to 8 hex chars (self.narHashis Nix's SRI base64 format, not hex -- rehashing was confirmed necessary, not optional), gated on the samehasAttr "shortRev"-style clean/dirty branchmyCommitIdalready uses; threaded throughnixSupport/default.nixintoxce.nix/xcecli.nix's eval-timemesonFlagslist as-Ddirty_fingerprint=, alongside the untouched-Dcommit_id=;build_time's separatepreConfigure/mesonFlagsArraymechanism left completely undisturbed- Observable confirmed live (independently re-verified by review, including a full re-run of both
nix build ./src#xcecore_debugand./src#xcecli, no--impure):nix evalresolves a real, non-empty, content-sensitive-Ddirty_fingerprint=value matching an independent Python cross-check; editing a tracked file changes the resolved value;-Dcommit_id=unaffected throughout;nix logconfirms both values reach the realmesonConfigurePhaseinvocation. Full artifact completion is blocked in this sandbox by a pre-existing, unrelated network limitation (an autoscaler Go module fetch needinggoproxy.cn, confirmed recurring identically on two disjoint Go module sets) -- not a regression from this task, and orthogonal to the eval/meson-configuration behavior this task's Observable actually requires - Requirements: 1.1, 1.2, 1.3, 5.1
- Boundary: Nix packaging
-
3. Core: C daemon --version fingerprint display
-
3.1 Extend the shared version-composition mechanism with an optional fingerprint field, without touching commit_id
- New sibling function
xce_compose_version_ex()added alongside the completely untouchedxce_compose_version()(zero diff lines in its body or its 3 pre-existing tests); anchors the-dirtystrip via a true tail-slicestrcmp(notstrstr), so it cannot false-match a-dirtysubstring elsewhere; correctly appends-<fingerprint>with exactly one dash even when the commit field has no-dirtyto strip; delegates via a genuinereturn xce_compose_version(...)call (not a re-implementation) when the fingerprint is empty/NULL, structurally guaranteeing byte-identical output, proven by a dedicated equivalence regression test - No
main.ccall sites were touched by this task (grep-confirmed all still call the original, untouchedxce_compose_version()) -- that's tasks 3.2/3.3's job - Observable confirmed live (independently re-verified by review, full lib suite on both debug and ASAN profiles): 301 tests, 0 failures, 0 ignored on both profiles; all 3 required cases present with byte-exact assertions, plus 2 meaningful additional regression/defensive tests; buffer handling confirmed snprintf-bounded with no overflow risk
- Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 3.1, 3.2, 5.2
- Boundary: utils.h, utils.c
- New sibling function
-
3.2 (P) Controller and scheduler: fingerprint in --version, startup log unaffected
argp_program_versionfor controller/scheduler now composed via a genuinely separate buffer/call toxce_compose_version_ex()(readingSTR(VERSION_DIRTY_FINGERPRINT), matching the existing commit_id/build_time macro pattern); the startup-log call site'sxce_compose_version()call, arguments, and buffer are byte-for-byte unchanged (independently verified by review via diff + grep);controller/testsuite/test.c(no startup log, confirmed via grep) got a direct in-place swap; all three files carry explicit code comments marking the divergence as deliberate- Observable confirmed live (independently re-verified by review, real builds + live daemon starts):
xce_controller --version/xce_test --version/xce_scheduler --versionall show<commit>-<fingerprint>, cross-checked againstcompile_commands.json; live controller and scheduler startup logs show the old<commit>-dirtyformat unchanged, fingerprint never present, build_time matching--versionexactly - Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 3.1, 3.2, 4.1
- Boundary: controller/main.c, scheduler/main.c, controller/testsuite/test.c
- Depends: 3.1
-
3.3 (P) Worker: fingerprint in --version, startup log unaffected
OPT_VERSION's case now composes via a genuinely separateversion_display_buf/xce_compose_version_ex()call, byte-for-byte mirroring task 3.2's already-approved controller/scheduler pattern (independently confirmed by review via direct diff comparison against commitfd62e26); bothXCECD_LOGstartup-log call sites (--peersand no---peers) left completely untouched, samexce_compose_version()call, sameversion_buf- Observable confirmed live (independently re-verified by review, real build + live daemon runs in both branches):
xcecd --versionshows<commit>-<fingerprint>matchingcompile_commands.jsonexactly,-dirtycorrectly stripped not doubled; both startup log branches show the old fingerprint-less<commit>-dirtyformat unchanged - Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 3.1, 3.2, 4.1
- Boundary: worker/main.c
- Depends: 3.1
-
4. Core: Go binary --version/-version fingerprint display
-
4.1 go_build injects the fingerprint via ldflags
go_buildreadsXCE_DIRTY_FINGERPRINT(empty-safe) and appends-X main.DirtyFingerprint=...to the existing-ldflagsconstruction; falls back to plain empty string (deliberately NOT"unknown", unlikeGitCommit/BuildTime), matchingdirty_fingerprint's convention everywhere else in this feature; the existingGitCommit/BuildTimeunknown-fallback logic is completely untouched- Observable confirmed live (independently re-verified by review, real scratch Go builds traced via
bash -x): fingerprint unset ->-X main.DirtyFingerprint=empty, binary confirms empty (not fabricated); fingerprint set -> flag carries the exact value; all three vars unset ->GitCommit/BuildTimestill fall back tounknown,DirtyFingerprintstays empty, the two fallback conventions coexist without interference - Requirements: 1.1, 5.1
- Boundary: go_build script
-
4.2 (P) apiserver and xcecli meson builds pass the resolved value through
- Both
apiserver/meson.buildandxcecli/meson.buildadd'XCE_DIRTY_FINGERPRINT=' + get_option('dirty_fingerprint'), unquoted, identically positioned to the existingXCE_GIT_COMMIT/XCE_BUILD_TIMEentries - Observable confirmed live (independently re-verified by review with a distinct test value, fresh configure, and real
ninjabuilds of both binaries): the value reachesgo build's real invocation and shows up ingo version -m's recorded-ldflagsbuild setting for both apiserver and xcecli; matches the C-side-DVERSION_DIRTY_FINGERPRINT=byte-for-byte from the same configure; degrades to empty identically to the two pre-existing vars when omitted - Requirements: 1.1, 4.1
- Boundary: apiserver/meson.build, xcecli/meson.build
- Depends: 4.1
- Both
-
4.3 (P) Makefile dev-loop path computes the same fingerprint, independently of GIT_COMMIT
GIT_COMMIT/GIT_STATUS/BUILD_TIME(andGIT_COMMIT's own-dirtysuffix) confirmed byte-for-byte untouched throughout two rounds of adversarial remediationDIRTY_FINGERPRINTcomputed independently, mirroring task 2.1's algorithm exactly (cross-checked byte-identical on the real dirty tree); failure-detection required two remediation rounds to get right -- round 1 fixed a{ git diff HEAD; ...; } >filegrouped command silently swallowing agit diff HEADfailure (only the last command's exit status was checked); round 2 found the SAME class of bug one step further down (git ls-files | sort | xargs cat's pipe also swallowing anls-filesfailure) and fixed it by pullinggit ls-filesout of the pipe entirely into its own directly-redirected, individually-checked step -- deliberately choosing this over aset -o pipefail;prefix (which empirically also worked) because this repo's ownbuild-deployment.mddocuments a past incident of code silently relying on/bin/shhappening to be bash with noSHELL:=bashpin- One narrow, explicitly-disclosed residual gap remains and was assessed as acceptable: a
sort-only failure (notcat) in the trailingsort -z | xargs -0 -r cat --pipe can still be masked -- independently confirmed present, low-risk, and accurately scoped, not grounds for further rejection - Observable confirmed live (independently re-verified across 3 review rounds, real builds + two independently-reproduced failure-injection wrappers with control tests proving each wrapper genuinely triggers the old bug):
make -n build-cli's fingerprint matches a standalone reference computation byte-for-byte; both thegit diff-fails andgit ls-files-fails scenarios correctly degrade to empty, not a fabricated hash;GIT_COMMIT's-dirtybehavior unaffected throughout - Requirements: 1.1, 1.2, 1.3, 1.4, 5.1
- Boundary: Makefile
- Depends: 4.1
-
4.4 (P) apiserver: fingerprint in -version, startup log unaffected
DirtyFingerprintpackage var (default"") +composeVersionDisplay()helper doing the strip-and-append via a genuine anchoredstrings.TrimSuffix(not a blind substring replace, independently confirmed via a self-constructed mutation test);GitCommit's declaration and thelogger.Infostartup-log call site (including its zap fields) confirmed byte-for-byte untouched- Observable confirmed live (independently re-verified by review, real build across all 5 scenarios + a live daemon-start log capture):
-versionshows<hash>-<fingerprint>never<hash>-dirty-<fingerprint>; the startup log shows the raw, un-fingerprintedGitCommit(still-dirty-suffixed when applicable) on the same binary whose-versionoutput differs;go.sum/go.moduntouched - Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 3.1, 3.2, 4.1
- Boundary: apiserver/cmd/main.go
- Depends: 4.1
-
4.5 (P) xcecli: fingerprint in --version
DirtyFingerprintvar +composeVersionDisplay()helper, a verbatim logical duplicate of apiserver's just-approved implementation (task 4.4); applied at the sole consumption point (the version string fed intorouter.Execute(cm, version));router.goconfirmed untouched (independently re-verified by the parent controller after the review, not just the reviewer, given a mid-review incident where the reviewer's own tooling briefly discarded the uncommitted diff before catching and byte-for-byte restoring it)- Observable confirmed live (independently re-verified by review, real builds across all 3 scenarios + full xcecli module test suite):
--version/-vshows<hash>-<fingerprint>on dirty+fingerprint,<hash>alone on clean,<hash>-dirtyunchanged on dirty+degraded-fingerprint; all exit 0; no regressions in any other xcecli package - Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 4.1
- Boundary: xcecli/cmd/main.go
- Depends: 4.1
-
5. Core: xceadmin fingerprint display
-
5.1 (P) meson-build.sh generates the fingerprint field in the build-info module
dirty_fingerprintthreaded through as an 8th positional arg ($8), correctly numbered and consistent betweenmeson.buildandmeson-build.sh;_build_info.pygainsDIRTY_FINGERPRINTwith an independent empty-string fallback (not"unknown");GIT_COMMIT/BUILD_TIME's existing generation and fallback confirmed byte-for-byte untouched- Observable confirmed live (independently re-verified by review, full real build+test+wheel cycles across 3 scenarios): dirty tree -> real, non-empty
DIRTY_FINGERPRINTpresent identically in the mirrored tree, the build/lib copy, an installed venv, and the packaged wheel, cross-checked byte-for-byte against that same build'scompile_commands.json; explicit-empty fingerprint -> genuinely""whileGIT_COMMIT/BUILD_TIMEpass through real values; all-empty ->GIT_COMMIT/BUILD_TIMEstill fall back to"unknown"whileDIRTY_FINGERPRINTstays""; 261 passed/3 skipped in all three scenarios - Requirements: 1.1, 1.2, 1.3, 1.4, 5.1
- Boundary: xceadmin/meson.build, xceadmin/meson-build.sh
- Depends: 1
-
5.2 (P) Committed fallback stub and CLI fingerprint wiring
_build_info.py's fallback stub gainsDIRTY_FINGERPRINT = "";cli.py's new_compose_version_display()applies the strip-and-append rule via a genuine anchoredremovesuffix("-dirty")(independently confirmed via a second, differently-constructed mutation test); both fallback paths (_build_info.py's module stub andcli.py's separateImportErrorfallback class) correctly carry the field- A pre-existing test's hard-coded literal-
GIT_COMMITassertion was updated to compute its expected value via the production_compose_version_display()function instead -- independently assessed by review as a legitimate strengthening (the old assertion's premise no longer holds once a fingerprint is present), not a weakened/gutted check; the 4 new dedicated unit tests independently guard the transform itself with hard-coded literal assertions - Observable confirmed live (independently re-verified by review, both install paths via a full real
/xce-build xceadmincycle): editable install shows0.1.0 (unknown, unknown), no import error; wheel built from the dirty tree shows<hash>-<fingerprint>, never<hash>-dirty-<fingerprint>; full suite 267 passed/3 skipped (261 baseline + 6 new) - Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 4.1
- Boundary: xceadmin/src/xceadmin
- Depends: 5.1
-
6. Integration: cross-toolchain consistency and regression verification
-
6.1 Dev-loop distinguishability and clean-tree regression test
- New script
src/tools/test-dirty-fingerprint-distinguishability.shuses a genuine isolatedgit worktree add --detach(uniquemktemp -upath,trap cleanup EXITregistered before creation, safe no-op if creation never happened,rm -rf+prunefallback) to sidestep this actively-shared repo's ambient concurrent-editing noise -- all file edits confined strictly inside the isolated worktree, the real repo's own working tree never touched - Drives a real
xce-build.sh schedulercycle through the 4 required states via genuine builds; fails loudly with a clear message on any mismatch - Observable confirmed live (independently re-verified by review across two full live runs, including a deliberately sabotaged copy forcing edit-B to reproduce edit-A's content): clean/no-suffix, dirty-A, dirty-B-differs-from-A, reverted-to-A-matches-A all held with real fingerprints; sabotaged run correctly failed with a clear message and exit 1, proving genuine (not just synthetic) discriminating power;
git worktree listand the real repo's working tree confirmed byte-identical to baseline before and after every run, both by implementer and reviewer - Requirements: 1.1, 1.2, 1.3, 1.4, 2.1
- Depends: 2.1, 3.2
- New script
-
6.2 Startup-log-unchanged consistency test
- New script
src/tools/test-dirty-fingerprint-startup-log-unchanged.shreuses task 6.1's already-approved isolated-git-worktree technique; builds scheduler and apiserver for real on a genuinely dirty tree, starts both daemons, captures--version/-version(expect fingerprint) and each startup log (expect old fingerprint-free format) - Apiserver's injected fingerprint value is reused from scheduler's own extracted value (same dirty tree, same content) rather than independently recomputed -- independently assessed by review as legitimate, not tautological: apiserver has no independent fingerprint-computation code of its own in production (only ever receives an externally-injected value via
-ldflags), the script still exercises apiserver's own real, unmockedcomposeVersionDisplay()/logger.Infocode paths on a genuinely running compiled binary, and a round-tripapi_fp == sched_fpcheck would catch a real strip-and-append bug - Observable confirmed live (independently re-verified by review, fresh full run + a separately-authored 4-case discrimination probe outside the script's own demo block): both daemons'
--version/-versionshow real fingerprints while their startup logs show the unchanged, fingerprint-free old format; no leftover processes, worktrees, or build dirs after either run - Requirements: 3.1, 3.2
- Depends: 3.2, 4.4
- New script
-
6.3 Nix production path end-to-end fingerprint verification
- New script
src/tools/test-dirty-fingerprint-nix-production-path.sh(reusing task 6.1's isolated-worktree technique) editsflake.nix, runsnix build ./src#xcecore_debug -L --keep-going(no--impure) twice with different content, and cross-checksnix eval's eval-timemyDirtyFingerprintvalue against the real build log'smesonConfigurePhase flags:line for each - This sandbox's
nix builddispatches by default to an unreachable-in-practice remote builder (ssh://rshen@172.31.109.18, confirmed genuinely expected behavior, not a misconfiguration) making a directly-runnable binary impractical to retrieve; the eval+build-log cross-check is not a weaker substitute -- independently confirmed structurally sound by review, sinceself.narHash's value is computed at flake-evaluation time and baked as a literal string into the derivation before any build phase runs, so eval-time and build-time values cannot diverge by construction, not just by empirical coincidence. Forcing--builders ''(local-only) was investigated per a live suggestion and does reach real local.ccompilation with a direct log match, but still can't produce a fully linked binary in this sandbox (a second, unrelated network dependency), confirming no stronger approach is currently available; recorded as a learning for future sessions - Observable confirmed live (independently re-verified by review, real
nix buildinvocations including a live-witnessed remote-builder connection attempt and a genuine local-only run): two builds with different tracked-file edits produce different fingerprints in both eval and build-log evidence; reverting to the first edit's exact content reproduces the first fingerprint exactly;--impurenever used; nogitdependency in the build sandbox;flake.nix/nixSupport/and the worktree list confirmed byte-identical to baseline after every run - Requirements: 1.1, 1.2, 1.3, 5.1
- Depends: 2.2
- New script
Implementation Notes
- Task 4.3: a
{ cmd1; cmd2; } >fileorcmd1 | cmd2 | cmd3shell construct's exit status (as checked byif ! ... ; then ...; fi) only reflects the LAST command's exit status, not any earlier command's -- this silently swallows an earlier failure and can produce fabricated output from partial/incomplete data instead of the intended graceful-degradation path. Took two rejected review rounds to fully generalize (first fixed forgit diff HEAD, then found again one step later forgit ls-files | sort | xargs). When writing any multi-stage shell pipeline whose failure must be individually detectable, either enablepipefailexplicitly (verify the actual invoking shell first --$(shell ...)in Make does NOT inherit a Makefile'sSHELL/.SHELLFLAGSsettings) or restructure each stage to its own directly-redirected, individually-$?-checked step (the safer default absent aSHELL:=bash-style pin, per this repo's own documented/bin/sh-is-not-guaranteed-bash incident inbuild-deployment.md).