chore(wolf): mark bug-1673/1674/1675/1677 fixed

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
This commit is contained in:
Rongsong Shen 2026-08-24 14:23:51 +00:00
parent fe87dafc85
commit 8174186948
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2

View file

@ -18451,7 +18451,7 @@
"error_message": "Gitea issue #40 (\"job \u8c03\u5ea6\u4e0d\u6b63\u786e\"): `xcecli hosts list` shows MAX_SLOT=0 for a dynamically-joined worker even though the host's real NCPUS (e.g. 16 or 22) is correctly reported and scheduling correctly dispatches up to that many concurrent jobs. Reproduced live on branch scheduler-framework: single-node deploy, worker joined as 'worker-1', `xcecli hosts list` -> NCPUS=22 MAX_SLOT=0. Submitted 9 single-slot sleep jobs -- all 9 eventually dispatched and ran (no hard cap observed under this test), so the reporter's secondary claim of a hard ~8-job concurrency ceiling did NOT reproduce here (most likely a mid-dispatch snapshot, dispatch is not instantaneous across all pending jobs on this branch; a queue/usergroup slot limit in limits.yaml, e.g. ug1_normal_slots=8, remains a plausible alternate explanation worth asking the original reporter about). Only the MAX_SLOT=0 display value itself is a confirmed, reproducible bug.",
"file": "src/frontend/apiserver/backend/handler.go, src/configs/hosts.yaml",
"root_cause": "OnHostConfigUpdated() (handler.go:60-70) only applies config-pushed fields (including MaxSlot) onto a host entry via `store.Hosts.Get(incoming.HostName)` -- an EXACT hostname match. hosts.yaml commonly defines only a wildcard `hostname: default` entry (plus a couple of literally-named ones, e.g. worker2/host3) -- confirmed via grep, no entry named after the actual dynamically-joined worker (e.g. 'worker-1'). So a worker that joins under its own hostname never receives a HostConfig push under that literal name, `store.Hosts.Get()` misses, OnHostConfigUpdated returns early, and MaxSlot is left at Go's zero-value (0) forever -- completely decoupled from the value actually used for scheduling. The C-side path is correct: worker.c's apply_join_state()/find_matched_hostconfig() falls back to the 'default' wildcard entry's mxj/maxcpus for real dispatch decisions, confirmed via a live controller log line showing the correct slots=22 resource value. This is purely a Go apiserver display gap, not a scheduling defect.",
"fix": "NOT FIXED -- reproduced and root-caused during a Gitea-issue verification pass (issues #40-44), no code change made. Candidate fix: OnHostConfigUpdated should fall back to matching the wildcard 'default' HostConfig entry (mirroring worker.c's own fallback) when no exact-named entry exists, instead of silently no-op'ing.",
"fix": "FIXED (2026-08-24). src/frontend/apiserver/backend/handler.go -- OnHostConfigUpdated now caches the \"default\" pseudo-host's config-sourced fields (defaultHostConfig, package-level, mutex-guarded) instead of discarding them, and retroactively backfills that fallback onto any already-registered host with no explicit (non-default) config of its own; OnHostUpdated applies the same fallback immediately on a host's first-ever registration. The HOSTCONFIG_MXJ_AUTO_DETECT -1 sentinel (bug-1556) is further resolved to the host's real NumCPUs when applied via fallback, mirroring worker.c's C-side `if (nslots<0) nslots = maxcpus`. A host with its own real per-host hosts.yaml entry is never overridden. Added resetHostConfigCache() test hook plus 5 new tests (both arrival orderings, no-override-of-explicit-config, unresolvable-stays-negative) -- all pass, plus all 3 pre-existing OnHostConfigUpdated/OnHostUpdated tests pass unmodified (`make test-backend`). Live-verified: `xcecli hosts list` for the dynamically-joined worker-1 (no hosts.yaml entry) now shows MAX_SLOT=22, matching NCPUS=22, instead of 0.",
"tags": [
"gitea-issue-40",
"apiserver",
@ -18466,7 +18466,7 @@
"bug-1556"
],
"occurrences": 1,
"last_seen": "2026-08-24T13:40:00Z",
"last_seen": "2026-08-24T14:25:00Z",
"gitea_issue": 40
},
{
@ -18475,7 +18475,7 @@
"error_message": "Gitea issue #41 (\"job output timestamp is incorrect\"): reporter's transcript shows `xcecli jobs list -l <jobid>` succeeding but omitting submit/start/done timestamps. Reproduced live on branch scheduler-framework, but the actual failure is more severe than reported: `xcecli jobs list -l <jobid>` (and bare `xcecli jobs list -l`) fail OUTRIGHT with `query request failed: [invalid parameters: unsupported query field: pending_reason]` -- no output is produced at all, not even a partial listing missing timestamps. Likely a regression introduced after the original issue was filed (this branch is under active scheduler-framework development).",
"file": "src/frontend/apiserver/controllers/jobs.go:553, src/frontend/apiserver/controllers/jobs.go:901",
"root_cause": "Both the `-l`/fields-filtered job-list code paths (jobs.go:553 and the near-duplicate at jobs.go:901) validate the requested field list via `utils.GetSupportedFields(models.JobSubmitRequest{})` -- the job SUBMISSION request struct -- instead of `models.JobInfo{}`, the job query/response struct (the correct pattern, confirmed already used correctly for hosts at hosts.go:105/307 with `models.HostInfo{}`, and for at least one other job code path at jobs.go:1131 with `models.JobInfo{}`). Read-only/response-only fields like `pending_reason`, `start_time`, `end_time`, `pids`, `pgids` don't exist on JobSubmitRequest, so the first such field hit in Go's randomized map-iteration order triggers a hard `unsupported query field` rejection, making `-l` (and any custom -o field list touching these fields) fail unconditionally.",
"fix": "NOT FIXED -- reproduced and root-caused during a Gitea-issue verification pass, no code change made. Fix is mechanical: change both `utils.GetSupportedFields(models.JobSubmitRequest{})` call sites (jobs.go:553, jobs.go:901) to `utils.GetSupportedFields(models.JobInfo{})`, matching the working pattern already used at jobs.go:1131 and hosts.go's equivalent checks.",
"fix": "FIXED (2026-08-24). src/frontend/apiserver/controllers/jobs.go:553,901 -- both field-validation call sites now use utils.GetSupportedFields(models.JobInfo{}) instead of models.JobSubmitRequest{}, matching the already-correct pattern at jobs.go:1131. Caught during live verification (not source review alone): core_limit/mem_limit exist on JobSubmitRequest but not JobInfo/JobAdditionalFields -- switching wholesale would have newly broken those two previously-valid -o/-l fields. Fixed by adding CoreLimit/MemLimit (CustomLimit) to models.JobAdditionalFields (models/jobs.go), the existing merge-in bucket already used for pids/pgids/interactive_job_url. Added TestJobsListFieldValidation_UsesJobInfoNotSubmitRequest (jobs_test.go) covering all 24 fields in xcecli's real JobFieldsMap vocabulary. Full apiserver/controllers suite passes (CGO_ENABLED=0, this package's pre-existing required mode). Live-verified: `jobs list -l` and `-o \"pending_reason start_time core_limit mem_limit pid pgid\"` all now succeed -- every one previously errored with \"unsupported query field\".",
"tags": [
"gitea-issue-41",
"apiserver",
@ -18487,7 +18487,7 @@
],
"related_bugs": [],
"occurrences": 1,
"last_seen": "2026-08-24T13:40:00Z"
"last_seen": "2026-08-24T14:25:00Z"
},
{
"id": "bug-1675",
@ -18495,7 +18495,7 @@
"error_message": "Gitea issue #42 (\"\u521a\u542f\u52a8\u7684\u65f6\u5019\u67e5\u8be2\u4f5c\u4e1a\u62a5\u7684\u9519\u8bef\u4e0d\u592a\u53cb\u597d\"): `xcecli jobs list` run in the narrow window right after the apiserver (re)starts, before its listener is up, prints a raw `get the request failed: [connection refused]` instead of a user-friendly message. Reproduced live on branch scheduler-framework: killed and relaunched the apiserver, hammered `xcecli jobs list` in a tight loop from the instant of relaunch -- attempts 1-13 all returned the exact reported text; the listener came up by attempt 14.",
"file": "src/frontend/xcecli/common/request/request.go:97-98, src/frontend/xcecli/common/request/request.go:185-188",
"root_cause": "ExtractErrorMessage() (request.go:185-188) explicitly special-cases the connection-refused case (`if strings.Contains(errStr, \"connection refused\") { return \"connection refused\" }`) but returns the raw OS-level string verbatim instead of a friendlier message (e.g. explaining the API server may still be starting up). GetRequestFromAPIServer() (request.go:97-98) then wraps it as `\"get the request failed: [%s]\"`, producing exactly the reported output.",
"fix": "NOT FIXED -- reproduced and root-caused during a Gitea-issue verification pass, no code change made. Fix is localized: change the connection-refused branch in ExtractErrorMessage() to return an operator-friendly message (e.g. \"cannot reach the API server -- it may still be starting up, retry shortly\") instead of the bare OS error string.",
"fix": "FIXED (2026-08-24). src/frontend/xcecli/common/request/request.go:187 -- ExtractErrorMessage()'s connection-refused branch now returns \"cannot reach the API server -- it may still be starting up, retry shortly\" instead of the raw \"connection refused\" string. Confirmed no other call site string-matches the old literal. Added TestExtractErrorMessage (request_test.go, table-driven) -- RED before, GREEN after. Full xcecli suite passes. Live-verified: killed+relaunched the apiserver, hit `xcecli jobs list` during the startup window -- new message confirmed both via the fresh test and independently by rebuilding xcecli and re-checking.",
"tags": [
"gitea-issue-42",
"xcecli",
@ -18507,7 +18507,7 @@
],
"related_bugs": [],
"occurrences": 1,
"last_seen": "2026-08-24T13:40:00Z"
"last_seen": "2026-08-24T14:25:00Z"
},
{
"id": "bug-1676",
@ -18536,7 +18536,7 @@
"error_message": "scripts/gitea-sync.py's sync_bugs() would crash (or silently no-op) on any real invocation: `buglog = json.loads(BUGLOG_PATH.read_text())` (line 726) then `for i, bug in enumerate(buglog):` (line 731) treats buglog.json as a bare list, but its actual top-level structure is `{\"version\": 1, \"bugs\": [...]}` -- a dict. `enumerate()` over a dict yields its keys (\"version\", \"bugs\") as `bug`, and the very next line's `bug.get(\"id\", ...)` would raise AttributeError on the string \"version\". Discovered incidentally while checking whether to set the `gitea_issue` cross-reference field on newly-logged bugs (bug-1673..bug-1676) during a Gitea-issue verification pass -- not run live, found via static read of the sync script against the current buglog.json wrapper format.",
"file": "scripts/gitea-sync.py",
"root_cause": "sync_bugs() was apparently written against (or never updated from) an earlier bare-array buglog.json format. Every other buglog reader/writer in this session's own tooling (and the Stop hook's own validation, per .wolf/OPENWOLF.md's 'Always preserve the top-level {\"version\": 1, \"bugs\": [...]} wrapper') expects the wrapper; this script does not, unlike its own spec-sync half (sync_specs et al.) which was presumably tested more recently.",
"fix": "NOT FIXED -- discovered via static review only, not executed live, no code change made. Fix is a one-line change: `buglog = json.loads(BUGLOG_PATH.read_text())[\"bugs\"]` (and the corresponding `_write_json(BUGLOG_PATH, buglog)` call at line 799 needs to re-wrap as `{\"version\": 1, \"bugs\": buglog}` rather than writing the bare list back out, or the wrapper will be destroyed on the next real sync run).",
"fix": "FIXED (2026-08-24). scripts/gitea-sync.py's sync_bugs() (~line 726, 799) now unwraps buglog_wrapper[\"bugs\"] on read and re-wraps buglog_wrapper[\"bugs\"] = buglog before _write_json on write, instead of treating the file as a bare list. Verified via a standalone read/write round-trip against a scratch copy of the real buglog.json (not the live file, no Gitea API calls) -- version and all 1019 entries survive intact.",
"tags": [
"gitea-sync",
"scripts",
@ -18547,7 +18547,7 @@
],
"related_bugs": [],
"occurrences": 1,
"last_seen": "2026-08-24T13:40:00Z"
"last_seen": "2026-08-24T14:25:00Z"
},
{
"id": "bug-1678",