--- id: "bug-1579" status: "wontfix" status_updated: "2026-09-24" status_note: "not a bug: intended host-attrs reset on disconnect; script fixed b673b7c9" component: "unknown" severity: "unknown" timestamp: "2026-08-18T09:00:00Z" last_seen: "2026-09-19T09:00:00Z" occurrences: 2 files: [".claude/skills/xce-test-resources/run-resource-verify.sh (not a bug in this file's new logic -- see root_cause); src/controller/worker.c (add_hostattrs_resvals()", "apply_worker_dead_mutation()) is the production code responsible for the behavior being (correctly) observed"] tags: ["false-positive", "test-tooling", "resource-value-verification", "run-resource-verify.sh", "task-6.2", "controller-check", "cpuf", "worker-disconnect", "host-attrs", "add_hostattrs_resvals", "mark_worker_unavail", "not-a-bug", "default-resource-set", "task-7.1-followup"] related: ["bug-1578"] legacy: true --- # bug-1579: run-resource-verify.sh's new controller-side check (task 6.2, query_controller_resvals()) reported… ## Description run-resource-verify.sh's new controller-side check (task 6.2, query_controller_resvals()) reported a live MISMATCH for the default resource set's 'cpuf' resource: 'controller check: cpuf -> MISMATCH: injected=9.5 observed=0.000000', even though inject_resources()'s own resupdate call reported 'cpuf=9.5 -> accepted' moments earlier in the same run. ## Environment _Not recorded (migrated from buglog.json)._ ## Reproduction _Not recorded (migrated from buglog.json)._ ## Root cause NOT A BUG -- documented, intentional controller production behavior colliding with this test script's own multi-process session structure. inject_resources() (task 6.1) runs join+resupdate+quit in ONE xce_test process; the 'quit' disconnects the synthetic worker's TCP connection to the controller at the end of that same script. query_controller_resvals() (task 6.2) then runs its resval query in a SEPARATE, LATER xce_test process/session -- by which point the synthetic worker is already gone from the controller's perspective. 'cpuf' is one of worker.c's N_HOST_ATTRS resources (add_hostattrs_resvals(), worker.c:260-287: type/model/cpuf/maxcpus/maxmem/maxswap/maxtmp/ndisks), which mark_worker_unavail() -> apply_worker_dead_mutation() (worker.c:704-716) deliberately RESETS (reset_hostattrs_unknown() then re-applies add_hostattrs_resvals()) whenever a worker is marked dead/disconnected -- correct, intentional production behavior for a REAL worker daemon that has genuinely gone away (you don't want a dead worker still advertising stale cpu capacity for scheduling). Every OTHER default resource (r15m, pg, ls, it, swp, io, tmp, mem -- none of which are in worker.c's N_HOST_ATTRS list) is a generic, non-host-attrs resval that persists correctly across worker disconnect and reported MATCH. Confirmed via live isolation: re-running with the exact same 8 non-cpuf resources reported 8/8 MATCH; re-running the mixed accept/reject scenario (mem=5, not-a-real-resource=1) correctly reported mem MATCH and skipped the rejected resource entirely (no query attempted). design.md's own sequence diagram does not show a worker disconnect between the resupdate leg and the resval-query leg, implying the intended flow keeps the synthetic worker connected throughout verification -- task 6.1's single-shot 'join;resupdate;quit' session structure deviates from that, but only resources that collide with worker.c's host-attrs reset list are affected. ## Fix DEFAULT-SET INSTANCE FIXED (task 6.2 remediation round 2): DEFAULT_RESOURCE_ARGS in run-resource-verify.sh now uses "r1m=9.5" instead of "cpuf=9.5" as the second already-supported regression-coverage name (mem=8.5 kept as-is -- mem is NOT host-attrs, confirmed safe). r1m is confirmed via resval_typeresolve.c's resinfo[] table to be a genuinely pre-existing resource name, and via src/worker/src/resource_sync.c to be a periodic/dynamic load-index resource (not in worker.c's N_HOST_ATTRS list), so it preserves the original 'already-supported name for regression coverage' intent without the disconnect-reset problem. Live-validated: default (no-args) set now reports a clean N/N MATCH with no false cpuf mismatch. Original two options re-evaluated: option (a) -- drop the host-attrs name from the default set -- is what was taken here. Option (b) -- keep the synthetic worker's xce_test session connected across all per-layer checks instead of quitting after inject_resources() -- was investigated live and found NOT to be a simple call-reordering fix: xce_test's REPL has no command path from the `worker` context back to the `client` context without first calling leave_ctx() (via `..`/cmd_up), which performs the exact same disconnect that `quit` does. Making option (b) work would require either a C-level xce_test change (e.g. a context-preserving command) or a materially riskier bash coprocess restructuring of this script -- both explicitly out of scope for this remediation. The underlying production behavior (add_hostattrs_resvals() / mark_worker_unavail() resetting host-attrs resources on worker disconnect) remains correct and untouched, and this note is preserved for any FUTURE task or user-supplied custom resource=value argument that names a host-attrs resource (type, model, cpuf, maxcpus, maxmem, maxswap, maxtmp, ndisks) -- those still hit this same class of false-MISMATCH if queried after the synthetic worker disconnects. REAL FIX APPLIED (follow-up session, 2026-08-18): the underlying disconnect-timing gap this workaround left open for any host-attrs name is now actually closed, not just avoided for the default set. run-resource-verify.sh's inject_resources() now inserts a `!bash "$SELF_SCRIPT" --internal-controller-check ` line (xce_test's `!` escape, preprocess_and_run(), test.c ~line 950-998 -- a single top-level-REPL-loop call site that works identically in ANY context including `worker`, with no leave_ctx()/disconnect) BETWEEN `resupdate` and `quit`, inside the SAME xce_test worker session. This invokes a new internal_controller_check() function (hidden dispatch at the bottom of the script, before `main "$@"`) that runs a nested client-context xce_test session and queries resval for every requested name WHILE the synthetic worker's connection is still open -- so a host-attrs resource is never reset to baseline before it is checked. Raw observed values are written to logs/controller-check-raw.tsv; query_controller_resvals() (still called at the same point in main(), after inject_resources() returns) now reads that file instead of running its own live query -- a pure sequencing change, the MATCH/MISMATCH comparison logic and TSV formats are byte-for-byte unchanged. DEFAULT_RESOURCE_ARGS restored `cpuf=9.5` (dropped the r1m workaround) as live proof: 'controller check: cpuf -> MATCH' now, not the old false MISMATCH. Live-validated (5 separate runs): default 9-resource set incl. cpuf clean 9/9 MATCH at both controller and scheduler layers (~5-7s total runtime); mixed accept/reject with a host-attrs custom name (cpuf=3.25 alongside a rejected unknown resource) correctly MATCHes cpuf and skips the rejected name at both layers; --keep-running and mid-injection SIGTERM (landing WHILE the nested `!`-escape check was actively running) both verified clean, zero orphaned xce_test processes (full /proc/[0-9]*/cmdline scan, not just pgrep). Option (b) from the original analysis below (keep the session connected) turned out to be achievable after all via this `!`-escape mechanism, without any C-level xce_test change -- the earlier conclusion that it needed one was specific to trying to move BETWEEN contexts (worker -> client) without disconnecting, which is genuinely not possible; running an entirely separate NESTED xce_test client session via a shell escape while remaining IN the worker context sidesteps that limitation entirely. ## Verification _Not recorded (migrated from buglog.json)._ ## References - Related: bug-1578