myxce/.wolf/bugs/bug-1743.md
Rongsong Shen d26ff8870d
feat(buglog): one Markdown record per bug, checked against a record standard
The buglog was one 27K-line JSON file whose fields covered only symptom,
root cause and fix, as free text: 2% of entries named the code version a
bug was found on, 12% the build profile, 36% a way to reproduce, and 58% of
the file was OpenWolf hook auto-detections ("Missing guard clause",
"Function not marked async" on .md files).

- .claude/skills/buglog/bug-record.md: the record standard. Eight
  sections (Summary as the title, Description, Environment, Reproduction;
  Root cause, Fix, Verification, References once fixed), each with the
  content it must contain -- e.g. Environment needs the OS, the libc the
  failing binary loads (from its ELF interpreter: glibc 2.42 in the nix
  shell vs 2.40 on the host), toolchain, build profile and commit.
- .wolf/bugs/<id>.md: 500 records migrated from buglog.json; every field
  verified to round-trip. They carry legacy: true and an explicit "not
  recorded" where the old log had no such field; component derived from
  file paths, severity from keywords (else unknown), fix_commits from
  hashes in status_note/fix that git resolves (91 of 463 fixed).
- .wolf/buglog-archive.json: the 710 hook auto-detections, verbatim.
- .wolf/buglog.json is now an index generated from the records, keeping
  the fields OpenWolf's hooks and `openwolf bug search` read.
- scripts/buglog.py rewritten: new (template + Environment collected from
  the machine and --binary), check, status (refuses a status the record
  doesn't support; fixed needs Root cause, Fix, Verification and
  --commit hashes git resolves), note, recur, set, show, list, triage,
  env, index. 29 unittest cases in scripts/tests/test_buglog.py.
- scripts/git-hooks/pre-commit runs `check --staged`: incomplete staged
  records, a legacy record hand-changed to fixed without the fix-time
  sections, a new record claiming legacy: true, or a stale index refuse
  the commit.
- scripts/gitea-sync.py reads the records: issue body = the record's
  sections plus linked fix commits (origin remote, GITEA_COMMIT_REPO to
  override), and a body hash so an issue's text is refreshed when the
  record changes.
- bug-1866 rewritten to the full standard as the worked example.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 03:40:11 +00:00

6.3 KiB

id status status_updated status_note component severity timestamp last_seen occurrences files tags related legacy gitea_issue gitea_synced_status
bug-1743 fixed 2026-09-24 config unknown 2026-09-01T04:10:00Z 2026-09-19T09:00:00Z 1
src/scheduler/src/resource.c (sched_check_host_satisfy_:328-377)
src/scheduler/src/plugins/limit.c (build_vres_name/per-user-queue-project virtual resource accounting:183-227
312-376)
src/configs/resources.yaml (slots resource:4
consumable:true)
src/configs/limits.yaml (ug1_normal_slots example
value:8
lines 41-49)
src/frontend/apiserver/models/hosts.go (HostInfo.NumRun:87)
scheduler
slots
admission-control
limits.yaml
usergroup-limit
queue-limit
hosts-list
NumRun
dead-field
visibility-gap
feature-request
new
found-static-analysis
needs-live-repro
related-to-bug-1673
related-to-bug-1556
needs-reporter-confirmation
bug-1673
bug-1556
bug-1784
bug-1785
bug-1786
bug-1787
bug-1788
bug-1789
bug-1790
true 46 fixed

bug-1743: Gitea issue #46 (还需要一个slots的概念): host test01 shows NCPUS=16, MAX_SLOT=16 via xcecli hosts list…

Description

Gitea issue #46 (还需要一个slots的概念): host test01 shows NCPUS=16, MAX_SLOT=16 via xcecli hosts list, but of 9 submitted single-slot sleep jobs on queue normal, only 8 reach RUN and the 9th is stuck PEND -- dispatch stops at 8/16 host capacity. Secondary ask: hosts list should show slots used/free, not just NCPUS/MAX_SLOT.

Environment

Not recorded (migrated from buglog.json).

Reproduction

Not recorded (migrated from buglog.json).

Root cause

