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>
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 |
|
|
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).