--- id: "bug-1777" status: "fixed" status_updated: "2026-09-28" status_note: "" component: "controller" severity: "unknown" timestamp: "2026-09-06T21:10:00Z" last_seen: "2026-09-19T09:00:00Z" occurrences: 1 files: ["src/harness/test.c", "src/harness/joblist_display.c"] tags: ["controller", "worker", "resource", "maxswap", "workerlist", "config-override", "deferred"] related: ["bug-1554"] fix_commits: ["da1a663f"] legacy: true gitea_issue: 307 gitea_synced_status: "fixed" gitea_synced_hash: "2df1c322623f" --- # bug-1777: xce_test workerlist's MaxSwap column can permanently disagree with the scheduler's own… ## Description xce_test workerlist's MaxSwap column can permanently disagree with the scheduler's own resmgr/replay view for the same worker: workerlist always shows the join-time hardware_monitor stub/detected value, never a hosts.yaml per-host maxswap override, while the scheduler always uses the override. User noticed this while comparing a scheduler simulator replay (maxswap=10000) against xce_test workerlist (MaxSwap=1.00 GB) for the same host and asked whether the two should be consistent. ## Environment _Not recorded (migrated from buglog.json)._ ## Reproduction _Not recorded (migrated from buglog.json)._ ## Root cause CONFIRMED via code trace (not yet reproduced against a live pc13v/replay artifact -- none existed on disk at investigation time). xce_worker_t carries two separate copies of a host-attrs-style resource: attrs->maxswap (hostattrs_t, written ONLY by xcecd.c's init_host_attrs() at join time -- rejoin_worker(), worker.c:440, just re-copies the same join-time value) and resvals[idx("maxswap")] (resmgr-indexed zarray, seeded from attrs->maxswap by add_hostattrs_resvals() at apply_join_state() start, worker.c, then OVERWRITTEN by mark_host_res()/update_val_res() if a hosts.yaml resource override exists for that host, worker.c:79 `array = &(w->host.resvals)`). cmd_workerlist() (test.c:1478) reads attrs->maxswap directly -- structurally incapable of ever reflecting a config override, since nothing writes an override back into attrs. The scheduler-facing path (collect_resvals_workers() -> resvals_to_sched -> xcesched_push_workers(), dataex.c/sched.c) reads resvals, which DOES pick up the override. So whenever a maxswap override is configured, the scheduler correctly uses it (and a replay/snapshot reflects it) while xce_test workerlist permanently shows the stale join-time value regardless of timing/staleness -- not a caching/race artifact, a structural gap. The Go apiserver/xcecli path (convert.go) also just casts attrs.maxswap with no override-awareness, and xcecli's hosts.yaml model doesn't even expose a MaxSwap column today. ## Fix Direction (a): workerlist (table and --json) shows maxmem/maxswap/maxtmp from the worker's effective resource values, which the workerlist reply already carries in resvals_to_sched (collect_resvals_workers(), controller/dataex.c) and which include a hosts.yaml override, falling back to the join-time attrs when a value is absent or not numeric (worker_effective_attr(), src/harness/joblist_display.c). Harness only; the Go apiserver's worker view is not changed here. ## Verification - Test: test_effective_attr_prefers_resval and test_effective_attr_falls_back_to_join_value in src/harness/testsuite/test_joblist_display.c; new function, the old code read attrs->maxswap directly - Suites: harness 6/6 (asan): harness_unit_test 141/0, cmdutil 14/0, resval_typeresolve 7/0, joblist_display 22/0, join_worker_args 7/0, listrow_json 12/0 - Live: n/a; xce_test is a client tool and every case above runs without a controller ## References - Related: bug-1554