myxce/.wolf/bugs/bug-1758.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

5.2 KiB

id status status_updated status_note component severity timestamp last_seen occurrences files tags related legacy
bug-1758 fixed 2026-09-24 scheduler unknown 2026-09-02T03:23:00Z 2026-09-19T09:00:00Z 1
src/scheduler/testsuite/test_core_events.c
scheduler-dispatch-commit
core_events-c
test_core_events-c
sched_reconcile_job_resource_usage
mem-reservation
resInUse
unrelated-branch-breakage
discovered-by-worker-rejoin-resync-validation
true

bug-1758: scheduler suite (meson test --suite scheduler): sched_core_events_test FAILs deterministically…

Description

scheduler suite (meson test --suite scheduler): sched_core_events_test FAILs deterministically -- test_core_events.c:1364:test_job_rusage_reconciles_mem_reservation_against_usage:FAIL: Expected 4 Was 0. Discovered as one of 2 failures (the other is a pre-existing, unrelated libxce/meson.build ASAN-flag gap) during worker-rejoin-resync feature-level /kiro-validate-impl full-suite run; confirmed NOT caused by worker-rejoin-resync.

Environment

Not recorded (migrated from buglog.json).

Reproduction

Not recorded (migrated from buglog.json).

Root cause

NOT YET ROOT-CAUSED (logged, not investigated -- out of scope for the session that found it). Confirmed via git blame that the ENTIRE failing test function, including the failing sanity assertion at line 1364 itself, was newly added by commit eb06f16d ("fix(scheduler): wire mem reservation reconciliation into live rusage event path", .kiro/specs/scheduler-dispatch-commit/), not by worker-rejoin-resync or any earlier commit -- this is that commit's own new test failing against its own new code, not a regression it caused in pre-existing coverage. The failure is at the test's OWN pre-condition sanity check (line 1364, before the rusage/reconciliation event the test is actually about is even pushed): a JOBS_PUSH-dispatched job with a real 4.0 "mem" xce_alloc_t is asserted to have already charged 4.0 into w->resInUse ("matching sched_charge_account()'s existing behavior", per the test's own comment) -- but val[0] reads back 0. Two live hypotheses, neither yet confirmed: (a) core_events.c's XCE_CORE_EVENT_JOBS_PUSH handler (used here to simulate a dispatch by directly attaching job1->allocs) never actually calls sched_charge_account()/an equivalent resInUse-charging step for a pushed RUN job carrying allocs -- JOBS_PUSH may be resync-shaped (report already-existing state) rather than dispatch-shaped (perform a fresh charge) by design, making the test's own sanity-check premise wrong; or (b) charging happens but keyed off a different resource-index/worker-pointer path than this test's fixture reads back from. Needs an actual debugging pass (e.g. kiro-debug) to distinguish; not attempted here.

RESOLVED (2026-09-08, follow-up session): hypothesis (a) confirmed, but with the opposite implication than it first suggested -- this is NOT a production gap. core_session.c's own core_begin_session_internal() doc comment (lines 156-176) already documents the real architecture: resInUse/sharedInUse is never charged incrementally at JOBS_PUSH/dispatch time. It is fully RE-DERIVED once per round by sched_account_jobs() (scheduler.c:1434) -- iterates every currently-RUN job in core->jobs and calls sched_charge_account() on each one's accounts -- called by BOTH the real normal-mode driver (driver.c:761) and the sim driver (sim_loop.c:1118), always BEFORE anything else in that round reads resInUse. JOBS_PUSH intentionally does none of this itself (confirmed by reading its full handler in core_events.c and builtin_fcfs_on_job_push() -- neither calls sched_charge_account/sched_uncharge_account anywhere), and neither does the terminal-state cleanup path (JOB_STATE_CHANGE/JOB_UPDATE just free the accounts structure) -- both are consistent with a 'recompute from source of truth each round' design that needs no incremental charge/uncharge pairing at all. The test's own precondition assertion (checking resInUse immediately after JOBS_PUSH, with no round boundary simulated) was checking an invariant that was never the real contract -- a test bug, not a production one.

Fix

FIXED (2026-09-08, follow-up session). test_job_rusage_reconciles_mem_reservation_against_usage (test_core_events.c) now calls sched_charge_account(&core, tracked->accounts) right after JOBS_PUSH and before the resInUse sanity assertion -- simulating the exact reconciliation step sched_account_jobs() would perform for this test's one RUN job, the same primitive sched_account_jobs() itself calls internally (test_core_events.c already white-box #includes resource.c, where sched_charge_account() lives; sched_account_jobs() itself is scheduler.c, not included here, so its single-job effect is reproduced directly rather than pulling in that whole file). No production code changed -- the bug was entirely in the test's precondition assumption, not the scheduler. Verified: full scheduler suite xce-build.sh scheduler asan --incremental: 77/77 Ok (was 76/77, this test's own prior deterministic failure now gone); full xce-build.sh all asan --incremental: 94/94 Ok, zero regressions.

Verification

Not recorded (migrated from buglog.json).

References

Not recorded (migrated from buglog.json).