fix(apiserver): detail-only PEND reason promotion was unreachable on the C path

cJobToModel pre-filled main_reason_name with pendReasonName(main_reason),
so a detail-only record (main_reason 0, the allocator's ordinary shortfall
shape) arrived at rawJobToModel named "unknown(0)" — and the promotion that
derives the overall reason from the first detail row requires an EMPTY
name. The promotion's own tests passed because they build rawJobData
directly; the live C path never hit it. Found by the advisor P0
verification: jobs whose res_reasons named no_resource read
main_reason_name=unknown(0) over the API.

main_reason 0 now leaves the name empty for the promotion to fill; a
non-zero main reason keeps its mapped name unchanged.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
lei.chen 2026-10-19 07:07:02 +00:00
parent 4db1aa8aef
commit 3e3b6d7947
2 changed files with 54 additions and 1 deletions

View file

@ -201,9 +201,19 @@ func cJobToModel(job *C.xce_job_t) *models.JobInfo {
// baselines encode main_reason=0 detail-only PENDs).
if job.pend_reasons != nil {
pr := job.pend_reasons
// main_reason 0 is detail-only (the allocator's ordinary shortfall
// shape): leave the NAME empty so rawJobToModel's promotion fills it
// from the first detail row. Pre-filling pendReasonName(0) here
// ("unknown(0)") made the promotion unreachable on the live C path —
// the advisor P0 verification caught jobs whose res_reasons named the
// real cause while main_reason_name read unknown(0).
mainName := ""
if pr.main_reason != 0 {
mainName = pendReasonName(int(pr.main_reason))
}
r.pendReason = &rawPendReason{
MainReason: int(pr.main_reason),
MainReasonName: pendReasonName(int(pr.main_reason)),
MainReasonName: mainName,
}
for i := 0; i < int(pr.nhost_reasons); i++ {
hr := C.job_host_reason(pr, C.int(i))