Two independent findings. (1) Dispatch-stops-at-8 is most likely NOT a slot-counting bug in the scheduler -- MAX_SLOT genuinely gates per-host admission in sched_check_host_satisfy_() the same way mem does (per .kiro/steering/resource-accounting.md, reservation==usage for virtual resources like slots), but there is a SEPARATE, independent admission gate: cluster-wide usergroup+queue slot limits enforced by the scheduler's limit plugin (limit.c), configured in limits.yaml. This repo's example limits.yaml defines ug1_normal_slots: users in group ug1 on queue normal share a pool capped at exactly 8 (limits.yaml:41-49) -- an exact match to the reporter's queue (normal) and the observed 8/16 cutoff. This exact scenario (a queue/usergroup slot limit as an alternate explanation to a host-capacity bug) was explicitly predicted-but-unconfirmed in bug-1673 (filed against the related earlier report Gitea #40) and appears to be that prediction now reproduced. CAVEAT: limits.yaml/users.yaml in this repo look like sample/demo config (users.yaml's stock ug1 group only contains user1/user2, not admin) -- confirming this requires checking the reporter's actual deployed limits.yaml/users.yaml or their job's pend-reason output, neither of which was available this session (static analysis only). (2) The feature-request half (show slot usage in hosts list) is NOT starting from scratch: models.HostInfo.NumRun (hosts.go:87) already exists in the schema and is already an output column in xcecli hosts list (matching the reporter's own output), but grep -rn "\.NumRun\s*=" apiserver --include=*.go returns zero hits anywhere in the apiserver -- the field is never assigned and is permanently stuck at Go's zero value, which is exactly why the reporter's own output shows NUM_RUN=0 while 8 jobs are actually running on that host. Same for NumSSusp/NumUSusp.

Fix

PARTIALLY FIXED (2026-09-01). Part 2 (hosts-list slot visibility) is FIXED: added computeHostSlotUsage() (controllers/hosts.go) which scans store.Jobs' live ExecHosts JSONB (the same {"host_slots":[{"host_name","num_slots"}],...} shape backend/convert_pure.go populates) and JobStatus bits (JOBSTAT["RUN"]/["SSUSP"]/["USUSP"]) to count occupied slots per host, per sub-state -- counting SLOTS (not just job count) so the numbers are directly comparable to max_slot, matching the reporter's actual ask ('host上需要体现用了多少slots'). processHostData() now overwrites row.Data["num_run"/"num_ssusp"/"num_ususp"] with these live counts instead of leaving HostInfo's always-zero struct fields untouched. TDD: added TestProcessHostData_ComputesSlotUsageFromJobs (host_control_test.go) covering plain RUN, USUSP, a 2-slot SSUSP job (verifies slot-counting, not job-counting), a PEND job with no exec host (must not count), and a job on a different host (must not bleed across hosts). Confirmed red (num_run=0, want 6) before the fix, green after. Full apiserver suite passes with zero regressions.

Part 1 (dispatch-stops-at-8 root cause): FULLY RESOLVED (2026-09-07/08, follow-up session). Confirmed live (no reporter config needed after all -- the leading hypothesis was right, just broken at a much deeper layer than 'is a limit configured'): the entire usergroup/queue limit-matching machinery in the limit plugin was silently non-functional, a 6-bug cascade -- see bug-1784 (named usergroups never registered into the scheduler), bug-1785 (unconfigured scope matched no one instead of falling back to all), bug-1786 (election loop aborted after the first matched limit), bug-1787 (extra pointer indirection broke a resmgr handle lookup), bug-1788 (instantiate_limit() conflated not-found with a real error), and bug-1789/bug-1790 (even once matching worked, the limit's own consumption computation read the wrong request vector and always saw a 0 'wanted' value, so the numeric cap itself never bound). All six fixed and live-verified. Final confirmation (2026-09-08): fresh single-node deploy at current HEAD, 9 single-slot jobs submitted as user1 (a genuine ug1 member) on queue normal -- the exact repro shape from this issue -- scheduler trace shows limit1/ug1_slots/ug1_normal_slots all correctly matching and, for the first time, a real nonzero wanted value ('unsatisfy_ resource 35 total 3.000000 inuse 3.000000 uncomit 0.000000 wanted 1.000000' / 'unsatisfy_ unmet resource 35 (limit=limit1) shortfall 1.000000'), correctly PENDing jobs past the cap. Posted as a comment on gitea#46 and closed the issue (2026-09-08).

Verification

Not recorded (migrated from buglog.json).

References

  • Related: bug-1673, bug-1556, bug-1784, bug-1785, bug-1786, bug-1787, bug-1788, bug-1789, bug-1790
  • Gitea: #46